English Русский 中文 Español Deutsch Português
preview
SMAとEMAを使った自動最適化された利益確定と指標パラメータの例

SMAとEMAを使った自動最適化された利益確定と指標パラメータの例

MetaTrader 5 | 14 10月 2024, 09:28
256 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

はじめに

日々進化するアルゴリズム取引の世界では、技術革新が市場に先んじるための重要な鍵となります。今回は、機械学習と伝統的なテクニカル分析を統合し、FX市場に対応する高度なEAをご紹介します。このEAは、慎重に最適化されたテクニカル指標とONNXモデルを活用し、取引判断をサポートします。

このEAは多面的なアプローチを採用しており、機械学習モデルによる価格予測、トレンドフォロー技術、そして適応的なパラメータ最適化を組み合わせています。主に#AAPL銘柄を対象としていますが、他の銘柄にも応用可能な柔軟性を持っています。ダイナミックなロットサイズ、トレーリングストップ、そして市況に自動調整する機能を備え、このEAは最先端技術と長年の取引経験に基づいた原則を見事に融合しています。

使用した指標の説明

  1. 単純移動平均 (SMA):EAは、動的に最適化された期間を持つSMAを使用しています。SMAは、全体的なトレンドの方向を把握し、価格や他の指標と組み合わせて売買シグナルを生成する役割を果たします。
  2. 指数移動平均(EMA):EMAも同様に採用され、期間は動的に最適化されています。EMAはSMAよりも最近の価格変動に敏感に反応し、トレンドの異なる視点を提供します。
  3. アベレージトゥルーレンジ(ATR):Aは、明示的に計算されていないものの、ATRベースの計算を用いて損切りと利食いのレベルを設定しています。これにより、ボラティリティに基づいたポジションサイジングとリスク管理が可能となります。
  4. 機械学習モデル:EAにはONNX (Open Neural Network Exchange) モデルが組み込まれ、価格予測に利用されています。このモデルは、直近の一連の価格データを入力として次の値動きを予測し、取引戦略に予測の要素を加えます。

これらの指標は高度に組み合わされ、それらのパラメータは最近の市況に基づいて動的に最適化されます。また、トレーリングストップや期待値計算などの機能を備え、ポジション管理の効果を高めています。

これらのテクニカル指標と機械学習の要素を組み合わせることで、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は非常に洗練されており、伝統的なテクニカル分析とFX取引のための機械学習を組み合わせています。また、変化する市場環境に対応するため、さまざまなリスク管理や最適化機能も備えています。

入力

グラフAAPL

AAPLのバックテスト

この分析によれば、自動売買戦略はシャープレシオ6.21という堅実な結果を示し、収益性が確認されました。しかし、ドローダウンが大きいため、より慎重なリスク管理が求められます。エクイティカーブに示される安定した利益の達成能力は、実際の取引への応用可能性を示しています。今後は、ドローダウンの削減や回収係数の改善に重点を置くことで、全体的なパフォーマンスを向上させることができるでしょう。


まとめ

