DoEasyライブラリでの価格(第64部): 板情報、DOMスナップショットのクラスおよびスナップショットシリーズオブジェクト

Artyom Trishkin | 5 5月, 2021

内容


概念

前の記事では、板情報(DOM)抽象注文オブジェクトとその子孫のクラスを作成しました。これらのオブジェクトの多数は、OnBookEvent()ハンドラがアクティブ化された瞬間に、MarketBookGet()関数が1回呼び出されたときに取得された1つのDOMスナップショットを構成します。MarketBookGet()関数によって取得されたデータはMqlBookInfo構造体配列に設定されます。取得したデータに基づいて、MqlBookInfo構造体配列で取得したすべての注文を格納するDOMスナップショットオブジェクトを作成できます。つまり、前述の構造体配列のデータはDOMスナップショットを形成し、各構造体メンバーは単一のDOM注文オブジェクトで表されます。OnBookEvent()ハンドラがアクティブ化するたびに、別のDOMスナップショットが作成されてDOMスナップショットシリーズクラスのオブジェクトに入力されます。
標準ライブラリのCObjectクラスとその子孫のインスタンスへのポインタの動的配列のクラスは、DOMスナップショットオブジェクトを格納するリストとして使用されます。リストのサイズは、指定された数のオブジェクトによって制限されます。デフォルトでは、リストのサイズは200,000 DOMスナップショットオブジェクトを超えません。これは、約1〜2取引日をカバーするはずです。このようなDOMスナップショットシリーズリストは、プログラムで使用される銘柄ごとに作成されます。その結果、そのようなリストはすべてDOMデータコレクションに保存されます。

ここでは、単一銘柄のDOMスナップショットオブジェクトのクラスと、単一銘柄のDOMスナップショットシリーズのクラスの2つを作成します。次の記事では、DOMスナップショットシリーズコレクションのクラスを作成してテストします。


ライブラリクラスの改善

\MQL5\Include\DoEasy\Data.mqhに、ライブラリの新しいメッセージインデックスを追加します

//--- CMarketBookOrd
   MSG_MBOOK_ORD_TEXT_MBOOK_ORD,                      // Order in DOM
   MSG_MBOOK_ORD_VOLUME,                              // Volume
   MSG_MBOOK_ORD_VOLUME_REAL,                         // Extended accuracy volume
   MSG_MBOOK_ORD_STATUS_BUY,                          // Buy side
   MSG_MBOOK_ORD_STATUS_SELL,                         // Sell side
   MSG_MBOOK_ORD_TYPE_SELL,                           // Sell order
   MSG_MBOOK_ORD_TYPE_BUY,                            // Buy order 
   MSG_MBOOK_ORD_TYPE_SELL_MARKET,                    // Sell order by Market
   MSG_MBOOK_ORD_TYPE_BUY_MARKET,                     // Buy order by Market

//--- CMarketBookSnapshot
   MSG_MBOOK_SNAP_TEXT_SNAPSHOT,                      // DOM snapshot
   
//--- CMBookSeries
   MSG_MBOOK_SERIES_TEXT_MBOOKSERIES,                 // DOM snapshot series
   
  };
//+------------------------------------------------------------------+

また、新しく追加されたインデックスに対応するテキストも追加します。

//--- CMarketBookOrd
   {"Заявка в стакане цен","Order in Depth of Market"},
   {"Объем","Volume"},
   {"Объем c повышенной точностью","Volume Real"},
   {"Сторона Buy","Buy side"},
   {"Сторона Sell","Sell side"},
   {"Заявка на продажу","Sell order"},
   {"Заявка на покупку","Buy order"},
   {"Заявка на продажу по рыночной цене","Sell order at market price"},
   {"Заявка на покупку по рыночной цене","Buy order at market price"},
   
//--- CMarketBookSnapshot
   {"Снимок стакана цен","Depth of Market Snapshot"},
   
//--- CMBookSeries
   {"Серия снимков стакана цен","Series of shots of the Depth of Market"},
   
  };
//+---------------------------------------------------------------------+

シリーズリストで必要なDOMスナップショットオブジェクトを検索するときに時間による並べ替え基準を指定できるようにするには、DOM注文オブジェクトに新しいプロパティ(ミリ秒単位のスナップショットを受信する時間)を追加する必要があります。注文自体にはそのようなプロパティはありませんが、DOMスナップショットを受信した時間を追跡することはできます。単一の整数プロパティ(ミリ秒単位のスナップショットを取得する時間)を含むDOMスナップショットシリーズリストに新しい列挙が導入されるのを避けるために、このプロパティをDOM注文オブジェクトプロパティに追加しましょう。スナップショットを取得する時間は、単一スナップショットオブジェクトの各注文に割り当てられます。この新しく更新された定数を使用して、シリーズリストの検索と並べ替えを行います。

\MQL5\Include\DoEasy\Defines.mqhで、DOMスナップショットシリーズのパラメータを入力して、必要なデータ日数とリスト内のスナップショットの数の可能な最大値を設定できるようにします。

//--- Tick series parameters
#define TICKSERIES_DEFAULT_DAYS_COUNT  (1)                        // Required number of days for tick data in default series
#define TICKSERIES_MAX_DATA_TOTAL      (200000)                   // Maximum number of stored tick data of a single symbol
//--- Parameters of the DOM snapshot series
#define MBOOKSERIES_DEFAULT_DAYS_COUNT (1)                        // The default required number of days for DOM snapshots in the series
#define MBOOKSERIES_MAX_DATA_TOTAL     (200000)                   // Maximum number of stored DOM snapshots of a single symbol
//+------------------------------------------------------------------+

