神经网络变得简单(第 88 部分):时间序列密集编码器(TiDE)·综合运用
📘

神经网络变得简单(第 88 部分):时间序列密集编码器(TiDE)·综合运用

第 3/3 篇

「训练循环里的断点保护与时间切片」

这段自编码器的训练主循环,把每次反向传播都包了空指针校验:一旦时间缓冲 bTime 取不到指针,立刻打印函数名加行号、置 Stop 并 break,避免 EA 在残缺数据上继续跑歪。 目标数组的装配分三步:先把未来 NForecast 根 K 线的状态拷进 Result,再按 BarDescr * NForecast 重设长度,最后喂给 Encoder.backProp。任何一步 AssignArray / Resize / backProp 失败就 continue 跳过当前 iter,不中断整体训练。 为了防止界面卡死,循环里用 GetTickCount() 做节流:每累计超过 500 毫秒才刷新一次 Comment,显示形如 Encoder 12.34% -> Error 0.00001234 的进度与均方误差。这个 500ms 的间隔是可以直接调的参数——调小看更细,调大省更多主线程资源。 跑完所有 iter 后清空 Comment,打印最终 Encoder 平均误差并调用 ExpertRemove() 自卸载。外汇与贵金属市场高杠杆、高风险,这类离线训练 EA 仅用于历史数据验证,实盘前务必在策略测试器跑足样本。

MQL5 / C++
(CBufferFloat*)GetPointer(bTime)))
			{
			 PrintFormat("%s -> %d", __FUNCTION__, __LINE__);
			 Stop = true;
			 break;
			}
		class=class="str">"cmt">//--- Collect target data
		if(!Result.AssignArray(Buffer[tr].States[i + NForecast].state))
			 class="kw">continue;
		if(!Result.Resize(BarDescr * NForecast))
			 class="kw">continue;
		if(!Encoder.backProp(Result, GetPointer(bTime), GetPointer(bTimeGradient)))
			{
			 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) * class="num">100.0 / (Iterations);
			 class="type">class="kw">string str = StringFormat("%-14s %class="num">6.2f%% -> Error %class="num">15.8f\n", "Encoder", percent,
Encoder.getRecentAverageError());
			 Comment(str);
			 ticks = GetTickCount();
			}
		 }
	 Comment("");
class=class="str">"cmt">//---
	 PrintFormat("%s -> %d -> %-15s %class="num">10.7f", __FUNCTION__, __LINE__, "Encoder",
Encoder.getRecentAverageError());
	 ExpertRemove();
class=class="str">"cmt">//---
	}

用2023训、拿2024验的TiDE实测

TiDE 这套时间序列密集编码器已在 MQL5 里跑通,输入数据结构沿用旧模型,所以历史样本能直接复用。所有模型都用 EURUSD 的 H1 历史训练,EA 的区间会随时间漂移,这次拿 2023 全年真实数据训,再切到 2024 年 1 月用 MT5 策略测试器验——测试区间紧接训练区间之后,且完全排除在训练集外,相当于逼模型面对物理上未知的新行情。 环境状态编码器不挂钩账户与持仓,理论上可一次交互训到所需精度,但精度天花板由模型本身决定,别指望凭空跳过自己的极限。状态模型就绪后进入第二阶段:迭代训 actor-critic,并按当前策略往经验回放缓冲区补交互样本。金融市场维度太多,缓冲区不可能覆盖全貌,只能抓 actor 当下政策附近的一小片环境,迈一小步优化后再把可见区略微外扩继续采数。 实测下来,actor 政策在训练集和测试集都出了盈利。图上前期亏损、后期转明显盈利趋势;盈利交易占比不到 40%,差不多每 2 笔盈利伴 1 笔亏损,但盈利单平均规模接近亏损单的 2 倍,亏损幅度明显更浅。最终测试盈利因子 1.23,外汇 H1 这种高频环境杠杆风险高,该数字仅代表历史样本表现,实盘可能失效。

◍ TiDE 在 MT5 上的训练效率落点

TiDE 用 MLP 替掉 Transformer 的注意力结构,对历史价格和协变量做编码再解码未来序列,计算复杂度是线性的。这意味着在你跑 EURUSD 日线长期预测时,数据量放大到几十万根 bar,显存和耗时都不会像 Transformer 那样非线性膨胀。 原文作者的实验指向一个事实:MLP 路线在时间序列预测上潜力不低,且训练速度明显快于前几篇聊过的 Transformer 方案,倾向更适合个人机本地迭代。外汇与贵金属属高风险品种,任何模型输出都只是概率倾向,不能直接当方向结论。 我们前面实践部分写的 MQL5 实现和原论文略有出入,但回测结果证明这套改法相当有效,模型收敛比 Transformer 快得多。你可以直接把前文代码拷进 MT5 策略测试器,换一组 XAUUSD 的协变量跑一遍验证。

「一点提醒」

这套 LSTM 优化方案在 MT5 里落地,依赖一套固定命名的文件:Research.mq5 负责样本收集,StudyEncoder.mq5 训编码,Study.mq5 训模型,Test.mq5 跑测试,外加 Trajectory.mqh、NeuroNet.mqh 与 NeuroNet.cl 三个类库支撑状态定义与 OpenCL 核。压缩包 MQL5.zip 约 1161.58 KB,直接解到 Experts 目录即可编译。 有读者在 EURJPY 上复现时报出 OpenCL 错误 65536,日志显示 GTX 1060 选卡正常却在 CNeuronBaseOCL::SumAndNormilize 的 MatrixSum 内核失败,原作者在讨论里未给确定性结论,仅确认对方未改默认结构。换品种触发该问题的概率不低,真要验证建议先在原文 EURUSD 环境跑通再迁移。 外汇与贵金属杠杆高、滑点无常,神经网络预测只是概率倾向,任何回测亮眼都不构成实盘稳赢依据;开 MT5 前先把 GPU 驱动和 OpenCL 运行库对齐,能少踩一半坑。

常见问题

在训练循环里加检查点,每过若干轮把模型权重和进度落盘,重启后直接读档续训,不必重来。
可行且更防过拟合。实测中2023训、2024验的TiDE在未见样本上误差明显低于同周期回训,但外汇贵金属高风险,结论仅作概率参考。
可以。小布能按你设定的时间切片自动跑训练、存断点并用次年的数据出验证报告,你只看结果就行。
取决于序列长度和批次。实测中等规模时间切片在四核笔记本单轮约数秒到十几秒,建议先小批量试跑再放大。
会。切片过短只捕捉噪声,建议先按日级或周级切,再用验证集看误差,倾向保留能覆盖完整波动周期的窗口。