English Русский 中文 Deutsch 日本語 Português
Trabajando con los precios en la biblioteca DoEasy (Parte 64): Profundidad del mercado, clases del objeto de instantánea y del objeto de serie de instantáneas del DOM

Trabajando con los precios en la biblioteca DoEasy (Parte 64): Profundidad del mercado, clases del objeto de instantánea y del objeto de serie de instantáneas del DOM

MetaTrader 5Ejemplos | 14 abril 2021, 12:31
371 0
Artyom Trishkin
Artyom Trishkin

Contenido


Concepto

En el artículo anterior, creamos la clase del objeto de una orden abstracta del DOM y las clases herederas de este objeto. El conjunto de estos objetos constituye una instantánea (snapshot en inglés) del DOM que se obtiene al invocar una vez la función MarketBookGet(), en el momento de la activación del manejador OnBookEvent(). Los datos obtenidos por la función MarketBookGet() se registran en la matriz de estructuras MqlBookInfo. A base de estos datos obtenidos, podemos crear un objeto de instantánea del DOM que va a almacenar todas las órdenes del DOM obtenidas en la matriz de estructuras MqlBookInfo. En otras palabras, los datos en esta matriz de estructuras van a constituir una instantánea del DOM, donde cada miembro de la estructura será representado por un objeto de orden del DOM. Cada activación ordinaria del manejador OnBookEvent() va a provocar la creación de una instantánea ordinaria del DOM. A su vez, estas instantáneas van a introducirse en el objeto de la clase de la serie de instantáneas del DOM.
La clase de la matriz dinámica de punteros a las instancias de la clase CObject y sus herederos de la Biblioteca estándar nos va a servir de una lista para almacenar los objetos de instantánea del DOM. El tamaño de esta lista será limitada por un número establecido de objetos. Por defecto, el tamaño de esta lista no superará 200 000 objetos de instantánea del DOM, lo cual debe cubrir una o dos sesiones comerciales. Estas listas de serie de instantáneas del DOM serán creadas para cada símbolo usado en el programa. Al final, cada una de estas listas va a almacenarse en una colección de datos del DOM.

En este artículo, vamos a crear dos clases: la clase del objeto de instantánea del DOM de un símbolo y la clase de serie de instantáneas del DOM de un símbolo. En el siguiente artículo, crearemos y probaremos la clase de colección de estas series de instantánea del DOM.


Mejorando las clases de la biblioteca

Añadimos los índices de nuevos mensajes de la biblioteca al archivo \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
   
  };
//+------------------------------------------------------------------+

y añadimos los mensajes de texto correspondientes a los índices nuevamente añadidos:

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

Para poder especificar los criterios de ordenación por hora durante la búsqueda de objetos de instantánea necesarios del DOM en la lista de serie, tenemos que añadir una propiedad nueva para el objeto de orden del DOM, a saber, la hora de obtención de la instantánea en milisegundos. La orden no tiene esta propiedad, pero podemos monitorear la obtención de la instantánea del DOM. Además, para no introducir nuevas enumeraciones para la lista de serie de las instantáneas del DOM, donde habrá sólo una propiedad entera —la hora de obtención de la instantánea en milisegundos— añadiremos esta propiedad a las propiedades del objeto de orden del DOM. A cada orden en un objeto de instantánea se le asignará la hora de obtención de esta instantánea. Y para la búsqueda y ordenación en la lista de serie vamos a usar esta constante nuevamente añadida.

En el archivo \MQL5\Include\DoEasy\Defines.mqh escribiremos los parámetros de las series de las instantáneas del DOM que son necesarios para especificar el número de días de datos y el número máximo posible de las instantáneas en la lista:

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

El primer parámetro (número de días) no vamos a usar de momento. En el futuro, intentaremos vincular estos datos con el número de días de datos de tick, mientras tanto vamos a usar sólo el segundo parámetro —el número máximo posible de los datos de las instantáneas del DOM.

En el mimo archivo, vamos a añadir una nueva propiedad entera del objeto de orden del DOM (en milisegundos),
y aumentaremos la cantidad de las propiedades enteras del objeto a 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
//+------------------------------------------------------------------+

Como hemos añadido una nueva propiedad entera, tenemos que añadir un nuevo criterio de ordenación según las propiedades enteras:

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

Precisamente esta constante será especificada como parámetro según el cual habrá que ordenar los objetos de instantánea del DOM en la clase nueva creada del objeto de serie de instantáneas del DOM.

