English Русский 中文 Español Deutsch 日本語
Trabalhando com preços e sinais na biblioteca DoEasy (Parte 65): coleção de livros de ofertas e classe para trabalhar com sinais MQL5.com

Trabalhando com preços e sinais na biblioteca DoEasy (Parte 65): coleção de livros de ofertas e classe para trabalhar com sinais MQL5.com

MetaTrader 5Exemplos | 6 maio 2021, 12:13
736 0
Artyom Trishkin
Artyom Trishkin

Sumário


Ideia

Temos a funcionalidade pronta para trabalhar com o livro de ofertas de qualquer símbolo - nos artigos anteriores criamos classes de objetos para uma ordem abstrata e seus herdeiros, uma classe de instantâneo do livro de ofertas e uma classe para uma série de instantâneos do livro de ofertas. Resta criar um armazenamento comum para os objetos-séries de instantâneos do livro de ofertas - uma classes-coleção de séries de instantâneos, onde todas essas séries serão armazenadas com acesso conveniente a qualquer instantâneo do livro de ofertas daquelas armazenadas no listas na coleção, bem como com sua atualização automática - adição de novos instantâneos e exclusão dos antigos - para manter os tamanhos de lote especificados.

Além de criar uma classes-coleção de séries de instantâneos do livro de ofertas, hoje iniciaremos uma nova seção da biblioteca - outras classes da biblioteca.
E vamos começar com a funcionalidade para trabalhar com o serviço sinais MQL5.com, nomeadamente, iremos criar uma classe do objeto-sinal, que irá armazenar todos os dados de um sinal transmitido pelo serviço sinais do recurso MQL5.com.


Aprimorando as classes da biblioteca

Vamos adicionar imediatamente novas mensagens à biblioteca. No arquivo \MQL5\Include\DoEasy\Data.mqh inserimos os índices das novas mensagens:

//--- CMBookSeries
   MSG_MBOOK_SERIES_TEXT_MBOOKSERIES,                 // DOM snapshot series
   MSG_MBOOK_SERIES_ERR_ADD_TO_LIST,                  // Error. Failed to add DOM snapshot series to the list
   
//--- CMBookSeriesCollection
   MSG_MB_COLLECTION_TEXT_MBCOLLECTION,               // DOM snapshot series collection
 
//--- CMQLSignal
   MSG_SIGNAL_MQL5_TEXT_SIGNAL,                       // Signal
   MSG_SIGNAL_MQL5_TEXT_SIGNAL_MQL5,                  // MQL5.com Signals service signal
   MSG_SIGNAL_MQL5_TRADE_MODE,                        // Account type
   MSG_SIGNAL_MQL5_DATE_PUBLISHED,                    // Publication date
   MSG_SIGNAL_MQL5_DATE_STARTED,                      // Monitoring start date
   MSG_SIGNAL_MQL5_DATE_UPDATED,                      // Date of the latest update of the trading statistics 
   MSG_SIGNAL_MQL5_ID,                                // ID
   MSG_SIGNAL_MQL5_LEVERAGE,                          // Trading account leverage
   MSG_SIGNAL_MQL5_PIPS,                              // Trading result in pips
   MSG_SIGNAL_MQL5_RATING,                            // Position in the signal rating
   MSG_SIGNAL_MQL5_SUBSCRIBERS,                       // Number of subscribers
   MSG_SIGNAL_MQL5_TRADES,                            // Number of trades
   MSG_SIGNAL_MQL5_SUBSCRIPTION_STATUS,               // Status of account subscription to a signal
   
   MSG_SIGNAL_MQL5_EQUITY,                            // Account equity
   MSG_SIGNAL_MQL5_GAIN,                              // Account growth in %
   MSG_SIGNAL_MQL5_MAX_DRAWDOWN,                      // Maximum drawdown
   MSG_SIGNAL_MQL5_PRICE,                             // Signal subscription price
   MSG_SIGNAL_MQL5_ROI,                               // Signal ROI (Return on Investment) in %

   MSG_SIGNAL_MQL5_AUTHOR_LOGIN,                      // Author login
   MSG_SIGNAL_MQL5_BROKER,                            // Broker (company) name
   MSG_SIGNAL_MQL5_BROKER_SERVER,                     // Broker server
   MSG_SIGNAL_MQL5_NAME,                              // Name
   MSG_SIGNAL_MQL5_CURRENCY,                          // Account currency
   
   MSG_SIGNAL_MQL5_TEXT_GAIN,                         // Growth
   MSG_SIGNAL_MQL5_TEXT_DRAWDOWN,                     // Drawdown
   
  };
//+------------------------------------------------------------------+

e os textos que correspondem aos índices recém-adicionados:

//--- CMBookSeries
   {"Серия снимков стакана цен","Series of shots of the Depth of Market"},
   {"Ошибка. Не удалось добавить серию снимков стакана цен в список","Error. Failed to add a shots series of the Depth of Market to the list"},
   
//--- CMBookSeriesCollection
   {"Коллекция серий снимков стакана цен","Collection of series of the Depth of Market shot"},   
   
//--- CMQLSignal
   {"Сигнал","Signal"},
   {"Сигнал сервиса сигналов MQL5.com","Signal from MQL5.com signal service"},
   {"Тип счета","Account type"},
   {"Дата публикации","Publication date"},
   {"Дата начала мониторинга","Monitoring starting date"},
   {"Дата последнего обновления торговой статистики","The date of the last update of the signal's trading statistics"},
   {"ID","ID"},
   {"Плечо торгового счета","Account leverage"},
   {"Результат торговли в пипсах","Profit in pips"},
   {"Позиция в рейтинге сигналов","Position in rating"},
   {"Количество подписчиков","Number of subscribers"},
   {"Количество трейдов","Number of trades"},
   {"Состояние подписки счёта на этот сигнал","Account subscription status for this signal"},

   {"Средства на счете","Account equity"},
   {"Прирост счета в процентах","Account gain"},
   {"Максимальная просадка","Account maximum drawdown"},
   {"Цена подписки на сигнал","Signal subscription price"},
   {"Значение ROI (Return on Investment) сигнала в %","Return on Investment (%)"},
   
   {"Логин автора","Author login"},
   {"Наименование брокера (компании)","Broker name (company)"},
   {"Сервер брокера","Broker server"},
   {"Имя","Name"},
   {"Валюта счета","Base currency"},
   
   {"Прирост","Gain"},
   {"Просадка","Drawdown"},
   
  };
//+---------------------------------------------------------------------+

Como vamos criar uma nova coleção hoje, precisamos registrar o identificador dessa coleção. No arquivo \MQL5\Include\DoEasy\Defines.mqh no seção de identificadores inserimos o identificador da coleção de série de instantâneos de livros de ofertas:

//--- Collection list IDs
#define COLLECTION_HISTORY_ID          (0x777A)                   // Historical collection list ID
#define COLLECTION_MARKET_ID           (0x777B)                   // Market collection list ID
#define COLLECTION_EVENTS_ID           (0x777C)                   // Event collection list ID
#define COLLECTION_ACCOUNT_ID          (0x777D)                   // Account collection list ID
#define COLLECTION_SYMBOLS_ID          (0x777E)                   // Symbol collection list ID
#define COLLECTION_SERIES_ID           (0x777F)                   // Timeseries collection list ID
#define COLLECTION_BUFFERS_ID          (0x7780)                   // Indicator buffer collection list ID
#define COLLECTION_INDICATORS_ID       (0x7781)                   // Indicator collection list ID
#define COLLECTION_INDICATORS_DATA_ID  (0x7782)                   // Indicator data collection list ID
#define COLLECTION_TICKSERIES_ID       (0x7783)                   // Tick series collection list ID
#define COLLECTION_MBOOKSERIES_ID      (0x7784)                   // DOM series collection list ID
//--- Data parameters for file operations

Vamos modificar o arquivo de classe de objeto-série de instantâneos do livro de ofertas. Às vezes, precisamos exibir a descrição de um objeto uma vez e, às vezes, ao exibir a partir de um objeto-coleção, precisamos exibir as descrições de todas as séries de instantâneos dos livros de ofertas de uma só vez. Neste caso, a lista ficará mais bonita se antes da descrição de cada série for adicionado um hífen. No arquivo de classe de uma série de instantâneos do livro de ofertas \MQL5\Include\DoEasy\Objects\Book\MBookSeries.mqh vamos adicionar mudanças na definição dos métodos:

//--- Display (1) description and (2) short description of a DOM snapshot series
   void              Print(const bool dash=false);
   void              PrintShort(const bool dash=false);

//--- Constructors

Apenas usamos o sinalizador de exibição de hífen antes da descrição do objeto.

Na implementação de métodos também vamos escrever essas mudanças:

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

Por padrão, o sinalizador tem o valor false, e o hífen na frente da descrição do objeto não é exibido.


Classe-coleção de livros de ofertas

Criamos todos os objetos necessários para criar uma coleção de livros de ofertas. Há um objeto-ordem de livro de ofertas, que é representado no terminal pela estrutura MqlBookInfo. Quando um evento BookEvent ocorre, o manipulador OnBookEvent() para este evento é chamado, nele seu parâmetro indica o símbolo em que ocorreu o evento de alteração do livro de ofertas. Além disso, podemos obter todos os dados atuais do livro de ofertas na matriz de estruturas MqlBookInfo. A coleta desses dados em nossa biblioteca é descrita pelo objeto-instantânea do livro de ofertas - ele contém objetos-ordens - exatamente a quantidade que recebemos ao processar o evento de alteração de alteração do livro de ofertas. Cada vez que o livro de ofertas muda, criamos um novo objeto instantâneo, que adicionamos à lista. Essa lista é representada pelo objeto-série de instantâneos de livros de ofertas. Para cada símbolo usado no programa e assinado para receber eventos do livro de ofertas, criamos essas listas. Nós criamos essas listas no modo em tempo real (infelizmente, o próprio terminal não tem um histórico de mudanças do livro de ofertas para um símbolo). Como resultado, agora precisamos combinar todas as listas disponíveis num objeto-coleção dos livros de ofertas dos símbolos.

A coleção de livros de ofertas de símbolos armazenará listas de instantâneas de livros de ofertas constantemente atualizadas, o que nos permitirá criar um histórico de alterações do livro de ofertas para cada símbolo durante a execução do programa. Poderemos receber dados de qualquer instantâneo das listas de coleção, e de cada imagem podemos extrair qualquer ordem. Poderemos buscar os dados necessários, filtrar as listas por critérios e realizar estudos estatísticos com as listas disponíveis na coleção.

Assim, na pasta da biblioteca \MQL5\Include\DoEasy\Collections\ criamos a nova classe CMBookSeriesCollection no arquivo BookSeriesCollection.mqh.

A classe base deve ser a classe do objeto base de todos os objetos da biblioteca CBaseObj, e todos os arquivos necessários devem ser incluídos na lista de classes:

//+------------------------------------------------------------------+
//|                                         BookSeriesCollection.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 "ListObj.mqh"
#include "..\Objects\Book\MBookSeries.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
//+------------------------------------------------------------------+
//| Collection of symbol DOM series                                  |
//+------------------------------------------------------------------+
class CMBookSeriesCollection : public CBaseObj
  {
  }

Vejamos o corpo da classe, seus métodos e, em seguida, analisemos sua implementação e finalidade:

