Preise in der DoEasy-Bibliothek (Teil 64): Markttiefe, Klassenobjekte für Schnappschüsse der Markttiefe und der Schnappschuss-Reihen

Artyom Trishkin | 14 April, 2021

Inhalt


Konzept

Im vorherigen Artikel habe ich die Klasse des abstrakten DOM-Objekts "Depth of Market" (Markttiefe) und seine Abkömmlinge erstellt. Die Vielzahl dieser Objekte bildet einen DOM-Schnappschuss, der bei einem Aufruf der Funktion MarketBookGet() im Moment der Aktivierung des Handlers OnBookEvent() erhalten wird. Die von der Funktion MarketBookGet() erhaltenen Daten werden in das Array der Struktur MqlBookInfo eingestellt. Basierend auf den erhaltenen Daten sind wir in der Lage, das DOM-Schnappschuss-Objekt zu erstellen, das alle erhaltenen DOM-Aufträge im MqlBookInfo-Strukturarray speichern soll. Mit anderen Worten, die Daten im erwähnten Struktur-Array bilden den DOM-Schnappschuss, in dem jedes Strukturelement durch ein einzelnes DOM-Anforderungsobjekt repräsentiert wird. Jede Aktivierung von OnBookEvent() führt zur Erzeugung eines weiteren DOM-Schnappschusses, der wiederum in das Objekt der Klasse DOM-Schnappschuss-Reihen eingetragen wird.
Als Liste für die Speicherung der DOM-Schnappschuss-Objekte soll die Klasse der Standardbibliothek als dynamisches Array von Zeigern auf Instanzen der Klasse CObject und deren Abkömmlinge verwendet werden. Die Größe der Liste soll durch eine bestimmte Anzahl von Objekten begrenzt werden. Standardmäßig beträgt die Größe der Liste nicht mehr als 200.000 DOM-Schnappschuss-Objekte, was etwa einen oder zwei Handelstage abdecken sollte. Solche DOM-Schnappschuss-Reihen-Listen sind für jedes im Programm verwendete Symbol zu erstellen. Daher soll jede solche Liste in der DOM-Datensammlung gespeichert werden.

Hier werde ich zwei Klassen erstellen — die Klasse des DOM-Schnappschuss-Objekts eines einzelnen Symbols und die Klasse der DOM-Schnappschuss-Reihen eines einzelnen Symbols. Im nächsten Artikel werde ich die Klasse der DOM-Schnappschuss-Reihen-Sammlung erstellen und testen.


Verbesserung der Bibliothek der Klasse

In \MQL5\Include\DoEasy\Data.mqh fügen wir die neuen Nachrichtenindizes der Bibliothek hinzu:

//--- 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
   
  };
//+------------------------------------------------------------------+

und die Textnachrichten, die den neu hinzugefügten Indizes entsprechen:

//--- 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"},
   
  };
//+---------------------------------------------------------------------+

Um das Kriterium für die Sortierung nach Zeit bei der Suche nach den erforderlichen DOM-Schnappschuss-Objekten in der Liste der Reihen angeben zu können, müssen wir dem DOM-Anforderungsobjekt eine neue Eigenschaft hinzufügen — die Zeit des Empfangs eines Schnappschusses in Millisekunden. Die Anforderung selbst hat keine solche Eigenschaft, aber wir sind in der Lage, die Zeit des Empfangs eines DOM-Schnappschusses zu verfolgen. Um zu vermeiden, dass neue Enumerationen für die Liste der Schnappschuss-Reihen eingeführt werden, die eine einzige Integer-Eigenschaft enthalten (Zeit des Erhalts eines Schnappschusses in Millisekunden), fügen wir diese Eigenschaft zu den Eigenschaften des DOM-Anforderungsobjekts hinzu. Die Zeit des Erhalts eines Schnappschusses wird jedem Anforderung in einem einzelnen Schnappschuss-Objekt zugewiesen. Wir werden diese neu aktualisierte Konstante für die Suche und Sortierung in der Liste der Reihen verwenden.

