交易中的神经网络:免掩码注意力方式预测价格走势·综合运用
「残差与位置分支的层叠初始化」
这段初始化逻辑把卷积、基类和残差三个组件按 layer_id 顺序压入容器,任一环节失败立即返回 false,保证 MT5 端神经网络结构不被半残状态接管。 注意残差块用 CNeuronBaseOCL 承接卷积梯度:base.SetGradient(conv.getGradient()) 把前层误差回传路径先绑死,再 cResidual.Add(base)。若你改了 iUnits 或 iWindow,必须同步核对 conv.Init 的窗口参数,否则梯度维度对不上会在 feedForward 阶段直接崩。 位置分支 cQPosition 用 SIGMOID 激活,卷积核尺寸等于 iWindow 且步长 1,输出再接一个 Base 层做线性映射。循环收尾时 base 指向 cResidual 最后一员(下标 iLayers*3-1),用它的梯度给整个网络 SetGradient 收口。 feedForward 里先跑 Superpoints 再跑 Query 双路,total_sp 由 cSuperPoints.Total() 动态取,循环内只要某个 FeedForward 返回 false 就中断。开 MT5 把 iLayers 设成 2,观察 layer_id 是否按 0→1→2→3→4→5 递增,能快速验证这段装配有没有漏层。
class="kw">return false; if(!cFeedForward.Add(conv)) class="kw">return false; layer_id++; class=class="str">"cmt">//--- Residual base = new CNeuronBaseOCL(); if(!base || !base.Init(class="num">0, layer_id, OpenCL, iWindow * iUnits, optimization, iBatch)) class="kw">return false; if(!base.SetGradient(conv.getGradient())) class="kw">return false; if(!cResidual.Add(base)) class="kw">return false; layer_id++; class=class="str">"cmt">//--- Delta position conv = new CNeuronConvOCL(); if(!conv || !conv.Init(class="num">0, layer_id, OpenCL, iWindow, iWindow, iWindow, iUnits, class="num">1, optimization, iBatch)) class="kw">return false; conv.SetActivationFunction(SIGMOID); if(!cQPosition.Add(conv)) class="kw">return false; layer_id++; base = new CNeuronBaseOCL(); if(!base || !base.Init(class="num">0, layer_id, OpenCL, conv.Neurons(), optimization, iBatch)) class="kw">return false; if(!base.SetGradient(conv.getGradient())) class="kw">return false; if(!cQPosition.Add(base)) class="kw">return false; layer_id++; } base = cResidual[iLayers * class="num">3 - class="num">1]; if(!SetGradient(base.getGradient())) class="kw">return false; class=class="str">"cmt">//--- SetOpenCL(OpenCL); class=class="str">"cmt">//--- class="kw">return true; } class="type">bool CNeuronMAFT::feedForward(CNeuronBaseOCL *NeuronOCL) { class=class="str">"cmt">//--- Superpoints CNeuronBaseOCL *superpoints = NeuronOCL; class="type">int total_sp = cSuperPoints.Total(); for(class="type">int i = class="num">0; i < total_sp; i++) { if(!cSuperPoints[i] || !((CNeuronBaseOCL*)cSuperPoints[i]).FeedForward(superpoints)) class="kw">return false; superpoints = cSuperPoints[i]; } class=class="str">"cmt">//--- Query CNeuronBaseOCL *inputs = NULL; for(class="type">int i = class="num">0; i < class="num">2; i++) { inputs = cQuery[i + class="num">1]; if(!inputs || !inputs.FeedForward(cQuery[i])) class="kw">return false; } CNeuronBaseOCL *query = NULL, *key = NULL, *value = NULL, *base = NULL; class=class="str">"cmt">//--- Inside layers for(class="type">uint l = class="num">0; l < iLayers; l++) { class=class="str">"cmt">//--- Self-Atention
◍ Transformer层里自注意力与交叉注意力的前向链路
这段逻辑跑的是单层 Transformer 的前向传播:先取第 l 层的 query/key/value 三个投影层,任一为空或 FeedForward 失败就直接返回 false,保证输入张量 inputs 能往下走。 自注意力部分调用 AttentionOut,传入 cScores[l*2] 与 cMHSelfAttentionOut[l],头数由 iHeads 控制、窗口由 iWindowKey 约束,use_causal 设为 false 表示不屏蔽未来信息。 残差归约用 SumAndNormilize 把 inputs 与自注意力输出 base 合并,再叠加位置投影 cQPosition,归一化维度走 iWindow;随后 CalcPositionBias 用可学习位置编码 CNeuronLearnabledPE 算出 cPositionBias[l],供交叉注意力偏置。 交叉注意力按 l/iLayersSP 取超级点层的 key/value,仅当 l%iLayersSP==0 时刷新一次;AttentionOut 这里 use_causal 为 true,并喂入刚算好的 cPositionBias[l],输出写进 cMHCrossAttentionOut[l],再交给 cCrossAttentionOut[l] 收口。 在 MT5 里把 iHeads、iWindowKey 调到与你品种波动周期匹配(如 EURUSD 的 M15 常用 iWindowKey=60),可观察 cMHCrossAttentionOut 输出维度是否稳定非空,外汇与贵金属杠杆高,信号失效时回撤可能偏大。
query = cQuery[l * class="num">2 + class="num">3]; if(!query || !query.FeedForward(inputs)) class="kw">return false; key = cQKey[l]; if(!key || !key.FeedForward(inputs)) class="kw">return false; value = cQValue[l]; if(!value || !value.FeedForward(inputs)) class="kw">return false; if(!AttentionOut(query, key, value, cScores[l * class="num">2], cMHSelfAttentionOut[l], -class="num">1, iUnits, iHeads, iUnits, iHeads, iWindowKey, false)) class="kw">return false; base = cSelfAttentionOut[l]; if(!base || !base.FeedForward(cMHSelfAttentionOut[l])) class="kw">return false; value = cResidual[l * class="num">3]; if(!value || !SumAndNormilize(inputs.getOutput(), base.getOutput(), value.getOutput(), iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; inputs = value; value = cQPosition[l * class="num">2]; if(!value || !SumAndNormilize(inputs.getOutput(), value.getOutput(),inputs.getOutput(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; class=class="str">"cmt">//--- Calc Position bias if(!CalcPositionBias(value.getOutput(), ((CNeuronLearnabledPE*)superpoints).GetPE(), cPositionBias[l], iUnits, iSPUnits, iWindow)) class="kw">return false; class=class="str">"cmt">//--- Cross-Attention query = cQuery[l * class="num">2 + class="num">4]; if(!query || !query.FeedForward(inputs)) class="kw">return false; key = cSPKey[l / iLayersSP]; value = cSPValue[l / iLayersSP]; if(l % iLayersSP == class="num">0) { if(!key || !key.FeedForward(superpoints)) class="kw">return false; if(!value || !value.FeedForward(cSuperPoints[total_sp - class="num">2])) class="kw">return false; } if(!AttentionOut(query, key, value, cScores[l * class="num">2 + class="num">1], cMHCrossAttentionOut[l], cPositionBias[l], iUnits, iHeads, iSPUnits, iSPHeads, iWindowKey, true)) class="kw">return false; base = cCrossAttentionOut[l];
Transformer 块里的残差与位置偏移怎么串
这段逻辑跑在一个多层循环里,每一层 l 都先做 cross-attention 的残差归并,再做两次 feed-forward,最后更新 delta query 位置。看索引就能发现规律:cResidual 按 l*3+1、l*3+2 取,feed-forward 权重按 l*2 和 l*2+1 成对取,说明每层结构完全对称。 SumAndNormilize 的最后一个参数在残差归并时是 1,在 query 位置偏移时被压到 0.5f,这意味着位置编码的步长只有残差的一半,模型对时序位置的修正倾向更保守。外汇与贵金属行情跳变频繁,这种系数若直接照搬,高频噪声可能被过度平滑。 循环结束后,用 cQPosition[iLayers*2] 做最后一层输出归并写进 Output。任意一步 base 或 value 为空、或 FeedForward / SumAndNormilize 返回 false,整个函数立即 return false,调用方必须检查返回值,否则后面拿到的 Output 可能是上一帧的脏数据。
if(!base || !base.FeedForward(cMHCrossAttentionOut[l])) class="kw">return false; value = cResidual[l * class="num">3 + class="num">1]; if(!value || !SumAndNormilize(inputs.getOutput(), base.getOutput(), value.getOutput(), iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; inputs = value; class=class="str">"cmt">//--- Feed Forward base = cFeedForward[l * class="num">2]; if(!base || !base.FeedForward(inputs)) class="kw">return false; base = cFeedForward[l * class="num">2 + class="num">1]; if(!base || !base.FeedForward(cFeedForward[l * class="num">2])) class="kw">return false; value = cResidual[l * class="num">3 + class="num">2]; if(!value || !SumAndNormilize(inputs.getOutput(), base.getOutput(), value.getOutput(), iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; inputs = value; class=class="str">"cmt">//--- Delta Query position base = cQPosition[l * class="num">2 + class="num">1]; if(!base || !base.FeedForward(inputs)) class="kw">return false; value = cQPosition[(l + class="num">1) * class="num">2]; query = cQPosition[l * class="num">2]; if(!value || !SumAndNormilize(query.getOutput(), base.getOutput(), value.getOutput(), iWindow, false, class="num">0,class="num">0,class="num">0,class="num">0.5f)) class="kw">return false; } value = cQPosition[iLayers * class="num">2]; if(!value || !SumAndNormilize(inputs.getOutput(), value.getOutput(), Output, iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; class=class="str">"cmt">//--- class="kw">return true; }
「用 2024 年 1 月数据跑一遍训练好的策略」
模型按 MAFT 框架在真实历史上训练完后,要在 MT5 策略测试器里验证一次。训练用 EURUSD 的 2023 全年 H1 数据,指标全走默认值;测试切到 2024 年 1 月,其余参数不动,直接看训练好的参与者政策怎么跑。 测试区间余额曲线整体向上,表面看是正向结果。但整月只成交 21 笔,其中 12 笔盈利。样本量这么小,没法推断它在更长周期里是否真有概率优势。 外汇和贵金属属高风险品种,单月 21 笔的样本对任何强化学习策略都谈不上置信度。建议你在 MT5 里把测试窗口拉长到至少 3–6 个月,再观察交易频次和回撤分布。
◍ 把 MAFT 接进你自己的 MT5 验证流
这一路把免掩码变换器(MAFT)拆完,核心就一句:它砍掉了传统 Transformer 的数据屏蔽环节,序列处理更快,训练与推理的计算开销更低。原文回测倾向显示,同等样本下 MAFT 的预测准确性有提升,同时模型训练时间下降,这对日内多品种轮动的外汇、贵金属策略是实打实的成本优势,但外汇贵金属高杠杆属性意味着模型胜率提升不代表账户必然盈利。 附件里 7 个文件是落地入口:Research.mq5 与 ResearchRealORL.mq5 负责采样本,Study.mq5 跑训练,Test.mq5 做验证,Trajectory.mqh 管状态结构,NeuroNet.mqh 与 NeuroNet.cl 是神经网络与 OpenCL 底层。解压后按作者回复的路径放——OpenCL 程序在 MQL5\Experts\NeuroNet_DNG\NeuroNet.cl,类库在同目录的 NeuroNet.mqh,本文模型与 EA 在 MQL5\Experts\MAFT\。 开 MT5 直接编译 Test.mq5 先跑一遍样本外,别急着上实盘;若你手上有自己的 tick 数据,把 Research.mq5 的采集字段改掉,就能用同一套 MAFT 骨架替换原 LSTM 方案做对照。模型只解决信号质量,仓位与滑点仍归你管。