自動売買06

ここでは、前回までの記事で作成したMetaTrader4のEAをカスタマイズする方法を紹介します。

もし「前回までの記事、まだ見ていないよー」という方は【MetaTrader4のEAの作り方(前編)】から読み進めてください。

前々回の記事【MetaTrader4のEAの作り方(前編)】へ

前回までの記事で作成したEAのおさらい

Dr.EADr.EA

前回までの記事で作成したEAがこちら

//+------------------------------------------------------------------+
//|                                             MA_Doten_EAv1.00.mq4 |
//|                                                      Dr.EA Keiji |
//|                                 https://www.dr-ea.com/meta-blog/ |
//+------------------------------------------------------------------+
#property copyright "Dr.EA Keiji"
#property link      "https://www.dr-ea.com/meta-blog/"
#property version   "1.00"
#property strict

// パラメーター
extern double  Lots        = 0.1;
extern int     MagicNumber = 20191030;

// グローバル変数
int entry_bar; // エントリーした時のバーの数

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   // 使い回ししそうな変数を宣言
   int i, ticket;
   
   
   // 保有ポジションを確認 -------------------------------
   
   int ticket_buy = 0;  // 買いポジションの注文番号
   double lots_buy = 0; // 買いポジションのロット数
   int ticket_sell = 0; // 売りポジションの注文番号
   double lots_sell = 0;// 売りポジションのロット数
   
   for (i=0; i<OrdersTotal(); i++)
   {
      // ポジション選択
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return;
      // 通貨ペアまたはマジックナンバーが違う場合はスキップ
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      
      // 保有ポジションの注文番号とロット数を変数に代入
      if (OrderType() == OP_BUY)
      {
         ticket_buy = OrderTicket();
         lots_buy = OrderLots();
      }
      if (OrderType() == OP_SELL)
      {
         ticket_sell = OrderTicket();
         lots_sell = OrderLots();
      }
   }
   
   
   // 取引シグナルを判定 ---------------------------------
   
   int entry_sign = 0;  // エントリー用シグナル
   int exit_sign = 0;   // 決済用シグナル
   
   // MAの値を取得
   double ma_1 = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 1);
   double ma_2 = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 2);
   
   // 条件を満たしたらシグナル発生 (1: 買いシグナル, -1: 売りシグナル)
   if (Close[2] <= ma_2 && Close[1] > ma_1)
   {
      entry_sign = 1;
      exit_sign = 1;
   }
   if (Close[2] >= ma_2 && Close[1] < ma_1)
   {
      entry_sign = -1;
      exit_sign = -1;
   }
   
   
   // 決済 -----------------------------------------------
   
   // 買いポジション決済
   if (ticket_buy > 0 && exit_sign == -1)
   {
      if (OrderClose(ticket_buy, lots_buy, Bid, 0, clrYellow) == true)
         ticket_buy = 0;
      else
         Print("OrderClose error.");
   }
   
   // 売りポジション決済
   if (ticket_sell > 0 && exit_sign == 1)
   {
      if (OrderClose(ticket_sell, lots_sell, Ask, 0, clrYellow) == true)
         ticket_sell = 0;
      else
         Print("OrderClose error.");
   }
   
   
   // エントリー-------------------------------------------
   
   if (ticket_buy == 0 && ticket_sell == 0 && entry_bar != Bars)
   {
      // 買いエントリー
      if (entry_sign == 1)
      {
         ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, 0, 0, NULL, MagicNumber, 0, clrBlue);
         if (ticket > 0)
            entry_bar = Bars;
         else
            Print("OrderSend error.");
      }

      // 売りエントリー
      if (entry_sign == -1)
      {
         ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 0, 0, 0, NULL, MagicNumber, 0, clrRed);
         if (ticket > 0)
            entry_bar = Bars;
         else
            Print("OrderSend error.");
      }
   }
  }
//+------------------------------------------------------------------+
にゃんたにゃんた

これこれー♪

単純移動平均線(期間20)を終値が超えて終えたら、次のローソク足の始めでドテン取引するEAです。

今回のEAの改良ポイント

次の4つの改良を行います。

  1. SL幅とTP幅を設定するパラメーターを追加する
  2. エントリーフィルタを追加する
  3. MAによる決済をするか否かのパラメーターを追加する
  4. 移動平均のパラメーターを追加する

