交易中的神经网络:具有预测编码的混合交易框架(StockFormer)(基础篇)
📘

交易中的神经网络:具有预测编码的混合交易框架(StockFormer)(基础篇)

第 1/3 篇

「用 StockFormer 给 MT5 接入预测编码」

StockFormer 是一套面向 MT5 的混合交易框架,核心是把预测编码(predictive coding)塞进神经网络,用来对行情序列做前向推断。作者在 2025 年 12 月 9 日发布的版本,截至发布日社区页面显示阅读量 734、评论 0,说明这套思路还处在早期验证阶段,未经过大量实盘吐槽。 在 MT5 里跑这套框架,本质是用历史 tick 或柱体序列训练一个能输出‘下一状态分布’的模型,再用预测误差反向修正交易信号。外汇与贵金属杠杆高、滑点随机,这类模型在外盘实盘只具备概率优势,不存在稳定胜率保证。 想自己验证,直接在 MT5 的‘文件—打开数据文件夹—MQL5—Include’里丢进框架头文件,挂上 EA 后看预测误差曲线是否随行情 regime 切换而突变,比单纯看 equity 更有用。

噪声市场里,单看价格序列会漏掉什么

强化学习进金融圈已经不是新鲜事,开发交易策略、管组合都在用,模型啃的是价格、成交量、技术指标的 historical 数据。但多数方案默认喂进去的数据已经把资产间的相互依赖全抓住了——这在外汇和贵金属这种高噪、高波动盘里基本是幻想,真实相关性常常藏在价格序列之外。 传统做法另一个短板是短期回报和长期回报的预测经常割裂,跨资产相关性也顾不上。能活下来的策略往往是对这几层关系都有体感。StockFormer 的思路是用预测编码先从不干净的输入里榨出有信息量的隐藏状态,再交给 RL 智能体,预测编码本来是 NLP 和 CV 里的老活,挪到金融噪声里反而珍贵。 它叠了三个改过的 transformer 分支,分别盯长期趋势、短期趋势、跨资产依赖,每个分支塞进 DMH-Attn(多元化多头注意力),用多个并行模块替掉单个前馈,能在子空间里捞到不同时间尺度的形态还不丢关键信息。三路潜状态后来用多头注意力融成一个统一空间给 RL 用,策略学习走 actor-critic,critic 的梯度还会反传去改预测编码模块,让建模和优化绑在一起。 论文在三个公开数据集上的实验显示,StockFormer 的预测准确率和投资回报都明显超过既有方法。外汇/贵金属属高风险品种,这类混合架构只是提升信息提取概率,实盘仍需自己跑 MT5 接数据验证,别直接当信号源。

◍ StockFormer 用改良 Transformer 做跨资产预测与决策

StockFormer 把强化学习拆成两个阶段来跑:先靠预测编码从噪数据里抠隐藏形态,再做交易策略学习。传统模型最大的坑是给不了资产与未来趋势之间的动态依赖关系建模,行情变脸快的时候尤其致命。 它在原型 Transformer 的多头注意力上动了刀——把单一前馈网络(FFN)换成一组并行 FFN,参数总量不增,却能把多头注意力拆出的特征在多个子空间里分别处理,跨资产的异质时态模式就更好建模了。这个改动叫多头注意力多元化(DMH-Attn):把注意力输出 Z 按通道维切成 h 组(h 即头数),每组过一个专属 FFN,里面是两条线性投影夹一个 ReLU。 预测编码阶段,编码器和解码器都用上;到了策略优化,只留编码器。模型由 L 个编码层和 M 个解码层组成,末层编码输出 X_Lenc 喂给每个解码层。交叉资产依赖模块在每个时间步 t 处理同输入,股市数据里作者塞了 MACD、RSI、SMA 这些技术指标。 训练时数据切成两块:一是按固定窗口每日收盘价算的协方差矩阵,二是把一半时间序列随机零掩码、另一半留可见。目标是从协方差加可见特征重建被掩掉的统计值——这逼编码器学跨资产互依赖。短期模块预测次日回报(H=1),长期模块看更长横截面,两路共用回归误差加股票排名误差的组合损失,排名误差保证高收益资产排前面。 第二阶段把三种潜表示 s_relat,t、s_long,t、s_short,t 通过多头注意力级联融进统一状态空间 S_t。长期预测表示当查询(受短期噪音干扰小),再和资产互依赖表示拼成后续注意力的主键与数值,最后用参与者–评论者框架训出最优策略。预测编码和策略优化打通后,评论者反哺潜表示质量,噪音和跨资产关系都处理得更干净。外汇与贵金属市场同样存在高波动与不可预测风险,此类模型输出仅作概率倾向参考,实盘前务必在 MT5 用历史数据回测验证。

「把 StockFormer 的多头卷积层搬进 MT5」

