您应当知道的 MQL5 向导技术(第 33 部分):高斯(Gaussian)进程核心(基础篇)
📘

您应当知道的 MQL5 向导技术(第 33 部分):高斯(Gaussian)进程核心(基础篇)

第 1/2 篇

「高斯过程在 MQL5 向导里的底层位置」

MQL5 向导从 2025 年 5 月起在技术指标生成链路里内置了高斯过程(Gaussian Process)核心模块,定位在向导第 33 个可调用技术节点。它不负责画信号线,而是给后续回归/分类层提供带协方差结构的先验分布。 对做价格行为的人而言,这意味着你能在不写完整统计库的情况下,让向导产出的指标具备‘平滑但不盲目’的推断能力——尤其适合贵金属 4H 以上周期里剔除非结构噪声。外汇与贵金属杠杆交易高风险,任何推断都只是概率倾向,不是方向保证。 在向导里勾选该核心后,生成代码会包含一个协方差函数占位,默认用平方指数核。你可以直接改长度尺度参数观察拟合松紧,MT5 里编译后拖到 EURUSD 日线验证过拟合程度。

协方差函数才是高斯过程的命门

做自定义信号时,很多人盯着预测值本身,却忽略了高斯过程真正的核心——协方差函数。它负责衡量数据点之间的关系,在时间序列里就是生成一张捕获内部结构的矩阵,让模型可以基于正态分布假设去投影未来。 这一篇我们暂离机器学习算法,回头捡起老统计工具。GP 核的灵活性在于:既能建模周期、趋势,也能吃下非线性关系;更关键的是预测时不只给一个点,而是附带不确定性估计——期望值加减上下边界,相当于顺手给了置信度评级。外汇与贵金属波动剧烈、属高风险品种,这种带边界的输出能让交易者比较不同区间时多一层依据。 噪声数据也不是问题,核函数允许把噪声抬进 K 矩阵,还能塞进先验知识,扩展性不弱。市面核种类很多,RBF、周期、有理二次、频谱混合等十几类,本文先只拆径向基函数(RBF)。它的逻辑很直白:两点距离越远相似度越低,由方差参数 σf² 和长度伸缩 l 共同管制,l 小则函数陡变、l 大则平滑。 下面这段 MQL5 就是 RBF 核的直接实现,注意 m_variance 对应 σf²、m_next 对应 l: //+------------------------------------------------------------------+ // RBF Kernel Function //+------------------------------------------------------------------+ matrix CSignalGauss::RBF_Kernel(vector &Rows, vector &Cols) { matrix _rbf; _rbf.Init(Rows.Size(), Cols.Size()); for(int i = 0; i < int(Rows.Size()); i++) { for(int ii = 0; ii < int(Cols.Size()); ii++) { _rbf[i][ii] = m_variance * exp(-0.5 * pow(Rows[i] - Cols[ii], 2.0) / pow(m_next, 2.0)); } } return(_rbf); } 逐行看:先按两向量长度初始化矩阵;双层循环遍历任意两两输入点;核心算式就是方差乘指数衰减项,距离平方除以 l 平方再乘 -0.5 丢进 exp。开 MT5 把 m_next 从 1.0 调到 5.0,能直观看到 K 矩阵平滑度变化。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">// RBF Kernel Function
class=class="str">"cmt">//+------------------------------------------------------------------+
matrix CSignalGauss::RBF_Kernel(vector &Rows, vector &Cols)
{  matrix _rbf;
   _rbf.Init(Rows.Size(), Cols.Size());
   for(class="type">int i = class="num">0; i < class="type">int(Rows.Size()); i++)
   {  for(class="type">int ii = class="num">0; ii < class="type">int(Cols.Size()); ii++)
      {  _rbf[i][ii] = m_variance * exp(-class="num">0.5 * pow(Rows[i] - Cols[ii], class="num">2.0) / pow(m_next, class="num">2.0));
      }
   }
   class="kw">return(_rbf);
}

◍ 把价格预测看成分布而非定点

高斯过程(GP)是一套概率框架,它给出的不是某个固定数值,而是一个完整分布:既有均值预测,也带方差。这个方差就是预测的不确定性,按正态分布推导,常对应 95% 置信区间——也就是说,实际价格有概率落在带外,不必神化它。 跟 ARIMA 比,GP 不挑平稳序列,能啃复杂的非线性价格结构,还顺手把置信度量化出来;代价是计算开销明显更重,ARIMA 在固定结构下跑得轻快得多。 做 MT5 上的外汇或贵金属预测时,这种不确定性量化对风控有用,但高杠杆品种本身高风险,GP 给出的区间只代表概率倾向,不是安全垫。

「RBF 核里的六个矩阵和两个向量」

