【超入門】MQL5 EA講座 第132回「待機注文用EA開発テンプレートを使って実際にEAを作る」【EAの作り方】

MQL5でEA作ろう講座
スポンサーリンク
スポンサーリンク

前回のおさらい

前回待機注文用EA開発テンプレートを作成する過程を解説しました。

基本的な記述はEA開発用テンプレートのものを残しつつ、新たなインクルードファイルである

「OriginalCpending.mqh」ファイルを追加し、そのインスタンスを宣言しました。

そして、グローバル領域には2つのグローバル変数を追加しました。

input変数OnInit関数内には特に追加・修正する箇所はないのでEA開発用テンプレートの記述がそのまま残っています。

OnTick関数内の記述においては、注文条件を制御しているif文内の記述を待機注文用に修正した上で、対応する{}内の記述も成行注文の実行関数から、待機注文の実行関数に変更しました。

※それぞれのプロセスにおける詳細は前回記事の

・「EA開発用テンプレートから新規ファイルを作成する

・「インクルードファイルに「OriginalCpending.mqh」ファイルを追加し、インスタンスを宣言する

・「グローバル変数を追加する

・「OnTick関数内の注文条件箇所の記述を変更する

セクションをそれぞれご覧ください。

待機注文用EA開発テンプレートの全体記述については↓の記事から確認ができます。

今回は前回作った待機注文用EA開発テンプレートを利用して、実際にEAを作る過程を解説していきたいと思います。

今回作るEAの仕様

今回作るEAの仕様は以下の通りです。

1:トレードタイマーを必ず使い、指定したトレード許可時間(=トレードタイマーONの時)のみに待機注文を出す

2:指定したトレード許可時間以外の時間(トレードタイマーOFFの時)になったら、ポジションは全て決済し、有効化していない待機注文も削除する。

3:指定した期間(input変数で任意に設定する)における最高値と最安値を取得し、買いの場合、最高値を超えたらエントリーするよう待機注文を設定する。売りの場合は、最安値を超えたらエントリーするよう待機注文を設定する。

4:買いのストップロスは、指定した期間の最安値、テイクプロフィットはinput変数で任意に設定した値とする。

5:売りのストップロスは、指定した期間の最高値、テイクプロフィットはinput変数で任意に設定した値とする。

6:最高値と最安値の差分を求め、その値を資金管理モードONの時は、その差分値を元にロット数を計算する。

上記の仕様に従い、コードを記述していきます。

ブレイクアウト戦略EA作成のロードマップ

ブレイクアウト戦略EAの作成は以下の手順を踏んで行います。

「input変数」groupに追加・削除処理をおこなう

確定足モード・トレードタイマーモードに関する記述を削除・修正する

トレード許可時間以外の時間(トレードタイマーOFFの時)に関する記述を行う

注文関連の記述を書き換える

トレーリングストップ・ブレイクイーブンに関する記述を削除する

1つ1つ順を追って見ていきましょう

「input変数」groupに追加・削除処理をおこなう

まずは「input変数groupに追加・削除処理をおこないます。

待機注文用EA開発テンプレートでは「input変数groupは以下のようになっていますが↓

//+------------------------------------------------------------------+
//| Input変数                                                         |
//+------------------------------------------------------------------+
input group "基本取引設定"  // 基本取引設定のグループ化
input ulong Slippage = 3;              // スリッページ設定
input ulong MagicNumber = 123;         // EA識別番号
input bool TradeOnNewBar = true;       // 新しいバーでの取引を行うかどうか

input group "資金管理"                  // 資金管理設定のグループ化
input bool UseMoneyManagement = false;  // マネーマネジメントを使用するかどうか
input double RiskPercent = 2;          // リスク許容度(%)
input double FixedVolume = 0.1;        // 固定取引量

input group "ストップロスとテイクプロフィット"  // ストップロスとテイクプロフィット設定のグループ化
input int StopLoss = 0;                // ストップロスの設定値
input int TakeProfit = 0;              // テイクプロフィットの設定値

input group "トレーリングストップ"            // トレーリングストップ設定のグループ化
input bool UseTrailingStop = false;    // トレーリングストップを使用するかどうか
input int TrailingStop = 500;            // トレーリングストップの距離
input int MinimumProfit = 200;           // トレーリングを開始する最小利益
input int Step = 20;                    // トレーリングのステップ

input group "ブレイクイーブン"              // ブレイクイーブン設定のグループ化
input bool UseBreakEven = false;       // ブレイクイーブンを使用するかどうか
input int BreakEvenProfit = 300;         // ブレイクイーブンに設定する利益
input int LockProfit = 0;              // 利益を確保するためのロック量

