您应当知道的 MQL5 向导技术(第 51 部分):配以 SAC 的强化学习·综合运用
📘

您应当知道的 MQL5 向导技术(第 51 部分):配以 SAC 的强化学习·综合运用

第 3/3 篇

「用 ONNX 跑强化学习信号推断的坑」

把训练好的 SAC actor 网络塞进 MT5,靠 OnnxRun 做推断前,必须先锁死输入输出张量形状。OnnxSetInputShape 用 ONNX_DEFAULT 配 _actor_in_shape,输出用 OnnxSetOutputShape(m_actor_handle, 0, _actor_out_shape);任何一步返回 false 就直接退出,否则后面推理会拿空矩阵硬跑。 GetOutput 里实际拉数据的是 H1 与 D1 两个周期、各取 shift 0 和 1 的两根 8 长度序列:_in_row 减 _in_row_old、_in_col 减 _in_col_old,得到两段差分状态。环境判定交给 Cql 实例,Environment() 吐出 _e[0] 作为 _x_states[0] 喂给网络。 推断时 _y_mu_logstd 是 6×1 的 matrixf,OnnxRun 用 ONNX_NO_CONVERSION 模式;失败就 Print 错误并返回全 0 的 _out(动作数由 __ACTIONS 定),成功才拆出 _mu 和 _logstd 各 __ACTIONS 长度。外汇和贵金属这种高波动品种,RL 信号只代表概率倾向,实盘前务必在策略测试器用历史数据回测验证形状匹配。

MQL5 / C++
  class="kw">return(false);
  }
  if(!OnnxSetInputShape(m_actor_handle, ONNX_DEFAULT, _actor_in_shape))
  {  Print("Actor OnnxSetInputShape error ", GetLastError());
     class="kw">return(false);
  }
  if(!OnnxSetOutputShape(m_actor_handle, class="num">0, _actor_out_shape))
  {  Print("Actor OnnxSetOutputShape error ", GetLastError());
     class="kw">return(false);
  }
class=class="str">"cmt">//read best weights
class=class="str">"cmt">//--- ok
   class="kw">return(true);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| This function calculates the next actions to be selected from    |
class=class="str">"cmt">//| the Reinforcement Learning Cycle.                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
vectorf CSignalSAC::GetOutput()
{  vectorf _out;
   class="type">int _load = class="num">1;
   class="kw">static vectorf _x_states(class="num">1);
   _out.Init(__ACTIONS);
   _out.Fill(class="num">0.0);
   vector _in, _in_row, _in_row_old, _in_col, _in_col_old;
   if
   (
       _in_row.Init(_load) &&
       _in_row.CopyRates(m_symbol.Name(), PERIOD_H1, class="num">8, class="num">0, _load) &&
       _in_row.Size() == _load
       &&
       _in_row_old.Init(_load) &&
       _in_row_old.CopyRates(m_symbol.Name(), PERIOD_H1, class="num">8, class="num">1, _load) &&
       _in_row_old.Size() == _load
       &&
       _in_col.Init(_load) &&
       _in_col.CopyRates(m_symbol.Name(), PERIOD_D1, class="num">8, class="num">0, _load) &&
       _in_col.Size() == _load
       &&
       _in_col_old.Init(_load) &&
       _in_col_old.CopyRates(m_symbol.Name(), PERIOD_D1, class="num">8, class="num">1, _load) &&
       _in_col_old.Size() == _load
   )
   { _in_row -= _in_row_old;
     _in_col -= _in_col_old;
     Cql *QL;
     Sql _RL;
     _RL.actions   = __ACTIONS;class=class="str">"cmt">//buy, sell, do nothing
     _RL.environments = __ENVIONMENTS;class=class="str">"cmt">//bullish, bearish, flat
     QL = new Cql(_RL);
     vector _e(_load);
     QL.Environment(_in_row, _in_col, _e);
     class="kw">delete QL;
     _x_states[class="num">0] = class="type">class="kw">float(_e[class="num">0]);
     class="kw">static matrixf _y_mu_logstd(class="num">6, class="num">1);
class=class="str">"cmt">//--- run the inference
     ResetLastError();
     if(!OnnxRun(m_actor_handle, ONNX_NO_CONVERSION, _x_states, _y_mu_logstd))
     {  Print("Actor OnnxConversion error ", GetLastError());
        class="kw">return(_out);
     }
     else
     {  vectorf _mu(__ACTIONS), _logstd(__ACTIONS);
        _mu.Fill(class="num">0.0); _logstd.Fill(class="num">0.0);

从网络输出拆出动作均值与对数标准差

这段循环把策略网络吐出的二维数组拆成两条平行向量:前 __ACTIONS 个位置存均值 _mu,偏移 __ACTIONS 之后的位置存对数标准差 _logstd。注意下标 i+__ACTIONS 的写法,它直接把同一张 _y_mu_logstd 矩阵的后半段映射成波动率参数,没有另开缓冲区。 拆完之后立刻丢进 LogProbabilities(_mu, _logstd) 算对数概率,返回值 _out 就是该状态下各动作的高斯对数似然。在 MT5 里把 __ACTIONS 设成你实际下单维度(比如 3 档仓位比例),跑一遍能在专家日志看到 _mu 与 _logstd 的数值范围,借此判断网络是否塌成常数。 外汇与贵金属杠杆高,这类概率输出只代表模型倾向,实盘前务必用历史Tick校验分布漂移。

MQL5 / C++
for(class="type">int i=class="num">0;i<__ACTIONS;i++)
  { _mu[i] = _y_mu_logstd[i][class="num">0];
    _logstd[i] = _y_mu_logstd[i+__ACTIONS][class="num">0];
  }
  _out = LogProbabilities(_mu, _logstd);
  }
  }
  class="kw">return(_out);
}

◍ 画得少,看得清

上面这套 SAC 基础实现没依赖张量智代函数库,好处是你能直接看清反向传播为什么慢——多个网络配对训练,且根本没有典型训练数据集可用。 熵项由 alpha 参数调制,作用是在探索时留安全余量;当前 demo 用的是固定 alpha,概率上限制了策略自适应探索的深度。 建议你在 MT5 里把 alpha 改成随目标熵自动调整,附件里 WZ_51.mq5(6.19 KB)和 SignalWZ_51.mqh(10.32 KB)配合三个 ONNX 网络可直接拖进向导编译验证。外汇与贵金属波动剧烈,这类实验策略仅作技术参照,实盘前务必自测风险。

常见问题

检查网络训练时的状态向量长度与推理时喂入的特征数是否一致,多数坑出在归一化步骤被遗漏或顺序错位,建议先打印两端 shape 对比。
输出层通常前 N 维是均值、后 N 维是对数标准差,按索引切分即可;采样动作时用均值加标准差乘随机噪声,别直接拿均值当信号。
可以,小布能读取你的策略文件结构并提示输入维度、输出切分和归一化的一致性异常,把重复核对交给它省时间。
会,建议只保留动作均值线加阈值带,把对数标准差转成背景色块,画得少才看得清关键翻转。
若状态窗口设得长就可能滞后,可缩短回看步数或用更高帧率数据重训;外汇贵金属高风险,信号仅作概率参考。