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