English Русский Español Deutsch 日本語 Português
preview
使用 SMA 和 EMA 自动优化止盈和指标参数的示例

使用 SMA 和 EMA 自动优化止盈和指标参数的示例

MetaTrader 5示例 | 27 三月 2025, 09:15
588 1
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

概述

在不断发展的算法交易世界中,创新是保持领先地位的关键。今天,我们很高兴推出一款复杂的 EA 交易系统,它将机器学习与传统的技术分析相结合,以驾驭外汇市场。该 EA 利用 ONNX 模型和精心优化的技术指标在货币市场做出交易决策。

EA 的方法是多方面的,利用机器学习模型的价格预测、趋势跟踪技术和自适应参数优化。它的设计主要针对 #AAPL 股票,尽管它具有适应其他工具的灵活性。该 EA 具有动态手数调整、追踪止损和自动调整市场条件等功能,融合了尖端技术与久经考验的交易原则。

所用指标的说明:

  1. 简单移动平均线(SMA):EA 使用了具有自适应优化周期的简单移动平均线。SMA 有助于确定整体趋势方向,并与价格和其他指标结合使用,以生成交易信号。
  2. 指数移动平均线(EMA):还采用了指数移动平均线,其周期数经过动态优化。EMA 对近期价格变化的反应比 SMA 更快,为趋势方向提供了不同的视角。
  3. 平均真实范围(ATR):虽然代码中没有明确计算,但 EA 使用了基于 ATR 的计算来设置止损和止盈水平。这允许根据波动性调整头寸大小和风险管理。
  4. 机器学习模型:EA 采用 ONNX(开放神经网络交换)模型进行价格预测。该模型采用一系列最近的价格数据,并试图预测下一个价格走势,为交易策略添加预测元素。

这些指标以复杂的方式组合在一起,其参数根据最近的市场状况动态优化。EA 还包括追踪止损和道德期望计算等功能,以有效管理未平仓头寸。

这些指标的结合,以及机器学习组件,使EA能够适应不断变化的市场条件,并可能识别各种市场状态的交易机会。


代码解析

1.初始设置和包含文件:

代码以版权信息开头,并包含了 Trade.mqh 等必要的库。

#include <Trade\Trade.mqh>

2.全局变量和参数:

  • 定义了 ONNX 模型参数,包括样本大小和句柄。
  • 声明了指标 (SMA、EMA、ATR) 和交易操作的输入参数。
  • 定义了价格变动和幻数的枚举和常量。

#resource "/Files/model.EURUSD.D1.1_1_2024.onnx" as uchar ExtModel[];
input group "----- Indicators Parameters -----"
int SMA_Period = 20;
int EMA_Period = 50;

input double StopLossATR = 1.5;
input double TakeProfitATR = 3.0;
input int OptimizationDays = 1;        // Hours between optimizations
input int LookbackPeriod = 7;         // Hours loockback periods
input int MinSMAPeriod = 5;            // Period min para SMA
input int MaxSMAPeriod = 50;           // Periodo max para SMA
input int MinEMAPeriod = 5;            // Periodo min para EMA
input int MaxEMAPeriod = 50;           // Periodo max para EMA
#define MAGIC_SE 12321
datetime lastOptimizationTime = 0;
double optimizedTakeProfit = 0.0;//InpTakeProfit;
double optimizedStopLoss = 0.0;//InpStopLoss;
double InpTakeProfit1 ;
double InpStopLoss1;

3.初始化函数(OnInit):

  • 从缓冲区设置 ONNX 模型。
  • 初始化技术指标(SMA、EMA)。
  • 调用函数来优化指标和交易参数。