In \MQL5\Include\DoEasy\Defines.mqh geben wir die Parameter der DOM Schnappschuss-Reihen ein, damit wir die notwendige Anzahl von Datentagen und die maximal mögliche Anzahl von Schnappschüssen in der Liste einstellen können:

//--- 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
//+------------------------------------------------------------------+

Ich werde den ersten Parameter (Anzahl der Tage) noch nicht verwenden — später werde ich versuchen, die Daten mit der Anzahl der Tick-Daten-Tage zu verknüpfen. Derzeit werde ich nur den zweiten Parameter verwenden — die maximal mögliche Menge an DOM-Schnappschuss-Daten.

Fügen wir in derselben Datei die neue ganzzahlige DOM-Anforderung-Objekteigenschaft hinzu (die Zeit in Millisekunden) und erhöhen Sie die Anzahl der ganzzahligen Objekteigenschaften auf 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
//+------------------------------------------------------------------+

Da wir eine neue Integer-Eigenschaft hinzugefügt habe, sollten wir auch ein neues Kriterium zum Sortieren nach Integer-Eigenschaften hinzufügen:

//+------------------------------------------------------------------+
//| 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
  };
//+------------------------------------------------------------------+

Diese Konstante wird als Parameter für die Sortierung von DOM-Schnappschuss-Objekten in der aktuell entwickelten Klasse von DOM-Schnappschuss-Reihen-Objekten angegeben.

Es besteht also Bedarf an den Methoden zum Suchen und Sortieren von DOM-Anforderungsobjekten in der Klassendatei CSelect, die in \MQL5\Include\DoEasy\Services\Select.mqh gespeichert ist und ausführlich im dritten Artikel beschrieben ist. Jetzt beschreibe ich einfach alle notwendigen Modifikationen dieser Klasse, um die Suche und Sortierung nach Eigenschaften von DOM-Anforderungsobjekten zu organisieren.

Fügen wir die Klasse des abstrakten DOM-Anforderungsobjekts in die Datei ein:

//+------------------------------------------------------------------+
//|                                                       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"
//+------------------------------------------------------------------+

Deklarieren wir alle notwendigen Methoden am Ende des Klassenkörpers:

//+------------------------------------------------------------------+
//| 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);
//---
  };
//+------------------------------------------------------------------+

Implementieren wir das außerhalb des Klassenkörpers:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Die Logik der Funktionsweise der Methoden ist ähnlich wie die der anderen Methoden der Klasse, die ich zuvor für andere Bibliotheksobjekte erstellt habe. Daher werde ich mich nicht damit aufhalten, die Funktionsweise der Methoden zu beschreiben. Sie finden alle notwendigen Daten hier.

Da ich einen neuen Parameter eingeführt habe — den Zeitpunkt des Erhalts eines DOM-Schnappschusses — wird dieser im Objekt eines abstrakten DOM-Anforderungs gesetzt. Die Struktur MqlBookInfo, die einen DOM Anforderung beschreibt, hat keinen Zeitparameter. Das bedeutet, dass wir den Zeitpunkt des Empfangs eines Schnappschusses für jedes DOM-Anforderungsobjekt selbst beschreiben müssen.

Dazu erhält die Datei der abstrakten DOM-Anforderungsklasse \MQL5\Include\DoEasy\Objects\Book\MarketBookOrd.mqh eine neue öffentliche Methode:

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

Die Methode setzt einfach den erhaltenen Zeitwert in Millisekunden in der neuen Eigenschaft des Objekts.

Wir initialisieren die Zeit des Erhalts eines Schnappschusses im parametrischen Konstruktor der abstrakten Anforderungsklasse 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);
  }
//+------------------------------------------------------------------+

Die Zeit jedes der in einem einzelnen DOM-Schnappschuss vorhandenen Aufträge wird zum Zeitpunkt des Empfangs des DOM-Schnappschusses festgelegt.

Einige kleinere Änderungen wurden an den virtuellen Objektbeschreibungsmethoden in der DOM abstrakten Anforderungsklassendatei MarketBookOrd.mqh und ihren Ableitungen MarketBookBuy. mqh, MarketBookBuyMarket.mqh, MarketBookSell.mqh und MarketBookSellMarket.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);

