English Русский Español Deutsch 日本語
preview
一个基于新指标和条件长短期记忆网络(LSTM)的实例

一个基于新指标和条件长短期记忆网络(LSTM)的实例

MetaTrader 5示例 | 21 五月 2025, 11:05
139 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

引言

在金融市场的动态世界中,交易者和分析师始终在寻找新的和富有创意的方法,以获得相对于竞争对手的优势。本文研究了一种新颖的自动化交易方法,将深度学习的预测能力与传统技术分析的优势相结合。我们希望通过将复杂的条件长短期记忆(LSTM)神经网络模型与专有的技术指标——波动率调整动量(VAM)相融合,开发出一种能够应对现代市场复杂性的稳定且灵活的交易技术。

技术指标长期以来一直被金融行业用来发现趋势和潜在的交易机会。尽管这些指标很重要,但它们常常无法完全捕捉市场动态的复杂性,特别是在极端波动或急剧变化的时期。然而,深度学习架构,特别是LSTM,已经在处理复杂的时间序列数据的模式识别和预测方面展现出惊人的潜力。然而,这些模型并不总是像传统技术分析那样提供可解释性和特定领域的知识。

我们的策略旨在通过结合这两种方法的优势来弥合这一差距。本文介绍了一种名为波动率调整动量(VAM)指标的新工具,它试图在考虑潜在波动率的同时衡量市场动量。与传统动量指标相比,这为市场动态提供了更细致的图景。VAM旨在通过考虑波动率,在从平静到动荡的各种市场情境中提供更可靠的信号。

为了增强VAM指标,我们使用了一种条件LSTM模型,这是一种专门用于处理带有额外上下文信息的序列数据的循环神经网络。由于该模型是通过历史价格数据和技术指标进行训练的,因此它可以识别出传统分析技术可能遗漏的复杂非线性市场关系。由于LSTM的“条件”特性,该模型可以考虑更多的市场变量,从而可能产生更精确且更具情境意识的预测。

EA是我们策略实现的核心,这是一种特别设计的自动化交易系统,将VAM指标与条件LSTM模型的预测相结合。通过结合这两个组件的信号,该EA被集成到广受欢迎的MetaTrader 5平台中,以帮助交易者做出明智的决策。此外,它还具备动态风险管理能力,能够根据市场波动调整获利和止损水平。

在本文中,我们将探讨条件LSTM和VAM指标模型的理论基础,提供它们各自优势的见解以及它们如何最好地协同工作的方法。我们将详细介绍创建和实施EA的每一步,包括设置数据、训练模型以及将其集成到MetaTrader 5环境中。此外,我们将展示全面优化和回测的结果,对比仅使用VAM方法与结合VAM和条件LSTM方法的有效性。

在探讨这种新颖的交易策略时,我们将讨论将前沿机器学习方法与传统技术分析相结合的困难和因素。我们旨在提供一个关于实施此类系统的实际要素的全面概述,包括从数据质量、模型可解释性到在实时交易环境中运行复杂模型的计算需求。

到本文结束时,读者将全面了解如何应用前沿机器学习技术来增强传统技术分析,从而可能改善交易结果。无论您是交易者、数据科学家,还是研究量化金融领域的学者,对VAM和条件LSTM在自动化交易中的应用研究都将为算法交易的未来提供深刻的见解。

波动率调整动量(VAM)

VAM的核心理念是在评估动量时考虑市场波动率。它计算当前价格与过去价格(动量)之间的差异,然后除以波动率与动量周期平方根的乘积。该值通过一个因子进行缩放,表示经近期市场波动率调整后的动量强度。

深度学习模型

本文使用了一种条件LSTM模型,这是一种适用于金融时间序列数据的循环神经网络(RNN)。该模型以历史价格数据和技术指标(如本文中使用的MACD)作为输入,并预测未来价格走势。条件LSTM的优势在于其能够捕捉各种市场因素之间的复杂关系。

EA

本文描述了创建一个将深度学习模型的预测与VAM相结合的EA。以下是其主要功能的总结:

  • 初始化: EA加载并配置预训练ONNX深度学习模型的输入和输出参数。
  • 数据获取与归一化: EA收集MACD读数和之前的价格数据。在将这些变量输入深度学习模型之前,EA对它们进行归一化处理。
  • VAM计算: EA使用历史和当前价格数据计算VAM指标。
  • 交易逻辑与预测: EA从深度学习模型中获取价格预测。
