トップページイメージ

ここでは、複数のシグナルやエントリーフィルターを搭載して、それらのどれを使用するかを選択できるEAを作成する方法を紹介します。

今回解説するEAのコード

EAコード全体

Dr.EADr.EA

今回のEAコードがこちら

#property strict

// Main Setting
extern double  Lots                 = 0.01;
extern double  StopLoss             = 50;
extern double  TakeProfit           = 100;
extern double  Slippage             = 1;
extern string  PosComment           = "EA";
extern int     MagicNumber          = 20191208;

// Signal Setting
//Ma
extern bool    UseMaCrossSignal     = true;
extern int     MaShortPeriod        = 20;
extern int     MaLongPeriod         = 50;
//Macd
extern bool    UseMacdCrossSignal   = false;
extern int     MacdFastPeriod       = 12;
extern int     MacdSlowPeriod       = 26;
extern int     MacdSignalPeriod     = 9;

// Entry Filter Setting
//Ma
extern bool    UseMaTrendFilter     = true;
extern int     MaTrendPeriod        = 100;
//ADX
extern bool    UseAdxFilter         = true;
extern int     AdxPeriod            = 14;
extern double  AdxFilterLevel       = 25.0;
//ATR
extern bool    UseAtrFilter         = true;
extern int     AtrPeriod            = 14;
extern double  AtrFilterPips        = 10.0;

//Exit Setting
extern bool    ExitReverseSign      = true;

// グローバル変数
double g_point;

int   g_entry_bar_buy;
int   g_entry_bar_sell;

//+------------------------------------------------------------------+
int OnInit()
{
   // Parameter setting error
   if(UseMaCrossSignal == false && UseMacdCrossSignal == false)   //シグナルが1つも使われていない場合
   {
      Alert("Signal setting error.");  // エラーアラートを出して
      return(INIT_FAILED);             // EAを終了する
   }

   // パラメーターをPips入力にする為の処理
   g_point = Point;
   if (Digits % 2 == 1)
   {
      g_point *= 10;
      Slippage *= 10;
   }
   
   return(INIT_SUCCEEDED);
}
  
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
void OnTick()
{
   // Positions Check :::::::::::::::::::::::::::::::::::::::::::::::::
   int pos_ticket_buy = 0;
   int pos_ticket_sell = 0;
   
   for (int i=0 ; i<OrdersTotal() ;i++)
   {
      if (OrderSelect(i, SELECT_BY_POS) == false) return;
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      
      if (OrderType() == OP_BUY) pos_ticket_buy = OrderTicket();
      if (OrderType() == OP_SELL) pos_ticket_sell = OrderTicket();
   }
   
   
   // Entry Signal ::::::::::::::::::::::::::::::::::::::::::::::::::::
   // MA
   int ma_cross_sign = 0;
   if(UseMaCrossSignal == true)
   {
      double ma_s_1 = iMA(NULL, 0, MaShortPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
      double ma_s_2 = iMA(NULL, 0, MaShortPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
      double ma_l_1 = iMA(NULL, 0, MaLongPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
      double ma_l_2 = iMA(NULL, 0, MaLongPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
      
      if(ma_l_2 >= ma_s_2 && ma_l_1 < ma_s_1) ma_cross_sign = 1;
      if(ma_l_2 <= ma_s_2 && ma_l_1 > ma_s_1) ma_cross_sign = -1;
   }

   // MACD
   int macd_sign = 0;
   if(UseMacdCrossSignal == true)
   {
      double macd_1 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_MAIN, 1);
      double macd_2 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_MAIN, 2);
      double macd_sig_1 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_SIGNAL, 1);
      double macd_sig_2 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_SIGNAL, 2);
      
      if(macd_sig_2 >= macd_2 && macd_sig_1 < macd_1) macd_sign = 1;
      if(macd_sig_2 <= macd_2 && macd_sig_1 > macd_1) macd_sign = -1;
   }
   
   // Entry Filter :::::::::::::::::::::::::::::::::::::::::::::::::::::
   //MA
   int ma_filter = 0;
   if(UseMaTrendFilter == true)
   {
      double ma_trend_1 = iMA(NULL, 0, MaTrendPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
      double ma_trend_2=iMA(NULL, 0, MaTrendPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
      if(ma_trend_2 < ma_trend_1) ma_filter=1;
      if(ma_trend_2 > ma_trend_1) ma_filter=-1;
   }

   // ADX
   bool adx_filter = false;
   if(UseAdxFilter == true)
   {
      double adx_1 = iADX(NULL, 0, AdxPeriod, PRICE_CLOSE, MODE_MAIN, 1);
      if(adx_1 >= AdxFilterLevel) adx_filter = true;
   }
   
   // ATR
   bool atr_filter = false;
   if(UseAtrFilter == true)
   {
      double atr1=iATR(NULL, 0, AtrPeriod, 1);
      if(atr1 >= AtrFilterPips * g_point) atr_filter = true;
   }
   
   // Entry Sign ******************************************************
   int sign = 0;
   
   if((UseMaCrossSignal == false || ma_cross_sign == 1) &&
      (UseMacdCrossSignal == false || macd_sign == 1) &&
      (UseMaTrendFilter == false || ma_filter == 1) &&
      (UseAdxFilter == false || adx_filter == true) &&
      (UseAtrFilter == false || atr_filter == true)) sign = 1;
      
   if((UseMaCrossSignal == false || ma_cross_sign == -1) &&
      (UseMacdCrossSignal == false || macd_sign == -1) &&
      (UseMaTrendFilter == false || ma_filter == -1) &&
      (UseAdxFilter == false || adx_filter == true) &&
      (UseAtrFilter == false || atr_filter == true)) sign = -1;
   
   //Exit Sign:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
   int exit_sign = 0;
   if(ExitReverseSign == true)
   {
      if((UseMaCrossSignal == false || ma_cross_sign == 1) &&
         (UseMacdCrossSignal == false || macd_sign == 1)) exit_sign = 1;
         
      if((UseMaCrossSignal == false || ma_cross_sign == -1) &&
         (UseMacdCrossSignal == false || macd_sign == -1)) exit_sign = -1;
   }
   
   
   //Exit::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
   
   if (pos_ticket_buy > 0 && exit_sign == -1)
   {
      if (OrderSelect(pos_ticket_buy, SELECT_BY_TICKET) == true)
      {
         if (OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), (int)Slippage, clrYellow) == true) pos_ticket_buy = 0;
      }
   }
   
   if (pos_ticket_sell > 0 && exit_sign == 1)
   {
      if (OrderSelect(pos_ticket_sell, SELECT_BY_TICKET) == true)
      {
         if (OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), (int)Slippage, clrYellow) == true) pos_ticket_sell = 0;
      }
   }
   
   //Entry:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
   
   int ticket;
   double sl = 0, tp = 0;
   
   if (pos_ticket_buy == 0 && g_entry_bar_buy != Bars && sign == 1)
   {
      if (StopLoss > 0) sl = Ask - StopLoss * g_point;
      if (TakeProfit > 0) tp = Ask + TakeProfit * g_point;
      ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, (int)Slippage, sl, tp, PosComment, MagicNumber, 0, clrBlue);
      if (ticket > 0) g_entry_bar_buy = Bars;
   }
   
   if (pos_ticket_sell == 0 && g_entry_bar_sell != Bars && sign == -1)
   {
      if (StopLoss > 0) sl = Bid + StopLoss * g_point;
      if (TakeProfit > 0) tp = Bid - TakeProfit * g_point;
      ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, (int)Slippage, sl, tp, PosComment, MagicNumber, 0, clrRed);
      if (ticket > 0) g_entry_bar_buy = Bars;
   }
}

