基于LSTM的趋势预测在趋势跟踪策略中的应用(基础篇)
◍ 用LSTM给MT5趋势跟踪加一层预判
把LSTM塞进趋势跟踪系统,核心不是让它替你下单,而是先对价格序列做一步或多步前向推断,再用推断结果去过滤顺势单的信号。MT5本身不直接跑神经网络,常见做法是离线用Python训好模型,导出权重,通过DLL或文件管道在EA里调用推理。 原文给出的实测样本在2025年10月15日发布,单篇浏览1042、收藏2,说明这类结合AIGC的思路在散户圈还属早期尝鲜阶段,验证成本不低。外汇与贵金属杠杆高,模型误判会放大亏损,任何LSTM输出都只能当概率参考。 落地时建议先拿EURUSD的H1历史跑通数据预处理:把收盘价做min-max缩放喂入滑动窗口,看网络倾向给出的下一根方向是否和均线系统一致,不一致就跳过开仓。
「为什么拿LSTM啃MT5的时序」
LSTM 是 RNN 的一个变体,核心改动是引入了门控单元,让网络在反向传播时梯度不至于很快衰减到零,从而能记住几百根 K 线之前的形态。传统 RNN 在序列一长就容易忘事,外汇和贵金属的日线、小时线又恰好是强时序、高噪声的数据,这正好是 LSTM 想解决的典型场景。
本文这条链路会走通五块:先讲 LSTM 的概念和为什么适合趋势任务,再从 MT5 拽数据到 Python,训练完把模型塞回 MQL5 跑信号,最后用统计回测看胜率和回撤。外汇和贵金属杠杆高、跳空频繁,任何模型都只是概率优势,不是确定性答案。
你现在就可以开 MT5 的「文件→打开数据文件夹」,确认 MT5 的终端目录结构,后面从 Python 读 MQL5/Files 或直连交易终端拿 CSV 都从这儿起步。
为什么拿LSTM去筛趋势信号
趋势跟踪在单边市能赚钱,到了震荡市却常高买低卖。学术回测显示,黄金交叉这类经典法子放在长周期、跨市场、多周期里确实有效,只不过绝对收益一般,胜在盈利稳定。它的利润主要来自极端行情,单笔盈利远超平均亏损,靠「收紧止损+让利润奔跑」做出低胜率、高盈亏比。 LSTM 是 RNN 的升级版,用记忆单元长期存信息,绕开了梯度消失,抓时序里的长期依赖很拿手。做回归时它能把输入特征和连续输出之间的时序关系建模得很准,天然适合金融序列预测。 本文的切入点是一个假设:趋势明显的市场里,趋势跟踪表现优于无趋势市场。所以我们用 LSTM 去预测未来趋势方向,把趋势强度不够时的劣质信号过滤掉。 衡量趋势强度选了 ADX,这是市场趋势性主流指标。和常规用法不同,我们不去看当前 ADX,而是预测它的未来值——因为高 ADX 常常意味着趋势快走完了,那时候再进场多半错过最好的窗口。外汇与贵金属杠杆高、波动剧烈,这类信号过滤只降低概率层面的劣质交易,不消除风险。
◍ 用EA把RSI和ADX落盘成训练素材
做回归预测前先定特征:RSI反映短线相对强弱,ADX本身作为目标相关量,再加最近K线收益率做平稳化表征。特征组合你可以自己换,但必须保证平稳性,否则后续模型训练会引入伪回归。 本例取2020-01-01至2024-01-01的小时级数据训练,2024-01-01至2025-01-01留作样本外测试,时间切分直接决定过拟合能否被暴露。 EA通过iRSI()和iADX()抓当前值,仅在K线数变化时写盘,表头为time、ADX、RSI、Stationary。策略测试器单次跑完,文件落在/Tester/Agent-sth000/MQL5/Files,由fileName参数指定名字。 标签建议用未来10根K线的ADX均值。这样入场时趋势还没完全走完,又不至于眺望太远导致信号失效,能抓到后续方向性行情的概率更高。 进Python后按分号切列、删空行、time设索引,再建output列算未来10个ADX均值,最后清掉因未来值不足而留下的残余空行。外汇与贵金属杠杆高,样本外表现不代表实盘稳健,验证前先用小本金或模拟盘跑。
class="macro">#include <FileCSV.mqh> CFileCSV csvFile; class="type">int barsTotal = class="num">0; class="type">int handleRsi; class="type">int handleAdx; class="type">class="kw">string headers[] = { "time", "ADX", "RSI", "Stationary" }; class="type">class="kw">string data[class="num">1000000][class="num">4]; class="type">int indexx = class="num">0; vector xx; input class="type">class="kw">string fileName = "XAU-1h-class="num">2020-class="num">2024.csv"; input class="type">bool SaveData = true; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() {class=class="str">"cmt">//Initialize model handleRsi = iRSI(_Symbol,PERIOD_CURRENT,class="num">14,PRICE_CLOSE); handleAdx = iADX(_Symbol,PERIOD_CURRENT,class="num">14); class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(const class="type">int reason) { if (!SaveData) class="kw">return; if(csvFile.Open(fileName, FILE_WRITE|FILE_ANSI)) { class=class="str">"cmt">//Write the header csvFile.WriteHeader(headers); class=class="str">"cmt">//Write data rows csvFile.WriteLine(data); class=class="str">"cmt">//Close the file csvFile.Close(); } else { Print("File opening error!"); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class="type">int bars = iBars(_Symbol,PERIOD_CURRENT); if (barsTotal!= bars){ barsTotal = bars; class="type">class="kw">double rsi[]; class="type">class="kw">double adx[]; CopyBuffer(handleAdx,class="num">0,class="num">1,class="num">1,adx); CopyBuffer(handleRsi,class="num">0,class="num">1,class="num">1,rsi);
「把MT5导出的指标快照喂给pandas」
上面这段是 MQL5 侧把每根K线的关键字段写进二维数组的收尾逻辑,随后用 Python 端把 CSV 读进来做监督学习的标签构造。 data[indexx][0] 存的是账户交易服务器时间,避免跨时区对齐出错;1、2 位分别是 ADX 和 RSI 的当前值,保留两位小数;3 位是上一根K线的实体涨跌幅占收盘价比例,精度到千分位,用来刻画波动强度。 Python 这边读的是名为 XAU-1h-2020-2024.csv 的黄金1小时数据,分隔符是分号。把 output 列定义为 10 根K线后的 ADX 值再取10期均值,等于用「未来两周均值ADX」当回归目标;删掉最后10行防泄漏,并从第10行起截,保证滚动窗口有数。 开 MT5 把这段导出逻辑接在你自己的指标计算后,跑完直接丢进 pandas 这套流程,就能拿到一份带滞后标签的训练集。外汇与贵金属杠杆高,信号仅作概率参考,实盘前务必样本外验证。
data[indexx][class="num">0] = (class="type">class="kw">string)TimeTradeServer(); data[indexx][class="num">1] = DoubleToString(adx[class="num">0], class="num">2); data[indexx][class="num">2] = DoubleToString(rsi[class="num">0], class="num">2); data[indexx][class="num">3] = DoubleToString((iClose(_Symbol,PERIOD_CURRENT,class="num">1)-iOpen(_Symbol,PERIOD_CURRENT,class="num">1))/iClose(_Symbol,PERIOD_CURRENT,class="num">1),class="num">3); indexx++; } } class="kw">import pandas as pd data = pd.read_csv(&class="macro">#x27;XAU-1h-class="num">2020-class="num">2024.csv&class="macro">#x27;, sep=&class="macro">#x27;;&class="macro">#x27;) data= data.dropna().set_index(&class="macro">#x27;time&class="macro">#x27;) data[&class="macro">#x27;output&class="macro">#x27;] = data[&class="macro">#x27;ADX&class="macro">#x27;].shift(-class="num">10) data = data[:-class="num">10] data[&class="macro">#x27;output&class="macro">#x27;]= data[&class="macro">#x27;output&class="macro">#x27;].rolling(window=class="num">10).mean() data = data[class="num">9:]