【超入門】MQL5 EA講座 第88回「待機注文情報取得用のクラスを追加する」

MQL5でEA作ろう講座

前回は、前々回の講座記事第86回で作った

PendingOpen関数アクセスレベル=protected)にメインプログラムからアクセスする為のアクセスレベル=public関数を合計で6つ、OriginalCTradeクラスに追加しました。

追加した関数は以下の通りです。

BuyLimit関数(買いのリミット待機注文を出す)

SellLimit関数(売りのリミット待機注文を出す)

BuyStop関数(買いのストップ待機注文を出す)

SellStop関数(売りのストップ待機注文を出す)

BuyStopLimit関数(買いのストップリミット待機注文を出す)

SellStopLimit関数(売りのストップリミット待機注文を出す)

87回時点での、のOriginalTrade.mqhファイル全体のコード記述は↓の記事からご確認ください。

さて、今回も引き続き待機注文についてです。

第86回87回では待機注文を発注する為のクラス関数を作ってきたわけですが、今回は注文が出された待機注文の情報を取得・管理するクラス関数を作っていきたいと思います。

スポンサーリンク
スポンサーリンク

待機注文専用のクラスを実装していく

では、さっそく待機注文情報を取得・管理するクラスを作っていきましょう

今までは、OriginalTrade.mqhファイルというインクルードファイルにすべてのクラス関数を集約させてきたのですが、今回は待機注文用の専用mqhファイルを別に作ります。↓

//+------------------------------------------------------------------+
//|                                             OriginalCpending.mqh |
//|                                                         MQL5ssei |
//|                                    https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link      "https://mqlinvestmentlab.com/"
#property version   "1.00"

class OriginalCpending
  {

  };

ファイル名をOriginalPending.mqhとし、クラス名をOriginalCpendingクラスとしました。

これをたたき台にして、メンバ変数メンバ関数を追加していきます。

インクルードファイルについての概要、使い方などについては↓の記事をご参照ください。

アクセスレベル=privateのメンバを追加する

まずはアクセスレベル=privateメンバを追加していきます。

クラスアクセスレベルに関しては↓の記事をご覧ください。

MQL5 EA講座 第50回「クラスについて3 -アクセス指定子-」

class OriginalCpending
  {
      private:
		void CountOrder(string parSymbol);
		int CountBuyLimit, CountSellLimit, CountBuyStop, CountSellStop, 
        CountBuyStopLimit, CountSellStopLimit, CountTotalPending;
		ulong TicketsPending[];
		
  };

戻り値void型CountOrder関数は、待機注文数を処理する内部関数になります。

処理実装記述は後程解説していきますが、成行注文で言う所の第82回「ポジション情報管理クラスを作る-その1」で取り上げた、GetPosInfo関数と同じような役割を担う関数となります。

戻り値int型変数CountBuyLimit, CountSellLimit, CountBuyStop, CountSellStop, CountBuyStopLimit, CountSellStopLimit, CountTotalPendingはそれぞれの待機注文種類の数をカウントする為の変数となっています。

CountBuyLimitは買いのリミット待機注文の数、CountSellLimitは売りのリミット待機注文の数、

CountBuyStopは買いのストップ待機注文の数、CountSellStopは売りのストップ待機注文の数、

CountBuyStopLimitは買いのストップリミット待機注文の数、CountSellStopLimitは売りのストップリミット待機注文の数、CountTotalPendingは種類を問わず待機注文全体の数

をそれぞれ格納する予定になっています。

ulong型の TicketsPending[]配列は、各待機注文オーダー番号を格納する予定になっています。

MQL5ではオーダー番号ポジション番号約定番号(ディール番号)という概念が存在します。

それぞれの違いについては各用語のアンカーテキストリンクから該当の記事をご参照ください。

アクセスレベル=publicのメンバを追加する

続いてアクセスレベル=publicメンバを追加していきます。

public:
		int BuyLimitNum(string parSymbol);
		int SellLimitNum(string parSymbol);
		int BuyStopNum(string parSymbol);
		int SellStopNum(string parSymbol);
		int BuyStopLimitNum(string parSymbol);
		int SellStopLimitNum(string parSymbol);
		int TotalPendingNum(string parSymbol);
		
		void GetOrderTickets(string parSymbol, ulong &parTickets[]);
  };

待機注文数をメインプログラムで取得する為のpublic関数を追加する

待機注文数をメインプログラムで取得する為のpublicレベル関数を7つ追加します。

