交易中的神经网络:针对金融市场的多模态、扩增工具型智代(终篇)·进阶篇
🧠

交易中的神经网络:针对金融市场的多模态、扩增工具型智代(终篇)·进阶篇

(2/3)·把论文里的五模块架构拆成 MQL5 对象,看反射与记忆如何嵌进同一组件

偏理论 第 2/3 篇
很多交易者把神经网络框架当成黑箱直接调用,却没意识到模块间的数据流设计决定了延迟与过拟合风险。把记忆硬塞进反射对象能省去跨模块拷贝,但也会让单对象体积膨胀,回测时容易忽略边界。

把分层模块拼成 FinAgent 主类

把所有已实现的子模块收进一个统一对象 CNeuronFinAgent,它直接继承 CNeuronRelativeCrossAttention。父类那一层交叉注意力并非凑数,而是决策模块的最后一层,用来在财务结果背景下整合高层反射输出。 内部对象全部声明为静态,类构造与析构留空,所有初始化塞进 Init 方法。调用父类 Init 时,主流水线分析窗口设为 3,序列元素数量 = 智代动作向量大小 ×3——动作矩阵每行是一个独立操作,由交易量、止损价、止盈价三列描述,所以买卖各占不同行。 市场分析模块由两个对象组成:分段注意力变换器(抓多变量时序里的稳定形态)加记忆模块。两个低层反射模块并行跑在不同投影上,第二个投影靠置换对象生成;一个看多元时序的步间依赖,一个看单变量序列自身的规律。高层反射模块则结合市场变化与近期财务结果评估智代行为。 前向 feedForward 收两个指针:环境状态、账户与财务结果。低层反射只用当前形态、不碰记忆模块的历史,逼模型对即时反应更敏感;高层反射递归调用自身结果缓冲区里的历史动作张量。辅助工具模块直接啃原始指标读数找信号,但不走梯度回传。 反向 calcInputGradients 完全镜像前馈、只反方向。先调父类分派高层反射与前置交叉注意力的误差,再逐层穿透决策模块的所有交叉注意力,最后回到分段注意力变换器输出级收集梯度。高层反射同时吃主流与财务流误差,低层反射只走单源数据。每次迭代的新梯度必须累加进旧值,否则模型误差统计会断片。 下面这段是 FinAgent 的类骨架,内部对象与覆盖方法一目了然,挂在 MT5 的 OCL 环境里就能接着填实现。

MQL5 / C++
class CNeuronFinAgent  :  class="kw">public CNeuronRelativeCrossAttention
  {
class="kw">protected:
   CNeuronTransposeOCL   cTransposeState;
   CNeuronLowLevelReflection  cLowLevelReflection[class="num">2];
   CNeuronHighLevelReflection cHighLevelReflection;
   CNeuronMoreLessEqual cTools;
   CNeuronPSformer       cMarketIntelligence;
   CNeuronMemory         cMarketMemory;
   CNeuronRelativeCrossAttention cCrossLowLevel;
   CNeuronRelativeCrossAttention cMarketToLowLevel;
   CNeuronRelativeCrossAttention cMarketToTools;
class=class="str">"cmt">//---
   class="kw">virtual class="type">bool        feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) class="kw">override;
   class="kw">virtual class="type">bool        calcInputGradients(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput,
CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None) class="kw">override;
   class="kw">virtual class="type">bool        updateInputWeights(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) class="kw">override;
