卡尔曼滤波器预测价格方向:基础篇厘清噪声与主趋势分离原理(基础篇)
📡

卡尔曼滤波器预测价格方向:基础篇厘清噪声与主趋势分离原理(基础篇)

(1/3)·多数交易者被短期噪音牵着走,却说不清滤波器的预测与校正到底在算什么

含代码示例实战向 第 1/3 篇
直接在图表上画趋势线判断方向,常被次级波动带偏而不自知。把价格里的噪音当成信号,是新手和老手都会犯的错。卡尔曼滤波器正是为从含噪数据里剥离主走势而设计的。

◍ 用卡尔曼滤波给价格方向做一步预测

卡尔曼滤波原本是工程里的状态估计器,放到 MT5 里可以当成一种对价格序列的递归平滑与预测工具。它不假设价格服从某种固定分布,而是用上一刻的估计和当前观测值不断修正,输出一条比均线更‘跟手’的方向轨迹。 在 MQL5 里实现单变量卡尔曼预测,核心就是两个矩阵运算:先验估计和更新增益。下面这段是最小可用的预测步代码,跑在 OnCalc 里就能拿到下一根可能的方向。 外汇与贵金属波动带杠杆,卡尔曼给出的只是概率意义上的倾向,不是确定信号,实盘前务必用历史数据验证参数稳定性。

MQL5 / C++
class="type">class="kw">double KalmanPredict(class="type">class="kw">double price, class="type">class="kw">double& x_est, class="type">class="kw">double& p_est, class="type">class="kw">double q, class="type">class="kw">double r)
{
   class=class="str">"cmt">// 先验估计:状态不变模型,预测值等于上次估计
   class="type">class="kw">double x_pred = x_est;
   class=class="str">"cmt">// 先验误差协方差
   class="type">class="kw">double p_pred = p_est + q;
   class=class="str">"cmt">// 卡尔曼增益
   class="type">class="kw">double k = p_pred / (p_pred + r);
   class=class="str">"cmt">// 更新估计值
   x_est = x_pred + k * (price - x_pred);
   class=class="str">"cmt">// 更新误差协方差
   p_est = (class="num">1 - k) * p_pred;
   class=class="str">"cmt">// 返回预测方向(当前估计相对上次的变化)
   class="kw">return x_est - x_pred;
}

用卡尔曼滤波剥离市场噪音

货币与贵金属价格图表里,波动的频率和幅度从来不齐整。短线受消息和流动性扰动,长线才反映多空主力的真实意图。交易者画趋势线或挂指标,本质都是在做同一件事:把主趋势从短期噪音里捞出来。外汇和贵金属杠杆高,噪音诱发的假突破极易扫损,分辨信号真伪是存活前提。 我在这套思路里换用卡尔曼滤波器做分离。数字滤波器在交易里不是新东西,之前用过低通滤波器压高频杂波,但参数钝化后滞后明显。卡尔曼的优势是递推更新、带不确定性加权,对突变走势的跟随比固定窗低通更紧。 下一篇会直接给 MT5 的 MQL5 实现并跑历史数据,你可以先开终端把 EURUSD 的 M5 拉出来,肉眼标一段震荡,等代码贴出后对照滤波输出看噪音压制效果。

「卡尔曼滤波怎么给价格去噪」

卡尔曼滤波器本质是一套处理带噪观测的递推算法,最初为含统计噪声和不完整数据的动态系统设计。价格图表本身就是典型的动态系统,所以它能直接套用:外推(预测)和更新(校正)两步循环,把含噪报价收敛成一条更可信的状态轨迹。 第一步外推,用状态转换模型 F_k 把前一步滤波值 x̂_{k-1} 推到当前预测 x_k,同时外推误差协方差 P_k = F_k P̂_{k-1} F_kᵀ + Q_k。Q_k 是过程噪声矩阵,新闻冲击等未知控制量实际被归进这里。 第二步更新,先算实测 z_k 与预测的差 y_k = z_k - H_k x_k(H_k 常取 1,即报价直接对照预测)。再算误差协方差 S_k = H_k P_k H_kᵀ + R_k,R_k 是报价本身的测量噪声。增益 K_k = P_k H_kᵀ S_k⁻¹ 决定该信模型还是信盘面,最终 x̂_k = x̂_{k-1} + K_k y_k,P̂_k = (I - K_k H_k) P_k。 在 MT5 里验证时,把收盘价当 z_k、H_k=1,用单状态模型跑完一轮,你会看到 K_k 在震荡市偏向 0.2~0.4 区间,平滑后曲线对突刺的滞后明显小于简单移动平均。外汇与贵金属杠杆高、滑点随机,这套滤波只降低噪声不代表方向判断胜率提升,参数 Q_k/R_k 比值要自己回测调。

