基于LSTM的趋势预测在趋势跟踪策略中的应用
概述
长短期记忆网络(LSTM)是一种特殊的循环神经网络(RNN),其设计初衷是通过有效捕捉数据中的长期依赖关系,并解决传统RNN存在的梯度消失问题,从而实现对时序数据的高效建模。本文将系统阐述如何利用LSTM进行未来趋势预测,进而提升趋势跟踪策略的实战表现。具体内容涵盖这些模块:LSTM关键概念介绍与发展契机、从MetaTrader 5平台提取数据、在Python中构建并训练模型、将机器学习模型嵌入MQL5中、基于统计回测的结果分析与改进方向。
契机
趋势跟踪策略在趋势明显的市场中能实现盈利,但在震荡市场中表现欠佳——此时策略往往以高价买入、低价卖出。学术研究表明,包括"黄金交叉"在内的经典趋势跟踪策略,在历史长周期、多市场及多时间框架下均展现出有效性。尽管这类策略的绝对收益可能并不突出,但其盈利稳定性已得到验证。该类策略的核心盈利来源在于极端行情,其单次盈利幅度显著超过平均亏损。通过"收紧止损+让利润奔跑"的机制,策略实现了低胜率但高盈亏比的交易特征。
LSTM是RNN的改进版本,专门用于捕捉时序数据中的长期依赖关系。其通过记忆单元实现信息的长期存储,有效解决了传统RNN的梯度消失问题。这种对历史序列信息的存储与调用能力,使LSTM在时间序列预测和趋势研判任务中表现卓越。对于回归问题,LSTM可精准建模输入特征与连续输出之间的时序关联,尤其适用于金融市场的预测场景。
本文旨在探索LSTM在趋势回归分析中的应用,通过预测未来趋势方向,过滤掉趋势强度不足时的劣质交易信号。其契机基于以下假设:趋势跟踪策略在趋势明显的市场中表现优于无趋势市场。
我们选用平均趋向指数(ADX)作为趋势强度量化工具,因其是衡量当前市场趋势性的主流指标。与传统用法不同,本研究将尝试预测ADX的未来值而非直接使用其当前值——这是因为高ADX值往往意味着趋势已接近尾声,此时入场可能错失最佳时机。
ADX计算方法:

