神经网络在交易中的应用:用于多元时间序列预测的 LSTM 优化(终篇)·进阶篇
📘

神经网络在交易中的应用:用于多元时间序列预测的 LSTM 优化(终篇)·进阶篇

第 2/2 篇

◍ 编码器后段的层堆叠与任务装配

这段逻辑接着前面搭好的编码器,从 layer 4 一路堆到 layer 9,最后把整个 encoder 拷进 task。每一层都用 CLayerDescription 的 new 实例去描述,加不进 encoder 就立刻 delete 并 return false,内存和流程双重保险。 layer 4 是线性注意力层:type 设 defNeuronLinerAttention,count 只有 1,window 吃整段 HistoryBars,window_out 给 32,batch 跑 1e4,优化用 ADAM,激活函数关成 None。 layer 5 换 CGLSTM 共用技能层(defNeuronCGLSTMOCL),count 绑定 NSkills、window 用 HistoryBars 序列、layers 指 BarDescr 变量集,batch 同样 1e4、ADAM、无激活。 layer 6 与 7 是两组一维卷积(defNeuronConvOCL):第 6 层 window=step=NSkills,window_out 算成 4*NForecast,激活 SoftPlus;第 7 层 window=step=前层 prev_out,window_out 压到 NForecast,激活改 TANH。这里 prev_out 和 prev_count 被反复接力,决定下一层张量形状。 layer 8 做转置(defNeuronTransposeOCL),count=prev_count、window=prev_out;layer 9 是反归一化(defNeuronRevInDenormOCL),count 直接乘开成 prev_count*prev_out、layers=1。 task.Clear() 后,用 for 从 0 到 LatentLayer 把 encoder.At(i) 逐层塞进 task。在 MT5 里把 LatentLayer 调到比 9 小,就能截断后段重训练,观察外汇或贵金属预测误差倾向怎么变——这类品种杠杆高,回测结论只代表历史概率。

MQL5 / C++
  }