input group "トレードタイマー"              // トレードタイマー設定のグループ化
input bool UseTimer = false;           // トレードタイマーを使用するかどうか
input int StartHour = 0;               // トレード開始時間(時)
input int StartMinute = 0;             // トレード開始時間(分)
input int EndHour = 0;                 // トレード終了時間(時)
input int EndMinute = 0;               // トレード終了時間(分)
input bool UseLocalTime = false;       //ローカル時間を使うかどうか

これを以下のように変更します。

//+------------------------------------------------------------------+
//| Input変数                                                         |
//+------------------------------------------------------------------+
input group "基本取引設定"  // 基本取引設定のグループ化
input ulong Slippage = 3;              // スリッページ設定
input ulong MagicNumber = 123;         // EA識別番号
//input bool TradeOnNewBar = true;       // 新しいバーでの取引を行うかどうか

input group "資金管理"                  // 資金管理設定のグループ化
input bool UseMoneyManagement = false;  // マネーマネジメントを使用するかどうか
input double RiskPercent = 2;          // リスク許容度(%)
input double FixedVolume = 0.1;        // 固定取引量

input group "ストップロスとテイクプロフィット"  // ストップロスとテイクプロフィット設定のグループ化
//input int StopLoss = 0;                // ストップロスの設定値
input int TakeProfit = 0;              // テイクプロフィットの設定値
input int HighLowBars = 8; // 高値と安値を計算するためのバー数

input group "トレードタイマー"              // トレードタイマー設定のグループ化
//input bool UseTimer = false;           // トレードタイマーを使用するかどうか
input int StartHour = 0;               // トレード開始時間(時)
input int StartMinute = 0;             // トレード開始時間(分)
input int EndHour = 0;                 // トレード終了時間(時)
input int EndMinute = 0;               // トレード終了時間(分)
input bool UseLocalTime = false;       //ローカル時間を使うかどうか

input変数groupの変更点は以下の通りです。

変更点1:確定足モードのフラグである「TradeOnNewBar」を削除(コメントアウト)

今回作るEAでは確定足モードに基づいた処理は行いません。

従って、”基本取引設定”group内にある、確定足モードのフラグとして使っていた「TradeOnNewBar」は削除しました(変更点を際立たせる為、今回はコメントアウトで消しています)。

変更点2:”ストップロスとテイクプロフィット”group内の「StopLoss」を削除し、新たに「HighLowBars」を追加

今回のEAではストップロスの設定に、再高値と最安値の差分値を用います。

従って、任意にストップロス値を設定する役割だった「StopLoss」は削除(コメントアウト)しました。

代わりに”ストップロスとテイクプロフィット”group内に「HighLowBars」というint型input変数を追加しました。

「HighLowBars」は最高値と最安値を計算する為の期間を設定する為に利用します

変更点3:”トレードタイマー”group から「UseTimer」を削除(コメントアウト)

今回作るEAには指定時間になったら、保有ポジションを決済し、有効化していない待機注文を削除する回路を埋め込みます。

つまりトレードタイマーはモードとして切り替えたりせず、「常時」使われる事になります。

従って、トレードタイマーモードの切り替えフラグとして使っていた「UseTimer」は削除(コメントアウト)しました。

※トレード開始時間と終了時間は任意に指定するので、他の”トレードタイマーgroup にあるinput変数は引き続き残しておきます。

変更点4:”トレーリングストップ”groupと”ブレイクイーブン”groupのinput変数を全て削除

今回作るEAにおいては、トレーリングストップブレイクイーブンストップは使いません。

従って、”トレーリングストップgroupと”ブレイクイーブンストップgroupinput変数を全て削除しました。

input変数groupの変更・修正は以上になります。

グローバル変数OnInit関数については待機注文用EA開発テンプレートの記述から変更点はありません。続いてはOnTick関数内の記述に移ります。

確定足モード・トレードタイマーモードに関する記述を削除・修正する

待機注文用EA開発テンプレートの記述では、OnTick関数の冒頭は以下のようになっていました。

