MQL5交易策略自动化(第二十一部分):借助自适应学习率提升神经网络交易效果(基础篇)
📘

MQL5交易策略自动化(第二十一部分):借助自适应学习率提升神经网络交易效果(基础篇)

第 1/3 篇

「用自适应学习率喂饱你的神经网络」

在 MT5 里跑神经网络策略,最容易被忽略的其实是学习率。固定学习率要么收敛慢,要么在损失平面陡峭处直接发散,尤其外汇和贵金属这种高波动品种,过拟合风险被放大数倍。 MQL5 的 CNeuralNet 类允许在训练循环里动态改学习率。下面这段把学习率做成随 epoch 衰减的形式,能让网络在前期快速下降、后期微调权重。

MQL5 / C++
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 曲线震荡是否收窄。外汇与贵金属杠杆高,模型表现可能随行情结构突变而失效,务必小仓验证。

MQL5 / C++
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 策略测试器跑回测。

MQL5 / C++
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 点对齐,否则黄金跳空时止损可能形同虚设。

MQL5 / C++
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

常见问题

固定学习率要么在平坦区收敛慢,要么在陡峭区震荡不收敛;让学习率随误差大小自适应调整,训练更稳更快。
主要把信号生成从指标交叉判断改为神经网络前向输出,并把 CCI、AO 数值作为网络输入特征接入训练样本。
小布可以接入你的品种页,自动汇总网络输出信号和训练误差变化,帮你快速识别模型是否过拟合或失效。
至少需要样本采集、网络前向、误差反向和权重更新四块逻辑,并用缓冲区把输出画到副图。
不用改代码就能现场调参做对比测试,方便你针对贵金属或外汇不同品种找合适配置,注意杠杆交易高风险。