最初のパラメータ(日数)はまだ使用しませんが、後に、データをティックデータの日数にリンクします。現在、2番目のパラメータ(DOMスナップショットデータの可能な最大量)のみを使用します。

同じファイルで、新しい整数DOM注文オブジェクトプロパティ(ミリ秒単位の時間)を追加し、整数オブジェクトプロパティの数を4まで増やします

//+------------------------------------------------------------------+
//| Integer properties of DOM order                                  |
//+------------------------------------------------------------------+
enum ENUM_MBOOK_ORD_PROP_INTEGER
  {
   MBOOK_ORD_PROP_STATUS = 0,                         // Order status
   MBOOK_ORD_PROP_TYPE,                               // Order type
   MBOOK_ORD_PROP_VOLUME,                             // Order volume
   MBOOK_ORD_PROP_TIME_MSC,                           // Time of making a DOM snapshot in milliseconds
  }; 
#define MBOOK_ORD_PROP_INTEGER_TOTAL (4)              // Total number of integer properties
#define MBOOK_ORD_PROP_INTEGER_SKIP  (0)              // Number of integer DOM properties not used in sorting
//+------------------------------------------------------------------+

新しい整数プロパティを追加したので、整数プロパティで並べ替えるための新しい基準も追加する必要があります。

//+------------------------------------------------------------------+
//| Possible sorting criteria of DOM orders                          |
//+------------------------------------------------------------------+
#define FIRST_MB_DBL_PROP  (MBOOK_ORD_PROP_INTEGER_TOTAL-MBOOK_ORD_PROP_INTEGER_SKIP)
#define FIRST_MB_STR_PROP  (MBOOK_ORD_PROP_INTEGER_TOTAL-MBOOK_ORD_PROP_INTEGER_SKIP+MBOOK_ORD_PROP_DOUBLE_TOTAL-MBOOK_ORD_PROP_DOUBLE_SKIP)
enum ENUM_SORT_MBOOK_ORD_MODE
  {
//--- Sort by integer properties
   SORT_BY_MBOOK_ORD_STATUS = 0,                      // Sort by order status
   SORT_BY_MBOOK_ORD_TYPE,                            // Sort by order type
   SORT_BY_MBOOK_ORD_VOLUME,                          // Sort by order volume
   SORT_BY_MBOOK_ORD_TIME_MSC,                        // Sort by time of making a DOM snapshot in milliseconds
//--- Sort by real properties
   SORT_BY_MBOOK_ORD_PRICE = FIRST_MB_DBL_PROP,       // Sort by order price
   SORT_BY_MBOOK_ORD_VOLUME_REAL,                     // Sort by extended accuracy order volume
//--- Sort by string properties
   SORT_BY_MBOOK_ORD_SYMBOL = FIRST_MB_STR_PROP,      // Sort by symbol name
  };
//+------------------------------------------------------------------+

この定数は、現在開発されているDOMスナップショットシリーズオブジェクトのクラスでDOMスナップショットオブジェクトを並べ替えるために使用されるパラメータとして指定されます。

したがって、\MQL5\Include\DoEasy\Services\Select.mqhに格納されているCSelectクラスファイルでDOM注文オブジェクトを検索および並べ替えるメソッドが必要です。 これは、3番目の記事で詳しく説明されています。ここでは、DOM注文オブジェクトのプロパティによる検索と並べ替えを整理するために必要なこのクラスのすべての変更について説明するだけにします。

DOM抽象注文オブジェクトのクラスをファイルにインクルードします

//+------------------------------------------------------------------+
//|                                                       Select.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\Objects\Orders\Order.mqh"
#include "..\Objects\Events\Event.mqh"
#include "..\Objects\Accounts\Account.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "..\Objects\PendRequest\PendRequest.mqh"
#include "..\Objects\Series\SeriesDE.mqh"
#include "..\Objects\Indicators\Buffer.mqh"
#include "..\Objects\Indicators\IndicatorDE.mqh"
#include "..\Objects\Indicators\DataInd.mqh"
#include "..\Objects\Ticks\DataTick.mqh"
#include "..\Objects\Book\MarketBookOrd.mqh"
//+------------------------------------------------------------------+

クラス本体の最後で必要なすべてのメソッドを宣言します

//+------------------------------------------------------------------+
//| Methods of working with DOM data                                 |
//+------------------------------------------------------------------+
   //--- Return the list of DOM data with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion
   static CArrayObj *ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode);
   //--- Return the DOM data index in the list with the maximum value of (1) integer, (2) real and (3) string property of data
   static int        FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property);
   static int        FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property);
   static int        FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property);
   //--- Return the DOM data index in the list with the minimum value of (1) integer, (2) real and (3) string property of data
   static int        FindMBookMin(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property);
   static int        FindMBookMin(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property);
   static int        FindMBookMin(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property);
//---
  };
//+------------------------------------------------------------------+

クラス本体以外に実装します。