Pues bien, aquí llegamos a la necesidad de crear los métodos para buscar y ordenar los objetos de orden del DOM en el archivo de la clase CSelect, que se almacena en \MQL5\Include\DoEasy\Services\Select.mqh. Pueden encontrar su descripción detallada en el tercer artículo. Ahora, simplemente describiremos todas las mejoras necesarias de esta clase con el fin de organizar la búsqueda y ordenación según los objetos de orden del DOM.

Vamos a incluir la clase del objeto de orden abstracta del DOM en el archivo:

//+------------------------------------------------------------------+
//|                                                       Select.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/es/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/es/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"
//+------------------------------------------------------------------+

Declaramos todos los métodos necesarios al final del cuerpo de la clase:

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

Escribiremos su implementación fuera del cuerpo de la clase:

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

La lógica del funcionamiento de los métodos es idéntica a la lógica del funcionamiento de otros métodos parecidos de esta clase que han sido creados antes para otros objetos de la biblioteca. Por eso, no vamos a perder tiempo en describir el funcionamiento de los métodos. Lo único es que siempre pueden repasar los temas estudiados más de una vez si vuelven a consultar la descripción del funcionamiento de estos métodos.

Como hemos introducido un parámetro nuevo —la hora de obtención de la instantánea del DOM— vamos a escribir esta hora en el objeto de la orden abstracta del DOM. En la estructura MqlBookInfo, que describe una orden del DOM no hay parámetro de la hora. Por eso, nosotros tendremos que añadir la hora de obtención de la instantánea a cada objeto de orden del DOM.

Para eso, añadimos un método público nuevo al archivo de la clase de la orden abstracta del DOM \MQL5\Include\DoEasy\Objects\Book\MarketBookOrd.mqh:

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

El método simplemente establece el valor transmitido de la hora en milisegundos en la propiedad nueva del objeto.

En el constructor paramétrico de la clase de la orden abstracta del DOM, inicializamos la hora de la obtención de la instantánea usando cero:

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

La hora para cada una de las órdenes que figura en una instantánea del DOM se establecerá en el momento de la obtención de la instantánea del DOM.

Además, en el archivo de la clase de la orden abstracta del DOM  MarketBookOrd.mqh y en los archivos de las clases de sus herederos MarketBookBuy.mqh, MarketBookBuyMarket.mqh, MarketBookSell.mqh y MarketBookSellMarket.mqh, han sido introducidos pequeñas modificaciones en los métodos virtuales de la descripción de los objetos:

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

A cada uno de los métodos se le han sido añadidas las banderas que indican en la necesidad de visualizar el nombre del símbolo en la descripción del objeto. Por defecto, el símbolo no se visualiza en la descripción del objeto de orden. Eso se debe a que el objeto de orden no actúa como un objeto independiente, sino forma parte de la instantánea del DOM cuya clase vamos a hacer en este artículo. Entonces, al mostrar la descripción del objeto de instantánea del DOM, donde aparte de la descripción del objeto se muestra la descripción de todas las órdenes que forman su parte, la visualización del símbolo para cada orden parece algo excesivo, ya que el símbolo ya se visualiza en el encabezado del objeto de instantánea del DOM.

La mejora de estos métodos es igual para todas las clases arriba mencionadas.

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

Para la clase CMarketBookBuy, CMarketBookBuyMarket, CMarketBookSell y 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)+"]";
  }
//+------------------------------------------------------------------+

Para la clase 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)+"]";
  }
//+------------------------------------------------------------------+

Para la clase 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)+"]";
  }
//+------------------------------------------------------------------+

Para la clase 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)+"]";
  }
//+------------------------------------------------------------------+

Por tanto, en la declaración de estos métodos, en todas las clases herederas, han sido añadidas las banderas:

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

Por defecto, el símbolo no va a visualizarse en la descripción del objeto


Clase del objeto de instantánea del DOM

Bien, ya está todo preparado para crear la clase del objeto de instantánea del DOM. En esencia, se trata de una lista de órdenes del DOM obtenida en la matriz de estructuras MqlBookInfo al ser activado el manejador OnBookEvent(). Lo único es que cada una de las órdenes ubicadas en la matriz será representada en esta clase por el objeto de la clase CMarketBookOrd —por sus herederos. Todos ellos van a colocarse en la lista CArrayObj, que constituye la clase de la matriz dinámica de punteros a las instancias de la clase CObject y sus herederos de la Biblioteca estándar. Aparte de la lista que almacenará los objetos de orden del DOM, la clase va a proporcionar las posibilidades estándar para todos los objetos de la biblioteca de trabajar con estos objetos y con sus listas (búsqueda y ordenación según diferentes propiedades), para una conveniente recopilación de datos estadísticos durante el trabajo con el DOM en nuestros programas.