EA将预测结果与VAM值结合:

  • 如果VAM值较高且预测显示价格将上涨,则EA启动买入交易。
  • 相反,如果VAM值较低且预测显示价格将下跌,则EA开启卖出交易。

EA通过根据平均真实波动范围(ATR)动态确定止损和获利水平来管理风险。

结果:

文章提到了使用VAM以及有无条件LSTM策略的EA的回测结果。


让我们创建一个新的指标(VAM)

如果我们创建一个新的指标,例如这个:

// Calcular Momentum
   double momentum = close_price - iClose(NULL, 0, momentum_period);

// Calcular Volatilidad
   double volatility = iMA(NULL, 0, volatility_period, 0, MODE_SMA, PRICE_CLOSE);

// Calcular VAM
   double vam =( momentum / (volatility * MathSqrt(momentum_period)))*10000;

我们将使用动量(Momentum)和波动率(Volatility)来创建一个新的指标,这个指标将被称为VAM。

动量除以动量周期平方根与波动率的乘积。

为了进行比例调整,结果再乘以10,000。

通过考虑波动率,VAM指标试图量化动量。它试图通过将动量除以波动率,来使动量在各种市场条件下保持一致。动量周期的平方根作为分母,有助于在不同时间段内标准化该指标。

正值的VAM表示向上动量,而负值表示向下动量。VAM的绝对值表示经近期市场波动率调整后的动量强度。

该指标可用于识别潜在的趋势反转,或在考虑市场波动率的情况下衡量当前市场趋势的强度。

仅使用这个指标,我们就可以创建一个EA,并检查其是否盈利。

该策略将如下所述:

void OnTick()
  {
   int bars = iBars(NULL, 0);
   if(bars < MathMax(momentum_period, MathMax(volatility_period, (vam_period))))//, MathMax(ma_long_period, rsi_period)))))
      return;

   double close_price = iClose(NULL, 0, 0);

// Calcular Momentum
   double momentum = close_price - iClose(NULL, 0, momentum_period);

// Calcular Volatilidad
   double volatility = iMA(NULL, 0, volatility_period, 0, MODE_SMA, PRICE_CLOSE);

// Calcular VAM
   double vam =( momentum / (volatility * MathSqrt(momentum_period)))*10000;


   double atr = iATR(_Symbol,PERIOD_CURRENT,14)*_Point;
   double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double slPriceBuy = NormalizeDouble(Bid - slmul*atr,_Digits);
   double tpPriceBuy = NormalizeDouble(Ask + tpmul*atr,_Digits);
   double slPriceSell = NormalizeDouble(Ask + slmul*atr,_Digits);
   double tpPriceSell = NormalizeDouble(Bid - tpmul*atr,_Digits);

// Señales
   if(vam > VAMTHRESH)// && ma_short > ma_long)// && rsi < 70 && ma_short > ma_long )
     {
      // Comprar
      trade.Buy(lot_size,_Symbol,   Ask, slPriceBuy, tpPriceBuy, " BUY EA ");
     }
   else
      if(vam < -VAMTHRESH)// && ma_short < ma_long)// rsi > 30 && ma_short < ma_long )
        {
         // Vender
         trade.Sell(lot_size,_Symbol,   Bid, slPriceSell, tpPriceSell, " SELL EA ");
        }
  }

iBars(NULL, 0) 函数返回给定交易品种和时间周期下可用的K线总数。
bars int:K线总数,即返回的值,存储在变量 bars 中。

MathMax:此函数返回提供的数字中的最大值。在此示例中,嵌套使用是为了确定多个时间段内的最大值。

变量 momentum_period、volatility_period、vam_period、ma_long_period 和 rsi_period 已经预先设定,分别表示各种指标或计算的时间间隔。

If:此条件判断可用的K线总数是否少于分配的时间总和。

如果“if”条件为真(即K线数量不足),函数将立即停止执行,后续代码不会运行。


VAM结果

结果如下(经过快速优化,尚未完成):

设置VAM