//+------------------------------------------------------------------+
//| Methods of working with DOM data                                 |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Return the list of DOM data with one of integer                  |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   int total=list_source.Total();
   for(int i=0; i<total; i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      long obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the list of DOM data with one of real                     |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      double obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the list of DOM data with one of string                   |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      string obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the DOM data index in the list                            |
//| with the maximum integer property value                          |
//+------------------------------------------------------------------+
int CSelect::FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CMarketBookOrd *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      long obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the DOM data index in the list                            |
//| with the maximum real property value                             |
//+------------------------------------------------------------------+
int CSelect::FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CMarketBookOrd *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      double obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the DOM data index in the list                            |
//| with the maximum string property value                           |
//+------------------------------------------------------------------+
int CSelect::FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CMarketBookOrd *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      string obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the DOM data index in the list                            |
//| with the minimum integer property value                          |
//+------------------------------------------------------------------+
int CSelect::FindMBookMin(CArrayObj* list_source,ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   int index=0;
   CMarketBookOrd *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      long obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the DOM data index in the list                            |
//| with the minimum real property value                             |
//+------------------------------------------------------------------+
int CSelect::FindMBookMin(CArrayObj* list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   int index=0;
   CMarketBookOrd *min_obj=NULL;
   int total=list_source.Total();
   if(total== 0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      double obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the DOM data index in the list                            |
//| with the minimum string property value                           |
//+------------------------------------------------------------------+
int CSelect::FindMBookMin(CArrayObj* list_source,ENUM_MBOOK_ORD_PROP_STRING property)
  {
   int index=0;
   CMarketBookOrd *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CMarketBookOrd *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      string obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+

メソッドの操作のロジックは、他のライブラリオブジェクト用に以前に作成したクラスの他のメソッドのロジックと似ています。したがって、メソッドの操作については説明しません。必要なすべてのデータはここにあります。

新しいパラメータ(DOMスナップショットを取得する時間)を導入したので、それはDOM抽象注文のオブジェクトに設定されます。DOM注文を記述するMqlBookInfo構造体には、時間パラメータがありません。これは、各DOM注文オブジェクトのスナップショットを自分で受信する時間を記述する必要があることを意味します。

これを実現するために、\MQL5\Include\DoEasy\Objects\Book\MarketBookOrd.mqhファイルに新しいpublicメソッドを作成します。

public:
//+-------------------------------------------------------------------+ 
//|Methods of a simplified access to the DOM request object properties|
//+-------------------------------------------------------------------+
//--- Set a snapshot time - all orders of a single DOM snapshot have the same name
   void              SetTime(const long time_msc)  { this.SetProperty(MBOOK_ORD_PROP_TIME_MSC,time_msc);                      }
   
//--- Return order (1) status, (2) type and (3) order volume

このメソッドは、取得した時間値をオブジェクトの新しいプロパティにミリ秒単位で設定するだけです。

DOM抽象注文クラスのパラメトリックコンストラクタでスナップショットを取得する時間を初期化します

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CMarketBookOrd::CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol)
  {
//--- Save symbol’s Digits
   this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS);
//--- Save integer object properties
   this.SetProperty(MBOOK_ORD_PROP_STATUS,status);
   this.SetProperty(MBOOK_ORD_PROP_TYPE,book_info.type);
   this.SetProperty(MBOOK_ORD_PROP_VOLUME,book_info.volume);
//--- Save real object properties
   this.SetProperty(MBOOK_ORD_PROP_PRICE,book_info.price);
   this.SetProperty(MBOOK_ORD_PROP_VOLUME_REAL,book_info.volume_real);
//--- Save additional object properties
   this.SetProperty(MBOOK_ORD_PROP_SYMBOL,(symbol==NULL || symbol=="" ? ::Symbol() : symbol));
//--- Order time is not present in the parameters and is considered in the DOM snapshot class. Reset the time
   this.SetProperty(MBOOK_ORD_PROP_TIME_MSC,0);
  }
//+------------------------------------------------------------------+

単一のDOMスナップショットに存在する各注文の時刻は、DOMスナップショットを受信した時点で設定されます。

MarketBookOrd.mqh DOM抽象注文クラスファイルとその子孫MarketBookBuy.mqhMarketBookBuyMarket.mqhMarketBookSell.mqhMarketBookSellMarket.mqhの仮想オブジェクト記述メソッドにいくつかの小さな変更が加えられました。

//--- Display a short description of the object in the journal
   virtual void      PrintShort(const bool symbol=false);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);

各メソッドは、オブジェクトの説明に銘柄名を表示する必要があることを示すフラグを取得しています。デフォルトでは、銘柄は注文オブジェクトの説明に表示されません。その理由は、注文オブジェクトはいわば独立しておらず、代わりに現在の記事で開発するクラスのDOMスナップショットの一部であるためです。銘柄はDOMスナップショットオブジェクトの説明のヘッダーにすでに表示されているため、すべての注文の説明と一緒にDOMスナップショットオブジェクトの説明を表示する場合に各注文の銘柄を表示することは冗長に見えます。

これらのメソッドの改良は、上記のすべてのクラスで同じように見えます。

CMarketBookOrdクラス:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookOrd::Header(const bool symbol=false)
  {
   return this.TypeDescription()+(symbol ? " \""+this.Symbol()+"\"" : "");
  }
//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CMarketBookOrd::PrintShort(const bool symbol=false)
  {
   ::Print(this.Header(symbol));
  }
//+------------------------------------------------------------------+

CMarketBookBuyCMarketBookBuyMarketCMarketBookSell CMarketBookSellMarket各クラス:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookBuy::Header(const bool symbol=false)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY)+(symbol ? " \""+this.Symbol() : "")+
          ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+

CMarketBookBuyMarketクラス:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookBuyMarket::Header(const bool symbol=false)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY_MARKET)+(symbol ? " \""+this.Symbol() : "")+
          ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+

CMarketBookSellクラス:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookSell::Header(const bool symbol=false)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL)+(symbol ? " \""+this.Symbol() : "")+
          ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+

CMarketBookSellMarketクラス:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookSellMarket::Header(const bool symbol=false)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL_MARKET)+(symbol ? " \""+this.Symbol() : "")+
          ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+

すべての子孫クラスでのこれらすべてのメソッドの宣言にフラグが追加されました

//--- Return the object short name
   virtual string    Header(const bool symbol=false);

デフォルトでは、銘柄はオブジェクトの説明に表示されません。


