MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第2部)過去の注文と取引のコレクション

Artyom Trishkin | 15 5月, 2019

内容

前の記事ではMetaTrader 5とMetaTrader 4プラットフォーム用のプログラムの開発を単純化するための大規模なクロスプラットフォームライブラリの作成を始めました。過去の注文と取引、および市場の注文とポジションに関するデータを格納するための基本オブジェクトであるCOrder抽象オブジェクトを作成しました。

この部分では、口座履歴データをコレクションに格納するために必要なすべてのオブジェクトの開発、過去の注文と取引のコレクションの準備、既に作成されているオブジェクトと列挙の変更と改善を進めます。

過去の注文と取引のオブジェクト

COrder基本オブジェクトには、市場注文(アクションを実行する注文)、未決注文、取引、ポジションなど、任意の口座オブジェクトに関するすべてのデータが含まれています。これらすべてのオブジェクトを互いに独立して自由に操作できるようにするために、抽象的なCOrderに基づいていくつかのクラスを開発します。これらのクラスは、オブジェクトの型を正確に示します。

過去の注文および取引のリストには、未決注文の削除、成行注文の発注および取引(成行注文の実行結果)といういくつかの種類のそのようなオブジェクトが含まれることがあります。MQL4には、さらに残高とクレジット操作の2個のオブジェクトタイプがあります(MQL5では、これらのデータは取引プロパティに格納されます)。

ライブラリのObjectsフォルダに新しいCHistoryOrderクラスを作成します。
これにはObjectsフォルダを右クリックして[New file]メニュー項目(Ctrl+N)を選択します。新しく開いたMQL5ウィザードで[新しいクラス]を選択して[次へ]をクリックします。クラス名フィールドにCHistoryOrder (1)と入力し、ベースクラスフィールドにCOrder(2)抽象クラスの名前を入力して、[完了]をクリックします。


HistoryOrder.mqh (3)ファイルがObjectsフォルダに生成されます。このファイルを開きます。

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
private:

public:
                     CHistoryOrder();
                    ~CHistoryOrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::~CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+

今のところ、これは単にクラステンプレートです。コンパイルしようとすると、既によく知られている5つのエラー が表示されます。COrderから派生した新しいクラスはその親については何も知りません。Order.mqhファイルをインクルードします

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                           |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
private:

public:
                     CHistoryOrder();
                    ~CHistoryOrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::~CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+

これでコンパイルに問題はありません。

クラスはかなり小さいです。COrder親クラスメソッドを再定義する必要があります。これは、注文プロパティのメンテナンスフラグを返し、コンストラクタで注文チケットをクラスに渡すように設定します。

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                           |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| 履歴成行注文                                                       |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
public:
   //--- コンストラクタ
                     CHistoryOrder(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_ORDER,ticket) {}
   //--- サポートされる整数注文プロパティ
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| 注文が渡されたプロパティをサポートする場合は「true」を返し、             |
//| その他の場合は「false」を返す                                       |
//+------------------------------------------------------------------+
bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP       || 
      property==ORDER_PROP_DEAL_ENTRY     || 
      property==ORDER_PROP_TIME_UPDATE    || 
      property==ORDER_PROP_TIME_UPDATE_MSC
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

したがって、選択された注文のチケットはクラスコンストラクタに渡され注文ステータス(過去の注文)とそのチケットはCOrder親オブジェクトの保護されたコンストラクタに渡されます。

また、整数注文プロパティのサポートを返す、親クラスの仮想メソッドも再定義しました。実数および文字列注文プロパティのサポートを返すメソッドは変更されていません。これらの親クラスのメソッドは常に 「true」を返します。過去の注文はすべての実数型プロパティと文字列プロパティをサポートすると仮定し、今のところ再定義はしません。

整数注文プロパティをサポートするメソッドでプロパティを確認して、有効期限、取引方向、ポジション変更時刻の場合は「false」を返します。これらのプロパティは成行注文によってはサポートされていません。残りのすべてのプロパティはサポートされているため、「true」が返されます

同様に、過去の(削除された)未決注文のCHistoryPendingクラスと過去の取引のCHistoryDealクラスを作成します。