En la carpeta de la biblioteca \MQL5\Include\DoEasy\Objects\Book\ creamos archivo nuevo MarketBookSnapshot.mqh de la clase CMBookSnapshot.
De clase base servirá la clase del objeto básico de todos los objetos de la biblioteca CBaseObj
.
El archivo debe incluir los archivos de las clases de objetos herederos del objeto de la orden abstracta del DOM
.

Vamos a echar un vistazo al listado de la clase y a la implementación de sus métodos:

//+------------------------------------------------------------------+
//|                                           MarketBookSnapshot.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/es/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/es/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;   }
  };
//+------------------------------------------------------------------+

Aquí, podemos observar una organización común de la clase, como la de los demás objetos de la biblioteca. En la sección privada, tenemos declaradas las variables–miembros de la clase. En la sección pública, están declarados los métodos estándar para los objetos de la biblioteca para devolver las listas según las propiedades especificadas de los objetos de orden; el método para comparar dos objetos de instantánea del DOM para buscar y ordenar estos objetos en la lista en la que luego vamos a colocarlos (en la lista del objeto de serie de las instantáneas del DOM); los métodos para describir el objeto de instantánea del DOM; dos constructores —constructor predefinido y constructor paramétrico (el constructor paramétrico se usará al crear nuevos objetos de instantánea del DOM para los que se conocen todas sus propiedades; por defecto él va a servir para crear rápidamente un objeto nuevo y añadirle una propiedad necesaria con el fin de buscar los objetos en la lista con un valor especificado de esta propiedad). Los métodos del acceso simplificado a las propiedades del objeto sirven para establecer y devolver algunas propiedades del objeto que serán necesarias más tarde.

Vamos a analizar la implementación de los métodos de la clase.

En el constructor paramétrico, revisamos la matriz de estructuras transmitida MqlBookInfo, y de acuerdo con el tipo de las órdenes, creamos los tipos correspondientes de los objetos de orden del DOM y los añadimos a la lista.

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

Método para devolver el nombre breve del objeto de instantánea del DOM:

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

Aquí, simplemente se crea una cadena compuesta del mensaje de texto con la descripción del objeto y del símbolo, que tendrá aproximadamente el siguiente aspecto:

EURUSD DOM snapshot

Método que muestra en el diario la descripción breve del objeto de instantánea del DOM:

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

El método muestra en el diario una cadena compuesta del nombre del objeto y de la hora de la instantánea del DOM en milisegundos, por ejemplo:

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

Método que muestra en el diario las propiedades del objeto de instantánea del 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());
     }
  }
//+------------------------------------------------------------------+

Primero, se muestra el encabezado con la descripción de la instantánea del DOM. Luego, en el ciclo por la lista de todos los objetos de orden del DOM, se muestran sus descripciones.

Ya que los objetos de orden que se encuentran en la lista del objeto de instantánea del DOM no tienen la posibilidad de obtener su hora, escribiremos en esta clase el método que establece para todos los objetos de orden en la lista la hora en milisegundos registrada en este objeto

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

En el ciclo por la lista de todos los objetos de orden del DOM, obtenemos el objeto de orden y le establecemos la hora registrada en las propiedades del objeto de instantánea del DOM. De esta manera, todos los objetos de orden ubicados en la lista de esta instantánea del DOM tienen la misma hora de su obtención, lo cual es lógico. Los obtenemos cuando se activa el manejador OnBookEvent(), y asignamos la hora de activación al objeto de instantánea del DOM y a todas sus órdenes.

El objeto de instantánea del DOM está preparado. Ahora tenemos que ubicar estos objetos en la lista, porque cuando se activa el manejador OnBookEvent(), vamos a obtener una nueva instantánea del DOM y crear el objeto correspondiente.
Vamos a almacenar todos estos objetos en la clase del objeto de serie de instantáneas del DOM.

Clase del objeto de serie de instantáneas del DOM

La clase de la serie de instantáneas del DOM, según su «ideología», parece a las clases de las series temporales de los símbolos o de datos de tick. A diferencia de estas clases, donde se puede obtener los datos desde el entorno, en la clase de lista de las instantáneas del DOM no podemos obtener datos históricos: tendremos que acumularlos en modo de tiempo real. Por eso, la clase no va a tener el método para crear la lista, sólo tendrá el método de su actualización.