板情報スナップショットオブジェクトクラス

これで、DOMスナップショットオブジェクトクラスを開発する準備が整いました。実際、これは、OnBookEvent()ハンドラがアクティブ化されたときにMqlBookInfo構造体配列に渡されるDOM要求のリストです。ただし、クラス内の各配列要求は、CMarketBookOrdクラスオブジェクト(その子孫)によって表されます。これらはすべてCArrayObjリストに追加されます。これはCObjectクラスとその子孫の標準ライブラリのインスタンスへのポインタの動的配列のクラスです。DOMリクエストオブジェクトを格納するリストとは別に、このクラスは、すべてのライブラリオブジェクトに標準的なオブジェクトとそのリストを処理する機能(さまざまなプロパティによる検索と並べ替え)を備えており、プログラム内のDOM操作するときに統計データを便利に収集できます。

\MQL5\Include\DoEasy\Objects\Book\に、CMBookSnapshotクラスの新しいファイルMarketBookSnapshot.mqhを作成します。
すべてのCBaseObjライブラリオブジェクトの基本オブジェクトのクラスを基本クラスとして使用します

DOM抽象注文オブジェクトの子孫オブジェクトクラスのファイルをファイルにインクルードします

クラスリストとそのメソッドの実装について考えてみましょう。

//+------------------------------------------------------------------+
//|                                           MarketBookSnapshot.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\Select.mqh"
#include "MarketBookBuy.mqh"
#include "MarketBookSell.mqh"
#include "MarketBookBuyMarket.mqh"
#include "MarketBookSellMarket.mqh"
//+------------------------------------------------------------------+
//| "DOM snapshot" class                                             |
//+------------------------------------------------------------------+
class CMBookSnapshot : public CBaseObj
  {
private:
   string            m_symbol;                  // Symbol
   long              m_time;                    // Snapshot time
   int               m_digits;                  // Symbol's Digits
   CArrayObj         m_list;                    // List of DOM order objects
public:
//--- Return (1) itself and (2) the list of DOM order objects
   CMBookSnapshot   *GetObject(void)                                    { return &this;   }
   CArrayObj        *GetList(void)                                      { return &m_list; }

//--- Return the list of DOM order objects by selected (1) double, (2) integer and (3) string property satisfying the compared condition
   CArrayObj        *GetList(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMBookProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); }
//--- (1) Return the DOM order object by index in the list and (2) the order list size
   CMarketBookOrd   *GetMBookByListIndex(const uint index)              { return this.m_list.At(index);  }
   int               DataTotal(void)                              const { return this.m_list.Total();    }

//--- The comparison method for searching and sorting DOM snapshot objects by time
   virtual int       Compare(const CObject *node,const int mode=0) const 
                       {   
                        const CMBookSnapshot *compared_obj=node;
                        return(this.Time()<compared_obj.Time() ? -1 : this.Time()>compared_obj.Time() ? 1 : 0);
                       } 

//--- Return the DOM snapshot change
   string            Header(void);
//--- Display (1) description and (2) short description of a DOM snapshot
   void              Print(void);
   void              PrintShort(void);

//--- Constructors
                     CMBookSnapshot(){;}
                     CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]);
//+--------------------------------------------------------------------+ 
//|Methods of a simplified access to the DOM snapshot object properties|
//+--------------------------------------------------------------------+
//--- Set (1) a symbol, (2) a DOM snapshot time and (3) the specified time for all DOM orders
   void              SetSymbol(const string symbol)   { this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); }
   void              SetTime(const long time_msc)     { this.m_time=time_msc; }
   void              SetTimeToOrders(const long time_msc);
//--- Return (1) a DOM symbol, (2) symbol's Digits and (3) a snapshot time
   string            Symbol(void)               const { return this.m_symbol; }
   int               Digits(void)               const { return this.m_digits; }
   long              Time(void)                 const { return this.m_time;   }
  };
//+------------------------------------------------------------------+

ここでは、すべてのライブラリオブジェクトと同様のクラスの通常の配置を確認できます。クラスメンバー変数はprivateセクションで宣言され、publicセクションは、指定された注文オブジェクトプロパティによってリストを返す標準メソッド、2つのDOMスナップショットオブジェクトを比較して、リスト(後でオブジェクトを格納するDOMスナップショットシリーズオブジェクトのリスト)で検索および並べ替えるメソッド、DOMスナップショットオブジェクトを記述するためのメソッド、および2つのコンストラクタ(デフォルトとパラメトリック)を備えています。 パラメトリックコンストラクタは、すべてのプロパティがわかっている新しいDOMスナップショットオブジェクトを作成するときに使用され、デフォルトのコンストラクタは、新しいオブジェクトをすばやく作成し、リスト内のオブジェクトを検索するために必要なプロパティを指定されたプロパティ値で追加するために使用されます。オブジェクトプロパティへの簡略化されたアクセスのメソッドは、後で必要になるいくつかのオブジェクトプロパティを設定して返すのに役立ちます。

クラスメソッドの実装を見てみましょう。

