English Русский 中文 Español Deutsch 日本語
Trabalhando preços na biblioteca DoEasy (Parte 63): livro de ofertas, classe de ordem abstrata do livro de ofertas

Trabalhando preços na biblioteca DoEasy (Parte 63): livro de ofertas, classe de ordem abstrata do livro de ofertas

MetaTrader 5Exemplos | 22 abril 2021, 15:17
801 0
Artyom Trishkin
Artyom Trishkin

Sumário


Ideia

Com este artigo, começaremos a criar funcionalidades para trabalhar com o livro de ofertas. Conceitualmente, as classes para trabalhar com o livro de ofertas não serão diferentes de todas as classes da biblioteca previamente escritas. Paralelamente, teremos um “instantâneo” do livro de ofertas que conterá os dados das ordens do livro de ofertas obtidas pela função MarketBookGet() quando o manipulador OnBookEvent() é acionado, além disso, cada um dos seus símbolos, cuja assinatura de eventos é habilitada, desencadeia um evento quando o livro de ofertas muda.

Assim, a estrutura das classes do livro de ofertas será a seguinte:

  1. Classe do objeto-ordem do livro de ofertas: objeto que descreve os dados de uma ordem a partir de um conjunto de ordens recebidas desde o livro de ofertas quando o manipulador OnBookEvent() é acionado uma vez para um símbolo;
  2. Classe do objeto-instantâneo do livro de ofertas: objeto que descreve os dados de todas as ordens recebidas simultaneamente desde o livro de ofertas quando o manipulador OnBookEvent() é acionado uma vez para um símbolo - conjunto de objetos n1 que constituem o instantâneo atual do livro de ofertas;
  3. Classe-série temporal que consiste numa sequência de n2 objetos inseridos numa lista-série temporal quando o manipulador OnBookEvent() é acionado uma vez para um símbolo;
  4. Classe-coleção de séries temporais de dados do livro de ofertas de todos os símbolos usados no programa, cuja assinatura de eventos do livro de ofertas é ativada.

Hoje vamos criar a classe do objeto-ordem (1) e testar o recebimento dos dados do livro de ofertas quando OnBookEvent() for acionado para o símbolo atual.

As propriedades de cada ordem são escritas na estrutura MqlBookInfo que fornece informações no livro de ofertas:

  • tipo de ordem a partir da enumeração ENUM_BOOK_TYPE
  • o preço para colocação da ordem
  • volume da ordem
  • volume da ordem com maior precisão

O livro de ordens pode conter quatro tipos de ordens (a partir da enumeração ENUM_BOOK_TYPE):

  • Ordem de venda
  • Ordem de venda a preço de mercado
  • Ordem de compra
  • Ordem de compra ao preço de mercado

Como podemos ver, existem quatro tipos de ordens - dois Buy e dois Sell. Assim, para dividir todos os tipos de ordens em dois lados, nós, além das propriedades já existentes, adicionaremos mais uma propriedade - o status da ordem indicando sua direção - ordem Buy ou ordem Sell. Isso nos permitirá, no futuro, separar rapidamente todas as ordens de suas partes - oferta e demanda.

O objeto de um livro de ofertas será feito à imagem dos objetos-ordens (e muitos outros objetos de biblioteca) - teremos um objeto base de ordem abstrata de livro de ofertas e quatro objetos herdados com especificação do tipo de ordem. A ideia por trás da construção de tais objetos foi abordada por nós no início da criação da biblioteca no primeiro e no segundo artigo.

Antes de começarmos a criar classes para trabalhar com o livro de ofertas, adicionaremos novas mensagens à biblioteca e modificaremos ligeiramente as classes de objetos de dados de ticks. No arquivo \MQL5\Include\DoEasy\Data.mqh adicionamos os índices das novas mensagens:

   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

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

e os textos das mensagens correspondentes aos índices recém-adicionados:

   {"В окно \"Обзор рынка\" добавлен символ","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"},
   
  };
//+---------------------------------------------------------------------+

No arquivo da classe do objeto-símbolo \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh escrevemos a impressão de uma mensagem de erro ao assinar o livro de ofertas:

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

