Trabajando con los precios en la biblioteca DoEasy (Parte 63): Profundidad del mercado, clase de orden abstracta de la Profundidad del mercado

Artyom Trishkin | 30 marzo, 2021

Contenido


Concepto

A partir de este artículo, empezaremos a desarrollar la funcionalidad para trabajar con la Profundidad del mercado (en inglés Depth of Market, o DOM). Las clases para trabajar con el DOM no van a diferenciarse conceptualmente de todas las demás clases de la biblioteca desarrolladas anteriormente. Al mismo tiempo, vamos a tener una plantilla del DOM que va a contener datos sobre las ordenes en el DOM que se obtienen por la función MarketBookGet() cuando se active el manejador OnBookEvent(). Ahí, cuando el DOM se cambie, se activa un evento para cada símbolo que tenga activada la suscripción a los eventos del DOM.

De esta forma, la estructura del DOM va a ser la siguiente:

  1. La clase del objeto de orden del DOM es un objeto que describe los datos de una orden entre varias ordenes que se obtienen del DOM, durante la activación unitaria del manejador OnBookEvent() para un símbolo;
  2. La clase del objeto de plantilla del DOM es un objeto que describe los datos de todas las órdenes que se obtienen del DOM al mismo tiempo, durante una activación del manejador OnBookEvent() para un símbolo. Se trata de un conjunto de objetos del punto 1 que forman parte de la plantilla actual del DOM;
  3. La clase de serie temporal compuesta de una secuencia de objetos del punto 2 que se introducen en la lista de serie temporal durante cada activación de OnBookEvent() para un símbolo;
  4. La clase de colección de las series de datos de los DOMs de todos los símbolos utilizados en el programa que tienen activada la suscripción a los eventos del DOM.

En este artículo, vamos a crear la clase del objeto de orden (1) y hacer la prueba de la obtención de datos del DOM cuando OnBookEvent() se active en el símbolo actual.

Las propiedades de cada orden están escritas en la estructura MqlBookInfo que facilita la información en el DOM:

  • tipo de la orden desde la enumeración ENUM_BOOK_TYPE
  • precio de la orden colocada
  • volumen de la orden
  • volumen de la orden con precisión aumentada

En el DOM puede haber cuatro tipos de órdenes (de la enumeración ENUM_BOOK_TYPE):

  • Orden de venta
  • Orden de venta por el precio de mercado
  • Orden de compra
  • Orden de compra por el precio de mercado

Como podemos observar, hay cuatros tipos de órdenes: dos en la dirección Buy, y otras dos en la dirección Sell. Por tanto, para dividir todos los tipos de las órdenes según estas dos direcciones, aparte de las propiedades existentes, vamos a añadir una más: el estatus de la orden que indica su dirección (solicitud en la dirección Buy o solicitud en la dirección Sell). En lo sucesivo, eso nos permitirá dividir todas las órdenes según sus direcciones (demanda y oferta).

El objeto de una orden del DOM será hecho a semejanza de los objetos de orden (y muchos otros objetos de la biblioteca): es decir, habrá un objeto básico de la orden abstracta del DOM y cuatro objetos herederos con precisión del tipo de la orden. El concepto de la construcción de estos objetos ya fue considerado al principio del desarrollo de la biblioteca, en el primero y en el segundo artículos.

Antes de empezar a crear las clases para trabajar con el DOM, añadiremos nuevos mensajes de la biblioteca y mejoraremos un poco las clases de los objetos de datos de tick. Añadimos los índices de nuevos mensajes al archivo \MQL5\Include\DoEasy\Data.mqh:

   MSG_SYM_EVENT_SYMBOL_ADD,                          // Added symbol to Market Watch window
   MSG_SYM_EVENT_SYMBOL_DEL,                          // Symbol removed from Market Watch window
   MSG_SYM_EVENT_SYMBOL_SORT,                         // Changed location of symbols in Market Watch window
   MSG_SYM_SYMBOLS_MODE_CURRENT,                      // Work with current symbol only
   MSG_SYM_SYMBOLS_MODE_DEFINES,                      // Work with predefined symbol list
   MSG_SYM_SYMBOLS_MODE_MARKET_WATCH,                 // Work with Market Watch window symbols
   MSG_SYM_SYMBOLS_MODE_ALL,                          // Work with full list of all available symbols
   MSG_SYM_SYMBOLS_BOOK_ADD,                          // Subscribed to Depth of Market 
   MSG_SYM_SYMBOLS_BOOK_DEL,                          // Unsubscribed from Depth of Market 
   MSG_SYM_SYMBOLS_MODE_BOOK,                         // Subscription to Depth of Market
   MSG_SYM_SYMBOLS_ERR_BOOK_ADD,                      // Error subscribing to DOM
   MSG_SYM_SYMBOLS_ERR_BOOK_DEL,                      // Error unsubscribing from DOM
   