//+------------------------------------------------------------------+
//|                                               HistoryPending.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                           |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| 削除された未決注文                                                   |
//+------------------------------------------------------------------+
class CHistoryPending : public COrder
  {
public:
   //--- コンストラクタ
                     CHistoryPending(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_PENDING,ticket) {}
   //--- サポートされる注文プロパティ: (1)実数、(2)整数
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| 注文が渡されたプロパティをサポートする場合は「true」を返し、             |
//| その他の場合は「false」を返す                                       |
//+------------------------------------------------------------------+
bool CHistoryPending::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_PROFIT_PT         ||
      property==ORDER_PROP_DEAL_ORDER        ||
      property==ORDER_PROP_DEAL_ENTRY        ||
      property==ORDER_PROP_TIME_UPDATE       ||
      property==ORDER_PROP_TIME_UPDATE_MSC   ||
      property==ORDER_PROP_TICKET_FROM       ||
      property==ORDER_PROP_TICKET_TO         ||
      property==ORDER_PROP_CLOSE_BY_SL       ||
      property==ORDER_PROP_CLOSE_BY_TP
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
//| 注文が渡されたプロパティをサポートする場合は「true」を返し、            |
//| その他の場合は「false」を返す                                       |
//+------------------------------------------------------------------+
bool CHistoryPending::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
   if(property==ORDER_PROP_COMMISSION  ||
      property==ORDER_PROP_SWAP        ||
      property==ORDER_PROP_PROFIT      ||
      property==ORDER_PROP_PROFIT_FULL ||
      property==ORDER_PROP_PRICE_CLOSE
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                  HistoryDeal.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                           |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| 取引                                                               |
//+------------------------------------------------------------------+
class CHistoryDeal : public COrder
  {
public:
   //--- コンストラクタ
                     CHistoryDeal(const ulong ticket) : COrder(ORDER_STATUS_DEAL,ticket) {}
   //--- サポートされる取引プロパティ: (1)実数、(2)整数
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| 注文が渡されたプロパティをサポートする場合は「true」を返し、             |
//| その他の場合は「false」を返す                                       |
//+------------------------------------------------------------------+
bool CHistoryDeal::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP          || 
      property==ORDER_PROP_PROFIT_PT         ||
      property==ORDER_PROP_POSITION_BY_ID    ||
      property==ORDER_PROP_TIME_UPDATE       ||
      property==ORDER_PROP_TIME_UPDATE_MSC   ||
      property==ORDER_PROP_STATE             ||
      (
       this.OrderType()==DEAL_TYPE_BALANCE &&
       (
        property==ORDER_PROP_POSITION_ID     ||
        property==ORDER_PROP_POSITION_BY_ID  ||
        property==ORDER_PROP_TICKET_FROM     ||
        property==ORDER_PROP_TICKET_TO       ||
        property==ORDER_PROP_DEAL_ORDER      ||
        property==ORDER_PROP_MAGIC           ||
        property==ORDER_PROP_TIME_CLOSE      ||
        property==ORDER_PROP_TIME_CLOSE_MSC  ||
        property==ORDER_PROP_CLOSE_BY_SL     ||
        property==ORDER_PROP_CLOSE_BY_TP
       )
      )
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
bool CHistoryDeal::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
   if(property==ORDER_PROP_TP                || 
      property==ORDER_PROP_SL                || 
      property==ORDER_PROP_PRICE_CLOSE       ||
      property==ORDER_PROP_VOLUME_CURRENT    ||
      property==ORDER_PROP_PRICE_STOP_LIMIT  ||
      (
       this.OrderType()==DEAL_TYPE_BALANCE &&
       (
        property==ORDER_PROP_PRICE_OPEN      ||
        property==ORDER_PROP_COMMISSION      ||
        property==ORDER_PROP_SWAP            ||
        property==ORDER_PROP_VOLUME
       )
      )
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

過去の注文のコレクションが基づくことになる3つの注文オブジェクトを作成しました。それらはすべてCOrder抽象注文基本クラスから継承されています。それらにはプロパティがありますが、これらの注文タイプでサポートされているプロパティのみを返すことができます。それらすべては単一のコレクションリスト(過去の注文のコレクション)に配置され、そこから口座履歴に関する必要なすべてのデータを任意の構成および注文で受け取ります。

操作ログで注文プロパティを表示するためのSupportProperty()メソッドでは、サポートの有無にかかわらずプロパティがすべて考慮されるわけではありません。たとえば、取引では3つのタイプ(買い、売り、残高操作)のみが考慮されます。

まだ考慮されておらず、それらのサポートを返すメソッドで明示的に指定されていないプロパティは常に出力されます。その後、出力を避けるためには、状況に関係なく常にゼロの値を返すプロパティ(サポートされていないもの)をメソッドに追加できます。

過去の注文と取引のコレクション

口座履歴は手元にあると便利なものです。ターミナルは口座履歴を提供し、プログラムでそれを取得するためのツールを提供します。しかしながら、現在の操作には必要なデータをプログラムに返すために並び替えて再配置することができるカスタムリストが必要です。これは、ティックごとに前回の口座履歴ステータスの変更を確認する必要があることを意味します。変更が検出された場合、過去の注文と取引のリストが再計算されます。しかし、ティックごとに履歴全体を並べ替えるのにはリソースがかかりすぎます。したがって、以前のデータがすでにリストに格納されている間に、新しいデータのリストに追加するだけにします。

Collectionsフォルダに新しいCHistoryCollectionクラスを作成しましょう。

Collectionsフォルダに右クリックし、[New File]を選択して、MQLウィザードウィンドウで[新しいクラス]を選択して[次へ]をクリックします。CHistoryCollectionクラス名を入力し、ベースクラスフィールドを空のままにして[完了]をクリックします。


Collectionsフォルダに新しいHistoryCollectionファイルが生成されます。

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:

public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

書き入れましょう。

リストにはCArrayObj標準ライブラリのオブジェクトインスタンスへのポインタの動的リストを使用します。それをファイルにインクルードしてすぐに定義します(右クリックのコンテキストメニューを使って行います)。


CArrayObjをインクルードしてプライベートセクションで過去の注文と取引のリストを定義します。

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                           |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| 過去の注文と取引のコレクション                                         |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // 過去の注文と取引のリスト

public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

コレクションに追加された最後の注文と取引のインデックスを保存する必要があります。その上、過去と現在の注文数と取引数の差を知る必要があるので、それらを格納するためのプライベートクラスメンバを作成します。

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                           |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| 過去の注文と取引のコレクション                                         |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // 過去の注文と取引のリスト
   int               m_index_order;          // ターミナルの履歴リストからコレクションに追加された最後の注文のインデックス(MQL4、MQL5)
   int               m_index_deal;           // ターミナルの履歴リストからコレクションに追加された最後の取引のインデックス(MQL5)
   int               m_delta_order;          // 過去の注文数と比較した注文数の違い
   int               m_delta_deal;           // 過去の取引数と比較した取引数の違い
public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

最初の起動時に、すべてのプライベートクラスメンバがリセットされ、履歴が再計算されます。これを行うには、単にクラスコンストラクタにクラスメンバ初期化リストを追加し、コレクションリストの並び替え基準となるデフォルト基準を設定します。

現在、デフォルトのコンストラクタがあります。それを実装する前に、コレクションリストで注文と取引を並び替えるためのすべての可能な基準を含む列挙を作成する必要があります。
しかし、まず、操作ログ内でより論理的に表示されるように、整数、実数、文字列注文プロパティを調整しましょう。ライブラリのルートフォルダからDefines.mqhファイルを開き、列挙型メンバを必要な順序で配置します。

//+------------------------------------------------------------------+
//| 注文、取引、ポジションの整数型プロパティ                               |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // 注文チケット
   ORDER_PROP_MAGIC,                                        // 注文のマジックナンバー
   ORDER_PROP_TIME_OPEN,                                    // 開始時間(MQL5取引時間)
   ORDER_PROP_TIME_CLOSE,                                   // 終了時間(MQL5実行または削除時間 - ORDER_TIME_DONE)
   ORDER_PROP_TIME_OPEN_MSC,                                // ミリ秒での開始時間(ミリ秒でのMQL5取引時間)
   ORDER_PROP_TIME_CLOSE_MSC,                               // ミリ秒での終了時間(ミリ秒でのMQL5実行または削除時間 - ORDER_TIME_DONE_MSC)
   ORDER_PROP_TIME_EXP,                                     // 注文有効期限(未決注文用)
   ORDER_PROP_STATUS,                                       // 注文ステータス(ENUM_ORDER_STATUS列挙体から)
   ORDER_PROP_TYPE,                                         // 注文タイプ(MQL5取引タイプ)
   ORDER_PROP_DIRECTION,                                    // 方向(買または売)
   ORDER_PROP_REASON,                                       // 取引/注文/ポジション理由またはソース
   ORDER_PROP_POSITION_ID,                                  // ポジションID
   ORDER_PROP_POSITION_BY_ID,                               // 反対側のポジションID
   ORDER_PROP_DEAL_ORDER,                                   // 取引が基づく注文
   ORDER_PROP_DEAL_ENTRY,                                   // 取引の方向 – IN、OUT、IN/OUT
   ORDER_PROP_TIME_UPDATE,                                  // ポジション変更時間(秒)
   ORDER_PROP_TIME_UPDATE_MSC,                              // ポジション変更時間(ミリ秒)
   ORDER_PROP_TICKET_FROM,                                  // 親注文チケット
   ORDER_PROP_TICKET_TO,                                    // 派生注文チケット
   ORDER_PROP_PROFIT_PT,                                    // 利益(ポイント)
   ORDER_PROP_CLOSE_BY_SL,                                  // ストップロスによる決済のフラグ
   ORDER_PROP_CLOSE_BY_TP,                                  // テイクプロフィットによる決済のフラグ
  }; 
#define ORDER_PROP_INTEGER_TOTAL    (22)                    // 整数型プロパティの総数
//+------------------------------------------------------------------+
//| 注文、取引、ポジションの実数型プロパティ                               |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_DOUBLE
  {
   ORDER_PROP_PRICE_OPEN = ORDER_PROP_INTEGER_TOTAL,        // 始値(MQL5取引価格)
   ORDER_PROP_PRICE_CLOSE,                                  // 終値
   ORDER_PROP_SL,                                           // ストップロス価格
   ORDER_PROP_TP,                                           // テイクプロフィット価格
   ORDER_PROP_PROFIT,                                       // 利益
   ORDER_PROP_COMMISSION,                                   // 手数料
   ORDER_PROP_SWAP,                                         // スワップ
   ORDER_PROP_VOLUME,                                       // ボリューム
   ORDER_PROP_VOLUME_CURRENT,                               // 実行されていないボリューム
   ORDER_PROP_PROFIT_FULL,                                  // 利益+手数料+スワップ
   ORDER_PROP_PRICE_STOP_LIMIT,                             // ストップリミット注文が発動した際のリミット注文価格
  };
#define ORDER_PROP_DOUBLE_TOTAL     (11)                    // 実数型プロパティの総数
//+------------------------------------------------------------------+
//| 注文、取引、ポジションの文字列型プロパティ                             |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_STRING
  {
   ORDER_PROP_SYMBOL = (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL), // 注文銘柄
   ORDER_PROP_COMMENT,                                      // 注文コメント
   ORDER_PROP_EXT_ID                                        // 外部取引システムの注文ID
  };
#define ORDER_PROP_STRING_TOTAL     (3)                     // 文字列型プロパティの総数
//+------------------------------------------------------------------+

それでは、同じファイルにすべての可能な種類の注文と取引の並べ替えを含む列挙型を追加しましょう。

//+------------------------------------------------------------------+
//| 注文と取引の並べ替えの可能な基準                                        |
//+------------------------------------------------------------------+
enum ENUM_SORT_ORDERS_MODE
  {
   //--- 整数型プロパティによって並び替える
   SORT_BY_ORDER_TICKET          =  0,                      // 注文チケットによって並び替える
   SORT_BY_ORDER_MAGIC           =  1,                      // 注文マジックナンバーによって並び替える
   SORT_BY_ORDER_TIME_OPEN       =  2,                      // 注文開始時間によって並び替える
   SORT_BY_ORDER_TIME_CLOSE      =  3,                      // 注文終了時間によって並び替える
   SORT_BY_ORDER_TIME_OPEN_MSC   =  4,                      // ミリ秒での注文開始時間によって並び替える
   SORT_BY_ORDER_TIME_CLOSE_MSC  =  5,                      // ミリ秒での注文終了時間によって並び替える
   SORT_BY_ORDER_TIME_EXP        =  6,                      // 注文有効期限によって並び替える
   SORT_BY_ORDER_STATUS          =  7,                      // 注文ステータス(市場注文/未決注文/取引)によって並び替える
   SORT_BY_ORDER_TYPE            =  8,                      // 注文タイプによって並び替える
   SORT_BY_ORDER_REASON          =  10,                     // 取引/注文/ポジション理由またはソースによって並び替える
   SORT_BY_ORDER_POSITION_ID     =  11,                     // ポジションIDによって並び替える
   SORT_BY_ORDER_POSITION_BY_ID  =  12,                     // 反対側のポジションIDによって並び替える
   SORT_BY_ORDER_DEAL_ORDER      =  13,                     // 取引が基づく注文によって並び替える
   SORT_BY_ORDER_DEAL_ENTRY      =  14,                     // 取引方向(IN、OUT、IN/OUT)によって並び替える
   SORT_BY_ORDER_TIME_UPDATE     =  15,                     // ポジション変更時間(秒)によって並び替える
   SORT_BY_ORDER_TIME_UPDATE_MSC =  16,                     // ポジション変更時間(ミリ秒)によって並び替える
   SORT_BY_ORDER_TICKET_FROM     =  17,                     // 親の注文チケットによって並び替える
   SORT_BY_ORDER_TICKET_TO       =  18,                     // 派生した注文チケットによって並び替える
   SORT_BY_ORDER_PROFIT_PT       =  19,                     // 注文利益(ポイント)によって並び替える
   SORT_BY_ORDER_CLOSE_BY_SL     =  20,                     // 注文の「ストップロスによる決済」フラグによって並び替える
   SORT_BY_ORDER_CLOSE_BY_TP     =  21,                     // 注文の「テイクプロフィットによる決済」フラグによって並び替える
   //--- 実数型プロパティによって並び替える
   SORT_BY_ORDER_PRICE_OPEN      =  ORDER_PROP_INTEGER_TOTAL,// 始値によって並び替える
   SORT_BY_ORDER_PRICE_CLOSE     =  23,                     // 終値によって並び替える
   SORT_BY_ORDER_SL              =  24,                     // ストップロス価格によって並び替える
   SORT_BY_ORDER_TP              =  25,                     // テイクプロフィット価格によって並び替える
   SORT_BY_ORDER_PROFIT          =  26,                     // 利益によって並び替える
   SORT_BY_ORDER_COMMISSION      =  27,                     // 手数料によって並び替える
   SORT_BY_ORDER_SWAP            =  28,                     // スワップによって並び替える
   SORT_BY_ORDER_VOLUME          =  29,                     // ボリュームによって並び替える
   SORT_BY_ORDER_VOLUME_CURRENT  =  30,                     // 未実行ボリュームによって並び替える
   SORT_BY_ORDER_PROFIT_FULL     =  31,                     // 利益+手数料+スワップによって並び替える
   SORT_BY_ORDER_PRICE_STOP_LIMIT=  32,                     // ストップリミット注文が発動した際のリミット注文価格によって並び替える
   //--- 文字列型プロパティによって並び替える
   SORT_BY_ORDER_SYMBOL          =  ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL,// 銘柄によって並び替える
   SORT_BY_ORDER_COMMENT         =  34,                     // コメントによって並び替える
   SORT_BY_ORDER_EXT_ID          =  35                      // 外部取引システムの注文IDによって並び替える
  };
//+------------------------------------------------------------------+

: リストはそのリスト内での検索に使用されるのと同じ値で並び替えられる必要があるため、並び替え用の列挙型メンバのインデックスはプロパティの列挙型メンバのインデックスと一致する必要があります。

ご覧のとおり、ORDER_PROP_DIRECTION並び替えプロパティはライブラリによって使用されるサービスプロパティであるため、以前に追加した他のカスタムプロパティ同様、このリストではスキップされています。ただし、並べ替えが必要な可能性があり、これがこのプロパティが残っている理由です。

これで、CHistoryCollectionクラスのコンストラクタを実装できます。

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                           |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\DELib.mqh"
//+------------------------------------------------------------------+
//| 過去の注文と取引のコレクション                                         |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // 過去の注文と取引のリスト
   int               m_index_order;          // ターミナルの履歴リストからコレクションに追加された最後の注文のインデックス(MQL4、MQL5)
   int               m_index_deal;           // ターミナルの履歴リストからコレクションに追加された最後の取引のインデックス(MQL5)
   int               m_delta_order;          // 過去の注文数と比較した注文数の違い
   int               m_delta_deal;           // 過去の取引数と比較した取引数の違い
public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//| コンストラクタ                                                     |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection(void) : m_index_deal(0), 
                                               m_delta_deal(0), 
                                               m_index_order(0),
                                               m_delta_order(0) 
  {
   m_list_all_orders.Sort(SORT_BY_ORDER_TIME_CLOSE);
  }
//+------------------------------------------------------------------+

リストを分析しましょう。クラスコンストラクタは新しく追加された列挙体の値のみを使用するので、Defines.mqhファイルをクラスファイルにインクルードする必要があります。
最初の記事で注文の抽象基本クラスを準備しながら、DELib.mqhサービス関数ライブラリを開発し、必要なすべての列挙とマクロ置換を含むDefines.mqhをインクルードしました。よって、サービス関数ライブラリをインクルードします
コンストラクタの初期化リストでは、すべてのインデックスおよび現在値と以前の値の差の値がリセットされ、コンストラクタ本体では終了時間による並び替えがデフォルトの並び替えとして指定されます

ここで、口座情報の収集を開始し、収集リストに保存します。これを行うには、口座履歴をループで調べ、リスト内の各注文を指定します。前のチェックと比較して注文数または取引数が変化した場合は、取引イベント発生のフラグを設定します。口座履歴で発生した新しいイベントに関するメッセージは外部プログラムに送信する必要があります。プライベートクラスセクションで取引イベントフラグを宣言して、パブリッククラスセクションで公開コレクションの履歴コレクションを更新するためのRefresh()メソッドを宣言します。

//+------------------------------------------------------------------+
//| 過去の注文と取引のコレクション                                         |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // 過去の注文と取引のリスト
   bool              m_is_trade_event;       // 取引イベントフラグ
   int               m_index_order;          // ターミナルの履歴リストからコレクションに追加された最後の注文のインデックス(MQL4、MQL5)
   int               m_index_deal;           // ターミナルの履歴リストからコレクションに追加された最後の取引のインデックス(MQL5)
   int               m_delta_order;          // 過去の注文数と比較した注文数の違い
   int               m_delta_deal;           // 過去の取引数と比較した取引数の違い
public:
                     CHistoryCollection();
   //--- 注文リストを更新し、新しい注文の数に関するデータを入力し、取引イベントフラグを設定する
   void              Refresh(void);
  };
//+------------------------------------------------------------------+

収集された注文のリストの更新を実装するには、全履歴データを要求するためのもう1つのマクロ置換が必要です。これにはHistorySelect()関数が使用されます。必要なデータの開始日と終了日は、そのパラメータで渡されます。すべての口座履歴を取得するには、最初の日付を0として渡し、最後の日付をTimeCurrent()として渡す必要があります。ただし、その場合、返された履歴データは不完全な場合があります。これを回避するには、TimeCurrent()の代わりに現在のサーバ時間以降の日付を入力してください。ここでは可能な最大値「31.12.3000 23:59:59」を入力します。ここでのもう1つの利点は、カスタム銘柄にそのような日付が含まれていても履歴を取得できることです。

Defines.mqhファイルに新しいマクロ置換を挿入しましょう。

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
//+------------------------------------------------------------------+
//| マクロ置換                                                         |
//+------------------------------------------------------------------+
#define COUNTRY_LANG   ("Russian")              // 国の言語
#define DFUN           (__FUNCTION__+": ")      //「関数の説明」
#define END_TIME       (D'31.12.3000 23:59:59') // 口座履歴データの最終リクエスト時間
//+------------------------------------------------------------------+

ここで、終了時間としてTimeCurrent()のかわりにEND_TIMEマクロを入力します。

以下はコレクション注文リストの更新を実装したものです。

//+------------------------------------------------------------------+
//| 注文リストを更新する                                                |
//+------------------------------------------------------------------+
void CHistoryCollection::Refresh(void)
  {
#ifdef __MQL4__
   int total=::OrdersHistoryTotal(),i=m_index_order;
   for(; i<total; i++)
     {
      if(!::OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)::OrderType();
      //--- 決済済みのポジいしょんおよび残高/クレジット操作
      if(order_type<ORDER_TYPE_BUY_LIMIT || order_type>ORDER_TYPE_SELL_STOP)
        {
         CHistoryOrder *order=new CHistoryOrder(::OrderTicket());
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
      else
        {
         //--- 削除された未決注文  
         CHistoryPending *order=new CHistoryPending(::OrderTicket());
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
     }
//---
   int delta_order=i-m_index_order;
   this.m_index_order=i;
   this.m_delta_order=delta_order;
   this.m_is_trade_event=(this.m_delta_order!=0 ?true : false);
//--- __MQL5__
#else 
   if(!::HistorySelect(0,END_TIME)) return;
//--- 注文
   int total_orders=::HistoryOrdersTotal(),i=m_index_order;
   for(; i<total_orders; i++)
     {
      ulong order_ticket=::HistoryOrderGetTicket(i);
      if(order_ticket==0) continue;
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::HistoryOrderGetInteger(order_ticket,ORDER_TYPE);
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL)
        {
         CHistoryOrder *order=new CHistoryOrder(order_ticket);
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
      else
        {
         CHistoryPending *order=new CHistoryPending(order_ticket);
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
     }
//--- 最後に追加された注文のインデックスと前回のチェックと比較した差を保存する
   int delta_order=i-this.m_index_order;
   this.m_index_order=i;
   this.m_delta_order=delta_order;
   
//--- 取引
   int total_deals=::HistoryDealsTotal(),j=m_index_deal;
   for(; j<total_deals; j++)
     {
      ulong deal_ticket=::HistoryDealGetTicket(j);
      if(deal_ticket==0) continue;
      CHistoryDeal *deal=new CHistoryDeal(deal_ticket);
      if(deal==NULL) continue;
      m_list_all_orders.InsertSort(deal);
     }
//--- 最後に追加された取引のインデックスと前回のチェックと比較した差を保存する
   int delta_deal=j-this.m_index_deal;
   this.m_index_deal=j;
   this.m_delta_deal=delta_deal;
//--- 履歴に新規イベントフラグを設定する
   this.m_is_trade_event=(this.m_delta_order+this.m_delta_deal);
#endif 
  }
//+------------------------------------------------------------------+

MQL4MQL5をチェックします。これはもう少し複雑なので、例としてMQL5を使用してコードを分析しましょう。

まず、口座履歴をすべてリクエストします。失敗した場合は、次のティックまで終了します。履歴リクエストが成功すると、注文と取引のリストの2つのリストが作成されます。

まず、すべての注文のリストに沿ってループで移動します。ループが移動し始める最初のインデックスは、前のループ操作の結果です(最初の開始時= 0)。これにより、履歴全体に沿ってリソース集約型のループで移動するのではなく、前回の確認以降に履歴に表示された新しい注文のみで移動できます。

次に注文チケットとそのタイプを取得します。文タイプチェックの結果(過去の成行注文または削除された 未決注文)に合わせて新しいオブジェクトを作成して、すぐに順番に並んだ形でコレクションリストに配置します(すでに終了時刻による並び替えがなされています)。

反復処理が完了したら、次のループの開始点として新しい注文インデックスを保存します。1つ前と現在のループの操作の結果の違いが新しく追加された注文の数です。
取引を処理するためのループは、取引をタイプ別に分割する必要がないこと以外は同じです。代わりに、取引オブジェクトは直ちにコレクションリストに追加できます。

MQL4コードでのループは、口座で利用可能な履歴全体からループが取得されることを除けば、ほぼ同じです。履歴の長さは、ターミナルの[履歴]タブでユーザーが指定します。つまり、プログラムで必要な場合に、履歴全体を確実に利用できるようにするかどうかはユーザー次第です。他の選択肢は、全履歴を取得するためにWinAPIを使用することです。これは本稿の範囲を超えています。

ループが完了すると、新しい注文と取引の数が確認されます。数がゼロより大きい場合、発生した取引イベントのフラグが設定されます

今回の場合、履歴注文のさまざまなオブジェクトがステータス別に作成されることを除いて前半のテストEAで実装されているものと同様の履歴コレクションクラスでデータの取得を実装しました。その動作を確認するために、外部(ここでは、このライブラリを使用することになっているプログラム(テストEA))で作成された過去の注文のコレクションリストを取得する必要があります。

これを行うには、CHistoryCollectionクラスのpublicセクションに、パラメータなしでGetList()メソッドを追加します(次の記事では、パラメータ付きリストを受け取るためのメソッドを追加します)。
//+------------------------------------------------------------------+
//| 過去の注文と取引のコレクション                                       |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // 過去の注文と取引のリスト
   bool              m_is_trade_event;       // 取引イベントフラグ
   int               m_index_order;          // ターミナルの履歴リストからコレクションに追加された最後の注文のインデックス(MQL4、MQL5)
   int               m_index_deal;           // ターミナルの履歴リストからコレクションに追加された最後の取引のインデックス(MQL5)
   int               m_delta_order;          // 過去の注文数と比較した注文数の違い
   int               m_delta_deal;           // 過去の取引数と比較した取引数の違い
public:
   //--- 完全なコレクションリストを「そのまま」で返す
   CArrayObj*        GetList(void)           { return &m_list_all_orders;  }
//--- コンストラクタ
                     CHistoryCollection();
   //--- 注文リストを更新し、新しい注文の数に関するデータを入力し、取引イベントを設定する
   void              Refresh(void);
  };
//+------------------------------------------------------------------+

コードからわかるように、(オブジェクト自体ではなく)リストへのポインタが返されます。プログラム内のリストを使用するにはこれで十分です。ただし、これはライブラリを素早く簡単に使用するには不十分です。 次の記事では、必要に応じて必要なデータに簡単にアクセスできるようにします。今後の記事では、カスタムプログラムでライブラリを操作するための特別な関数を作成することによって、アクセスをさらに簡単にするつもりです。

リストがどのように書き入れられるかを見てみましょう。これには、小さいEAを作成します。TestDoEasyフォルダ(第1部ですでに作成済み)に、Part02サブフォルダを作成します。これには、TestDoEasyPart02という2番目のテスト用EAのファイルが含まれ、作成されたコレクションをそれに接続します

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart02.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//--- include
#include <DoEasy\Collections\HistoryCollection.mqh>
//+------------------------------------------------------------------+
//| エキスパート初期化関数                                              |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| エキスパート初期化解除関数                                           |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| エキスパートティック関数                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

リストには1つのCOrder型の親から継承されたさまざまなタイプのオブジェクトが格納されているので、選択した注文オブジェクトの説明の表示を仕訳帳に実装しましょう。これを行うには、入力の表示された注文タイプの選択列挙体と、口座データが読み取られるコレクションオブジェクト作成します。

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart02.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//--- include
#include <DoEasy\Collections\HistoryCollection.mqh>
//--- 列挙体
enum ENUM_TYPE_ORDERS
  {
   TYPE_ORDER_MARKET,   // 成行注文
   TYPE_ORDER_PENDING,  // 未決注文
   TYPE_ORDER_DEAL      // 取引
  };
//--- 入力パラメータ
input ENUM_TYPE_ORDERS  InpOrderType   =  TYPE_ORDER_DEAL;  // タイプを表示する
//--- グローバル変数
CHistoryCollection history;
//+------------------------------------------------------------------+
//| エキスパート初期化関数                                              |
//+------------------------------------------------------------------+

ライブラリ記述の最初の部分からの前のテストEA同様、OnInit()ハンドラで口座履歴を読み取り、注文に関する情報をループで操作ログに表示します。

//+------------------------------------------------------------------+
//| エキスパート初期化関数                                              |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 履歴を更新する
   history.Refresh();
//--- 完全なコレクションリストへのポインタを取得する
   CArrayObj* list=history.GetList();
   if(list==NULL)
     {
      Print("Could not get collection list");
      return INIT_FAILED;
     }
   int total=list.Total();
   for(int i=0;i<total;i++)
     {
      //--- リストから注文を取得する
      COrder* order=list.At(i);
      if(order==NULL) continue;
      //--- これが取引の場合
      if(order.Status()==ORDER_STATUS_DEAL && InpOrderType==TYPE_ORDER_DEAL)
         order.Print();
      //--- これが過去の成行注文の場合
      if(order.Status()==ORDER_STATUS_HISTORY_ORDER && InpOrderType==TYPE_ORDER_MARKET)
         order.Print();
      //--- これが削除された未決注文の場合
      if(order.Status()==ORDER_STATUS_HISTORY_PENDING && InpOrderType==TYPE_ORDER_PENDING)
         order.Print();
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

ここでは、コレクションリストへのポインタを作成し、そこで作成されたGetList()メソッドを使用してCHistoryCollectionから受け取ります。
次に、ループ内で、注文オブジェクトをリストから取得し、そのステータスと操作ログでデータを表示する許可をEAの設定で確認します。
結果によって、操作ログにデータを表示するしないを決めます。
リストからはCOrder基本オブジェクトを取得しますが、操作ログには、基本注文の子孫に固有のデータ(注文がその継承されたプロパティのみをサポートするというフラグを返す仮想メソッドで再定義された市場注文、未決注文、取引)のみが表示されます。

コンパイルしてEAを起動します。操作ログには、選択した注文タイプと取引タイプに関するデータが表示されます。


表示されているプロパティタイプをよく見ると、MQL5の注文では一般的ではないプロパティ(ポイント単位での収益、スワップ、コミッション、利益)が表示されています。

作成済みのオブジェクトにいくつかの改良と追加を加えましょう。

サポートされていないプロパティポイント単位でのMQL5利益をCHistoryOrderクラスのSupportProperty(ENUM_ORDER_PROP_INTEGERプロパティ)メソッドに追加します。

//+------------------------------------------------------------------+
//| 注文が渡されたプロパティをサポートする場合は「true」を返し、             |
//| その他の場合は「false」を返す                                       |
//+------------------------------------------------------------------+
bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP       || 
      property==ORDER_PROP_DEAL_ENTRY     || 
      property==ORDER_PROP_TIME_UPDATE    || 
      property==ORDER_PROP_TIME_UPDATE_MSC
      #ifdef __MQL5__                     ||
      property==ORDER_PROP_PROFIT_PT
      #endif                        
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

注文による実数プロパティのサポートを返し、さらに別の仮想メソッドを追加します。

//+------------------------------------------------------------------+
//| 過去の成行注文                                                     |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
public:
   //--- コンストラクタ
                     CHistoryOrder(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_ORDER,ticket) {}
   //--- 注文のサポートされた整数型プロパティ
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
   //--- 注文のサポートされた実数型プロパティ
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
  };
//+------------------------------------------------------------------+

実装します。

//+------------------------------------------------------------------+
//| 注文が渡されたプロパティをサポートする場合は「true」を返し、            |
//| その他の場合は「false」を返す                                       |
//+------------------------------------------------------------------+
bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
#ifdef __MQL5__
   if(property==ORDER_PROP_PROFIT      || 
      property==ORDER_PROP_PROFIT_FULL || 
      property==ORDER_PROP_SWAP        || 
      property==ORDER_PROP_COMMISSION  ||
      property==ORDER_PROP_PRICE_STOP_LIMIT
     ) return false;
#endif 
   return true;
  }
//+------------------------------------------------------------------+

MQL5の場合、利益、スワップ、コミッション、全利益、ストップリミット注文価格はサポートされていません。MQL4およびMQL5の他の実数注文プロパティでは、注文の実数プロパティサポートのフラグを返します

MQL5注文にはORDER_STATEプロパティもあります。これはENUM_ORDER_STATE列挙体で設定された注文ステータスです。
整数注文プロパティのリストに追加します(Defines.mqhファイルのENUM_ORDER_PROP_INTEGER列挙体)。

//+------------------------------------------------------------------+
//| 注文、取引、ポジションの整数型プロパティ                              |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // 注文チケット
   ORDER_PROP_MAGIC,                                        // 注文のマジックナンバー
   ORDER_PROP_TIME_OPEN,                                    // 開始時間(MQL5取引時間)
   ORDER_PROP_TIME_CLOSE,                                   // 終了時間(MQL5実行または削除時間 - ORDER_TIME_DONE)
   ORDER_PROP_TIME_OPEN_MSC,                                // ミリ秒での開始時間(ミリ秒でのMQL5取引時間)
   ORDER_PROP_TIME_CLOSE_MSC,                               // ミリ秒での終了時間(ミリ秒でのMQL5実行または削除時間 - ORDER_TIME_DONE_MSC)
   ORDER_PROP_TIME_EXP,                                     // 注文有効期限(未決注文用)
   ORDER_PROP_STATUS,                                       // 注文ステータス(ENUM_ORDER_STATUS列挙体から)
   ORDER_PROP_TYPE,                                         // 注文タイプ(MQL5取引タイプ)
   ORDER_PROP_DIRECTION,                                    // 方向(買または売)
   ORDER_PROP_REASON,                                       // 取引/注文/ポジション理由またはソース
   ORDER_PROP_STATE,                                        // 注文ステータス(ENUM_ORDER_STATE列挙体から)
   ORDER_PROP_POSITION_ID,                                  // ポジションID
   ORDER_PROP_POSITION_BY_ID,                               // 反対側のポジションID
   ORDER_PROP_DEAL_ORDER,                                   // 取引が基づく注文
   ORDER_PROP_DEAL_ENTRY,                                   // 取引の方向 – IN、OUT、IN/OUT
   ORDER_PROP_TIME_UPDATE,                                  // ポジション変更時間(秒)
   ORDER_PROP_TIME_UPDATE_MSC,                              // ポジション変更時間(ミリ秒)
   ORDER_PROP_TICKET_FROM,                                  // 親注文チケット
   ORDER_PROP_TICKET_TO,                                    // 派生注文チケット
   ORDER_PROP_PROFIT_PT,                                    // 利益(ポイント)
   ORDER_PROP_CLOSE_BY_SL,                                  // ストップロスによる決済のフラグ
   ORDER_PROP_CLOSE_BY_TP,                                  // テイクプロフィットによる決済のフラグ
  }; 
#define ORDER_PROP_INTEGER_TOTAL    (23)                    // 整数プロパティの総数
//+------------------------------------------------------------------+

ORDER_PROP_INTEGER_TOTALマクロ置換で、注文の整数プロパティの数を22から23に変更し、正確な 「アドレス」を計算するために使用します。 同じファイルで、新しい並べ替え基準に新しいプロパティを追加して、この新しいプロパティで並べ替えを行い、 その後列挙型が変更された場合により便利なインデックスの計算を実装できるようにします。

//+------------------------------------------------------------------+
//| 注文と取引の並べ替えの可能な基準                                     |
//+------------------------------------------------------------------+
#define FIRST_DBL_PROP              (ORDER_PROP_INTEGER_TOTAL)
#define FIRST_STR_PROP              (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL)
enum ENUM_SORT_ORDERS_MODE
  {
   //--- 整数型プロパティによって並び替える
   SORT_BY_ORDER_TICKET          =  0,                      // 注文チケットによって並び替える
   SORT_BY_ORDER_MAGIC           =  1,                      // 注文マジックナンバーによって並び替える
   SORT_BY_ORDER_TIME_OPEN       =  2,                      // 注文開始時間によって並び替える
   SORT_BY_ORDER_TIME_CLOSE      =  3,                      // 注文終了時間によって並び替える
   SORT_BY_ORDER_TIME_OPEN_MSC   =  4,                      // ミリ秒での注文開始時間によって並び替える
   SORT_BY_ORDER_TIME_CLOSE_MSC  =  5,                      // ミリ秒での注文終了時間によって並び替える
   SORT_BY_ORDER_TIME_EXP        =  6,                      // 注文有効期限によって並び替える
   SORT_BY_ORDER_STATUS          =  7,                      // 注文ステータス(市場注文/未決注文/取引)によって並び替える
   SORT_BY_ORDER_TYPE            =  8,                      // 注文タイプによって並び替える
   SORT_BY_ORDER_REASON          =  10,                     // 取引/注文/ポジション理由またはソースによって並び替える
   SORT_BY_ORDER_STATE           =  11,                     // 注文ステータス
   SORT_BY_ORDER_POSITION_ID     =  12,                     // ポジションIDで並び替える
   SORT_BY_ORDER_POSITION_BY_ID  =  13,                     // 反対のポジションIDで並び替える
   SORT_BY_ORDER_DEAL_ORDER      =  14,                     // 取引が基づいている注文で並び替える
   SORT_BY_ORDER_DEAL_ENTRY      =  15,                     // 取引方向で並び替える(IN, OUT, IN/OUT)
   SORT_BY_ORDER_TIME_UPDATE     =  16,                     // 秒単位でのポジション変化で並び替える
   SORT_BY_ORDER_TIME_UPDATE_MSC =  17,                     // ミリ秒単位でのポジション変化で並び替える
   SORT_BY_ORDER_TICKET_FROM     =  18,                     // 親注文チケットで並び替える
   SORT_BY_ORDER_TICKET_TO       =  19,                     // 派生注文チケットで並び替える
   SORT_BY_ORDER_PROFIT_PT       =  20,                     // ポイント単位での利益で並び替える
   SORT_BY_ORDER_CLOSE_BY_SL     =  21,                     // 注文の「ストップロスによる決済」フラグによって並び替える
   SORT_BY_ORDER_CLOSE_BY_TP     =  22,                     // 注文の「テイクプロフィットによる決済」フラグによって並び替える
   //--- 実数型プロパティによって並び替える
   SORT_BY_ORDER_PRICE_OPEN      =  FIRST_DBL_PROP,         // 始値によって並び替える
   SORT_BY_ORDER_PRICE_CLOSE     =  FIRST_DBL_PROP+1,       // 終値によって並び替える
   SORT_BY_ORDER_SL              =  FIRST_DBL_PROP+2,       // ストップロス価格によって並び替える
   SORT_BY_ORDER_TP              =  FIRST_DBL_PROP+3,       // テイクプロフィット価格によって並び替える
   SORT_BY_ORDER_PROFIT          =  FIRST_DBL_PROP+4,       // 利益によって並び替える
   SORT_BY_ORDER_COMMISSION      =  FIRST_DBL_PROP+5,       // 手数料によって並び替える
   SORT_BY_ORDER_SWAP            =  FIRST_DBL_PROP+6,       // スワップによって並び替える
   SORT_BY_ORDER_VOLUME          =  FIRST_DBL_PROP+7,       // ボリュームによって並び替える
   SORT_BY_ORDER_VOLUME_CURRENT  =  FIRST_DBL_PROP+8,       // 未実行のボリュームによって並び替える
   SORT_BY_ORDER_PROFIT_FULL     =  FIRST_DBL_PROP+9,       // 利益+手数料+スワップによって並び替える
   SORT_BY_ORDER_PRICE_STOP_LIMIT=  FIRST_DBL_PROP+10,      // ストップリミット注文が発動した際のリミット注文価格によって並び替える
   //--- 文字列型プロパティによって並び替える
   SORT_BY_ORDER_SYMBOL          =  FIRST_STR_PROP,         // 銘柄によって並び替える
   SORT_BY_ORDER_COMMENT         =  FIRST_STR_PROP+1,       // コメントによって並び替える
   SORT_BY_ORDER_EXT_ID          =  FIRST_STR_PROP+2        // 外部取引システムの注文IDによって並び替える
  };
//+------------------------------------------------------------------+

Order.mqhファイルのCOrder抽象注文クラスのprotectedセクションで、ENUM_ORDER_STATE列挙からそのステータスを注文プロパティに書き込むOrderState()メソッドを宣言します。

protected:
   //--- 保護されたパラメトリックコンストラクタ
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);

   //--- 選択した注文の整数型プロパティをそのパラメータから取得して返す
   long              OrderMagicNumber(void)        const;
   long              OrderTicket(void)             const;
   long              OrderTicketFrom(void)         const;
   long              OrderTicketTo(void)           const;
   long              OrderPositionID(void)         const;
   long              OrderPositionByID(void)       const;
   long              OrderOpenTimeMSC(void)        const;
   long              OrderCloseTimeMSC(void)       const;
   long              OrderType(void)               const;
   long              OrderState(void)              const;
   long              OrderTypeByDirection(void)    const;
   long              OrderTypeFilling(void)        const;
   long              OrderTypeTime(void)           const;
   long              OrderReason(void)             const;
   long              DealOrder(void)               const;
   long              DealEntry(void)               const;
   bool              OrderCloseByStopLoss(void)    const;
   bool              OrderCloseByTakeProfit(void)  const;
   datetime          OrderOpenTime(void)           const;
   datetime          OrderCloseTime(void)          const;
   datetime          OrderExpiration(void)         const;
   datetime          PositionTimeUpdate(void)      const;
   datetime          PositionTimeUpdateMSC(void)   const;

実装を追加します。

//+------------------------------------------------------------------+
//| 注文状態を返す                                                     |
//+------------------------------------------------------------------+
long COrder::OrderState(void) const
  {
#ifdef __MQL4__              
   return ORDER_STATE_FILLED;
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_STATE); break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_STATE);                 break;
      case ORDER_STATUS_MARKET_ACTIVE     : 
      case ORDER_STATUS_DEAL              : 
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+

