您应当知道的 MQL5 向导技术(第 45 部分):蒙特卡洛强化学习·进阶篇
◍ 蒙特卡洛信号类的骨架与可调旋钮
这段继承自 CExpertSignal 的 CSignalMC 类,把蒙特卡洛强化学习塞进了 MT5 信号模块。它不像常规指标那样算均线,而是靠环境矩阵和回合奖励去推导买卖动作,外汇与贵金属品种上属于高风险试探,实盘前务必在策略测试器跑通。 保护变量里先铺好维度:m_actions 是马尔可夫可选动作数,m_environments 是环境矩阵单边长度,m_scale 控制行到列的缩放比例。m_epsilon 管探索概率,m_policy 切换 on/off policy,m_episode_cycles 定一个回合的步数——这些直接决定模型是保守跟随还是乱撞寻优。 对外暴露的 setter 极简:QL_Scale(int) 只改 m_scale,QL_Markov(bool) 切马尔可夫开关,QL_Epsilon(bool) 写 m_epsilon。注意原文 QL_Epsilon 参数类型标了 bool,但变量 m_epsilon 是 double,复制时若想做 0.1 这类渐进探索率得自己改签名,否则只能是非零即满探索。 奖励回传那几行是核心回路:按 gamma 的 (回合步数-1-i) 次幂折扣累加 Rewards[i],再依据 m_policy 分流进 SetOnPolicy 或 SetOffPolicy。折扣因子越接近 1,远期奖励权重越高,EURUSD 回测里常看到滞后信号被放大。
{ _reward += pow(QL.THIS.gamma, m_episode_cycles - class="num">1 - i) * Rewards[i];
}
if(m_policy)
{ QL.SetOnPolicy(_reward, _in_e);
}
else if(!m_policy)
{ QL.SetOffPolicy(_reward, _in_e);
}
}
}
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| MCs CSignalMC. |
class=class="str">"cmt">//| Purpose: MonteCarlo for Reinforcement-Learning. |
class=class="str">"cmt">//| Derives from class CExpertSignal. |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CSignalMC : class="kw">public CExpertSignal
{
class="kw">protected:
class="type">int m_actions; class=class="str">"cmt">// LetMarkov possible actions
class="type">int m_environments; class=class="str">"cmt">// Environments, per matrix axis
class="type">int m_scale; class=class="str">"cmt">// Environments, row-to-col scale
class="type">bool m_use_markov; class=class="str">"cmt">// Use Markov
class="type">class="kw">double m_epsilon; class=class="str">"cmt">// Epsilon
class="type">bool m_policy; class=class="str">"cmt">// On Policy
class="type">int m_episode_cycles;class=class="str">"cmt">// Episode Size
class="kw">public:
class="type">void CSignalMC(class="type">void);
class="type">void ~CSignalMC(class="type">void);
class=class="str">"cmt">//--- methods of setting adjustable parameters
class="type">void QL_Scale(class="type">int value)
{ m_scale = value;
}
class="type">void QL_Markov(class="type">bool value)
{ m_use_markov = value;
}
class="type">void QL_Epsilon(class="type">bool value)
{ m_epsilon = value;
}强化学习交易类的接口与成员落地
这段声明把一套 QL 策略骨架直接摊开在 MT5 自定义信号类里。两个 setter 把策略开关和回合数塞进成员变量,训练节奏和在线/离线决策由此分离。 void QL_Policy(bool value) { m_policy = value; } void QL_EpisodeCycles(int value) { m_episode_cycles = value; } 上面两段就是最直白的写入接口:Policy 为真时倾向走学习策略,EpisodeCycles 控制单轮训练步数,默认不传就容易让代理一直用初始随机权重瞎跑。 //--- method of verification of arch virtual bool ValidationSettings(void); //--- method of creating the indicator and timeseries virtual bool InitIndicators(CIndicators *indicators); //--- methods of checking if the market models are formed virtual int LongCondition(void); virtual int ShortCondition(void); 这几个虚函数把架构校验、指标初始化和多空条件判断全留给子类实现。LongCondition 返回大于 0 才认为多头模型成立,实盘里若返回恒为 0,EA 就不会开多——这是排查信号失效的第一道闸。 protected: void GetOutput(Cql *QL, vector &Rewards); Sql RL; Cql *QL_BUY, *QL_SELL; vector REWARDS_BUY, REWARDS_SELL; 保护段里挂了买/卖两套 Q 学习指针和对应奖励向量。REWARDS_BUY 与 REWARDS_SELL 分开存,意味着多空奖励函数可以非对称设计;外汇和贵金属波动剧烈,这种分离对控制单边滑点损耗有实际意义,但杠杆品种的高风险仍在。开 MT5 把这段塞进你的 CSignal 派生类,先只改 EpisodeCycles 从 0 设到 200,看回测里训练收敛步数落在哪段。
class="type">void QL_Policy(class="type">bool value) { m_policy = value; } class="type">void QL_EpisodeCycles(class="type">int value) { m_episode_cycles = value; } class=class="str">"cmt">//--- method of verification of arch class="kw">virtual class="type">bool ValidationSettings(class="type">void); class=class="str">"cmt">//--- method of creating the indicator and timeseries class="kw">virtual class="type">bool InitIndicators(CIndicators *indicators); class=class="str">"cmt">//--- methods of checking if the market models are formed class="kw">virtual class="type">int LongCondition(class="type">void); class="kw">virtual class="type">int ShortCondition(class="type">void); class="kw">protected: class="type">void GetOutput(Cql *QL, vector &Rewards); Sql RL; Cql *QL_BUY, *QL_SELL; vector REWARDS_BUY, REWARDS_SELL; };
「把蒙特卡洛装进信号类的多空投票」
自定义信号类里跑蒙特卡洛强化学习,核心是把 Q-映射当根模型,再用 LongCondition / ShortCondition 做多空方向的「投票」。上面两个函数就是做多和做空条件的落地写法,完整源码挂在类底部,向导里拼 EA 的流程另行参考。 马尔可夫决策过程本就内嵌在 Q-映射里,但实盘里留了一个输入开关,决定 Q-值更新时是否加马尔可夫权重。另外 ε 大小、探索与利用的配比、单局回合数都能进优化器去跑。 我们拿 GBPUSD 的 2022 年 H1 数据做了优化,外汇品种波动剧烈、杠杆高风险突出,结果仅代表该样本区间的概率倾向,不等于后续行情必然复现。 下面这段是做多/做空条件的原始代码,逐行拆一下: CSignalMC::LongCondition 先给 result 置 0,调用 GetOutput(QL_BUY, REWARDS_BUY) 算出买权 Q 输出;若 QL_BUY.transition_act 等于 0,就投出 100 分看多票,否则返回 0。 CSignalMC::ShortCondition 同理,GetOutput(QL_SELL, REWARDS_SELL) 后检查 QL_SELL.transition_act 是否等于 2,命中则返回 100 分看空票,未命中返回 0。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| "Voting" that price will grow. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int CSignalMC::LongCondition(class="type">void) { class="type">int result = class="num">0; GetOutput(QL_BUY, REWARDS_BUY); if(QL_BUY.transition_act == class="num">0) { result = class="num">100; } class="kw">return(result); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| "Voting" that price will fall. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int CSignalMC::ShortCondition(class="type">void) { class="type">int result = class="num">0; GetOutput(QL_SELL, REWARDS_SELL); if(QL_SELL.transition_act == class="num">2) { result = class="num">100;class=class="str">"cmt">//printf(__FUNCSIG__); } class="kw">return(result); }
◍ 把这条线请下神坛
蒙特卡洛这套强化学习思路,说白了是把 Q-学习和 SARSA 的长期环境感知揉进了一个更动态更新的框架里,但它绝不是点石成金的圣杯。自定义环境矩阵之外,把动作量表扩到三个以上选项,也只是把状态-行动空间摊得更开,不保证样本外还能稳。 偏差和方差的拉扯很实在:局内周期少(m_episode_cycles 偏小)往往高偏差低方差,模型容易贴着短期动作跑;周期拉长的局次反过来,高方差更能咬住长期特征。你在 MT5 里调 wz_45.mq5 的 m_episode_cycles,能直接看到信号强度随回报范围变粗变细。 多 n 步回报让入场离场的判定粒度更细,这点对贵金属和外汇这类高杠杆品种尤其要手稳——参数掠一下可能回测漂亮,实盘就是另一回事。开 MT5 把 SignalWZ_45.mqh 挂上,先跑小周期验证再谈放大,别把文献里的动态适应当成免死金牌。