にゃんたにゃんた

なんだか良くなりそうな気がするにゃ!

Dr.EADr.EA

では早速。(カタカタ・・・)っほい!

//+------------------------------------------------------------------+
//|                                             MA_Doten_EAv1.01.mq4 |
//+------------------------------------------------------------------+
#property copyright "Dr.EA Keiji"
#property link      "https://www.dr-ea.com/meta-blog/"
#property version   "1.01"
#property strict

// パラメーター
extern int     StopLoss    = 500;
extern int     TakeProfit  = 500;
extern double  Lots        = 0.1;
extern int     MagicNumber = 20191030;

extern int     MA_Period   = 20;
extern int     MA_Shift    = 0;
extern ENUM_MA_METHOD MA_Method = MODE_SMA;
extern ENUM_APPLIED_PRICE MA_Applied = PRICE_CLOSE;

extern bool    ExitByMA    = false;

// グローバル変数
int entry_bar; // エントリーした時のバーの数

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   // 使い回ししそうな変数を宣言
   int i, ticket;
   double sl, tp;
   
   
   // 保有ポジションを確認 -------------------------------
   
   int ticket_buy = 0;  // 買いポジションの注文番号
   double lots_buy = 0; // 買いポジションのロット数
   int ticket_sell = 0; // 売りポジションの注文番号
   double lots_sell = 0;// 売りポジションのロット数
   
   for (i=0; i<OrdersTotal(); i++)
   {
      // ポジション選択
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return;
      // 通貨ペアまたはマジックナンバーが違う場合はスキップ
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      
      // 保有ポジションの注文番号とロット数を変数に代入
      if (OrderType() == OP_BUY)
      {
         ticket_buy = OrderTicket();
         lots_buy = OrderLots();
      }
      if (OrderType() == OP_SELL)
      {
         ticket_sell = OrderTicket();
         lots_sell = OrderLots();
      }
   }
   
   
   // 取引シグナルを判定 ---------------------------------
   
   int entry_sign = 0;  // エントリー用シグナル
   int exit_sign = 0;   // 決済用シグナル
   
   // MAの値を取得
   double ma_1 = iMA(NULL, 0, MA_Period, MA_Shift, MA_Method, MA_Applied, 1);
   double ma_2 = iMA(NULL, 0, MA_Period, MA_Shift, MA_Method, MA_Applied, 2);
   
   // 条件を満たしたらシグナル発生 (1: 買いシグナル, -1: 売りシグナル)
   if (Close[2] <= ma_2 && Close[1] > ma_1)
   {
      if (ma_2 < ma_1) entry_sign = 1;       // MAが上昇なら買いエントリーシグナル発生
      if (ExitByMA == true) exit_sign = 1;   // ExitByMAがtrueなら売りポジ決済シグナル発生
   }
   if (Close[2] >= ma_2 && Close[1] < ma_1)
   {
      if (ma_2 > ma_1) entry_sign = -1;      // MAが下降なら売りエントリーシグナル発生
      if (ExitByMA == true) exit_sign = -1;  // ExitByMAがtrueなら買いポジ決済シグナル発生
   }
   
   
   // 決済 -----------------------------------------------
   
   // 買いポジション決済
   if (ticket_buy > 0 && exit_sign == -1)
   {
      if (OrderClose(ticket_buy, lots_buy, Bid, 0, clrYellow) == true)
         ticket_buy = 0;
      else
         Print("OrderClose error.");
   }
   
   // 売りポジション決済
   if (ticket_sell > 0 && exit_sign == 1)
   {
      if (OrderClose(ticket_sell, lots_sell, Ask, 0, clrYellow) == true)
         ticket_sell = 0;
      else
         Print("OrderClose error.");
   }
   
   
   // エントリー-------------------------------------------
   
   if (ticket_buy == 0 && ticket_sell == 0 && entry_bar != Bars)
   {
      // 買いエントリー
      if (entry_sign == 1)
      {
         sl = 0;
         tp = 0;
         if (StopLoss > 0) sl = Ask - StopLoss * Point;
         if (TakeProfit > 0) tp = Ask + TakeProfit * Point;
            
         ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, sl, tp, NULL, MagicNumber, 0, clrBlue);
         if(ticket > 0)
            entry_bar = Bars;
         else
            Print("OrderSend error.");
      }
      
      // 売りエントリー
      if (entry_sign == -1)
      {
         sl = 0;
         tp = 0;
         if (StopLoss > 0) sl = Bid + StopLoss * Point;
         if (TakeProfit > 0) tp = Bid - TakeProfit * Point;
         
         ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 0, sl, tp, NULL, MagicNumber, 0, clrRed);
         if(ticket > 0)
            entry_bar = Bars;
         else
            Print("OrderSend error.");
      }
   }
  }