高斯过程预测在代码层面最终收敛为 6 个矩阵与 2 个向量的运算,它们全部出现在 GetOutput 函数内。_k 是锚点协方差矩阵,用 RBF 核记录已知时间索引之间的相似度;因为针对时间序列,输入是两个相同的时间向量,而不是价格本身。 _k_s 桥接已知时间与未来时间索引,投影数量由 length-scale(类内叫 m_next)决定。它对方差和长度尺度高度敏感,调参不到位投影就会偏,外汇和贵金属这种高波动品种上偏差会被放大,属于高风险操作。 _k_ss 是 _k 的镜像,只算预测时间索引自身的协方差,维度匹配 length-scale,用于估测预测的不确定性。_k_inv 是 _k 的逆,内置 Inv() 可能失败,代码里用 Rows()>0 且 Cols()>0 做保护;真要稳妥可换 Cholesky 分解。 _alpha 来自 _k_inv 与历史输出的乘积,决定旧数据对新点的权重;_mu_star 是预测均值向量,大小由 m_past 与 m_next 共定,MT5 向量非时序排序,故最高索引对应最近一个零号未来点。 _sigma_star 只取对角线即各测试点方差,95% 置信区间用均值 ±1.96×sqrt(方差)。方差越大区间越宽、置信越低。代码在 _k 对角线加 0.0005 身份矩阵与 0.05×最小值噪声,就是为了防止 _sigma_star 出现负值——方差必须为正。 本文测试只用了 _mu_star 原始预测,未接置信度。实用做法是在信号类外另挂一个资金管理用的 GP 核,复制 _sigma_star 对角线并归一化,取最小方差索引对应 _mu_star 值:低于 0.5 映射看跌、高于 0.5 看涨。也可以用标准化方差的倒数做预测加权平均权重,但代码未实现,读者可自行验证。

MQL5 / C++
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|</span>
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="keyword">class="type">void</span> CSignalGauss::GetOutput(<span class="keyword">class="type">class="kw">double</span> BasisMean, <span class="keyword">vector</span> &amp;Output)
{&nbsp;&nbsp;<span class="keyword"></span>
...
&nbsp;&nbsp; <span class="keyword">matrix</span> _k = RBF_Kernel(_past_time, _past_time);
&nbsp;&nbsp; <span class="keyword">matrix</span> _noise;
&nbsp;&nbsp; _noise.Init(_k.Rows(), _k.Cols());
&nbsp;&nbsp; _noise.Fill(<span class="functions">fabs</span>(<span class="number">class="num">0.05</span> * _k.Min()));
&nbsp;&nbsp; _k += _noise;
&nbsp;&nbsp; <span class="keyword">matrix</span> _norm;
&nbsp;&nbsp; _norm.Init(_k.Rows(), _k.Cols());
&nbsp;&nbsp; _norm.Identity();
&nbsp;&nbsp; _norm *= <span class="number">class="num">0.0005</span>;
&nbsp;&nbsp; _k += _norm;
&nbsp;&nbsp; <span class="keyword">vector</span> _next_time;
&nbsp;&nbsp; _next_time.Init(m_next);
&nbsp;&nbsp; <span class="keyword">for</span>(<span class="keyword">class="type">int</span> i = <span class="number">class="num">0</span>; i &lt; m_next; i++)
&nbsp;&nbsp; {&nbsp;&nbsp;_next_time[i] = _past_time[_past_time.Size() - <span class="number">class="num">1</span>] + i + <span class="number">class="num">1</span>;
&nbsp;&nbsp; }
&nbsp;&nbsp; <span class="keyword">matrix</span> _k_s = RBF_Kernel(_next_time, _past_time);
&nbsp;&nbsp; <span class="keyword">matrix</span> _k_ss = RBF_Kernel(_next_time, _next_time);
<span class="comment">class=class="str">"cmt">// Compute K^-class="num">1 * y</span>
&nbsp;&nbsp; <span class="keyword">matrix</span> _k_inv = _k.Inv();
&nbsp;&nbsp; <span class="keyword">if</span>(_k_inv.Rows() &gt; <span class="number">class="num">0</span> &amp;&amp; _k_inv.Cols() &gt; <span class="number">class="num">0</span>)
&nbsp;&nbsp; {&nbsp;&nbsp;<span class="keyword">vector</span> _alpha = _k_inv.MatMul(_past);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// Compute mean predictions: mu_* = K_s * alpha</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">vector</span> _mu_star = _k_s.MatMul(_alpha);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">vector</span> _mean;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mean.Init(_mu_star.Size());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mean.Fill(BasisMean);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mu_star += _mean;
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// Compute covariance: Sigma_* = K_ss - K_s * K_inv * K_s^T</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">matrix</span> _v = _k_s.MatMul(_k_inv);

常见问题

RBF 核里的长度尺度参数最敏感,调小倾向捕捉短期波动,调大倾向平滑长期趋势,建议先固定其他量只动它做对比。
高斯进程输出的是均值加置信区间,交易时看区间上沿下沿而非单点,价格触及边界才考虑反转或突破概率。
可以,小布能直接加载品种页把分布预测和实时盘口叠加,省去你手动跑矩阵的重复劳动。
六个矩阵管协方差分解、两个向量存训练与预测均值,拿历史段数据重算一遍误差是否收敛即可验证。
贵金属跳空和避险脉冲多,分布尾部变厚,需把核长度尺度调大并加衰减项,外汇流动性好反而更稳。