利用回归衡量度评估 ONNX 模型(基础篇)
用回归指标给 ONNX 模型打分
在 MT5 里跑 ONNX 推理模型做行情预测,光看预测曲线和真实价格贴不贴是不够的,得有量化误差手段。回归衡量度(Regression Measure)就是一套现成的尺子,能直接反映模型输出和真实值之间的偏离程度。 常用的几个指标里,MSE(均方误差)和 MAE(平均绝对误差)最直观:MSE 对大偏差更敏感,MAE 则更抗异常点。如果模型在样本外连续多根 K 线 MSE 持续走高,说明过拟合概率偏大,该回炉重训。 这篇示例发布于 2023 年 12 月 18 日,在 MetaQuotes 官方渠道获得 1688 次查看,说明用回归指标评估 ONNX 预测精度是实盘前绕不开的一步。打开 MT5 终端,接好你的 .onnx 模型,先把历史回测的误差分布打出来,再决定要不要上真金白银——外汇和贵金属杠杆高,模型飘了就是实亏。
「回归衡量度与损失函数的边界」
回归任务的本质,是用一组未标记样本去逼近某个连续真实值。最直观的例子是按克拉重量、色泽、净度等特征估算钻石价格——输出不是分类标签,而是一个数值。 在建模时容易混淆两个概念:损失函数和回归衡量度。前者出现在你把建模转成优化问题时,比如梯度下降要求它可微、凸性好;后者是站在模型之外的客观准则,只看预测值与真值的偏差,不依赖模型内部参数。 实操意义很直接:调参阶段盯损失函数,模型定型后必须用衡量度(如 RMSE、MAE)做横向比较。把优化目标当成品判据,可能选出在训练集上乖巧但样本外偏差大的模型。外汇与贵金属预测属高风险场景,历史衡量度优不代表未来概率占优。
◍ MQL5 自带的七种回归误差指标
在 MT5 的策略回测与模型验证里,MQL5 已经内置了七类回归衡量度,足以覆盖从线性拟合到百分比偏差的常见诊断需求:平均绝对误差(MAE)、均方误差(MSE)、均方根误差(RMSE)、R 平方(R2)、平均绝对百分比误差(MAPE)、均方百分比误差(MSPE)以及均方根对数误差(RMSLE)。 这些指标并非摆设。比如 RMSE 对异常值更敏感,适合排查少数极端预测;MAPE 以百分比呈现,跨品种对比模型偏差时比 MAE 更直观。外汇与贵金属波动结构差异大,用同一组衡量度横向比较不同品种模型,需警惕尺度误导,属高风险操作。 目前 MQL5 公开的回归衡量度数量为 7 个,官方预计后续版本还会扩充。写 EA 或指标时,直接调用内置函数比手搓误差计算更稳,也方便和小布盯盘的输出做交叉验证。
回归误差指标怎么选不踩坑
MAE 量的是预测值跟实际值差多少,单位和目标函数一致。看它不能脱离数值区间:目标在 1~1.5 之间时平均绝对误差 10 就是离谱,但目标在 10000~15000 时就还能接受;它不适合扩散很大的样本。 MSE 靠平方给大误差加权,预测和现实差得越远越显眼。RMSE 继承了 MSE 的优点,但单位回到原尺度更好读,对异常尖峰敏感。RMSE 永远 ≥ MAE,两者差得越大说明样本里独立误差扩散越广;若 RMSE = MAE,则所有误差幅度一致。 R2 看两个随机变量的关系强度,模型全中就是 1,泛泛模型是 0,比乱猜还差可能为负。MAPE 无量纲,MQL5 里是小数,0.1 即真实值 10% 偏差,适合看相对偏离但不给真实量纲任务用。MSPE 是 MSE 的反平方加权版,观测值越大误差权重越小;RMSLE 用于跨数量级且不能为负的实际值。 外汇与贵金属波动大、杠杆高,这些指标只对历史样本说话,实盘仍属高风险,开 MT5 把 VectorRegressionMetric.mqh 拉进来跑一遍最直观。
「EURUSD D1 的四个 ONNX 回归模型」
实盘里接 ONNX 做日线收盘预测,这套方案用的是 4 个回归模型,输入都是 EURUSD 日线前一根已收盘的柱线,输出是当天收盘价预估。模型文件已经训好,命名对应不同窗口或结构:model.eurusd.D1.10、model.eurusd.D1.30、model.eurusd.D1.52、model.eurusd.D1.63,都随文打包在 zip 的对应目录里。 训练脚本放在 Python 子文件夹,想复训改参直接跑就行;外汇 EURUSD 波动受宏观与流动性影响,模型输出只是概率倾向,实盘前务必在 MT5 用历史数据回测验证。 之前几篇已经拆过 MQL5 里包装和调用 ONNX 的具体写法,这一节不重复训练规则,重点是把现成模型接进 EA 跑通日线级信号。
◍ 给 ONNX 包装类加上任意时间点预测能力
把推理从“只能看当前柱”解放出来,关键改动在基类的 PredictPrice 和 PredictClass 方法里塞进一个 datetime 参数。这样一来,预测向量既能用实时行情拼,也能拿历史某根 K 线的时间戳去回测,验证模型在过往时点的输出倾向。 下面这段头文件骨架定义了 CModelSymbolPeriod 基类,它按品种和时间周期绑定训练数据。注意 m_next_bar 只认柱开头,m_class_delta 默认 0.0001,用来在回归模型里界定“价格近似不变”的区间,外汇和贵金属波动下这个阈值可能要按点值重调。 代码里 PRICE_UP、PRICE_SAME、PRICE_DOWN 分别宏定义为 0、1、2,是分类模型的三态输出约定。构造函数接收 symbol、period 和 class_delta,析构直接调 Shutdown 释放模型会话句柄,避免 MT5 端会话泄漏。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| ModelSymbolPeriod.mqh | class=class="str">"cmt">//| Copyright class="num">2023, MetaQuotes Ltd. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- price movement prediction class="macro">#define PRICE_UP class="num">0 class="macro">#define PRICE_SAME class="num">1 class="macro">#define PRICE_DOWN class="num">2 class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Base class for models based on trained symbol and period | class=class="str">"cmt">//+------------------------------------------------------------------+ class CModelSymbolPeriod { class="kw">protected: class="type">class="kw">string m_name; class=class="str">"cmt">// model name class="type">long m_handle; class=class="str">"cmt">// created model session handle class="type">class="kw">string m_symbol; class=class="str">"cmt">// symbol of trained data ENUM_TIMEFRAMES m_period; class=class="str">"cmt">// timeframe of trained data class="type">class="kw">datetime m_next_bar; class=class="str">"cmt">// time of next bar(we work at bar begin only) class="type">class="kw">double m_class_delta; class=class="str">"cmt">// delta to recognize "price the same" in regression models class="kw">public: class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Constructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CModelSymbolPeriod(class="kw">const class="type">class="kw">string symbol,class="kw">const ENUM_TIMEFRAMES period,class="kw">const class="type">class="kw">double class_delta=class="num">0.0001) { m_name=""; m_handle=INVALID_HANDLE; m_symbol=symbol; m_period=period; m_next_bar=class="num">0; m_class_delta=class_delta; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Destructor | class=class="str">"cmt">//+------------------------------------------------------------------+ ~CModelSymbolPeriod(class="type">void) { Shutdown(); } class=class="str">"cmt">//+------------------------------------------------------------------+