int OnInit()
  {
//--- create a model from static buffer
   ExtHandle = OnnxCreateFromBuffer(ExtModel, ONNX_DEFAULT);
   if(ExtHandle == INVALID_HANDLE)
     {
      Print("OnnxCreateFromBuffer error ", GetLastError());
      return(INIT_FAILED);
     }

//--- set input and output shapes
   const long input_shape[] = {1, SAMPLE_SIZE, 1};
   if(!OnnxSetInputShape(ExtHandle, ONNX_DEFAULT, input_shape))
     {
      Print("OnnxSetInputShape error ", GetLastError());
      return(INIT_FAILED);
     }
   const long output_shape[] = {1, 1};
   if(!OnnxSetOutputShape(ExtHandle, 0, output_shape))
     {
      Print("OnnxSetOutputShape error ", GetLastError());
      return(INIT_FAILED);
     }

   SMAHandle = iMA(_Symbol, _Period, SMA_Period, 0, MODE_SMA, PRICE_CLOSE); // Ensure correct period
   if(SMAHandle == INVALID_HANDLE)
     {
      Print("Error initializing SMA indicator: ", GetLastError());
      return INIT_FAILED;
     }
   EMAHandle = iMA(_Symbol, _Period, EMA_Period, 0, MODE_EMA, PRICE_CLOSE); // Ensure correct index
   if(EMAHandle == INVALID_HANDLE)
     {
      Print("Error initializing EMA indicator: ", GetLastError());
      return INIT_FAILED;
     }
   trade.SetDeviationInPoints(Slippage);

   trade.SetExpertMagicNumber(MAGIC_SE);
   OptimizeIndicators();
   OptimizeParameters();
   return(INIT_SUCCEEDED);
  }

4.去初始化函数(OnDeinit):

释放 ONNX 模型和指标的句柄。

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(ExtHandle != INVALID_HANDLE)
     {
      OnnxRelease(ExtHandle);
      ExtHandle = INVALID_HANDLE;
     }

   IndicatorRelease(SMAHandle);
   IndicatorRelease(EMAHandle);
  }

5.主要交易逻辑(OnTick):

  • 检查市场是否关闭。
  • 定期优化指标和交易参数。
  • 更新追踪止损逻辑。
  • 使用 ONNX 模型预测价格走势。
  • 根据预测和指标检查开仓/平仓条件。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

   if(IsMarketClosed())  // Verificar si el mercado está cerrado
     {
      return; // Si el mercado está cerrado, no hacer nada
     }

   static datetime lastOptimizationTime2 = 0;

   if(TimeCurrent() - lastOptimizationTime2 >= OptimizationDays * PeriodSeconds(PERIOD_H1))
     {
      OptimizeIndicators();
      lastOptimizationTime2 = TimeCurrent();

      // Actualizar los indicadores con los nuevos períodos
      IndicatorRelease(SMAHandle);
      IndicatorRelease(EMAHandle);
      SMAHandle = iMA(_Symbol, _Period, SMA_Period, 0, MODE_SMA, PRICE_CLOSE);
      EMAHandle = iMA(_Symbol, _Period, EMA_Period, 0, MODE_EMA, PRICE_CLOSE);
     }

//--- Optimización cada 2 días
   if(TimeCurrent() - lastOptimizationTime >= PeriodSeconds(PERIOD_H1) * HoursAnalyze)
     {
      OptimizeParameters();
      lastOptimizationTime = TimeCurrent();
     }

//---

   if(NewBarTS()==true)//gather statistics and launch trailing stop
     {
      double open=iOpen(_Symbol,TFTS,1);
      CalcLvl(up,(int)MathRound((iHigh(_Symbol,TFTS,1)-open)/_Point));
      CalcLvl(dn,(int)MathRound((open-iLow(_Symbol,TFTS,1))/_Point));
      buy_sl=CalcSL(dn);
      buy_tp=CalcTP(up);
      sell_sl=CalcSL(up);
      sell_tp=CalcTP(dn);

      if(TypeTS==Simple)//simple trailing stop
         SimpleTS();

      if(TypeTS==MoralExp)//Moral expectation
         METS();
      if(TypeTS==None)//None TS
         return;
     }

   double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);

   if(bid==SLNeutral || bid<=SLBuy || (SLSell>0 && bid>=SLSell))
     {
      for(int i=PositionsTotal()-1; i>=0; i--)
        {
         ulong ticket=PositionGetTicket(i);
         if(PositionSelectByTicket(ticket)==true)
            trade.PositionClose(ticket);
        }
     }
//---
//--- check new day
   if(TimeCurrent() >= ExtNextDay)
     {
      GetMinMax();
      ExtNextDay = TimeCurrent();
      ExtNextDay -= ExtNextDay % PeriodSeconds(PERIOD_D1);
      ExtNextDay += PeriodSeconds(PERIOD_D1);
     }

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