class="kw">public:
                 CNeuronFinAgent(class="type">void) {};
                ~CNeuronFinAgent(class="type">void) {};
   class=class="str">"cmt">//---
   class="kw">virtual class="type">bool        Init(class="type">uint numOutputs, class="type">uint myIndex, COpenCLMy *open_cl,

「金融智能体类的初始化链路」

在 MT5 的 OpenCL 神经网络框架里,CNeuronFinAgent 作为金融决策智能体,构造函数先接收一批维度参数:window 为时间窗口长度,units_count 是隐藏单元数,heads 指多头注意力头数,nactions 为可执行动作数,segments 用于市场记忆切分,batch 则是训练批大小。 Init 方法并没有从头搭图,而是先调用父类 CNeuronRelativeCrossAttention::Init,并硬编码把输入通道压成 3 路、nactions 除以 3 作为子空间动作数,这一步决定了后续注意力计算的张量形状。若返回 false,整个智能体直接不可用。 随后按顺序挂接四个子模块:cMarketIntelligence 用 segments 和 0.2f 学习率初始化市场感知,cMarketMemory 带 window_key 做跨窗口记忆,cTransposeState 做状态转置,cLowLevelReflection[0] 再走一层相对交叉注意力。每挂一个 index 自增 1,任一失败即中断——你在调参时若发现代理不训练,优先查这几个 Init 的返回值而不是怀疑优化器。 外汇与贵金属行情下用这类 GPU 智能体做信号生成,属于高风险实验,回测与实盘偏差可能很大,参数改动前务必在策略测试器里跑通 Save/Load 的二进制一致性。

MQL5 / C++
class="type">uint window, class="type">uint window_key, class="type">uint units_count, class="type">uint heads,
              class="type">uint account_descr, class="type">uint nactions, class="type">uint segments,
              ENUM_OPTIMIZATION optimization_type, class="type">uint batch);
  class=class="str">"cmt">//---
  class="kw">virtual class="type">int      Type(class="type">void) class="kw">override  const   {  class="kw">return defNeuronFinAgent; }
  class=class="str">"cmt">//---
  class="kw">virtual class="type">bool     Save(class="type">int const file_handle) class="kw">override;
  class="kw">virtual class="type">bool     Load(class="type">int const file_handle) class="kw">override;
  class=class="str">"cmt">//---
  class="kw">virtual class="type">bool     WeightsUpdate(CNeuronBaseOCL *source, class="type">class="kw">float tau) class="kw">override;
  class="kw">virtual class="type">void     SetOpenCL(COpenCLMy *obj) class="kw">override;
  class=class="str">"cmt">//---
  class="kw">virtual class="type">bool     Clear(class="type">void) class="kw">override;
  };
class="type">bool CNeuronFinAgent::Init(class="type">uint numOutputs, class="type">uint myIndex, COpenCLMy *open_cl,
                  class="type">uint window, class="type">uint window_key, class="type">uint units_count, class="type">uint heads,
                  class="type">uint account_descr, class="type">uint nactions, class="type">uint segments,
                  ENUM_OPTIMIZATION optimization_type, class="type">uint batch)
  {
   if(!CNeuronRelativeCrossAttention::Init(numOutputs, myIndex, open_cl, class="num">3,
                            window_key, nactions / class="num">3, heads,
                            window, units_count,
                            optimization_type, batch))
      class="kw">return class="kw">false;
   class="type">int index = class="num">0;
   if(!cMarketIntelligence.Init(class="num">0, index, OpenCL, window, units_count, segments, class="num">0.2f, optimization, iBatch))
      class="kw">return class="kw">false;
   index++;
   if(!cMarketMemory.Init(class="num">0, index, OpenCL, window, window_key, units_count, heads, optimization, iBatch))
      class="kw">return class="kw">false;
   index++;
   if(!cTransposeState.Init(class="num">0, index, OpenCL, units_count, window, optimization, iBatch))
      class="kw">return class="kw">false;
   index++;
   if(!cLowLevelReflection[class="num">0].Init(class="num">0, index, OpenCL, window, window_key, units_count, heads, optimization, iBatch))
      class="kw">return class="kw">false;
   index++;

◍ FinAgent 子网络的初始化与前向链路

在 MT5 的 OpenCL 神经网络框架里,CNeuronFinAgent 的 init 方法靠一串 index++ 把不同子层按顺序挂到同一计算上下文上。注意 cTools 这一层在 init 之后立刻调了 SetActivationFunction(None),说明它输出不做非线性压缩,直接当线性映射用。 feedForward 的调用顺序决定了张量怎么流:市场特征先过 cMarketIntelligence 和 cMarketMemory,再分两路进低层反射阵列;高层反射 cHighLevelReflection 同时吃市场特征和外部 SecondInput(比如账户状态描述)。最后一层把高层反射输出和 cMarketToTools 的输出做相对交叉注意力融合。 calcInputGradients 的入口先判空指针,再反向从交叉注意力层往回传梯度。SecondActivation 默认 -1 表示沿用前向的激活配置,若你接的是自定义信号源,得显式传参否则梯度可能不对。 外汇与贵金属行情跳空频繁,这类多子层网络在实盘推理时若 OpenCL 设备显存不足,init 阶段就会返回 false,建议在 MT5 的「专家属性—OpenCL」里先确认设备可用再加载。

MQL5 / C++
  if(!cLowLevelReflection[class="num">1].Init(class="num">0, index, OpenCL, units_count, window_key, window, heads, optimization, iBatch))
      class="kw">return class="kw">false;
  index++;
  if(!cHighLevelReflection.Init(class="num">0, index, OpenCL, window, window_key, units_count, heads, account_descr, nactions,
optimization, iBatch))
      class="kw">return class="kw">false;
  index++;
  if(!cTools.Init(class="num">0, index, OpenCL, window * units_count, optimization, iBatch))
      class="kw">return class="kw">false;
  cTools.SetActivationFunction(None);
  index++;
  if(!cCrossLowLevel.Init(class="num">0, index, OpenCL, window, window_key, units_count, heads, units_count, window,
optimization, iBatch))
      class="kw">return class="kw">false;
  index++;
  if(!cMarketToLowLevel.Init(class="num">0, index, OpenCL, window, window_key, units_count, heads, window, units_count,
optimization, iBatch))
      class="kw">return class="kw">false;
  index++;
  if(!cMarketToTools.Init(class="num">0, index, OpenCL, window, window_key, units_count, heads, window, units_count,
optimization, iBatch))
      class="kw">return class="kw">false;
class=class="str">"cmt">//---
  class="kw">return true;
  }