EAファイルをダウンロード

次のリンクから、この記事で解説するサンプルEA【Sample_SwitchSignal_2019.mq4】がダウンロードできます。

新MQL4リメイク版EA【Sample_SwitchSignal_2019.mq4】をダウンロード

次のリンクは、旧MQL4のサンプルEAです。
旧MQL4のEA【Sample_SwitchSignal.zip】をダウンロード

EAコード解説

Dr.EADr.EA

今回のEAコードの重要な部分を解説するぞい

パラメーター抜粋

次のように、2つのエントリーシグナルと3つのエントリーフィルターをbool(真偽)型のパラメーターにして、true:使用する, false:使用しない を選択できるようにしています。

extern bool    UseMaCrossSignal     = true;  // MAのクロスによるシグナル
extern bool    UseMacdCrossSignal   = false; // MACDのクロスによるシグナル
extern bool    UseMaTrendFilter     = true;  // MAの向きによるフィルター
extern bool    UseAdxFilter         = true;  // ADXの値によるフィルター
extern bool    UseAtrFilter         = true;  // ATRの値によるフィルター

OnInit()関数内でパラメーター設定を制限

OnInit()関数内で次のようにして、エントリーシグナルが一つも使用されない場合は、エラーアラートを出してEA稼働を終了するようにしています。

   if(UseMaCrossSignal == false && UseMacdCrossSignal == false)   //シグナルが1つも使われていない場合
   {
      Alert("Signal setting error.");  // エラーアラートを出して
      return(INIT_FAILED);             // EAを終了する
   }

OnTick()関数内の構成

OnTick()関数内は次の順で書いています。

  1. 保有ポジション確認
  2. エントリーシグナル判定
  3. エントリーフィルター判定
  4. エントリーサイン判定
  5. エグジットサイン判定
  6. エグジット処理
  7. エントリー処理

エントリーサイン判定

エントリーサイン判定を次のように、パラメーターで設定した「使用する or 使用しない」が反映されるようにしています。

   int sign = 0;
   
   if((UseMaCrossSignal == false || ma_cross_sign == 1) &&
      (UseMacdCrossSignal == false || macd_sign == 1) &&
      (UseMaTrendFilter == false || ma_filter == 1) &&
      (UseAdxFilter == false || adx_filter == true) &&
      (UseAtrFilter == false || atr_filter == true)) sign = 1;
      
   if((UseMaCrossSignal == false || ma_cross_sign == -1) &&
      (UseMacdCrossSignal == false || macd_sign == -1) &&
      (UseMaTrendFilter == false || ma_filter == -1) &&
      (UseAdxFilter == false || adx_filter == true) &&
      (UseAtrFilter == false || atr_filter == true)) sign = -1;
もし、
UseMaCrossSignal を使用しないまたは、ma_cross_sign が買いシグナル かつ
UseMacdCrossSignal を使用しないまたは、macd_sign が買いシグナル かつ
UseMaTrendFilter を使用しないまたは、ma_filter が買いOK かつ
UseAdxFilter を使用しないまたは、adx_filter がエントリーOK かつ
UseAtrFilter を使用しないまたは、atr_filter がエントリーOK
の場合、sign を買いサインにする
(以下、売りサインの場合も同様)

あとがき

今回のEAコードの書き方は、色々なシグナルやフィルターを試したいときに便利ですので是非カスタマイズして使ってみてください。
では、今回はこのへんで^^