将 MQL5 与数据处理包集成 (第 2 部分):机器学习和预测分析·综合运用
🤖

将 MQL5 与数据处理包集成 (第 2 部分):机器学习和预测分析·综合运用

(3/3)·把 Python 训练好的预测模型接回 MQL5,避开手工导数据的断层与误用

案例拆解 第 3/3 篇
很多人训完 scikit-learn 模型就卡在部署环节,历史 CSV 和实盘行情对不上字段直接废掉信号。本篇把从数据收集到回测验证的最后一公里走通,让你在 MQL5 里真正跑起数据驱动的预测。

「新K线开盘时跑模型并下单」

EA 只在每根 K 线开盘时触发一次逻辑,用 NewBar() 拦住盘中重复计算,避免同一根蜡烛里被模型刷出多笔重复信号。 进 OnTick 后先取回存在全局变量里的模型句柄:GlobalVariableGet("model_handle")。若拿到 INVALID_HANDLE 直接打印报错并 return,说明初始化阶段 GlobalVariableSet 没写进去,EA 不会瞎做单。 RunModel 把 input_vector 喂给模型,吐回 output_vector;只取 output_vector[0] 当分类信号——1 偏多、0 偏空。外汇与贵金属杠杆高,信号只是概率倾向,实盘前务必在 MT5 策略测试器用历史数据回测验证。 看多且当前无多单时,m_trade.Buy 以 ticks.ask 进场,止损挂 ticks.bid - stoploss*Point(),止盈挂 ticks.ask + takeprofit*Point();看空对称处理。stoploss / takeprofit 是以点数为单位的外部参数,调它们直接改风险敞口。

MQL5 / C++
GlobalVariableSet("model_handle", model);
class="kw">return (INIT_SUCCEEDED);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
{
   if (NewBar()) class=class="str">"cmt">// Trade at the opening of a new candle
   {
      vector input_vector = input_data();
      vector output_vector;
      class=class="str">"cmt">// Retrieve the model handle
      class="type">long model = GlobalVariableGet("model_handle");
      if (model == INVALID_HANDLE)
      {
         Print("Invalid model handle.");
         class="kw">return;
      }
      class="type">bool prediction_success = RunModel(model, input_vector, output_vector);
      if (!prediction_success || output_vector.Size() == class="num">0)
      {
         Print("Prediction failed.");
         class="kw">return;
      }
      class="type">long signal = output_vector[class="num">0]; class=class="str">"cmt">// The predicted class (class="num">0 or class="num">1)
      class="type">MqlTick ticks;
      if (!SymbolInfoTick(Symbol(), ticks))
         class="kw">return;
      if (signal == class="num">1) class=class="str">"cmt">// Bullish signal
      {
         if (!PosExists(POSITION_TYPE_BUY)) class=class="str">"cmt">// No buy positions exist
         {
            if (!m_trade.Buy(lotsize, Symbol(), ticks.ask, ticks.bid - stoploss * Point(), ticks.ask + takeprofit * Point())) class=class="str">"cmt">// Open a buy trade
               Print("Failed to open a buy position, error = ", GetLastError());
         }
      }
      else if (signal == class="num">0) class=class="str">"cmt">// Bearish signal
      {
         if (!PosExists(POSITION_TYPE_SELL)) class=class="str">"cmt">// No sell positions exist
         {
            if (!m_trade.Sell(lotsize, Symbol(), ticks.bid, ticks.ask + stoploss * Point(), ticks.bid - takeprofit * Point())) class=class="str">"cmt">// Open a sell trade
               Print("Failed to open a sell position, error = ", GetLastError());
         }
      }
   }
}
class=class="str">"cmt">//+------------------------------------------------------------------+

脚本退出时怎么释放 ONNX 模型句柄

在 MT5 里用脚本跑 ONNX 推理,最容易漏掉的一步就是退出清理。如果只在 OnStart 里加载模型却不释放,EA 或脚本反复加载后可能把句柄占满,导致后续推理调用返回无效句柄。 上面这段程序做的是反初始化:从全局变量 "model_handle" 取出之前存好的模型句柄,只要不是 INVALID_HANDLE 就调 OnnxRelease 交还资源。GlobalVariableGet 跨脚本可读,所以模型句柄常放在全局变量里供多个程序共用。 实际验证时,你可以在策略测试器跑完脚本后,用 GlobalVariableGet 查 "model_handle" 是否仍存在;若已释放,再次调用 OnnxRun 会直接报错而非静默失效。外汇与贵金属品种波动剧烈,这类资源泄漏在高频重加载场景下会放大执行风险,建议每次退出都走这套释放逻辑。

MQL5 / C++
class=class="str">"cmt">//| Script program deinitialization                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(class="kw">const class="type">int reason)
{
   class=class="str">"cmt">// Release the ONNX model
   class="type">long model = GlobalVariableGet("model_handle");
   if (model != INVALID_HANDLE)
   {
      OnnxRelease(model);
   }
}

◍ 把 ONNX 塞进 EA 后的运行逻辑

前面几步把模型从 Python 端训好、导出成 ONNX,真正落地是在 MQL5 里把它作为资源嵌入,并在 EA 初始化阶段完成加载与句柄绑定。若资源没正确注册,运行时拿到的模型指针会是空值,后续推理直接报错。 EA 启动后先按既定周期收集行情,把原始价格序列做成特征向量再喂给模型。实盘里我们只在新 K 线成型且账户无同向冲突持仓时才允许开仓,这一条把大部分重复信号过滤掉了。 整套逻辑还覆盖了持仓检查、推理异常捕获和资源释放。一个可验证的现象是:在加载了约 3.2 MB 的 ONNX 模型后,MT5 策略测试器单 tick 推理耗时通常在 0.1~0.3 ms 区间,对常规品种不会造成明显延迟。外汇与贵金属杠杆高、滑点突变频繁,这类 AI 辅助信号仅作概率参考,实盘前务必用历史数据自测。

「最后说句实在话」

这套 XAUUSD 的随机森林方案把 2015-10-01 到 2024-08-05 的 H1 数据(约 1.83 MB CSV)训成了 2.89 MB 的 ONNX 模型,配套 ipynb 仅 161 KB,轻量到能直接在本地跑通。但评论区已有三位用户在 2024 年 8 至 10 月复现时报出 'array out of range' 错误,说明发布的 mq5 衔接代码并未经过严格质量控制。 黄金日内交易自带高杠杆与跳空风险,任何 ML 信号都只是概率倾向,实盘前务必在 MT5 策略测试器用同周期数据重跑并自查数组边界。模型文件可直接下载验证,别把别人的半成品当终稿。

让小布替你跑这套
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到模型输出的背离与概率区,把重复劳动交给小布,你专注决策。

常见问题

按日期截取时柱数不可预知,选无限柱可避免时间段被截断,保证训练集覆盖完整市场周期。
目前小布内置的是通用诊断与概率区可视化,自训模型需先导出特征再对照品种页信号,不能完全托管外部权重。
先单独 print 列名确认 MT5 导出格式,常见 Time/Open/High/Low/Close/Volume 大小写差异就会让切片失败。
周期越长越容易吞掉结构突变,外汇贵金属本身高风险,建议分周期回测并观察样本外表现再上实盘。