//--- CAccount

...

//--- CTickSeries
   MSG_TICKSERIES_TEXT_TICKSERIES,                    // Tick series
   MSG_TICKSERIES_ERR_GET_TICK_DATA,                  // Failed to get tick data
   MSG_TICKSERIES_FAILED_CREATE_TICK_DATA_OBJ,        // Failed to create tick data object
   MSG_TICKSERIES_FAILED_ADD_TO_LIST,                 // Failed to add tick data object to list
   MSG_TICKSERIES_TEXT_IS_NOT_USE,                    // Tick series not used. Set the flag using SetAvailable()
   MSG_TICKSERIES_REQUIRED_HISTORY_DAYS,              // Requested number of days
   
//--- 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

  };
//+------------------------------------------------------------------+

y los textos de los mensajes que se corresponden con los índices nuevamente añadidos:

   {"В окно \"Обзор рынка\" добавлен символ","Added symbol to \"Market Watch\" window"},
   {"Из окна \"Обзор рынка\" удалён символ","Removed from \"Market Watch\" window"},
   {"Изменено расположение символов в окне \"Обзор рынка\"","Changed arrangement of symbols in \"Market Watch\" window"},
   {"Работа только с текущим символом","Work only with the current symbol"},
   {"Работа с предопределённым списком символов","Work with predefined list of symbols"},
   {"Работа с символами из окна \"Обзор рынка\"","Working with symbols from \"Market Watch\" window"},
   {"Работа с полным списком всех доступных символов","Work with full list of all available symbols"},
   {"Осуществлена подписка на стакан цен ","Subscribed to Depth of Market"},
   {"Осуществлена отписка от стакан цен ","Unsubscribed from Depth of Market"},
   {"Подписка на стакан цен","Subscription to Depth of Market"},
   {"Ошибка при подписке на стакан цен",""},
   {"Ошибка при отписке от стакан цен",""},
   
//--- CAccount

...

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

En el archivo de la clase del objeto de símbolo \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh añadimos la visualización de los mensajes sobre el error al realizar la suscripción al DOM:

//+------------------------------------------------------------------+
//| Subscribe to the Depth of Market                                 |
//+------------------------------------------------------------------+
bool CSymbol::BookAdd(void)
  {
   this.m_book_subscribed=(#ifdef __MQL5__ ::MarketBookAdd(this.m_name) #else false #endif);
   this.m_long_prop[SYMBOL_PROP_BOOKDEPTH_STATE]=this.m_book_subscribed;
   if(this.m_book_subscribed)
      ::Print(CMessage::Text(MSG_SYM_SYMBOLS_BOOK_ADD)+" "+this.m_name);
   else
      ::Print(CMessage::Text(MSG_SYM_SYMBOLS_ERR_BOOK_ADD)+": "+CMessage::Text(::GetLastError()));
   return this.m_book_subscribed;
  }
//+------------------------------------------------------------------+

hacemos lo mismo cuando intentamos dar de baja la suscripción:

//+------------------------------------------------------------------+
//| Close the market depth                                           |
//+------------------------------------------------------------------+
bool CSymbol::BookClose(void)
  {
//--- If the DOM subscription flag is off, subscription is disabled (or not enabled yet). Return 'true'
   if(!this.m_book_subscribed)
      return true;
//--- Save the result of unsubscribing from the DOM
   bool res=( #ifdef __MQL5__ ::MarketBookRelease(this.m_name) #else true #endif );
//--- If unsubscribed successfully, reset the DOM subscription flag and write the status to the object property
   if(res)
     {
      this.m_long_prop[SYMBOL_PROP_BOOKDEPTH_STATE]=this.m_book_subscribed=false;
      ::Print(CMessage::Text(MSG_SYM_SYMBOLS_BOOK_DEL)+" "+this.m_name);
     }
   else
     {
      this.m_long_prop[SYMBOL_PROP_BOOKDEPTH_STATE]=this.m_book_subscribed=true;
      ::Print(CMessage::Text(MSG_SYM_SYMBOLS_ERR_BOOK_DEL)+": "+CMessage::Text(::GetLastError()));
     }
//--- Return the result of unsubscribing from DOM
   return res;
  }
//+------------------------------------------------------------------+

En el método para actualizar la serie de tick de la clase de la serie de tick, en el archivo \MQL5\Include\DoEasy\Objects\Ticks\TickSeries.mqh, eliminamos la visualización de los comentarios de depuración en el gráfico del símbolo , la que dejamos en el artículo anterior para la simulación:

//+------------------------------------------------------------------+
//| Update the tick series list                                      |
//+------------------------------------------------------------------+
void CTickSeries::Refresh(void)
  {
   MqlTick ticks_array[];
   if(IsNewTick())
     {
      //--- Copy ticks from m_last_time time+1 ms to the end of history
      int err=ERR_SUCCESS;
      int total=::CopyTicksRange(this.Symbol(),ticks_array,COPY_TICKS_ALL,this.m_last_time+1,0);
      //--- If the ticks have been copied, create new tick data objects and add them to the list in the loop by their number
      if(total>0)
        {
         for(int i=0;i<total;i++)
           {
            //--- Create the tick object and add it to the list
            CDataTick *tick_obj=this.CreateNewTickObj(ticks_array[i]);
            if(tick_obj==NULL)
               break;
            //--- Write the last tick time for subsequent copying of newly arrived ticks
            long end_time=ticks_array[::ArraySize(ticks_array)-1].time_msc;
            if(this.Symbol()=="AUDUSD")
               Comment(DFUN,this.Symbol(),", copied=",total,", m_last_time=",TimeMSCtoString(m_last_time),", end_time=",TimeMSCtoString(end_time),", total=",DataTotal());
            this.m_last_time=end_time;
           }
         //--- If the number of ticks in the list exceeds the default maximum number,
         //--- remove the calculated number of tick objects from the end of the list
         if(this.DataTotal()>TICKSERIES_MAX_DATA_TOTAL)
           {
            int total_del=m_list_ticks.Total()-TICKSERIES_MAX_DATA_TOTAL;
            for(int j=0;j<total_del;j++)
               this.m_list_ticks.Delete(j);
           }
        }
     }
  }
//+------------------------------------------------------------------+

Ahora, la hora del último tick va a registrarse directamente en la variable m_last_time que sirve precisamente para eso, porque en el artículo anterior, teníamos que visualizar los datos de prueba a través del comentario en el gráfico del símbolo, donde era necesario ver la hora del tick anterior y del tick actual. Ahora, no lo necesitamos, vamos a guardar la hora directamente en la variable:

//+------------------------------------------------------------------+
//| Update the tick series list                                      |
//+------------------------------------------------------------------+
void CTickSeries::Refresh(void)
  {
   MqlTick ticks_array[];
   if(IsNewTick())
     {
      //--- Copy ticks from m_last_time time+1 ms to the end of history
      int err=ERR_SUCCESS;
      int total=::CopyTicksRange(this.Symbol(),ticks_array,COPY_TICKS_ALL,this.m_last_time+1,0);
      //--- If the ticks have been copied, create new tick data objects and add them to the list in the loop by their number
      if(total>0)
        {
         for(int i=0;i<total;i++)
           {
            //--- Create the tick object and add it to the list
            CDataTick *tick_obj=this.CreateNewTickObj(ticks_array[i]);
            if(tick_obj==NULL)
               break;
            //--- Write the last tick time for subsequent copying of newly arrived ticks
            this.m_last_time=ticks_array[::ArraySize(ticks_array)-1].time_msc;
           }
         //--- If the number of ticks in the list exceeds the default maximum number,
         //--- remove the calculated number of tick objects from the end of the list
         if(this.DataTotal()>TICKSERIES_MAX_DATA_TOTAL)
           {
            int total_del=m_list_ticks.Total()-TICKSERIES_MAX_DATA_TOTAL;
            for(int j=0;j<total_del;j++)
               this.m_list_ticks.Delete(j);
           }
        }
     }
  }
//+------------------------------------------------------------------+


Clase del objeto de orden abstracta en la Profundidad del mercado

Al igual que para todos los objetos de la biblioteca que tienen sus propios conjuntos de enumeraciones para determinar constantes de las propiedades del objeto, es necesario crear enumeraciones de las propiedades de tipo entero, real y string del objeto para los objetos nuevos de las clases de objetos de orden del DOM.

Añadimos las enumeraciones de las propiedades y parámetros del objeto de orden del DOM al archivo \MQL5\Include\DoEasy\Defines.mqh. Como no vamos a hacer el modelo de eventos para trabajar con cada orden en el DOM (en un momento dado, el DOM muestra el estado actual de todas las órdenes, y su modificación lleva a su siguiente estado y se procesa durante la siguiente activación de OnBookEvent()), simplemente añadimos una constante que indica el código del siguiente evento después del último código del evento del DOM. Se hace para mantener la identidad de constantes de todos los objetos, es decir, reducirlas a una imagen común:

//+------------------------------------------------------------------+
//| Data for working with DOM                                        |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of possible DOM events                                      |
//+------------------------------------------------------------------+
#define MBOOK_ORD_EVENTS_NEXT_CODE  (SERIES_EVENTS_NEXT_CODE+1)   // The code of the next event after the last DOM event code
//+------------------------------------------------------------------+

Vamos a definir la enumeración en la que escribiremos dos posibles estatus de una orden en el DOM (Buy o Sell):

//+------------------------------------------------------------------+
//| Abstract DOM type (status)                                       |
//+------------------------------------------------------------------+
enum ENUM_MBOOK_ORD_STATUS
  {
   MBOOK_ORD_STATUS_BUY,                              // Buy side
   MBOOK_ORD_STATUS_SELL,                             // Sell side
  };
//+------------------------------------------------------------------+

La filtración de todas las órdenes en el DOM según estas propiedades permitirá formar una lista con todas las órdenes en el DOM que pertenecen a la demanda o a la oferta.

A continuación, añadiremos enumeraciones de las propiedades de tipo entero, real y string del objeto de orden del DOM:

//+------------------------------------------------------------------+
//| 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
  }; 
#define MBOOK_ORD_PROP_INTEGER_TOTAL (3)              // Total number of integer properties
#define MBOOK_ORD_PROP_INTEGER_SKIP  (0)              // Number of integer DOM properties not used in sorting
//+------------------------------------------------------------------+
//| Real properties of DOM order                                     |
//+------------------------------------------------------------------+
enum ENUM_MBOOK_ORD_PROP_DOUBLE
  {
   MBOOK_ORD_PROP_PRICE = MBOOK_ORD_PROP_INTEGER_TOTAL, // Order price
   MBOOK_ORD_PROP_VOLUME_REAL,                        // Extended accuracy order volume
  };
#define MBOOK_ORD_PROP_DOUBLE_TOTAL  (2)              // Total number of real properties
#define MBOOK_ORD_PROP_DOUBLE_SKIP   (0)              // Number of real properties not used in sorting
//+------------------------------------------------------------------+
//| String properties of DOM order                                   |
//+------------------------------------------------------------------+
enum ENUM_MBOOK_ORD_PROP_STRING
  {
   MBOOK_ORD_PROP_SYMBOL = (MBOOK_ORD_PROP_INTEGER_TOTAL+MBOOK_ORD_PROP_DOUBLE_TOTAL), // Order symbol name
  };
#define MBOOK_ORD_PROP_STRING_TOTAL  (1)              // Total number of string properties
//+------------------------------------------------------------------+

Por consiguiente, escribiremos para las propiedades creadas una enumeración de posibles criterios de ordenación de las órdenes en el DOM:

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

Ahora, se puede crear la clase del objeto de orden abstracta en el DOM

En el catálogo de la biblioteca \MQL5\Include\DoEasy\Objects\ creamos la nueva carpeta Book\, y dentro de ella, el nuevo archivo MarketBookOrd.mqh de la clase CMarketBookOrd derivada del objeto básico de todos los objetos de la biblioteca CBaseObj:

//+------------------------------------------------------------------+
//|                                                MarketBookOrd.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\DELib.mqh"
#include "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| DOM abstract order class                                         |
//+------------------------------------------------------------------+
class CMarketBookOrd : public CBaseObj
  {
private:
   int               m_digits;                                       // Number of decimal places
   long              m_long_prop[MBOOK_ORD_PROP_INTEGER_TOTAL];      // Integer properties
   double            m_double_prop[MBOOK_ORD_PROP_DOUBLE_TOTAL];     // Real properties
   string            m_string_prop[MBOOK_ORD_PROP_STRING_TOTAL];     // String properties

//--- Return the index of the array the (1) double and (2) string properties are actually located at
   int               IndexProp(ENUM_MBOOK_ORD_PROP_DOUBLE property)  const { return(int)property-MBOOK_ORD_PROP_INTEGER_TOTAL;                              }
   int               IndexProp(ENUM_MBOOK_ORD_PROP_STRING property)  const { return(int)property-MBOOK_ORD_PROP_INTEGER_TOTAL-MBOOK_ORD_PROP_DOUBLE_TOTAL;  }

public:
//--- Set object's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_MBOOK_ORD_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                      }
   void              SetProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;    }
   void              SetProperty(ENUM_MBOOK_ORD_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;    }
//--- Return object’s (1) integer, (2) real and (3) string property from the properties array
   long              GetProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)        const { return this.m_long_prop[property];                     }
   double            GetProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];   }
   string            GetProperty(ENUM_MBOOK_ORD_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];   }