MQL4の場合は、今のところ注文の完全な実行を返しましょう。MQL5の場合は、注文状態によって、0(取引かポジションがある場合)または注文状態(成行注文か未決注文がある場合)を返します。

COrderクラスのpublicセクションで、注文状況の説明を返すメソッドを宣言します。

//+------------------------------------------------------------------+
//| 注文オブジェクトプロパティの説明                                     |
//+------------------------------------------------------------------+
   //--- 注文の(1)整数、(2)実数、(3)文字列プロパティの説明を取得する
   string            GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_STRING property);
   //--- 注文状態名を返す
   string            StatusDescription(void)    const;
   //--- 注文またはポジションの名前を返す
   string            TypeDescription(void)      const;
   //--- 注文状態の説明を返す
   string            StateDescription(void)     const;
   //--- 取引方向名を返す           
   string            DealEntryDescription(void) const;
   //--- 注文またはポジションの方向の種類を返す   
   string            DirectionDescription(void) const;
   //--- 注文プロパティの説明を操作ログに送信する(full_prop=true  - すべてのプロパティ、false-サポートされているプロパティのみ)
   void              Print(const bool full_prop=false);

実装します。

//+------------------------------------------------------------------+
//| 注文状態の説明を返す                                                |
//+------------------------------------------------------------------+
string COrder::StateDescription(void) const
  {
   if(this.Status()==ORDER_STATUS_DEAL || this.Status()==ORDER_STATUS_MARKET_ACTIVE)
      return "";                       
   else switch(this.StateOrder())
     {
      case ORDER_STATE_STARTED         :  return TextByLanguage("Ордер проверен на корректность, но еще не принят брокером","Order checked for correctness, but not yet accepted by broker");
      case ORDER_STATE_PLACED          :  return TextByLanguage("Ордер принят","Order accepted");
      case ORDER_STATE_CANCELED        :  return TextByLanguage("Ордер снят клиентом","Order withdrawn by client");
      case ORDER_STATE_PARTIAL         :  return TextByLanguage("Ордер выполнен частично","Order filled partially");
      case ORDER_STATE_FILLED          :  return TextByLanguage("Ордер выполнен полностью","Order filled");
      case ORDER_STATE_REJECTED        :  return TextByLanguage("Ордер отклонен","Order rejected");
      case ORDER_STATE_EXPIRED         :  return TextByLanguage("Ордер снят по истечении срока его действия","Order withdrawn upon expiration");
      case ORDER_STATE_REQUEST_ADD     :  return TextByLanguage("Ордер в состоянии регистрации (выставление в торговую систему)","Order in state of registration (placing in trading system)");
      case ORDER_STATE_REQUEST_MODIFY  :  return TextByLanguage("Ордер в состоянии модификации","Order in state of modification.");
      case ORDER_STATE_REQUEST_CANCEL  :  return TextByLanguage("Ордер в состоянии удаления","Order in deletion state");
      default                          :  return TextByLanguage("Неизвестное состояние","Unknown state");
     }
  }