VAM的输入

VAM图形

回测VAM

这看起来还不错,对于一个简单的策略和一个简单的指标来说。

让我们看看如果我们使用深度学习模型来实现这个(但今天将使用不同的东西),我们将结合一些指标来构建一个深度学习模型,看看哪种组合效果更好。


深度学习模型

我们将把该模型导出为ONNX格式,但在那之前,先比较哪种模型更好。

为了完成所有这些工作,我们将使用Google Colab(这样就不会占用我们电脑的资源),并附带其Python脚本。

由于这是一个MQL5网站,我将不会解释Python代码。

有两个Python脚本,第一个脚本包含所有使用的指标,第二个脚本则相同,但只包含MACD指标(因为在第一个脚本中我们假设MACD具有较高的命中率和R²,且误差较低)。

第一个脚本的图形结果如下:

命中率

MAE对比情况

MAPE对比情况

R²对比情况

RMSE对比情况

在决定使用MACD之后,我们准备了脚本并将日期调整为2024年1月1日(这样我们就可以从2024年1月1日起在MQL5中回测结果)。

第二个脚本的结果与第一个(非常相似)。

命中率 2

等等……(你可以自己动手做,并用Colab检查结果)。

Python脚本是为Colab准备的,你必须先运行第一个单元,当所有库都安装完成后,再运行第二个单元,允许它将模型和图表保存到你的Google Drive中,然后只需等待完成即可。

数据是从MQL5中获取的,因为Colab中没有安装MetaTrader(数值应该类似)。

正如你在第二个图像中所看到的,MACD模型的命中率非常高,这就是我们选择它的原因。


条件LSTM

条件LSTM是传统长短期记忆(LSTM)神经网络的一个增强版本。它通过在LSTM架构的预测过程中添加更多的上下文数据或情境,从而提升了预测能力。由于金融市场的价格变化受到许多因素的影响,因此它在金融市场预测领域特别有趣。

条件逻辑回归机在股票或外汇预测领域是一种有效的工具。它使模型能够除了考虑历史价格数据之外,还能结合多种市场指标和外部变量。这可能包括情绪数据、更广泛的经济指标以及技术指标,如RSI或移动平均线。通过整合这些多种输入,模型试图提供一个更全面的市场动态图景。

使用条件LSTM进行金融预测的一个主要好处是其上下文感知能力。金融市场是一个复杂的系统,受到多种因素的影响。由于条件LSTM能够结合多种指标,因此它可能能够揭示不同市场动态之间的复杂相关性。它能够处理静态特征和时间序列数据,使其非常适合金融市场,因为在金融市场中,过去的趋势和当前的情况同样重要。

此外,条件LSTM在捕捉时间序列数据中的长期依赖关系方面表现出色,就像传统LSTM一样。这在金融市场中特别有用,因为长期模式可能会出现。由于模型能够跨长序列保留相关信息,因此它可以检测到简单模型可能会忽略的模式。

然而,在使用条件LSTM进行金融预测时也存在一些困难。尽管模型的复杂性可能带来优势,但它也带来了挑战。随着训练变得更加复杂,尤其是在处理较小数据集时,过拟合的可能性会增加。这种复杂性导致更高的计算成本,这在实时交易应用中可能是一个重要因素。

对于条件LSTM而言,数据质量和相关性变得更加关键。模型不仅需要价格数据,还需要高质量、相关的指标数据。在金融市场这个快速变化且有时不透明的世界中,确保所有这些维度的数据一致且准确可能是一个挑战。

在评估条件LSTM的潜力时,考虑金融市场的本质也很重要。市场受到不可预测事件和人类行为的影响,这可能会限制任何预测模型的有效性,无论其多么复杂。模型可能在识别历史数据中的模式方面表现出色,但在面对前所未有的市场条件或重大经济冲击时可能会陷入困境。

与许多深度学习模型一样,条件LSTM的另一个问题是可解释性。尽管它们可能产生精确的预测,但理解其背后的推理可能很困难。这种“黑箱”特性可能会在金融应用中引发问题,因为这些领域通常需要可解释性和透明度。