//+------------------------------------------------------------------+
//| Collection of symbol DOM series                                  |
//+------------------------------------------------------------------+
class CMBookSeriesCollection : public CBaseObj
  {
private:
   CListObj                m_list;                                   // List of used symbol DOM series
//--- Return the DOM series index by a symbol name
   int                     IndexMBookSeries(const string symbol);
public:
//--- Return (1) itself, (2) DOM series collection list and (3) the number of DOM series in the list
   CMBookSeriesCollection *GetObject(void)                              { return &this;               }
   CArrayObj              *GetList(void)                                { return &this.m_list;        }
   int                     DataTotal(void)                        const { return this.m_list.Total(); }
//--- Return the pointer to the DOM series object (1) by symbol and (2) by index in the list
   CMBookSeries           *GetMBookseries(const string symbol);
   CMBookSeries           *GetMBookseries(const int index)              { return this.m_list.At(index);}
//--- Create symbol DOM series collection list
   bool                    CreateCollection(const CArrayObj *list_symbols,const uint required=0);
//--- Set the flag of using the DOM series of (1) a specified symbol and (2) all symbols
   void                    SetAvailableMBookSeries(const string symbol,const bool flag=true);
   void                    SetAvailableMBookSeries(const bool flag=true);
//--- Return the flag of using the DOM series of (1) a specified symbol and (2) all symbols
   bool                    IsAvailableMBookSeries(const string symbol);
   bool                    IsAvailableMBookSeries(void);

//--- Set the number of DOM history days of (1) a specified symbol and (2) all symbols
   bool                    SetRequiredUsedDays(const string symbol,const uint required=0);
   bool                    SetRequiredUsedDays(const uint required=0);

//--- Return the DOM snapshot object of a specified symbol (1) by index and (2) by time in milliseconds
   CMBookSnapshot         *GetMBook(const string symbol,const int index);
   CMBookSnapshot         *GetMBook(const string symbol,const long time_msc);

//--- Update the DOM series of a specified symbol
   bool                    Refresh(const string symbol,const long time_msc);

//--- Display (1) the complete and (2) short collection description in the journal
   void                    Print(void);
   void                    PrintShort(void);
   
//--- Constructor
                           CMBookSeriesCollection();
  };
//+------------------------------------------------------------------+

A partir das descrições dos métodos, fica claro que a coleção em si é representada por uma lista m_list, que armazenará objetos-séries de instantâneos de livro de ofertas de diferentes símbolos representados pela classe CMBookSeries, que, por sua vez, contêm objetos-instantâneas do livro de ofertas representados pela classe CMBookSnapshot.

Vamos dar uma olhada mais de perto na implementação dos métodos de classe.

No construtor da classe é limpa a lista de coleção, é definido o sinalizador de lista classificada e o é atribuído identificador da lista da coleção de séries do livro de ofertas:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMBookSeriesCollection::CMBookSeriesCollection()
  {
   this.m_list.Clear();
   this.m_list.Sort();
   this.m_list.Type(COLLECTION_MBOOKSERIES_ID);
  }
//+------------------------------------------------------------------+

Por padrão, todas as listas de série são classificadas na lista-coleção pelo nome dos símbolos da série de instantâneas dos livros de ofertas.

Método para criar uma lista-coleção de séries de livros de ofertas para símbolos:

//+------------------------------------------------------------------+
//| Create symbol DOM series collection list                         |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::CreateCollection(const CArrayObj *list_symbols,const uint required=0)
  {
//--- If an empty list of symbol objects is passed, exit
   if(list_symbols==NULL)
      return false;
//--- Get the number of symbol objects in the passed list
   int total=list_symbols.Total();
//--- Clear the DOM series collection list
   this.m_list.Clear();
//--- In a loop by all symbol objects
   for(int i=0;i<total;i++)
     {
      //--- get the next symbol object
      CSymbol *symbol_obj=list_symbols.At(i);
      //--- if failed to get a symbol object, move on to the next one in the list
      if(symbol_obj==NULL)
         continue;
      //--- Create a new DOM series object
      CMBookSeries *bookseries=new CMBookSeries(symbol_obj.Name(),required);
      //--- If failed to create the DOM series object, move on to the next symbol in the list
      if(bookseries==NULL)
         continue;
      //--- Set the sorted list flag for the DOM series collection list
      this.m_list.Sort();
      //--- If the object with the same symbol name is already present in the DOM series collection list, remove the DOM series object
      if(this.m_list.Search(bookseries)>WRONG_VALUE)
         delete bookseries;
      //--- otherwise, there is no object with such a symbol name in the collection yet
      else
        {
         //--- if failed to add the DOM series object to the collection list, remove the series object,
         //--- inform of that and return 'false'
         if(!this.m_list.Add(bookseries))
           {
            delete bookseries;
            ::Print(DFUN,"\"",symbol_obj.Name(),"\": ",CMessage::Text(MSG_MBOOK_SERIES_ERR_ADD_TO_LIST));
            return false;
           }
        } 
     }
//--- Collection created successfully, return 'true'
   return true;
  }
//+------------------------------------------------------------------+

Toda a lógica do método é descrita em detalhes em sua listagem. Resumidamente: ao método é passada uma lista de todos os símbolos usados no programa e o número de instantâneas do livro de ofertas que podem ser armazenadas nas listas de coleção. No loop através da lista passada para o método, obtemos o próximo objeto-símbolo da lista, criamos um novo objeto-série de instantâneas do livro de ofertas para este símbolo e o adicionamos à lista-coleção. Como resultado, obtemos uma lista de objetos-séries de instantâneos do livro de ofertas de diferentes símbolos - aqueles que estão presentes na lista passada para o método. Cada lista criada de séries de instantâneos está inicialmente vazia.
As listas criadas na coleção serão preenchidas no método de atualização da série de listas dos instantâneos do livro de ofertas do símbolo especificado:

//+------------------------------------------------------------------+
//| Update the snapshot series list of a specified symbol DOM        |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::Refresh(const string symbol,const long time_msc)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return false;
   return bookseries.Refresh(time_msc);
  }
//+------------------------------------------------------------------+

Como o manipulador OnBookEvent() é acionado para cada símbolo, usamos o método de atualização não para a coleção inteira, mas apenas para um dos símbolos da coleção. Ao método são passados o nome do símbolo, em que ocorreu o evento de mudança no livro de ofertas, e o tempo de registro do evento de alteração do livro de ofertas em milissegundos. Em seguida, obtemos uma série de instantâneos do livro de ofertas para o símbolo passado para o método e retornamos o resultado do método Refresh() da classe da objeto-série de instantâneos do livro de ofertas, considerado por nós no artigo anterior.

Método que retorna o índice da série do livro de ofertas pelo nome do símbolo:

//+------------------------------------------------------------------+
//| Return the DOM series index by a symbol name                     |
//+------------------------------------------------------------------+
int CMBookSeriesCollection::IndexMBookSeries(const string symbol)
  {
   const CMBookSeries *obj=new CMBookSeries(symbol==NULL || symbol=="" ? ::Symbol() : symbol);
   if(obj==NULL)
      return WRONG_VALUE;
   this.m_list.Sort();
   int index=this.m_list.Search(obj);
   delete obj;
   return index;
  }
//+------------------------------------------------------------------+

Aqui: criamos uma nova objeto-série temporária de instantâneos do livro de ofertas com o símbolo especificado nos parâmetros de entrada. Definimos o sinalizador de lista classificada (apenas pesquisa em lista classificada) e obtemos o índice do objeto com o mesmo símbolo da lista. Sempre excluímos o objeto temporário criado e retornamos o índice resultante. Se o objeto-série de instantâneos do livro de ofertas com o símbolo especificado estiver na lista, o método Search() retornará seu índice, caso contrário, o método retornará -1.

Método que retorna um objeto da série do livro de ofertas do símbolo especificado:

//+------------------------------------------------------------------+
//| Return the specified symbol DOM series object                    |
//+------------------------------------------------------------------+
CMBookSeries *CMBookSeriesCollection::GetMBookseries(const string symbol)
  {
   int index=this.IndexMBookSeries(symbol);
   return this.m_list.At(index);
  }
//+------------------------------------------------------------------+

Aqui: usando o método acima obtemos o índice do objeto-série de instantâneos do livro de ofertas na lista por símbolo e retornamos um ponteiro para um objeto na lista com base no índice especificado. Se o objeto com o símbolo especificado não estiver na lista (índice -1), o método At() retornará NULL.

Para usar a funcionalidade que permite trabalhar com o livro de ofertas, devemos gerar o acompanhamento (assinatura) de eventos de mudanças no livro de ofertas para cada símbolo. Isso já está pronto para nós e funciona - já fizemos essa funcionalidade na classe do objeto-símbolo. Além disso, na classe do objeto-série dos instantâneos do livro de ofertas, temos um sinalizador que nos indica a necessidade de habilitar/desabilitar o processamento de eventos para alterações no livro de ofertas. Quer dizer, mesmo se um símbolo já tiver sido assinado para receber os eventos BookEvent, podemos desativar temporariamente o símbolo, controlando este sinalizador. Para definir o sinalizador que indica a necessidade de manipular eventos BookEvent por símbolo, temos um método:

//+------------------------------------------------------------------+
//| Set the flag of using a series                                   |
//| of a specified symbol's DOM                                      |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::SetAvailableMBookSeries(const string symbol,const bool flag=true)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return;
   bookseries.SetAvailable(flag);
  }
//+------------------------------------------------------------------+

Aqui: obtemos um objeto-série de livros de ofertas do símbolo especificado e definimos o sinalizador passado para o método.
Por padrão, o valor do sinalizador é true.

Se nosso programa trabalha com muitos símbolos, e precisamos controlar simultaneamente os sinalizadores descritos acima da série de instantâneas de livros de ofertas, então para isso temos um método que permite definir o valor do sinalizador para todos os símbolos usados no programa de uma vez:

//+------------------------------------------------------------------+
//|Set the flag of using the DOM series for all symbols              |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::SetAvailableMBookSeries(const bool flag=true)
  {
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      bookseries.SetAvailable(flag);
     }
  }
//+------------------------------------------------------------------+

Aqui: num loop pelo número total de objetos-séries de instantâneas de livros de ofertas na coleção temos a próxima lista-série e definimos o sinalizador passado para o método. Por padrão, o valor do sinalizador é true.

Métodos opostos aos considerados acima, que retornam valores de sinalizadores para trabalhar com uma série-lista do símbolo especificado, ou de todos de uma vez.

Um método que retorna o sinalizador de uso de uma série de livro de ofertas do símbolo especificado:

//+------------------------------------------------------------------+
//|Return the flag of using the DOM series of a specified symbol     |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::IsAvailableMBookSeries(const string symbol)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return false;
   return bookseries.IsAvailable();
  }
//+------------------------------------------------------------------+

Aqui: obtemos um objeto-série de instantâneas de livro de ofertas para o símbolo passado para o método e retornamos o valor do sinalizador definido para este objeto.

Método que retorna o sinalizador de uso da série de livros de ofetas de todos os símbolos:

//+------------------------------------------------------------------+
//| Return the flag of using the DOM series of all symbols           |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::IsAvailableMBookSeries(void)
  {
   bool res=true;
   int total=this.m_list.Total();
   for(int i=0;i<total;i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      res &=bookseries.IsAvailable();
     }
   return res;
  }
//+------------------------------------------------------------------+

Este método retorna true somente se o sinalizador de necessidade de uso for definida para cada um dos símbolos usados em sua série de livros de ofertas. Aqui num loop por todos os objetos-séries da coleção pegamos outro lote e adicionamos o valor do sinalizador à variável desta série. Se pelo menos um dos símbolos tiver um sinalizador false, o método retornará false.

Método que define o número de instantâneos no histórico do livro de ofertas do símbolo especificado:

//+------------------------------------------------------------------+
//| Set the number of snapshots in history                           |
//| of a specified symbol's DOM                                      |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::SetRequiredUsedDays(const string symbol,const uint required=0)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return false;
   bookseries.SetRequiredUsedDays(required);
   return true;
  }
//+------------------------------------------------------------------+


Este método é usado para limitar o número total de instantâneos de livro de ofertas para cada símbolo, a fim de não desperdiçar memória extra com dados desatualizados. Aqui: obtemos uma lista-série de instantâneos do símbolo especificado e definimos o número máximo de instantâneos na lista. Se a lista-série de instantâneas não puder ser obtida, retornamos false. Após a instalação bem-sucedida da quantidade necessária, devolvemos true.

Método que define o número de instantâneos no histórico de livros de ofertas para todos os símbolos:

