基于LSTM的趋势预测在趋势跟踪策略中的应用·综合运用
(3/3)·当LSTM预测的未来ADX接手信号过滤,趋势跟踪策略如何告别震荡期的高买低卖
很多交易者把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 倾向改变信号频率。
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 实盘里,这种清理能避免一类典型事故——人工干预后机器人以为还在场,结果反向信号来时既不加仓也不对冲。外汇与贵金属杠杆高,这类状态不同步可能放大滑点损失,建议直接把这段粘进自己的订单管理函数里验证。
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%
盈亏比:<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 更稳。