//--- Return itself
   CMarketBookOrd   *GetObject(void)                                                { return &this;}

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)          { return true; }
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)           { return true; }
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_STRING property)           { return true; }

//--- Get description of (1) integer, (2) real and (3) string properties
   string            GetPropertyDescription(ENUM_MBOOK_ORD_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_MBOOK_ORD_PROP_STRING property);

//--- Display the description of object properties in the journal (full_prop=true - all properties, false - supported ones only)
   void              Print(const bool full_prop=false);
//--- Display a short description of the object in the journal
   virtual void      PrintShort(void);
//--- Return the object short name
   virtual string    Header(void);
   
//--- Compare CMarketBookOrd objects by all possible properties (to sort the lists by a specified order object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CMarketBookOrd objects by all properties (to search for equal request objects)
   bool              IsEqual(CMarketBookOrd* compared_req) const;
   
//--- Default constructor
                     CMarketBookOrd(){;}
protected:
//--- Protected parametric constructor
                     CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol);
                     
public:
//+-------------------------------------------------------------------+ 
//|Methods of a simplified access to the DOM request object properties|
//+-------------------------------------------------------------------+
//--- Return order (1) status, (2) type and (3) order volume
   ENUM_MBOOK_ORD_STATUS Status(void)        const { return (ENUM_MBOOK_ORD_STATUS)this.GetProperty(MBOOK_ORD_PROP_STATUS);   }
   ENUM_BOOK_TYPE    TypeOrd(void)           const { return (ENUM_BOOK_TYPE)this.GetProperty(MBOOK_ORD_PROP_TYPE);            }
   long              Volume(void)            const { return this.GetProperty(MBOOK_ORD_PROP_VOLUME);                          }