BuyLimitNum関数は買いのリミット待機注文の数を取得する関数です。

SellLimitNum関数は売りのリミット待機注文の数を取得する関数です。

BuyStopNum関数は買いのストップ待機注文の数を取得する関数です。

SellStopNum関数は売りのストップ待機注文の数を取得する関数です。

BuyStopLimitNum関数は買いのストップリミット待機注文の数を取得する関数です。

SellStopLimitNum関数は売りのストップリミット待機注文の数を取得する関数です。

待機注文のオーダー番号を取得するpublic関数を宣言する

続いて、待機注文オーダー番号を取得するpublicレベル関数を1つ宣言します。

関数名をGetOrderTickets関数とします。

待機注文オーダー番号を取得するにあたっては、アクセスレベル=privateセクションで定義したTicketsPending[]配列を利用します。

配列return演算子によって、戻り値として返すことは出来ない為、関数の第2引数参照渡し配列を渡すことによって情報を取得します。

<参考リンク>

第44回「参照渡しについて」

「配列を参照渡しで渡す」

オーダー番号

ポジション番号

約定番号

では、これから各メンバ関数の解説を行っていきたいと思います。

OrderCount関数について

まずはOrderCount関数からです。

OrderCount関数の戻り値と引数構成について

OrderCount関数戻り値引数構成は以下の通りです。

void OrderCount(string parSymbol);

引数「parSymbol」は取引銘柄が記述される想定です。

OrderCount関数の処理実装記述はこの後解説しますが、OrderCount関数で振り分けた待機注文の種類を、この後作るpublicレベル関数を使ってアクセスし、取得する仕様になっているので、戻り値void型になっています。

OrderCount関数の処理実装記述について

OrderCount関数の処理実装記述は以下の通りです。

void OriginalCpending::OrderCount(string parSymbol)
{
	CountBuyLimit = 0; 
	CountSellLimit = 0;
	CountBuyStop = 0; 
	CountSellStop = 0; 
	CountBuyStopLimit = 0; 
	CountSellStopLimit = 0; 
	CountTotalPending = 0;
	//各種待機注文の数を格納
	
	ArrayResize(TicketsPending, 1);
	ArrayInitialize(TicketsPending, 0);
	
	//各待機注文の要素数と初期値を仮規定
	
	
	for(int i = 0; i < OrdersTotal(); i++)//注文数分チェック
	{
		ulong ticket = OrderGetTicket(i);
		if(OrderGetString(ORDER_SYMBOL) == parSymbol)
		{
			long type = OrderGetInteger(ORDER_TYPE);
			
			switch((int)type)
			{
				case ORDER_TYPE_BUY_STOP://ストップ買い待機注文なら
				CountBuyStop++;//インクリメント
				break;
				
				case ORDER_TYPE_SELL_STOP://ストップ売り待機注文なら
				CountSellStop++;//インクリメント
				break;
				
				case ORDER_TYPE_BUY_LIMIT:
				CountBuyLimit++; break;
				
				case ORDER_TYPE_SELL_LIMIT:
				CountSellLimit++; break;
				
				case ORDER_TYPE_BUY_STOP_LIMIT:
				
				CountBuyStopLimit++; break;
				
				case ORDER_TYPE_SELL_STOP_LIMIT:
				CountSellStopLimit++; break;
			}//switch文の終わり
			
			CountTotalPending++;
			
			ArrayResize(TicketsPending,CountTotalPending);
			TicketsPending[ArraySize(TicketsPending)-1] = ticket;
		}//if文の終わり
	}//for文の終わり
}//処理実装記述の終わり

例によって一つ一つのプロセスを順を追って見ていきます。

オーダー数を格納する変数の初期化

 //オーダー数を格納する変数の初期化
  CountBuyLimit = 0; 
	CountSellLimit = 0;
	CountBuyStop = 0; 
	CountSellStop = 0; 
	CountBuyStopLimit = 0; 
	CountSellStopLimit = 0; 
	CountTotalPending = 0;

上記サンプルコードのおける7つの変数の役割については、

アクセスレベル=privateのメンバを追加する」で解説しました。

オーダー数を格納する為の、アクセスレベル=privateメンバ変数です。7つの変数初期値を0とします。

オーダー番号を格納する配列の初期化とリサイズ

//オーダー番号を格納する配列の初期化とリサイズ
	ArrayResize(TicketsPending, 1);
	ArrayInitialize(TicketsPending, 0);