//+------------------------------------------------------------------+
//|Set the number of snapshots in the DOM history of all symbols     |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::SetRequiredUsedDays(const uint required=0)
  {
   bool res=true;
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
        {
         res &=false;
         continue;
        }
      bookseries.SetRequiredUsedDays(required);
     }
   return res;
  }
//+------------------------------------------------------------------+

Este método define a mesma quantidade de dados de histórico de livro de ofertas necessários para todos os símbolos usados no programa de uma só vez.

Num loop sobre o número total de objetos-séries na coleção obtemos outro objeto-série de instantâneos de livros de ofertas e definimos a quantidade especificada de dados para ele. Se a série não puder ser obtida, ao resultado é adicionado o valor false. Assim, caso não tenha sido possível definir a quantidade necessária para pelo menos uma série, o método retornará false. No final do ciclo, retornamos a variável resultante res.

Método que retorna um objeto-instantâneo de livro de ofertas do símbolo especificado por índice:

//+------------------------------------------------------------------+
//|Return the DOM snapshot object of a specified symbol by index     |
//+------------------------------------------------------------------+
CMBookSnapshot *CMBookSeriesCollection::GetMBook(const string symbol,const int index)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return NULL;
   return bookseries.GetMBookByListIndex(index);
  }
//+------------------------------------------------------------------+

Aqui: obtemos um objeto-série de instantâneos do livro de ofertas do símbolo especificado e retornamos um ponteiro para o objeto-instantâneo livro de ofertas com base no índice especificado pelo método GetMBookByListIndex() da classe CMBookSeries, descrito no artigo anterior.

Um método que retorna um objeto-instantâneo de livro de ofertas do símbolo especificado por tempo em milissegundos:

//+------------------------------------------------------------------+
//| Return the DOM snapshot object of a specified symbol             |
//| by time in milliseconds                                          |
//+------------------------------------------------------------------+
CMBookSnapshot *CMBookSeriesCollection::GetMBook(const string symbol,const long time_msc)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return NULL;
   return bookseries.GetMBook(time_msc);
  }
//+------------------------------------------------------------------+

Aqui: obtemos uma série-objeto de instantâneos de livro de ofertas do símbolo especificado e retornamos um ponteiro para o objeto-instantâneo de livro de ofertas com base no índice especificado pelo método GetMBook() da classe CMBookSeries, descrito no artigo anterior.

O método é específico porque, para obter um ponteiro garantido para o objeto-instantâneo de livro de ofertas, precisamos saber exatamente e com antecedência seu tempo em milissegundos.

Método que exibe uma descrição completa de uma coleção de séries de instantâneos de livros de ofertas no log:

//+------------------------------------------------------------------+
//| Display complete collection description to the journal           |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::Print(void)
  {
   ::Print(CMessage::Text(MSG_MB_COLLECTION_TEXT_MBCOLLECTION),":");
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      bookseries.Print(true);
     }
  }
//+------------------------------------------------------------------+

Primeiro, imprimimos o cabeçalho, e depois num loop obtemos cada objeto-série do livro de ofertas da coleção e imprimimos sua descrição completa. Neste caso, para o método Print() do objeto-série de instantâneos passamos true, de forma que o método preceda a descrição da série com um hífen.

O método que registra no log uma breve descrição da coleção:

//+------------------------------------------------------------------+
//| Display the short collection description in the journal          |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::PrintShort(void)
  {
   ::Print(CMessage::Text(MSG_MB_COLLECTION_TEXT_MBCOLLECTION),":");
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      bookseries.PrintShort(true);
     }
  }
//+------------------------------------------------------------------+

O método é idêntico ao anterior, exceto que para exibir a descrição das séries da coleção, usamos o método para exibir uma breve descrição do objeto-série de livro de ofertas.

Alteramos a classe de objeto base de biblioteca CEngine no arquivo \MQL5\Include\DoEasy\Engine.mqh.

Anexamos ao arquivo a classe-coleção de séries de instantâneos de livros de ofertas:

//+------------------------------------------------------------------+
//|                                                       Engine.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://MQL5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://MQL5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Services\TimerCounter.mqh"
#include "Collections\HistoryCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\EventsCollection.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\ResourceCollection.mqh"
#include "Collections\TimeSeriesCollection.mqh"
#include "Collections\BuffersCollection.mqh"
#include "Collections\IndicatorsCollection.mqh"
#include "Collections\TickSeriesCollection.mqh"
#include "Collections\BookSeriesCollection.mqh"
#include "TradingControl.mqh"
//+------------------------------------------------------------------+

Na lista de objetos de classe adicionamos um novo objeto - um objeto da coleção-classe de séries de instantâneos dos livros de ofertas:

//+------------------------------------------------------------------+
//| Library basis class                                              |
//+------------------------------------------------------------------+
class CEngine
  {
private:
   CHistoryCollection   m_history;                       // Collection of historical orders and deals
   CMarketCollection    m_market;                        // Collection of market orders and deals
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CSymbolsCollection   m_symbols;                       // Symbol collection
   CTimeSeriesCollection m_time_series;                  // Timeseries collection
   CBuffersCollection   m_buffers;                       // Collection of indicator buffers
   CIndicatorsCollection m_indicators;                   // Indicator collection
   CTickSeriesCollection m_tick_series;                  // Collection of tick series
   CMBookSeriesCollection m_book_series;                 // Collection of DOM series
   CResourceCollection  m_resource;                      // Resource list
   CTradingControl      m_trading;                       // Trading management object
   CPause               m_pause;                         // Pause object
   CArrayObj            m_list_counters;                 // List of timer counters
   int                  m_global_error;                  // Global error code
   bool                 m_first_start;                   // First launch flag
   bool                 m_is_hedge;                      // Hedge account flag
   bool                 m_is_tester;                     // Flag of working in the tester
   bool                 m_is_market_trade_event;         // Account trading event flag
   bool                 m_is_history_trade_event;        // Account history trading event flag
   bool                 m_is_account_event;              // Account change event flag
   bool                 m_is_symbol_event;               // Symbol change event flag
   ENUM_TRADE_EVENT     m_last_trade_event;              // Last account trading event
   int                  m_last_account_event;            // Last event in the account properties
   int                  m_last_symbol_event;             // Last event in the symbol properties
   ENUM_PROGRAM_TYPE    m_program;                       // Program type
   string               m_name;                          // Program name

Adicionamos um novo manipulador para o evento BookEvent, e no método que define a lista de símbolos usados na coleção de símbolos, além de transferir o número de dias para a série de ticks, adicionamos a transmissão do número máximo de instantâneos de livros de ofertas:

//--- (1) Timer, event handler (2) NewTick, (3) Calculate, (4) BookEvent, (4) Deinit
   void                 OnTimer(SDataCalculate &data_calculate);
   void                 OnTick(SDataCalculate &data_calculate,const uint required=0);
   int                  OnCalculate(SDataCalculate &data_calculate,const uint required=0);
   bool                 OnBookEvent(const string &symbol);
   void                 OnDeinit(void);
   
//--- Set the list of used symbols in the symbol collection and create the collection of symbol timeseries
   bool                 SetUsedSymbols(const string &array_symbols[],const uint required_ticks=0,const uint required_books=0);

Na lista de métodos para trabalhar com uma coleção de séries de ticks adicionamos novos métodos para facilitar o uso da coleção de séries de ticks, e escrevemos métodos para trabalhar com uma coleção de séries de livros de ofertas:

//--- Return (1) the tick series collection, (2) the list of tick series from the tick series collection
   CTickSeriesCollection *GetTickSeriesCollection(void)                                { return &this.m_tick_series;                                  }
   CArrayObj           *GetListTickSeries(void)                                        { return this.m_tick_series.GetList();                         }

//--- Create (1) a specified tick series and (2) all tick series
   bool                 TickSeriesCreate(const string symbol,const uint required=0)    { return this.m_tick_series.CreateTickSeries(symbol,required); }
   bool                 TickSeriesCreateAll(const uint required=0)                     { return this.m_tick_series.CreateTickSeriesAll(required);     }

//--- Update (1) a tick series of a specified symbol, (2) all symbols and (3) all symbols except the current one
   void                 TickSeriesRefresh(const string symbol)                         { this.m_tick_series.Refresh(symbol);                          }
   void                 TickSeriesRefreshAll(void)                                     { this.m_tick_series.Refresh();                                }
   void                 TickSeriesRefreshAllExceptCurrent(void)                        { this.m_tick_series.RefreshExpectCurrent();                   }

//--- Return (1) the DOM series collection and (2) the list of DOM series from the DOM series collection
   CMBookSeriesCollection *GetMBookSeriesCollection(void)                              { return &this.m_book_series;                         }
   CArrayObj           *GetListMBookSeries(void)                                       { return this.m_book_series.GetList();                }

//--- Update the DOM series of a specified symbol
   void                 MBookSeriesRefresh(const string symbol,const long time_msc)    { this.m_book_series.Refresh(symbol,time_msc);        }

//--- Return the DOM series of a specified symbol
   CMBookSeries        *GetMBookSeries(const string symbol)                            { return this.m_book_series.GetMBookseries(symbol);   }

Todos esses métodos simplesmente chamam os métodos de coleção correspondentes com o mesmo nome.

Fora do corpo da classe, vamos escrever a implementação do manipulador OnBookEvent() da biblioteca:

//+------------------------------------------------------------------+
//| BookEvent event handler                                          |
//+------------------------------------------------------------------+
bool CEngine::OnBookEvent(const string &symbol)
  {
   CSymbol *sym=this.m_symbols.GetSymbolObjByName(symbol);
   if(sym==NULL || !sym.BookdepthSubscription())
      return false;
   return this.m_book_series.Refresh(sym.Name(),sym.Time());
  }
//+------------------------------------------------------------------+

Como o manipulador OnBookEvent() sempre é ativado quando alterado o livro de ofertas de um símbolo, podemos reconhecer esse símbolo dentro do próprio manipulador.
Respectivamente, para este método passamos o nome do símbolo onde foi registrado o evento de mudança de livro de ofertas, e depois obtemos o objeto-símbolo correspondente da classe-coleção de símbolos e retornamos o resultado do método de atualização da série correspondente de instantâneos do livro de ofertas , ao mesmo tempo que especificamos o tempo em milissegundos, que será definido para o instantâneo recém-criado no método Refresh().

Vamos modificar o método que define a lista de símbolos usados na coleção de símbolos:

//+------------------------------------------------------------------+
//| Set the list of used symbols in the symbol collection            |
//| and create the collections of timeseries, tick series            |
//| and symbol DOM series                                            |
//+------------------------------------------------------------------+
bool CEngine::SetUsedSymbols(const string &array_symbols[],const uint required_ticks=0,const uint required_books=0)
  {
   bool res=this.m_symbols.SetUsedSymbols(array_symbols);
   CArrayObj *list=this.GetListAllUsedSymbols();
   if(list==NULL)
      return false;
   res&=this.m_time_series.CreateCollection(list);
   res&=this.m_tick_series.CreateCollection(list,required_ticks);
   res&=this.m_book_series.CreateCollection(list,required_books);
   return res;
  }
//+------------------------------------------------------------------+

Agora ao método são passados o número de dias das séries de tick e o número máximo de instantâneos de livros de ofertas em sua série.
Aqui nós adicionamos adequadamente a criação de uma coleção de séries de instantâneos de livros de ofertas de todos os símbolos.

Assim concluímos o desenvolvimento de classes para trabalhar com séries de livros de ofertas.
No futuro, podemos retornar a este tópico para fazer melhorias, mas por enquanto abordaremos outras funcionalidades necessárias da biblioteca.

Sinais MQL5.com é um serviço que permite que as transações de traders sejam ão copiadas para a sua conta de negociação.
Aqui, consideraremos uma conta de negociação como um objeto de um sinal mql5, no qual as operações de negociação são rastreadas para a transmissão pública de trades - fonte do sinal.
A fonte do sinal possui seus próprios parâmetros, que podem ser obtidos por meio das funções SignalBaseGetInteger(), SignalBaseGetDouble() e SignalBaseGetString(). Também há opções de assinatura - configurações para copiar um sinal para uma conta específica. Esses parâmetros podem ser obtidos através das funções SignalInfoGetDouble(), SignalInfoGetInteger() e SignalInfoGetString().

O objeto-sinal mql5 descreverá uma fonte de sinal disponível no terminal para ser assinada. Você pode assinar apenas um sinal de uma conta, mas dispor de uma lista completa de todos os sinais disponíveis para assinatura - objetos-sinais mql5, com a capacidade de classificá-los por propriedades, filtrar, comparar e assinar o sinal selecionado - esta é uma funcionalidade muito conveniente e útil para quem deseja usar o serviço de sinal do recurso MQL5.com.

Classe de objeto-sinal mql5

No arquivo \MQL5\Include\DoEasy\Defines.mqh escrevemos a enumeração de propriedades do objeto-sinal mql5 inteiras, reais e de string:

//+------------------------------------------------------------------+
//| Data for working with MQL5.com signals                           |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| The list of possible signal events                               |
//+------------------------------------------------------------------+
#define SIGNAL_MQL5_EVENTS_NEXT_CODE  (MBOOK_ORD_EVENTS_NEXT_CODE+1)   // The code of the next event after the last signal event code
//+------------------------------------------------------------------+
//| MQL5 signal integer properties                                   |
//+------------------------------------------------------------------+
enum ENUM_SIGNAL_MQL5_PROP_INTEGER
  {
   SIGNAL_MQL5_PROP_TRADE_MODE = 0,                   // Account type
   SIGNAL_MQL5_PROP_DATE_PUBLISHED,                   // Signal publication date 
   SIGNAL_MQL5_PROP_DATE_STARTED,                     // Start date of signal monitoring
   SIGNAL_MQL5_PROP_DATE_UPDATED,                     // Date of the latest update of the signal trading statistics
   SIGNAL_MQL5_PROP_ID,                               // Signal ID
   SIGNAL_MQL5_PROP_LEVERAGE,                         // Trading account leverage
   SIGNAL_MQL5_PROP_PIPS,                             // Trading result in pips
   SIGNAL_MQL5_PROP_RATING,                           // Position in the signal rating
   SIGNAL_MQL5_PROP_SUBSCRIBERS,                      // Number of subscribers
   SIGNAL_MQL5_PROP_TRADES,                           // Number of trades
   SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS,              // Status of account subscription to a signal
  };
#define SIGNAL_MQL5_PROP_INTEGER_TOTAL (11)           // Total number of integer properties
#define SIGNAL_MQL5_PROP_INTEGER_SKIP  (0)            // Number of integer DOM properties not used in sorting
//+------------------------------------------------------------------+
//| MQL5 signal real properties                                      |
//+------------------------------------------------------------------+
enum ENUM_SIGNAL_MQL5_PROP_DOUBLE
  {
   SIGNAL_MQL5_PROP_BALANCE = SIGNAL_MQL5_PROP_INTEGER_TOTAL, // Account balance
   SIGNAL_MQL5_PROP_EQUITY,                           // Account equity
   SIGNAL_MQL5_PROP_GAIN,                             // Account growth in %
   SIGNAL_MQL5_PROP_MAX_DRAWDOWN,                     // Maximum drawdown
   SIGNAL_MQL5_PROP_PRICE,                            // Signal subscription price
   SIGNAL_MQL5_PROP_ROI,                              // Signal's ROI (Return on Investment) in %
  };
#define SIGNAL_MQL5_PROP_DOUBLE_TOTAL  (6)            // Total number of real properties
#define SIGNAL_MQL5_PROP_DOUBLE_SKIP   (0)            // Number of real properties not used in sorting
//+------------------------------------------------------------------+
//| MQL5 signal string properties                                    |
//+------------------------------------------------------------------+
enum ENUM_SIGNAL_MQL5_PROP_STRING
  {
   SIGNAL_MQL5_PROP_AUTHOR_LOGIN = (SIGNAL_MQL5_PROP_INTEGER_TOTAL+SIGNAL_MQL5_PROP_DOUBLE_TOTAL), // Signal author's login
   SIGNAL_MQL5_PROP_BROKER,                           // Broker (company) name
   SIGNAL_MQL5_PROP_BROKER_SERVER,                    // Broker server
   SIGNAL_MQL5_PROP_NAME,                             // Signal name
   SIGNAL_MQL5_PROP_CURRENCY,                         // Signal account currency
  };
#define SIGNAL_MQL5_PROP_STRING_TOTAL  (5)            // Total number of string properties
//+------------------------------------------------------------------+

Por enquanto, não faremos a lista de possíveis eventos de sinal mql5, mas nos restringiremos a uma constante indicando o código do próximo evento após os códigos de evento dos sinais mql5 e, então, muito provavelmente, iremos mudar isso.

Para conseguir pesquisar e classificar pelas propriedades dos sinais mql5, definimos a enumeração de todos os critérios de classificação possíveis:

//+------------------------------------------------------------------+
//| Possible sorting criteria of MQL5 signals                        |
//+------------------------------------------------------------------+
#define FIRST_SIGNAL_MQL5_DBL_PROP  (SIGNAL_MQL5_PROP_INTEGER_TOTAL-SIGNAL_MQL5_PROP_INTEGER_SKIP)
#define FIRST_SIGNAL_MQL5_STR_PROP  (SIGNAL_MQL5_PROP_INTEGER_TOTAL-SIGNAL_MQL5_PROP_INTEGER_SKIP+SIGNAL_MQL5_PROP_DOUBLE_TOTAL-SIGNAL_MQL5_PROP_DOUBLE_SKIP)
enum ENUM_SORT_SIGNAL_MQL5_MODE
  {
//--- Sort by integer properties
   SORT_BY_SIGNAL_MQL5_TRADE_MODE = 0,                // Sort by signal type
   SORT_BY_SIGNAL_MQL5_DATE_PUBLISHED,                // Sort by signal publication date 
   SORT_BY_SIGNAL_MQL5_DATE_STARTED,                  // Sort by signal monitoring start date
   SORT_BY_SIGNAL_MQL5_DATE_UPDATED,                  // Sort by date of the latest update of the signal trading statistics
   SORT_BY_SIGNAL_MQL5_ID,                            // Sort by signal ID
   SORT_BY_SIGNAL_MQL5_LEVERAGE,                      // Sort by trading account leverage
   SORT_BY_SIGNAL_MQL5_PIPS,                          // Sort by trading result in pips
   SORT_BY_SIGNAL_MQL5_RATING,                        // Sort by a position in the signal rating
   SORT_BY_SIGNAL_MQL5_SUBSCRIBERS,                   // Sort by the number of subscribers
   SORT_BY_SIGNAL_MQL5_TRADES,                        // Sort by the number of trades
   SORT_BY_SIGNAL_MQL5_SUBSCRIPTION_STATUS,           // Sort by the status of account subscription to a signal
//--- Sort by real properties
   SORT_BY_SIGNAL_MQL5_BALANCE = FIRST_SIGNAL_MQL5_DBL_PROP, // Sort by account balance
   SORT_BY_SIGNAL_MQL5_EQUITY,                        // Sort by account equity
   SORT_BY_SIGNAL_MQL5_GAIN,                          // Sort by account growth in %
   SORT_BY_SIGNAL_MQL5_MAX_DRAWDOWN,                  // Sort by maximum drawdown
   SORT_BY_SIGNAL_MQL5_PRICE,                         // Sort by signal subscription price
   SORT_BY_SIGNAL_MQL5_ROI,                           // Sort by ROI
//--- Sort by string properties
   SORT_BY_SIGNAL_MQL5_AUTHOR_LOGIN = FIRST_SIGNAL_MQL5_STR_PROP, // Sort by signal author login
   SORT_BY_SIGNAL_MQL5_BROKER,                        // Sort by Broker (company) name
   SORT_BY_SIGNAL_MQL5_BROKER_SERVER,                 // Sort by broker server
   SORT_BY_SIGNAL_MQL5_NAME,                          // Sort by signal name
   SORT_BY_SIGNAL_MQL5_CURRENCY,                      // Sort by signal account currency
  };
//+------------------------------------------------------------------+

Este é o mínimo necessário para criar uma nova classe para um novo objeto de biblioteca.

No diretório da biblioteca \MQL5\Include\DoEasy\Objects\ criamos a pasta MQLSignalBase\, e nesta, o novo arquivo MQLSignal.mqh da classe CMQLSignal.

A classe base deve ser a classe do objeto base de todos os objetos da biblioteca CBaseObj:

//+------------------------------------------------------------------+
//|                                                    MQLSignal.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 "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Abstract MQL5 signal class                                       |
//+------------------------------------------------------------------+
class CMQLSignal : public CBaseObj
  {
  }

Consideremos a composição da classe e, em seguida, a implementação de seus métodos:

//+------------------------------------------------------------------+
//|                                                    MQLSignal.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 "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Abstract MQL5 signal class                                       |
//+------------------------------------------------------------------+
class CMQLSignal : public CBaseObj
  {
private:
   long              m_long_prop[SIGNAL_MQL5_PROP_INTEGER_TOTAL];       // Integer properties
   double            m_double_prop[SIGNAL_MQL5_PROP_DOUBLE_TOTAL];      // Real properties
   string            m_string_prop[SIGNAL_MQL5_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_SIGNAL_MQL5_PROP_DOUBLE property)   const { return(int)property-SIGNAL_MQL5_PROP_INTEGER_TOTAL;                               }
   int               IndexProp(ENUM_SIGNAL_MQL5_PROP_STRING property)   const { return(int)property-SIGNAL_MQL5_PROP_INTEGER_TOTAL-SIGNAL_MQL5_PROP_DOUBLE_TOTAL; }

public:
//--- Set object's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_SIGNAL_MQL5_PROP_INTEGER property,long value)    { this.m_long_prop[property]=value;                      }
   void              SetProperty(ENUM_SIGNAL_MQL5_PROP_DOUBLE property,double value)   { this.m_double_prop[this.IndexProp(property)]=value;    }
   void              SetProperty(ENUM_SIGNAL_MQL5_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_SIGNAL_MQL5_PROP_INTEGER property)         const { return this.m_long_prop[property];                     }
   double            GetProperty(ENUM_SIGNAL_MQL5_PROP_DOUBLE property)          const { return this.m_double_prop[this.IndexProp(property)];   }
   string            GetProperty(ENUM_SIGNAL_MQL5_PROP_STRING property)          const { return this.m_string_prop[this.IndexProp(property)];   }
//--- Return itself
   CMQLSignal       *GetObject(void)                                                   { return &this;}

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_SIGNAL_MQL5_PROP_INTEGER property)           { return true; }
   virtual bool      SupportProperty(ENUM_SIGNAL_MQL5_PROP_DOUBLE property)            { return true; }
   virtual bool      SupportProperty(ENUM_SIGNAL_MQL5_PROP_STRING property)            { return true; }

//--- Get description of (1) integer, (2) real and (3) string properties
   string            GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_SIGNAL_MQL5_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(const bool shrt=false);
   
//--- Compare CMQLSignal objects by a specified property (to sort the list by an MQL5 signal object)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CMQLSignal objects by all properties (to search for equal MQL5 signal objects)
   bool              IsEqual(CMQLSignal* compared_obj) const;
   
//--- Constructors
                     CMQLSignal(){;}
                     CMQLSignal(const long signal_id);
                     
public:
//+------------------------------------------------------------------+ 
//| Methods of simplified access to MQL5 signal object               |
//+------------------------------------------------------------------+
//--- Returns the dates of (1) publication, (2) monitoring start, (3) trading statistics last update,
//--- (4) ID, (5) trading account leverage, (6) trading result in pips, (7) position in the signal rating,
//--- (8) number of subscribers, (9) number of trades, (10) account type, (11) flag of the current account subscription to a signal
   datetime          DatePublished(void)     const { return (datetime)this.GetProperty(SIGNAL_MQL5_PROP_DATE_PUBLISHED);         }
   datetime          DateStarted(void)       const { return (datetime)this.GetProperty(SIGNAL_MQL5_PROP_DATE_STARTED);           }
   datetime          DateUpdated(void)       const { return (datetime)this.GetProperty(SIGNAL_MQL5_PROP_DATE_UPDATED);           }
   long              ID(void)                const { return this.GetProperty(SIGNAL_MQL5_PROP_ID);                               }
   long              Leverage(void)          const { return this.GetProperty(SIGNAL_MQL5_PROP_LEVERAGE);                         }
   long              Pips(void)              const { return this.GetProperty(SIGNAL_MQL5_PROP_PIPS);                             }
   long              Rating(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_RATING);                           }
   long              Subscribers(void)       const { return this.GetProperty(SIGNAL_MQL5_PROP_SUBSCRIBERS);                      }
   long              Trades(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_TRADES);                           }
   long              TradeMode(void)         const { return (long)this.GetProperty(SIGNAL_MQL5_PROP_TRADE_MODE);                 }
   bool              SubscriptionStatus(void)const { return (bool)this.GetProperty(SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS);        }
