前回は、前々回の講座記事第86回で作った
PendingOpen関数(アクセスレベル=protected)にメインプログラムからアクセスする為のアクセスレベル=publicの関数を合計で6つ、OriginalCTradeクラスに追加しました。
追加した関数は以下の通りです。
BuyLimit関数(買いのリミット待機注文を出す)
SellLimit関数(売りのリミット待機注文を出す)
SellStop関数(売りのストップ待機注文を出す)
BuyStopLimit関数(買いのストップリミット待機注文を出す)
SellStopLimit関数(売りのストップリミット待機注文を出す)
※87回時点での、のOriginalTrade.mqhファイル全体のコード記述は↓の記事からご確認ください。
さて、今回も引き続き待機注文についてです。
第86回、87回では待機注文を発注する為のクラス・関数を作ってきたわけですが、今回は注文が出された待機注文の情報を取得・管理するクラス・関数を作っていきたいと思います。
- 待機注文専用のクラスを実装していく
- アクセスレベル=privateのメンバを追加する
- アクセスレベル=publicのメンバを追加する
- OrderCount関数について
- まとめ
待機注文専用のクラスを実装していく
では、さっそく待機注文情報を取得・管理するクラスを作っていきましょう
今までは、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つ宣言します。
待機注文のオーダー番号を取得するにあたっては、アクセスレベル=privateセクションで定義したTicketsPending[]配列を利用します。
配列をreturn演算子によって、戻り値として返すことは出来ない為、関数の第2引数に参照渡しで配列を渡すことによって情報を取得します。
<参考リンク>
・約定番号
では、これから各メンバ関数の解説を行っていきたいと思います。
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講座 第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);
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講座 第48回「クラスについて1-クラスとは?-」
- MQL5 EA講座 第49回「クラスについて2 -クラスの使い方-」
- MQL5 EA講座 第50回「クラスについて3 -アクセス指定子-」
- MQL5 EA講座 第51回「クラスについて4 -派生クラス-」
- MQL5 EA講座 第52回「クラスについて5 -コンストラクタ-」
- MQL5 EA講座 第53回「クラスについて6 -仮想関数-」
コメント