class="type">bool CNeuronFinAgent::feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput)
  {
  if(!cMarketIntelligence.FeedForward(NeuronOCL))
      class="kw">return class="kw">false;
  if(!cMarketMemory.FeedForward(cMarketIntelligence.AsObject()))
      class="kw">return class="kw">false;
  if(!cTransposeState.FeedForward(cMarketIntelligence.AsObject()))
      class="kw">return class="kw">false;
  if(!cLowLevelReflection[class="num">0].FeedForward(cMarketIntelligence.AsObject()))
      class="kw">return class="kw">false;
  if(!cLowLevelReflection[class="num">1].FeedForward(cTransposeState.AsObject()))
      class="kw">return class="kw">false;
  if(!cHighLevelReflection.FeedForward(cMarketIntelligence.AsObject(), SecondInput))
      class="kw">return class="kw">false;
  if(!cTools.FeedForward(NeuronOCL))
      class="kw">return class="kw">false;
  if(!cCrossLowLevel.FeedForward(cLowLevelReflection[class="num">0].AsObject(), cLowLevelReflection[class="num">1].getOutput()))
      class="kw">return class="kw">false; 
  if(!cMarketToLowLevel.FeedForward(cMarketMemory.AsObject(), cCrossLowLevel.getOutput()))
      class="kw">return class="kw">false;
  if(!cMarketToTools.FeedForward(cMarketToLowLevel.AsObject(), cTools.getOutput()))
      class="kw">return class="kw">false;
  class="kw">return CNeuronRelativeCrossAttention::feedForward(cHighLevelReflection.AsObject(), cMarketToTools.getOutput());
  }