//--- Return (1) the price and (2) extended accuracy order volume
   double            Price(void)             const { return this.GetProperty(MBOOK_ORD_PROP_PRICE);                           }
   double            VolumeReal(void)        const { return this.GetProperty(MBOOK_ORD_PROP_VOLUME_REAL);                     }
//--- Return (1) order symbol and (2) symbol's Digits
   string            Symbol(void)            const { return this.GetProperty(MBOOK_ORD_PROP_SYMBOL);                          }
   int               Digits()                const { return this.m_digits;                                                    }
   
//--- Return the description of order  (1) type (ENUM_BOOK_TYPE) and (2) status (ENUM_MBOOK_ORD_STATUS)
   virtual string    TypeDescription(void)   const { return this.StatusDescription();                                         }
   string            StatusDescription(void) const;

  };
//+------------------------------------------------------------------+

La estructura de la clase es idéntica a otras clases de los objetos de la biblioteca. Ya las analizamos varias veces. Pueden refrescar la memoria y consultar las primeras y posteriores artículos donde todo se describe al detalle.

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

En el constructor paramétrico cerrado de la clase, establecemos todas las propiedades del objeto desde la estructura de la orden de el DOM transmitida al constructor:

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

Además al constructor se le transmite el estatus de la orden que vamos a indicar en los objetos herederos de esta clase durante la creación de un nuevo objeto de orden del DOM.

Método para comparar dos objetos CMarketBookOrd entre sí según la propiedad indicada para determinar la igualdad de propiedades indicadas de dos objetos:

//+------------------------------------------------------------------+
//| Compare CMarketBookOrd objects                                   |
//| by a specified property                                          |
//+------------------------------------------------------------------+
int CMarketBookOrd::Compare(const CObject *node,const int mode=0) const
  {
   const CMarketBookOrd *obj_compared=node;
//--- compare integer properties of two objects
   if(mode<MBOOK_ORD_PROP_INTEGER_TOTAL)
     {
      long value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare real properties of two objects
   else if(mode<MBOOK_ORD_PROP_DOUBLE_TOTAL+MBOOK_ORD_PROP_INTEGER_TOTAL)
     {
      double value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare string properties of two objects
   else if(mode<MBOOK_ORD_PROP_DOUBLE_TOTAL+MBOOK_ORD_PROP_INTEGER_TOTAL+MBOOK_ORD_PROP_STRING_TOTAL)
     {
      string value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+

El método recibe el objeto cuya propiedad debe ser comparada con la misma propiedad del objeto actual. Si la propiedad indicada del objeto comparado tiene el valor inferior al actual, se devuelve -1; si es superior, se devuelve +1; si las propiedades son iguales, se devuelve 0.

Método para comparar dos objetos CMarketBookOrd entre sí según todas las propiedades. Permite determinar la igualdad completa de dos objetos comparados:

//+------------------------------------------------------------------+
//| Compare CMarketBookOrd objects by all properties                 |
//+------------------------------------------------------------------+
bool CMarketBookOrd::IsEqual(CMarketBookOrd *compared_obj) const
  {
   int beg=0, end=MBOOK_ORD_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_INTEGER prop=(ENUM_MBOOK_ORD_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=MBOOK_ORD_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_DOUBLE prop=(ENUM_MBOOK_ORD_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=MBOOK_ORD_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_STRING prop=(ENUM_MBOOK_ORD_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

Aquí, todas las propiedades de dos objetos se comparan una por una, y si las propiedades no son iguales, se devuelve false. Después de comprobar si todas las propiedades de dos objetos son iguales, y si false no ha sido devuelto, se devuelve true. Es decir, ambos objetos son absolutamente idénticos.

Método que muestra en el diario todas las propiedades del objeto:

//+------------------------------------------------------------------+
//| Display object properties in the journal                         |
//+------------------------------------------------------------------+
void CMarketBookOrd::Print(const bool full_prop=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=MBOOK_ORD_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_INTEGER prop=(ENUM_MBOOK_ORD_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=MBOOK_ORD_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_DOUBLE prop=(ENUM_MBOOK_ORD_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=MBOOK_ORD_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_MBOOK_ORD_PROP_STRING prop=(ENUM_MBOOK_ORD_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n");
  }
//+------------------------------------------------------------------+

Vamos a iterar en tres ciclos por todas las propiedades de tipo entero, real y string, mostrando las descripciones string de cada siguiente propiedad en el diario.

Los métodos que retornan las descripciones de la propiedad especificada de tipo entero, real y string del objeto:

//+------------------------------------------------------------------+
//| Return description of object's integer property                  |
//+------------------------------------------------------------------+
string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   return
     (
      property==MBOOK_ORD_PROP_STATUS        ?  CMessage::Text(MSG_ORD_STATUS)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.StatusDescription()
         )  :
      property==MBOOK_ORD_PROP_TYPE          ?  CMessage::Text(MSG_ORD_TYPE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.TypeDescription()
         )  :
      property==MBOOK_ORD_PROP_VOLUME        ?  CMessage::Text(MSG_MBOOK_ORD_VOLUME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's real property                     |
//+------------------------------------------------------------------+
string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   int dg=(this.m_digits>0 ? this.m_digits : 1);
   return
     (
      property==MBOOK_ORD_PROP_PRICE         ?  CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==MBOOK_ORD_PROP_VOLUME_REAL   ?  CMessage::Text(MSG_MBOOK_ORD_VOLUME_REAL)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's string property                   |
//+------------------------------------------------------------------+
string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_STRING property)
  {
   return(property==MBOOK_ORD_PROP_SYMBOL ? CMessage::Text(MSG_LIB_PROP_SYMBOL)+": \""+this.GetProperty(property)+"\"" : "");
  }
//+------------------------------------------------------------------+

A cada uno de los métodos se le transmite la propiedad cuya descripción debe ser devuelta. Dependiendo de la propiedad transmitida al método, se crea una cadena que al final se devuelve del método.

Método que retorna la denominación breve del objeto:

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

El método devuelve una cadena compuesta de la descripción del tipo de la orden y de su símbolo.

Método que muestra en el diario la descripción breve del objeto:

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

El método simplemente visualiza en el diario la cadena creada por el método anterior.

Método que retorna la descripción del estatus de la orden en el DOM:

//+------------------------------------------------------------------+
//| Return the order status description in DOM                       |
//+------------------------------------------------------------------+
string CMarketBookOrd::StatusDescription(void) const
  {
   return
     (
      Status()==MBOOK_ORD_STATUS_SELL  ?  CMessage::Text(MSG_MBOOK_ORD_STATUS_SELL) :
      Status()==MBOOK_ORD_STATUS_BUY   ?  CMessage::Text(MSG_MBOOK_ORD_STATUS_BUY)  :
      ""
     );
  }
//+------------------------------------------------------------------+

Dependiendo de la propiedad «estatus» de la orden, se devuelve la cadena con la descripción de este estatus.

Esta es la clase completa del objeto de orden en la DOM.

Ahora, tenemos que crear cuatro clases herederas de este objeto de la orden abstracta. Precisamente estas clases herederas van a usarse para crear nuevos objetos de orden del DOM. Simplemente, en el constructor de la clase heredera, en su lista de inicalización, vamos a indicar el estatus del objeto de orden creado dependiendo del tipo de esta orden.


Clases herederas del objeto de orden abstracta

En la carpeta \MQL5\Include\DoEasy\Objects\Book\ creamos un archivo nuevo MarketBookBuy.mqh de la clase CMarketBookBuy. La clase de la orden abstracta CMarketBookOrd que acabamos de crear nos servirá de la clase padre:

//+------------------------------------------------------------------+
//|                                                MarketBookBuy.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"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "MarketBookOrd.mqh"
//+------------------------------------------------------------------+
//| Buy order in DOM                                                 |
//+------------------------------------------------------------------+
class CMarketBookBuy : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookBuy(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_BUY,book_info,symbol) {}
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(void);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CMarketBookBuy::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CMarketBookBuy::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookBuy::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY)+" \""+this.Symbol()+
          "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+
//| Return the description of order type                             |
//+------------------------------------------------------------------+
string CMarketBookBuy::TypeDescription(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY);
  }
//+------------------------------------------------------------------+

Al crear un nuevo objeto de orden del DOM, indicamos el estatus «Dirección Buy» en el constructor de la clase padre.

En los métodos virtuales que devuelven la bandera del soporte de la propiedad entera y real devolvemos true —el objeto soporta cada propiedad.

En el método virtual que devuelve el nombre breve del objeto de orden del DOM, devolvemos la cadena en el formato

Type "Symbol": Price [VolumeReal]

Por ejemplo:

"EURUSD" buy order: 1.20123 [10.00]

En el método virtual que devuelve la descripción del tipo del objeto de orden del DOM, devolvemos la cadena «Orden de compra»

Las demás tres clases derivadas de la clase padre de la orden abstracta del DOM son idénticas a la considerada, a excepción del estatus de la orden. En cada constructor de la clase, se especifica su estatus correspondiente al objeto de orden descrito y a sus métodos virtuales que devuelven las cadenas correspondientes al tipo de la orden del DOM descrito por cada uno de los objetos. Todas estas clases se encuentran en la misma carpeta que la clase considerada arriba. Simplemente, vamos a mostrar sus listados para que el lector pueda analizarlos y comparar sus métodos virtuales por sí mismo.

MarketBookBuyMarket.mqh:

//+------------------------------------------------------------------+
//|                                          MarketBookBuyMarket.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"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "MarketBookOrd.mqh"
//+------------------------------------------------------------------+
//| Buy order by Market in DOM                                       |
//+------------------------------------------------------------------+
class CMarketBookBuyMarket : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookBuyMarket(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_BUY,book_info,symbol) {}
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(void);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CMarketBookBuyMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CMarketBookBuyMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookBuyMarket::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY_MARKET)+" \""+this.Symbol()+
          "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+
//| Return the description of order type                             |
//+------------------------------------------------------------------+
string CMarketBookBuyMarket::TypeDescription(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY_MARKET);
  }
//+------------------------------------------------------------------+

MarketBookSell.mqh:

//+------------------------------------------------------------------+
//|                                               MarketBookSell.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"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "MarketBookOrd.mqh"
//+------------------------------------------------------------------+
//| Sell order in DOM                                                |
//+------------------------------------------------------------------+
class CMarketBookSell : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookSell(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_SELL,book_info,symbol) {}
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(void);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CMarketBookSell::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CMarketBookSell::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookSell::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL)+" \""+this.Symbol()+
          "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+
//| Return the description of order type                             |
//+------------------------------------------------------------------+
string CMarketBookSell::TypeDescription(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL);
  }
//+------------------------------------------------------------------+

MarketBookSellMarket.mqh:

//+------------------------------------------------------------------+
//|                                         MarketBookSellMarket.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"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "MarketBookOrd.mqh"
//+------------------------------------------------------------------+
//| Sell order by Market in DOM                                      |
//+------------------------------------------------------------------+
class CMarketBookSellMarket : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookSellMarket(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_SELL,book_info,symbol) {}
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(void);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CMarketBookSellMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return 'true' if an order supports a passed                      |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CMarketBookSellMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMarketBookSellMarket::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL_MARKET)+" \""+this.Symbol()+
          "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]";
  }
//+------------------------------------------------------------------+
//| Return the description of order type                             |
//+------------------------------------------------------------------+
string CMarketBookSellMarket::TypeDescription(void)
  {
   return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL_MARKET);
  }
//+------------------------------------------------------------------+

Eso es todo por hoy.


Prueba

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

¿Qué es lo que vamos a hacer? Al ejecutar el EA, se realizará la suscripción a los DOMs de los símbolos establecidos en los ajustes para el trabajo. Todos los eventos con el DOM se registran en el manejador OnBookEvent(). Por tanto, vamos a verificar en este manejador que el evento ha ocurrido en el símbolo actual, obtener la captura de imagen del DOM y guardar todas las órdenes existentes en una lista ordenada según el valor del precio. Luego, mostraremos la primera y la última orden de esta lista en el comentario para el gráfico. Así, mostraremos dos órdenes extremas del DOM (una de venta y otra de compra). En el diario, se mostrará la lista de todas las órdenes del DOM obtenidas durante la primera activación de OnBookEvent().

Para que el EA pueda ver las clases nuevamente creadas, las incluimos en el archivo del EA (por ahora, no se puede acceder a ellas desde el objeto principal de la biblioteca CEngine):

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

Ahora, tenemos que crear el manejador OnBookEvent() en el EA, y escribir dentro el procesamiento del evento del DOM:

//+------------------------------------------------------------------+
//| 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;
   //--- create the list for storing DOM order objects
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return;
   //--- Work by the current symbol
   if(symbol==sym.Name())
     {
      //--- Declare the DOM structure array
      MqlBookInfo book_array[];
      //--- Get DOM entries to the structure array
      if(!MarketBookGet(sym.Name(),book_array))
         return;
      //--- clear the list
      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(sym.Name(),book_array[i]);         break;
            case BOOK_TYPE_SELL        : mbook_ord=new CMarketBookSell(sym.Name(),book_array[i]);        break;
            case BOOK_TYPE_BUY_MARKET  : mbook_ord=new CMarketBookBuyMarket(sym.Name(),book_array[i]);   break;
            case BOOK_TYPE_SELL_MARKET : mbook_ord=new CMarketBookSellMarket(sym.Name(),book_array[i]);  break;
            default: break;
           }
         if(mbook_ord==NULL)
            continue;
         //--- Set the sorted list flag for the list (by the price value) and add the current order object to it
         list.Sort(SORT_BY_MBOOK_ORD_PRICE);
         if(!list.InsertSort(mbook_ord))
            delete mbook_ord;
        }
      //--- Get the very first and last DOM order objects from the list
      CMarketBookOrd *ord_0=list.At(0);
      CMarketBookOrd *ord_N=list.At(list.Total()-1);
      if(ord_0==NULL || ord_N==NULL) return;
      //--- Display the size of the current DOM snapshot in the chart comment, 
      //--- the maximum number of displayed orders in DOM for a symbol and
      //--- the highest and lowest orders of the current DOM snapshot
      Comment
        (
         DFUN,sym.Name(),": ",TimeMSCtoString(sym.Time()),", array total=",total,", book size=",sym.TicksBookdepth(),", list.Total: ",list.Total(),"\n",
         "Max: ",ord_N.Header(),"\nMin: ",ord_0.Header()
        );
      //--- Display the first DOM snapshot in the journal
      if(first)
        {
         for(int i=list.Total()-1;i>WRONG_VALUE;i--)
           {
            CMarketBookOrd *ord=list.At(i);
            ord.PrintShort();
           }
         first=false;
        }
     }
   //--- Delete the created list
   delete list;
  }