パラメトリッククラスコンストラクタで、取得したMqlBookInfo構造体配列を表示し、適切なタイプのDOM注文オブジェクトを作成して、リストに追加します。

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CMBookSnapshot::CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]) : m_time(time)
  {
   //--- Set a symbol
   this.SetSymbol(symbol);
   //--- Clear the list
   this.m_list.Clear();
   //--- In the loop by the structure array
   int total=::ArraySize(book_array);
   for(int i=0;i<total;i++)
     {
      //--- Create order objects of the current DOM snapshot depending on the order type
      CMarketBookOrd *mbook_ord=NULL;
      switch(book_array[i].type)
        {
         case BOOK_TYPE_BUY         : mbook_ord=new CMarketBookBuy(this.m_symbol,book_array[i]);         break;
         case BOOK_TYPE_SELL        : mbook_ord=new CMarketBookSell(this.m_symbol,book_array[i]);        break;
         case BOOK_TYPE_BUY_MARKET  : mbook_ord=new CMarketBookBuyMarket(this.m_symbol,book_array[i]);   break;
         case BOOK_TYPE_SELL_MARKET : mbook_ord=new CMarketBookSellMarket(this.m_symbol,book_array[i]);  break;
         default: break;
        }
      if(mbook_ord==NULL)
         continue;
      //--- Set the DOM snapshot time for the order
      mbook_ord.SetTime(this.m_time);
      //--- Set the sorted list flag for the list (by the price value) and add the current order object to it
      this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE);
      if(!this.m_list.InsertSort(mbook_ord))
         delete mbook_ord;
     }
  }
//+------------------------------------------------------------------+

以下は、DOMスナップショットオブジェクトの短い名前を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMBookSnapshot::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_SNAP_TEXT_SNAPSHOT)+" \""+this.Symbol();
  }
//+------------------------------------------------------------------+

ここでは、オブジェクトと銘柄の説明がおおよそ次のようになっているテキストメッセージで作成された文字列を作成します。

EURUSD DOM snapshot

以下は、操作ログにDOMスナップショットオブジェクトの簡単な説明を表示するメソッドです。

//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CMBookSnapshot::PrintShort(void)
  {
   ::Print(this.Header()," ("+TimeMSCtoString(this.m_time),")");
  }
//+------------------------------------------------------------------+

操作ログでは、メソッドはオブジェクト名とミリ秒単位のDOMスナップショット時間を含む文字列を出力します。以下は例です。

"EURUSD" DOM snapshot (2021.02.09 22:16:24.557)

以下は、操作ログにDOMスナップショットオブジェクトのプロパティを表示するメソッドです。

//+------------------------------------------------------------------+
//| Display object properties in the journal                         |
//+------------------------------------------------------------------+
void CMBookSnapshot::Print(void)
  {
   ::Print(this.Header()," ("+TimeMSCtoString(this.m_time),"):");
   this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE);
   for(int i=this.m_list.Total()-1;i>WRONG_VALUE;i--)
     {
      CMarketBookOrd *ord=this.m_list.At(i);
      if(ord==NULL)
         continue;
      ::Print(" - ",ord.Header());
     }
  }
//+------------------------------------------------------------------+

DOMスナップショットの説明を特徴とするヘッダーが最初に表示され、次にループ内のすべてのDOM注文オブジェクトの説明が表示されます。

DOMスナップショットオブジェクトリスト内の注文オブジェクトは時間を取得できないため、オブジェクトで指定された時間(ミリ秒単位)をリスト内のすべての注文オブジェクトに設定するメソッドを実装します。

//+------------------------------------------------------------------+
//| Set the specified time to all DOM orders                         |
//+------------------------------------------------------------------+
void CMBookSnapshot::SetTimeToOrders(const long time_msc)
  {
   int total=this.m_list.Total();
   for(int i=0;i<total;i++)
     {
      CMarketBookOrd *ord=this.m_list.At(i);
      if(ord==NULL)
         continue;
      ord.SetTime(time_msc);
     }
  }
//+------------------------------------------------------------------+

すべてのDOM注文オブジェクトのリストによるループで、次の注文オブジェクトを取得し、DOMスナップショットオブジェクトのプロパティで指定された時間を割り当てます。したがって、DOMリスト内のすべての注文オブジェクトは、同じ時間に受信されます。OnBookEvent()ハンドラのアクティブ化の時点で取得するため、これは論理的です。アクティブ化の時間は、DOMスナップショットオブジェクトとそのすべての注文に設定されます。

DOMスナップショットオブジェクトの準備ができました。ここで、新しいDOMスナップショットを取得し、OnBookEvent()ハンドラをアクティブ化するたびに適切なオブジェクトを作成するため、これらのオブジェクトをリストに配置します。
これらのオブジェクトはすべて、DOMシリーズのオブジェクトクラスに格納されます。

板情報スナップショットシリーズオブジェクトクラス

その「イデオロギー」の観点から、DOMスナップショットシリーズのクラスは、銘柄時系列クラスまたはティックデータに似ています。このクラスでは、データは環境から取得できますが、DOMスナップショットリストクラスでは、履歴データを取得できません。リアルタイムで蓄積する必要があります。したがって、このクラスはリスト作成メソッドではなく、リスト更新メソッドのみを備えています。

\MQL5\Include\DoEasy\Objects\Book\で、CMBookSeriesクラスの新しいファイルMBookSeries.mqhを作成します。
すべてのCBaseObjライブラリオブジェクトの基本オブジェクトのクラスを基本クラスとして使用します

DOMスナップショットオブジェクトクラスのファイルをファイルにインクルードします

クラスのコードを検討し、後でそのメソッドを分析してみましょう。

//+------------------------------------------------------------------+
//|                                                  MBookSeries.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "MarketBookSnapshot.mqh"
//+------------------------------------------------------------------+
//| "DOM snapshot series" class                                      |
//+------------------------------------------------------------------+
class CMBookSeries : public CBaseObj
  {
private:
   string            m_symbol;                                          // Symbol
   uint              m_amount;                                          // Number of used DOM snapshots in the series
   uint              m_required;                                        // Required number of days for DOM snapshot series
   CArrayObj         m_list;                                            // DOM snapshot series list
   MqlBookInfo       m_book_info[];                                     // DOM structure array
public:
//--- Return (1) itself and (2) the series list
   CMBookSeries     *GetObject(void)                                    { return &this;   }
   CArrayObj        *GetList(void)                                      { return &m_list; }

//--- Return the DOM snapshot list by selected (1) double, (2) integer and (3) string properties fitting the compared condition
   CArrayObj        *GetList(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMBookProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); }