Zu jeder der Methoden wurden Flags hinzugefügt, die die Notwendigkeit der Ausgabe des Symbolnamens in der Objektbeschreibung anzeigen. Standardmäßig wird ein Symbol in der Beschreibung des Anforderungsobjekts nicht angezeigt. Der Grund dafür ist, dass das Anforderungsobjekt kein eigenständiges Objekt ist, sondern ein Teil des DOM-Schnappschusses, dessen Klasse wir heute bilden werden. Und bei der Ausgabe der Beschreibung des DOM-Schnappschuss-Objekts, bei der neben der Objektbeschreibung auch die Beschreibungen aller Anforderungen angezeigt werden, wirkt die Ausgabe des Symbols für jede Anforderung redundant, da das Symbol bereits in der Kopfzeile der DOM-Schnappschuss-Objektbeschreibung angezeigt wird.

Die Verfeinerung dieser Methoden sieht für alle der oben genannten Klassen gleich aus.

Für die Klasse CMarketBookOrd:k

//+------------------------------------------------------------------+
//| 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));
  }
//+------------------------------------------------------------------+

Für die Klassen CMarketBookBuy, CMarketBookBuyMarket, CMarketBookSell und 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)+"]";
  }
//+------------------------------------------------------------------+

Für die Klasse 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)+"]";
  }
//+------------------------------------------------------------------+

Für die Klasse 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)+"]";
  }
//+------------------------------------------------------------------+

Für die Klasse 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)+"]";
  }
//+------------------------------------------------------------------+

Dementsprechend wurden die Flags bei der Deklaration all dieser Methoden in allen Nachfolgeklassen hinzugefügt:

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

Standardmäßig wird ein Symbol in der Objektbeschreibung nicht angezeigt.


Klassenobjekt für einen Schnappschusses der Markttiefe

Jetzt ist alles bereit für die Entwicklung der Klasse des Schnappschuss-Objekts eines DOMs. Tatsächlich handelt es sich um eine Liste von DOM-Anforderungen, die an das Array der MqlBookInfo-Struktur übergeben werden, wenn ein Ereignis von OnBookEvent() auftritt. Allerdings wird jede der Array-Anforderungen in der Klasse durch das Klassenobjekt CMarketBookOrd repräsentiert — seine Abkömmlinge. Sie werden alle in die Liste CArrayObj eingefügt, die eine Klasse eines dynamischen Arrays von Zeigern auf die Instanzen der Klasse CObject und ihrer Abkömmlinge der Standardbibliothek ist. Neben der Liste, in der die DOM-Anforderungsobjekte gespeichert werden, soll die Klasse die für alle Bibliotheksobjekte standardmäßigen Funktionen für den Umgang mit Objekten und ihren Listen bereitstellen — Suchen und Sortieren nach ihren verschiedenen Eigenschaften — für die komfortable Erfassung beliebiger statistischer Daten bei der Arbeit mit dem DOM in ihren Programmen.

Wir erstellen in \MQL5\Include\DoEasy\Objects\Book\ die neue Datei MarketBookSnapshot.mqh der Klasse CMBookSnapshot.
Die Klasse des Basisobjekts aller CBaseObj-Bibliotheksobjekte soll als Basisklasse verwendet werden
.
Die Dateien der abgeleiteten Objektklassen des abstrakten DOM-Anforderungsobjekts sollen in die Datei aufgenommen werden
.

Betrachten wir nun den Code der Klasse und die Implementierung ihrer Methoden:

//+------------------------------------------------------------------+
//|                                           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;   }
  };
//+------------------------------------------------------------------+

