交易中的神经网络:基于 ResNeXt 模型的多任务学习(终篇)·综合运用
🧠

交易中的神经网络:基于 ResNeXt 模型的多任务学习(终篇)·综合运用

(3/3)· 前篇铺好理论与模块,本篇把编码器拼起来、接上多任务头并跑通回测,补全整套框架

案例拆解新手友好 第 3/3 篇
很多人以为多任务网络一定要从头写一个大类,其实用现成的残差分组卷积块就能像搭乐高一样拼编码器。把共享编码器和多头输出分开看,反而更容易调参,也不会被单体对象绑死。

持仓动作数组的归一化与止损裁剪

这段逻辑出现在强化学习代理输出交易动作之后,负责把原始浮点结果压成 MT5 可下单价。tp>0 的分支里,先对 sl 做截断:用 MathAbs(sl)/(MaxSL*Point()) 算比例,MathMax 封顶到 1,再 MathMax(…, 0.01) 保证下限 0.01,避免零止损。 tp 则直接除以 MaxTP*Point() 并 MathMin 截到 1,意味着盈利空间超过最大允许值就归一为满格。result[0] 写的是仓位系数,取账户态的 account[0]/100*0.01 与 0.011 的较大者,实盘里这对应约 1.1% 风险敞口的底仓。 else 分支处理不开新仓只调已有止损的情形。argmax==0 或 argmax>argmin 时进入,用循环扫 target 与 fstate 差值:tp 取各段 target[j]+fstate[j,2]-fstate[j,0] 的最小值,sl 取对应下沿的最大值,一旦 cur_sl 已小于等于某段下沿就 break,说明止损已碰到位无需再扩。 外汇与贵金属杠杆高,这类自动裁剪若 MaxSL 设错,可能在黄金跳空时 sl 比例被截到 0.01 仍挡不住滑点,建议把 MaxSL 按品种 ATR(14) 的 3 倍预填后再跑。

MQL5 / C++
if(tp > class="num">0)
{
 sl = (class="type">class="kw">float)MathMax(MathMin(MathAbs(sl) / (MaxSL * Point()), class="num">1), class="num">0.01);
 tp = (class="type">class="kw">float)MathMin(tp / (MaxTP * Point()), class="num">1);
 result[class="num">0] = class="type">class="kw">float(MathMax(Buffer[tr].States[i].account[class="num">0]/class="num">100*class="num">0.01, class="num">0.011));
 result[class="num">1] = tp;
 result[class="num">2] = sl;
 for(class="type">int j = class="num">3; j < NActions; j++)
   result[j] = class="num">0;
 bActions.AssignArray(result);
}
 }
 else
 {
 if(argmax == class="num">0 || argmax > argmin)
  {
  class="type">class="kw">float tp = class="num">0;
  class="type">class="kw">float sl = class="num">0;
  class="type">class="kw">float cur_sl = class="type">class="kw">float(MaxSL * Point());
  class="type">class="kw">ulong pos = class="num">0;
  for(class="type">class="kw">ulong j = class="num">0; j < argmin; j++)
   {
   tp = MathMin(tp, target[j] + fstate[j, class="num">2] - fstate[j, class="num">0]);
   pos = j;
   if(cur_sl <= target[j] + fstate[j, class="num">1] - fstate[j, class="num">0])
    break;
   sl = MathMax(sl, target[j] + fstate[j, class="num">1] - fstate[j, class="num">0]);
   }
  if(tp < class="num">0)

◍ 策略网络里的止损止盈归一化

在强化学习交易代理的输出层,止损和止盈需要先压缩到 [0,1] 区间才能喂给策略网络。下面这段把绝对止损点数除以 MaxSL*Point() 做归一,并用 MathMax 限制下限 0.01,避免零止损导致网络梯度爆炸。 sl = (float)MathMax(MathMin(MathAbs(sl) / (MaxSL * Point()), 1), 0.01); tp = (float)MathMin(-tp / (MaxTP * Point()), 1); 这两行把 sl 夹在 0.01~1 之间,tp 夹在 0~1 之间。注意 tp 用了负号,说明原始 tp 变量存的是负值(空头盈利距离),归一后转成正向比例。 result[3] 写入仓位系数,取账户浮亏占比的 0.01 倍与 0.011 的较大值,意味着单步最小下注比例被锁在 1.1% 附近。result[4]、result[5] 分别存 tp、sl 归一值,前三个动作位先清零再由 bActions.AssignArray 送出。 反向传播阶段若 Actor.backProp 返回 false,立刻置 Stop=true 并 break,训练循环超时阈值设为 500ms(GetTickCount()-ticks>500)。外汇与贵金属杠杆高,这类 Agent 策略实盘前必须在 MT5 策略测试器跑满回测,参数失真可能放大爆仓概率。

MQL5 / C++
sl = (class="type">class="kw">float)MathMax(MathMin(MathAbs(sl) / (MaxSL * Point()), class="num">1), class="num">0.01);
tp = (class="type">class="kw">float)MathMin(-tp / (MaxTP * Point()), class="num">1);
result[class="num">3] = class="type">class="kw">float(MathMax(Buffer[tr].States[i].account[class="num">0]/class="num">100*class="num">0.01,class="num">0.011));
result[class="num">4] = tp;
result[class="num">5] = sl;
for(class="type">int j = class="num">0; j < class="num">3; j++)
   result[j] = class="num">0;
bActions.AssignArray(result);
class=class="str">"cmt">//--- Actor Policy
if(!Actor.backProp(GetPointer(bActions), (CBufferFloat*)GetPointer(bAccount),
GetPointer(bGradient)))
   {
   PrintFormat("%s -> %d", __FUNCTION__, __LINE__);
   Stop = true;
   break;
   }
target = vector<class="type">class="kw">float>::Zeros(NActions / class="num">3);
for(class="type">int a = class="num">0; a < NActions; a += class="num">3)
   target[a / class="num">3] = class="type">class="kw">float(result[a] > class="num">0);
if(!Result.AssignArray(target) ||
!Probability.backProp(Result, GetPointer(Actor), LatentLayer) ||
!Actor.backPropGradient((CBufferFloat*)NULL, (CBufferFloat*)NULL, LatentLayer))
   {
   PrintFormat("%s -> %d", __FUNCTION__, __LINE__);
   Stop = true;
   break;
   }
if(GetTickCount() - ticks > class="num">500)
   {
   class="type">class="kw">double percent = class="type">class="kw">double(iter + i - start) * class="num">100.0 / (Iterations);

「把两个网络的误差打到图表上」

这段片段干的事很直接:在每轮训练 tick 里,把 Actor 与 Probability 两个网络的最近平均误差用 Comment 刷到图表左上角,方便肉眼盯收敛。格式串里 %6.2f%% 控制百分比两位小数,%15.8f 给误差留了 8 位小数宽度,浮点抖动一眼能看出来。 StringFormat 先把两行文本拼进 str,再统一交给 Comment;随后用 GetTickCount 重置计时,控制下一次打印节奏。注意 Comment("") 在循环外清屏,避免 EA 停止后文字残留。 收尾处用 PrintFormat 把函数名、行号、网络名和误差打到日志,精度 10.7f;最后 ExpertRemove 让 EA 自卸载。外汇与贵金属行情噪声大,这类误差曲线只反映样本内拟合,实盘泛化可能偏差,务必先在策略测试器跑完再谈信任。

MQL5 / C++
  class="type">class="kw">string str = StringFormat("%-14s %class="num">6.2f%% -> Error %class="num">15.8f\n", "Actor",
percent, Actor.getRecentAverageError());
  str += StringFormat("%-13s %class="num">6.2f%% -> Error %class="num">15.8f\n", "Probability",
percent, Probability.getRecentAverageError());
  Comment(str);
  ticks = GetTickCount();
   }
  }
 }
 Comment("");