数据准备与预处理
在获取数据前,需明确所需数据类型。我们计划使用多个特征构建回归模型,以预测未来ADX值。这些特征包括:反映市场当前相对强弱的RSI、作为收盘价的平稳化表征值的最近K线收益率、与预测目标直接相关的ADX值本身。请注意,这里我们仅阐述特征选择逻辑。您可以自定义特征组合,但是需要确保其合理性与平稳性。我们将采用2020年1月1日至2024年1月1日的小时级数据进行模型训练,并以2024年1月1日至2025年1月1日的数据作为样本外测试集。
明确数据需求后,让我们构建EA实现数据采集。
我们将使用该文章介绍的CFileCSV类,将数组数据以字符串形式保存为CSV文件。此过程的代码非常简洁,如下所示:
#include <FileCSV.mqh> CFileCSV csvFile; int barsTotal = 0; int handleRsi; int handleAdx; string headers[] = { "time", "ADX", "RSI", "Stationary" }; string data[1000000][4]; int indexx = 0; vector xx; input string fileName = "XAU-1h-2020-2024.csv"; input bool SaveData = true; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() {//Initialize model handleRsi = iRSI(_Symbol,PERIOD_CURRENT,14,PRICE_CLOSE); handleAdx = iADX(_Symbol,PERIOD_CURRENT,14); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if (!SaveData) return; if(csvFile.Open(fileName, FILE_WRITE|FILE_ANSI)) { //Write the header csvFile.WriteHeader(headers); //Write data rows csvFile.WriteLine(data); //Close the file csvFile.Close(); } else { Print("File opening error!"); } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { int bars = iBars(_Symbol,PERIOD_CURRENT); if (barsTotal!= bars){ barsTotal = bars; double rsi[]; double adx[]; CopyBuffer(handleAdx,0,1,1,adx); CopyBuffer(handleRsi,0,1,1,rsi); data[indexx][0] =(string)TimeTradeServer(); data[indexx][1] = DoubleToString(adx[0], 2); data[indexx][2] = DoubleToString(rsi[0], 2); data[indexx][3] = DoubleToString((iClose(_Symbol,PERIOD_CURRENT,1)-iOpen(_Symbol,PERIOD_CURRENT,1))/iClose(_Symbol,PERIOD_CURRENT,1),3); indexx++; } }
该EA用于跟踪记录指定交易品种的RSI和ADX数值。EA通过iRSI()和iADX()函数获取当前RSI与ADX值,并将时间戳、指标值及平稳化数据存储至CSV文件。CSV文件头包含:"time"、"ADX"、"RSI"和"Stationary"。当启用SaveData选项时,EA会在去初始化时将数据写入指定文件(路径由fileName参数定义)。系统在每个tick更新时追踪新数据,仅在K线数量变化时执行存储操作。
在策略测试器中以单次测试模式运行该EA。测试完成后,数据文件将被保存至以下路径:/Tester/Agent-sth000/MQL5/Files。
接下来,我们进入Python环境进行数据预处理,为机器学习模型训练做准备。
本研究采用监督学习框架,模型通过学习带标签的数据来预测目标值。训练过程中通过调整特征运算权重,最小化误差损失以生成最终输出。
建议使用未来10个ADX值的均值作为训练标签。该方法确保入场时趋势尚未完全形成,同时避免选取过于遥远的未来值导致信号失效。通过未来10个ADX值的均值反映后续数根K线的趋势强度,使入场点能有效捕获后续方向性行情的利润。
import pandas as pd data = pd.read_csv('XAU-1h-2020-2024.csv', sep=';') data= data.dropna().set_index('time') data['output'] = data['ADX'].shift(-10) data = data[:-10] data['output']= data['output'].rolling(window=10).mean() data = data[9:]
该代码读取CSV文件后,按分号(;)将数据分隔到不同的列中。随后,代码删除所有空行,并将“time”列设为索引,以确保数据按时间顺序排列,便于训练。接下来,新建名为“output”的列,用于计算未来10个ADX值的均值。之后,代码再次删除剩余的空行(因部分行可能无法提供足够的未来ADX值来计算输出)。
模型训练

上图展示了LSTM在训练阶段的核心目标:我们希望输入张量的维度(样本数, 时间步长, 特征数),其中time_steps表示用过去多少个时间点的数据来预测下一个值。例如,可用周一至周四的数据预测周五的某种结果。LSTM通过算法识别时间序列中的模式以及特征与结果之间的关系。它构建一层或多层神经网络,每层包含大量权重单元(神经元),对每个特征和每个时间步长赋予权重,最终输出预测值。
为简化操作,您只需运行下方代码,训练过程将自动完成。
import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense # Assume data is your DataFrame already loaded with the specified columns and a time-based index # data.columns should include ['ADX', 'RSI', 'Stationary', 'output'] # --- Step 1: Data Preparation --- time_step = 5 # Select features and target features = ['ADX', 'RSI', 'Stationary'] target = 'output' # --- Step 2: Create sequences for LSTM input --- def create_sequences(data, target_col, time_step): """ Create sequences of length time_step from the DataFrame. data: DataFrame of input features and target. target_col: Name of the target column. Returns: X, y arrays suitable for LSTM. """ X, y = [], [] feature_cols = data.columns.drop(target_col) for i in range(len(data) - time_step): seq_x = data.iloc[i:i+time_step][feature_cols].values # predict target at the next time step after the sequence seq_y = data.iloc[i+time_step][target_col] X.append(seq_x) y.append(seq_y) return np.array(X), np.array(y) # Create sequences X, y = create_sequences(data, target_col=target, time_step=time_step) # --- Step 3: Split into training and evaluation sets --- # Use a simple 80/20 split for training and evaluation X_train, X_eval, y_train, y_eval = train_test_split(X, y, test_size=0.2, shuffle=False) # --- Step 4: Build the LSTM model --- n_features = len(features) # number of features per time step model = Sequential() model.add(LSTM(50, input_shape=(time_step, n_features))) # LSTM layer with 50 units model.add(Dense(1)) # output layer for regression model.compile(optimizer='adam', loss='mse') model.summary() # --- Step 5: Train the model --- epochs = 50 batch_size = 100 history = model.fit( X_train, y_train, epochs=epochs, batch_size=batch_size, validation_data=(X_eval, y_eval) )
使用上述代码训练时,请注意以下要点:
-
数据预处理:务必保证数据按时间顺序排列。否则,在将数据分割为固定时间步长(time_steps)的区块时,可能会导致前瞻性偏差。
-
训练-测试划分:拆分训练集与测试集时,不要打乱数据。必须保持时间顺序,避免前瞻性偏差。
-
模型复杂度:对于时间序列,尤其在数据量有限时,无需堆叠过多层、神经元或迭代次数。过度复杂化模型易导致过拟合或高偏差参数。示例中的设置已经足够。
# --- Step 6: Evaluate the model --- eval_loss = model.evaluate(X_eval, y_eval) print(f"Evaluation Loss: {eval_loss}") # --- Step 7: Generate Predictions and Plot --- # Generate predictions on the evaluation set predictions = model.predict(X_eval).flatten() # Create a plot for predictions vs actual values plt.figure(figsize=(12, 6)) plt.plot(predictions, label='Predicted Output', color='red') plt.plot(y_eval, label='Actual Output', color='blue') plt.title('LSTM Predictions vs Actual Output') plt.xlabel('Sample Index') plt.ylabel('Output Value') plt.legend() plt.show()
该代码应输出验证集预测结果与真实值的均方误差(MSE),输出格式如下:

评估亏损值:57.405677795410156 计算方法:

其中,n为样本量;yi 为第i个样本的预测值,y^i为每个评估结果的实际值。
由计算过程可见,可通过比较模型损失与预测目标均值平方值,判断相对损失是否过高。同时需确保验证集损失与训练集损失相近,以此验证模型未对训练数据产生过拟合。
最后,为使模型适配MQL5环境,需将其保存为ONNX格式。由于LSTM模型不直接支持ONNX转换,需先将模型保存为函数式架构,并明确定义其输入和输出格式。完成此步骤后,即可导出为ONNX文件,供后续MQL5调用。
import tensorflow as tf import tf2onnx # Define the input shape based on your LSTM requirements: (time_step, n_features) time_step = 5 n_features = 3 # Create a new Keras Input layer matching the shape of your data inputs = tf.keras.Input(shape=(time_step, n_features), name="input") # Pass the input through your existing sequential model outputs = model(inputs) functional_model = tf.keras.Model(inputs=inputs, outputs=outputs) # Create an input signature that matches the defined input shape input_signature = ( tf.TensorSpec((None, time_step, n_features), dtype=tf.float32, name="input"), ) output_path = "regression2024.onnx" # Convert the functional model to ONNX format onnx_model, _ = tf2onnx.convert.from_keras( functional_model, input_signature=input_signature, # matching the input signature opset=15, output_path=output_path ) print(f"Model successfully converted to ONNX at {output_path}")
需注意,此处输入格式设为"None",表示模型可接受任意数量的样本输入。模型将自动为每个样本生成对应的预测结果,从而灵活适配不同批量的数据处理需求。
构建EA
保存好ONNX模型文件后,需将其复制至/MQL5/Files目录以备后续调用。
我们返回MetaEditor环境。将基于经典的金叉趋势跟踪策略进行扩展开发。该策略与我此前在前一篇机器学习文章 中实现的版本一致。基本逻辑是通过快慢两条移动平均线的交叉信号判断趋势。当两条移动平均线交叉时产生交易信号,交易方向跟随快速移动平均线,因此称为“趋势跟踪”。当价格穿越慢速移动平均线时触发离场信号,为跟踪止损留出更大空间。完整代码如下:
#include <Trade/Trade.mqh> //XAU - 1h. CTrade trade; input int MaPeriodsFast = 15; input int MaPeriodsSlow = 25; input int MaPeriods = 200; input double lott = 0.01; ulong buypos = 0, sellpos = 0; input int Magic = 0; int barsTotal = 0; int handleMaFast; int handleMaSlow; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { trade.SetExpertMagicNumber(Magic); handleMaFast =iMA(_Symbol,PERIOD_CURRENT,MaPeriodsFast,0,MODE_SMA,PRICE_CLOSE); handleMaSlow =iMA(_Symbol,PERIOD_CURRENT,MaPeriodsSlow,0,MODE_SMA,PRICE_CLOSE); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { int bars = iBars(_Symbol,PERIOD_CURRENT); //Beware, the last element of the buffer list is the most recent data, not [0] if (barsTotal!= bars){ barsTotal = bars; double maFast[]; double maSlow[]; CopyBuffer(handleMaFast,BASE_LINE,1,2,maFast); CopyBuffer(handleMaSlow,BASE_LINE,1,2,maSlow); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double lastClose = iClose(_Symbol, PERIOD_CURRENT, 1); //The order below matters if(buypos>0&& lastClose<maSlow[1]) trade.PositionClose(buypos); if(sellpos>0 &&lastClose>maSlow[1])trade.PositionClose(sellpos); if (maFast[1]>maSlow[1]&&maFast[0]<maSlow[0]&&buypos ==sellpos)executeBuy(); if(maFast[1]<maSlow[1]&&maFast[0]>maSlow[0]&&sellpos ==buypos) executeSell(); if(buypos>0&&(!PositionSelectByTicket(buypos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ buypos = 0; } if(sellpos>0&&(!PositionSelectByTicket(sellpos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ sellpos = 0; } } } //+------------------------------------------------------------------+ //| Expert trade transaction handling function | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { if (trans.type == TRADE_TRANSACTION_ORDER_ADD) { COrderInfo order; if (order.Select(trans.order)) { if (order.Magic() == Magic) { if (order.OrderType() == ORDER_TYPE_BUY) { buypos = order.Ticket(); } else if (order.OrderType() == ORDER_TYPE_SELL) { sellpos = order.Ticket(); } } } } } //+------------------------------------------------------------------+ //| Execute sell trade function | //+------------------------------------------------------------------+ void executeSell() { double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); bid = NormalizeDouble(bid,_Digits); trade.Sell(lott,_Symbol,bid); sellpos = trade.ResultOrder(); } //+------------------------------------------------------------------+ //| Execute buy trade function | //+------------------------------------------------------------------+ void executeBuy() { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); ask = NormalizeDouble(ask,_Digits); trade.Buy(lott,_Symbol,ask); buypos = trade.ResultOrder(); }
关于回测策略的验证方法及选择建议,本文不再展开详述。更多详细内容可参阅我此前发布的机器学习相关文章,链接已附此处。
现在,我们将基于该框架运行LSTM模型。
首先,需声明这些全局变量:指定模型输入/输出维度的参数和用于存储输入/输出数据的双维数组。另外,我们声明一个模型句柄,用于管理数据加载与预测结果提取的流程。该配置可确保模型与输入/输出变量间的数据流及交互逻辑的正确性。
#resource "\\Files\\regression2024.onnx" as uchar lstm_onnx[] float data[1][5][3]; float out[1][1]; long lstmHandle = INVALID_HANDLE; const long input_shape[] = {1,5,3}; const long output_shape[]={1,1};
接下来,在 OnInit()函数中,我们将初始化相关技术指标,如 RSI、ADX及ONNX模型。初始化过程中,需验证MQL5中声明的输入/输出维度是否与Python函数式模型中定义的规格一致。该步骤可确保数据格式兼容性,避免模型初始化错误,从而确保按照预期格式正确处理数据。
int handleMaFast; int handleMaSlow; int handleAdx; // Average Directional Movement Index - 3 int handleRsi; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() {//Initialize model trade.SetExpertMagicNumber(Magic); handleMaFast =iMA(_Symbol,PERIOD_CURRENT,MaPeriodsFast,0,MODE_SMA,PRICE_CLOSE); handleMaSlow =iMA(_Symbol,PERIOD_CURRENT,MaPeriodsSlow,0,MODE_SMA,PRICE_CLOSE); handleAdx=iADX(_Symbol,PERIOD_CURRENT,14);//Average Directional Movement Index - 3 handleRsi = iRSI(_Symbol,PERIOD_CURRENT,14,PRICE_CLOSE); // Load the ONNX model lstmHandle = OnnxCreateFromBuffer(lstm_onnx, ONNX_DEFAULT); //--- specify the shape of the input data if(!OnnxSetInputShape(lstmHandle,0,input_shape)) { Print("OnnxSetInputShape failed, error ",GetLastError()); OnnxRelease(lstmHandle); return(-1); } //--- specify the shape of the output data if(!OnnxSetOutputShape(lstmHandle,0,output_shape)) { Print("OnnxSetOutputShape failed, error ",GetLastError()); OnnxRelease(lstmHandle); return(-1); } if (lstmHandle == INVALID_HANDLE) { Print("Error creating model OnnxCreateFromBuffer ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); }
接下来,我们声明一个用于更新输入数据的函数,该函数会在每根新K线生成时触发。此函数通过循环遍历时间步长(本例中为5),将对应数据存入全局多维数组中。过程中会将数据转换为浮点型,以满足ONNX模型所需的32位精度要求。此外,该函数会确保多维数组的数据顺序正确:历史数据在前,新数据按生成顺序追加。这样保证了模型接收到的数据是按时间顺序排列的。
void getData(){ double rsi[]; double adx[]; CopyBuffer(handleAdx,0,1,5,adx); CopyBuffer(handleRsi,0,1,5,rsi); for (int i =0; i<5; i++){ data[0][i][0] = (float)adx[i]; data[0][i][1] = (float)rsi[i]; data[0][i][2] = (float)((iClose(_Symbol,PERIOD_CURRENT,5-i)-iOpen(_Symbol,PERIOD_CURRENT,5-i))/iClose(_Symbol,PERIOD_CURRENT,5-i)); } }
最后,在OnTick()函数中实现交易逻辑。
该函数会确保仅在新K线生成时触发后续交易逻辑检查。此机制可避免同一K线周期内的重复计算或交易操作,同时保证模型预测均基于每个时间步长的完整数据。
int bars = iBars(_Symbol,PERIOD_CURRENT); if (barsTotal!= bars){ barsTotal = bars;
当EA的magic编号关联的持仓全部平仓后,该代码会将buypos和sellpos变量重置为0。这两个变量用于确保在生成入场信号前,买方和卖方持仓均为空。通过在无持仓时重置这些变量,可避免系统在已有持仓的情况下误开新仓。
if(buypos>0&&(!PositionSelectByTicket(buypos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ buypos = 0; } if(sellpos>0&&(!PositionSelectByTicket(sellpos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ sellpos = 0; }
我们通过这行代码运行ONNX模型,该模型接收输入数据并将预测结果输出至out数组。此操作仅在初始入场信号形成时执行,而非每根新K线都触发。这种策略可以节省计算资源,使回测更高效——避免在无入场信号期间进行不必要的模型评估。
OnnxRun(lstmHandle, ONNX_NO_CONVERSION, data, out);
当前交易逻辑为:当均线(MA)交叉发生且当前无持仓时,运行模型获取预测的ADX值。如果该值低于设定阈值,则判定为趋势性较弱,避免开仓;若高于阈值,则执行入场。完整OnTick()函数的实现如下:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { int bars = iBars(_Symbol,PERIOD_CURRENT); if (barsTotal!= bars){ barsTotal = bars; double maFast[]; double maSlow[]; double adx[]; CopyBuffer(handleMaFast,BASE_LINE,1,2,maFast); CopyBuffer(handleMaSlow,BASE_LINE,1,2,maSlow); CopyBuffer(handleAdx,0,1,1,adx); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double lastClose = iClose(_Symbol, PERIOD_CURRENT, 1); //The order below matters if(buypos>0&& lastClose<maSlow[1]) trade.PositionClose(buypos); if(sellpos>0 &&lastClose>maSlow[1])trade.PositionClose(sellpos); if(maFast[1]<maSlow[1]&&maFast[0]>maSlow[0]&&sellpos == buypos){ getData(); OnnxRun(lstmHandle, ONNX_NO_CONVERSION, data, out); if(out[0][0]>threshold)executeSell();} if(maFast[1]>maSlow[1]&&maFast[0]<maSlow[0]&&sellpos == buypos){ getData(); OnnxRun(lstmHandle, ONNX_NO_CONVERSION, data, out); if(out[0][0]>threshold)executeBuy();} if(buypos>0&&(!PositionSelectByTicket(buypos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ buypos = 0; } if(sellpos>0&&(!PositionSelectByTicket(sellpos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ sellpos = 0; } } }
统计回测
完成所有功能实现后,我们可编译EA并在策略测试器中验证结果。本次将对XAUUSD(黄金兑美元)在2024年1月1日至2025年1月1日期间的1小时K线图进行样本外测试。首先,我们将运行原始回测策略作为比较基准。预期搭载LSTM模型的EA在此期间表现将优于基准策略。




现在,我们将对搭载LSTM模型的EA进行回测,ADX阈值设定为30,该值通常被视为强趋势信号的临界点。




通过对比两组回测结果发现,LSTM模型过滤了约70%的原始交易,同时将盈亏比从1.48提升至1.52。该模型还表现出比基准策略更高的线性回归(LR)相关性,表明其有助于提升整体收益的稳定性。
在回测机器学习模型时,需要特别注意的是,与参数影响较小的简单策略不同,模型内部参数是决定性能的关键因素。因此,不同训练数据可能会导致参数结果产生显著差异。此外,一次性使用全部历史数据训练并不理想,由于样本量过大且多数数据缺乏时效性。为此,建议在此类场景下采用滑动窗口法进行回测。如果整个回测历史中的样本量有限,正如我在前文关于CatBoost模型的讨论所述,则更适合使用扩展窗口回测法。
以下是演示图例:


扩展窗口回测法初始采用固定大小的数据窗口,但随着新数据点的加入,窗口会动态扩展以纳入新增数据,从而在不断增大的数据集上持续测试策略性能。
执行滑动窗口回测时,只需重复本文所述流程,并将各阶段结果合并为统一数据集。以下是2015年1月1日至2025年1月1日期间的滑动窗口回测表现:

度量指标:
盈亏比:1.24 最大回撤:-250.56 平均盈利:12.02 平均亏损:-5.20 胜率:34.81%
该结果表现优异,但仍具备进一步的优化空间。
反思
EA的性能与模型预测能力直接相关。若需提升EA表现,需重点考量以下因素:
- 回测策略优势:原始交易信号中需有足够比例具备显著优势,方能支撑后续筛选的合理性。
- 数据利用:通过分析输入特征的贡献度,挖掘被忽视的市场无效性指标,可获取超额收益机会。
- 模型选择:明确待解决问题类型(分类/回归),并精准调校训练参数。
- 预测目标:与其直接预测交易结果,不如聚焦间接影响最终结果的变量(如本文所述方法)。
在前文中,我系统探讨了零散交易者可落地的机器学习技术。旨在激发读者自身的实践创新——该领域的技术突破永无止境。机器学习并非高深莫测,而是一种思维模式。需理解优势,构建预测模型,并严格验证假设。随着实践的深入,认知将逐步升华。
结论
本文首先阐述了采用LSTM模型进行趋势预测的契机,同时解析了平均趋向指数(ADX)与长短期记忆网络(LSTM)的核心原理。随后,我们通过MetaTrader 5平台获取数据并完成预处理,在Python环境中完成模型训练。接着,我们演示了EA的构建流程,并深入剖析了回测结果。最后,介绍了滑动窗口回测与扩展窗口回测两种方法论,并在结语部分分享了策略优化的深度思考。
文件表
| 文件名 | 文件使用 |
|---|---|
| FileCSV.mqh | 用于将数据存储为CSV格式的Include文件 |
| LSTM_Demonstration.ipynb | 用于训练LSTM模型的python文件 |
| LSTM-TF-XAU.mq5 | 集成LSTM模型的EA |
| OHLC Getter.mq5 | 用于获取数据的EA |
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/16940
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
MQL5 简介(第 10 部分):MQL5 中使用内置指标的初学者指南
迁移至 MQL5 Algo Forge(第 4 部分):使用版本和发布
在MQL5中自动化交易策略(第5部分):开发自适应交叉RSI交易套件策略
我不明白:regression2024.onnx 模型本身在压缩包里的什么地方?
你好,an_tar。
正如文章中提到的,此类系统应通过滚动窗口回溯测试进行验证。我不想把我自 2008 年以来训练的所有模型都包含在内,以免文件太重。
建议使用文章中介绍的框架来训练你自己的模型,以便与你个人的验证方法兼容。