Hier sehen wir die übliche Struktur einer Klasse, ähnlich wie bei allen Bibliotheksobjekten: die Klassenvariablen werden im Abschnitt 'private' deklariert, während der 'public' Teil die Standardmethoden für die Rückgabe der Listen nach den angegebenen Eigenschaften des Ordnungsobjekts, die Methode für den Vergleich zweier DOM-Schnappschuss-Objekte zum Suchen und Sortieren in der Liste (die Liste des DOM-Schnappschuss-Reihen-Objekts, das die Objekte später speichern soll), die Methoden zur Beschreibung des DOM-Schnappschuss-Objekts enthält, sowie zwei Konstruktoren — der Standard- und der parametrische Konstruktor (der parametrische Konstruktor ist bei der Erstellung neuer DOM-Schnappschuss-Objekte mit allen bekannten Eigenschaften zu verwenden, während der Standardkonstruktor für die schnelle Erstellung eines neuen Objekts und das Hinzufügen der erforderlichen Eigenschaft für die Suche der Objekte in der Liste mit dem angegebenen Eigenschaftswert zu verwenden ist). Die Methoden des vereinfachten Zugriffs auf Objekteigenschaften dienen zum Setzen und Zurückgeben einiger Objekteigenschaften, die ich später benötigen werde.

Werfen wir einen Blick auf die Implementierung der Klassenmethoden.

Im parametrischen Klassenkonstruktor, sehen wir uns das erhaltene MqlBookInfo-Strukturarray an, erstellen die entsprechenden Typen von DOM-Anforderungen und fügen sie der Liste hinzu.

//+------------------------------------------------------------------+
//| 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;
     }
  }
//+------------------------------------------------------------------+

Die Methode gibt einen Kurznamen des DOM-Schnappschuss-Objekts zurück:

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

Hier erstellen wir einfach eine Zeichenkette, die aus der Textmeldung mit der Objekt- und Symbolbeschreibung besteht und in etwa wie folgt aussieht:

EURUSD DOM snapshot

Die Methode, die eine kurze Beschreibung des DOM-Schnappschuss-Objekts im Journal anzeigt:

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

Im Journal gibt die Methode eine Zeichenkette aus, die aus dem Objektnamen plus der DOM-Schnappschuss-Zeit in Millisekunden besteht, z. B:

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

Die Methode, die die Eigenschaften des DOM-Schnappschuss-Objekts im Journal anzeigt:

//+------------------------------------------------------------------+
//| 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());
     }
  }
//+------------------------------------------------------------------+

Zuerst wird die Kopfzeile mit der Beschreibung des DOM-Schnappschusses angezeigt, dann folgen in einer Schleife die Beschreibungen aller DOM-Auftragsobjekte.

Da die Auftragsobjekte in der Liste der DOM-Schnappschuss-Objekte nicht in der Lage sind, ihre Zeit zu erhalten, werde ich die Methode implementieren, die die im Objekt angegebene Zeit in Millisekunden auf alle Auftragsobjekte in der Liste setzt:

//+------------------------------------------------------------------+
//| 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);
     }
  }
//+------------------------------------------------------------------+

Wir holen uns in der Schleife durch die Liste aller DOM-Anforderungsobjekte das nächste Anforderungsobjekt und weisen ihm die in den Eigenschaften des DOM-Schnappschuss-Objekts angegebene Zeit zu. So haben alle Anforderungen in der DOM-Liste den gleichen Zeitpunkt ihres Erhalts. Dies ist logisch, da wir sie im Moment der Aktivierung von OnBookEvent() erhalten. Der Aktivierungszeitpunkt wird für das DOM-Schnappschuss-Objekt und alle seine Anforderungen festgelegt.

Das DOM-Schnappschuss-Objekt ist fertig. Jetzt ist es an der Zeit, diese Objekte in der Liste zu platzieren, da wir bei jeder Aktivierung von OnBookEvent() einen neuen DOM-Schnappschuss erhalten und das entsprechende Objekt erstellen.
Alle diese Objekte sollen in der Objektklasse DOM-Reihe gespeichert werden.

Klassenobjekt für eine Reihe von Schnappschüssen der Markttiefe