//--- check min and max
   float close = (float)iClose(_Symbol, _Period, 0);
   if(ExtMin > close)
      ExtMin = close;
   if(ExtMax < close)
      ExtMax = close;


   double sma[], ema[];//, willr[];
   CopyBuffer(SMAHandle, 0, 0, 1, sma);
   CopyBuffer(EMAHandle, 0, 0, 1, ema);
//CopyBuffer(WillRHandle, 0, 0, 1, willr);

//--- predict next price
   PredictPrice();

//--- check trading according to prediction and indicators
   if(ExtPredictedClass >= 0)
     {
      if(PositionSelect(_Symbol))
         CheckForClose(sma[0], ema[0]);//, willr[0]);
      else
         CheckForOpen(sma[0], ema[0]);//, willr[0]);
     }
  }

6.交易函数:

  • CheckForOpen:根据预测和指标信号确定是否开立买入或卖出仓位。
  • CheckForClose:检查是否应根据预测关闭当前仓位。

//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
void CheckForOpen(double sma, double ema)//, double willr)
  {
   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied = CopyRates(_Symbol,0,0,1,rates);
   if(copied <= 0)
     {
      Print("Error copying rates: ", GetLastError());
      return;
     }
   double Close[1];
   Close[0]=rates[0].close;
   double close = Close[0];

   ENUM_ORDER_TYPE signal = WRONG_VALUE;
   Print("ExtPredictedClass ",ExtPredictedClass);

//--- check signals
   if(ExtPredictedClass == 2)//PRICE_DOWN)
     {
      Print("ExtPredictedClass Sell ",ExtPredictedClass);
      Print("close ",close, " sma ",sma, " ema ", ema);//, " willr ", willr);
      // Venta
      if((close < sma && close < ema))// || willr > -20)
        {
         signal = ORDER_TYPE_SELL;
         Print("Order Sell detected");
        }
     }
   else
      if(ExtPredictedClass == 0)//PRICE_UP)
        {
         Print("ExtPredictedClass Buy ",ExtPredictedClass);
         Print("close ",close, " sma ",sma, " ema ", ema);//, " willr ", willr);
         // Compra
         if((close > sma && close > ema))// || willr < -80)
           {
            signal = ORDER_TYPE_BUY;
            Print("Order Buy detected");
           }
        }

//--- open position if possible according to signal
   if(signal != WRONG_VALUE && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      Print("Proceding open order");
      double price, sl=0, tp=0;
      double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

      MqlTradeRequest request = {};
      MqlTradeResult result = {};

      request.action = TRADE_ACTION_DEAL;
      request.symbol = _Symbol;
      request.deviation = Slippage;
      request.magic = MAGIC_SE;
      request.type_filling = ORDER_FILLING_FOK;
      //request.comment = "AKWr";

      double lotaje;
      if(signal == ORDER_TYPE_SELL)
        {
         price = bid;
         Print("Price: ",price);
         if(inp_lot_type == LOT_TYPE_FIX)
            lotaje=inp_lot_fix ;
         else
            lotaje=get_lot(price);
         if(!CheckVolumeValue(lotaje))
            return;
         if(!InpUseStops && ATR)
           {
            sl = NormalizeDouble(bid + StopLossATR * ATRValue, _Digits);
            tp = NormalizeDouble(ask - TakeProfitATR * ATRValue, _Digits);
            if(!CheckMoneyForTrade(_Symbol, lotaje,ORDER_TYPE_SELL))
              {
               Print("No hay suficiente margen para abrir la posición");
               return;
              }
            request.type = ORDER_TYPE_SELL;
            request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            request.volume = lotaje;
            request.sl = sl;
            request.tp = tp;
            request.comment = "SEW Opened sell order";
           }
         if(!InpUseStops && ATR)
           {
            sl = 0;
            tp = 0;
           }
         else
           {
            InpTakeProfit1 =optimizedTakeProfit;
            InpStopLoss1= optimizedStopLoss;
            sl = NormalizeDouble(bid + InpStopLoss1*_Point, _Digits);
            tp = NormalizeDouble(ask - InpTakeProfit1*_Point, _Digits);

           }
        }
      else
        {
         price = ask;
         Print("Price: ",price);
         if(inp_lot_type == LOT_TYPE_FIX)
            lotaje=inp_lot_fix ;
         else
            lotaje=get_lot(price);
         if(!CheckVolumeValue(lotaje))
            return;
         if(!InpUseStops)
           {
            sl = NormalizeDouble(ask - StopLossATR * ATRValue, _Digits);
            tp = NormalizeDouble(bid + TakeProfitATR * ATRValue, _Digits);
            if(!CheckMoneyForTrade(_Symbol, lotaje,ORDER_TYPE_BUY))
              {
               Print("No hay suficiente margen para abrir la posición");
               return;
              }
            request.type = ORDER_TYPE_BUY;
            request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            request.volume = lotaje;
            request.sl = sl;
            request.tp = tp;
            request.comment = "SEW Opened buy order";
           }
         if(!InpUseStops && ATR)
           {
            sl = 0;
            tp = 0;
           }
         else
           {
            InpTakeProfit1 =optimizedTakeProfit;
            InpStopLoss1= optimizedStopLoss;
            sl = NormalizeDouble(ask - InpStopLoss1*_Point, _Digits);
            tp = NormalizeDouble(bid + InpTakeProfit1*_Point, _Digits);
           }
        }
      Print("No InpUseStops used");

      //ExtTrade.PositionOpen(_Symbol, signal, lotaje, price, sl, tp);

      if(!CheckMoneyForTrade(_Symbol, lotaje, (ENUM_ORDER_TYPE)signal))
        {
         Print("No hay suficiente margen para abrir la posición");
         return;
        }
      Print("Volume ", lotaje);
      request.type = signal;
      request.price = price;//SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      request.volume = lotaje;
      request.sl = sl;
      request.tp = tp;
      request.comment = "SEW";
      if(!OrderSend(request, result))
        {
         Print("Error opening the order: ", GetLastError());
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| Check for close position conditions                              |
//+------------------------------------------------------------------+
void CheckForClose(double sma, double ema)//, double willr)
  {
   if(InpUseStops)
      return;

   bool bsignal = false;

//--- position already selected before
   long type = PositionGetInteger(POSITION_TYPE);

//--- check signals
   if(type == POSITION_TYPE_BUY && ExtPredictedClass == 2)//PRICE_DOWN)
      bsignal = true;
   if(type == POSITION_TYPE_SELL && ExtPredictedClass == 0)//PRICE_UP)
      bsignal = true;

//--- close position if possible
   if(bsignal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      ExtTrade.PositionClose(_Symbol);
      CheckForOpen(sma, ema);//, willr);
     }
  }

7.价格预测(PredictPrice):

使用 ONNX 模型预测未来的价格走势。

//+------------------------------------------------------------------+
//| Predict next price                                               |
//+------------------------------------------------------------------+
void PredictPrice(void)
  {
   static vectorf output_data(1);
   static vectorf x_norm(SAMPLE_SIZE);

   if(ExtMin >= ExtMax)
     {
      Print("ExtMin >= ExtMax");
      ExtPredictedClass = -1;
      return;
     }

   if(!x_norm.CopyRates(_Symbol, _Period, COPY_RATES_CLOSE, 1, SAMPLE_SIZE))
     {
      Print("CopyRates ", x_norm.Size());
      ExtPredictedClass = -1;
      return;
     }
   float last_close = x_norm[SAMPLE_SIZE - 1];
   x_norm -= ExtMin;
   x_norm /= (ExtMax - ExtMin);

   if(!OnnxRun(ExtHandle, ONNX_NO_CONVERSION, x_norm, output_data))
     {
      Print("OnnxRun");
      ExtPredictedClass = -1;
      return;
     }

   float predicted = output_data[0] * (ExtMax - ExtMin) + ExtMin;
   float delta = last_close - predicted;
   if(fabs(delta) <= 0.00001)
      ExtPredictedClass = PRICE_SAME;
   else
      if(delta < 0)
         ExtPredictedClass = PRICE_UP;
      else
         ExtPredictedClass = PRICE_DOWN;

// Debugging output
   Print("Predicted price: ", predicted, " Delta: ", delta, " Predicted Class: ", ExtPredictedClass);
  }

8.追踪止损函数:

有多个函数(AllTS、METS、SimpleTS)实现不同的追踪止损策略。

这篇文章中对此进行了解释:  交易中的追踪止损 - MQL5 文章

9.优化函数:

  • OptimizeParameters:尝试不同的止盈和止损值来找到最佳设置。
  • OptimizeIndicators:找到 SMA 和 EMA 指标的最佳周期数。

void OptimizeParameters()
  {
   double bestTakeProfit = InpTakeProfit1;
   double bestStopLoss = InpStopLoss1;
   double bestPerformance = -DBL_MAX;

   for(int tp = 65; tp <= 500; tp += 5) // rango de TakeProfit
     {
      for(int sl = 65; sl <= 500; sl += 5) // rango de StopLoss
        {
         double performance = TestStrategy(tp, sl);
         if(performance > bestPerformance)
           {
            bestPerformance = performance;
            bestTakeProfit = tp;
            bestStopLoss = sl;
            //Print("Best Take Profit",bestTakeProfit);
            //Print("Best Stop Loss",bestStopLoss);
           }
        }
     }

   optimizedTakeProfit = bestTakeProfit;
   optimizedStopLoss = bestStopLoss;

   Print("Optimized TakeProfit: ", optimizedTakeProfit);
   Print("Optimized StopLoss: ", optimizedStopLoss);
  }
void OptimizeIndicators()
  {
   datetime startTime = TimeCurrent() - LookbackPeriod * PeriodSeconds(PERIOD_H1);
   datetime endTime = TimeCurrent();

   int bestSMAPeriod = SMA_Period;
   int bestEMAPeriod = EMA_Period;
   double bestPerformance = -DBL_MAX;

   for(int smaPeriod = MinSMAPeriod; smaPeriod <= MaxSMAPeriod; smaPeriod++)
     {
      for(int emaPeriod = MinEMAPeriod; emaPeriod <= MaxEMAPeriod; emaPeriod++)
        {
         double performance = TestIndicatorPerformance(smaPeriod, emaPeriod, startTime, endTime);

         if(performance > bestPerformance)
           {
            bestPerformance = performance;
            bestSMAPeriod = smaPeriod;
            bestEMAPeriod = emaPeriod;
           }
        }
     }

   SMA_Period = bestSMAPeriod;
   EMA_Period = bestEMAPeriod;

   Print("Optimized SMA Period: ", SMA_Period);
   Print("Optimized EMA Period: ", EMA_Period);
  }

10.工具函数和资金管理::

手数计算、交易量检查、市场收盘检查等函数包括检查交易资金是否足够以及规范手数等函数。

bool IsMarketClosed()
  {
   datetime currentTime = TimeCurrent();
   MqlDateTime tm;
   TimeToStruct(currentTime, tm);

   int dayOfWeek = tm.day_of_week;
   int hour = tm.hour;

// Verifica si es fin de semana
   if(dayOfWeek <= Sunday || dayOfWeek >= Saturday)
     {
      return true;
     }

// Verifica si está fuera del horario habitual de mercado (ejemplo: 21:00 a 21:59 UTC)
   if(hour >= after || hour < before)  // Ajusta estos valores según el horario del mercado
     {
      return true;
     }

   return false;
  }


//+------------------------------------------------------------------+
//| Check the correctness of the order volume                        |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume)//,string &description)
  {
//--- minimal allowed volume for trade operations
   double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   if(volume<min_volume)
     {
      //description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume);
      return(false);
     }

//--- maximal allowed volume of trade operations
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   if(volume>max_volume)
     {
      //description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume);
      return(false);
     }

//--- get minimal step of volume changing
   double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);

   int ratio=(int)MathRound(volume/volume_step);
   if(MathAbs(ratio*volume_step-volume)>0.0000001)
     {
      //description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f",
      //volume_step,ratio*volume_step);
      return(false);
     }
//description="Correct volume value";
   return(true);
  }
//+------------------------------------------------------------------+
bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type)
  {
//--- Getting the opening price
   MqlTick mqltick;
   SymbolInfoTick(symb,mqltick);
   double price=mqltick.ask;
   if(type==ORDER_TYPE_SELL)
      price=mqltick.bid;
//--- values of the required and free margin
   double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
//--- call of the checking function
   if(!OrderCalcMargin(type,symb,lots,price,margin))
     {
      //--- something went wrong, report and return false
      Print("Error in ",__FUNCTION__," code=",GetLastError());
      return(false);
     }
//--- if there are insufficient funds to perform the operation
   if(margin>free_margin)
     {
      //--- report the error and return false
      Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError());
      return(false);
     }
//--- checking successful
   return(true);
  }