void OnTick()
  {
// 新しいバーがあるかどうかの初期状態をtrueと仮定し、バーシフトを0に設定
   bool newBar = true;
   int barShift = 0;

// 新しいバーでの取引を行う場合の処理
   if(TradeOnNewBar == true)
     {
      // 現在のシンボルと期間で新しいバーが始まったかどうかをチェック
      newBar = NewBar.CheckNewBar(_Symbol,_Period);

      // 新しいバーが確認された場合、バーシフトを1に設定
      barShift = 1;
     }

// トレードタイマーの設定
   bool timerOn = true;
// トレードタイマーを使用する場合の処理
   if(UseTimer == true)
     {
      // 指定された時間内で取引が許可されているかどうかをチェック
      timerOn = Session.DailySessionTimer(StartHour, StartMinute, EndHour, EndMinute, UseLocalTime);
     }

//価格情報をアップデートする
   Price.Update(_Symbol,_Period);

この部分を今回作るEAでは以下のように変更します。

// 指定された時間内で取引が許可されているかどうかをチェック
   bool timerOn = Session.DailySessionTimer(StartHour, StartMinute, EndHour, EndMinute, UseLocalTime);

・・・たった1行になってしまいました。

この1行のみ残して他の記述を削除した理由についてですが、まずは以下の箇所↓

/ 新しいバーがあるかどうかの初期状態をtrueと仮定し、バーシフトを0に設定
   bool newBar = true;
   int barShift = 0;

// 新しいバーでの取引を行う場合の処理
   if(TradeOnNewBar == true)
     {
      // 現在のシンボルと期間で新しいバーが始まったかどうかをチェック
      newBar = NewBar.CheckNewBar(_Symbol,_Period);

      // 新しいバーが確認された場合、バーシフトを1に設定
      barShift = 1;
     }

確定足モードに関する記述です。

変更点1:確定足モードのフラグである「TradeOnNewBar」を削除(コメントアウト)」セクションでも書いた通り、今回はそもそも確定足モードを使わないので削除します。

トレードタイマーの切り替えはDailySessionTimer関数戻り値によってのみ行われます。

DailySessionTimer関数同じ時間帯に取引できるようにする処理を担う、CTradeSessionクラスメンバ関数です。詳細は講座記事第120回の「DailySessionTimer関数について」セクションをご覧ください。

その下にあった記述についてですが↓

// トレードタイマーの設定
   bool timerOn = true;
// トレードタイマーを使用する場合の処理
   if(UseTimer == true)
     {
      // 指定された時間内で取引が許可されているかどうかをチェック
      timerOn = Session.DailySessionTimer(StartHour, StartMinute, EndHour, EndMinute, UseLocalTime);
     }

//価格情報をアップデートする
   Price.Update(_Symbol,_Period);

これらの記述はトレードタイマー設定に関する記述です。

これも当記事の「変更点3:”トレードタイマー”group から「UseTimer」を削除(コメントアウト)」セクションにて書いた事ですが、今回はそもそもトレードタイマーモードの切り替えを行いません。

従って、トレードタイマー設定に関する記述を全て削除しました。

Update関数は、バーデータをコピーする役割を担うOriginalCBarsクラスメンバ関数ですが、注文条件にも発注自体にも利用しないので、今回はこちらも削除しています。

※「特定期間の最高値と最安値」情報については、それ専用のHighestHigh関数LowestLow関数を用いて取得します。この件については後程解説します。

トレード許可時間以外の時間(トレードタイマーOFFの時)に関する記述を行う

続いて、トレード許可時間以外の時間(トレードタイマーOFFの時)に関する記述を行います。

この記述は待機注文用EA開発テンプレートにはなかったものです。

DailySessionTimer関数の下に以下の記述を追加します。

// タイマーがオフの場合
   if(timerOn == false)
     {
      // 現在のポジションの総数を取得
      int totalPos = Positions.GetTotalPosCount(MagicNumber);

      // ポジションが1つ以上ある場合
      if(totalPos > 0)
        {
         // ポジション番号を格納する配列を宣言
         ulong posNum[];

         // ポジションの番号を取得
         Positions.GetTotalPosNum(MagicNumber, posNum);

         // すべてのポジションを閉じるループ
         for(int i = 0; i < totalPos; i++)
           {
            // 指定されたポジションを閉じる
            Trade.ClosePosition(posNum[i]);
           }
        }//if(totalPos > 0)

      // ペンディング注文の総数を取得
      int totalOrder = Pending.TotalPendingNum(_Symbol);

      // ペンディング注文が1つ以上ある場合
      if(totalOrder > 0)
        {
         // ペンディング注文のチケット番号を格納する配列を宣言
         ulong orderNum[];

         // ペンディング注文のチケット番号を取得
         Pending.GetOrderTickets(_Symbol, orderNum);

         // すべてのペンディング注文を削除するループ
         for(int i = 0; i < totalOrder; i++)
           {
            // 指定されたペンディング注文を削除
            Trade.DeletePending(orderNum[i]);
           }
        }// if(totalOrder > 0)

      // ペンディング注文フラグをリセット
      glBuyPlaced = false;
      glSellPlaced = false;

     }//if(timerOn == false)

この記述は以下のようなことをやっています。

トレード終了時刻になったので、保有ポジションを決済する

// 現在のポジションの総数を取得
      int totalPos = Positions.GetTotalPosCount(MagicNumber);

今回作るEAの仕様」セクションで書いたように今回のEAはトレード終了時間になったらポジションを全て決済します。まずはGetTotalPosCount関数を用いてポジション数の確認をおこないます。

 // ポジションが1つ以上ある場合
      if(totalPos > 0)
        {
         // ポジション番号を格納する配列を宣言
         ulong posNum[];

         // ポジションの番号を取得
         Positions.GetTotalPosNum(MagicNumber, posNum);

ポジションが1つ以上ある場合、配列「posNum」を宣言し、GetTotalPosNum関数を用いて配列「posNum」にポジション番号を格納します。

 // すべてのポジションを閉じるループ
         for(int i = 0; i < totalPos; i++)
           {
            // 指定されたポジションを閉じる
            Trade.ClosePosition(posNum[i]);
           }
        }//if(totalPos > 0)

ポジション数が格納されている「totalPos」の数だけfor文で繰り返し処理を行い、ClosePosition関数を用いてポジションの決済をします。

ClosePosition関数引数にはポジション番号が記述されます。配列「posNum」のi番目がポジション番号になります。

有効化していない待機注文があれば削除する

有効化していない待機注文(=トレード時間中に条件の価格帯に達しなかった注文)の削除処理をおこないます。これも「今回作るEAの仕様」セクションで定めた処理です。

 // ペンディング注文の総数を取得
      int totalOrder = Pending.TotalPendingNum(_Symbol);

待機注文削除の為にまずは待機注文の数を取得します。待機注文の取得にはTotalPendingNum関数を用います。待機注文変数「totalOrder」に代入します。

 // ペンディング注文が1つ以上ある場合
      if(totalOrder > 0)
        {
         // ペンディング注文のオーダー番号を格納する配列を宣言
         ulong orderNum[];

         // ペンディング注文のオーダー番号を取得
         Pending.GetOrderTickets(_Symbol, orderNum);

待機注文がある場合、配列「orderNum」を宣言しオーダー番号をこの配列に格納していきます。

オーダー番号の取得にはGetOrderTickets関数を用います。

 // すべてのペンディング注文を削除するループ
         for(int i = 0; i < totalOrder; i++)
           {
            // 指定されたペンディング注文を削除
            Trade.DeletePending(orderNum[i]);
           }
        }// if(totalOrder > 0)

待機注文数、すなわち「totalOrder」分だけfor文で繰り返し処理をおこない、待機注文の削除を行います。待機注文の削除はDeletePending関数を使います。DeletePending関数引数にはオーダー番号である、配列「orderNum」のi番目を記述します。

待機注文のフラグをfalseにリセットする

保有ポジションを決済し、待機注文も削除し終わったら、最後に待機注文フラグをリセットします。

  // ペンディング注文フラグをリセット
      glBuyPlaced = false;
      glSellPlaced = false;

     }//if(timerOn == false)