最后,尽管条件LSTM在基于指标的股票和外汇预测方面具有潜力,但使用它们时需要谨慎。它们能够包含复杂、多维度的数据,可能会产生更精确、更细致的预测。然而,由于复杂性增加、数据需求以及金融市场的固有不可预测性所带来的挑战,它们应该作为更全面、经过深思熟虑的分析方法的一部分来使用。对模型在实际场景中的局限性有深入的理解,并进行广泛的回测。在高风险的金融交易领域应用这些先进技术需要广泛地回测,并了解模型在实际场景中的局限性。

模型(如Python脚本中所实现的)看起来像这样:

ONNX 模型

它的输入和输出如下:

ONNX模型的输入和输出


EA代码

这款EA的核心目的是基于技术指标和深度学习(ONNX)模型的预测来自动化交易决策。EA使用波动率调整动量(VAM)指标和MACD(移动平均线收敛发散指标),以及由机器学习模型做出的价格预测。它根据这些元素的组合来执行交易。

EA首先定义了若干属性和库。包含用于执行交易的 CTrade 类,以及其他用于统计函数和数组管理的头文件。定义了用于VAM计算和交易执行的输入参数,例如 momentum_period(动量周期)、volatility_period(波动率周期)和 vam_period(VAM周期),这些参数用于控制动量和波动率计算的逻辑。交易参数如 lot_size(仓位大小)以及止损(slmul)和获利(tpmul)的乘数也在此定义,为EA的行为提供了灵活性。此外,还包含了定义ONNX模型参数的常量,如 BATCH_SIZE(批量大小)、SEQUENCE_LENGTH(序列长度)等,用于管理数据如何传递给深度学习模型。

//+------------------------------------------------------------------+
//|                                                      VAM + DL(MACD) EA |
//|                                      Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera |
//|                                       https://www.mql5.com/en/users/jsgaston/news |
//+------------------------------------------------------------------+
#property copyright "Javier Santiago Gaston de Iriarte Cabrera"
#property link      "https://www.mql5.com/en/users/jsgaston/news"
#property version   "1.01"


#include <Trade\Trade.mqh>
#include <Math\Stat\Math.mqh>
#include <Arrays\ArrayFloat.mqh>

CTrade trade;

// Inputs
input int momentum_period = 13;
input int volatility_period = 7;
input int vam_period = 9;
input double lot_size = 0.01;
input int slippage = 3;
input double VAMTHRESH = 9.0;
input int slmul = 2;
input int tpmul = 4;

// ONNX model parameters
#define BATCH_SIZE 1
#define SEQUENCE_LENGTH 30
#define INPUT_FEATURES 3
#define CONDITION_FEATURES 2
#define HIDDEN_DIM 128
#define NUM_LAYERS 2

float input_x[][SEQUENCE_LENGTH][INPUT_FEATURES];
float input_condition[][CONDITION_FEATURES];
float h0[][BATCH_SIZE][HIDDEN_DIM];
float c0[][BATCH_SIZE][HIDDEN_DIM];

#define PRICE_UP   0
#define PRICE_SAME 1
#define PRICE_DOWN 2

long ExtHandle = INVALID_HANDLE;
int ExtPredictedClass = -1;
datetime ExtNextBar = 0;
datetime ExtNextDay = 0;
float ExtMin = 0.0;
float ExtMax = 1.0;  // Initialize to 1.0 to prevent division by zero
float predicted_last;

#resource "/Files/stock_prediction_model_MACD.onnx" as uchar ExtModel[]

初始化函数 OnInit() 至关重要,因为它从二进制资源(stock_prediction_model_MACD.onnx)中加载ONNX模型,并设置模型的输入和输出形状。ONNX模型的输入包括历史价格数据、MACD值,以及为模型的循环层初始化的隐藏状态和单元状态(h0、c0)。如果模型加载成功,该函数还会初始化最小和最大价格值(ExtMin 和 ExtMax),这些值将用于对输入到ONNX模型的数据进行归一化。如果在模型加载过程中发生任何错误,它将返回 INIT_FAILED,从而有效地停止EA的运行。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   Print("BATCH_SIZE: ", BATCH_SIZE, ", CONDITION_FEATURES: ", CONDITION_FEATURES);
   ExtHandle = OnnxCreateFromBuffer(ExtModel,ONNX_DEFAULT);
   if(ExtHandle == INVALID_HANDLE)
     {
      Print("OnnxCreateFromBuffer error ", GetLastError());
      return(INIT_FAILED);
     }