class="type">bool CNeuronFinAgent::calcInputGradients(CNeuronBaseOCL *NeuronOCL,
                                        CBufferFloat *SecondInput,
                                        CBufferFloat *SecondGradient,
                                        ENUM_ACTIVATION SecondActivation = -class="num">1)
  {
  if(!NeuronOCL || !SecondGradient)
      class="kw">return class="kw">false;
  if(!CNeuronRelativeCrossAttention::calcInputGradients(cHighLevelReflection.AsObject(),
                                                         cMarketToTools.getOutput(),
                                                         cMarketToTools.getGradient(),

反向传播里的梯度链式回传

这段实现把多层神经元的隐藏梯度按依赖顺序逐层回算,任何一层失败就直接 return false,保证前向状态不被污染。 cMarketToTools 与 cMarketToLowLevel 先向 cTools 回传梯度,激活类型由 cTools.Activation() 强转 ENUM_ACTIVATION 决定;接着 cMarketMemory 从 cCrossLowLevel 的输出与梯度反向计算,这里跨了两条低层反射通道。 cMarketIntelligence 的处理最重:先取自身梯度缓存到 temp,再分别向 cHighLevelReflection、cLowLevelReflection[0]、cTransposeState 回传,每次都用 SumAndNormilize(temp, ..., 1, false, 0, 0, 0, 1) 做累加归一,参数里最后一个 1 表示批次维度不缩放。外汇与贵金属行情用这类结构建模时波动剧烈,过拟合概率偏高,需以 MT5 实盘样本严控层数。 最后 NeuronOCL 从 cMarketIntelligence 对象回算梯度,全部通过才 return true,否则整链作废。

MQL5 / C++
if(!cMarketToTools.calcHiddenGradients(cMarketToLowLevel.AsObject(),
                                          cTools.getOutput(),
                                          cTools.getGradient(),
                                          (ENUM_ACTIVATION)cTools.Activation()))
   class="kw">return class="kw">false;
if(!cMarketToLowLevel.calcHiddenGradients(cMarketToTools.AsObject(),
                                           cTools.getOutput(),
                                           cTools.getGradient(),
                                           (ENUM_ACTIVATION)cTools.Activation()))
   class="kw">return class="kw">false;
class=class="str">"cmt">//---
if(!cMarketMemory.calcHiddenGradients(cMarketToLowLevel.AsObject(),
                                       cCrossLowLevel.getOutput(),
                                       cCrossLowLevel.getGradient(),
                                       (ENUM_ACTIVATION)cCrossLowLevel.Activation()))
   class="kw">return class="kw">false;
if(!cLowLevelReflection[class="num">0].calcHiddenGradients(cCrossLowLevel.AsObject(),
      cLowLevelReflection[class="num">1].getOutput(),
      cLowLevelReflection[class="num">1].getGradient(),
      (ENUM_ACTIVATION)cLowLevelReflection[class="num">1].Activation()))
   class="kw">return class="kw">false;
if(!cTransposeState.calcHiddenGradients(cLowLevelReflection[class="num">1].AsObject()))
   class="kw">return class="kw">false;
if(!((CNeuronBaseOCL*)cMarketIntelligence.AsObject()).calcHiddenGradients(cMarketMemory.AsObject()))
   class="kw">return class="kw">false;
CBufferFloat *temp = cMarketIntelligence.getGradient();
if(!cMarketIntelligence.SetGradient(cMarketIntelligence.getPrevOutput(), class="kw">false) ||
   !((CNeuronBaseOCL*)cMarketIntelligence.AsObject()).calcHiddenGradients(cHighLevelReflection.AsObject(),
                                                                          SecondInput, SecondGradient, SecondActivation) ||
   !SumAndNormilize(temp, cMarketIntelligence.getGradient(), temp, class="num">1, class="kw">false, class="num">0, class="num">0, class="num">0, class="num">1))
   class="kw">return class="kw">false;
if(!((CNeuronBaseOCL*)cMarketIntelligence.AsObject()).calcHiddenGradients(cLowLevelReflection[class="num">0].AsObject()) ||
   !SumAndNormilize(temp, cMarketIntelligence.getGradient(), temp, class="num">1, class="kw">false, class="num">0, class="num">0, class="num">0, class="num">1))
   class="kw">return class="kw">false;
if(!((CNeuronBaseOCL*)cMarketIntelligence.AsObject()).calcHiddenGradients(cTransposeState.AsObject()) ||
   !SumAndNormilize(temp, cMarketIntelligence.getGradient(), temp, class="num">1, class="kw">false, class="num">0, class="num">0, class="num">0, class="num">1) ||
   !cMarketIntelligence.SetGradient(temp, class="kw">false))
   class="kw">return class="kw">false;
if(!NeuronOCL.calcHiddenGradients(cMarketIntelligence.AsObject()))
   class="kw">return class="kw">false;
class=class="str">"cmt">//---
class="kw">return true;
}
class=class="str">"cmt">//--- layer class="num">2
if(!(descr = new CLayerDescription()))
把多源诊断交给小布盯盘
这些模块产出的形态信号与记忆检索结果,小布盯盘的 AIGC 已内置对应品种页的异动标注,打开即可对照自己的 MQL5 日志,不必手工比对新闻与报价流。

常见问题

分别由 CNeuronLowLevelReflection 与 CNeuronHighLevelReflection 实现,前者抓短期信号依赖,后者协同历史交易结果调长期趋势策略。
可以,品种页的 AIGC 模块支持粘贴智代运行日志,自动标记记忆检索噪声与反射偏移,省去肉眼翻向量库。
原框架独立存记忆,本文 MQL5 版为简化数据流将记忆嵌入反射组件,减少跨模块交互但需注意单对象膨胀。
它遍历历史形态与专家评估,把先验知识挂到当前信号上,让决策支持系统输出带逻辑链的建议而非纯数值。