class=class="str">"cmt">//---
 PrintFormat("%s -> %d -> %-15s %class="num">10.7f", __FUNCTION__, __LINE__,
"Actor", Actor.getRecentAverageError());
 PrintFormat("%s -> %d -> %-15s %class="num">10.7f", __FUNCTION__, __LINE__,
             "Probability", Probability.getRecentAverageError());
 ExpertRemove();
class=class="str">"cmt">//---
}

用未见过的数据逼出模型真本事

训练完的「智代」行为政策不能直接信,得拿没参与过训练的样本去压。我们在逻辑里塞了一层短期走势概率预判:只有智能体准备下单的方向和这个概率模型里的最可能趋势重叠,订单才真正发出。相当于给策略加了道趋势过滤器,避免逆着主概率跑。 测试在 MT5 策略测试器里跑,用的是 2025 年 1 月行情,这段数据完全不在训练集内,其余参数和造训练集时保持一致。这种隔离能更贴近实盘碰未见数据的状态,外汇与贵金属杠杆高、滑点跳空频繁,隔离测试只是降低过拟合错觉,不承诺任何胜率。 实测 60 笔成交,日均约 3 笔;平仓盈利占比 43% 出头。关键在盈亏比——平均和最大盈利差不多是对应亏损的两倍,所以财务结果偏正。盈利因子 1.52,恢复因子 1.14,说明这段样本下净值回撤后爬回来的能力尚可,但换到其他月份可能明显变脸。

◍ 把这条线请下神坛

ResNeXt 多任务框架在 MT5 里跑通的关键,不在架构多玄乎,而在共享编码器加专用头的组合能压住过拟合——同一次训练里多任务并行,逼出的市场表征比单任务更泛化。 模块化参数让你按品种调卷积分组数,但原文给出的 MQL5 实现(Research / Study / Test 等mq5)只是在时间序列与趋势预测上验证过有效性,样本外韧性来自新增趋势模块,不是凭空抗跌。 真要上实盘,先在更具代表性的数据集重训,再用 Test.mq5 跑全样本回测;外汇与贵金属杠杆高、跳空频繁,模型在纸面稳健不等于实盘概率占优。 开 MT5 把 NeuroNet.mqh 和 Study.mq5 调出来,改一组卷积宽度跑一遍,比信任何「新机遇」口号都实在。

把回测巡检交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到多任务信号与波动预警,你只管判断要不要跟。

常见问题

通过 CNeuronResNeXtBlock 的调节参数限制分组数与深度,实时处理 tick 时延迟可控,不会卡在决策窗口。
框架允许动态转移优先级,行情剧烈时模型自动倾向波动头,平稳段更看趋势头,概率上更稳。
多是归一化方法没随数据频率切换,用前文给的构建模块时注意匹配品种周期即可降低异常。
目前小布内置的是信号诊断视图,模型需用户在 MT5 端部署,但盘面特征可对照着看,省去手动记参数。
联合训练抗噪能力提升的是模型稳定性,不代表交易无风险,贵金属杠杆高,实盘仍可能大幅回撤。