神经网络变得轻松(第三十部分):遗传算法·综合运用
「训练循环里的样本门槛与奖励构造」
这段逻辑跑在 MT5 的模型训练主循环里,先卡样本量:若状态容器总数不足 HistoryBars 的 12 倍就直接 continue 跳过,避免用太少数据喂前馈网络导致权重失真。 前馈推理用 Models.feedForward(State, 12, true) 做 12 步预测,任一环节失败就打印函数名与行号并 break,方便在专家日志里定位断点。 奖励信号按单根 K 线实体计算:reward = 收盘价 - 开盘价。TempData 里塞了三组浮点——亏时放大 20 倍负收益、赚时记 20 倍反向惩罚、再加一个 -fabs(reward) 的绝对损失项,这种不对称设计倾向让网络更怕回撤。 进度显示用 GetTickCount64 节流,每超过 250 毫秒才刷新一次 Comment,算出剩余样本占比 perc = x*100.0/(total-test_size),实盘跑时你能直接盯着这个百分比估剩余时间。 一代训完调 Models.NextGeneration 做 quantile 淘汰与变异,打印平均累计奖励和最大奖励;最后 SaveModel 落盘 .nnw,调 ExpertRemove 结束EA。外汇与贵金属波动剧烈,这类强化学习模型过拟合概率高,上真仓前务必用历史数据复跑验证。
if(State.Total() < (class="type">int)HistoryBars * class="num">12) class="kw">continue; if(!Models.feedForward(State, class="num">12, true)) { PrintFormat("%s -> %d", __FUNCTION__, __LINE__); class="kw">break; } class="type">class="kw">double reward = Rates[i - class="num">1].close - Rates[i - class="num">1].open; TempData.Clear(); if(!TempData.Add((class="type">class="kw">float)(reward < class="num">0 ? class="num">20 * reward : reward)) || !TempData.Add((class="type">class="kw">float)(reward > class="num">0 ? -reward * class="num">20 : -reward)) || !TempData.Add((class="type">class="kw">float) - fabs(reward))) { PrintFormat("%s -> %d", __FUNCTION__, __LINE__); class="kw">break; } if(!Models.Rewards(TempData)) { PrintFormat("%s -> %d", __FUNCTION__, __LINE__); class="kw">break; } if(GetTickCount64() - ticks > class="num">250) { class="type">uint x = total - i; class="type">class="kw">double perc = x * class="num">100.0 / (total - test_size); Comment(StringFormat("%d from %d -> %.2f%% from %.2f%%", x, total - test_size, perc, class="num">100)); ticks = GetTickCount64(); } } Models.SaveModel(MODEL+".nnw", -class="num">1, class="kw">false); class="type">class="kw">double average, maximum; if(!Models.NextGeneration(Quantile, Mutation, average, maximum)) { PrintFormat("Error of create next generation: %d", GetLastError()); PrintFormat("%s -> %d", __FUNCTION__, __LINE__); class="kw">break; } class=class="str">"cmt">//--- PrintFormat("Genegation %d, Average Cumulative reward %.5f, Max Reward %.5f", gen, average, maximum); } class="kw">delete State; Comment(""); class=class="str">"cmt">//--- ExpertRemove(); }
用留出月份验证概率分布模型
训练用的样本是 EURUSD H1 过去 2 年历史,EA 全部走默认参数,优化架构沿用上一篇文章里搜决策最佳概率分布的那套,等效替换成此前用过的 REINFORCE-test.mq5。这是同一体系结构第三种训练路数,前两种分别是策略梯度和扮演者-评价者,所以横向比结果才有意义。 优化时特意扣掉最近一个月不出场,留作样本外测试。把优化完的模型丢进策略测试器,跑出来的余额曲线整体向上,但盈利水平比扮演者-评价者那版略低,而且成交稀疏——交易次数大概只有前者的一半。 切到品种图表看成交点,模型明显在顺着趋势做,不像梯度法那版在杂波里乱开仓。这跟‘顺势’的常识对得上,但也可能只是我看图附会,你最好自己跑一遍核对。 硬指标上,相比扮演者-评价者测试,盈利交易占比高了近 1.5%,代价是交易次数砍半、单笔平均损益下滑,整段期间总盈利随之走低。只测第 1 个月不能外推长期,外汇和贵金属杠杆高、回撤凶,上实盘前务必自己用 MT5 多周期重测。
◍ 遗传优化落地前的最后一道关
前面几节把遗传算法在 MQL5 里的实现和测试模型跑通了,策略测试器里能看到优化后的参数组合确实比初始随机值更收敛。 从回测现象看,这套不可微模型的优化路径在测试模型上收敛稳定,说明遗传法替代梯度下降在交易参数搜索里是可行路线。 但外汇和贵金属市场高波动、高杠杆,实盘和回测的分布偏移可能很大。把模型搬上真实账户前,建议用不同年份行情分段重跑优化,确认参数鲁棒性再考虑实盘。
「顺着这几篇往下啃」
想把强化学习在 MQL5 里的落地吃透,前面几篇是绕不开的台阶。第二十六部分先铺了强化学习的基础框架,第二十七部分直接上深度 Q-学习(DQN),把 Q 值逼近交给神经网络。 第二十八部分讲政策梯度算法,思路从「算值」转到「直接优化策略分布」;第二十九部分用优势扮演者-评价者(A2C)把价值评估与策略更新拆成两套网络协同。 这几篇在 MT5 策略测试器里都能找到对应示例代码,建议开终端把第二十七篇的 DQN 样例跑一遍,先确认自己环境里特征归一化区间和原文一致,再改隐藏层节点数看回测曲线漂移。外汇与贵金属品种波动跳空频繁,强化学习策略过拟合风险高,任何回测优势都只是概率倾向。
随包附带的五个工程文件
这篇 LSTM 优化实操里,真正要落到 MT5 上跑的并非一篇文章,而是一组工程文件。压缩包 MQL5.zip(680.14 KB)里含 5 个关键件:Genetic.mq5 是做模型优化的 EA;NetGenetic.mqh 实现遗传算法函数;REINFORCE-test.mq5 负责在策略测试器里验模型;NeuroNet.mqh 与 NeuroNet.cl 分别用类库和 OpenCL 代码建神经网络。 读者直接把 ZIP 解到 MT5 的 MQL5 目录即可调用。需留意:评论区有用户反馈 Genetic EA 报 5109(ERR_OPENCL_EXECUTE),这是 OpenCL 运行期错误,说明本机显卡或驱动未正确提供 OpenCL 支撑,外汇与贵金属行情的高波动下任何模型都只是概率工具,实盘前务必在策略测试器先跑通。 作者在原讨论里点过一句实操细节:给 EA 一个常规模型,它会用结构相似的模型自动补全成整个模型群,不必手搓全部网络。想验证效果,先确认显卡 OpenCL 状态,再加载 REINFORCE-test.mq5 做回测,比空读结论更有用。