En la carpeta de la biblioteca \MQL5\Include\DoEasy\Objects\Book\ creamos archivo nuevo MBookSeries.mqh de la clase CMBookSeries.
De clase base servirá la clase del objeto básico de todos los objetos de la biblioteca CBaseObj
.
El archivo debe incluir el archivo de la clase del objeto de instantánea del DOM
.

Vamos a examinar el listado de la clase, luego analizaremos sus métodos:

//+------------------------------------------------------------------+
//|                                                  MBookSeries.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/es/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/es/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);
  };
//+------------------------------------------------------------------+

Bien, ¿qué es lo que vemos aquí?

  • métodos estándar para los objetos de la biblioteca para obtener las propiedades del objeto y de las listas de objetos según propiedades especificadas,
  • métodos para establecer algunas propiedades,
  • método de comparación de dos objetos de lista para ordenarlos sólo según el nombre del símbolo,
  • métodos de devolución del nombre del objeto y constructores de la clase.

Vamos a analizar la implementación de los métodos de la clase.

En el constructor paramétrico (en su lista de inicialización), se establece el símbolo de la lista. Se limpia en el cuerpo del método, se le asigna la bandera de una lista ordenada según la hora en milisegundos y se establece la cantidad necesaria de días de los datos de las instantáneas del 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);
  }
//+------------------------------------------------------------------+

Método para actualizar la lista de instantáneas del 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;
  }
//+------------------------------------------------------------------+

El método va a invocarse cuando se active el manejador OnBookEvent(). Por tanto, al método se le transmite la hora de la activación del manejador. Usando MarketBookGet() obtenemos la matriz de estructuras del DOM. A base de esta estructura, creamos un nuevo objeto de instantánea del DOM y lo añadimos a la lista de serie de instantáneas.
La lógica al completo se describe en los comentarios al código. Creo que la lógica está clara.

Método para establecer el nombre del símbolo para la lista de serie de instantáneas:

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

Aquí, todo es transparente: si ha sido transmitido NULL o una cadena vacía, se establece el símbolo actual; de lo contrario, el que ha sido transmitido al método.

Método para establecer el número de días para la serie la serie de instantáneas del 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);
  }
//+------------------------------------------------------------------+

Si ha sido transmitido el valor cero, se establece el número de días especificado por defecto; de lo contrario, el que ha sido transmitido al método. De momento, este método no se usa en ningún sitio.

Método para devolver el objeto de instantánea del DOM según la hora especificada:

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

Aquí: creamos un objeto de instantánea temporal del DOM, le asignamos la hora necesaria, la bandera de una lista ordenada, y usando el método Search() obtenemos el índice del objeto en la lista con la hora igual a la buscada. Eliminamos necesariamente el objeto temporal y devolvemos el puntero al objeto encontrado según el índice en la lista.

Método para devolver la hora en milisegundos de la instantánea del DOM especificada según el índice:

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

Obtenemos el puntero al objeto de instantánea del DOM según el índice especificado y devolvemos su hora en milisegundos, o NULL en caso de fallo.

Método para devolver el nombre de la serie de instantáneas del DOM:

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

El método devuelve una cadena compuesta de la descripción del objeto y símbolo, por ejemplo:

Series of "EURUSD" DOM snapshots

Método que muestra en el diario la descripción de la serie de instantáneas del 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);
  }
//+------------------------------------------------------------------+

Primero, se crea el encabezado con la descripción de la serie de instantáneas, número solicitado de días de los datos y el número real recopilado de las instantáneas del DOM. Luego, se muestran cíclicamente las descripciones de todas las órdenes que forman parte del objeto de instantánea.

Con esto, damos por terminada la creación de las clases del objeto de instantánea y del objeto de serie de instantáneas del DOM.

Prueba

Para la simulación, vamos a usar el asesor del artículo anterior
y guardarlo en la nueva carpeta \MQL5\Experts\TestDoEasy\Part64\ con el nombre nuevo TestDoEasyPart64.mq5.

Vamos a crear el objeto de serie de instantáneas del DOM para el símbolo actual en el asesor. Cada vez que se active el manejador OnBoolEvent() para el símbolo actual, vamos a añadir el nuevo objeto de instantánea a la lista. En el comentario del gráfico, mostramos los datos sobre el número de los objetos de instantáneas añadidos a la lista y dos ordenes extremas de la instantánea actual: la máxima de venta y la mínima de compra. Al obtener los datos del DOM por primera vez, los visualizamos en el diario del terminal.

Eliminamos del listado del EA la inclusión de las clases de los objetos de órdenes. Ahora, están incluidas en los archivos de nuevas clases que hemos creado hoy:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart63.mq5 |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/es/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/es/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

