机器学习中的高斯过程:MQL5中的回归模型·综合运用
(3/3)· 从贝叶斯公式到可运行回归代码,补齐前 two 篇没讲的工程拼图
◍ 优化器退出码与参数落盘
MINBLEIC 优化器在 GP 回归调参结束时,会通过 rep 结构返回退出码。读懂这些码能直接判断这次寻优是正常收敛还是被数值问题打断。 出现 NAN 值通常意味着函数或梯度里混入了非数,优化器会抛异常终止;返回 -3 则说明约束不自洽,可行点可能根本不存在,或者太难找——这时换一组更好的初值重启优化器往往比硬跑更省时间。 正常退出的码也有区分:1 代表相对函数改进已不大于 EpsF,2 是缩放步长不大于 EpsX,4 是缩放梯度范数不大于 EpsG,5 表示吃满了 MaxIts 步数,8 则是用户主动调用 minbleicrequesttermination() 中断,此时 X 里装的是收到终止请求那一刻的“当前接受点”。 代码末尾把结果直接打印并抽出来:用 rep.GetInnerIterationsCount() 看迭代次数,PrintKernelParams 把核参数打到日志,ffunc.GetNLML() 给出最优参数下的负对数边际似然值,最后 ExtractKernelParams 按核列表把 w 拆回 optimized_params 返回。开 MT5 跑这段,重点盯退出码和 NLML,能立刻知道调参是否靠谱。外汇与贵金属市场高波动,GP 模型参数失稳可能频繁触发 -3,实盘前务必在历史数据上反复验证。
Print("IterationsCount =", rep.GetInnerIterationsCount()); class=class="str">"cmt">// Number of iterations Print("Parameters:"); PrintKernelParams(w, kernel_list); class=class="str">"cmt">// Display optimized parameters in the log Print("NLML = ", ffunc.GetNLML()); class=class="str">"cmt">// final NLML value for optimal parameters KernelParams optimized_params; CRowDouble parameters = w; class=class="str">"cmt">// determine the correct distribution of parameters across kernels ExtractKernelParams(parameters, kernel_list, optimized_params); class="kw">return optimized_params;
核组合怎么选,外推与周期全看它
合成数据用 100 个在 [−5,5] 均匀分布的样本点,拟合 y=sin(x)+0.5x 再加高斯噪声,同时塞进了线性项、周期项与不确定性,正好用来压测高斯过程回归的核配置。 SetKernelList 支持三种组合:仅 RBF+白噪声(2核)、RBF+线性+白噪声(3核)、RBF+线性+周期+白噪声(4核)。单跑 RBF 时,测试点一旦越出 [−5,5],协方差 K* 指数衰减到 0,预测均值回退到先验 0——插值强、外推废。 叠上线性核后,0.5x 趋势被接住,区间外预测改善但仍丢了对 sin(x) 的还原;再把周期核加进来,隐函数 f* 的预测区间几乎和后验均值重合,三种相关特征全被吃下。观测值 y* 的区间明显更宽,因为多算了白噪声方差。 别把 f* 区间当 y* 区间 很多人忘了在协方差里显式加噪声方差,会把隐函数预测带误读成实际观测带。Predict 里已经用 KERNEL_WHITE 取 sigma 平方补进 K_noisy_train 与 Sigma_y_star,少这步就会系统性低估风险。 下面这段是 Predict 核心,逐行拆一下:先算训练集 K 矩阵,再扫 kernel_list 找白核拿观测噪声方差;K_noisy_train 就是 K 加噪声单位阵。K_star 是训练-测试交叉协方差,后验均值用 inv(K_noisy)@y_train 左乘 K_star 转置得到。Sigma_f_star 由测试自协方差减 K_star 项算出,Sigma_y_star 再叠噪声阵——外汇与贵金属行情噪声结构多变,直接套容易误判波动边界,属高风险用法。
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| Predict the Gaussian posterior distribution for new points | </span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------------+</span> GPPredictionResult Predict(<span class="keyword">class="kw">const</span> <span class="keyword">matrix</span> &x_train, <span class="keyword">class="kw">const</span> <span class="keyword">matrix</span> &y_train, <span class="keyword">class="kw">const</span> <span class="keyword">matrix</span> &x_test, <span class="keyword">class="type">int</span> &kernel_list[], KernelParams &params) { GPPredictionResult result; <span class="comment">class=class="str">"cmt">// Calculate the K covariance matrix for the training points </span> <span class="keyword">matrix</span> K = ComputeKernelMatrix(x_train, x_train, kernel_list, params); <span class="comment">class=class="str">"cmt">// Obtain the observation noise variance</span> <span class="keyword">class="type">class="kw">double</span> observation_noise_variance = <span class="number">class="num">0.0</span>; <span class="keyword">for</span> (<span class="keyword">class="type">int</span> i = <span class="number">class="num">0</span>; i < <span class="functions">ArraySize</span>(kernel_list); i++) { <span class="keyword">if</span> (kernel_list[i] == KERNEL_WHITE) { observation_noise_variance = params.white.sigma * params.white.sigma; <span class="keyword">break</span>; } } <span class="comment">class=class="str">"cmt">// Form a noise matrix for the training data: K + sigma_n^class="num">2 * I</span> <span class="keyword">matrix</span> K_noisy_train = K + <span class="keyword">matrix</span>::Identity((<span class="keyword">class="type">int</span>)x_train.Rows(), (<span class="keyword">class="type">int</span>)x_train.Rows()) * observation_noise_variance; <span class="comment">class=class="str">"cmt">// Calculate the K* cross-covariance matrix between training and test points </span> <span class="keyword">matrix</span> K_star = ComputeKernelMatrix(x_train, x_test, kernel_list, params); <span class="comment">class=class="str">"cmt">// Calculate the posterior mean</span> <span class="keyword">matrix</span> inv_term = K_noisy_train.Inv(); result.mu_f_star = K_star.Transpose() @ (inv_term @ y_train); <span class="comment">class=class="str">"cmt">// Matches mu_y_star</span> <span class="comment">class=class="str">"cmt">// Calculate the posterior covariance matrix for the latent function(Sigma_f_star)</span> <span class="keyword">matrix</span> K_star_star = ComputeKernelMatrix(x_test, x_test, kernel_list, params); result.Sigma_f_star = K_star_star - K_star.Transpose() @ (inv_term @ K_star); <span class="comment">class=class="str">"cmt">// Calculate the posterior covariance matrix for a new observation(Sigma_y_star)</span> <span class="comment">class=class="str">"cmt">// Sigma_y_star = Sigma_f_star + sigma_n^class="num">2 * I</span> result.Sigma_y_star = result.Sigma_f_star + <span class="keyword">matrix</span>::Identity((<span class="keyword">class="type">int</span>)x_test.Rows(), (<span class="keyword">class="type">int</span>)x_test.Rows()) * observation_noise_variance; <span class="keyword">class="kw">return</span> result; }
「一点提醒」
高斯过程这套框架在 MT5 里已经能跑通:GP_Samples_Prior.mq5 做先验采样、GP_Samples_Posterior.mq5 做后验采样、GP_Regressor 负责回归建模,三个脚本体积分别约 22.6 KB、28.48 KB 和 61.32 KB,直接丢进终端就能复现文中结果。 后验分布给出的不是单点预测,而是一整条带置信区间的曲线,这对判断「模型自己有多不确定」比单纯看拟合值更有用。外汇与贵金属行情高波动、跳空频繁,用 RBF 或周期核外推时,实盘失效概率可能偏高。 文中没展开的稀疏近似和 NLML 解析梯度,是后续把数据量堆上去的关键;现在先用小样本把核函数手感摸熟,比急着上大模型更实际。