// Set input shapes
   long input_shape[] = {BATCH_SIZE, SEQUENCE_LENGTH, INPUT_FEATURES};
   if(!OnnxSetInputShape(ExtHandle, ONNX_DEFAULT, input_shape))
     {
      Print("OnnxSetInputShape for input_x error ", GetLastError());
      return(INIT_FAILED);
     }

   long condition_shape[] = {BATCH_SIZE,CONDITION_FEATURES};
   if(!OnnxSetInputShape(ExtHandle, 1, condition_shape))
     {
      Print("OnnxSetInputShape for input_condition error ", GetLastError());
      return(INIT_FAILED);
     }

   long h0_shape[] = {NUM_LAYERS, BATCH_SIZE, HIDDEN_DIM};
   if(!OnnxSetInputShape(ExtHandle, 2, h0_shape))
     {
      Print("OnnxSetInputShape for h0 error ", GetLastError());
      return(INIT_FAILED);
     }

   long c0_shape[] = {NUM_LAYERS, BATCH_SIZE, HIDDEN_DIM};
   if(!OnnxSetInputShape(ExtHandle, 3, c0_shape))
     {
      Print("OnnxSetInputShape for c0 error ", GetLastError());
      return(INIT_FAILED);
     }



   const long output_shape[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }

// Initialize ExtMin and ExtMax
   GetMinMax();

   Print("Initializing EA with VAM and ONNX integration");
   return(INIT_SUCCEEDED);
  }

OnTick() 函数是每个价格变动时运行的核心逻辑。它首先检查是否是新的一天,并通过 GetMinMax() 函数相应地更新最小和最大价格值。接下来的代码块确保只有在有新的K线到来时,函数才会继续执行。EA随后将 ExtMin 和 ExtMax 变量更新为最新的价格值。这个函数的核心是VAM计算和ONNX预测的结合。VAM的计算方法是:取价格变化(动量)除以波动率与 momentum_period 的平方根的乘积,再乘以10,000进行缩放。如果VAM超过一个阈值(VAMTHRESH),则表明市场存在强烈的趋势,发出潜在交易信号。 

然后,EA将预测结果与VAM结果结合起来。如果VAM值较高(大于 VAMTHRESH)且ONNX模型预测价格将上涨,EA将根据平均真实波动范围(ATR)计算止损和获利水平后,开启一笔买入交易。同样地,如果VAM值较低(低于负的 VAMTHRESH)且ONNX模型预测价格将下跌,EA将开启一笔卖出交易。这些交易通过 CTrade 类执行,该类与MetaTrader 5平台的交易功能进行交互。

在风险管理方面,止损和获利水平是根据资产的平均真实波动范围(ATR)动态计算的。这确保了该策略能够根据市场的波动性进行调整,根据当前市场条件提供更具适应性的交易退出点。

void OnTick()
  {
// Check for new day and update ExtMin and ExtMax
   if(TimeCurrent() >= ExtNextDay)
     {
      GetMinMax();
      ExtNextDay = TimeCurrent() - TimeCurrent() % PeriodSeconds(PERIOD_D1) + PeriodSeconds(PERIOD_D1);
     }

// Check for new bar
   if(TimeCurrent() < ExtNextBar)
      return;
   ExtNextBar = TimeCurrent() - TimeCurrent() % PeriodSeconds() + PeriodSeconds();

// Update ExtMin and ExtMax
   double close = iClose(_Symbol, _Period, 0);
   if(ExtMin > close)
      ExtMin = (float)close;
   if(ExtMax < close)
      ExtMax = (float)close;

   int bars = iBars(_Symbol, PERIOD_CURRENT);
   if(bars < MathMax(momentum_period, MathMax(volatility_period, MathMax(vam_period, SEQUENCE_LENGTH))))
      return;

// Calculate VAM
   double momentum = close - iClose(_Symbol, PERIOD_CURRENT, momentum_period);
   double volatility = iStdDev(_Symbol, PERIOD_CURRENT, volatility_period, 0, MODE_SMA, PRICE_CLOSE);
   double vam = (momentum / (volatility * MathSqrt(momentum_period))) * 10000;
   Print("VAM ", vam);

// Get ONNX prediction
   int result=GetPrediction();

// Trading logic combining VAM and ONNX prediction
   double atr = iATR(_Symbol, PERIOD_CURRENT, 14)*_Point;
   double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double slPriceBuy = NormalizeDouble(Bid - slmul * atr, _Digits);
   double tpPriceBuy = NormalizeDouble(Ask + tpmul * atr, _Digits);
   double slPriceSell = NormalizeDouble(Ask + slmul * atr, _Digits);
   double tpPriceSell = NormalizeDouble(Bid - tpmul * atr, _Digits);
   
   //Print(result);

   if(vam > VAMTHRESH && result == 0)
     {
      trade.Buy(lot_size, _Symbol, Ask, slPriceBuy, tpPriceBuy, "BUY VAM+ONNX");
     }
   else
      if(vam < -VAMTHRESH && result == 2)
        {
         trade.Sell(lot_size, _Symbol, Bid, slPriceSell, tpPriceSell, "SELL VAM+ONNX");
        }
  }

