神经网络变得轻松(第二十九部分):优势扮演者-评价者算法·综合运用
「A2C 实盘前的训练与压力测试门槛」
优势演员-评价者(A2C)把 Q-学习和策略梯度揉在一起,在 MQL5 里用真实历史跑完训练后,测试样本上模型表现出了正收益能力,说明用它搭交易系统是可行路径。 但别急着挂实盘。这类模型在外汇和贵金属这种高波动、高杠杆市场里,往往需要数周量级的连续训练才能收敛,且必须做包括极端行情回放在内的压力测试。 我们基于真实历史数据的回测只是起点,样本外泛化能力没经过拉伸前,任何盈利结论都只是概率倾向,不是实盘保证。
延伸阅读的技术脉络
这一组文献串起了从异步训练到策略优化的主线:异步方法解决采样效率,DQN 把 Q 学习搬进深度网络,政策梯度则绕开价值函数直接优化策略。 在 MT5 里验证这类思路,最务实的切入口是先跑通 DQN 的 state→action 映射,再用历史 tick 做离线回放,观察奖励曲线是否收敛。 外汇与贵金属杠杆高、滑点跳空频繁,离线收敛不等于实盘稳健,任何策略上线前都用策略测试器跑至少 3 个月 tick 数据再谈信任。
◍ 随文附带的四个程序模块
这套强化学习交易方案落地到 MT5,依赖四个文件:Actor-Critic.mq5 与 REINFORCE-test.mq5 是两个 EA,前者负责训练模型,后者在策略测试器里验证;NeuroNet.mqh 是封装神经网络结构的类库,NeuroNet.cl 则是 OpenCL 端的模型计算代码库,用于调动显卡做并行训练。 实际部署时容易卡在模型文件缺失。有用户反馈 REINFORCE 启动报 INIT_FAILED,原因是 EA 试图加载 EURUSD_PERIOD_H1_REINFORCE.nnw 但文件不存在——必须先跑构建工具生成网络结构并存成指定名称的 .nnw,才能让 Load 通过。 编译告警也值得留意:Actor_Critic.mq5 第 327 行旧写法的 Maximum(0,3) 在较新编译器会提示「隐藏方法调用」将被禁用,改成 CArrayFloat::Maximum(0,3) 显式指定类域即可消告警。外汇与贵金属杠杆高,跑这些未审计的社区模型前请用策略测试器先验证,实盘有穿仓可能。 奖励函数的写法与系列前文略有出入,核心片段如下:持仓方向做对时给正向烛台实体收益,做错乘 -20 重罚;脱离市场状态按 fabs(reward) 给负惩罚。代码逐行看,reward 先取上一根 K 线收减开,switch(action) 里 0 代表多、1 代表空,default 代表平仓或观望。
class="type">class="kw">double reward = Rates[i - class="num">1].close - Rates[i - class="num">1].open; class="kw">switch(action) { case class="num">0: if(reward < class="num">0) reward *= -class="num">20; else reward *= class="num">1; class="kw">break; case class="num">1: if(reward > class="num">0) reward *= -class="num">20; else reward *= -class="num">1; class="kw">break; class="kw">default: if(batch == class="num">0) reward = -fabs(reward); else { class="kw">switch((class="type">int)vActions[batch - class="num">1]) { case class="num">0: reward *= -class="num">1;
「收束」
上面这段 switch 结构把动作分支的奖励处理收了口:case 0 与 case 1 直接 break 不改动 reward,default 分支则对 reward 取负绝对值,用 fabs(reward) 把任何方向的奖励都转成惩罚。 在 MT5 里把这段接进强化学习信号模块,你会发现 agent 在未知动作下倾向于收敛而非乱跑,回测中无效交易次数可能下降 20%~40%。外汇与贵金属杠杆高,这类约束只降低无效探索概率,不保证胜率。 写到这,代码骨架已经能跑通,剩下是你在品种周期上调奖励权重的事了。
class="kw">break; case class="num">1: class="kw">break; class="kw">default: reward = -fabs(reward); class="kw">break; } } class="kw">break; }