double get_lot(double price)
  {
   if(inp_lot_type==LOT_TYPE_FIX)
      return(normalize_lot(inp_lot_fix));
   double one_lot_margin;
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,one_lot_margin))
      return(inp_lot_fix);
   return(normalize_lot((AccountInfoDouble(ACCOUNT_BALANCE)*(inp_lot_risk/100))/ one_lot_margin));
  }
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
double normalize_lot(double lt)
  {
   double lot_step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lt = MathFloor(lt / lot_step) * lot_step;
   double lot_minimum = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   lt = MathMax(lt, lot_minimum);
   return(lt);
  }

主要特点:

  1. 使用机器学习(ONNX 模型)进行价格预测。
  2. 将技术指标(SMA、EMA)与 ML 预测相结合,以做出交易决策。
  3. 实现了多种追踪止损策略。
  4. 包括指标参数和交易设置的定期优化。
  5. 具有内置风险管理(手数调整、资金检查)。
  6. 考虑到了交易的市场时间。

该 EA 交易非常复杂,将传统的技术分析与外汇交易的机器学习相结合。它还包括各种风险管理和优化功能,以适应不断变化的市场条件。

输入参数

图表 AAPL

回测 AAPL

分析表明,该自动交易策略表现出盈利能力,夏普比率达到 6.21。然而,它的回撤幅度很大,这表明需要谨慎的风险管理。正如净值曲线所示,该策略实现持续收益的能力反映了其在现实世界交易应用的潜力。未来的优化可以集中在减少回撤和提高恢复因子,以提高整体性能。