Die Klasse der DOM Schnappschuss-Reihen ähnelt in ihrer "Ideologie" den Symbol-Zeitreihen-Klassen oder Tick-Daten. In diesen Klassen können die Daten aus der Umgebung bezogen werden, während wir in der Klasse der DOM Schnappschuss-Liste keine historischen Daten erhalten können — sie müssen in Echtzeit akkumuliert werden. Daher wird die Klasse nicht über die Methode zur Listenerstellung verfügen, sondern nur über die Methode zur Listenaktualisierung.

Wir erstellen in \MQL5\Include\DoEasy\Objects\Book\ die neue Datei MBookSeries.mqh der Klasse CMBookSeries.
Die Klasse des Basisobjekts aller CBaseObj-Bibliotheksobjekte soll als Basisklasse verwendet werden
.
Die Datei der Klasse des DOM-Schnappschuss-Objekts sollte in die Datei aufgenommen werden
.

Betrachten wir nun den Code der Klasse und analysieren anschließend deren Methoden:

//+------------------------------------------------------------------+
//|                                                  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);
  };
//+------------------------------------------------------------------+

Hier können wir sehen:

Werfen wir einen Blick auf die Implementierung der Klassenmethoden.

Das Listensymbol wird in der Initialisierungsliste des parametrischen Konstruktors gesetzt, während die Liste im Methodenkörper gelöscht wird. Dafür wird das Flag einer nach Zeit in Millisekunden sortierten Liste gesetzt und die gewünschte Anzahl von DOM-Schnappschuss-Datentagen angegeben.

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Die aktualisierte Methode der Liste der DOM-Schnappschüsse:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Die Methode wird aufgerufen, wenn OnBookEvent() aktiviert wird, und sie erhält die Aktivierungszeit dieser Ereignisfunktion. Wir verwenden MarketBookGet(), um das DOM-Struktur-Array zu erhalten. Die Struktur verwenden wir, um ein neues DOM-Schnappschuss-Objekt zu erstellen und es zur Liste der Schnappschuss-Reihen hinzuzufügen.
Die gesamte Logik ist in den Kommentaren zum Methodencode detailliert beschrieben. Ich glaube, sie ist klar.

Die Methode zum Einfügen eines Symbolnamens in die Liste der Schnappschuss-Reihen:

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

Hier ist alles transparent. Wenn NULL oder ein leerer String übergeben wird, wird das aktuelle Symbol verwendet, ansonsten das der Methode übergebene.

Die Methode, die die gewünschte Anzahl von Tagen für DOM-Schnappschuss-Reihen definiert:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Wenn ein Nullwert übergeben wird, setzen wir die Standardanzahl von Tagen, andernfalls wird der der Methode übergebenen Wert verwendet. Die Methode wird noch nirgends verwendet.

Die Methode gibt das DOM-Schnappschuss-Objekt zum angegebenen Zeitpunkt zurück:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Hier erzeugen wir ein temporäres DOM-Schnappschuss-Objekt, setzen seine benötigte Zeit, sowie das Sortier-Flag und verwenden die Methode Search(), um den Objektindex in der Liste mit der benötigten Zeit zu erhalten. Stellen wir sicher, dass wir das temporäre Objekt löschen und den Zeiger auf das gefundene Objekt per Index in der Liste zurückgeben.

Die Methode gibt die Zeit des DOM-Schnappschusses auf Basis des in Millisekunden Index zurück:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Holt den Zeiger auf das DOM-Schnappschuss-Objekt über den angegebenen Index und gibt dessen Zeit in Millisekunden oder NULL im Falle eines Fehlers zurück.

Die Methode gibt den Namen der DOM Schnappschuss-Reihe zurück:

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

Die Methode gibt die Zeichenkette zurück, die aus der Beschreibung eines Objekts und eines Symbols besteht, zum Beispiel:

Reihe von "EURUSD" DOM-Schnappschüssen

Die Methode zeigt die Beschreibung der DOM-Schnappschuss-Reihen im Journal an:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Zunächst wird der Kopf mit der Beschreibung der Schnappschuss-Reihen, einer gewünschten Anzahl von Datentagen und einer Anzahl der tatsächlich gesammelten DOM-Schnappschüsse erstellt. Dann werden alle Anforderungen des Schnappschuss-Objekts in der Schleife angezeigt.