//--- Return the DOM snapshot object by (1) index in the list, (2) time and (3) actual list size
   CMBookSnapshot   *GetMBookByListIndex(const uint index)        const { return this.m_list.At(index);              }
   CMBookSnapshot   *GetLastMBook(void)                           const { return this.m_list.At(this.DataTotal()-1); }
   CMBookSnapshot   *GetMBook(const long time_msc); 
   int               DataTotal(void)                              const { return this.m_list.Total();                }

//--- Set a (1) symbol, (2) a number of days for DOM snapshots
   void              SetSymbol(const string symbol);
   void              SetRequiredUsedDays(const uint required=0);

//--- The comparison method for searching and sorting DOM snapshot series objects by symbol
   virtual int       Compare(const CObject *node,const int mode=0) const 
                       {   
                        const CMBookSeries *compared_obj=node;
                        return(this.Symbol()==compared_obj.Symbol() ? 0 : this.Symbol()>compared_obj.Symbol() ? 1 : -1);
                       } 
//--- Return the name of the DOM  snapshot series
   string            Header(void);
//--- Display (1) description and (2) short description of a DOM snapshot series
   void              Print(void);
   void              PrintShort(void);

//--- Constructors
                     CMBookSeries(){;}
                     CMBookSeries(const string symbol,const uint required=0);

//+------------------------------------------------------------------+ 
//| Methods of working with objects and accessing their properties   |
//+------------------------------------------------------------------+
//--- Return (1) a symbol, a number of (2) used and (3) requested DOM snapshots in the series and
//--- (4) the time of a DOM snapshot specified by the index in milliseconds
   string            Symbol(void)                                          const { return this.m_symbol;    }
   ulong             AvailableUsedData(void)                               const { return this.m_amount;    }
   ulong             RequiredUsedDays(void)                                const { return this.m_required;  }
   long              MBookTime(const int index) const;
//--- update the list of DOM snapshot series
   bool              Refresh(const long time_msc);
  };
//+------------------------------------------------------------------+

ここには以下があります。

クラスメソッドの実装を見てみましょう。

リスト銘柄は、パラメトリックコンストラクタの初期化リストで設定され、リストはメソッド本体でクリアされます。ミリ秒単位の時間で並び替えられたリストのフラグが設定され、必要なDOMスナップショットデータの日数が指定されます。

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CMBookSeries::CMBookSeries(const string symbol,const uint required=0) : m_symbol(symbol)
  {
   this.m_list.Clear();
   this.m_list.Sort(SORT_BY_MBOOK_ORD_TIME_MSC);
   this.SetRequiredUsedDays(required);
  }
//+------------------------------------------------------------------+

以下は、DOMスナップショットリストを更新するメソッドです。

//+------------------------------------------------------------------+
//| Update the list of DOM snapshot series                           |
//+------------------------------------------------------------------+
bool CMBookSeries::Refresh(const long time_msc)
  {
//--- Get DOM entries to the structure array
   if(!::MarketBookGet(this.m_symbol,this.m_book_info))
      return false;
//--- Create a new DOM snapshot object
   CMBookSnapshot *book=new CMBookSnapshot(this.m_symbol,time_msc,this.m_book_info);
   if(book==NULL)
      return false;
//--- Set the flag of a list sorted by time for the list and add the created DOM snapshot to it
   this.m_list.Sort(SORT_BY_MBOOK_ORD_TIME_MSC);
   if(!this.m_list.InsertSort(book))
     {
      delete book;
      return false;
     }
//--- Set time in milliseconds to all DOM snapshot order objects
   book.SetTimeToOrders(time_msc);
//--- If the number of snapshots in the list exceeds the default maximum number,
//--- remove the calculated number of snapshot objects from the end of the list
   if(this.DataTotal()>MBOOKSERIES_MAX_DATA_TOTAL)
     {
      int total_del=this.m_list.Total()-MBOOKSERIES_MAX_DATA_TOTAL;
      for(int i=0;i<total_del;i++)
         this.m_list.Delete(i);
     }
   return true;
  }
//+------------------------------------------------------------------+

このメソッドは、OnBookEvent()ハンドラがアクティブ化されたときに呼び出されて、ハンドラがアクティブ化した時刻を受け取ります。MarketBookGet()を使用して、DOM構造体配列を取得します。この構造体を使用して、新しいDOMスナップショットオブジェクトを作成し、スナップショットシリーズリストに追加します。
ロジック全体は、メソッドコードへのコメントで詳しく説明されています。はっきりしていると思います。

以下は、スナップショットシリーズリストに銘柄名を配置するメソッドです。

//+------------------------------------------------------------------+
//| Set a symbol                                                     |
//+------------------------------------------------------------------+
void CMBookSeries::SetSymbol(const string symbol)
  {
   if(this.m_symbol==symbol)
      return;
   this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol);
  }
//+------------------------------------------------------------------+

ここではすべてが明らかです。NULLまたは空の文字列が渡されると現在の銘柄が設定され、それ以外の場合はメソッドに渡されたものが設定されます。

以下は、DOMスナップショットシリーズに必要な日数を定義するメソッドです。

//+------------------------------------------------------------------+
//| Set the number of days for DOM snapshots in the series           |
//+------------------------------------------------------------------+
void CMBookSeries::SetRequiredUsedDays(const uint required=0)
  {
   this.m_required=(required<1 ? MBOOKSERIES_DEFAULT_DAYS_COUNT : required);
  }
