基于LSTM的趋势预测在趋势跟踪策略中的应用·综合运用
🧠

基于LSTM的趋势预测在趋势跟踪策略中的应用·综合运用

(3/3)·当LSTM预测的未来ADX接手信号过滤,趋势跟踪策略如何告别震荡期的高买低卖

偏理论 第 3/3 篇

很多交易者把LSTM当成黑箱直接丢进EA,却连训练数据是否平稳都没验证,结果样本外一跑就崩。另一些人用当前ADX判定趋势,等信号出来趋势已近尾声。本篇把数据提取、Python训练、MQL5嵌入和统计回测串成一条线,看清这套闭环到底卡在哪。

◍ 把 LSTM 推理塞进 MT5 的 tick 流程

这段逻辑把 ONNX 模型跑在 EA 的实时循环里:每次 K 线数变化才重算,避免每 tick 空转。注意 barsTotal 与 iBars 的对比是唯一触发闸门,漏掉它 CPU 占用会直接翻倍。 数据装配用 5 根 K 线做窗口:索引 0~4 分别写入 ADX、RSI,以及每根收盘相对开盘的涨跌幅(已转 float)。其中 (iClose-iOpen)/iClose 把价格差归一化,模型吃的是这个比值而非绝对点数。 持仓校验放在闸门内:buypos/sellpos 若指向的 ticket 已不在或 magic 不对,立刻归零,防止旧单幽灵触发信号。外汇与贵金属杠杆高,这种脏状态不清理可能误平或漏平。 OnTick 里先 CopyBuffer 取快慢 MA 各 2 根、ADX 1 根。快慢线金叉且当前无双向持仓时,才调 getData + OnnxRun;out[0][0] 大于 threshold 才 executeSell。threshold 是你可以直接调的旋钮,0.5 还是 0.7 倾向改变信号频率。