e da mesma forma ao cancelar a assinatura:

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

A partir do método para atualizar a série de ticks da classe da série de ticks no arquivo \MQL5\Include\DoEasy\Objects\Ticks\TickSeries.mqh removemos a impressão de comentários de depuração no gráfico do símbolo que deixamos para testes no último artigo:

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

A hora do último tick agora será escrita diretamente na variável m_last_time, porque no artigo anterior foi necessário apresentar os dados de verificação com um comentário no gráfico do símboloo, onde era necessário ver a hora dos ticks passados e atuais. Agora não precisamos disso e imediatamente armazenamos o tempo numa variável:

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


Classe de objeto para uma ordem abstrata colocada no livro de ofertas

Como para todos os objetos de biblioteca que têm seus próprios conjuntos de enumerações para definir constantes de propriedade de objeto, bem como para novos objetos de classes de objetos-ordens de livro de ofertas, precisamos criar enumerações de propriedades inteiras, reais e de string do objeto.

No arquivo \MQL5\Include\DoEasy\Defines.mqh inserimos a enumeração de propriedades e parâmetros do objeto-ordem do livro de ofertas. Visto que não faremos um modelo de evento de trabalho com cada uma das ordens do livro de ofertas (num momento o livro de ofertas exibe o estado atual de todas as ordens, e sua alteração leva ao seu próximo estado e é processada no próximo acionamento de OnBookEvent()), apenas adicionamos uma constante, indicando o código do próximo evento após o último código de evento do livro de ofertas - apenas para manter a identidade das constantes de todos os objetos - para dar o mesmo formato:

//+------------------------------------------------------------------+
//| 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 definir uma enumeração na qual escreveremos dois status possíveis de uma ordem do livro de ofertas - lado da Buy ou Sell:

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

Ao filtrar todas as ordens do livro de ofertas de acordo com essas propriedades, podemos selecionar rapidamente na lista todas as ordens que pertencem à demanda ou à oferta.

Em seguida, escrevemos as enumerações de propriedades inteiras, reais e de string do objeto-ordem do livro de ofertas:

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

Depois, de acordo com as propriedades criadas, escreveremos uma lista de possíveis critérios para classificação das ordens no livro de ofertas:

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

Agora podemos criar uma classe de objeto de ordem abstrata no livro de ofertas.

No diretório da biblioteca \MQL5\Include\DoEasy\Objects\ criamos a nova pasta Book\, e nela, o novo arquivo MarketBookOrd.mqh da classe CMarketBookOrd, herdada do objeto base de todos os objetos da biblioteca CBaseObj:

//+------------------------------------------------------------------+
//|                                                MarketBookOrd.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\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;

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

A composição da classe é absolutamente idêntica a outras classes de objetos da biblioteca. Nós as discutimos mais de uma vez, e você pode refrescar sua memória lendo os primeiros artigos e os próximos onde elas são detalhadas.

Consideremos a implementação de métodos de classe.

Num construtor de classe paramétrica privada definimos todas as propriedades do objeto a partir da estrutura de ordens do livro de ofertas que é transferida para o construtor:

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

Também ao construtor é transferido o status da ordem, que indicaremos nos objetos herdados desta classe ao criar um novo objeto-ordem do livro de ofertas.

Método que compara a propriedade especificada de dois objetos CMarketBookOrd para determinar se as propriedades especificadas de dois objetos são iguais:

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

Ao método é passado um objeto, cuja propriedade deve ser comparada com a mesma propriedade do objeto atual. Se a propriedade especificada do objeto comparado tiver um valor menor que o atual, será retornado -1, já se for maior, +1, e se as propriedades forem iguais, será devolvido 0.

Método para comparar todas as propriedades de dois objetos CMarketBookOrd. Permite determinar a identidade completa de dois 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;
  }
//+------------------------------------------------------------------+

Aqui, cada propriedade de dois objetos é comparada alternadamente. e, se as propriedades não forem iguais, é retornado false. Após verificar se absolutamente todas as propriedades de dois objetos são idênticas, e se não foi retornado false, então ele devolverá true pois ambos os objetos são completamente idênticos.