「glBuyPlaced 」「glSellPlaced 」を falseにすることによって、再び取引開始時間が来た時に待機注文が出せるようになります。

取引終了時間になった時の記述は以上になります。

注文関連の記述を書き換える

続いて注文関連の記述を書き換えていきます。

待機注文用EA開発テンプレートの記述から変更している点について解説していきます。

変更点1:確定足モードを前提としたif文の条件箇所を削除

まず冒頭のif文待機注文用EA開発テンプレートでは以下のようになっていますが↓

// 注文関連の記述
// 新しいバーかつトレードタイマーが許可している時のみ注文処理を行う
   if(newBar == true && timerOn == true)
     {

確定足モードを採用しなくなったことに伴い、以下のように変わっています。

// 注文関連の記述
//許可している時のみ注文処理を行う
   if(timerOn == true)

足が確定しているかどうかに関わらず、timerOn == trueの時、すなわち、事前に指定した時間帯のみトレードを行うように変更しました。

変更点2:ロット調整の箇所に変更・追加の記述をおこなう

ロット調整の記述は待機注文用EA開発テンプレートでは以下のようになっていますが↓

// ロット調整
      double tradeSize;
      //資金管理モードONなら設定したリスクに応じたロットを算出
      if(UseMoneyManagement == true)
         tradeSize = MoneyRiskManagement(_Symbol,FixedVolume,RiskPercent,StopLoss);

      //固定ロットを指定
      else
         tradeSize = VerifyVolume(_Symbol,FixedVolume);

ストップロスに最高値や最安値を採用し、また資金管理モードがOnの時は、最高値と最安値の差分をロット計算に用いると仕様に決めた事を受けて以下のようになっています。

 // 指定されたバー数から最高値と最安値を取得
		double hHigh = HighestHigh(_Symbol, _Period, HighLowBars);
		double lLow = LowestLow(_Symbol, _Period, HighLowBars);
		
		// 価格差を計算
		double diff = (hHigh - lLow) / _Point;
		
      // ロット調整
      double tradeSize;
      //資金管理モードONなら設定したリスクに応じたロットを算出
      if(UseMoneyManagement == true)
         tradeSize = MoneyRiskManagement(_Symbol,FixedVolume,RiskPercent,(int)diff);

      //固定ロットを指定
      else
         tradeSize = VerifyVolume(_Symbol,FixedVolume);

指定された期間の最高値を取得するにはHighestHigh関数を用います。

指定された期間の最安値を取得するにはLowestLow関数を用います。

HighestHigh関数LowestLow関数の詳細については、講座記事第106回の「HighestHigh関数について」「LowestLow関数について」セクションをそれぞれご覧ください。

取得した最高値、最安値をローカル変数「hHigh」「lLow」にそれぞれ代入し、引き算を行います。

その計算結果を定義済み変数_Point」で割り算をすると、最高値と最安値の差分値が求まります。

ローカル変数「diff」にその値を代入し、MoneyRiskManagement関数の第3引数に記述すれば、資金管理モードOnの時に最高値と最安値の差分値に基づいたロット調整が行われます。

買い注文箇所の記述に変更を行う

次は買い注文箇所の記述に変更を行います。

待機注文用EA開発テンプレートの記述では以下のようになっています。

 // 買い注文について
      if(Positions.GetBuyPosCount(MagicNumber) == 0 // 買いポジションがない場合
         &&
         Pending.BuyLimitNum(_Symbol) == 0 // 買いリミット注文がない場合
         &&
         Pending.BuyStopNum(_Symbol) == 0 // 買いストップ注文がない場合
         &&
         Pending.BuyStopLimitNum(_Symbol) == 0 // 買いストップリミット注文がない場合
        ) // 買いポジションがなく、買い待機注文もなければ
        {
         double orderPrice = 0; // 注文価格を格納する変数
         orderPrice =ModifyUpperStopLevel(_Symbol, orderPrice); // ストップロスの設定が有効かチェック
         double buyStop = CalBuySL(_Symbol, StopLoss, orderPrice); // ストップロス計算
         double buyProfit = CalBuyTP(_Symbol, TakeProfit, orderPrice); // テイクプロフィット計算

         glBuyPlaced=Trade.BuyStop(_Symbol, tradeSize, orderPrice, buyStop, buyProfit); // 買いストップ注文を配置

         

        }//買い注文記述の終わり

この記述を以下のように変更します。

// 買い注文について
      if(
         Pending.BuyStopNum(_Symbol) == 0 // 買いストップ注文がない場合
         &&
         glBuyPlaced == false//フラグがfalseの時
        
        ) 
        {
         double orderPrice = hHigh; // 注文価格を最高値に設定
         orderPrice =ModifyUpperStopLevel(_Symbol, orderPrice); // ストップロスの設定が有効かチェック
         double buyStop =lLow; // ストップロスを最安値に設定 CalBuySL(_Symbol, StopLoss, orderPrice); // ストップロス計算
         double buyProfit = CalBuyTP(_Symbol, TakeProfit, orderPrice); // テイクプロフィット計算

         glBuyPlaced=Trade.BuyStop(_Symbol, tradeSize, orderPrice, buyStop, buyProfit); // 買いストップ注文を配置



        }//買い注文記述の終わり

今回のEAは最高値を超えたらエントリーするよう待機注文を設定します。

したがって複数ある待機注文の発注関数のうち、使うのはBuyStop関数のみです。

他の待機注文は生じようがないので、Pending.BuyStopNum(_Symbol) == 0以外の記述は削除しました。

論理積&&で繋いだglBuyPlaced == falseの記述ですが、「glBuyPlaced 」は取引終了時間になり、ポジションクローズと待機注文削除が完了した後でfalseになる仕様です。

※詳細は当記事の「待機注文のフラグをfalseにリセットする」セクションをご覧ください。

glBuyPlaced == falseという事は、ポジションクローズと待機注文削除がうまくいき、ポジションも待機注文も0になっている事を意味します。

待機注文の最終的な価格を格納するローカル変数「orderPrice」には指定期間の最高値が格納されている「hHigh」を代入します。

また、ストップロス値を格納する「buyStop」には指定期間の最安値が格納されている「lLow」を代入します。

ストップレベルのチェックやテイクプロフィットの設定、BuyStop関数による待機注文の発注などは基本的に記述の変更はありません。

売り注文箇所の記述に変更を行う

同様に売り注文箇所の記述も変更を行います。

待機注文用EA開発テンプレートの記述では以下のようになっています。

  // 売り注文について
      if(Positions.GetSellPosCount(MagicNumber) == 0 // 売りポジションがない場合
         &&
         Pending.SellLimitNum(_Symbol) == 0 // 売りリミット注文がない場合
         &&
         Pending.SellStopNum(_Symbol) == 0 // 売りストップ注文がない場合
         &&
         Pending.SellStopLimitNum(_Symbol) == 0 // 売りストップリミット注文がない場合
        ) // 売りポジションがなく、売り待機注文もなければ
        {
         double orderPrice = 0; // 注文価格を格納する変数
         orderPrice =ModifyLowerStopLevel(_Symbol, orderPrice); // ストップロスの設定が有効かチェック
         double sellStop = CalSellSL(_Symbol,StopLoss,orderPrice);// ストップロス計算
         double sellProfit = CalSellTP(_Symbol,TakeProfit,orderPrice);// テイクプロフィット計算
         glSellPlaced = Trade.SellStop(_Symbol, tradeSize, orderPrice, sellStop, sellProfit); // 売りストップ注文を配置

         
        }//売り注文の記述終わり

     }// 注文関連の記述終わり