StockFormer 的关键改动是把多头自注意力输出切分成 h 个等长组,每组走独立 MLP。传统多头注意力靠 Q/K/V 投影造头,而这里直接把序列元素的表示向量拆组,不增参数量、不出投影层,但现有卷积层用不了,只能自己造多头卷积变体。 OpenCL 端先写前馈内核 FeedForwardMHConv。头标识和头总数被塞进任务空间当额外维度,内核里先定位线程、算每个头的输入输出偏移,再在单线程内对一头做卷积。外环扫输出层元素,内环扫卷积窗口,用向量乘法吃满处理器带宽,跑完激活函数写回输出缓冲区。 反向传播不能把头当任务空间维度,因为步幅小于窗口时一个输入会喂多个头。CalcHiddenGradientMHConv 把头数当外部参数,在二维任务空间定位线程后,外环扫受影响输出窗口、内环扫滤波器,累完梯度再过激活导数写回。参数更新内核建议自己翻附录。 主程序侧新增 CNeuronMHConvOCL,父类是普通卷积层。Init 里只多一个头数变量,可训练张量维度 = 单变量级数 × 总滤波器数 × 单头窗口大小;单头参数量 Fi*(Wi+1),乘头数 H 得每序列总数。随机初始化后送 OpenCL 显存,动量缓冲填零。 用两个静态 CNeuronMHConvOCL 拼出 CNeuronMHFeedForward:第一层 GELU、第二层无激活且交换滤波器数与窗口参,输出做带归一化的残差连接。calcInputGradients 要沿内部流水线和源数据两条流回传,无激活时直接累加,有激活先过导数再合。 解码器 CNeuronDMHAttention 继承 CNeuronRMAT,Init 按层数环建自注意力、交叉注意力、多头 FF。第二输入源被各层交叉注意力共用,梯度需聚到继承的闲置缓冲,逆向环里遇交叉注意力就累加第二源梯度,最后回传主流。完整代码在附录,下篇再拆两级训练。

MQL5 / C++
__kernel class="type">void FeedForwardMHConv(__global class="type">float *matrix_w,
                                      __global class="type">float *matrix_i,
                                      __global class="type">float *matrix_o,

OpenCL 卷积核里的分头偏移计算

这段内核代码把输入窗口按 heads 维度做切分,每个计算单元只负责 window_in_h 长度的局部卷积,避免单线程爆显存。window_in_h 用 (window_in + heads - 1) / heads 向上取整,保证尾部不足一个头的样本也能被覆盖。 shift_out 与 shift_in 把全局样本索引 i 和头索引 h 映射成矩阵内的读写起点:输出偏 shift_out = window_out * i + window_out_h * h,输入偏 shift_in = step * i + window_in_h * h。若你改了 step 或 heads,这两个偏移必须同步重算,否则矩阵会错位。 内层循环以 4 为步长用 float4 向量化乘加,stop 变量限制有效输入长度——当 window_in_h 超出 inputs - shift_in 剩余量时,stop 被钳到边界。switch 的 case 0~2 处理尾部不足 4 的残段,手工补 1 或 0 凑齐向量,这是显存带宽换正确性的典型写法。 在 MT5 策略测试器里把 heads 从 1 调到 8,同规模样本前向耗时可能降 3~4 倍,但 window_in 小于 heads 时会退化成单头,属于高频外汇模型部署时容易踩的坑。

MQL5 / C++
const class="type">int inputs,
              const class="type">int step,
              const class="type">int window_in,
              const class="type">int window_out,
              const class="type">int activation
              )
  {
  const class="type">size_t i = get_global_id(class="num">0);
  const class="type">size_t h = get_global_id(class="num">1);
  const class="type">size_t v = get_global_id(class="num">2);
  const class="type">size_t total = get_global_size(class="num">0);
  const class="type">size_t heads = get_global_size(class="num">1);
  const class="type">int window_in_h = (window_in + heads - class="num">1) / heads;
  const class="type">int window_out_h = (window_out + heads - class="num">1) / heads;
  const class="type">int shift_out = window_out * i + window_out_h * h;
  const class="type">int shift_in = step * i + window_in_h * h;
  const class="type">int shift_var_in = v * inputs;
  const class="type">int shift_var_out = v * window_out * total;
  const class="type">int shift_var_w = v * window_out * (window_in_h + class="num">1);
  const class="type">int shift_w_h = h * window_out_h * (window_in_h + class="num">1);
  class="type">float sum = class="num">0;
  float4 inp, weight;
  class="type">int stop = (window_in_h <= (inputs - shift_in) ? window_in_h : (inputs - shift_in));
class=class="str">"cmt">//---
  for(class="type">int out = class="num">0; (out < window_out_h && (window_out_h * h + out) < window_out); out++)
    {
      class="type">int shift = (window_in_h + class="num">1) * out + shift_w_h;
      for(class="type">int k = class="num">0; k <= stop; k += class="num">4)
        {
         class="kw">switch(stop - k)
           {
            case class="num">0:
              inp = (float4)(class="num">1, class="num">0, class="num">0, class="num">0);
              weight = (float4)(matrix_w[shift_var_w + shift + window_in_h], class="num">0, class="num">0, class="num">0);
              break;
            case class="num">1:
              inp = (float4)(matrix_i[shift_var_in + shift_in + k], class="num">1, class="num">0, class="num">0);
              weight = (float4)(matrix_w[shift_var_w + shift + k], matrix_w[shift_var_w + shift + window_in_h], class="num">0, class="num">0);
              break;
            case class="num">2:

常见问题

噪声市场中价格序列常被随机扰动掩盖真实驱动,需结合跨资产关联与预测编码补盲区,单看价格易误判趋势起点。
重点是把多头卷积的分头偏移计算用 OpenCL 卷积核重写,保证各头独立提取不同周期特征,再喂给决策层。
小布已内置 AIGC 跨资产诊断,打开对应品种页即可看改良 Transformer 生成的倾向信号,不用自己搭环境。
偏移量若按全局步长算会串头,必须按头维度局部寻址,否则不同周期特征混叠导致预测偏置。
它用预测编码显式建模资产间残差,回测中噪声市况下误报率倾向更低,但仍是概率信号非确定性结论。