//--- Return (1) the account balance, (2) account funds, (3) account growth in %,
//--- (4) maximum drawdown, (5) subscription price and (6) signal ROI value (Return on Investment) in %
   double            Balance(void)           const { return this.GetProperty(SIGNAL_MQL5_PROP_BALANCE);                          }
   double            Equity(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_EQUITY);                           }
   double            Gain(void)              const { return this.GetProperty(SIGNAL_MQL5_PROP_GAIN);                             }
   double            MaxDrawdown(void)       const { return this.GetProperty(SIGNAL_MQL5_PROP_MAX_DRAWDOWN);                     }
   double            Price(void)             const { return this.GetProperty(SIGNAL_MQL5_PROP_PRICE);                            }
   double            ROI(void)               const { return this.GetProperty(SIGNAL_MQL5_PROP_ROI);                              }
//--- Return (1) signal author's login, (2) broker (company) name,
//--- (3) broker server, (4) signal name and (5) signal account currency
   string            AuthorLogin(void)       const { return this.GetProperty(SIGNAL_MQL5_PROP_AUTHOR_LOGIN);                     }
   string            Broker(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_BROKER);                           }
   string            BrokerServer(void)      const { return this.GetProperty(SIGNAL_MQL5_PROP_BROKER_SERVER);                    }
   string            Name(void)              const { return this.GetProperty(SIGNAL_MQL5_PROP_NAME);                             }
   string            Currency(void)          const { return this.GetProperty(SIGNAL_MQL5_PROP_CURRENCY);                         }

//--- Set the dates of (1) publication, (2) monitoring start, (3) trading statistics last update,
//--- (4) ID, (5) trading account leverage, (6) trading result in pips, (7) position in the signal rating,
//--- (8) number of subscribers, (9) number of trades, (10) account type, (11) flag of the current account subscription to a signal
   void              SetDatePublished(const datetime date)  { this.SetProperty(SIGNAL_MQL5_PROP_DATE_PUBLISHED,date);            }
   void              SetDateStarted(const datetime date)    { this.SetProperty(SIGNAL_MQL5_PROP_DATE_STARTED,date);              }
   void              SetDateUpdated(const datetime date)    { this.SetProperty(SIGNAL_MQL5_PROP_DATE_UPDATED,date);              }
   void              SetID(const long id)                   { this.SetProperty(SIGNAL_MQL5_PROP_ID,id);                          }
   void              SetLeverage(const long value)          { this.SetProperty(SIGNAL_MQL5_PROP_LEVERAGE,value);                 }
   void              SetPips(const long value)              { this.SetProperty(SIGNAL_MQL5_PROP_PIPS,value);                     }
   void              SetRating(const long value)            { this.SetProperty(SIGNAL_MQL5_PROP_RATING,value);                   }
   void              SetSubscribers(const long value)       { this.SetProperty(SIGNAL_MQL5_PROP_SUBSCRIBERS,value);              }
   void              SetTrades(const long value)            { this.SetProperty(SIGNAL_MQL5_PROP_TRADES,value);                   }
   void              SetTradeMode(const long mode)          { this.SetProperty(SIGNAL_MQL5_PROP_TRADE_MODE,mode);                }
   void              SetSubscriptionStatus(const bool flag) { this.SetProperty(SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS,flag);       }
//--- Set (1) the account balance, (2) account funds, (3) account growth in %,
//--- (4) maximum drawdown, (5) subscription price and (6) signal ROI value (Return on Investment) in %
   void              SetBalance(const double value)         { this.SetProperty(SIGNAL_MQL5_PROP_BALANCE,value);                  }
   void              SetEquity(const double value)          { this.SetProperty(SIGNAL_MQL5_PROP_EQUITY,value);                   }
   void              SetGain(const double value)            { this.SetProperty(SIGNAL_MQL5_PROP_GAIN,value);                     }
   void              SetMaxDrawdown(const double value)     { this.SetProperty(SIGNAL_MQL5_PROP_MAX_DRAWDOWN,value);             }
   void              SetPrice(const double value)           { this.SetProperty(SIGNAL_MQL5_PROP_PRICE,value);                    }
   void              SetROI(const double value)             { this.SetProperty(SIGNAL_MQL5_PROP_ROI,value);                      }
//--- Set (1) signal author's login, (2) broker (company) name,
//--- (3) broker server, (4) signal name and (5) signal account currency
   void              SetAuthorLogin(const string value)     { this.SetProperty(SIGNAL_MQL5_PROP_AUTHOR_LOGIN,value);             }
   void              SetBroker(const string value)          { this.SetProperty(SIGNAL_MQL5_PROP_BROKER,value);                   }
   void              SetBrokerServer(const string value)    { this.SetProperty(SIGNAL_MQL5_PROP_BROKER_SERVER,value);            }
   void              SetName(const string value)            { this.SetProperty(SIGNAL_MQL5_PROP_NAME,value);                     }
   void              SetCurrency(const string value)        { this.SetProperty(SIGNAL_MQL5_PROP_CURRENCY,value);                 }

//--- Return the account type name
   string            TradeModeDescription(void);
   
  };
//+------------------------------------------------------------------+

A seção privada declara matrizes para armazenar propriedades inteiras, reais e de string do objeto e métodos que retornam o índice real das propriedades reais e de string do objeto.

Na seção pública da classe, vemos os métodos padrão para objetos de biblioteca para definir e obter propriedades de objeto, métodos para pesquisar e classificar, exibir descrições de objeto e construtores de classe.

Também na seção pública são escritos métodos para fácil acesso às propriedades do objeto - os métodos simplesmente têm nomes "reveladores" - de forma que o usuário da biblioteca não se lembre de cor os nomes de todas as enumerações de um objeto para acessar uma propriedade particular.

Consideramos a composição das classes de objetos em detalhes na primeira parte da descrição da biblioteca. Consideremos a implementação de métodos de classe.

Num construtor de classe paramétrica é transmitido o identificador de sinal, e em seguida (levando em consideração que este sinal está selecionado) todas as propriedades do objeto são preenchidas com os valores obtidos nas funções correspondentes:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CMQLSignal::CMQLSignal(const long signal_id)
  {
   this.m_long_prop[SIGNAL_MQL5_PROP_ID]                             = signal_id;
   this.m_long_prop[SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS]            = false;
   this.m_long_prop[SIGNAL_MQL5_PROP_TRADE_MODE]                     = ::SignalBaseGetInteger(SIGNAL_BASE_TRADE_MODE);
   this.m_long_prop[SIGNAL_MQL5_PROP_DATE_PUBLISHED]                 = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_PUBLISHED);
   this.m_long_prop[SIGNAL_MQL5_PROP_DATE_STARTED]                   = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_STARTED);
   this.m_long_prop[SIGNAL_MQL5_PROP_DATE_UPDATED]                   = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_UPDATED);
   this.m_long_prop[SIGNAL_MQL5_PROP_LEVERAGE]                       = ::SignalBaseGetInteger(SIGNAL_BASE_LEVERAGE);
   this.m_long_prop[SIGNAL_MQL5_PROP_PIPS]                           = ::SignalBaseGetInteger(SIGNAL_BASE_PIPS);
   this.m_long_prop[SIGNAL_MQL5_PROP_RATING]                         = ::SignalBaseGetInteger(SIGNAL_BASE_RATING);
   this.m_long_prop[SIGNAL_MQL5_PROP_SUBSCRIBERS]                    = ::SignalBaseGetInteger(SIGNAL_BASE_SUBSCRIBERS);
   this.m_long_prop[SIGNAL_MQL5_PROP_TRADES]                         = ::SignalBaseGetInteger(SIGNAL_BASE_TRADES);
   
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_BALANCE)]      = ::SignalBaseGetDouble(SIGNAL_BASE_BALANCE);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_EQUITY)]       = ::SignalBaseGetDouble(SIGNAL_BASE_EQUITY);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_GAIN)]         = ::SignalBaseGetDouble(SIGNAL_BASE_GAIN);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_MAX_DRAWDOWN)] = ::SignalBaseGetDouble(SIGNAL_BASE_MAX_DRAWDOWN);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_PRICE)]        = ::SignalBaseGetDouble(SIGNAL_BASE_PRICE);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_ROI)]          = ::SignalBaseGetDouble(SIGNAL_BASE_ROI);
   
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_AUTHOR_LOGIN)] = ::SignalBaseGetString(SIGNAL_BASE_AUTHOR_LOGIN);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_BROKER)]       = ::SignalBaseGetString(SIGNAL_BASE_BROKER);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_BROKER_SERVER)]= ::SignalBaseGetString(SIGNAL_BASE_BROKER_SERVER);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_NAME)]         = ::SignalBaseGetString(SIGNAL_BASE_NAME);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_CURRENCY)]     = ::SignalBaseGetString(SIGNAL_BASE_CURRENCY);
  }
//+------------------------------------------------------------------+

Definimos o sinalizador de assinatura deste sinal como false - a assinatura do sinal selecionado será realizada a partir de uma classe diferente.

Método para comparar a propriedade especificada para objetos-sinais mql5:

//+----------------------------------------------------------------------+
//| Compare CMQLSignal objects with each other by the specified property |
//+----------------------------------------------------------------------+
int CMQLSignal::Compare(const CObject *node,const int mode=0) const
  {
   const CMQLSignal *obj_compared=node;
//--- compare integer properties of two objects
   if(mode<SIGNAL_MQL5_PROP_INTEGER_TOTAL)
     {
      long value_compared=obj_compared.GetProperty((ENUM_SIGNAL_MQL5_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_SIGNAL_MQL5_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare real properties of two objects
   else if(mode<SIGNAL_MQL5_PROP_DOUBLE_TOTAL+SIGNAL_MQL5_PROP_INTEGER_TOTAL)
     {
      double value_compared=obj_compared.GetProperty((ENUM_SIGNAL_MQL5_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_SIGNAL_MQL5_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare string properties of two objects
   else if(mode<SIGNAL_MQL5_PROP_DOUBLE_TOTAL+SIGNAL_MQL5_PROP_INTEGER_TOTAL+SIGNAL_MQL5_PROP_STRING_TOTAL)
     {
      string value_compared=obj_compared.GetProperty((ENUM_SIGNAL_MQL5_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_SIGNAL_MQL5_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+

Resumindo: um objeto para comparar e uma propriedade para comparar dois objetos são passados para o método. Dependendo da propriedade passada, é comparada a propriedade inteira, real ou string de dois objetos. O resultado da comparação é -1, 1 ou 0 (menor que, maior que, igual)

Método para comparar todas as propriedades de objetos-sinais mql5:

//+------------------------------------------------------------------+
//| Compare CMQLSignal objects by all properties                     |
//+------------------------------------------------------------------+
bool CMQLSignal::IsEqual(CMQLSignal *compared_obj) const
  {
   int beg=0, end=SIGNAL_MQL5_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_INTEGER prop=(ENUM_SIGNAL_MQL5_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=SIGNAL_MQL5_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_DOUBLE prop=(ENUM_SIGNAL_MQL5_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=SIGNAL_MQL5_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_STRING prop=(ENUM_SIGNAL_MQL5_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

Em três loops percorrendo três matrizes de propriedades de objeto, comparamos cada propriedade de dois objetos e, se as propriedades não forem iguais, retornamos false. Após comparar todas as propriedades de dois objetos em três matrizes, e se nenhumas propriedades desiguais forem encontradas, retornas true - os objetos são completamente idênticos.

Métodos que retornam uma descrição da propriedade inteira, real e de string do objeto:

//+------------------------------------------------------------------+
//| Return description of object's integer property                  |
//+------------------------------------------------------------------+
string CMQLSignal::GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_INTEGER property)
  {
   return
     (
      property==SIGNAL_MQL5_PROP_TRADE_MODE     ?  CMessage::Text(MSG_SIGNAL_MQL5_TRADE_MODE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.TradeModeDescription()
         )  :
      property==SIGNAL_MQL5_PROP_DATE_PUBLISHED ?  CMessage::Text(MSG_SIGNAL_MQL5_DATE_PUBLISHED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.DatePublished())
         )  :
      property==SIGNAL_MQL5_PROP_DATE_STARTED   ?  CMessage::Text(MSG_SIGNAL_MQL5_DATE_STARTED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.DateStarted())
         )  :
      property==SIGNAL_MQL5_PROP_DATE_UPDATED   ?  CMessage::Text(MSG_SIGNAL_MQL5_DATE_UPDATED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.DateUpdated())
         )  :
      property==SIGNAL_MQL5_PROP_ID             ?  CMessage::Text(MSG_SIGNAL_MQL5_ID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_LEVERAGE       ?  CMessage::Text(MSG_SIGNAL_MQL5_LEVERAGE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_PIPS           ?  CMessage::Text(MSG_SIGNAL_MQL5_PIPS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_RATING         ?  CMessage::Text(MSG_SIGNAL_MQL5_RATING)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_SUBSCRIBERS    ?  CMessage::Text(MSG_SIGNAL_MQL5_SUBSCRIBERS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_TRADES        ?  CMessage::Text(MSG_SIGNAL_MQL5_TRADES)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS  ?  CMessage::Text(MSG_SIGNAL_MQL5_SUBSCRIPTION_STATUS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's real property                     |
//+------------------------------------------------------------------+
string CMQLSignal::GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_DOUBLE property)
  {
   return
     (
      property==SIGNAL_MQL5_PROP_BALANCE         ?  CMessage::Text(MSG_ACC_PROP_BALANCE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_EQUITY   ?  CMessage::Text(MSG_SIGNAL_MQL5_EQUITY)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
         
      property==SIGNAL_MQL5_PROP_GAIN   ?  CMessage::Text(MSG_SIGNAL_MQL5_GAIN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_MAX_DRAWDOWN   ?  CMessage::Text(MSG_SIGNAL_MQL5_MAX_DRAWDOWN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_PRICE   ?  CMessage::Text(MSG_SIGNAL_MQL5_PRICE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_ROI   ?  CMessage::Text(MSG_SIGNAL_MQL5_ROI)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's string property                   |
//+------------------------------------------------------------------+
string CMQLSignal::GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_STRING property)
  {
   return
     (
      property==SIGNAL_MQL5_PROP_AUTHOR_LOGIN   ?  CMessage::Text(MSG_SIGNAL_MQL5_AUTHOR_LOGIN)+": \""+this.GetProperty(property)+"\""    :
      property==SIGNAL_MQL5_PROP_BROKER         ?  CMessage::Text(MSG_SIGNAL_MQL5_BROKER)+": \""+this.GetProperty(property)+"\""          :
      property==SIGNAL_MQL5_PROP_BROKER_SERVER  ?  CMessage::Text(MSG_SIGNAL_MQL5_BROKER_SERVER)+": \""+this.GetProperty(property)+"\""   :
      property==SIGNAL_MQL5_PROP_NAME           ?  CMessage::Text(MSG_SIGNAL_MQL5_NAME)+": \""+this.GetProperty(property)+"\""            :
      property==SIGNAL_MQL5_PROP_CURRENCY       ?  CMessage::Text(MSG_SIGNAL_MQL5_CURRENCY)+": \""+this.GetProperty(property)+"\""        :
      ""
     );
  }
//+------------------------------------------------------------------+

Dependendo da propriedade passada ao método, é criada e retornada uma string com sua descrição e valor.

Método que registra todas as propriedades do objeto-sinal mql5:

//+------------------------------------------------------------------+
//| Display object properties in the journal                         |
//+------------------------------------------------------------------+
void CMQLSignal::Print(const bool full_prop=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=SIGNAL_MQL5_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_INTEGER prop=(ENUM_SIGNAL_MQL5_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=SIGNAL_MQL5_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_DOUBLE prop=(ENUM_SIGNAL_MQL5_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=SIGNAL_MQL5_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_STRING prop=(ENUM_SIGNAL_MQL5_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 propriedades inteiras, reais e de string, exibimos a descrição de cada propriedade do objeto usando o método GetPropertyDescription() correspondente.

Método que retorna o nome abreviado do objeto sinal mql5:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMQLSignal::Header(const bool shrt=false)
  {
   return(shrt ? CMessage::Text(MSG_SIGNAL_MQL5_TEXT_SIGNAL) : CMessage::Text(MSG_SIGNAL_MQL5_TEXT_SIGNAL_MQL5));
  }
//+------------------------------------------------------------------+

Ao método é passado o sinalizador que indica a exibição de descrição breve ou longa. Por padrão, é exibida uma descrição longa:

The signal of the MQL5.com Signal service

Quando o sinalizador é definido como true, é exibida uma breve descrição:

Signal

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

//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CMQLSignal::PrintShort(void)
  {
   ::Print
     (
      this.Header(true),
      " \"",this.Name(),"\". ",
      CMessage::Text(MSG_SIGNAL_MQL5_AUTHOR_LOGIN),": ",this.AuthorLogin(),
      ", ID ",this.ID(),
      ", ",CMessage::Text(MSG_SIGNAL_MQL5_TEXT_GAIN),": ",::DoubleToString(this.Gain(),2),
      ", ",CMessage::Text(MSG_SIGNAL_MQL5_TEXT_DRAWDOWN),": ",::DoubleToString(this.MaxDrawdown(),2),
      ", ",CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE),": ",::DoubleToString(this.Price(),2)
     );
  }
//+------------------------------------------------------------------+

Primeiro, é criado um pequeno cabeçalho "Sinal" e, em seguida, a este são adicionados alguns parâmetros, que são impressos no log do terminal.
Por exemplo:

Signal "DemoForArticle". Author login: login, ID XXXXXX, Growth: XX.XX, Drawdown: XX.XX, Price: XX.XX

Método que retorna o nome do tipo de conta:

//+------------------------------------------------------------------+
//| Return the account type name                                     |
//+------------------------------------------------------------------+
string CMQLSignal::TradeModeDescription(void)
  {
   return
     (
      this.TradeMode()==0 ? CMessage::Text(MSG_ACC_TRADE_MODE_REAL)     :
      this.TradeMode()==1 ? CMessage::Text(MSG_ACC_TRADE_MODE_DEMO)     :
      this.TradeMode()==2 ? CMessage::Text(MSG_ACC_TRADE_MODE_CONTEST)  :
      CMessage::Text(MSG_ACC_TRADE_MODE_UNKNOWN)
     );
  }
//+------------------------------------------------------------------+

Dependendo da conta da qual o sinal é transmitido, é retornada uma string com o tipo de conta (real, demo e por aí fora).

Assim concluímos a criação do objeto-sinal mql5.


Teste

Para testar, vamos pegar um Expert Advisor do artigo anterior e o salvamos na nova pasta \MQL5\Experts\TestDoEasy\Part65\ com o nome TestDoEasyPart65.mq5.

A classe-coleção de séries de instantâneos de livros de ofertas agora está disponível no objeto da biblioteca principal, mas ainda não anexamos o objeto de sinal mql5 ao CEngine. Por isso, no Expert Advisor, iremos substituir a string de conexão da classe do objeto-série de instantâneos do livro de ofertas.

#include <DoEasy\Objects\Book\MBookSeries.mqh>

por linha de conexão de objeto-sinal mql5:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart65.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\MQLSignalBase\MQLSignal.mqh>
//--- enums

Da lista de variáveis globais do Expert Advisor removemos o anúncio do objeto-série do instantâneo do livro de ofertas:

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

Na Ajuda do MQL5 há um exemplo de como obter uma lista de sinais gratuitos lucrativos com um número diferente de zero de assinantes:

void OnStart()
  {
//--- request the total number of signals in the signal database
   int total=SignalBaseTotal();
//--- loop through all signals
   for(int i=0;i<total;i++)
     {
      //--- select a signal for further operation
      if(SignalBaseSelect(i))
        {
         //--- receive signal properties
         long   id    =SignalBaseGetInteger(SIGNAL_BASE_ID);          // signal ID
         long   pips  =SignalBaseGetInteger(SIGNAL_BASE_PIPS);        // trading result in pips
         long   subscr=SignalBaseGetInteger(SIGNAL_BASE_SUBSCRIBERS); // number of subscribers
         string name  =SignalBaseGetString(SIGNAL_BASE_NAME);         // signal name
         double price =SignalBaseGetDouble(SIGNAL_BASE_PRICE);        // signal subscription price
         string curr  =SignalBaseGetString(SIGNAL_BASE_CURRENCY);     // signal currency
         //--- display all profitable free signals with a non-zero number of subscribers
         if(price==0.0 && pips>0 && subscr>0)
            PrintFormat("id=%d, name=\"%s\", currency=%s, pips=%d, subscribers=%d",id,name,curr,pips,subscr);
        }
      else PrintFormat("Signal selection error. Error code=%d",GetLastError());
     }
  }

Vamos fazer o mesmo, mas com a ajuda de um novo objeto-sinal mql5. Para fazer isso, vamos escrever no manipulador OnInit() do Expert Advisor esse bloco de código:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Calling the function displays the list of enumeration constants in the journal 
//--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity
   //EnumNumbersTest();

//--- Set EA global variables
   prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";
   testing=engine.IsTester();
   for(int i=0;i<TOTAL_BUTT;i++)
     {
      butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i);
      butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i);
     }
   lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0));
   magic_number=InpMagic;
   stoploss=InpStopLoss;
   takeprofit=InpTakeProfit;
   distance_pending=InpDistance;
   distance_stoplimit=InpDistanceSL;
   slippage=InpSlippage;
   trailing_stop=InpTrailingStop*Point();
   trailing_step=InpTrailingStep*Point();
   trailing_start=InpTrailingStart;
   stoploss_to_modify=InpStopLossModify;
   takeprofit_to_modify=InpTakeProfitModify;
   distance_pending_request=(InpDistancePReq<5 ? 5 : InpDistancePReq);
   bars_delay_pending_request=(InpBarsDelayPReq<1 ? 1 : InpBarsDelayPReq);
   g_point=SymbolInfoDouble(NULL,SYMBOL_POINT);
   g_digits=(int)SymbolInfoInteger(NULL,SYMBOL_DIGITS);
//--- Initialize random group numbers
   group1=0;
   group2=0;
   srand(GetTickCount());
   
//--- Initialize DoEasy library
   OnInitDoEasy();
   
//--- Check and remove remaining EA graphical objects
   if(IsPresentObectByPrefix(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Create the button panel
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      return INIT_FAILED;
//--- Set trailing activation button status
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);
//--- Reset states of the buttons for working using pending requests
   for(int i=0;i<14;i++)
     {
      ButtonState(butt_data[i].name+"_PRICE",false);
      ButtonState(butt_data[i].name+"_TIME",false);
     }

//--- Check playing a standard sound by macro substitution and a custom sound by description
   engine.PlaySoundByDescription(SND_OK);
//--- Wait for 600 milliseconds
   engine.Pause(600);
   engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","Falling coin 2"));

   CArrayObj *list=new CArrayObj();
   if(list!=NULL)
     {
      //--- request the total number of signals in the signal database 
      int total=SignalBaseTotal(); 
      //--- loop through all signals 
      for(int i=0;i<total;i++) 
        { 
         //--- select a signal for further operation 
         if(!SignalBaseSelect(i))
            continue;
         long id=SignalBaseGetInteger(SIGNAL_BASE_ID);
         CMQLSignal *signal=new CMQLSignal(id);
         if(signal==NULL)
            continue;
         if(!list.Add(signal))
           {
            delete signal;
            continue;
           }
        } 
      //--- display all profitable free signals with a non-zero number of subscribers
      Print("");
      static bool done=false;
      for(int i=0;i<list.Total();i++)
        {
         CMQLSignal *signal=list.At(i);
         if(signal==NULL)
            continue;
         if(signal.Price()>0 || signal.Subscribers()==0)
            continue;
         //--- The very first suitable signal is fully displayed in the journal
         if(!done)
           {
            signal.Print();
            done=true;
           }
         //--- Short descriptions are displayed for the rest
         else
            signal.PrintShort();
        }
      delete list;
     }
     
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

À primeira vista, o código ficou mais volumoso do que o código da ajuda. Mas esse é um fenômeno temporário. Assim que a classe-coleção de sinais estiver pronta, tudo será muito mais conciso. Nesse ínterim, com este código, vamos verificar a operação do objeto de sinal mql5.

Visto que agora temos acesso à classe-coleção de séries de instantâneos de livros de ofertas a partir do objeto principal da biblioteca, o manipulador OnBookEvent() sofreu algumas alterações. Agora fica assim:

//+------------------------------------------------------------------+
//| OnBookEvent function                                             |
//+------------------------------------------------------------------+
void OnBookEvent(const string& symbol)
  {
   static bool first=true;
   //--- Leave if failed to update the symbol snapshot series
   if(!engine.OnBookEvent(symbol))
      return;
   //--- Work by the current symbol
   if(symbol==Symbol())
     {
      //--- Get the DOM snapshot series of the current symbol
      CMBookSeries *book_series=engine.GetMBookSeries(symbol);
      if(book_series==NULL)
         return;
      //--- Get the last DOM snapshot object from the DOM snapshot series object
      CMBookSnapshot *book=book_series.GetLastMBook();
      if(book==NULL)
         return;
      //--- Get the very first and last DOM order objects from the DOM snapshot object
      CMarketBookOrd *ord_0=book.GetMBookByListIndex(0);
      CMarketBookOrd *ord_N=book.GetMBookByListIndex(book.DataTotal()-1);
      if(ord_0==NULL || ord_N==NULL) return;
      //--- Display the time of the current DOM snapshot in the chart comment,
      //--- the maximum number of displayed orders in DOM for a symbol,
      //--- the obtained number of orders in the current DOM snapshot,
      //--- the total number of DOM snapshots set in the series list and
      //--- the highest and lowest orders of the current DOM snapshot
      Comment
        (
         DFUN,book.Symbol(),": ",TimeMSCtoString(book.Time()),
         //", symbol book size=",sym.TicksBookdepth(),
         ", last book data total: ",book.DataTotal(),
         ", series books total: ",book_series.DataTotal(),
         "\nMax: ",ord_N.Header(),"\nMin: ",ord_0.Header()
        );
      //--- Display the first DOM snapshot in the journal
      if(first)
        {
         //--- series description
         book_series.Print();
         //--- snapshot description
         book.Print();
         first=false;
        }
     }
  }
//+------------------------------------------------------------------+

Na função OnInitDoEasy(), também faremos algumas pequenas alterações. Agora a criação de séries de ticks de todos os símbolos usados é feita por referência direta ao método correspondente do objeto da biblioteca principal, e a verificação das séries criadas do livro de ofertas é adicionada:

//--- Check created timeseries - display descriptions of all created timeseries in the journal
//--- (true - only created ones, false - created and declared ones)
   engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions

//--- Create tick series of all used symbols
   engine.TickSeriesCreateAll();

//--- Check created tick series - display descriptions of all created tick series in the journal
   engine.GetTickSeriesCollection().Print();

//--- Check created DOM series - display descriptions of all created DOM series in the journal
   engine.GetMBookSeriesCollection().Print();


Vamos compilar o Expert Advisor e iniciá-lo, tendo previamente definido nas configurações usar dois símbolos e o período gráfico atual:


O log irá mostrar os dados sobre a coleção criada de instantâneos de livros de ofertas, dados completos no primeiro sinal apropriado e dados ressumidos de todos os sinais gratuitos lucrativos. No final da lista serão exibidas informações sobre uma série de instantâneos e o primeiro instantâneo do livro de ofertas no gráfico atual:

Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.) 10428.13 USD, 1:100, Hedge, MetaTrader 5 demo
--- Initializing "DoEasy" library ---
Working with predefined symbol list. The number of used symbols: 2
"AUDUSD" "EURUSD"
Working with the current timeframe only: H1
AUDUSD symbol timeseries: 
- Timeseries "AUDUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5385
EURUSD symbol timeseries: 
- Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6310
Tick series "AUDUSD": Requested number of days: 1, Historical data created: 294221
Tick series "EURUSD": Requested number of days: 1, Historical data created: 216048
DOM snapshot series collection:
- "AUDUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 0
"EURUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 0
Subscribed to Depth of Market  AUDUSD
Subscribed to Depth of Market  EURUSD
Library initialization time: 00:00:25.015
 
============= Beginning of parameter list (Signal from the MQL5.com Signal service) =============
Account type: Demo
Publication date: 2018.06.04 16:45
Monitoring start date: 2018.06.04 16:45
Date of the latest update of the trading statistics: 2021.02.20 02:01
ID: 435626
Trading account leverage: 200
Trading result in pips: -72124
Position in the Rating of Signals: 12
Number of subscribers: 132
Number of trades: 7866
Status of account subscription to a signal: No
------
Account balance: 43144.27
Account equity: 43150.55
Account growth in %: 331.44
Maximum drawdown: 43.93
Signal subscription price: 0.00
Signal ROI (Return on Investment) in %: 331.51
------
Author login: "robots4forex"
Broker (company) name: "MetaQuotes Software Corp."
Broker server: "MetaQuotes-Demo"
Name: "Prospector Scalper EA"
Account currency: "GBP"
============= End of parameter list (Signal from the MQL5.com Signal service) =============
 
Signal "ADS MT5". Author login: vluxus, ID 478235, Growth: 251.84, Drawdown: 40.26, Price: 0.00
Signal "Sparrow USD ForexClub c 01012019". Author login: Tradotrade, ID 519975, Growth: 12.45, Drawdown: 14.98, Price: 0.00
Signal "RAZRED v03". Author login: joaoluiz_sa, ID 545382, Growth: 96.17, Drawdown: 28.18, Price: 0.00
Signal "NRDemo". Author login: v3sare, ID 655353, Growth: 2.94, Drawdown: 25.37, Price: 0.00
Signal "Amega 1000085182". Author login: AmegaTrust, ID 722001, Growth: 1.92, Drawdown: 5.13, Price: 0.00
Signal "Wns My strategy". Author login: WaldeliN, ID 727851, Growth: 103.69, Drawdown: 47.01, Price: 0.00
Signal "Bk EA". Author login: worknet, ID 749557, Growth: 506.88, Drawdown: 59.78, Price: 0.00
Signal "ROBIN 24". Author login: juanca034, ID 752873, Growth: 926.29, Drawdown: 30.25, Price: 0.00
Signal "Deny Forex". Author login: deny.mendonca, ID 759729, Growth: 149.06, Drawdown: 39.24, Price: 0.00
Signal "T Strategy". Author login: tonarino210, ID 760343, Growth: 28.87, Drawdown: 20.37, Price: 0.00
Signal "IC MT5 Demo". Author login: InvestForce, ID 760539, Growth: 67.01, Drawdown: 35.99, Price: 0.00
Signal "Gridingale". Author login: Myxx, ID 766073, Growth: 21.10, Drawdown: 15.55, Price: 0.00
Signal "Marcos Monteiro". Author login: slovenwill, ID 783988, Growth: 85.08, Drawdown: 17.59, Price: 0.00
Signal "Multi currency trend". Author login: mj2019, ID 785447, Growth: 54.42, Drawdown: 18.52, Price: 0.00
Signal "W7 901074879 Campeonato MT5". Author login: dramos236, ID 787269, Growth: 91.99, Drawdown: 21.20, Price: 0.00
Signal "Ramon Fx". Author login: viniciusramon18, ID 788732, Growth: 54.31, Drawdown: 9.46, Price: 0.00
Signal "Douglas demo w7". Author login: douglas.o.carne, ID 792392, Growth: 219.94, Drawdown: 43.61, Price: 0.00
"Suelen" signal. Author login: suelenacca, ID 794655, Growth: 67.40, Drawdown: 20.97, Price: 0.00
Signal "Conquers". Author login: borgesti, ID 795133, Growth: 37.23, Drawdown: 11.09, Price: 0.00
Signal "Conta demo torneio". Author login: Tiagoximenes, ID 798798, Growth: 42.36, Drawdown: 17.94, Price: 0.00
Signal "Conta demo de mil". Author login: Tiagoximenes, ID 798802, Growth: 132.02, Drawdown: 27.87, Price: 0.00
Signal "The art of Forex". Author login: Myxx, ID 801685, Growth: 170.29, Drawdown: 40.95, Price: 0.00
Signal "BB29 ICM". Author login: desmondpylow, ID 806971, Growth: 2.28, Drawdown: 41.60, Price: 0.00
Signal "Prometheus". Author login: g0079, ID 808538, Growth: 91.44, Drawdown: 22.98, Price: 0.00
Signal "Prueba robot 2 0 automatico". Author login: richwolfcompany, ID 809986, Growth: 76.76, Drawdown: 44.45, Price: 0.00
Signal "Deep Takeover Hedge StressTest 5M Candle". Author login: johnnypasado, ID 811819, Growth: 10.08, Drawdown: 13.58, Price: 0.00
Signal "Campeonato". Author login: AndreAutotecnic, ID 812233, Growth: 87.47, Drawdown: 13.79, Price: 0.00
Signal "OPM PRO". Author login: herinata, ID 812856, Growth: 38.55, Drawdown: 32.35, Price: 0.00
Signal "Slowly but surely 2". Author login: gyurmanz, ID 815467, Growth: 53.73, Drawdown: 13.08, Price: 0.00
Signal "Beef Waves". Author login: vladimir0005, ID 819055, Growth: 50.46, Drawdown: 32.69, Price: 0.00
Signal "Adriano Garcia". Author login: agarcia_ag, ID 823082, Growth: 111.62, Drawdown: 36.00, Price: 0.00
Signal "Max ScalperSpeed MT5". Author login: paran1615, ID 824333, Growth: 74.51, Drawdown: 40.62, Price: 0.00
Signal "SyH". Author login: gtrader2017, ID 826520, Growth: 42.78, Drawdown: 36.81, Price: 0.00
Signal "ECmp5s free". Author login: VallaLorenzo, ID 830456, Growth: 146.90, Drawdown: 27.64, Price: 0.00
Signal "MaxScalperSpeed MT5". Author login: paran1615, ID 835890, Growth: 64.33, Drawdown: 35.14, Price: 0.00
Signal "YEARNSIGNALS". Author login: yearnsignal2k19, ID 837512, Growth: 11.10, Drawdown: 2.54, Price: 0.00
Signal "AGS test 2". Author login: alireza.akbari, ID 838427, Growth: 7.93, Drawdown: 10.89, Price: 0.00
Signal "Waldeli003". Author login: WaldeliN, ID 838605, Growth: 32.98, Drawdown: 5.54, Price: 0.00
Signal "Michele". Author login: michele-m-r, ID 843351, Growth: 49.27, Drawdown: 13.90, Price: 0.00
Signal "SNAILER". Author login: 8F117EE2, ID 843458, Growth: 83.65, Drawdown: 11.86, Price: 0.00
Signal "Juniornicks". Author login: juniornicks, ID 845611, Growth: 100.25, Drawdown: 43.93, Price: 0.00
Signal "Black Hunter". Author login: christianlara, ID 845761, Growth: 51.94, Drawdown: 24.44, Price: 0.00
Signal "Master dizicheh1". Author login: awdtghuoilp, ID 857594, Growth: 5.04, Drawdown: 37.93, Price: 0.00
Signal "EUROS". Author login: Marketsystem, ID 858449, Growth: 5.31, Drawdown: 2.94, Price: 0.00
Signal "Scalpers risk10 pairs7 leverage100". Author login: leron34, ID 861750, Growth: 27.98, Drawdown: 20.53, Price: 0.00
Signal "EUREKA". Author login: Edmed933, ID 861927, Growth: 59.89, Drawdown: 7.32, Price: 0.00
Signal "Nadando Com Tubaroes". Author login: jun152, ID 862191, Growth: 21.18, Drawdown: 5.45, Price: 0.00
Signal "Demo using a grid system". Author login: RyanAfriansyah, ID 865900, Growth: 20.56, Drawdown: 8.38, Price: 0.00
Signal "Pilares". Author login: ValterCezar, ID 866672, Growth: 29.87, Drawdown: 18.96, Price: 0.00
Signal "EUROUSD". Author login: fxtrader036, ID 866719, Growth: 303.28, Drawdown: 40.70, Price: 0.00
Signal "LanzPower 25 S". Author login: sirlanz, ID 868027, Growth: 36.64, Drawdown: 45.53, Price: 0.00
Signal "Amadeu Volpato Desafio Internacional". Author login: Amadeu1971, ID 868928, Growth: 19.79, Drawdown: 12.57, Price: 0.00
Signal "Fernando correia W7". Author login: nandooo_123-hotmail, ID 870169, Growth: 41.70, Drawdown: 25.16, Price: 0.00
Signal "MAK GO". Author login: 9489631, ID 870413, Growth: 469.22, Drawdown: 36.31, Price: 0.00
Signal "Adriano Garcia W7bt 4 Pilares". Author login: agarcia_ag, ID 871868, Growth: 42.84, Drawdown: 13.19, Price: 0.00
Signal "Albertofxsemstop". Author login: albertosuga, ID 871969, Growth: 27.84, Drawdown: 19.36, Price: 0.00
Signal "BetoSTCDemo". Author login: betoabcsp, ID 872141, Growth: 29.03, Drawdown: 18.07, Price: 0.00
Signal "DESAFIOSEMSTOPLOSSCDS". Author login: cdsantos42, ID 873575, Growth: 19.47, Drawdown: 13.24, Price: 0.00
Signal "MrGeek7421". Author login: KamranAhmadi, ID 873583, Growth: 86.74, Drawdown: 16.33, Price: 0.00
Signal "Douglastorneio2w7". Author login: douglas.o.carne, ID 876302, Growth: 18.13, Drawdown: 15.34, Price: 0.00
Signal "Douglasw7demo1". Author login: douglas.o.carne, ID 876303, Growth: 148.80, Drawdown: 26.47, Price: 0.00
Signal "Douglastorneio1w7". Author login: douglas.o.carne, ID 876932, Growth: 136.86, Drawdown: 41.86, Price: 0.00
Signal "Campeonato mundial sem stop". Author login: Lpontes835, ID 878082, Growth: 23.52, Drawdown: 14.93, Price: 0.00
Signal "ALPHA IA v3". Author login: avaalpha, ID 878517, Growth: 2.77, Drawdown: 0.77, Price: 0.00
Signal "Gold x10". Author login: DynamixFX, ID 878540, Growth: 6.47, Drawdown: 8.87, Price: 0.00
Signal "MultiBolbandsRealM5". Author login: 11BREATH11, ID 879072, Growth: 83.18, Drawdown: 20.09, Price: 0.00
Signal "Ticols Stable profit". Author login: ticols, ID 879609, Growth: -56.37, Drawdown: 68.68, Price: 0.00
Signal "EA SkyBot MultiPares CENT". Author login: 4PerformanceFx, ID 882222, Growth: 248.38, Drawdown: 41.29, Price: 0.00
Signal "Trader Unity M15 100 rec". Author login: crifalo, ID 882268, Growth: 24.36, Drawdown: 26.11, Price: 0.00
Signal "Mad Piper Bill Millin". Author login: DiXOVERS, ID 882495, Growth: 251.06, Drawdown: 38.78, Price: 0.00
Signal "ProfitGuy STAR M Demo". Author login: justbond, ID 882847, Growth: 27.45, Drawdown: 24.89, Price: 0.00
Signal "EA GrayRock". Author login: serggray, ID 883235, Growth: 49.42, Drawdown: 28.68, Price: 0.00
Signal "FX FLASH". Author login: tradedeal, ID 883322, Growth: 9.17, Drawdown: 2.88, Price: 0.00
Signal "Optimizer". Author login: alama1, ID 884765, Growth: 73.53, Drawdown: 28.58, Price: 0.00
Signal "NnaFX Demo 02". Author login: 12259468, ID 886070, Growth: 136.64, Drawdown: 30.54, Pric: 0.00
Signal "Phantom5000 DEMO". Author login: JosephSmith, ID 887046, Growth: 43.41, Drawdown: 17.73, Price: 0.00
Signal "Art of Forex MadCat The G". Author login: The_G, ID 888018, Growth: 215.67, Drawdown: 40.86, Price: 0.00
Signal "ICMarkets MT5 AK 05". Author login: A.Klimkovsky, ID 889370, Growth: 13.03, Drawdown: 8.55, Price: 0.00
Signal "ProfitGuy STAR G Demo". Author login: justbond, ID 890551, Growth: 58.84, Drawdown: 58.80, Price: 0.00
Signal "BetoSemStopDM". Author login: betoabcsp, ID 892251, Growth: 94.96, Drawdown: 6.30, Price: 0.00
Signal "Smart Grid 26980 Demo". Author login: tm3912, ID 892313, Growth: 86.30, Drawdown: 37.19, Price: 0.00
Signal "Rel Vigor PSar n Red Dragon n mad max". Author login: DynamixFX, ID 892523, Growth: 73.74, Drawdown: 38.55, Price: 0.00
Signal "SolangeL". Author login: Mulherdeletras1, ID 894019, Growth: 108.40, Drawdown: 20.84, Price: 0.00
Signal "Paulotbone 1". Author login: paulotbone, ID 894062, Growth: 35.14, Drawdown: 23.93, Price: 0.00
Signal "GOLD MASTER". Author login: THEICD, ID 894983, Growth: 218.90, Drawdown: 22.80, Price: 0.00
Signal "Fxfrance". Author login: fxfrance, ID 895838, Growth: 369.48, Drawdown: 41.48, Price: 0.00
Signal "Marcos Paulo Serigatti". Author login: mpm4rcos, ID 895960, Growth: 45.62, Drawdown: 18.21, Price: 0.00
Signal "Roma Forex Desafio 4 Pilares". Author login: Jhonesroma, ID 896016, Growth: 29.60, Drawdown: 43.45, Price: 0.00
Signal "BOSBM OTC Test 5W". Author login: houli, ID 896563, Growth: 144.65, Drawdown: 22.94, Price: 0.00
Signal "FSTickTrade". Author login: onlyforsignup, ID 897751, Growth: 24.68, Drawdown: 16.20, Price: 0.00
Signal "Sun AI". Author login: Myxx, ID 899179, Growth: 16.82, Drawdown: 21.07, Price: 0.00
Signal "Equinox Demo". Author login: Kratoner, ID 905773, Growth: 44.46, Drawdown: 20.55, Price: 0.00
Signal "STRAGA Tornado VM1". Author login: stragapede, ID 906398, Growth: 36.70, Drawdown: 26.00, Price: 0.00
Signal "DiegoT". Author login: DiegoTT, ID 910230, Growth: 28.20, Drawdown: 11.49, Price: 0.00
Signal "Breaking Bad". Author login: Myxx, ID 911569, Growth: 7.63, Drawdown: 8.42, Price: 0.00
Signal "TradesaovivoBr". Author login: dhyegorodrigo1988, ID 913924, Growth: 16.77, Drawdown: 5.60, Price: 0.00
Signal "VantageFX Sunphone Dragon". Author login: sunphone, ID 916421, Growth: 345.56, Drawdown: 36.04, Price: 0.00
Signal "BYQS121". Author login: kadirryildiz, ID 916600, Growth: 32.85, Drawdown: 4.18, Price: 0.00
Signal "FBSLevelUP". Author login: manoj, ID 919106, Growth: 15.29, Drawdown: 10.49, Price: 0.00
Signal "Omega". Author login: zyntherius74, ID 922043, Growth: 70.18, Drawdown: 25.42, Price: 0.00
Signal "Best Bingo". Author login: kalnov-an, ID 926010, Growth: 59.90, Drawdown: 20.63, Price: 0.00
Signal "LCF 1". Author login: yosuf, ID 931735, Growth: 22.42, Drawdown: 36.26, Price: 0.00
Signal "Bao365". Author login: bao365, ID 933208, Growth: 28.41, Drawdown: 11.49, Price: 0.00
The "EURUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 1
"EURUSD" DOM snapshot (2021.02.24 22:22:54.654):
 - Sell order: 1.21576 [250.00]
 - Sell order: 1.21567 [100.00]
 - Sell order: 1.21566 [50.00]
 - Sell order: 1.21565 [36.00]
 - Buy order: 1.21563 [36.00]
 - Buy order: 1.21561 [50.00]
 - Buy order: 1.21559 [100.00]
 - Buy order: 1.21555 [250.00]


O que vem agora?

No próximo artigo, criaremos uma coleção de sinais mql5.

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.
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 62): atualização em tempo real da série de ticks, preparação para trabalhar com o livro de ofertas Trabalhando preços na biblioteca DoEasy (Parte 63): livro de ofertas, classe de ordem abstrata 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

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

Arquivos anexados |
MQL5.zip (3907.3 KB)
Outras classes na biblioteca DoEasy (Parte 66): classe-coleção de Sinais MQL5.com Outras classes na biblioteca DoEasy (Parte 66): classe-coleção de Sinais MQL5.com
Neste artigo, criaremos uma classe-coleção de sinais - do serviço Sinais MQL5.com - com funções para gerenciar sinais assinados e também modificaremos a classe do objeto-instantâneo do livro de ofertas para exibir o volume total de ordens sell e buy.
Técnicas úteis e exóticas para a negociação automatizada Técnicas úteis e exóticas para a negociação automatizada
Neste artigo, eu demonstrarei algumas técnicas muito interessantes e úteis para a negociação automatizada. Algumas delas podem ser familiares para você. Eu tentarei cobrir os métodos mais interessantes e explicarei por que vale a pena usá-los. Além disso, eu mostrarei o que essas técnicas podem fazer na prática. Nós criaremos Expert Advisors e testaremos todas as técnicas descritas usando as cotações históricas.
Redes Neurais de Maneira Fácil (Parte 12): Dropout Redes Neurais de Maneira Fácil (Parte 12): Dropout
Como a próxima etapa no estudo das redes neurais, eu sugiro considerar os métodos de aumentar a convergência durante o treinamento da rede neural. Existem vários desses métodos. Neste artigo, nós consideraremos um deles intitulado Dropout.
Redes Neurais de Maneira Fácil (Parte 11): Uma visão sobre a GPT Redes Neurais de Maneira Fácil (Parte 11): Uma visão sobre a GPT
Talvez um dos modelos mais avançados entre as redes neurais de linguagem atualmente existentes seja a GPT-3, cuja variante máxima contém 175 bilhões de parâmetros. Claro, nós não vamos criar tal monstro em nossos PCs domésticos. No entanto, nós podemos ver quais soluções arquitetônicas podem ser usadas em nosso trabalho e como nós podemos nos beneficiar delas.