交易中的神经网络:多智代自适应模型(MASA)(基础篇)
◍ 多智代自适应模型在 MT5 里的起点
MQL5 社区在 2025 年 9 月 25 日发布的「多智代自适应模型(MASA)」交易系统,目前公开页显示浏览量 777、评论 0,作者为 Dmitriy Gizlyk,运行载体是 MetaTrader 5。它把神经网络思路搬进 EA,核心是用多个智能代理各自适应不同市况,再汇总信号。 这类模型对外汇与贵金属品种尤其敏感,杠杆与滑点会放大权重误差,实盘前务必在 MT5 策略测试器跑至少一年 tick 级回测。 从工程角度看,MASA 不是单一网络,而是「多智代」并行:每一代在样本内调参,跨代用适应度做筛选,倾向降低过拟合概率,但不保证样本外稳定。
双智代框架怎么补上风控缺口
传统强化学习做组合管理,目标函数基本只追最大回报,遇到疫情、自然灾害、地区冲突这类外生冲击时回撤往往失控。问题不在算法不行,而在单一智能体没有专门的对冲视角。 MASA 框架把这件事拆成两个交互智代:一个用 TD3 算法盯收益,另一个用进化算法或其它优化手段压风险;再挂一个市场观察器,靠深度神经网络读趋势并回灌反馈。相当于让「进攻」和「防守」分开训练又互相制约。 作者在 CSI 300、道琼斯工业平均指数、标普 500 共约 10 年数据上做了对照,MASA 在组合管理结果上优于传统 RL 方案。外汇与贵金属属高风险品种,这类框架若迁移到 MT5 回测,须自行重算波动约束,不能直接套股票结论。
「用双智代管道拆开回报与风险」
传统强化学习容易一头扎进回报优化,忽略波动市里的回撤。MASA 把这件事拆成两条线:一条用 TD3 类 RL 智代追组合收益,另一条用交替优化智代按市场观察器给的趋势评估去压风险,两者通过松散耦合的管道式模型交换信息。 训练开始前,RL 政策与观察器维护的市场状态先初始化。每步里,系统取当前市场状态 O_t(如近几个交易日的升降趋势)送观察器,同时把上一步动作 A_{t-1} 的奖励回灌 RL 智代细化政策。观察器算出风险边界 σ_{s,t} 和市场向量 V_{m,t},再作为附加特征去更新 RL 与控制器。 这种功能分离让模型能持续学底层动态。在 CSI 300、DJIA、S&P 500 上跨十多年区间测试,即便观察器只用较简单算法,RL 与交替优化器都有可见性能提升,组合在收益与风险间更平衡。外汇与贵金属属高风险品种,直接套用前需在 MT5 用真实点差与滑点重测。 最坏情况是观察器被噪音带偏、给出误导信号。此时 RL 奖励的自适应性会在后续迭代里跟环境重新对齐,观察器也随训练自我纠正,长横盘段不至于崩。某个智代挂了,其余仍能跑,这是管道松散耦合带来的健壮性。
◍ 三智代在 MT5 里的落地骨架
MASA 框架拆成三个独立对象来写,比塞进一个大类更好读也好改。市场观察器、RL 智代、控制器各自继承线性模型基类 CNeuronRMAT,再在 Init 里拼自己的结构,核心前向逻辑父类已经托管了。 市场观察器 CNeuronMarketObserver 走的是混合路数:分段线性表示抓趋势,相对位置编码注意力看单变量序列间的依赖,最后用残差卷积块替掉 MLP 去预测横向区间。Init 参数里 window 是单序列向量大小,units_count 是历史深度,heads 是注意力头数,forecast 是预测步长,这些常量直接决定显存和推理耗时。 RL 智代 CNeuronRLAgent 没照原版 TD3,改用 PSformer 做环境分析,轻量感知器出决策。它的 Init 里 forecast 换成了 n_actions 动作空间,多了 segments 和 rho 模糊系数;动作向量默认 sigmoid 压在 0~1,外部可覆盖。 控制器 CNeuronControlAgent 最麻烦,因为它吃双输入:市场观察器的多模态预测序列 + RL 智代 动作。作者判断单变量序列的趋势比单根预测烛线更抗偏差,所以把动作对齐到单变量序列预测值,解码器层里自注意力(仅当序列多于 1 元素才建)加交叉注意力,最后卷积层配激活函数收口。 calcInputGradients 是坑点:二级数据源在所有交叉注意力模块间共享,必须从每个交叉注意力模块回收误差梯度再累加传回。下面这段是市场观察器类头和方法签名骨架,参数顺序看清才能照着填。
class CNeuronMarketObserver : class="kw">public CNeuronRMAT { class="kw">public: CNeuronMarketObserver(class="type">void) {}; ~CNeuronMarketObserver(class="type">void) {}; class="kw">virtual class="type">bool 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,