通过调用 GetPrediction() 函数来获取ONNX模型的预测结果。模型的输入由 PrepareInputs() 函数准备,该函数收集历史收盘价和MACD数据,使用价格范围(ExtMin 和 ExtMax)对它们进行归一化,并填充模型期望的输入数组。它为输入价格序列(input_x)和基于MACD的条件(input_condition)设置数据,同时重置隐藏状态(h0、c0)。一旦输入准备就绪,OnnxRun() 函数将运行模型并计算预测价格。预测价格与上次预测价格之间的差异用于判断模型是否预期价格会上涨、下跌或保持不变。如果预测的变化太小,模型则认为没有变化(价格保持不变)。

void PrepareInputs()
  {
   ArrayResize(input_x, BATCH_SIZE);
   ArrayResize(input_condition, BATCH_SIZE);
   ArrayResize(h0, NUM_LAYERS);
   ArrayResize(c0, NUM_LAYERS);

   for(int i = 0; i < SEQUENCE_LENGTH; i++)
     {
      input_x[0][i][0] = (float)((iClose(_Symbol, PERIOD_CURRENT, i) - ExtMin) / (ExtMax - ExtMin));

      double macd_main[], macd_signal[];
      int macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
      CopyBuffer(macd_handle, 0, i, 1, macd_main);
      CopyBuffer(macd_handle, 1, i, 1, macd_signal);
      input_x[0][i][1] = (float)((macd_main[0] - ExtMin) / (ExtMax - ExtMin));
      input_x[0][i][2] = (float)((macd_signal[0] - ExtMin) / (ExtMax - ExtMin));
     }

   double macd_main2[], macd_signal2[];
   int macd_handle2 = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
   CopyBuffer(macd_handle2, 0, 0, 1, macd_main2);
   CopyBuffer(macd_handle2, 1, 0, 1, macd_signal2);
   input_condition[0][0] = (float)macd_main2[0];
   input_condition[0][1] = (float)macd_signal2[0];

   ArrayInitialize(h0, 0.0f);
   ArrayInitialize(c0, 0.0f);
  }
//+------------------------------------------------------------------+
//| Get prediction from ONNX model                                   |
//+------------------------------------------------------------------+
int GetPrediction()
  {
   PrepareInputs();
   

   float output_data[];
   ArrayResize(output_data, 1);

// Run the ONNX model
   if(!OnnxRun(ExtHandle,
               ONNX_NO_CONVERSION,
               input_x,
               input_condition,
               h0,
               c0,
               output_data))
     {
      Print("OnnxRun error: ", GetLastError());
      return ExtPredictedClass = -1;
     }

   float predicted=output_data[0]*(ExtMax-ExtMin)+ExtMin;
   Print("Predicted last ", predicted_last);
   Print("Predicted ",predicted);
   float last_close = (float)iClose(_Symbol, PERIOD_CURRENT, 0);
   Print("last close ",last_close);
   float delta = predicted_last - predicted;
   predicted_last=predicted;
   Print("Delta ",delta);

   if(MathAbs(delta) <= 0.00001)
      ExtPredictedClass = PRICE_SAME;
   else
      if(delta < 0)
         ExtPredictedClass = PRICE_UP;
      else
         ExtPredictedClass = PRICE_DOWN;
   Print(ExtPredictedClass);

   return ExtPredictedClass;
   
  }