En vez de ellas, añadimos la inclusión del archivo de la clase de serie de las instantáneas del DOM:

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

En la lista de variables globales del EA, declaramos el objeto de la clase de la serie de instantáneas del 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;
//+------------------------------------------------------------------+

Todo el trabajo de la creación de la lista de la serie de instantáneas del DOM se realiza en el manejador 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;
        }
     }
  }
//+------------------------------------------------------------------+

Todas las cadenas del código están comentadas y espero que no requieran aclaraciones adicionales.
En cualquier caso, el lector podrá escribir cualquier duda en los comentarios al artículo.

Compilamos el EA y lo iniciamos en el gráfico de cualquier símbolo, estableciendo previamente en los ajustes el uso de dos símbolos especificados y marco temporal actual:


En el diario, se mostrarán los datos sobre la serie de instantáneas que ha sido creada y sobre la primera instantánea:

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]

En el gráfico, se mostrarán los datos sobre la hora de la última instantánea del DOM, número de órdenes para el símbolo, número de órdenes en la instantánea actual y número total de instantáneas del DOM añadidas a la lista de instantáneas:

En la imagen se muestran los datos para el EA que ya estaba operando algún tiempo (5019 instantáneas han sido añadidas a la lista)

¿Qué es lo próximo?

En el siguiente artículo, vamos a crear una colección de las series de instantáneas del DOM. Eso nos permitirá trabajar de forma plenamente operativa con los DOMs de cualquier símbolo que tenga activada la suscripción al DOM y permitida su transmisión.

Más abajo se adjuntan todos los archivos de la versión actual de la biblioteca y el archivo del asesor de prueba para MQL5. Puede descargarlo todo y ponerlo a prueba por sí mismo.
Cabe mencionar que las clases para trabajar con el DOM se encuentran en el proceso del desarrollo. Por tanto, no se recomienda usarlas en sus programas en esta fase.
Si tiene preguntas, observaciones o sugerencias, podrá concretarlas en los comentarios al artículo.

Volver al contenido

Artículos de esta serie:

Trabajando con los precios en la biblioteca DoEasy (Parte 61): Actualización de las series de tick en tiempo real, preparando para trabajar con la Profundidad del mercado
Trabajando con los precios en la biblioteca DoEasy (Parte 63): Profundidad del mercado, clase de orden abstracta de la Profundidad del mercado

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/9044

Archivos adjuntos |
MQL5.zip (3897 KB)
Redes neuronales: así de sencillo (Parte 10): Multi-Head Attention (atención multi-cabeza) Redes neuronales: así de sencillo (Parte 10): Multi-Head Attention (atención multi-cabeza)
Ya hemos hablado con anterioridad del mecanismo de auto-atención (self-attention) en las redes neuronales. En la práctica, en las arquitecturas de las redes neuronales modernas, se usan varios hilos de auto-atención paralelos para buscar diversas dependencias entre los elementos de la secuencia. Vamos a ver la implementación de este enfoque y evaluar su influencia en el rendimiento general de la red.
Aproximación por fuerza bruta a la búsqueda de patrones (Parte II): Nuevos horizontes Aproximación por fuerza bruta a la búsqueda de patrones (Parte II): Nuevos horizontes
Este artículo prosigue con el tema de la fuerza bruta, ofreciendo al algoritmo de nuestro programa nuevas posibilidades para el análisis de mercado, y acelerando la velocidad de análisis y la calidad de los resultados finales, lo cual brinda un punto de vista de máxima calidad sobre los patrones globales en el marco de este enfoque.
Aplicación práctica de las redes neuronales en el trading (Parte 2). Visión por computadora Aplicación práctica de las redes neuronales en el trading (Parte 2). Visión por computadora
El uso de la visión por computadora permite entrenar redes neuronales con la representación visual de la tabla de precios y los indicadores. Este método nos permitirá utilizar con mayor libertad todo el complejo de indicadores técnicos, pues no requiere su suministro digital a la red neuronal.
Buscando patrones estacionales en el mercado de divisas con la ayuda del algoritmo CatBoost Buscando patrones estacionales en el mercado de divisas con la ayuda del algoritmo CatBoost
En el presente artículo, mostramos la posibilidad de crear modelos de aprendizaje automático con filtros temporales y también descubrimos la efectividad de este enfoque. Ahora, podremos descartar el factor humano, diciéndole simplemente al modelo: "Quiero que comercies a una hora determinada de un día concreto de la semana". Así, podremos delegar en el algoritmo la búsqueda de patrones.