MQL5 / C++
for(class="type">int i =class="num">0; i<class="num">5; i++){
  data[class="num">0][i][class="num">0] = (class="type">float)adx[i];
  data[class="num">0][i][class="num">1] = (class="type">float)rsi[i];
  data[class="num">0][i][class="num">2] = (class="type">float)((iClose(_Symbol,PERIOD_CURRENT,class="num">5-i)-iOpen(_Symbol,PERIOD_CURRENT,class="num">5-i))/iClose(_Symbol,PERIOD_CURRENT,class="num">5-i));
  }
}
class="type">int bars = iBars(_Symbol,PERIOD_CURRENT);
if (barsTotal!= bars){
  barsTotal = bars;
if(buypos>class="num">0&&(!PositionSelectByTicket(buypos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){
buypos = class="num">0;
}
if(sellpos>class="num">0&&(!PositionSelectByTicket(sellpos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){
sellpos = class="num">0;
}
OnnxRun(lstmHandle, ONNX_NO_CONVERSION, data, out);
class="type">void OnTick()
  {
  class="type">int bars = iBars(_Symbol,PERIOD_CURRENT);
  if (barsTotal!= bars){
    barsTotal = bars;
    class="type">class="kw">double maFast[];
    class="type">class="kw">double maSlow[];
    class="type">class="kw">double adx[];
    CopyBuffer(handleMaFast,BASE_LINE,class="num">1,class="num">2,maFast);
    CopyBuffer(handleMaSlow,BASE_LINE,class="num">1,class="num">2,maSlow);
    CopyBuffer(handleAdx,class="num">0,class="num">1,class="num">1,adx);
    class="type">class="kw">double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    class="type">class="kw">double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    class="type">class="kw">double lastClose = iClose(_Symbol, PERIOD_CURRENT, class="num">1);
    class=class="str">"cmt">//The order below matters
    if(buypos>class="num">0&& lastClose<maSlow[class="num">1]) trade.PositionClose(buypos);
    if(sellpos>class="num">0 &&lastClose>maSlow[class="num">1])trade.PositionClose(sellpos);
    if(maFast[class="num">1]<maSlow[class="num">1]&&maFast[class="num">0]>maSlow[class="num">0]&&sellpos == buypos){
      getData();
      OnnxRun(lstmHandle, ONNX_NO_CONVERSION, data, out);
      if(out[class="num">0][class="num">0]>threshold)executeSell();}
    if(maFast[class="num">1]>maSlow[class="num">1]&&maFast[class="num">0]<maSlow[class="num">0]&&sellpos == buypos){
      getData();
      OnnxRun(lstmHandle, ONNX_NO_CONVERSION, data, out);

持仓票据失效的兜底清理

EA 跑久了最怕一种静默错误:之前开仓的 ticket 还在变量里,但仓位其实已经被手动平掉、被别的魔法码接管,或者跨品种串了台。上面这段逻辑就是在每次 tick 里做一道安检。 对 buypos 和 sellpos 各自判断:如果 ticket 大于 0,但 PositionSelectByTicket 选不到这张单,或者选到了但 POSITION_MAGIC 不等于本 EA 的 Magic,就把对应变量归零。归零后后续开仓判断才会重新走,不会误以为「已经有单」而跳过信号。 在 MT5 实盘里,这种清理能避免一类典型事故——人工干预后机器人以为还在场,结果反向信号来时既不加仓也不对冲。外汇与贵金属杠杆高,这类状态不同步可能放大滑点损失,建议直接把这段粘进自己的订单管理函数里验证。

MQL5 / C++
if(out[class="num">0][class="num">0]>threshold)executeBuy();}
 if(buypos>class="num">0&&(!PositionSelectByTicket(buypos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){
   buypos = class="num">0;
   }
 if(sellpos>class="num">0&&(!PositionSelectByTicket(sellpos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){
   sellpos = class="num">0;
   }
}

「XAUUSD样本外回测与窗口法选择」

在 MT5 策略测试器里跑 XAUUSD 的 1 小时图,样本外区间取 2024-01-01 到 2025-01-01。先跑原始策略当基准,再跑挂了 LSTM 的版本,ADX 阈值锁在 30——这是常见强趋势临界值。 LSTM 把原始交易过滤掉约 70%,盈亏比从 1.48 抬到 1.52,线性回归相关性也比基准高,说明收益曲线更稳一些。外汇和贵金属杠杆高,回测优不等于实盘稳,样本外表现只代表历史概率。 机器学习 EA 和简单规则不同,内部训练参数主导性能,换一批训练数据结果可能差很多。一次性喂全部历史也不理想,旧数据时效性弱还稀释信号。 数据少就用扩展窗口,数据够就滑窗:滑窗固定长度往前滚,丢最旧补最新;扩展窗口则只增不减。下面这组 2015-01-01 到 2025-01-01 的滑窗结果,还有打磨空间。 盈亏比:1.24 最大回撤:-250.56 平均盈利:12.02 平均亏损:-5.20 胜率:34.81%

MQL5 / C++
盈亏比:<span class="number">class="num">1.24</span>
最大回撤:-<span class="number">class="num">250.56</span>
平均盈利:<span class="number">class="num">12.02</span>
平均亏损:-<span class="number">class="num">5.20</span>
胜率:<span class="number">class="num">34.81</span>%

◍ EA 表现卡在哪一层

EA 跑出来的曲线,本质上取决于模型从行情里抠出了多少可重复的优势。如果原始信号里只有极少数具备统计显著胜率,后面再怎么筛、怎么加权,都只是把噪声重新包装。 回测里真正有用的信号比例,是第一条硬指标。经验上,原始多空信号中具备显著优势(如样本内 AUC 持续 > 0.58)的占比若低于 15%,后续特征筛选的边际价值会快速衰减。 数据利用常被散户忽略:把输入特征的贡献度排个序,往往能翻出被常规指标掩盖的无效性窗口,比如某贵金属跨周期波动率差在美盘初段持续偏斜。模型选型先定清楚是分类还是回归,再死磕训练参数,而不是拿默认配置碰运气。 预测目标别直奔「下一根涨跌」。改去建模那些间接撬动结果的变量——比如流动性薄厚、订单流失衡度——反而更稳。机器学习对外汇、贵金属这类高杠杆品种只是思维框架,实盘前务必用 MT5 严格验证假设,杠杆风险极高。

画得少,看得清

整套 LSTM 趋势预测框架跑下来,真正落地的文件就四个:FileCSV.mqh 负责把行情存成 CSV,LSTM_Demonstration.ipynb 在 Python 里训模型,LSTM-TF-XAU.mq5 是把训好的模型接进 MT5 的 EA,OHLC Getter.mq5 专门拉数据。压缩包 LSTM-Trend.zip 体积 132.27 KB,作者明确说没把 2008 年以来的历史模型全塞进去,避免文件过重,只给可复用的训练框架。 外汇与贵金属杠杆高、滑点跳空频繁,LSTM 给出的只是概率倾向,实盘前必须用滚动或扩展窗口回测在自己样本上验证。打开 MT5 把 OHLC Getter 挂上 XAUUSD,跑通数据导出再用 ipynb 训一版,比直接信现成 onnx 更稳。

让小布替你跑这套诊断
LSTM模型的样本外衰减、ADX预测偏离度这些诊断,小布盯盘的AIGC模块已内置,打开对应品种页即可看到实时评估,你只需判断要不要跟信号。

常见问题

高ADX常意味着趋势接近尾声,用当前值入场易错失最佳窗口;预测未来ADX可提前识别趋势强度演化,过滤掉弱势段的劣质信号。
RSI、K线收益率、ADX等输入需具备平稳性,否则梯度更新会受非平稳序列干扰,建议先做差分或收益率变换再入模。
通过CFileCSV类把特征导出成CSV,Python侧训练后回写参数或推理结果,EA侧读取并依预测值控制下单逻辑,中间用文件或管道通信。
目前小布内置的是通用趋势强度与信号衰减诊断,自定义模型权重暂需本地推理,但诊断结论的呈现方式可对照参考。
训练截止后整段独立区间即可,例如训练用2020至2024年小时线,测试取其后一年同周期数据,中间不留重叠。