◍ 把卡尔曼滤波落进 MT5 的收盘价流

卡尔曼滤波器原本为线性系统而生,乘个系数就能推下一步;但外汇和贵金属的价线是非线性、步间比率漂移且相邻状态关系不明的。硬解法是套用自回归模型当动态过程模型,用柱线收盘价驱动离散版滤波。 实现上先建 CKalman 类,在初始化里给变量赋初值。噪声协方差用分析周期 Close 偏差的均方根,过程噪声协方差则靠自回归模型值的均方根偏差估出来;系统初值取最后 10 个收盘价的算术平均。 拿到全部初值后,Forecast 公有函数做单步前瞻:先查自回归模型算没算,必要时补算,再把状态转换系数存进 cda_F[0] 并顺移,重算状态与出错概率,返回的是新柱线预测收盘价。收到真实收盘价后,Correction 函数按理论式校正状态并返回更新值。 外汇和贵金属波动剧烈,这套滤波只降低噪声、不消除跳空风险,实盘前请在 MT5 策略测试器用历史数据验证系数稳定性。

MQL5 / C++
class CKalman
  {
class="kw">private:
class=class="str">"cmt">//---
   class="type">uint                 ci_HistoryBars;                class=class="str">"cmt">//用于分析的柱线数量
   class="type">uint                 ci_Shift;                      class=class="str">"cmt">//计算自回归的偏移
   class="type">class="kw">string               cs_Symbol;                    class=class="str">"cmt">//品名
   ENUM_TIMEFRAMES      ce_Timeframe;                 class=class="str">"cmt">//时间帧
   class="type">class="kw">double               cda_AR[];                     class=class="str">"cmt">//自回归系数
   class="type">int                  ci_IP;                        class=class="str">"cmt">//自回归系数的数量
   class="type">class="kw">datetime             cdt_LastCalculated;           class=class="str">"cmt">//最后计算时间;

   class="type">bool                 cb_AR_Flag;                   class=class="str">"cmt">//自回归计算的标志
class=class="str">"cmt">//--- 卡尔曼滤波器的数值
   class="type">class="kw">double               cd_X;                         class=class="str">"cmt">// X
   class="type">class="kw">double               cda_F[];                      class=class="str">"cmt">// F 数组
   class="type">class="kw">double               cd_P;                         class=class="str">"cmt">// P
   class="type">class="kw">double               cd_Q;                         class=class="str">"cmt">// Q
   class="type">class="kw">double               cd_y;                         class=class="str">"cmt">// y
   class="type">class="kw">double               cd_S;                         class=class="str">"cmt">// S
   class="type">class="kw">double               cd_R;                         class=class="str">"cmt">// R

卡尔曼类里的自回归初始化细节

上面这段是 CKalman 类的构造与自回归预处理的拼装代码,核心在把历史收盘价转成相邻比值序列,再据此定模型阶数。构造函数默认吃 6240 根 H1 棒线、偏移 0、品种留空时自动取 _Symbol,初始测量噪声协方差 cd_P 设 1、卡尔曼增益 cd_K 设 0.9,这两个值直接决定滤波对新报价的跟随锐度。 Autoregression() 先卡 Bars() 数量是否够 ci_HistoryBars,不够直接返 false;随后用 CopyClose 取 ci_HistoryBars+1 个收盘价,注意是从 ci_Shift+1 开始倒序存,ArraySetAsSeries(close,true) 后 close[0] 是最新根。 比值序列 cda_QuotesCenter[i]=close[i]/close[i+1] 是后面 Levinson 递归的输入。模型阶数 ci_IP 用 50*MathLog10(NumTS) 四舍五入,且硬卡不超过 NumTS*0.7——比如 NumTS=6240 时 log10 约 3.795,ci_IP 算出来约 190,远小于 4368 的上限,实际就取 190。外汇与贵金属波动跳变多,这套阶数上限能压住过拟合,但高杠杆下仍属高风险,参数照搬前先在 MT5 策略测试器跑一遍。 让小布替你跑这套 把 cd_K 从 0.9 改成 0.5 再回测同品种,滤波平滑度会明显上升、信号滞后也加大,适合对比震荡与趋势段的表现差异。

MQL5 / C++
  class="type">class="kw">double                cd_K;                                        class=class="str">"cmt">// K

class="kw">public:
                    CKalman(class="type">uint bars=class="num">6240, class="type">uint shift=class="num">0, class="type">class="kw">string symbol=NULL, ENUM_TIMEFRAMES period=PERIOD_H1);
                    ~CKalman();
  class="type">void                Clear_AR_Flag(class="type">void)  {  cb_AR_Flag=class="kw">false; }
};
CKalman::CKalman(class="type">uint bars, class="type">uint shift, class="type">class="kw">string symbol, ENUM_TIMEFRAMES period)
  {
   ci_HistoryBars =  bars;
   cs_Symbol       =  (symbol==NULL ? _Symbol : symbol);
   ce_Timeframe   =  period;
   cb_AR_Flag     =  class="kw">false;
   ci_Shift       =  shift;
   cd_P           =  class="num">1;
   cd_K           =  class="num">0.9;
  }
   class="type">bool                Autoregression(class="type">void);
   class="type">bool                LevinsonRecursion(class="kw">const class="type">class="kw">double &R[],class="type">class="kw">double &A[],class="type">class="kw">double &K[]);