本記事では、特にアップル社(#AAPL)の株取引に焦点を当てた、FX市場向けの革新的なEAを紹介しました。このEAは、機械学習と伝統的なテクニカル分析を高度に統合し、複雑な市場環境を正確かつ適応的にナビゲートすることを目指しています。

EAの中心的な要素は、機械学習コンポーネントとして活用されるONNX (Open Neural Network Exchange) モデルです。このモデルは、直近の市場データをもとに価格の動きを予測し、取引戦略に予測的な要素を加えます。予測結果は、単純移動平均(SMA)や指数移動平均(EMA)などの確立されたテクニカル指標と組み合わせて売買シグナルを生成します。

このEAは、多角的なアプローチを取り、いくつかの重要な機能を備えています。

  1. 動的最適化:テクニカル指標や取引パラメータが定期的に最適化され、市場環境の変化に柔軟に対応しながら、長期的なパフォーマンス向上を図ります。
  2. 適応的リスク管理:ダイナミックなロットサイジングと、平均トゥルーレンジ(ATR)を用いた損切り・利食い設定により、ボラティリティに基づいてリスクエクスポージャーとポジションサイズを調整します。
  3. 複数のトレーリングストップ戦略:さまざまなトレーリングストップを実装しており、損失を抑えつつ利益を最大化する柔軟なポジション管理が可能です。
  4. 市況の認識:EAは市場の時間帯や状況を考慮し、適切なタイミングでのみ取引を行うよう設計されています。

この記事では、EAのコード構造を詳細に分解し、その主要な構成要素を明らかにしています。

  1. 初期化:ONNXモデルやテクニカル指標を設定し、EAの動作を準備する段階です。
  2. 主な取引ロジック:機械学習モデルとテクニカル指標を組み合わせたシグナルに基づき、ポジションのエントリやエグジットを決定する中核機能です。
  3. 価格予想:ONNXモデルを活用して将来の値動きを予測します。
  4. 最適化関数:市場の変化に対応するため、指標や取引設定のパラメータを定期的に調整します。
  5. リスク管理:ロットサイズや資金管理、相場状況を確認する機能を備えています。

EAのパフォーマンスは、AAPL株のデータを用いたバックテストにより評価され、シャープレシオ6.21と高いリスク調整後のリターンを示しました。ただし、ドローダウンの数値が比較的高いことも判明しており、今後の改善点として、より効果的なリスク管理が必要とされています。


結論

今回紹介したEAは、機械学習などのスマートテクノロジーと、実証済みのテクニカル分析手法を組み合わせた、画期的なツールです。AAPL株や他の銘柄への投資において、トレーダーに貴重な意思決定をサポートする機能を提供します。

このEAは、価格予測を行うONNXモデルと最適化されたテクニカル指標を組み合わせており、短期的な価格変動にも長期的なトレンドにも柔軟に対応できるよう設計されています。

特に、リスク管理が強化されている点が特徴です。ダイナミックロットサイジング(市況に応じて取引サイズを調整)、ATRベースのストップロスとテイクプロフィット設定(状況が悪化した場合の損失額や有利な場合の利益額を制限)、そして複数のトレーリングストップ戦略を用いて、リスクを抑えつつ利益の最大化を目指します。これらのツールは、非公開の方法でごまかされることなく、あなたのお金を維持するために調整されています。

さらに、EAは定期的に指標と取引パラメータを更新することで、市場の変化に適応し、長期間にわたって効果を維持できるよう工夫されています。

しかし、EAが過去にどのような成績を残したかを示すバックテスト分析では、結果はまだやや期待外れです。利益とリスク管理という点では良い結果に見えますが、ドローダウンが大きい(価値が大きく下がる)ので、リスク管理を強化する必要があります。将来のバージョンでは、不安定な相場での慎重な取引や、より強固なセーフガードが追加される可能性があります。

EAはAAPL株の取引を目的に作られましたが、その設計原理は他の金融市場にも簡単に応用できるでしょう。この柔軟性により、現在の取引環境だけでなく、将来のアルゴリズム取引システムのモデルとしても価値を持つツールです。

このEAは、最先端技術と伝統的手法を融合した高度な自動売買システムであり、リスク管理に優れ、変化する市場環境に適応できる能力を持っています。しかし、他の取引ツールと同様に、定期的な監視や更新、実際の市場環境でのテストが必要であり、長期的な安定性を確保するための継続的なメンテナンスが求められます。

最後に、このEAには大きな可能性が秘められていますが、さらなる最適化や改善の余地があります。取引には常にリスクが伴うため、過去のパフォーマンスが将来の成果を保証するものではないことを理解しておくことが重要です。このEAや他の自動売買システムを使用する際には、事前にシミュレーション環境で十分なテストを行い、リスクをしっかり把握するよう心掛けてください。

このEAが今後さらに改良され、より良い結果が得られることを期待しています。自動最適化とストップを効果的に実装した一例として、ご参考になれば幸いです。ではまた。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/15476

添付されたファイル |
SE_v9.mq5 (80.02 KB)
ニューラルネットワークが簡単に(第88回):Time-series Dense Encoder (TiDE) ニューラルネットワークが簡単に(第88回):Time-series Dense Encoder (TiDE)
研究者たちは、より正確な予測を得るために、しばしばモデルを複雑化します。しかし、その結果として、モデルの訓練やメンテナンスにかかるコストも増加します。この増大したコストは常に正当化されるのでしょうか。本記事では、シンプルで高速な線形モデルの特性を活かし、複雑なアーキテクチャを持つ最新モデルに匹敵する結果を示すアルゴリズムを紹介します。
知っておくべきMQL5ウィザードのテクニック(第31回):損失関数の選択 知っておくべきMQL5ウィザードのテクニック(第31回):損失関数の選択
損失関数は、機械学習アルゴリズムの重要な指標です。これは、与えられたパラメータセットが目標に対してどれだけうまく機能しているかを定量的に評価し、学習プロセスにフィードバックを提供する役割を果たします。本記事では、MQL5のカスタムウィザードクラスを使って、損失関数のさまざまな形式を探っていきます。
多通貨エキスパートアドバイザーの開発(第10回):文字列からオブジェクトを作成する 多通貨エキスパートアドバイザーの開発(第10回):文字列からオブジェクトを作成する
エキスパートアドバイザー(EA)の開発計画は複数の段階で構成されており、中間結果はデータベースに保存されます。しかし、これらの結果はオブジェクトとしてではなく、文字列や数値としてのみ抽出できます。したがって、データベースから読み込んだ文字列を基に、EAで目的のオブジェクトを再構築する方法が必要です。
MQL5-Telegram統合エキスパートアドバイザーの作成(第2回):MQL5からTelegramへのシグナル送信 MQL5-Telegram統合エキスパートアドバイザーの作成(第2回):MQL5からTelegramへのシグナル送信
この記事では、移動平均クロスオーバーシグナルをTelegramに送信するMQL5-Telegram統合エキスパートアドバイザー(EA)を作成します。移動平均クロスオーバーから売買シグナルを生成し、MQL5で必要なコードを実装し、統合がシームレスに機能するようにするプロセスを詳しく説明します。その結果、リアルタイムの取引アラートをTelegramのグループチャットに直接提供するシステムが完成します。