Método que imprime todas as propriedades de um 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");
  }
//+------------------------------------------------------------------+

Em três loops percorrendo as propriedades inteiras, reais e de string do objeto, as descrições de string de cada propriedade são enviadas para o log.

Métodos que retornam uma descrição da propriedade inteira, real e de string do 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 um dos métodos é transferida uma propriedade, cuja descrição deve ser retornada e, dependendo de tal propriedade, é criada uma string que eventualmente é retornada do método.

Método que retorna o nome abreviado do objeto:

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

O método retorna uma string que consiste numa descrição do tipo de ordem e seu símbolo.

Método que imprime uma breve descrição do objeto no log:

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

O método simplesmente imprime no log a linha criada pelo método anterior.

Método que retorna uma descrição do status da ordem do livro de ofertas:

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

Dependendo da propriedade "status" da ordem, é retornada uma string descrevendo esse status.

Esta é a classe inteira do objeto-ordem do livro de ofertas.

Agora precisamos criar quatro classes herdeiras desse objeto de ordem abstrata. São as classes herdadas que serão usadas para criar novos objetos-ordens a partir do livro de ofertas. Simplesmente na lista de inicialização do construtor da classe herdada, será indicado o status do objeto-ordem criada, dependendo do seu tipo.


Classes herdeiras do objeto de uma ordem abstrata

Na pasta \MQL5\Include\DoEasy\Objects\Book\ criamos o novo arquivo MarketBookBuy.mqh da classe CMarketBookBuy. A classe pai deve ser a classe de ordem abstrata CMarketBookOrd que acabamos de criar.:

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

Ao criar um novo objeto-ordem do livro de ofertas, indicamos o status "Lado Buy" no construtor da classe pai.

Em métodos virtuais, que retornam um sinalizador de suporte de propriedade inteira e real, retornamos true - cada propriedade é suportada pelo objeto.

Num método virtual, que retorna o nome abreviado do objeto-ordem do livro de ofertas, retornamos uma string no formato

Type "Symbol": Price [VolumeReal]

Por exemplo, assim:

"EURUSD" buy order: 1.20123 [10.00]

Num método virtual, que retorna uma descrição do tipo de objeto-ordem do livro de ofertas, retornamos a linha "Ordem de compra"

As outras três classes herdeiras da classe base da ordem abstrata do livro de ofertas são idênticas à considerada, com exceção do status da ordem - cada construtor da classe especifica seu próprio status correspondente ao objeto-ordem descrita e seus métodos virtuais que retornam strings correspondentes ao tipo da ordem do livro de ofertas descrito por cada um dos objetos. Todas essas classes estão localizadas na mesma pasta da classe acima. Vamos apenas mostrar suas listagens para realizar uma autoanálise e comparar seus métodos virtuais.

MarketBookBuyMarket.mqh:

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

Isso é tudo que queríamos fazer hoje.


Teste

Para realizar o teste, vamos pegar o Expert Advisor do artigo anterior e
vamos salvá-lo na nova pasta \MQL5\Experts\TestDoEasy\Part63\ com o novo nome TestDoEasyPart63.mq5.

O que faremos será que, quando o Expert Advisor for iniciado, será concluída nossa assinatura do livro de ofertas dos símbolos definidos nas configurações. Todos os eventos relacionados ao livro de ofertas serão registrados no manipulador OnBookEvent(). Assim, neste manipulador, verificaremos se o evento ocorreu no símbolo atual, obteremos um instantâneo do livro de ofertas e salvaremos todas as ordens disponíveis numa lista classificada por valor de preço. Em seguida, imprimiremos as primeiras e as últimas ordens dessa lista nos comentários do gráfico. Assim, exibiremos as duas ordens extremas do livro de ofertas - uma para venda e outra para compra. No log exibiremos uma lista contendo todas as ordens recebidas do livro de ofertas no primeiro acionamento de OnBookEvent().

Para que o Expert Advisor possa ver as classes recém-criadas, vamos anexá-las ao arquivo do EA (até o momento elas não podem ser acessada a partir do objeto principal da biblioteca CEngine):

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