Damit ist die Erstellung des DOM-Schnappschuss-Objekts und der Objekt-Reihen-Klassen abgeschlossen.

Test

Um den Test durchzuführen, verwenden wir den EA aus dem vorherigen Artikel und speichern ihn in \MQL5\Experts\TestDoEasy\Part64\ als TestDoEasyPart64.mq5.

Erstellen wir im EA das DOM-Schnappschuss-Reihen-Objekt für das aktuelle Symbol und fügen bei jeder Aktivierung von OnBoolEvent() für das aktuelle Symbol ein neues DOM-Schnappschuss-Objekt hinzu. Wir zeigen die Daten über die Anzahl der zur Liste hinzugefügten Schnappschuss-Objekte und zwei extreme Anforderungen des aktuellen Schnappschusses (die höchsten Verkaufs- und die niedrigsten Kauf-Anforderungen) im Chart-Kommentar an. Wenn wir zum ersten Mal DOM-Daten erhalten, geben wir sie im Terminaljournal aus.

Wir entfernen die eingebundene Anforderungs-Objektklassen aus dem Code der EA — sie sind jetzt in den neuen Klassendateien enthalten, die ich heute erstellt habe:

//+------------------------------------------------------------------+
//|                                             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

Binden wir stattdessen die Klassendatei der DOM Schnappschuss-Reihe ein:

//+------------------------------------------------------------------+
//|                                             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

Deklarieren wir in der Liste der globalen EA-Variablen das Objekt der Klasse DOM Schnappschuss-Reihen:

//--- 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;
//+------------------------------------------------------------------+

Die gesamte Arbeit zur Erstellung der Liste der DOM Schnappschuss-Reihen wird in OnBoolEvent() ausgeführt:

//+------------------------------------------------------------------+
//| 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;
        }
     }
  }
//+------------------------------------------------------------------+

Alle Code-Zeilen sind hier in den Kommentaren beschrieben. Ich hoffe, sie bedürfen keiner weiteren Erklärung.
Wenn Sie Fragen haben, können Sie diese gerne in den Kommentaren stellen.

Kompilieren Sie den EA und starten Sie ihn auf einem Symbolchart, nachdem Sie zuvor in den Einstellungen die Arbeit auf zwei festgelegten Symbolen und dem aktuellen Zeitrahmen definiert haben:


Das Journal zeigt die Daten zu den erstellten DOM-Schnappschuss-Reihen und dem ersten Schnappschuss an:

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]

Die Nummer des letzten DOM-Schnappschusses, die Anzahl der Anforderungen für ein Symbol, die Anzahl der Anforderungen im aktuellen Schnappschuss und die Gesamtzahl der DOM-Schnappschüsse, die der DOM-Schnappschussliste hinzugefügt wurden, sollen in einem Symboldiagramm angezeigt werden:

Die Abbildung zeigt Daten des EAs, der bereits seit einiger Zeit in Betrieb ist (5019 Schnappschüsse wurden der Liste hinzugefügt)

Was kommt als Nächstes?

Im nächsten Artikel werde ich die Kollektion von DOM-Schnappschuss-Reihen erstellen, die es dem Nutzer ermöglichen, vollständig mit den DOMs beliebiger Symbole zu arbeiten, die ein aktives Abonnement des DOMs und aktivierten Broadcast haben.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit der Test-EA-Datei für MQL5 zum Testen und Herunterladen angehängt.
Die Klassen für die Arbeit mit dem DOM befinden sich in der Entwicklung, daher wird ihre Verwendung in benutzerdefinierten Programmen in diesem Stadium nicht empfohlen.
Schreiben Sie Ihre Fragen und Vorschläge in den Kommentaren.

Zurück zum Inhalt

*Frühere Artikel dieser Serie:

Preise in der DoEasy-Bibliothek (Teil 62): Aktualisieren der Tick-Serien in Echtzeit, Vorbereitung für die Arbeit mit Markttiefe
Preise in der DoEasy-Bibliothek (Teil 63): Markttiefe und deren abstrakte Anforderungsklasse