にゃんたにゃんた

はぅぅぅ。。

SL幅とTP幅を設定するパラメーターを追加

SL幅とTP幅をポイント単位で設定するパラメーターStopLossとTakeProfitを次のように追加します。

extern int     StopLoss    = 500;
extern int     TakeProfit  = 500;

OnTick()関数内で、実数変数slとtpを宣言しておきます。

   double sl, tp;

買いエントリーのコードを次のように変更します。

         sl = 0;
         tp = 0;
         if (StopLoss > 0) sl = Ask - StopLoss * Point;
         if (TakeProfit > 0) tp = Ask + TakeProfit * Point;
            
         ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, sl, tp, NULL, MagicNumber, 0, clrBlue);
slとtpに0を代入しておいて、StopLossが0より大きい場合AskからStopLossポイント下の価格をslに代入。
TakeProfitが0より大きい場合AskからTakeProfitポイント上の価格をtpに代入。
slとtpをOrderSend()関数のSL/TP設定箇所に入力。

売りエントリーのコードも同じように変更します。

ここで、例えばStopLossが0より大きい場合ではない場合、sl は 0 のままで、SL設定無しということになります。

エントリーフィルタを追加する

MAが上昇時のみ買いエントリーシグナルを発生させて、MAが下降時のみ売りエントリーシグナルを発生させるようにします。

買いエントリーシグナル発生部分を次のようにします。

      if (ma_2 < ma_1) entry_sign = 1;       // MAが上昇なら買いエントリーシグナル発生

売りエントリーシグナル発生部分を次のようにします。

      if (ma_2 > ma_1) entry_sign = -1;      // MAが下降なら売りエントリーシグナル発生

MAによる決済をするか否かのパラメーターを追加する

次のように、MAによる決済をするか否かを真偽型パラメーター変数ExitByMAを追加します。

extern bool    ExitByMA    = false;

決済用シグナルを判定する部分で、次のようにExitByMAがtrueの場合のみ決済シグナルが発生するようにします。

売りポジション決済シグナル発生部分を次のようにします。

      if (ExitByMA == true) exit_sign = 1;   // ExitByMAがtrueなら売りポジ決済シグナル発生

買いポジション決済シグナル発生部分を次のようにします。

      if (ExitByMA == true) exit_sign = -1;  // ExitByMAがtrueなら買いポジ決済シグナル発生

移動平均のパラメーターを追加する

移動平均の期間、表示移動、MAの種類、適用価格をそれぞれ設定するパラメーターを次のように追加します。

extern int     MA_Period   = 20;
extern int     MA_Shift    = 0;
extern ENUM_MA_METHOD MA_Method = MODE_SMA;
extern ENUM_APPLIED_PRICE MA_Applied = PRICE_CLOSE;

MAの種類のデータ型をENUM_MA_METHODにすることで、パラメーター入力画面で直接入力ではなく、リストから選択する形になります。適用価格のデータ型はENUM_APPLIED_PRICEとします。

iMA()関数の括弧内を次のように変更します。

   double ma_1 = iMA(NULL, 0, MA_Period, MA_Shift, MA_Method, MA_Applied, 1);
   double ma_2 = iMA(NULL, 0, MA_Period, MA_Shift, MA_Method, MA_Applied, 2);

あとがき

EAのパラメーターを増やすことで、取引ロジック設定の幅が広がりました。今回の記事ではEA改良の第一歩という感じでしたが、ぜひご自身のアイデアを取り込んだEAにカスタマイズしてみてください。

次回は、EAのパラメーターを最適化する方法を紹介します。