GetMinMax() 函数负责设置过去一天数据中的最小价格值(ExtMin)和最大价格值(ExtMax)。这些值用于在将输入传递给ONNX模型之前对输入数据进行归一化,确保模型接收到的输入数据范围保持一致。如果EA未能获取必要的价格数据,它将默认使用一个安全范围,以避免除以零的情况发生。

void GetMinMax()
  {
   double close[];
   int copied = CopyClose(_Symbol, PERIOD_D1, 0, SEQUENCE_LENGTH, close);

   if(copied > 0)
     {
      ExtMin = (float)MathMin(close);
      ExtMax = (float)MathMax(close);
     }
   else
     {
      Print("Failed to copy price data. Error: ", GetLastError());
      ExtMin = 0;
      ExtMax = 1;  // Prevent division by zero
     }
  }

最后,该EA包含了一个反初始化函数 OnDeinit(),当EA被移除时,该函数会释放ONNX模型的句柄,确保内存得到正确管理,避免资源泄漏。

void OnDeinit(const int reason)
  {
   if(ExtHandle != INVALID_HANDLE)
     {
      OnnxRelease(ExtHandle);
      ExtHandle = INVALID_HANDLE;
     }
  }

总结来说,这款EA将技术分析(通过VAM和MACD)与ONNX模型的机器学习预测相结合,以做出明智的自动化交易决策。技术分析有助于发现趋势,而机器学习模型则预测价格走势,从而形成一种混合策略。


结果

优化后

设置 VAM+条件LSTM

VAM+条件LSTM 输入参数

VAM+条件LSTM图形

回测 VAM + 条件LSTM


结论

本文探讨了深度学习,特别是条件长短期记忆(LSTM)模型,与波动率调整动量(VAM)指标的结合,以增强自动化交易系统。通过结合LSTM的预测能力和VAM对波动率敏感的动量分析,该策略旨在捕捉复杂的市场动态。该系统在MetaTrader 5上实现,能够生成交易信号并动态调整风险管理。

回测结果显示,将LSTM与VAM结合使用时,结果有所改善。尽管面临过拟合和计算需求等挑战,但研究表明,将深度学习与技术分析相结合可以显著改进算法交易策略。

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/15956

您应当知道的 MQL5 向导技术(第 35 部分):支持向量回归 您应当知道的 MQL5 向导技术(第 35 部分):支持向量回归
支持向量回归是一种理想主义的途径,寻找最能描述两组数据之间关系的函数或“超平面”。我们尝试在 MQL5 向导的自定义类内利用这一点来进行时间序列预测。
神经网络实践:第一个神经元 神经网络实践:第一个神经元
在本文中,我们将开始构建一些简单而不起眼的东西:神经元。我们将使用非常少量的 MQL5 代码对其进行编程。神经元在我的测试中表现良好。让我们回到这一系列关于神经网络的文章中,了解一下我在说什么。
从基础到中级:BREAK 和 CONTINUE 语句 从基础到中级:BREAK 和 CONTINUE 语句
在本文中,我们将学习如何在循环中使用 RETURN、BREAK 和 CONTINUE 语句。了解每个语句在循环执行流程中的作用对于处理更复杂的应用程序非常重要。此处提供的内容仅用于教育目的。在任何情况下,除了学习和掌握所提出的概念外,都不应出于任何目的使用此应用程序。
使用Python和MQL5进行多交易品种分析(第一部分):纳斯达克集成电路制造商 使用Python和MQL5进行多交易品种分析(第一部分):纳斯达克集成电路制造商
加入我们的讨论,了解如何利用人工智能(AI)优化您的仓位规模和订单数量,以最大化您的投资组合回报。我们将展示如何通过算法识别一个最优的投资组合,并根据您的回报预期或风险承受能力来调整投资组合。在本次讨论中,我们将使用SciPy库和MQL5语言,利用所拥有的全部数据创建一个最优且多样化的投资组合。