//+------------------------------------------------------------------+

Aquí hemos descrito todo con detalle en los comentarios al código, así que esperamos que no surjan ningunas dudas. En cualquier caso, el lector podrá expresar cualquier duda en los comentarios al artículo.

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


Después de iniciar el EA y recibir el primer evento del cambio del DOM, en los comentarios del gráfico se mostrarán los parámetros de la lista de la captura actual del DOM y dos ordenes (la máxima de venta y la mínima de compra):


En el diario, se mostrará la lista de todas las órdenes de la captura de pantalla del DOM:

Subscribed to Depth of Market  AUDUSD
Subscribed to Depth of Market  EURUSD
Library initialization time: 00:00:11.391
"EURUSD" sell order: 1.20250 [250.00]
"EURUSD" sell order: 1.20245 [100.00]
"EURUSD" sell order: 1.20244 [50.00]
"EURUSD" sell order: 1.20242 [36.00]
"EURUSD" buy order: 1.20240 [16.00]
"EURUSD" buy order: 1.20239 [20.00]
"EURUSD" buy order: 1.20238 [50.00]
"EURUSD" buy order: 1.20236 [100.00]
"EURUSD" buy order: 1.20232 [250.00]


¿Qué es lo próximo?

En el siguiente artículo, seguiremos desarrollando la funcionalidad para trabajar con la Profundidad del mercado.

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 59): Objeto para almacenar los datos de un tick
Trabajando con los precios en la biblioteca DoEasy (Parte 60): Lista de serie de datos de tick del símbolo
Trabajando con los precios en la biblioteca DoEasy (Parte 61): Colección de series de tick de los símbolos
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