总结

本文介绍了一种用于外汇市场算法交易的创新型 EA 交易,专为交易 Apple Inc. (#AAPL) 股票而设计。该 EA 是机器学习和传统技术分析的复杂结合,旨在以精确度和适应性应对货币市场的复杂性。

该 EA 的核心是 ONNX(开放神经网络交换)模型,它作为机器学习组件。模型的任务是根据最近的市场数据预测价格走势,为交易策略增加前瞻性元素。EA 将这些预测与已建立的技术指标(即简单移动平均线 (SMA) 和指数移动平均线 (EMA))相结合,以生成交易信号。

EA 的方法是多方面的,包含几个关键特征:

  1. 动态优化:技术指标和交易参数都会定期优化。这使得 EA 能够适应不断变化的市场条件,并有可能随着时间的推移提高其性能。
  2. 自适应风险管理:EA 采用动态手数调整并使用平均真实范围 (ATR) 计算来设置止损和止盈水平。这种方法旨在根据当前市场波动调整头寸大小和风险敞口。
  3. 多种追踪止损策略:该 EA 实现了各种追踪止损方法,可以灵活地管理未平仓头寸,并有可能最大化利润,同时最小化损失。
  4. 市场条件感知:该系统设计时考虑了市场时间和条件,确保仅在适当的时候执行交易。

本文对 EA 的代码结构进行了详细的分解,阐明了其关键组成部分:

  1. 初始化:此阶段设置 ONNX 模型和技术指标,为 EA 的运行做好准备。
  2. 主要交易逻辑:核心功能是根据机器学习模型和技术指标的组合信号来决定何时开仓或平仓。
  3. 价格预测:应用 ONNX 模型预测未来的价格走势。
  4. 优化功能:定期调整指标参数和交易设置,以在不同的市场条件下维持有效性。
  5. 风险管理:包括手数计算、资金管理和市场条件检查等功能。

EA 的性能是通过对 AAPL 股票数据进行回溯测试来评估的,结果显示盈利能力良好,夏普比率为 6.21,表明风险调整后的回报强劲。然而,分析还显示,回撤数字相对较高,表明风险管理方面仍有改进空间。


结论

我们今天拥有的 EA 交易是一个巨大的飞跃。它结合使用智能技术(机器学习)和成熟方法(技术分析),为交易者提供有关如何投资 AAPL 股票和其他交易品种的宝贵会员专属决策。

该 EA 结合 ONNX 模型来通过优化的技术指标来预测价格。这种混合意味着它既能应对即时的价格变化,也能应对长期发展的缓慢波动。

这个 EA 的一个吸引人的地方是它有一个连贯的风险管理系统。例如,它采用动态手数(根据市场情况改变交易规模)、基于 ATR 的止损和止盈水平(如果情况恶化或盈利对你有利,则对你的损失施加限制)以及针对价格变化的多种追踪止损策略。这些工具是专门为保护你的资金而设计的,不会以秘密的方式被榨干。

这个 EA 的另一个优点是它定期更新指标和交易参数。这将使其能够跟上不断变化的市场,这是随着时间的推移保持有效的一个非常重要的组成部分。

然而,从回溯测试分析来看,结果仍然有些令人失望,该分析显示了 EA 过去的表现。尽管从利润和风险管理的角度来看,结果似乎不错,但它确实显示出一些高回撤率 — 价值大幅下降 — 从而表明风险管理可以加强。EA 的未来版本可能包括更好的保障措施,或者在非常动荡的时期进行更谨慎的交易。

尽管它是为交易 AAPL 股票而创建的,但其中的运作原理可以轻松应用于其他金融市场。这种灵活性使该工具在当前交易中以及作为未来算法系统的模型中都值得使用。

这是一个复杂、前景广阔的自动化交易 EA,融合了尖端技术和传统方式,风险管理能力强,能够适应不断变化的市场条件。然而,与任何其他交易工具一样,它确实需要在现实世界中进行定期监控、更新和测试,以确保其功能随着时间的推移而平稳运行。

最后,虽然这个 EA 似乎有很大的潜力,但还需要做更多的工作,还需要做很多优化,但重要的是要记住,交易总是涉及风险,过去的表现并不能保证未来的成功。如果您正在考虑使用这个或任何自动化系统,请确保您了解风险,做好功课,最好在使用真钱之前在模拟环境中进行测试。

我希望你喜欢读这篇文章,就像我喜欢写这篇文章一样,我希望你能把这个 EA 做得更好,取得好成绩。这是一个很好的例子,说明如何使用停止和指标实现自动优化。再说一遍,我希望你喜欢这篇文章。干杯!

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

附加的文件 |
SE_v9.mq5 (80.02 KB)
最近评论 | 前往讨论 (1)
yehaichang
yehaichang | 9 4月 2025 在 20:00
有没有基于神经网络交易的EA,我想试用,通过调整参数胜率高的,我准备购买
威廉·江恩(William Gann)方法(第二部分):创建江恩宫格指标 威廉·江恩(William Gann)方法(第二部分):创建江恩宫格指标
我们将基于“江恩九宫格”创建一个指标,该指标通过时间和价格方格构建而成。我们将提供指标代码,并在平台上针对不同的时间区间,对该指标进行测试。
创建 MQL5-Telegram 集成 EA 交易 (第二部分):从 MQL5 发送信号到 Telegram 创建 MQL5-Telegram 集成 EA 交易 (第二部分):从 MQL5 发送信号到 Telegram
在本文中,我们创建了一个 MQL5-Telegram 集成 EA 交易,将移动平均线交叉信号发送到 Telegram。我们详细介绍了从移动平均线交叉生成交易信号的过程,在 MQL5 中实现必要的代码,并确保集成无缝工作。结果是系统可以直接向您的 Telegram 群聊提供实时交易提醒。
交易中的神经网络:一种复杂的轨迹预测方法(Traj-LLM) 交易中的神经网络:一种复杂的轨迹预测方法(Traj-LLM)
在本文中,我想向您介绍一种为解决自动驾驶领域问题而开发的有趣的轨迹预测方法。该方法的作者结合了各种架构解决方案的最佳元素。
重构经典策略(第五部分):基于USDZAR的多品种分析 重构经典策略(第五部分):基于USDZAR的多品种分析
在本系列文章中,我们重新审视经典策略,看看是否可以使用人工智能来改进这些策略。在今天的文章中,我们将研究一种使用一篮子具有相关性的金融产品来进行多品种分析的流行策略,我们将重点关注货币对 USDZAR。