この記述を以下のように変更します。

// 売り注文について
      if(
         Pending.SellStopNum(_Symbol) == 0 // 売りストップ注文がない場合
         &&
         glSellPlaced == false//フラグがfalseの時
       
        ) 
        {
         double orderPrice = lLow; // 注文価格を最安値に設定
         orderPrice =ModifyLowerStopLevel(_Symbol, orderPrice); // ストップロスの設定が有効かチェック
         double sellStop = hHigh; // ストップロスを最高値に設定 CalSellSL(_Symbol,StopLoss,orderPrice);// ストップロス計算
         double sellProfit = CalSellTP(_Symbol,TakeProfit,orderPrice);// テイクプロフィット計算
         glSellPlaced = Trade.SellStop(_Symbol, tradeSize, orderPrice, sellStop, sellProfit); // 売りストップ注文を配置


        }//売り注文の記述終わり

     }// 注文関連の記述終わり

売りの場合、は最安値を下回ったらエントリーするよう待機注文を設定します。

したがって複数ある待機注文の発注関数のうち、使うのはSellStop関数のみです。他の待機注文は生じようがないので、Pending.SellStopNum(_Symbol) == 0以外の記述は削除しました。

論理積&&で繋いだglSellPlaced == falseの状況はポジションクローズと待機注文削除がうまくいき、ポジションも待機注文も0になっている事を意味します。

