MQL5交易策略自动化(第二十一部分):借助自适应学习率提升神经网络交易效果(基础篇)
「用自适应学习率喂饱你的神经网络」
在 MT5 里跑神经网络策略,最容易被忽略的其实是学习率。固定学习率要么收敛慢,要么在损失平面陡峭处直接发散,尤其外汇和贵金属这种高波动品种,过拟合风险被放大数倍。
MQL5 的 CNeuralNet 类允许在训练循环里动态改学习率。下面这段把学习率做成随 epoch 衰减的形式,能让网络在前期快速下降、后期微调权重。
class="type">class="kw">double lr = class="num">0.1; class=class="str">"cmt">// 初始学习率 class="type">int epochs = class="num">1000; class=class="str">"cmt">// 训练轮数 for(class="type">int e=class="num">0; e<epochs; e++) { lr = class="num">0.1 * (class="num">1.0 - e/epochs); class=class="str">"cmt">// 线性衰减 net.Train(data, lr); class=class="str">"cmt">// 用当前 lr 训练 }
lr=0.1 定了个不算激进的起点;epochs=1000 给足迭代空间;循环里 lr = 0.1 * (1.0 - e/epochs) 让学习率从 0.1 线性滑到 0,第 500 轮时约 0.05;net.Train 每轮吃新 lr。实盘前建议把这套丢进 MT5 策略测试器,用 2023—2025 年 XAUUSD 的 M15 数据跑一遍,观察 equity 曲线震荡是否收窄。外汇与贵金属杠杆高,模型表现可能随行情结构突变而失效,务必小仓验证。
class="type">class="kw">double lr = class="num">0.1; class=class="str">"cmt">// 初始学习率 class="type">int epochs = class="num">1000; class=class="str">"cmt">// 训练轮数 for(class="type">int e=class="num">0; e<epochs; e++) { lr = class="num">0.1 * (class="num">1.0 - e/epochs); class=class="str">"cmt">// 线性衰减 net.Train(data, lr); class=class="str">"cmt">// 用当前 lr 训练 }
◍ 从 CCI+AO 策略切到神经网络
上一组多品种策略用 CCI 叠加 AO 做趋势反转,在 MQL5 里跑通了信号生成与风控,覆盖多个货币对。这一节起换赛道:把神经网络搬进 EA,重点不在网络结构本身,而是给学习率做自适应。 市场状态切换时固定学习率容易过冲或收敛慢,动态调参能抬升走势预测的概率准确性。本篇要落三件事:搞懂自适应学习率的逻辑、在 MQL5 里写进去、回测里调出合适区间。 外汇与贵金属波动受事件驱动明显,神经网络预测只是概率倾向,实盘前务必在 MT5 策略测试器用历史数据验证过拟合风险。
让学习率跟着误差跑
神经网络做价格方向预测,核心不在网络多深,而在权重怎么更新。反向传播从输出层往回算预测误差,再调权重和偏置;学习率决定每一步调多大。固定学习率要么在平稳段学太慢,要么在剧烈波动段调过头把模型带偏。 自适应策略的思路很直接:权重更新方向跟实际走势吻合时,调大学习率抢精度;误差突然放大时,调小学习率保稳定。这套机制配合 sigmoid 激活函数(输出压到 0~1,对应买/卖二类判断)和隐藏层神经元数量随 ATR 波动性伸缩,网络才不至于在贵金属跳空时直接废掉。 实盘验证可这样搭:输入层喂两条 MA、RSI、ATR,隐藏层用 sigmoid 做非线性变换,输出层出方向信号。外汇与贵金属杠杆高、滑点随机,自适应只降低过拟合概率,不消除爆仓风险,开 MT5 用策略测试器跑 2020–2023 年 XAUUSD 的 M15 先看权重收敛曲线再上真金。
「MT5里搭自适应神经网络指标骨架」
打开 MetaEditor,在导航器「指标」目录点新建走向导,先别写逻辑,把 OOP 框架和输入参数声明好。引入 Trade.mqh 并实例化 CTrade 的 tradeObject,后面神经网络出信号就靠它发单。 输入参数直接决定策略边界:LotSize 控仓,StopLossPoints / TakeProfitPoints 管风险,MinHiddenNeurons~MaxHiddenNeurons 框住隐藏层宽度,TrainingBarCount 定训练样本根数,MinPredictionAccuracy 是信号放行阈值,MinLearningRate~MaxLearningRate 锁死自适应步长区间。权重偏置用 InputToHiddenWeights 等四个字符串灌进去,不填就走默认随机。 网络常量先钉死:INPUT_NEURON_COUNT=10(接 MA20/MA50/RSI/ATR 等市场特征),OUTPUT_NEURON_COUNT=2(买/卖双输出),MAX_HISTORY_SIZE=10(记准确率与误差)。四个指标句柄 ma20 / ma50 / rsi / atr 分别 CopyBuffer 喂数据,TrainingData 结构体拿 inputValues 和 targetValues 两个数组存样本,顺序不能乱。 CNeuralNetwork 类把架构全收进私有成员:三层神经元数、三层数组、权重矩阵、偏置数组,再加 outputDeltas / hiddenDeltas 存反向传播梯度。trainingError 跟 currentLearningRate 实时走,accuracyHistory / errorHistory 各留 10 条做趋势判断。 ParseStringToArray 是权重字符串入口:空串或逗号拆分后长度不对就 Print 报错返 false;正常则用 StringToDouble 转双精度,MathMax/MathMin 压到 [-1,1]。公开接口里构造函数吃 inputs/hidden/outputs,InitializeWeights 区分「外部灌参」与「MathRand 随机 -1~1」两条路,Sigmoid 用 MathExp 算激活。 前向 ForwardPropagate 算加权和过 Sigmoid,反向 Backpropagate 拿 targets 算 delta 并用 currentLearningRate 更新权重偏置。AdjustLearningRate 看 errorHistory 末两项:误差降了步长 +5% 封顶 Max,涨超 20% 步长 -10% 保底 Min,其余微调 -1%,这条规则让外汇贵金属这种高波动品种的训练不易发散。 隐藏层神经元数跟着 ATR 跑:CopyBuffer 拉最近 10 根 atrValues 并 ArraySetAsSeries 成时间序列,avgATR 求均值,atrValues[0]/iClose 得波动比率,缩放进 Min~Max 区间返回。波动一扩隐藏层就加宽,模型容量跟着行情走。
◍ MT5里搭一个能自训的神经网络EA骨架
这段实现把神经网络的训练、更新与EA生命周期绑死了。TrainOnHistoricalData 里最大训练轮次写死 100,目标误差 0.01,currentLearningRate 重置为 MinLearningRate;每轮遍历 TrainingData,用 ForwardPropagate 算预测、MathPow 算输出层误差,Backpropagate 回传,准确率与 trainingError 达标就提前终止。 UpdateNetworkWithRecentData 取最近 10 根 K 线(recentBarCount=10)做增量训练,GetRecentAccuracy / GetRecentError 从 history 数组取最新值,记录为空返回 0.0。ShouldRetrain 要求 historyRecordCount≥2,把近期 accuracy 和 error 与 MinPredictionAccuracy 及前次误差的 1.5 倍比较,决定重训与否。 PrepareInputs 用 ArrayResize 把 inputs 对齐 INPUT_NEURON_COUNT,四个指标数组经 ArraySetAsSeries 转时间序列,CopyBuffer 取 MA20/MA50/RSI/ATR 各两根 K 线;特征含标准化价差、MA 偏差、0~1 缩放 RSI、相对收盘的 ATR(MathAbs 防除零)、高低区间比。CollectTrainingData 要求 OUTPUT_NEURON_COUNT=2,按 barCount 根 K 线填结构体,目标值由价格走势标定。 OnInit 中 iMA 建 20/50 周期 SMA、iRSI(14)、iATR(14),任一句柄 INVALID_HANDLE 就打印 GetLastError 并返回 INIT_FAILED;随后 new CNeuralNetwork 配网络结构,NULL 同样失败。OnDeinit 用 IndicatorRelease 清指标句柄、delete 清网络实例,不删会内存泄漏。 OnTick 每根新 K 线只跑一次:CalculateDynamicNeurons 算隐藏数,变了就 ResizeNetwork;超 12 小时或 ShouldRetrain 为真就 TrainNetwork。无持仓时 PrepareInputs 填 currentInputs,ForwardPropagate 出 outputValues,CONFIDENCE_THRESHOLD=0.8,outputValues[0] 超阈值且 [1] 低于补数则 tradeObject.Buy,反之 Sell。外汇与贵金属杠杆高、滑点跳空频繁,这套信号仅作概率参考,实盘前务必在 MT5 策略测试器跑回测。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Neural Networks Propagation EA.mq5 | class=class="str">"cmt">//| Copyright class="num">2025, Allan Munene Mutiiria. |
把神经网络参数直接塞进EA输入项
做外汇和贵金属的算法交易,高风险在于过拟合与滑点吞噬,但先把模型跑起来比空谈架构更实在。下面这段声明把神经网络的权重、偏置和训练约束全做成 input 参数,开 MT5 后不用改代码就能调隐含层规模。 INPUT_NEURON_COUNT 固定为 10,OUTPUT_NEURON_COUNT 为 2,对应多空两类输出;MinHiddenNeurons 与 MaxHiddenNeurons 给的是 10 到 50 的区间,TrainingBarCount 默认 1000 根 K 线,MinPredictionAccuracy 卡在 0.7。这几个数直接决定模型在 EURUSD 这类品种上重训的频率与过拟合概率。 权重字符串里 InputToHiddenWeights 用 0.1 与 -0.1 交替铺了 100 个值,HiddenToOutputWeights 是 20 个,HiddenBiases 和 OutputBiases 各 10 与 2 个。若你接了小布盯盘的 AIGC 特征提取,可以把这些串换成实时生成的初值,省掉冷启动。 指标句柄只挂了 MA20、MA50、RSI、ATR 四个,说明输入特征维度被压在 10 以内。实盘前建议把 ATR 点数和 StopLossPoints 的 100 点对齐,否则黄金跳空时止损可能形同虚设。
class=class="str">"cmt">//| https://t.me/Forex_Algo_Trader | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2025, Allan Munene Mutiiria." class="macro">#class="kw">property link "https:class=class="str">"cmt">//t.me/Forex_Algo_Trader" class="macro">#class="kw">property version "class="num">1.00" class="macro">#include <Trade/Trade.mqh> CTrade tradeObject; class=class="str">"cmt">//--- Instantiate trade object for executing trades class=class="str">"cmt">// Input parameters with clear, meaningful names input class="type">class="kw">double LotSize = class="num">0.1; class=class="str">"cmt">// Lot Size input class="type">int StopLossPoints = class="num">100; class=class="str">"cmt">// Stop Loss(points) input class="type">int TakeProfitPoints = class="num">100; class=class="str">"cmt">// Take Profit(points) input class="type">int MinHiddenNeurons = class="num">10; class=class="str">"cmt">// Minimum Hidden Neurons input class="type">int MaxHiddenNeurons = class="num">50; class=class="str">"cmt">// Maximum Hidden Neurons input class="type">int TrainingBarCount = class="num">1000; class=class="str">"cmt">// Training Bars input class="type">class="kw">double MinPredictionAccuracy = class="num">0.7; class=class="str">"cmt">// Minimum Prediction Accuracy input class="type">class="kw">double MinLearningRate = class="num">0.01; class=class="str">"cmt">// Minimum Learning Rate input class="type">class="kw">double MaxLearningRate = class="num">0.5; class=class="str">"cmt">// Maximum Learning Rate input class="type">class="kw">string InputToHiddenWeights = "class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1"; class=class="str">"cmt">// Input-to-Hidden Weights input class="type">class="kw">string HiddenToOutputWeights = "class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1"; class=class="str">"cmt">// Hidden-to-Output Weights input class="type">class="kw">string HiddenBiases = "class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1,class="num">0.1,-class="num">0.1"; class=class="str">"cmt">// Hidden Biases input class="type">class="kw">string OutputBiases = "class="num">0.1,-class="num">0.1"; class=class="str">"cmt">// Output Biases class=class="str">"cmt">// Neural Network Structure Constants const class="type">int INPUT_NEURON_COUNT = class="num">10; class=class="str">"cmt">//--- Define number of input neurons const class="type">int OUTPUT_NEURON_COUNT = class="num">2; class=class="str">"cmt">//--- Define number of output neurons const class="type">int MAX_HISTORY_SIZE = class="num">10; class=class="str">"cmt">//--- Define maximum history size for accuracy and error tracking class=class="str">"cmt">// Indicator handles class="type">int ma20IndicatorHandle; class=class="str">"cmt">//--- Handle for class="num">20-period moving average class="type">int ma50IndicatorHandle; class=class="str">"cmt">//--- Handle for class="num">50-period moving average class="type">int rsiIndicatorHandle; class=class="str">"cmt">//--- Handle for RSI indicator class="type">int atrIndicatorHandle; class=class="str">"cmt">//--- Handle for ATR indicator class=class="str">"cmt">// Training related structures class="kw">struct TrainingData { class="type">class="kw">double inputValues[]; class=class="str">"cmt">//--- Array to store input values for training