自動売買05イメージ

ここでは、前回記事に引き続きMetaTrader4のEAの作り方について説明します。

もし前回記事をまだ見ていない方はそちらから読み進めてください。

前回記事【MetaTrader4の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.");
      }
   }
  }
//+------------------------------------------------------------------+
にゃんたにゃんた

はぅぅ。。

取引シグナルを判定

エントリー用と決済用のシグナルを格納する変数を宣言します。

   int entry_sign = 0;  // エントリー用シグナル
   int exit_sign = 0;   // 決済用シグナル

次に、iMA()関数で、単純移動平均(期間20)の1つ前と2つ前の値を実数変数「ma_1」と「ma_2」に格納します。

   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);
iMA()関数について

iMA()関数の()括弧内は次のように指定します。

iMA(通貨ペア, 時間足周期, 期間, 表示移動, MAの種類, 適用価格, シフト数)

通貨ペア
通貨ペアを文字列で指定します。NULLとすると稼働チャートの通貨ペアのことになります。

時間足周期
時間足周期を整数または定数で指定します。0またはPERIOD_CURRENTとすると稼働チャートの時間足周期のことになります。
1分足は1またはPERIOD_M1、5分足は5またはPRIOD_M5というように指定します。

期間と表示移動
期間と表示移動は整数で指定します。

MAの種類
MAの種類は、次の4種類から選んで指定します。

単純移動平均 MODE_SMA
指数移動平均 MODE_EMA
平滑移動平均 MODE_SMMA
加重移動平均 MODE_LWMA

適用価格
適用価格は、次の7種類から選んで指定します。

終値 PRICE_CLOSE
始値 PRICE_OPEN
高値 PRICE_HIGH
安値 PRICE_LOW
Median price (高値+安値)/2 PRICE_MEDIAN
Typical price (高値+安値+終値)/3 PRICE_TYPICAL
Weighted close price (高値+安値+終値+終値)/4 PRICE_WEIGHTED

シフト数
シフト数は、ローソク足何本分前かを指定します。

取引シグナル判定セクションの最後で、次のようにif()文で条件判定をして、条件を満たしたときに、シグナル用変数に買いシグナル「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;
   }

ここではClose[シフト数]で、シフト数本前のローソク足の終値を取得して条件文に使用しています。

決済注文処理

決済注文処理のセクションでは、次のコードのようにif()文で保有ポジションの決済シグナルが出ているかを判定して、OrderClose()関数で決済注文をします。

   // 買いポジション決済
   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.");
   }
OrderClose()関数について

OrderClose()関数の()括弧内は次のように指定します。OrderClose()関数の実行に成功したらtrueが返り、失敗したらfalseが返ります。

OrderClose(注文番号, ロット数, 決済価格, 許容スリッページ, 決済マークの色)

注文番号
決済するポジションの注文番号を指定します。

ロット数
決済する取引数量(ロットサイズ)を指定します。

決済価格
決済する価格を指定します。通常、買いポジションはBid、売りポジションはAskで決済します。ポジション選択中はOrderClosePrice()を使用してもよいです。

許容スリッページ
許容スリッページをポイントで指定します。

決済マークの色
EAでの取引でチャート上に自動的に表示される決済マークの色を指定します。

CloseOrder()関数で正常に決済されたら、注文番号格納用の変数の値を0にリセットします。決済注文に失敗したら、エラー出力するようにします。

保有ポジションを確認するセクションで宣言した変数ticket_buyは、買いポジションの注文番号を格納することで、ポジションの有無を判定するのにも使用できます。また、lots_buyにロット数を格納しておくことで、決済時にポジションを選択することなくOrderClose()関数を実行することができます。

OrderClose()関数にパラメーターのLotsでロット数を指定すると、ポジション保有中にパラメーターのLotsを変更した場合に部分決済するなど想定外の取引になる可能性があります。

エントリー注文処理

エントリー注文処理のセクションでは、次のコードのように最初のif()文を保有ポジション無し・エントリーしたローソク足ではないという条件にします。それを満たした上で、エントリーシグナルが出ている場合に、OrderSend()関数でエントリー注文をします。

   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.");
      }
   }
OrderSend()関数について

OrderSend()関数の()括弧内は次のように指定します。OrderSend()関数の実行に成功したらその注文番号が返り、失敗したら-1が返ります。

OrderSend(通貨ペア, 注文の種類, ロット数, 注文価格, 許容スリッページ, 逆指値決済価格, 指値決済価格, コメント, マジックナンバー, 有効期限, エントリーマークの色)

通貨ペア
通貨ペアを文字列で指定します。稼働チャートの通貨ペアを指定する場合は、Symbol()とします。

注文の種類
注文の種類は、次の6種類から選んで指定します。

買い成行き注文 OP_BUY
売り成行き注文 OP_SELL
買い指値注文 OP_BUYLIMIT
売り指値注文 OP_SELLLIMIT
買い逆指値注文 OP_BUYSTOP
売り逆指値注文 OP_SELLSTOP

ロット数
取引数量(ロットサイズ)を指定します。

注文価格
エントリーする価格を指定します。成行き注文の場合、買い注文はAsk、売り注文はBidを指定します。

許容スリッページ
許容スリッページをポイントで指定します。

逆指値決済価格
ストップロス(SL)の価格を指定します。0を指定するとSL無しになります。

指値決済価格
テイクプロフィット(TP)の価格を指定します。0を指定するとTP無しになります。

コメント
注文のコメントを指定します。NULLを指定するとコメント無しになります。

マジックナンバー
注文のマジックナンバーを指定します。ちなみに手動取引のマジックナンバーは0です。

有効期限
指値・逆指値注文の場合、有効期限を指定できます。0を指定すると無期限になります。

エントリーマークの色
EAでの取引でチャート上に自動的に表示されるエントリーマークの色を指定します。

OrderSend()関数で正常に注文できたら、グローバル変数entry_barに現在のローソク足の本数を代入しておきます。注文に失敗したら、エラー出力するようにしています。

テスターでEA動作をチェック

コード入力が終わったらコンパイルボタンでコンパイルします。エラーなくコンパイルできたらテスターのビジュアルモードでEA動作を確認しましょう。

ビジュアルモードで表示されるチャートには、インジケーターを表示させることができるので、今回の場合でいうと単純移動平均線(期間20)のものを表示させて確認すると良いです。
移動平均線は、ナビゲーターウィンドウのインディケータ→トレンド→Moving Averageです。

あとがき

今回は初めてのEA作成される方に向けたシンプルなEAで解説してきましたが、いかがでしたか?
わからないところがあったらコメントくださいね^^

次回は、今回のEAをさらにカスタマイズする方法を紹介します。お楽しみに!