続いてオーダー番号を格納する配列の初期化とリサイズを行います。

ArrayResize関数ArrayInitialize関数は、ともに第1引数に処理を施したい配列を指定して使う関数です。

ArrayResize関数配列のサイズ(いわば箱の数)を規定する関数であるのに対し、ArrayInitialize関数は各配列の値(いわば箱の中身)を規定する関数、と言えます。

ArrayResize(TicketsPending, 1);

↑の表記は配列「TicketsPending」の配列数を1にする、という決まりを作ったことを意味します。

ArrayInitialize(TicketsPending, 0);

↑の表記は

配列の値を0にする、という決まりを作ったことを意味します。

for文で待機注文内を一番古いオーダーからチェック

for(int i = 0; i < OrdersTotal(); i++)//注文数分チェック
	{
		ulong ticket = OrderGetTicket(i);
		if(OrderGetString(ORDER_SYMBOL) == parSymbol)
		{
			long type = OrderGetInteger(ORDER_TYPE);
			
			switch((int)type)
			{
				case ORDER_TYPE_BUY_STOP://ストップ買い待機注文なら
				CountBuyStop++;//インクリメント
				break;
				
				case ORDER_TYPE_SELL_STOP://ストップ売り待機注文なら
				CountSellStop++;//インクリメント
				break;
				
				case ORDER_TYPE_BUY_LIMIT:
				CountBuyLimit++; break;
				
				case ORDER_TYPE_SELL_LIMIT:
				CountSellLimit++; break;
				
				case ORDER_TYPE_BUY_STOP_LIMIT:
				
				CountBuyStopLimit++; break;
				
				case ORDER_TYPE_SELL_STOP_LIMIT:
				CountSellStopLimit++; break;
			}

値の取得に必要な変数配列の初期化・リサイズが終わったので、次はfor文による待機注文のチェックです。

<参考リンク>

MQL5 EA講座 第37回「switch文」

MQL5 EA講座 第40回「for文について」

MQL5 EA講座 第41回「breakとcontinue」

for文の内部記述1:待機オーダーの選択
for(int i = 0; i < OrdersTotal(); i++)//注文数分チェック
	{
		ulong ticket = OrderGetTicket(i);

チェックにはOrdersTotal関数を使います。

第82回で、ポジション情報を取得・管理するクラス関数について解説しましたが、その際にはPositionsTotal関数を使っていました。PositionsTotal関数は、あくまでも現在銘柄保有中の取引の数を返す関数です。待機注文の総数を確認するOrdersTotal関数との違いに注意しましょう。

待機注文は古い順に0,1,2、・・・と並んでいますからfor文で古い順から新しい順に向かって、ポジションを選択していく事になります。

待機注文の選択にはOrderGetTicket関数を使います。

OrderGetTicket関数についての詳細は↓の記事をご参照ください

ulong型変数「ticket」にfor文で取得した待機注文オーダーインデックス引数としたOrderGetTicket関数戻り値を格納します。これで変数「ticket」にはオーダー番号が格納されました。

for文の内部記述2:選択オーダーの銘柄を確認し、オーダータイプを変数に格納
for(int i = 0; i < OrdersTotal(); i++)//注文数分チェック
	{
		ulong ticket = OrderGetTicket(i);
		if(OrderGetString(ORDER_SYMBOL) == parSymbol)
		{
			long type = OrderGetInteger(ORDER_TYPE);

変数「ticket」にオーダー番号を格納したら、

OrderGetString関数引数定数値「ORDER_SYMBOL」を記述した銘柄情報と、引数「parSymbol」の銘柄情報が一致しているかどうかをif文で判定しています。

OrderGetString関数を使った銘柄情報=現在チェック中のオーダーの銘柄情報

仮引数「parSymbol」=EA(自動売買プログラム)で指定している銘柄情報

ですから、これが不一致の場合、EA(自動売買プログラム)から発注した待機注文ではないという事になるので、次の待機注文オーダーインデックスのチェックにスキップします。一致していれば、EA(自動売買プログラム)からの待機注文として、if文の{}内執行内容に移ります。

for文の内部記述3:オーダータイプ情報の取得とカウント変数への振り分け
long type = OrderGetInteger(ORDER_TYPE);
			
			switch((int)type)
			{
				case ORDER_TYPE_BUY_STOP://ストップ買い待機注文なら
				CountBuyStop++;//インクリメント
				break;
				
				case ORDER_TYPE_SELL_STOP://ストップ売り待機注文なら
				CountSellStop++;//インクリメント
				break;
				
				case ORDER_TYPE_BUY_LIMIT://リミット買い待機注文なら
				CountBuyLimit++;//インクリメント
				 break;
				
				case ORDER_TYPE_SELL_LIMIT://リミット売り待機注文なら
				CountSellLimit++; //インクリメント
				break;
				
				case ORDER_TYPE_BUY_STOP_LIMIT://ストップリミット買い待機注文なら
				
				CountBuyStopLimit++;//インクリメント
				 break;
				
				case ORDER_TYPE_SELL_STOP_LIMIT:://ストップリミット売り待機注文なら
				CountSellStopLimit++; //インクリメント
				break;
			}//switch文の終わり
			

OrderGetInteger関数引数定数値「ORDER_TYPE」を記述し、取得した値を変数「type」に格納します。これで変数「type」にはチェック中の待機注文オーダーの注文タイプが格納されています。

この変数「type」の情報をswitch文の条件として、待機注文の数をカウントする各種private変数に振り分けていきます。

switch文についてはコチラの記事をご覧ください↓

変数「type」の値が、ORDER_TYPE_BUY_STOPの場合

変数「type」の値が、ORDER_TYPE_BUY_STOP、すなわちストップ買い待機注文ならCountBuyLimitの値に1をプラスして(インクリメントswitch文breakで抜けます。

変数「type」の値が、ORDER_TYPE_SELL_STOPの場合

変数「type」の値が、ORDER_TYPE_SELL_STOP、すなわちストップ売り待機注文ならCountSellStopの値に1をプラスして(インクリメントswitch文breakで抜けます。

変数「type」の値が、ORDER_TYPE_BUY_LIMITの場合

変数「type」の値が、ORDER_TYPE_BUY_LIMIT、すなわちリミット買い待機注文ならCountBuyLimitの値に1をプラスして(インクリメントswitch文breakで抜けます。

変数「type」の値が、ORDER_TYPE_SELL_LIMITの場合

変数「type」の値が、ORDER_TYPE_SELL_LIMIT、すなわちリミット買い待機注文ならCountSellLimitの値に1をプラスして(インクリメントswitch文breakで抜けます。

変数「type」の値が、ORDER_TYPE_BUY_STOP_LIMITの場合

変数「type」の値が、ORDER_TYPE_BUY_STOP_LIMIT、ストップリミット買い待機注文ならCountBuyStopLimitの値に1をプラスして(インクリメントswitch文breakで抜けます。

変数「type」の値が、ORDER_TYPE_SELL_STOP_LIMITの場合

変数「type」の値が、ORDER_TYPE_SELL_STOP_LIMIT、ストップリミット売り待機注文ならCountSellStopLimitの値に1をプラスして(インクリメントswitch文breakで抜けます。

for文の内部記述4:待機注文全体のカウント数をプラス
//全体の待機注文数をインクリメント
			CountTotalPending++;
			
     //オーダー番号情報を格納する配列「TicketsPending」の配列サイズを増やす
			ArrayResize(TicketsPending,CountTotalPending);
     //オーダー番号を配列に代入する。
			TicketsPending[ArraySize(TicketsPending)-1] = ticket;
   }//if文の終わり
	}//for文の終わり
}//処理実装記述の終わり

待機注文種別のカウント変数への振り分けが終わり、switch文を抜けたら全体の待機注文数を格納する変数「CountTotalPending」の値を1増やします(インクリメント)。

変数「CountTotalPending」の値が増えたということは、待機注文の数が増えたことを意味しますから、オーダー番号情報を格納する配列「TicketsPending」の配列サイズも増やす必要があります。

ArrayResize関数を使い、第1引数にリサイズ対象配列の「TicketsPending」を、第2引数に新たな配列サイズ=変数「CountTotalPending」を記述する事によって実現します。

変数「ticket」にはオーダー番号が格納されていますので、配列「TicketsPending」に格納していきます。

配列インデックス配列サイズ-1の関係にありますから、配列「TicketsPending」の[]にArraySize(TicketsPending-1)を指定する事で、チェックした順番に正しく格納されます。

以上の記述をもって、if(OrderGetString(ORDER_SYMBOL) == parSymbol)に対する処理内容の記述は終了したのでif文の{}で閉じます。

同時にfor文と処理実装記述自体も終了しますので、それぞれの{}を閉じます。

※プログラミングを始めたての方の場合、コンパイルエラーが発生した時に、その解決に難儀します。特に、その原因が{}が入れ子状になっている構文における{}が抜けている場合だと、後から特定・修正するのが中々大変です。

サンプルコードのようにコメントアウトでどの記述に対応する{}なのか、目印をつけるのも一つの手です。

まとめ

今回は待機注文の情報取得・管理用のクラス関数を集約する事を目的としたファイル「OriginalPending.mqh」を作り、そこにOriginalCpendingクラスを作りました。

そして宣言したアクセスレベルprivate,publicそれぞれのメンバのうちOrderCount関数の処理実装記述について主に解説してきました。

今回の講座記事第88回時点でのOriginalPending.mqhファイルのプログラミング記述内容は以下の通りです↓

//+------------------------------------------------------------------+
//|                                             OriginalCpending.mqh |
//|                                                         MQL5ssei |
//|                                    https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link      "https://mqlinvestmentlab.com/"
#property version   "1.00"

class OriginalCpending
  {
      private:
		void OrderCount(string parSymbol);
		int CountBuyLimit, CountSellLimit, CountBuyStop, CountSellStop, CountBuyStopLimit, CountSellStopLimit, CountTotalPending;
		ulong TicketsPending[];
		
		public:
		int BuyLimitNum(string parSymbol);
		int SellLimitNum(string parSymbol);
		int BuyStopNum(string parSymbol);
		int SellStopNum(string parSymbol);
		int BuyStopLimitNum(string parSymbol);
		int SellStopLimitNum(string parSymbol);
		int TotalPendingNum(string parSymbol);
		
		void GetOrderTickets(string parSymbol, ulong &parTickets[]);
  };
  
  void OriginalCpending::OrderCount(string parSymbol)
{
   //ポジション数を格納する変数の初期化
	CountBuyLimit = 0; 
	CountSellLimit = 0;
	CountBuyStop = 0; 
	CountSellStop = 0; 
	CountBuyStopLimit = 0; 
	CountSellStopLimit = 0; 
	CountTotalPending = 0;
	
	//オーダー番号を格納する配列の初期化とリサイズ
	ArrayResize(TicketsPending, 1);
	ArrayInitialize(TicketsPending, 0);

	for(int i = 0; i < OrdersTotal(); i++)//注文数分チェック
	{
		ulong ticket = OrderGetTicket(i);
		if(OrderGetString(ORDER_SYMBOL) == parSymbol)
		{
			long type = OrderGetInteger(ORDER_TYPE);
			
			switch((int)type)
			{
				case ORDER_TYPE_BUY_STOP://ストップ買い待機注文なら
				CountBuyStop++;//インクリメント
				break;
				
				case ORDER_TYPE_SELL_STOP://ストップ売り待機注文なら
				CountSellStop++;//インクリメント
				break;
				
				case ORDER_TYPE_BUY_LIMIT://リミット買い待機注文なら
				CountBuyLimit++;//インクリメント
				 break;
				
				case ORDER_TYPE_SELL_LIMIT://リミット売り待機注文なら
				CountSellLimit++; //インクリメント
				break;
				
				case ORDER_TYPE_BUY_STOP_LIMIT://ストップリミット買い待機注文なら
				
				CountBuyStopLimit++;//インクリメント
				 break;
				
				case ORDER_TYPE_SELL_STOP_LIMIT://ストップリミット売り待機注文なら
				CountSellStopLimit++; //インクリメント
				break;
			}//switch文の終わり
			
			//全体の待機注文数をインクリメント
			CountTotalPending++;
			
			ArrayResize(TicketsPending,CountTotalPending);
			TicketsPending[ArraySize(TicketsPending)-1] = ticket;
		}//if文の終わり
	}//for文の終わり
}//処理実装記述の終わり

次回は今回作ったOrderCount関数にアクセスするpublicレベル関数の処理実装記述について解説していきたいと思います。

今回は以上とさせていただきます。最後までお読みいただきありがとうございました。

※今回の内容がよくわからなかったという方は、ひょっとするとクラスに関しての基本的な理解が追い付いていない可能性があります。クラスについては以下のリンクをご参照ください。↓

MQL5 EA講座 第87回「待機注文関数を作る-その2-」

MQL5 EA講座 第89回「待機注文情報取得用クラスにpublic関数を実装する」

コメント

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