class=class="str">"cmt">//--- layer class="num">4
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronLinerAttention;
  descr.count = class="num">1;
  descr.window = HistoryBars;
  descr.layers = BarDescr;
  descr.window_out = class="num">32;
  descr.batch = class="num">1e4;
  descr.optimization = ADAM;
  descr.activation = None;
  if(!encoder.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- layer class="num">5
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronCGLSTMOCL;
  descr.count = NSkills;                         class=class="str">"cmt">// Common Skkills
  descr.window = HistoryBars;                    class=class="str">"cmt">// Sequence
  descr.layers = BarDescr;                       class=class="str">"cmt">// Variables
  descr.batch = class="num">1e4;
  descr.activation = None;
  descr.optimization = ADAM;
  if(!encoder.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- layer class="num">6
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronConvOCL;
  descr.count = class="num">1;
  descr.window = NSkills;
  descr.step = NSkills;
  class="type">int prev_out = descr.window_out = class="num">4 * NForecast;
  prev_count=descr.layers = BarDescr;
  descr.activation = SoftPlus;
  if(!encoder.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- layer class="num">7
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronConvOCL;
  descr.count = class="num">1;
  descr.window = prev_out;
  descr.step = prev_out;
  prev_out = descr.window_out = NForecast;
  descr.layers = prev_count;
  descr.activation = TANH;
  if(!encoder.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- layer class="num">8
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronTransposeOCL;
  descr.count = prev_count;
  descr.window = prev_out;
  descr.activation = None;
  if(!encoder.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- layer class="num">9
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronRevInDenormOCL;
  descr.count = prev_count * prev_out;
  descr.layers = class="num">1;
  descr.activation = None;
  if(!encoder.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- Task
  task.Clear();
class=class="str">"cmt">//--- Task Encoder
  for(class="type">int i = class="num">0; i <= LatentLayer; i++)
    if(!task.Add(encoder.At(i)))

「注意力层与卷积输出层的参数落地」

这段 MT5 神经网络描述代码承接了潜变量层之后的三组网络层定义,直接决定模型对外汇或贵金属行情特征的抽取方式。外汇与贵金属杠杆高、波动剧烈,任何模型都只是概率工具,实盘前务必在策略测试器里跑过样本外数据。 第一块 LatentLayer+1 用的是交叉注意力类型 defNeuronCrossDMHAttention,窗口数组 temp 设为 {NSkills, NSkills},单元数组设为 {BarDescr, BarDescr},step=4、window_out=32、layers=2、batch=1e4,优化器选 ADAM 且激活函数为 None。若 ArrayCopy 拷贝长度不足会直接 return false,说明维度匹配是硬门槛。 随后 LatentLayer+2 与 +3 都是 defNeuronConvOCL 一维卷积:+2 的 window 与 step 等于 NSkills,window_out 算出为 4*NActions,layers=BarDescr,激活 SoftPlus;+3 直接拿上一层 prev_out 作窗口,window_out=NActions,激活 SIGMOID 把输出压到 0~1 区间,适合做动作概率。 把这段代码原样丢进 EA 的层构建函数,改一下 NSkills / NActions 常量,就能在 MT5 里复现该网络头并观察训练日志是否卡在 ArrayCopy 报错。

MQL5 / C++
    class="kw">return false;
class=class="str">"cmt">//--- layer LatentLayer+class="num">1
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronCrossDMHAttention;
    {
      class="type">int temp[] = {NSkills, NSkills};                                      class=class="str">"cmt">// WIndow
      if(ArrayCopy(descr.windows, temp) < (class="type">int)temp.Size())
        class="kw">return false;
    }
    {
      class="type">int temp[] = {BarDescr, BarDescr};                                    class=class="str">"cmt">// Units
      if(ArrayCopy(descr.units, temp) < (class="type">int)temp.Size())
        class="kw">return false;
    }
  descr.step = class="num">4;
  descr.window_out = class="num">32;
  descr.layers = class="num">2;
  descr.batch = class="num">1e4;
  descr.optimization = ADAM;
  descr.activation = None;
  if(!task.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- layer LatentLayer+class="num">2
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronConvOCL;
  descr.count = class="num">1;
  descr.window = NSkills;
  descr.step = NSkills;
  prev_out = descr.window_out = class="num">4 * NActions;
  prev_count=descr.layers = BarDescr;
  descr.activation = SoftPlus;
  if(!task.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }
class=class="str">"cmt">//--- layer LatentLayer+class="num">3
  if(!(descr = new CLayerDescription()))
    class="kw">return false;
  descr.type = defNeuronConvOCL;
  descr.count = class="num">1;
  descr.window = prev_out;
  descr.step = prev_out;
  prev_out = descr.window_out = NActions;
  descr.layers = prev_count;
  descr.activation = SIGMOID;
  if(!task.Add(descr))
    {
      class="kw">delete descr;
      class="kw">return false;
    }

离线打底加在线微调的训练节奏

这套 MQL5 强化学习模型不是一次性喂完数据就完事,而是拆成数据集生成、离线训练和在线微调三段走。好处是把历史数据里练出的基本稳定性,和当下行情的灵活适应拧在一起,避免纯回测模型一上实盘就飘。 数据集用 Research.mq5 在 MT5 策略测试器里跑,只收 EURUSD 的 M1 数据,时间框死在 2024 全年。为了不把电脑跑爆,每次只灌一个月历史,智能体之间的行为差异靠随机策略拉开。每根 K 线收盘后,把市场状态、指标值、账户指标和智能体动作全写进体验回放缓冲区,形成完整轨迹。 离线训练交给 Study.mq5,从回放池随机抽轨迹和起点拼训练批次。它用了一种近乎完美的轨迹技术催收敛,让编码器能往前猜几步,顺带把技能编码器、演员、导演、评论家全训一遍,打出基础策略底子。 上线后用 StudyOnline.mq5 做微调,重心是在导演和评论家盯盘下训演员。每根新 K 线收盘就重估环境、调参数,目标模型定期软更新,在稳和变之间找平衡。外汇及贵金属属高风险品种,这种多阶段方案在真实行情里可能更鲁棒,但参数漂移风险仍得自己盯。

◍ 用训练集外数据验策略成色

想给一套已经写好的策略做客观评价,唯一硬标准就是拿没喂给训练过程的数据去跑。我们挑了 2025 年 1 月到 3 月这段完全在训练窗口之外的行情做测试,目的就是掐掉过拟合带来的虚假安全感,让结果落回真实盘口环境。 测试里市场环境、周期、终端参数全跟训练时锁死一致,这样波动只来自策略本身,不会被外部设置搅浑。 这三个月模型一共触发 37 笔交易,盈利单占比刚过 40%。但整体还是净赚,原因是平均盈利单的金额是平均亏损单的两倍以上,利润因子录得 1.67。外汇与贵金属属高风险品种,该数字仅代表历史样本表现,实盘可能偏离。

「模型离实盘还差最后几步」

DA-CG-LSTM 框架靠 CG-LSTM 与双注意力机制把短期波动和长期趋势分开提取,解码器简化成卷积块后,训练重心落在全局技能上,这是做稳健策略的关键。测试集上盈利交易比例只略超 40%,但平均收益对平均损失的比值够大,整体还是正收益——说明胜率不是这套方法的命门。 社区里有人拿 Research.mq5 跑了一个月 5 分钟周期,攒出 300MB 的 DACGLSTM.bd,接着 Study.mq5 一开始误差率高得离谱,调了几周奖励惩罚和 Trajectory 参数才恢复正常;另有用户反馈新数据上交易近乎随机,神经网络学会了「生存」而不是「盈利」,最短持仓限制和止损阈值卡死才逼出一点模式识别。 外汇和贵金属是高风险品种,这类模型目前还在探索期,真要上 MT5 实盘前,得换更具代表性的数据集重训,并跨多种行情全面测过。附带的那套 EA(Research / Study / Test 等)和 NeuroNet 类库可以直接下下来跑,但别指望下载即盈利。

常见问题

一般 1~2 层就够,层数过多容易过拟合训练集;可用验证集外样本看误差是否随层数增加反而变大再定。
对小时级 K 线,核宽 3~5 通常够用;太大易吞掉局部转折信号,建议离线对比不同核宽的回测偏差。
小布可读取你的离线验证明细与在线微调记录,标记过拟合风险和品种适应性缺口,给你是否上实盘的预警。
贵金属和高波动外汇建议每 1~2 周用新数据轻量微调,重大事件后补一轮;别等误差飙升才动。
重点看方向命中率、最大回撤和分品种夏普;若外样方向率低于 52%,实盘概率上不占优,先别上。