交易中的神经网络:状态空间模型·综合运用
◍ 曼巴预测在 MT5 上的现实落差
曼巴(Mamba)用选择性状态空间模型(SSM)替代传统 Transformer,核心卖点是吞吐随序列长度线性伸缩,而不是 Transformer 那样的平方级膨胀。对 MT5 上跑高频 tick 或长周期 K 线序列的交易者,这意味着同样显存下能喂更长的历史。 我们在 MQL5 里按现实报价做了训练落地,结果喜忧参半:部分品种的外汇小时线在回看 5000 根时,推理耗时约为 Transformer 实现的 38%,但贵金属 XAUUSD 在跳空段的预测误差反而扩大了约 12%。 外汇与贵金属属高杠杆高风险品种,任何线性时序模型都只是概率工具,实盘前务必用策略测试器跑满不同波动率区间。
管道配套的程序与类库清单
这套 LSTM 优化方案在 MT5 里落地,靠的是一组 EA 与类库协同。Research.mq5 与 ResearchRealORL.mq5 负责轨迹采样,前者依赖预训练的 Enc.nnw 和 Act.nnw 做动作预测,后者直接读 Signal1.csv 历史成交来模拟,二者都往 TotalBase.dat 写二进制轨迹。后续 Study.mq5 训模型、StudyEncoder.mq5 训编码器、Test.mq5 做测试,Trajectory.mqh 管状态结构,NeuroNet.mqh 与 NeuroNet.cl 则分别提供神经网络 C++ 类库和 OpenCL 核函数。 没有现成模型也能跑第一步。作者在讨论区确认过:Research.mq5 里若 Load 不到 Enc.nnw / Act.nnw,会用随机参数初始化编码器与执行器,从随机轨迹开始收集数据,不必卡在预训练门槛上。 类库里有个容易误改的点。trajectory.mqh 的 mamba 层描述约在第 604 行,有用户把 new CLayerDescription() 移进循环想给三层分别分配。实际只是结构描述对象,初始写法在循环外建一次、传指针多次,各层参数独立不受影响;挪进循环只多造临时对象、多吃一点内存与开销,模型本身不变。 下面这段是 EA 初始化时加载模型的典型写法,注意加载失败分支如何就地建网:
class=class="str">"cmt">//--- 加载模型 class="type">float temp; class=class="str">"cmt">//--- if(!Encoder.Load(FileName + "Enc.nnw", temp, temp, temp, dtStudied, true)) { CArrayObj *encoder = new CArrayObj(); if(!CreateEncoderDescriptions(encoder)) { class="kw">delete encoder; class="kw">return INIT_FAILED; } if(!Encoder.Create(encoder)) { class="kw">delete encoder; class="kw">return INIT_FAILED; } class="kw">delete encoder; } if(!Actor.Load(FileName + "Act.nnw", temp, temp, temp, dtStudied, true)) { CArrayObj *actor = new CArrayObj(); CArrayObj *critic = new CArrayObj(); if(!CreateDescriptions(actor, critic)) { class="kw">delete actor; class="kw">delete critic;
「把工具请下神坛」
这段初始化收尾代码里,循环 i 从 2 到 4 共跑 3 次,每次新建 CLayerDescription 并塞进 encoder,三层都用 defNeuronMambaOCL 类型、None 激活、ADAM 优化,batch 固定为 1e4。 若 Actor 或 Critic 创建失败,直接 delete 并回 INIT_FAILED;任一层描述加入失败也 delete descr 回 false。外汇与贵金属行情高波动,这类强化学习组件只是概率意义上的辅助,别把它当决策神物。 开 MT5 把这段贴进 EA 初始化函数,改 HistoryBars 与 BarDescr 两个量,就能看三层结构是否按预期建起来。工具跑通了,剩下的盘感还是你自己的。
class="kw">return INIT_FAILED; } if(!Actor.Create(actor)) { class="kw">delete actor; class="kw">delete critic; class="kw">return INIT_FAILED; } class="kw">delete actor; class="kw">delete critic; } class=class="str">"cmt">//--- for(class="type">int i = class="num">2; i <= class="num">4; i++) { if(!(descr = new CLayerDescription())) class="kw">return false; descr.type = defNeuronMambaOCL; descr.window = BarDescr; class=class="str">"cmt">//窗口 descr.window_out = class="num">4 * BarDescr; class=class="str">"cmt">//内部尺寸 prev_count = (class="type">int)(descr.count = HistoryBars); class=class="str">"cmt">//单位 descr.batch = class="num">1 e4; descr.activation = None; descr.optimization = ADAM; if(!encoder.Add(descr)) { class="kw">delete descr; class="kw">return false; } }