//+------------------------------------------------------------------+

ゼロ値が渡された場合はデフォルトの日数が設定され、それ以外の場合は、メソッドに渡される日数が設定されます。このメソッドはまだどこにも使用されていません。

以下は、指定された時間によってDOMスナップショットオブジェクトを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the DOM snapshot object by its time                       |
//+------------------------------------------------------------------+
CMBookSnapshot *CMBookSeries::GetMBook(const long time_msc)
  {
   CMBookSnapshot *book=new CMBookSnapshot();
   if(book==NULL)
      return NULL;
   book.SetTime(time_msc);
   this.m_list.Sort();
   int index=this.m_list.Search(book);
   delete book;
   return this.m_list.At(index);
  }
//+------------------------------------------------------------------+

ここでは、一時的なDOMスナップショットオブジェクトを作成し、必要な時間並べ替えられたリストフラグを設定します。また、Search()メソッドを使用して、リスト内のオブジェクトインデックスを必要な時間で受信します必ず一時オブジェクトを削除し、リスト内のインデックスで検出されたオブジェクトへのポインタを返します

以下は、インデックスで指定されたDOMスナップショットの時間をミリ秒単位で返すメソッドです。

//+------------------------------------------------------------------+
//| Returns the time in milliseconds                                 |
//| of a DOM snapshot specified by index                             |
//+------------------------------------------------------------------+
long CMBookSeries::MBookTime(const int index) const
  {
   CMBookSnapshot *book=this.m_list.At(index);
   return(book!=NULL ? book.Time() : 0);
  }
//+------------------------------------------------------------------+

指定されたインデックスでDOMスナップショットオブジェクトへのポインタを取得し、ミリ秒単位で時間を返します。失敗した場合はNULLを返します。

以下は、DOMスナップショットシリーズの名前を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the name of the DOM snapshot series                       |
//+------------------------------------------------------------------+
string CMBookSeries::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_SERIES_TEXT_MBOOKSERIES)+" \""+this.m_symbol+"\"";
  }
//+------------------------------------------------------------------+

このメソッドは、オブジェクトの説明と銘柄で構成される文字列を返します。以下は例です。

Series of "EURUSD" DOM snapshots

以下は、操作ログ内のDOMスナップショットオブジェクトの説明を表示するメソッドです。

//+------------------------------------------------------------------+
//| Display the description of the DOM snapshot series in the journal|
//+------------------------------------------------------------------+
void CMBookSeries::Print(void)
  {
   string txt=
     (
      CMessage::Text(MSG_TICKSERIES_REQUIRED_HISTORY_DAYS)+(string)this.RequiredUsedDays()+", "+
      CMessage::Text(MSG_LIB_TEXT_TS_ACTUAL_DEPTH)+(string)this.DataTotal()
     );
   ::Print(this.Header(),": ",txt);
  }
//+------------------------------------------------------------------+

スナップショットシリーズの説明、要求されたデータ日数、実際に収集されたDOMスナップショットの数を特徴とするヘッダーが作成されてから、スナップショットオブジェクトのすべての注文がループで表示されます。

これで、DOMスナップショットオブジェクトとオブジェクトシリーズクラスの作成が完了しました。

検証

テストを実行するには、前の記事のEAを使用して、\MQL5\Experts\TestDoEasy\Part64\TestDoEasyPart64.mq5として保存します。

EAで、現在の銘柄のDOMスナップショットシリーズオブジェクトを作成し、現在の銘柄でOnBoolEvent()ハンドラをアクティブ化するたびに新しいDOMスナップショットオブジェクトを追加します。リストに追加されたスナップショットオブジェクトの数と、現在のスナップショットの2つの極端な注文(最も高い売りと最も低い買い)に関するデータをグラフのコメントに表示します。DOMデータを初めて受信するときは、ターミナル操作ログに出力します。

EAリストから注文オブジェクトクラスの接続を削除します。これらは、今日作成した新しいクラスファイルにインクルードされるようになりました。

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart63.mq5 |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Engine.mqh>
#include <DoEasy\Objects\Book\MarketBookBuy.mqh>
#include <DoEasy\Objects\Book\MarketBookSell.mqh>
#include <DoEasy\Objects\Book\MarketBookBuyMarket.mqh>
#include <DoEasy\Objects\Book\MarketBookSellMarket.mqh>
//--- enums

代わりに、DOMスナップショットシリーズクラスファイルのインクルードを追加します。

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart64.mq5 |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Engine.mqh>
#include <DoEasy\Objects\Book\MBookSeries.mqh>
//--- enums

EAグローバル変数のリストで、 DOMスナップショットシリーズクラスのオブジェクトを宣言します

//--- global variables
CEngine        engine;
SDataButt      butt_data[TOTAL_BUTT];
string         prefix;
double         lot;
double         withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal);
ushort         magic_number;
uint           stoploss;
uint           takeprofit;
uint           distance_pending;
uint           distance_stoplimit;
uint           distance_pending_request;
uint           bars_delay_pending_request;
uint           slippage;
bool           trailing_on;
bool           pressed_pending_buy;
bool           pressed_pending_buy_limit;
bool           pressed_pending_buy_stop;
bool           pressed_pending_buy_stoplimit;
bool           pressed_pending_close_buy;
bool           pressed_pending_close_buy2;
bool           pressed_pending_close_buy_by_sell;
bool           pressed_pending_sell;
bool           pressed_pending_sell_limit;
bool           pressed_pending_sell_stop;
bool           pressed_pending_sell_stoplimit;
bool           pressed_pending_close_sell;
bool           pressed_pending_close_sell2;
bool           pressed_pending_close_sell_by_buy;
bool           pressed_pending_delete_all;
bool           pressed_pending_close_all;
bool           pressed_pending_sl;
bool           pressed_pending_tp;
double         trailing_stop;
double         trailing_step;
uint           trailing_start;
uint           stoploss_to_modify;
uint           takeprofit_to_modify;
int            used_symbols_mode;
string         array_used_symbols[];
string         array_used_periods[];
bool           testing;
uchar          group1;
uchar          group2;
double         g_point;
int            g_digits;
//---
CMBookSeries   book_series;
//+------------------------------------------------------------------+