待機注文の最終的な価格を格納するローカル変数「orderPrice」には指定期間の最安値が格納されている「lLow」を代入します。

また、ストップロス値を格納する「sellStop」には指定期間の最高値が格納されている「hHigh」を代入します。

ストップレベルのチェックやテイクプロフィットの設定、SellStop関数による待機注文の発注などは基本的に記述の変更はありません。

トレーリングストップ・ブレイクイーブンに関する記述を削除する

待機注文用EA開発テンプレートには発注記述の後、トレーリングストップブレイクイーブンストップに関する以下の記述がありますが↓

// ポジション番号を取得
   ulong tickets[]; // チケット番号を格納するための配列
   Positions.GetTotalPosNum(MagicNumber, tickets); // 全ポジションのポジション番号を取得
   int numTickets = ArraySize(tickets); // 取得したポジションの数を格納

// トレーリングストップ処理
   if(UseTrailingStop == true && numTickets > 0) // トレーリングストップが有効かつオープンポジションが存在する場合
     {
      for(int i = 0; i < numTickets; i++) // オープンポジションの数だけループ
        {
         // 各ポジションに対してトレーリングストップ処理を適用
         Trailing.TrailingStop(tickets[i], TrailingStop, MinimumProfit, Step);
        }
     }//トレーリングストップ記述の終わり

// ブレイクイーブン処理 
   if(UseBreakEven == true && numTickets > 0) // ブレイクイーブンが有効かつオープンポジションが存在する場合
     {
      for(int i = 0; i < numTickets; i++) // オープンポジションの数だけループ
        {
         // 各ポジションに対してブレイクイーブン処理を適用
         Trailing.BreakEven(tickets[i], BreakEvenProfit, LockProfit);
        }
     } // ブレイクイーブン処理の終わり

今回はトレーリングストップブレイクイーブンストップは用いないとEAの仕様で決めているので、上記の記述は削除します。

EAの記述は以上になります。

まとめ

今回は前回作った待機注文用EA開発テンプレートを使って、待機注文と時間指定機能を交えたブレイクアウト戦略のEAを作る過程を解説しました。

今回作ったEAの全体記述は以下の通りです。

//+------------------------------------------------------------------+
//|                                    Break Out EA Example          |
//|                                                MQL5ssei          |
//|                                  https://mqlinvestmentlab.com/   |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link      "https://mqlinvestmentlab.com/"


// 注文関連
#include <OriginalTrade.mqh> // 注文関連機能を提供するファイルをインクルード
OriginalCTrade Trade; // 取引のための主要インスタンス
OriginalCPositions Positions; // ポジション管理のためのインスタンス

// 価格情報
#include <OriginalPrice.mqh> // 価格データ取得のためのファイルをインクルード
OriginalCBars Price; // 価格情報を管理するインスタンス