//+------------------------------------------------------------------+

取引かポジションの場合は空の文字列を返し、そのほかの場合は、注文状態を確認してその説明を返します。

注文状態の説明をGetPropertyDescription(ENUM_ORDER_PROP_INTEGER property)メソッドの実装に追加します。

//+------------------------------------------------------------------+
//| 注文の整数型プロパティの説明を返す                                    |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property)
  {
   return
     (
   //--- 一般的なプロパティ
      property==ORDER_PROP_MAGIC             ?  TextByLanguage("Магик","Magic number")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET            ?  TextByLanguage("Тикет","Ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_FROM       ?  TextByLanguage("Тикет родительского ордера","Ticket of parent order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_TO         ?  TextByLanguage("Тикет наследуемого ордера","Inherited order ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN         ?  TextByLanguage("Время открытия","Open time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_CLOSE        ?  TextByLanguage("Время закрытия","Close time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_EXP          ?  TextByLanguage("Дата экспирации","Expiration date")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Не задана",": Not set") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS))
         )  :
      property==ORDER_PROP_TYPE              ?  TextByLanguage("Тип","Type")+": "+this.TypeDescription()                   :
      property==ORDER_PROP_DIRECTION         ?  TextByLanguage("Тип по направлению","Type by direction")+": "+this.DirectionDescription() :
      
      property==ORDER_PROP_REASON            ?  TextByLanguage("Причина","Reason")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetReasonDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_ID       ?  TextByLanguage("Идентификатор позиции","Position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ORDER        ?  TextByLanguage("Сделка на основании ордера","Deal by order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ENTRY        ?  TextByLanguage("Направление сделки","Deal direction")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetEntryDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_BY_ID    ?  TextByLanguage("Идентификатор встречной позиции","Opposite position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN_MSC     ?  TextByLanguage("Время открытия в милисекундах","Open time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_CLOSE_MSC    ?  TextByLanguage("Время закрытия в милисекундах","Close time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_UPDATE       ?  TextByLanguage("Время изменения позиции","Position change time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ?::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS) : "0")
         )  :
      property==ORDER_PROP_TIME_UPDATE_MSC   ?  TextByLanguage("Время изменения позиции в милисекундах","Position change time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ?(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property)) : "0")
         )  :
      property==ORDER_PROP_STATE             ?  TextByLanguage("Состояние","Statе")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": \""+this.StateDescription()+"\""
         )  :
   //--- 追加のプロパティ
      property==ORDER_PROP_STATUS            ?  TextByLanguage("Статус","Status")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": \""+this.StatusDescription()+"\""
         )  :
      property==ORDER_PROP_PROFIT_PT         ?  TextByLanguage("Прибыль в пунктах","Profit in points")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_CLOSE_BY_SL       ?  TextByLanguage("Закрытие по StopLoss","Close by StopLoss")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ?TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==ORDER_PROP_CLOSE_BY_TP       ?  TextByLanguage("Закрытие по TakeProfit","Close by TakeProfit")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ?TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

これで改善が完了です。

このライブラリは「ライブ」で開発されており、ベータ版なので、後でさまざまな改訂、変更、追加を行われる場合があります。

次の段階

次回の記事では、サポートされている基準のいずれかを使用して、注文、取引、およびポジションを簡単に選択および並び替えするためのクラスを開発し、成行注文およびポジションのコレクションを作成します。

現在のバージョンのライブラリのすべてのファイルは、テスト用EAファイルと一緒に以下に添付されているので、テストするにはダウンロードしてください。
質問、コメント、提案はコメント欄にお願いします。

目次に戻る