DOMスナップショットシリーズのリストを作成する作業全体は、OnBoolEvent()ハンドラで実行されます。

//+------------------------------------------------------------------+
//| OnBookEvent function                                             |
//+------------------------------------------------------------------+
void OnBookEvent(const string& symbol)
  {
   static bool first=true;
   //--- Get a symbol object
   CSymbol *sym=engine.GetSymbolCurrent();
   //--- If failed to get a symbol object or it is not subscribed to DOM, exit
   if(sym==NULL || !sym.BookdepthSubscription()) return;
   //--- Work by the current symbol
   if(symbol==sym.Name())
     {
      //--- Set a symbol and a required number of data days for the DOM snapshot series object
      book_series.SetSymbol(sym.Name());
      book_series.SetRequiredUsedDays();
      //--- Update the DOM snapshot series
      if(!book_series.Refresh(sym.Time()))
         return;
      
      //--- Get the last DOM snapshot object from the DOM snapshot series object
      CMBookSnapshot *book=book_series.GetLastMBook();
      if(book==NULL)
         return;
      //--- Get the very first and last DOM order objects from the DOM snapshot object
      CMarketBookOrd *ord_0=book.GetMBookByListIndex(0);
      CMarketBookOrd *ord_N=book.GetMBookByListIndex(book.DataTotal()-1);
      if(ord_0==NULL || ord_N==NULL) return;
      //--- Display the time of the current DOM snapshot in the chart comment,
      //--- the maximum number of displayed orders in DOM for a symbol,
      //--- the obtained number of orders in the current DOM snapshot,
      //--- the total number of DOM snapshots set in the series list and
      //--- the highest and lowest orders of the current DOM snapshot
      Comment
        (
         DFUN,sym.Name(),": ",TimeMSCtoString(book.Time()),
         ", symbol book size=",sym.TicksBookdepth(),

         ", last book data total: ",book.DataTotal(),
         ", series books total: ",book_series.DataTotal(),
         "\nMax: ",ord_N.Header(),"\nMin: ",ord_0.Header()
        );
      //--- Display the first DOM snapshot in the journal
      if(first)
        {
         //--- series description
         book_series.Print();
         //--- snapshot description
         book.Print();
         first=false;
        }
     }
  }
//+------------------------------------------------------------------+

すべてのコード文字列は、ここのコメントで説明されています。追加の説明は必要ないことを願っています。
質問がある場合は、コメント欄でお気軽にお問い合わせください。

EAをコンパイルし、設定で事前に定義された銘柄チャートで起動します。指定された2つの銘柄と現在の時間枠での作業は次のとおりです。


操作ログには、作成されたDOMスナップショットシリーズのデータ最初のスナップショットが表示されます。

Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.) 10428.13 USD, 1:100, Hedge, MetaTrader 5 demo
--- Initializing "DoEasy" library ---
Working with predefined symbol list. The number of used symbols: 2
"AUDUSD" "EURUSD"
Working with the current timeframe only: H1
AUDUSD symbol timeseries: 
- Timeseries "AUDUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5121
EURUSD symbol timeseries: 
- Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6046
Tick series "AUDUSD": Requested number of days: 1, Historical data created: 176033
Tick series "EURUSD": Requested number of days: 1, Historical data created: 181969
Subscribed to Depth of Market  AUDUSD
Subscribed to Depth of Market  EURUSD
Library initialization time: 00:00:12.516
The "EURUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 1
"EURUSD" DOM snapshot (2021.02.09 22:16:24.557):
 - Sell order: 1.21198 [250.00]
 - Sell order: 1.21193 [100.00]
 - Sell order: 1.21192 [50.00]
 - Sell order: 1.21191 [30.00]
 - Sell order: 1.21190 [6.00]
 - Buy order: 1.21188 [36.00]
 - Buy order: 1.21186 [50.00]
 - Buy order: 1.21185 [100.00]
 - Buy order: 1.21180 [250.00]

最後のDOMスナップショットの数、銘柄の注文数、現在のスナップショットの注文数、およびDOMスナップショットリストに追加されたDOMスナップショットの総数は、銘柄チャートに表示されます。

この図は、すでにしばらくの間機能しているEAのデータを示しています(5019個のスナップショットがリストに追加されています)。

次の段階

次の記事では、DOMスナップショットシリーズのコレクションを作成して、DOMへのアクティブなサブスクリプションとブロードキャストを有効にしている銘柄のDOMを完全に使用できるようにします。

ライブラリの現在のバージョンのすべてのファイルは、テストおよびダウンロードできるように、MQL5のテストEAファイルと一緒に以下に添付されています。
DOMを使用するためのクラスは開発中であるため、この段階でカスタムプログラムで使用しないことを強くお勧めします。
質問や提案はコメント欄にお願いします。

目次に戻る

*連載のこれまでの記事:

DoEasyライブラリでの価格(第62部): ティックシリーズをリアルタイムで更新して板情報で作業するための準備
DoEasyライブラリでの価格(第63部): 板情報とその抽象リクエストクラス