// 資金管理
#include <OriginalMoneyManagement.mqh> // 資金管理機能を提供するファイルをインクルード

// トレーリングストップ
#include <OriginalTrailingStop.mqh> // トレーリングストップ機能を提供するファイルをインクルード
OriginalCTrailing Trailing; // トレーリングストップを管理するインスタンス

// インジケータ
#include <OriginalIndicators.mqh> // インジケータを扱うためのファイルをインクルード

// タイマー
#include <OriginalTimer.mqh> // タイマー機能を提供するファイルをインクルード
CTradeSession Session; // トレーディングセッションを管理するインスタンス
OriginalCNewBar NewBar; // 新しいバーが生成されたかを検出するインスタンス

// ペンディング注文関連のクラスをインクルード
#include <OriginalCpending.mqh>
OriginalCpending Pending; //ペンディング注文関連の情報を扱うインスタンス


//+------------------------------------------------------------------+
//| Input変数                                                         |
//+------------------------------------------------------------------+
input group "基本取引設定"  // 基本取引設定のグループ化
input ulong Slippage = 3;              // スリッページ設定
input ulong MagicNumber = 123;         // EA識別番号
//input bool TradeOnNewBar = true;       // 新しいバーでの取引を行うかどうか

input group "資金管理"                  // 資金管理設定のグループ化
input bool UseMoneyManagement = false;  // マネーマネジメントを使用するかどうか
input double RiskPercent = 2;          // リスク許容度(%)
input double FixedVolume = 0.1;        // 固定取引量

input group "ストップロスとテイクプロフィット"  // ストップロスとテイクプロフィット設定のグループ化
//input int StopLoss = 0;                // ストップロスの設定値
input int TakeProfit = 0;              // テイクプロフィットの設定値
input int HighLowBars = 8; // 高値と安値を計算するためのバー数

input group "トレードタイマー"              // トレードタイマー設定のグループ化
//input bool UseTimer = false;           // トレードタイマーを使用するかどうか
input int StartHour = 0;               // トレード開始時間(時)
input int StartMinute = 0;             // トレード開始時間(分)
input int EndHour = 0;                 // トレード終了時間(時)
input int EndMinute = 0;               // トレード終了時間(分)
input bool UseLocalTime = false;       //ローカル時間を使うかどうか

//+------------------------------------------------------------------+
//| グローバル変数                                                       |
//+------------------------------------------------------------------+

ulong glBuyTicket, glSellTicket;//ポジション番号を格納する変数
bool glBuyPlaced, glSellPlaced; // 買い注文と売り注文が配置されたかどうかを示すフラグ

//+------------------------------------------------------------------+
//| OnInit関数                                                        |
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
// フィルポリシーを取得する
   ENUM_ORDER_TYPE_FILLING filltype = FillPolicy();

// EAのマジックナンバーを設定する
   Trade.SetMagicNumber(MagicNumber);

// 注文実行時の許容スリッページを設定する
   Trade.SetDeviation(Slippage);

// 取得したフィルポリシーを設定する
   Trade.SetFillType(filltype);

// 初期化が完了したことを示す(0 = 成功)
   return(0);
  }

//+------------------------------------------------------------------+
//| OnTick関数                                                        |
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   

// 指定された時間内で取引が許可されているかどうかをチェック
   bool timerOn = Session.DailySessionTimer(StartHour, StartMinute, EndHour, EndMinute, UseLocalTime);

// タイマーがオフの場合
   if(timerOn == false)
     {
      // 現在のポジションの総数を取得
      int totalPos = Positions.GetTotalPosCount(MagicNumber);

      // ポジションが1つ以上ある場合
      if(totalPos > 0)
        {
         // ポジション番号を格納する配列を宣言
         ulong posNum[];

         // ポジションの番号を取得
         Positions.GetTotalPosNum(MagicNumber, posNum);

         // すべてのポジションを閉じるループ
         for(int i = 0; i < totalPos; i++)
           {
            // 指定されたポジションを閉じる
            Trade.ClosePosition(posNum[i]);
           }
        }//if(totalPos > 0)

      // ペンディング注文の総数を取得
      int totalOrder = Pending.TotalPendingNum(_Symbol);

      // ペンディング注文が1つ以上ある場合
      if(totalOrder > 0)
        {
         // ペンディング注文のチケット番号を格納する配列を宣言
         ulong orderNum[];

         // ペンディング注文のチケット番号を取得
         Pending.GetOrderTickets(_Symbol, orderNum);

         // すべてのペンディング注文を削除するループ
         for(int i = 0; i < totalOrder; i++)
           {
            // 指定されたペンディング注文を削除
            Trade.DeletePending(orderNum[i]);
           }
        }// if(totalOrder > 0)

      // ペンディング注文フラグをリセット
      glBuyPlaced = false;
      glSellPlaced = false;

     }//if(timerOn == false)