Agora precisamos criar um manipulador OnBookEvent() no EA e registrar o tratamento de eventos do livro de ofertas:

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

Tudo está detalhado aqui nos comentários ao código e, espero, esteja tudo claro. Em qualquer caso, você pode tirar dúvidas na discussão do artigo.

Vamos compilar o Expert Advisor e iniciá-lo no gráfico do símbolo, tendo previamente selecionado o uso dos dois símbolos especificados e o timeframe atual nas configurações:


Após a inicialização do Expert Advisor e a chegada do primeiro evento de mudança no livro de ofertas, nos comentários do gráfico serão exibidos os parâmetros da lista do instantâneo atual do livro de ofertas e duas ordens - máxima para venda e mínima para compra:


No log será exibida uma lista contendo todas as ordens do instantâneo atual do livro de ofertas:

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]


O que vem agora?

No próximo artigo, continuaremos a criar funcionalidades para trabalhar com o livro de ofertas.

Todos os arquivos da versão atual da biblioteca e o arquivo do EA de teste para MQL5 estão anexados abaixo. Você pode baixá-los e testar tudo sozinho.
Gostaria de ressaltar que as classes para trabalhar com o livro de ofertas estão em desenvolvimento e, portanto, o seu uso em programas agora é altamente desaconselhado.
Se você tiver perguntas, comentários e sugestões, poderá expressá-los nos comentários do artigo.

Complementos

*Artigos desta série:

Trabalhando com preços na biblioteca DoEasy (Parte 59): objeto para armazenar dados de um tick
Trabalhando com preços na biblioteca DoEasy (Parte 60): lista-série de dados de tick do símbolo
Trabalhando com preços na biblioteca DoEasy (Parte 61): coleção de séries de ticks para símbolos
Trabalhando com preços na biblioteca DoEasy (Parte 62): atualização em tempo real da série de ticks, preparação para trabalhar com o livro de ofertas

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/9010

Arquivos anexados |
MQL5.zip (3891.18 KB)
Algoritmo auto-adaptável (Parte IV): funcionalidade e testes adicionais Algoritmo auto-adaptável (Parte IV): funcionalidade e testes adicionais
Continuo a complementar o algoritmo com a funcionalidade mínima necessária, vou fazer testes do que obtivemos como resultado. A lucratividade acabou sendo baixa, mas os artigos mostram um modelo que permite negociar com lucro de modo totalmente automático com base em instrumentos de negociação completamente diferentes, e não apenas diferentes, mas também operados em mercados fundamentalmente diferentes.
Aplicação prática de redes neurais no trading (Parte 2). Visão computacional Aplicação prática de redes neurais no trading (Parte 2). Visão computacional
O uso da visão computacional permite treinar redes neurais, usando uma representação visual do gráfico de preços e indicadores. Este método nos permite operar mais livremente com todo o conjunto de indicadores técnicos, uma vez que não requer feed digital para a rede neural.
Trabalhando com preços na biblioteca DoEasy (Parte 64): livro de ofertas, classes do objeto-instantâneo e objeto-série de instantâneos do livro de ofertas Trabalhando com preços na biblioteca DoEasy (Parte 64): livro de ofertas, classes do objeto-instantâneo e objeto-série de instantâneos do livro de ofertas
Neste artigo, criaremos duas classes (a do objeto-instantânea do livro de ofertas e a do objeto-série dos instantâneos do livro de ofertas) e testaremos a criação de uma série de dados do livro de ofertas.
Trabalhando com preços na biblioteca DoEasy (Parte 62): atualização em tempo real da série de ticks, preparação para trabalhar com o livro de ofertas Trabalhando com preços na biblioteca DoEasy (Parte 62): atualização em tempo real da série de ticks, preparação para trabalhar com o livro de ofertas
Neste artigo, atualizaremos em tempo real da coleção de dados de ticks e prepararemos a classe do objeto-símbolo para trabalhar com o livro de ofertas, cujo funcionamento abordaremos no próximo artigo.