class="type">bool CKalman::Autoregression(class="type">void)
  {
  class=class="str">"cmt">//--- 检查数据不足
   if(Bars(cs_Symbol,ce_Timeframe)<(class="type">int)ci_HistoryBars)
      class="kw">return class="kw">false;
class=class="str">"cmt">//---
   class="type">class="kw">double   cda_QuotesCenter[];                                      class=class="str">"cmt">//计算的数据
class=class="str">"cmt">//--- 令所有价格可用
   class="type">class="kw">double close[];
   class="type">int NumTS=CopyClose(cs_Symbol,ce_Timeframe,ci_Shift+class="num">1,ci_HistoryBars+class="num">1,close)-class="num">1;
   if(NumTS<=class="num">0)
      class="kw">return class="kw">false;
   ArraySetAsSeries(close,true);
   if(ArraySize(cda_QuotesCenter)!=NumTS)
     {
       if(ArrayResize(cda_QuotesCenter,NumTS)<NumTS)
         class="kw">return class="kw">false;
     }
   for(class="type">int i=class="num">0;i<NumTS;i++)
      cda_QuotesCenter[i]=close[i]/close[i+class="num">1];                      class=class="str">"cmt">// 计算系数
   ci_IP=(class="type">int)MathRound(class="num">50*MathLog10(NumTS));
   if(ci_IP>NumTS*class="num">0.7)
      ci_IP=(class="type">int)MathRound(NumTS*class="num">0.7);                              class=class="str">"cmt">// 自回归模型的顺序

   class="type">class="kw">double cor[],tdat[];
   if(ci_IP<=class="num">0 || ArrayResize(cor,ci_IP)<ci_IP || ArrayResize(cda_AR,ci_IP)<ci_IP || ArrayResize(tdat,ci_IP)<ci_IP)
      class="kw">return class="kw">false;
   class="type">class="kw">double a=class="num">0;
   for(class="type">int i=class="num">0;i<NumTS;i++)
把噪声诊断交给小布盯盘
这些滤波思路小布盯盘的 AIGC 已内置,打开对应品种页即可看到趋势与噪音的分离视图,你只需专注决策。

常见问题

低通滤波器侧重频域截断高频噪音,卡尔曼滤波器基于动态系统模型做预测校正,能处理不完整数据且适配时变过程。
两类品种受新闻与流动性冲击明显,滤波仅降低噪音干扰,方向仍可能失效,属高风险博弈,结论偏概率性。
可以,小布盯盘对应品种页内置了类卡尔曼的噪音分离视图,省去手动写 MQL5 代码的重复劳动。
实盘控制效果如新闻因素未知,通常忽略 uk 并将其影响归入过程噪声矩阵 Qk,不影响主滤波逻辑。
意味着外推可信度下降,校正阶段会更偏向实测值,滤波跟踪变灵敏但也更容易受单次噪音扰动。