// 注文関連の記述
//許可している時のみ注文処理を行う
   if(timerOn == true)
     {
     // 指定されたバー数から最高値と最安値を取得
		double hHigh = HighestHigh(_Symbol, _Period, HighLowBars);
		double lLow = LowestLow(_Symbol, _Period, HighLowBars);
		
		// 価格差を計算
		double diff = (hHigh - lLow) / _Point;
		
      // ロット調整
      double tradeSize;
      //資金管理モードONなら設定したリスクに応じたロットを算出
      if(UseMoneyManagement == true)
         tradeSize = MoneyRiskManagement(_Symbol,FixedVolume,RiskPercent,(int)diff);

      //固定ロットを指定
      else
         tradeSize = VerifyVolume(_Symbol,FixedVolume);

      // 買い注文について
      if(
         Pending.BuyStopNum(_Symbol) == 0 // 買いストップ注文がない場合
         &&
         glBuyPlaced == false//フラグがfalseの時
        
        ) 
        {
         double orderPrice = hHigh; // 注文価格を最高値に設定
         orderPrice =ModifyUpperStopLevel(_Symbol, orderPrice); // ストップロスの設定が有効かチェック
         double buyStop =lLow; // ストップロスを最安値に設定 
         double buyProfit = CalBuyTP(_Symbol, TakeProfit, orderPrice); // テイクプロフィット計算

         glBuyPlaced=Trade.BuyStop(_Symbol, tradeSize, orderPrice, buyStop, buyProfit); // 買いストップ注文を配置



        }//買い注文記述の終わり

      // 売り注文について
      if(
         Pending.SellStopNum(_Symbol) == 0 // 売りストップ注文がない場合
         &&
         glSellPlaced == false//フラグがfalseの時
       
        ) 
        {
         double orderPrice = lLow; // 注文価格を最安値に設定
         orderPrice =ModifyLowerStopLevel(_Symbol, orderPrice); // ストップロスの設定が有効かチェック
         double sellStop = hHigh; // ストップロスを最高値に設定 
         double sellProfit = CalSellTP(_Symbol,TakeProfit,orderPrice);// テイクプロフィット計算
         glSellPlaced = Trade.SellStop(_Symbol, tradeSize, orderPrice, sellStop, sellProfit); // 売りストップ注文を配置


        }//売り注文の記述終わり

     }// 注文関連の記述終わり
/*
// ポジション番号を取得
   ulong tickets[]; // チケット番号を格納するための配列
   Positions.GetTotalPosNum(MagicNumber, tickets); // 全ポジションのポジション番号を取得
   int numTickets = ArraySize(tickets); // 取得したポジションの数を格納

// トレーリングストップ処理
   if(UseTrailingStop == true && numTickets > 0) // トレーリングストップが有効かつオープンポジションが存在する場合
     {
      for(int i = 0; i < numTickets; i++) // オープンポジションの数だけループ
        {
         // 各ポジションに対してトレーリングストップ処理を適用
         Trailing.TrailingStop(tickets[i], TrailingStop, MinimumProfit, Step);
        }
     }//トレーリングストップ記述の終わり

// ブレイクイーブン処理 
   if(UseBreakEven == true && numTickets > 0) // ブレイクイーブンが有効かつオープンポジションが存在する場合
     {
      for(int i = 0; i < numTickets; i++) // オープンポジションの数だけループ
        {
         // 各ポジションに対してブレイクイーブン処理を適用
         Trailing.BreakEven(tickets[i], BreakEvenProfit, LockProfit);
        }
     } // ブレイクイーブン処理の終わり

*/

  }//全体記述の終わり

//+------------------------------------------------------------------+

講座記事第129回第130回では通常のEA開発用テンプレートを使ったEAの作り方を学びました。

従って、これで皆さんは成行注文でも待機注文でも、対応できるEA作りのスキルを手に入れたことになります。

【中級実際にEAを作ろう編】ではクラスインクルードファイル、テンプレートなどを使わずにEAを作った事を思い返してみてください。EA作りがこんなにも簡単に行えるようになったことを実感できるのではないかと思います。

MQL5は今現在もどんどん進化し、拡張していっています。

しかし、基礎的なMQL5の知識がなければそれらの恩恵を十分に受ける事は難しいでしょう。

ここまでお付き合い頂いた皆さんは、MQL5の基礎から応用まで十分な力が身についています。MQL5の潜在能力を利用して、存分にシステムトレードの可能性を探求して頂ければと思います。

皆様のEA開発ライフが明るいものになる事をお祈りしております。

長い間お付き合いいただきありがとうございました。

MQL5 EA講座 第131回「待機注文用EA開発テンプレートを作る」

MQL5 EA講座 第131回「待機注文用EA開発テンプレートを作る」

コメント

タイトルとURLをコピーしました