English Русский 中文 Español Deutsch 日本語
Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte II). Coleção do histórico de ordens e negócios

Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte II). Coleção do histórico de ordens e negócios

MetaTrader 5Exemplos | 24 abril 2019, 10:31
1 879 0
Artyom Trishkin
Artyom Trishkin

Conteúdo

No artigo anterior, nós começamos a criar uma grande biblioteca multi-plataforma simplificando o desenvolvimento de programas para as plataformas MetaTrader 5 e MetaTrader 4. Nós criamos o objeto abstrato COrder, que é um objeto base para o armazenamento de dados do histórico de ordens e negócios, bem como as ordens à mercado e posições.

Nesta parte, nós continuaremos o desenvolvimento de todos os objetos necessários para armazenar os dados do histórico da conta em coleções, preparar a coleção do histórico de ordens e negócios, bem como modificar e melhorar os objetos e enumerações já criados.

Objetos do histórico de ordens e negócios

O objeto base COrder contém todos os dados de qualquer objeto da conta, seja uma ordem à mercado (uma ordem para executar uma ação), uma ordem pendente, um negócio ou uma posição. Para que possamos operar livremente todos esses objetos separadamente, nós desenvolveremos várias classes baseadas na classe abstrata COrder. Essas classes indicarão com precisão a afiliação do objeto ao seu tipo.

A lista do histórico de ordens e negócios pode apresentar vários tipos de tais objetos: ordem pendente removida, ordem á mercado colocada e negócio (resultado da execução da ordem à mercado). Existem também mais dois tipos de objetos em MQL4: operações de saldo e crédito (em MQL5, esses dados são armazenados nas propriedades de negócio).

Crie a nova classe CHistoryOrder na pasta Objects da biblioteca.
Para fazer isso, clique com o botão direito do mouse na pasta Objects e selecione o item do menu "Novo arquivo" (Ctrl+N). No Assistente MQL5 recém-aberto, selecione "Nova Classe" e clique em Próximo. Digite CHistoryOrder (1) no campo nome da classe, especifique o nome da classe abstrata COrder(2) no campo da classe base e clique em Concluir.


Depois disso, o arquivo HistoryOrder.mqh (3) é gerado na pasta Objects. Abra-o:

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
private:

public:
                     CHistoryOrder();
                    ~CHistoryOrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::~CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+

Por enquanto, isso é apenas um modelo de classe. Se nós tentarmos compilá-lo, nós veremos os cinco erros já conhecidos — a nova classe derivada de COrder não sabe nada sobre o seu pai. Adicione o arquivo de inclusão Order.mqh:

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |  
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Arquivos de inclusão                                             |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
private:

public:
                     CHistoryOrder();
                    ~CHistoryOrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryOrder::~CHistoryOrder()
  {
  }
//+------------------------------------------------------------------+

Agora todo o código é compilado sem problemas.

A classe será bem pequena. Nós precisamos redefinir os métodos da classe pai COrder, que retornam as flags de manutenção das propriedades da ordem, bem como definir a passagem do ticket da ordem para a classe no construtor:

//+------------------------------------------------------------------+
//|                                                 HistoryOrder.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Arquivos de inclusão                                             |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| Histórico de ordens à mercado                                    |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
public:
   //--- Construtor
                     CHistoryOrder(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_ORDER,ticket) {}
   //--- Propriedades da ordem do tipo inteiro suportadas
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| Retorna 'true' se a ordem suportar a propriedade passada,        |
//| caso contrário, retorna 'false'                                  |
//+------------------------------------------------------------------+
bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP       || 
      property==ORDER_PROP_DEAL_ENTRY     || 
      property==ORDER_PROP_TIME_UPDATE    || 
      property==ORDER_PROP_TIME_UPDATE_MSC
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

Assim, um ticket de uma ordem selecionada é passada para o construtor de classe, enquanto o estado da ordem (histórico da ordem) e seu ticket são passados para o construtor protegido do objeto pai COrder.

Nós também redefinimos o método virtual de suporte ao retorno da classe pai para as propriedades do tipo inteiro de ordem. Os métodos que retornam o suporte para as propriedades do tipo real e string da ordem foram deixados inalterados — esses métodos da classe pai sempre retornam 'true' e nós assumimos que o histórico da ordem suporta todas as propriedades do tipo real e string, portanto nós não redefiniremos ela ainda.

Verifica a propriedade no método que suporta as propriedades do tipo inteiro da ordem. Se esta é o tempo de expiração, direção do negócio ou alteração do horário da posição, retorna 'false'. Tais propriedades não são suportadas pelas ordens à mercado. Todas as propriedades restantes são suportadas e retornado 'true'.

De maneira semelhante, crie a classe CHistoryPending do histórico de ordens pendentes (removida) e a classe CHistoryDeal do histórico de negócios:

//+------------------------------------------------------------------+
//|                                               HistoryPending.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Arquivos de inclusão                                             |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| Ordem pendente removida                                          |
//+------------------------------------------------------------------+
class CHistoryPending : public COrder
  {
public:
   //--- Construtor
                     CHistoryPending(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_PENDING,ticket) {}
   //--- Propriedades das ordens suportadas do tipo (1) real, (2) inteiro
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| Retorna 'true' se a ordem suportar a propriedade passada,        |
//| caso contrário, retorna 'false'                                  |
//+------------------------------------------------------------------+
bool CHistoryPending::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_PROFIT_PT         ||
      property==ORDER_PROP_DEAL_ORDER        ||
      property==ORDER_PROP_DEAL_ENTRY        ||
      property==ORDER_PROP_TIME_UPDATE       ||
      property==ORDER_PROP_TIME_UPDATE_MSC   ||
      property==ORDER_PROP_TICKET_FROM       ||
      property==ORDER_PROP_TICKET_TO         ||
      property==ORDER_PROP_CLOSE_BY_SL       ||
      property==ORDER_PROP_CLOSE_BY_TP
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
//| Retorna 'true' se a ordem suportar a propriedade passada,        |
//| caso contrário, retorna 'false'                                  |
//+------------------------------------------------------------------+
bool CHistoryPending::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
   if(property==ORDER_PROP_COMMISSION  ||
      property==ORDER_PROP_SWAP        ||
      property==ORDER_PROP_PROFIT      ||
      property==ORDER_PROP_PROFIT_FULL ||
      property==ORDER_PROP_PRICE_CLOSE
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                  HistoryDeal.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Arquivos de inclusão                                             |
//+------------------------------------------------------------------+
#include "Order.mqh"
//+------------------------------------------------------------------+
//| Histórico de negócios                                            |
//+------------------------------------------------------------------+
class CHistoryDeal : public COrder
  {
public:
   //--- Construtor
                     CHistoryDeal(const ulong ticket) : COrder(ORDER_STATUS_DEAL,ticket) {}
   //--- Propriedades dos negócios suportados do tipo (1) real, (2) inteiro
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
  };
//+------------------------------------------------------------------+
//| Retorna 'true' se a ordem suportar a propriedade passada,        |
//| caso contrário, retorna 'false'                                  |
//+------------------------------------------------------------------+
bool CHistoryDeal::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP          || 
      property==ORDER_PROP_PROFIT_PT         ||
      property==ORDER_PROP_POSITION_BY_ID    ||
      property==ORDER_PROP_TIME_UPDATE       ||
      property==ORDER_PROP_TIME_UPDATE_MSC   ||
      property==ORDER_PROP_STATE             ||
      (
       this.OrderType()==DEAL_TYPE_BALANCE &&
       (
        property==ORDER_PROP_POSITION_ID     ||
        property==ORDER_PROP_POSITION_BY_ID  ||
        property==ORDER_PROP_TICKET_FROM     ||
        property==ORDER_PROP_TICKET_TO       ||
        property==ORDER_PROP_DEAL_ORDER      ||
        property==ORDER_PROP_MAGIC           ||
        property==ORDER_PROP_TIME_CLOSE      ||
        property==ORDER_PROP_TIME_CLOSE_MSC  ||
        property==ORDER_PROP_CLOSE_BY_SL     ||
        property==ORDER_PROP_CLOSE_BY_TP
       )
      )
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+
bool CHistoryDeal::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
   if(property==ORDER_PROP_TP                || 
      property==ORDER_PROP_SL                || 
      property==ORDER_PROP_PRICE_CLOSE       ||
      property==ORDER_PROP_VOLUME_CURRENT    ||
      property==ORDER_PROP_PRICE_STOP_LIMIT  ||
      (
       this.OrderType()==DEAL_TYPE_BALANCE &&
       (
        property==ORDER_PROP_PRICE_OPEN      ||
        property==ORDER_PROP_COMMISSION      ||
        property==ORDER_PROP_SWAP            ||
        property==ORDER_PROP_VOLUME
       )
      )
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

Nós criamos três objetos order para os quais a coleção do histórico de ordens deve se basear. Todos eles são herdados da classe base e abstrata COrder. Eles têm suas propriedades, mas permitem retornar apenas as propriedades suportadas por esse tipo de ordem. Todos eles devem estar localizados em uma única lista de coleção (coleção do histórico de ordens), a partir da qual nós vamos receber todos os dados necessários sobre o histórico da conta em qualquer composição e ordem.

Nem todas as propriedades suportadas ou não suportadas são consideradas nos métodos SupportProperty() para exibir as propriedades da ordem no diário. Por exemplo, apenas três tipos são considerados para os negócios: operações de compra, venda e saldo.

As propriedades que ainda não foram consideradas e especificadas explicitamente nos métodos que retornam o suporte para elas sempre serão impressas. Em seguida, você pode adicioná-los ao método para não imprimir as propriedades que sempre retornam valores iguais a zero, independentemente da situação (sem suporte).

Coleção do histórico de ordens e negócios

É sempre útil ter o histórico da conta em mãos. O terminal fornece e provê as ferramentas para obtê-lo nos programas. No entanto, nossas tarefas atuais exigem uma lista personalizada que nós podemos ordenar e reorganizar para retornar os dados necessários aos nossos programas. Isso significa que a alteração do estado anterior do histórico da conta deve ser verificada a cada tick. Se uma alteração for detectada, a lista do histórico de ordens e negócios deve ser recalculada. Mas ordenar o histórico inteiro a cada tick é muito custoso. Portanto, nós faremos apenas as adições à nossa lista de novos dados, enquanto os dados anteriores já estão armazenados na lista.

Vamos criar a nova classe CHistoryCollection na pasta Collections:

Clique com o botão direito do mouse na pasta Collections, selecione "Novo Arquivo", selecione "Nova Classe" na janela do Assistente MQL e clique em Avançar. Digite o nome da classe CHistoryCollection, deixe o campo da classe base em branco e clique em Concluir.


O novo arquivo HistoryCollection é gerado na pasta Collections:

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:

public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

Vamos preenchê-lo.

Nós vamos usar a lista dinâmica de ponteiros para instanciar objetos da biblioteca padrão CArrayObj para a lista. Inclua-o no arquivo e defina-o imediatamente (você pode usar o menu de contexto do botão direito para fazer isso):


Inclua a CArrayObj e defina a lista do histórico de ordens e negócios na seção private da classe:

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Arquivos de inclusão                                             |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Coleção do histórico de ordens e negócios                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // Lista do histórico de ordens e negócios

public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

Nós precisamos salvar os índices das últimas ordens e negócios adicionados à coleção. Além disso, nós precisamos saber a diferença entre o número de ordens e negócios passados e atuais, portanto, nós vamos criar os membros da classe privada para armazená-los:

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Arquivos de inclusão                                             |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| Coleção do histórico de ordens e negócios                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // Lista do histórico de ordens e negócios
   int               m_index_order;          // Índice da última ordem adicionada à coleção da lista do histórico do terminal (MQL4, MQL5)
   int               m_index_deal;           // Índice do último negócio adicionado à coleção da lista do histórico do terminal (MQL5)
   int               m_delta_order;          // Diferença no número de ordens em comparação com a verificação passada
   int               m_delta_deal;           // Diferença no número de negócios em comparação com a verificação passada
public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryCollection::~CHistoryCollection()
  {
  }
//+------------------------------------------------------------------+

Durante a primeira execução, todos os membros da classe privada são redefinidos e o histórico é recalculado novamente. Para fazer isso, simplesmente adicione a lista de inicialização dos membros da classe no construtor da classe e defina o critério padrão para o qual a lista da coleção deve ser ordenada.

Atualmente, nós temos o construtor padrão. Antes de escrever sua implementação, nós devemos criar uma enumeração contendo todos os critérios possíveis para classificar as ordens e negócios na lista de coleção.
Mas primeiro, vamos organizar as propriedades do tipo inteiro, real e string da ordem para a sua exibição de forma mais lógica no diário. Abra o arquivo Define.mqh da pasta raiz da biblioteca e coloque os membros da enumeração na ordem necessária:

//+------------------------------------------------------------------+
//| Proprieades do tipo inteiro de ordem, negócio, posição           |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // Ticket da ordem
   ORDER_PROP_MAGIC,                                        // Magic number da ordem
   ORDER_PROP_TIME_OPEN,                                    // Horário de abertura (horário do negócio em MQL5)
   ORDER_PROP_TIME_CLOSE,                                   // Horário de fechamento (horário de execução ou remoção em MQL5 - ORDER_TIME_DONE)
   ORDER_PROP_TIME_OPEN_MSC,                                // Horário de abertura em milissegundos (horário do negócio MQL5 em ms)
   ORDER_PROP_TIME_CLOSE_MSC,                               // Horário de abertura em milissegundos (horário de execução ou remoção em MQL5 - ORDER_TIME_DONE_MSC)
   ORDER_PROP_TIME_EXP,                                     // Data de expiração da ordem (para ordens pendentes)
   ORDER_PROP_STATUS,                                       // Estado da ordem (da enumeração ENUM_ORDER_STATUS)
   ORDER_PROP_TYPE,                                         // Tipo da ordem (tipo da ordem em MQL5 deal type)
   ORDER_PROP_DIRECTION,                                    // Direção (Buy, Sell)
   ORDER_PROP_REASON,                                       // origem ou razão do negócio/ordem/posição
   ORDER_PROP_POSITION_ID,                                  // ID da posição
   ORDER_PROP_POSITION_BY_ID,                               // ID da posição oposta
   ORDER_PROP_DEAL_ORDER,                                   // Ordem, baseada no negócio executado
   ORDER_PROP_DEAL_ENTRY,                                   // Direção do negócio – IN, OUT ou IN/OUT
   ORDER_PROP_TIME_UPDATE,                                  // Horário da alteração da posição em segundos
   ORDER_PROP_TIME_UPDATE_MSC,                              // Horário da alteração da posição em milissegundos
   ORDER_PROP_TICKET_FROM,                                  // ticket da ordem pai
   ORDER_PROP_TICKET_TO,                                    // ticket da ordem derivada
   ORDER_PROP_PROFIT_PT,                                    // Lucro em pontos
   ORDER_PROP_CLOSE_BY_SL,                                  // Tipo do fechamento por StopLoss
   ORDER_PROP_CLOSE_BY_TP,                                  // Tipo do fechamento por TakeProfit
  }; 
#define ORDER_PROP_INTEGER_TOTAL    (22)                    // Número total de propriedades do tipo inteiro
//+------------------------------------------------------------------+
//| Propriedades do tipo real de ordem, negócio, posição             |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_DOUBLE
  {
   ORDER_PROP_PRICE_OPEN = ORDER_PROP_INTEGER_TOTAL,        // Preço de abertura (preço do negócio MQL5)
   ORDER_PROP_PRICE_CLOSE,                                  // Preço de fechamento
   ORDER_PROP_SL,                                           // Preço do StopLoss
   ORDER_PROP_TP,                                           // Preço do TakeProfit
   ORDER_PROP_PROFIT,                                       // Lucro
   ORDER_PROP_COMMISSION,                                   // Comissão
   ORDER_PROP_SWAP,                                         // Swap
   ORDER_PROP_VOLUME,                                       // Volume
   ORDER_PROP_VOLUME_CURRENT,                               // Volume não executado
   ORDER_PROP_PROFIT_FULL,                                  // Lucro+comissão+swap
   ORDER_PROP_PRICE_STOP_LIMIT,                             // Preço da ordem limitada quando a ordem StopLimit é ativada
  };
#define ORDER_PROP_DOUBLE_TOTAL     (11)                    // Número total de propriedades do tipo real
//+------------------------------------------------------------------+
//| Propriedades do tipo string de ordem, negócio, posição           |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_STRING
  {
   ORDER_PROP_SYMBOL = (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL), // Símbolo da ordem
   ORDER_PROP_COMMENT,                                      // Comentário da ordem
   ORDER_PROP_EXT_ID                                        // ID da ordem em um sistema de negociação externo
  };
#define ORDER_PROP_STRING_TOTAL     (3)                     // Número total de propriedades do tipo string
//+------------------------------------------------------------------+

Agora vamos adicionar a enumeração com todos os tipos possíveis de classificação de ordem e negócio para o mesmo arquivo:

//+------------------------------------------------------------------+
//| Possíveis critérios de classificação de ordens e negócios        |
//+------------------------------------------------------------------+
enum ENUM_SORT_ORDERS_MODE
  {
   //--- Classifica por propriedades do tipo inteiro
   SORT_BY_ORDER_TICKET          =  0,                      // Classifica pelo ticket da ordem
   SORT_BY_ORDER_MAGIC           =  1,                      // Classifia pelo número mágico da ordem
   SORT_BY_ORDER_TIME_OPEN       =  2,                      // Classifica pelo horário de abertura da ordem
   SORT_BY_ORDER_TIME_CLOSE      =  3,                      // Classifica pelo horário de fechamento da ordem
   SORT_BY_ORDER_TIME_OPEN_MSC   =  4,                      // Classifica pelo horário de abertura da ordem em milissegundos
   SORT_BY_ORDER_TIME_CLOSE_MSC  =  5,                      // Classifica pelo horário de fechamento da ordem em milissegundos
   SORT_BY_ORDER_TIME_EXP        =  6,                      // Classifica pela data de expiração da ordem
   SORT_BY_ORDER_STATUS          =  7,                      // Classifica pelo estado da ordem (ordem à mercado/ordem pendente/negócio)
   SORT_BY_ORDER_TYPE            =  8,                      // Classifica pelo tipo da ordem
   SORT_BY_ORDER_REASON          =  10,                     // Classifica pelo negócio/ordem/posição/razão/origem
   SORT_BY_ORDER_POSITION_ID     =  11,                     // Classifica pelo ID da posição
   SORT_BY_ORDER_POSITION_BY_ID  =  12,                     // Classifica pelo ID da posição oposta
   SORT_BY_ORDER_DEAL_ORDER      =  13,                     // Classifica pela ordem que o negócio se baseou
   SORT_BY_ORDER_DEAL_ENTRY      =  14,                     // Classifica pela direção do negócio – IN, OUT ou IN/OUT
   SORT_BY_ORDER_TIME_UPDATE     =  15,                     // Classifica pelo horário de alteração da posição em segundos
   SORT_BY_ORDER_TIME_UPDATE_MSC =  16,                     // Classifica pelo horário de alteração da posição em milissegundos
   SORT_BY_ORDER_TICKET_FROM     =  17,                     // Classifica pelo ticket da ordem pai
   SORT_BY_ORDER_TICKET_TO       =  18,                     // Classifica pelo ticket da ordem derivada
   SORT_BY_ORDER_PROFIT_PT       =  19,                     // Classifica pelo lucro da ordem em pontos
   SORT_BY_ORDER_CLOSE_BY_SL     =  20,                     // Classifica pelo fechamento da ordem pela flag StopLoss
   SORT_BY_ORDER_CLOSE_BY_TP     =  21,                     // Classifica pelo fechamento da ordem pela flag TakeProfit
   //--- Classifica por propriedades do tipo real
   SORT_BY_ORDER_PRICE_OPEN      =  ORDER_PROP_INTEGER_TOTAL,// Classifica pelo preço de abertura
   SORT_BY_ORDER_PRICE_CLOSE     =  23,                     // Classifica pelo preço do fechamento
   SORT_BY_ORDER_SL              =  24,                     // Classifica pelo preço de StopLoss
   SORT_BY_ORDER_TP              =  25,                     // Classifica pelo preço de TakeProfit
   SORT_BY_ORDER_PROFIT          =  26,                     // Classifica pelo lucro
   SORT_BY_ORDER_COMMISSION      =  27,                     // Classifica pela comissão
   SORT_BY_ORDER_SWAP            =  28,                     // Classifica pelo swap
   SORT_BY_ORDER_VOLUME          =  29,                     // Classifica pelo volume
   SORT_BY_ORDER_VOLUME_CURRENT  =  30,                     // Classifica pelo volume não executado
   SORT_BY_ORDER_PROFIT_FULL     =  31,                     // Classifica pelo critério de lucro+comissão+swap
   SORT_BY_ORDER_PRICE_STOP_LIMIT=  32,                     // Classifica pela ordem limitada quando a ordem StopLimit é ativada
   //--- Classifica pelas propriedades do tipo string
   SORT_BY_ORDER_SYMBOL          =  ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL,// Classifica pelo símbolo
   SORT_BY_ORDER_COMMENT         =  34,                     // Classifica pelo comentário
   SORT_BY_ORDER_EXT_ID          =  35                      // Classifica pelo ID da ordem em um sistema de negociação externo
  };
//+------------------------------------------------------------------+

Nota: Os índices dos membros da enumeração ordenados devem coincidir com um dos membros da enumeração de propriedades, uma vez que a lista deve ser classificada pelo mesmo valor que é usado para a busca nessa lista.

Como nós podemos ver, a propriedade de classificação ORDER_PROP_DIRECTION foi ignorada nessa lista, já que essa é uma propriedade de serviço usada para as necessidades da biblioteca, assim como outras propriedades personalizadas que nós adicionamos anteriormente. No entanto, eles podem precisar de ordenação. É por isso que eles foram deixados.

Agora nós podemos implementar o construtor da classe CHistoryCollection:

//+------------------------------------------------------------------+
//|                                            HistoryCollection.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Arquivos de inclusão                                             |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\DELib.mqh"
//+------------------------------------------------------------------+
//| Coleção do histórico de ordens e negócios                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // Lista do histórico de ordens e negócios
   int               m_index_order;          // Índice da última ordem adicionada à coleção da lista do histórico do terminal (MQL4, MQL5)
   int               m_index_deal;           // Índice do último negócio adicionado à coleção da lista do histórico do terminal (MQL5)
   int               m_delta_order;          // Diferença no número de ordens em comparação com a verificação passada
   int               m_delta_deal;           // Diferença no número de negócios em comparação com a verificação passada
public:
                     CHistoryCollection();
                    ~CHistoryCollection();
  };
//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CHistoryCollection::CHistoryCollection(void) : m_index_deal(0), 
                                               m_delta_deal(0), 
                                               m_index_order(0),
                                               m_delta_order(0) 
  {
   m_list_all_orders.Sort(SORT_BY_ORDER_TIME_CLOSE);
  }
//+------------------------------------------------------------------+

Vamos analisar o código.
Como o construtor da classe usa apenas o valor de uma enumeração recém-adicionada, nós devemos incluir o arquivo Defines.mqh no arquivo da classe.
Ao preparar a classe base e abstrata COrder no primeiro artigo, nós desenvolvemos a biblioteca de funções de serviço DELib.mqh e incluiu o arquivo Defines.mqh com todas as enumerações necessárias e substituições de macro para ele. Assim sendo, nós vamos incluir a biblioteca de funções de serviço.
Na lista de inicialização do construtor, todos os índices e valores das diferenças entre os números atuais e anteriores são redefinidos, e a classificação padrão por hora de fechamento é especificada no corpo do construtor.

Agora é hora de começar a coletar as informações da conta e salvá-las na lista de coleção. Para fazer isso, percorra o histórico da conta em loops e especifique cada ordem na lista. Se o número de ordens ou negócios se alterar em comparação com a verificação anterior, defina a flag do evento de negociação ocorrido. É necessário enviar mensagens sobre o novo evento ocorrido no histórico da conta para um programa externo.
Declare a flag de evento de negociação na seção da classe privada e o método Refresh() para atualizar a coleção do histórico na seção pública:

//+------------------------------------------------------------------+
//| Coleção do histórico de ordens e negócios                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // Lista de todo o histórico de ordens e negócios
   bool              m_is_trade_event;       // Flag do evento de negociação
   int               m_index_order;          // Índice da última ordem adicionada à coleção da lista do histórico do terminal (MQL4, MQL5)
   int               m_index_deal;           // Índice do último negócio adicionado à coleção da lista do histórico do terminal (MQL5)
   int               m_delta_order;          // Diferença no número de ordens em comparação com a verificação passada
   int               m_delta_deal;           // Diferença no número de negócios em comparação com a verificação passada
public:
                     CHistoryCollection();
   //--- Atualiza a lista de ordens, preenche os dados sobre o número de novas ordens e define a flag do evento de negociação
   void              Refresh(void);
  };
//+------------------------------------------------------------------+

Para implementar a atualização da lista de ordens da coleção, nós precisamos de mais uma substituição de macro para solicitar os dados completos do histórico. A função HistorySelect() é usada para isso. As datas do início e fim dos dados requeridos são passadas em seus parâmetros. Para obter a lista completa do histórico da conta, a data inicial deve ser passada como 0, enquanto a final deve ser passada como TimeCurrent(). No entanto, nesse caso, os dados do histórico retornado podem, às vezes, estar incompletos. Para evitar isso, insira uma data excedendo a hora atual do servidor em vez de TimeCurrent(). Eu vou inserir a data máxima possível: 31.12.3000 23:59:59. Outra vantagem aqui é que os símbolos personalizados podem conter essa data e a obtenção do histórico ainda funcionará.

Vamos inserir uma nova substituição de macros para o arquivo Defines.mqh:

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
//+------------------------------------------------------------------+
//| Substituições de macro                                           |
//+------------------------------------------------------------------+
#define COUNTRY_LANG   ("Russian")              // Idioma do país
#define DFUN           (__FUNCTION__+": ")      // "Descrição da função"
#define END_TIME       (D'31.12.3000 23:59:59') // Hora de término para solicitar os dados do histórico da conta
//+------------------------------------------------------------------+

Agora, em vez de entrar com TimeCurrent() como a hora final, nós vamos inserir a macro END_TIME.

Implementando a atualização da lista order da coleção:

//+------------------------------------------------------------------+
//| Atualiza a lista order                                           |
//+------------------------------------------------------------------+
void CHistoryCollection::Refresh(void)
  {
#ifdef __MQL4__
   int total=::OrdersHistoryTotal(),i=m_index_order;
   for(; i<total; i++)
     {
      if(!::OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)::OrderType();
      //--- Posições fechadas e operações de saldo/crédito
      if(order_type<ORDER_TYPE_BUY_LIMIT || order_type>ORDER_TYPE_SELL_STOP)
        {
         CHistoryOrder *order=new CHistoryOrder(::OrderTicket());
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
      else
        {
         //--- Ordens pendentes removidas
         CHistoryPending *order=new CHistoryPending(::OrderTicket());
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
     }
//---
   int delta_order=i-m_index_order;
   this.m_index_order=i;
   this.m_delta_order=delta_order;
   this.m_is_trade_event=(this.m_delta_order!=0 ? true : false);
//--- __MQL5__
#else 
   if(!::HistorySelect(0,END_TIME)) return;
//--- Ордера
   int total_orders=::HistoryOrdersTotal(),i=m_index_order;
   for(; i<total_orders; i++)
     {
      ulong order_ticket=::HistoryOrderGetTicket(i);
      if(order_ticket==0) continue;
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::HistoryOrderGetInteger(order_ticket,ORDER_TYPE);
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL)
        {
         CHistoryOrder *order=new CHistoryOrder(order_ticket);
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
      else
        {
         CHistoryPending *order=new CHistoryPending(order_ticket);
         if(order==NULL) continue;
         m_list_all_orders.InsertSort(order);
        }
     }
//--- salva o índice da última ordem adicionada e a diferença em comparação com a verificação anterior
   int delta_order=i-this.m_index_order;
   this.m_index_order=i;
   this.m_delta_order=delta_order;
   
//--- Negócios
   int total_deals=::HistoryDealsTotal(),j=m_index_deal;
   for(; j<total_deals; j++)
     {
      ulong deal_ticket=::HistoryDealGetTicket(j);
      if(deal_ticket==0) continue;
      CHistoryDeal *deal=new CHistoryDeal(deal_ticket);
      if(deal==NULL) continue;
      m_list_all_orders.InsertSort(deal);
     }
//--- salve o índice do último negócio adicionado e a diferença em comparação com a verificação anterior
   int delta_deal=j-this.m_index_deal;
   this.m_index_deal=j;
   this.m_delta_deal=delta_deal;
//--- Define a nova flag de evento no histórico
   this.m_is_trade_event=(this.m_delta_order+this.m_delta_deal);
#endif 
  }
//+------------------------------------------------------------------+

Verifica a afiliação com a MQL4 ou MQL5. Vamos analisar o código usando a MQL5 como exemplo, já que ela é um pouco mais complicada.

Primeiro, solicite o histórico completo da conta. Se falhar, saia até o próximo tick. Após a solicitação do histórico bem-sucedida, duas listas são criadas — lista de ordens e negócios.

Primeiro, percorra ao longo da lista de todas as ordens em um loop. O índice inicial do loop é um resultado da operação do loop anterior (no começo start = 0). Isso nos permite percorrer apenas através de novas ordens que apareceram no histórico desde a última verificação, em vez de percorrer um loop custoso ao longo de todo o histórico.

Em seguida, obtenha o ticket da ordem e o seu tipo. Crie um novo objeto de acordo com o resultado da verificação do tipo da ordem (um histórico de ordem à mercado ou de ordem pendente removida) e coloque-o na lista da coleção ordenada de forma imediata (já definimos a classificação por horário de fechamento antes).

Após a conclusão da operação de loop, salve o índice da nova ordem de modo que um novo loop comece a partir dele. A diferença entre os resultados da operação de loops anteriores e atuais é o número de ordens recém-adicionadas.
O loop para trabalhar com os negócios é o mesmo, exceto que não há necessidade de dividir os negócios por tipos. Em vez disso, você pode adicionar um objeto deal à lista da coleção imediatamente.

O loop no código em MQL4 é quase o mesmo, exceto que o loop é obtido de todo o histórico possível da conta. O comprimento do histórico é especificado por um usuário na guia Histórico do terminal, o que significa que cabe aos usuários garantir que todo o histórico esteja disponível, se o programa exigir. Outra opção é usar a WinAPI para obter o histórico inteiro, o que está além do escopo dos artigos.

Após a conclusão dos loops, o número de novas ordens e negócios é verificada. Se o número for maior que zero, a flag do evento de negociação ocorrido é definido.

Nós implementamos a obtenção dos dados na classe da coleção de histórico semelhante à implementada no teste do EA na primeira parte, exceto que no caso atual, diferentes objetos do histórico de ordens são criados separados pelo seu estado. A fim de verificar como tudo isso funciona, nós precisamos obter a lista da coleção criada do histórico de ordens do lado de fora (do programa que usa esta biblioteca; no nosso caso, este é um EA de teste).

Para fazer isso, adicione o método GetList() sem parâmetros para a seção public da classe CHistoryCollection (no próximo artigo, eu adicionarei os métodos para receber a lista com parâmetros):
//+------------------------------------------------------------------+
//| Coleção do histórico de ordens e negócios                        |
//+------------------------------------------------------------------+
class CHistoryCollection
  {
private:
   CArrayObj         m_list_all_orders;      // Lista de todo o histórico de ordens e negócios
   bool              m_is_trade_event;       // Flag do evento de negociação
   int               m_index_order;          // Índice da última ordem adicionada à coleção da lista do histórico do terminal (MQL4, MQL5)
   int               m_index_deal;           // Índice do último negócio adicionado à coleção da lista do histórico do terminal (MQL5)
   int               m_delta_order;          // Diferença no número de ordens em comparação com a verificação passada
   int               m_delta_deal;           // Diferença no número de negócios em comparação com a verificação passada
public:
   //--- Retorna a lista completa da coleção 'como está'
   CArrayObj*        GetList(void)           { return &m_list_all_orders;  }
//--- Construtor
                     CHistoryCollection();
   //--- Atualiza a lista de ordens, preenche os dados sobre o número de novas ordens e configura o evento de negociação
   void              Refresh(void);
  };
//+------------------------------------------------------------------+

Como pode ser visto na listagem, o ponteiro para a lista (não o objeto em si) é retornado. Isso é suficiente para usar a lista nos programas. No entanto, isso é insuficiente para o uso rápido e fácil da biblioteca. No próximo artigo dedicado à biblioteca, eu implementarei um acesso fácil aos dados necessários mediante solicitação. Nos próximos artigos, eu vou simplificar ainda mais o acesso, criando funções especiais para trabalhar com a biblioteca em programas personalizados.

Vamos ver como a lista está preenchida. Para fazer isso, crie um pequeno EA. Na pasta TestDoEasy (que nós já criamos na primeira parte), gere a subpasta Part02. Ele conterá o arquivo do segundo EA de teste chamado TestDoEasyPart02 e conecte a coleção criada a ela:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart02.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Collections\HistoryCollection.mqh>
//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função de desinicialização do Expert                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Função Tick do Expert                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Como a lista agora armazena os objetos de vários tipos herdados do único pai COrder, vamos implementar a exibição das descrições dos objetos selecionados no diário. Para fazer isso, crie a enumeração com a seleção dos tipos de ordens exibidos nas entradas, bem como o objeto da coleção para ler os dados da conta:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart02.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Collections\HistoryCollection.mqh>
//--- enums
enum ENUM_TYPE_ORDERS
  {
   TYPE_ORDER_MARKET,   // Ordens à mercado
   TYPE_ORDER_PENDING,  // Ordens pendentes
   TYPE_ORDER_DEAL      // Negócios
  };
//--- parâmetros de entrada
input ENUM_TYPE_ORDERS  InpOrderType   =  TYPE_ORDER_DEAL;  // Tipo da exibição:
//--- variáveis globais
CHistoryCollection history;
//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+

Como no teste anterior do EA da primeira parte da descrição da biblioteca, leia o histórico da conta no manipulador OnInit() e exiba as informações sobre as ordens para o diário em um loop:

//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- atualiza o histórico
   history.Refresh();
//--- obtém o ponteiro para a lista completa da coleção
   CArrayObj* list=history.GetList();
   if(list==NULL)
     {
      Print("Could not get collection list");
      return INIT_FAILED;
     }
   int total=list.Total();
   for(int i=0;i<total;i++)
     {
      //--- obtém a ordem da lista
      COrder* order=list.At(i);
      if(order==NULL) continue;
      //--- se isso é um negócio
      if(order.Status()==ORDER_STATUS_DEAL && InpOrderType==TYPE_ORDER_DEAL)
         order.Print();
      //--- se esta for o histórico da ordem à mercado
      if(order.Status()==ORDER_STATUS_HISTORY_ORDER && InpOrderType==TYPE_ORDER_MARKET)
         order.Print();
      //--- se esta for uma ordem pendente removida
      if(order.Status()==ORDER_STATUS_HISTORY_PENDING && InpOrderType==TYPE_ORDER_PENDING)
         order.Print();
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Aqui, crie um ponteiro para a lista da coleção e receba-o de CHistoryCollection usando o método GetList(), que foi criado lá.
Em seguida, em um loop, obtenha o objeto order da lista, verifique seu estado e permissão para exibir os dados no diário nas configurações do EA.
Dependendo dos resultados, exiba os dados no diário ou não.
No entanto, nós obtemos o objeto base COrder da lista, apenas os dados inerentes aos descendentes da ordem base são exibidos no diário — ordens à mercado, ordens pendentes e negócios com métodos virtuais redefinidos que retornam a flag, indicando que a ordem suporta apenas suas propriedades inerentes.

Compile e execute o EA. O jornal exibe os dados sobre os tipos de ordens e negócios selecionados:


Se você olhar de perto os tipos de propriedades exibidas, nós veremos as propriedades que não são típicas das ordens em MQL5: lucro, swap, comissão e lucro em pontos.

Vamos fazer algumas melhorias e adições nos objetos já criados.

Adicione a propriedade não suportada Lucro em MQL5 em pontos para o método SupportProperty(ENUM_ORDER_PROP_INTEGER property) da classe CHistoryOrder:

//+------------------------------------------------------------------+
//| Retorna 'true' se a ordem suportar a propriedade passada,        |
//| caso contrário, retorna 'false'                                  |
//+------------------------------------------------------------------+
bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_INTEGER property)
  {
   if(property==ORDER_PROP_TIME_EXP       || 
      property==ORDER_PROP_DEAL_ENTRY     || 
      property==ORDER_PROP_TIME_UPDATE    || 
      property==ORDER_PROP_TIME_UPDATE_MSC
      #ifdef __MQL5__                     ||
      property==ORDER_PROP_PROFIT_PT
      #endif                        
     ) return false;
   return true;
  }
//+------------------------------------------------------------------+

e ainda adiciona outro método virtual retornando o suporte de propriedades do tipo real pelas ordens:

//+------------------------------------------------------------------+
//| Histórico da ordem à mercado                                     |
//+------------------------------------------------------------------+
class CHistoryOrder : public COrder
  {
public:
   //--- Construtor
                     CHistoryOrder(const ulong ticket) : COrder(ORDER_STATUS_HISTORY_ORDER,ticket) {}
   //--- Propriedades do tipo inteiro suportadas de uma ordem
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property);
   //--- Propriedades do tipo real suportadas de uma ordem
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property);
  };
//+------------------------------------------------------------------+

bem como a sua implementação:

//+------------------------------------------------------------------+
//| Retorna 'true' se a ordem suportar a propriedade passada,        |
//| caso contrário, retorna 'false'                                  |
//+------------------------------------------------------------------+
bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_DOUBLE property)
  {
#ifdef __MQL5__
   if(property==ORDER_PROP_PROFIT      || 
      property==ORDER_PROP_PROFIT_FULL || 
      property==ORDER_PROP_SWAP        || 
      property==ORDER_PROP_COMMISSION  ||
      property==ORDER_PROP_PRICE_STOP_LIMIT
     ) return false;
#endif 
   return true;
  }
//+------------------------------------------------------------------+

Se for em MQL5, o lucro, swap, comissão, lucro total e preço da ordem StopLimit não são suportados. Para MQL4 e outras propriedades de ordem do tipo real em MQL5, retorna a flag do suporte da ordem para as propriedades do tipo real.

As ordens em MQL5 também possuem a propriedade ORDER_STATE. Esta é o estado da ordem definido na enumeração ENUM_ORDER_STATE.
Adicione-o à lista de propriedades da ordem inteira (a enumeração ENUM_ORDER_PROP_INTEGER nos arquivos Defines.mqh):

//+------------------------------------------------------------------+
//| Proprieades do tipo inteiro de ordem, negócio, posição           |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // Ticket da ordem
   ORDER_PROP_MAGIC,                                        // Magic number da ordem
   ORDER_PROP_TIME_OPEN,                                    // Horário de abertura (horário do negócio em MQL5)
   ORDER_PROP_TIME_CLOSE,                                   // Horário de fechamento (horário de execução ou remoção em MQL5 - ORDER_TIME_DONE)
   ORDER_PROP_TIME_OPEN_MSC,                                // Horário de abertura em milissegundos (horário do negócio MQL5 em ms)
   ORDER_PROP_TIME_CLOSE_MSC,                               // Horário de abertura em milissegundos (horário de execução ou remoção em MQL5 - ORDER_TIME_DONE_MSC)
   ORDER_PROP_TIME_EXP,                                     // Data de expiração da ordem (para ordens pendentes)
   ORDER_PROP_STATUS,                                       // Estado da ordem (da enumeração ENUM_ORDER_STATUS)
   ORDER_PROP_TYPE,                                         // Tipo da ordem (tipo da ordem em MQL5 deal type)
   ORDER_PROP_DIRECTION,                                    // Direção (Buy, Sell)
   ORDER_PROP_REASON,                                       // origem ou razão do negócio/ordem/posição
   ORDER_PROP_STATE,                                        // Estado da ordem (da enumeração ENUM_ORDER_STATE)
   ORDER_PROP_POSITION_ID,                                  // ID da posição
   ORDER_PROP_POSITION_BY_ID,                               // ID da posição oposta
   ORDER_PROP_DEAL_ORDER,                                   // Ordem, baseada no negócio executado
   ORDER_PROP_DEAL_ENTRY,                                   // Direção do negócio – IN, OUT ou IN/OUT
   ORDER_PROP_TIME_UPDATE,                                  // Horário da alteração da posição em segundos
   ORDER_PROP_TIME_UPDATE_MSC,                              // Horário da alteração da posição em milissegundos
   ORDER_PROP_TICKET_FROM,                                  // ticket da ordem pai
   ORDER_PROP_TICKET_TO,                                    // ticket da ordem derivada
   ORDER_PROP_PROFIT_PT,                                    // Lucro em pontos
   ORDER_PROP_CLOSE_BY_SL,                                  // Tipo do fechamento por StopLoss
   ORDER_PROP_CLOSE_BY_TP,                                  // Tipo do fechamento por TakeProfit
  }; 
#define ORDER_PROP_INTEGER_TOTAL    (23)                    // Número total de propriedades do tipo inteiro
//+------------------------------------------------------------------+

e certifique-se de alterar o número de propriedades do tipo inteiro da ordem de 22 para 23 na substituição de macro ORDER_PROP_INTEGER_TOTAL indicando o número de propriedades do tipo inteiro da ordem e usado para calcular o "endereço" exato da propriedade da ordem necessária.
No mesmo arquivo, adicione a nova propriedade aos possíveis critérios de classificação de ordem, para que possamos classificar as ordens por essa nova propriedade e implementar o cálculo mais conveniente de índices no caso de uma mudança subsequente das enumerações:

//+------------------------------------------------------------------+
//| Possíveis critérios de classificação de ordens e negócios        |
//+------------------------------------------------------------------+
#define FIRST_DBL_PROP              (ORDER_PROP_INTEGER_TOTAL)
#define FIRST_STR_PROP              (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL)
enum ENUM_SORT_ORDERS_MODE
  {
   //--- Classifica por propriedades do tipo inteiro
   SORT_BY_ORDER_TICKET          =  0,                      // Classifica pelo ticket da ordem
   SORT_BY_ORDER_MAGIC           =  1,                      // Classifia pelo número mágico da ordem
   SORT_BY_ORDER_TIME_OPEN       =  2,                      // Classifica pelo horário de abertura da ordem
   SORT_BY_ORDER_TIME_CLOSE      =  3,                      // Classifica pelo horário de fechamento da ordem
   SORT_BY_ORDER_TIME_OPEN_MSC   =  4,                      // Classifica pelo horário de abertura da ordem em milissegundos
   SORT_BY_ORDER_TIME_CLOSE_MSC  =  5,                      // Classifica pelo horário de fechamento da ordem em milissegundos
   SORT_BY_ORDER_TIME_EXP        =  6,                      // Classifica pela data de expiração da ordem
   SORT_BY_ORDER_STATUS          =  7,                      // Classifica pelo estado da ordem (ordem à mercado/ordem pendente/negócio)
   SORT_BY_ORDER_TYPE            =  8,                      // Classifica pelo tipo da ordem
   SORT_BY_ORDER_REASON          =  10,                     // Classifica pelo negócio/ordem/posição/razão/origem
   SORT_BY_ORDER_STATE           =  11,                     // Classifica pelo estado da ordem
   SORT_BY_ORDER_POSITION_ID     =  12,                     // Classifica pelo ID da posição
   SORT_BY_ORDER_POSITION_BY_ID  =  13,                     // Classifica pelo ID da posição oposta
   SORT_BY_ORDER_DEAL_ORDER      =  14,                     // Classifica pela ordem que o negócio se baseou
   SORT_BY_ORDER_DEAL_ENTRY      =  15,                     // Classifica pela direção do negócio – IN, OUT ou IN/OUT
   SORT_BY_ORDER_TIME_UPDATE     =  16,                     // Classifica pelo horário de alteração da posição em segundos
   SORT_BY_ORDER_TIME_UPDATE_MSC =  17,                     // Classifica pelo horário de alteração da posição em milissegundos
   SORT_BY_ORDER_TICKET_FROM     =  18,                     // Classifica pelo ticket da ordem pai
   SORT_BY_ORDER_TICKET_TO       =  19,                     // Classifica pelo ticket da ordem derivada
   SORT_BY_ORDER_PROFIT_PT       =  20,                     // Classifica pelo lucro da ordem em pontos
   SORT_BY_ORDER_CLOSE_BY_SL     =  21,                     // Classifica pelo fechamento da ordem pela flag StopLoss
   SORT_BY_ORDER_CLOSE_BY_TP     =  22,                     // Classifica pelo fechamento da ordem pela flag TakeProfit
   //--- Classifica por propriedades do tipo real
   SORT_BY_ORDER_PRICE_OPEN      =  FIRST_DBL_PROP,         // Classifica pelo preço de abertura
   SORT_BY_ORDER_PRICE_CLOSE     =  FIRST_DBL_PROP+1,       // Classifica pelo preço do fechamento
   SORT_BY_ORDER_SL              =  FIRST_DBL_PROP+2,       // Classifica pelo preço de StopLoss
   SORT_BY_ORDER_TP              =  FIRST_DBL_PROP+3,       // Classifica pelo preço de TakeProfit
   SORT_BY_ORDER_PROFIT          =  FIRST_DBL_PROP+4,       // Classifica pelo lucro
   SORT_BY_ORDER_COMMISSION      =  FIRST_DBL_PROP+5,       // Classifica pela comissão
   SORT_BY_ORDER_SWAP            =  FIRST_DBL_PROP+6,       // Classifica pelo swap
   SORT_BY_ORDER_VOLUME          =  FIRST_DBL_PROP+7,       // Classifica pelo volume
   SORT_BY_ORDER_VOLUME_CURRENT  =  FIRST_DBL_PROP+8,       // Classifica pelo volume não executado
   SORT_BY_ORDER_PROFIT_FULL     =  FIRST_DBL_PROP+9,       // Classifica pelo critério de lucro+comissão+swap
   SORT_BY_ORDER_PRICE_STOP_LIMIT=  FIRST_DBL_PROP+10,      // Classifica pela ordem limitada quando a ordem StopLimit é ativada
   //--- Classifica pelas propriedades do tipo string
   SORT_BY_ORDER_SYMBOL          =  FIRST_STR_PROP,         // Classifica pelo símbolo
   SORT_BY_ORDER_COMMENT         =  FIRST_STR_PROP+1,       // Classifica pelo comentário
   SORT_BY_ORDER_EXT_ID          =  FIRST_STR_PROP+2        // Classifica pelo ID da ordem em um sistema de negociação externo
  };
//+------------------------------------------------------------------+

Na seção protected da classe abstrata COrder do arquivo Order.mqh, declare o método OrderState() escrevendo seu estado a partir da enumeração ENUM_ORDER_STATE para as propriedades da ordem:

protected:
   //--- Construtor paramétrico protegido
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);

   //--- Obtém e retorna as propriedades do tipo inteiro de uma ordem selecionada de seus parâmetros
   long              OrderMagicNumber(void)        const;
   long              OrderTicket(void)             const;
   long              OrderTicketFrom(void)         const;
   long              OrderTicketTo(void)           const;
   long              OrderPositionID(void)         const;
   long              OrderPositionByID(void)       const;
   long              OrderOpenTimeMSC(void)        const;
   long              OrderCloseTimeMSC(void)       const;
   long              OrderType(void)               const;
   long              OrderState(void)              const;
   long              OrderTypeByDirection(void)    const;
   long              OrderTypeFilling(void)        const;
   long              OrderTypeTime(void)           const;
   long              OrderReason(void)             const;
   long              DealOrder(void)               const;
   long              DealEntry(void)               const;
   bool              OrderCloseByStopLoss(void)    const;
   bool              OrderCloseByTakeProfit(void)  const;
   datetime          OrderOpenTime(void)           const;
   datetime          OrderCloseTime(void)          const;
   datetime          OrderExpiration(void)         const;
   datetime          PositionTimeUpdate(void)      const;
   datetime          PositionTimeUpdateMSC(void)   const;

e adicione a sua implementação:

//+------------------------------------------------------------------+
//| Retorna o estado da ordem                                        |
//+------------------------------------------------------------------+
long COrder::OrderState(void) const
  {
#ifdef __MQL4__              
   return ORDER_STATE_FILLED;
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_STATE); break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_STATE);                 break;
      case ORDER_STATUS_MARKET_ACTIVE     : 
      case ORDER_STATUS_DEAL              : 
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+

No caso da MQL4, vamos retornar a execução completa da ordem por agora. No caso da MQL5, ou return 0 (se for um negócio ou uma posição) ou o estado da ordem (se for uma ordem à mercado ou pendente) dependendo do estado da ordem.

Na seção public da classe COrder, declare o método retornando a descrição do estado da ordem:

//+------------------------------------------------------------------+
//| Descrições de propriedades de objetos da ordem                   |
//+------------------------------------------------------------------+
   //--- Obtém a descrição da propriedade do tipo (1) inteiro, (2) real e (3) string
   string            GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_STRING property);
   //--- Retorna o nome do estado da ordem
   string            StatusDescription(void)    const;
   //--- Retorna a ordem ou o nome da posição
   string            TypeDescription(void)      const;
   //--- Retorna a descrição do estado da ordem
   string            StateDescription(void)     const;
   //--- Retorna o nome da direção do negócio
   string            DealEntryDescription(void) const;
   //--- Retorna o tipo da direção da ordem/posição
   string            DirectionDescription(void) const;
   //--- Envia a descrição das propriedades da ordem para o diário (full_prop=true - todas as propriedades, false - apenas as suportadas)
   void              Print(const bool full_prop=false);

bem como a sua implementação:

//+------------------------------------------------------------------+
//| Retorna a descrição do estado da ordem                           |
//+------------------------------------------------------------------+
string COrder::StateDescription(void) const
  {
   if(this.Status()==ORDER_STATUS_DEAL || this.Status()==ORDER_STATUS_MARKET_ACTIVE)
      return "";                       
   else switch(this.StateOrder())
     {
      case ORDER_STATE_STARTED         :  return TextByLanguage("Ордер проверен на корректность, но еще не принят брокером","Order checked for correctness, but not yet accepted by broker");
      case ORDER_STATE_PLACED          :  return TextByLanguage("Ордер принят","Order accepted");
      case ORDER_STATE_CANCELED        :  return TextByLanguage("Ордер снят клиентом","Order withdrawn by client");
      case ORDER_STATE_PARTIAL         :  return TextByLanguage("Ордер выполнен частично","Order filled partially");
      case ORDER_STATE_FILLED          :  return TextByLanguage("Ордер выполнен полностью","Order filled");
      case ORDER_STATE_REJECTED        :  return TextByLanguage("Ордер отклонен","Order rejected");
      case ORDER_STATE_EXPIRED         :  return TextByLanguage("Ордер снят по истечении срока его действия","Order withdrawn upon expiration");
      case ORDER_STATE_REQUEST_ADD     :  return TextByLanguage("Ордер в состоянии регистрации (выставление в торговую систему)","Order in state of registration (placing in trading system)");
      case ORDER_STATE_REQUEST_MODIFY  :  return TextByLanguage("Ордер в состоянии модификации","Order in state of modification.");
      case ORDER_STATE_REQUEST_CANCEL  :  return TextByLanguage("Ордер в состоянии удаления","Order in deletion state");
      default                          :  return TextByLanguage("Неизвестное состояние","Unknown state");
     }
  }
//+------------------------------------------------------------------+

Se esta for um negócio ou uma posição, retorne uma string vazia, caso contrário, verifique o estado da ordem e retorna a sua descrição.

Adiciona o retorno da descrição do estado da ordem na implementação do método GetPropertyDescription(ENUM_ORDER_PROP_INTEGER):

//+------------------------------------------------------------------+
//| Retorna a descrição da propriedade do tipo inteiro de uma ordem  |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property)
  {
   return
     (
   //--- Propriedades gerais
      property==ORDER_PROP_MAGIC             ?  TextByLanguage("Магик","Magic number")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET            ?  TextByLanguage("Тикет","Ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_FROM       ?  TextByLanguage("Тикет родительского ордера","Ticket of parent order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_TO         ?  TextByLanguage("Тикет наследуемого ордера","Inherited order ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN         ?  TextByLanguage("Время открытия","Open time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_CLOSE        ?  TextByLanguage("Время закрытия","Close time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_EXP          ?  TextByLanguage("Дата экспирации","Expiration date")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Не задана",": Not set") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS))
         )  :
      property==ORDER_PROP_TYPE              ?  TextByLanguage("Тип","Type")+": "+this.TypeDescription()                   :
      property==ORDER_PROP_DIRECTION         ?  TextByLanguage("Тип по направлению","Type by direction")+": "+this.DirectionDescription() :
      
      property==ORDER_PROP_REASON            ?  TextByLanguage("Причина","Reason")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetReasonDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_ID       ?  TextByLanguage("Идентификатор позиции","Position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ORDER        ?  TextByLanguage("Сделка на основании ордера","Deal by order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ENTRY        ?  TextByLanguage("Направление сделки","Deal direction")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetEntryDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_BY_ID    ?  TextByLanguage("Идентификатор встречной позиции","Opposite position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN_MSC     ?  TextByLanguage("Время открытия в милисекундах","Open time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_CLOSE_MSC    ?  TextByLanguage("Время закрытия в милисекундах","Close time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_UPDATE       ?  TextByLanguage("Время изменения позиции","Position change time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ? ::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS) : "0")
         )  :
      property==ORDER_PROP_TIME_UPDATE_MSC   ?  TextByLanguage("Время изменения позиции в милисекундах","Position change time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ? (string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property)) : "0")
         )  :
      property==ORDER_PROP_STATE             ?  TextByLanguage("Состояние","Statе")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": \""+this.StateDescription()+"\""
         )  :
   //--- Propriedade adicional
      property==ORDER_PROP_STATUS            ?  TextByLanguage("Статус","Status")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": \""+this.StatusDescription()+"\""
         )  :
      property==ORDER_PROP_PROFIT_PT         ?  TextByLanguage("Прибыль в пунктах","Profit in points")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_CLOSE_BY_SL       ?  TextByLanguage("Закрытие по StopLoss","Close by StopLoss")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==ORDER_PROP_CLOSE_BY_TP       ?  TextByLanguage("Закрытие по TakeProfit","Close by TakeProfit")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Nós completamos todas as melhorias.

Deve-se ter em mente que a biblioteca está sendo desenvolvida "ao vivo" e ela é uma versão beta, portanto várias revisões, alterações e adições podem ser implementadas posteriormente.

Qual é o próximo?

No próximo artigo, eu vou desenvolver uma classe para uma seleção e classificação convenientes das ordens, negócios e posições por qualquer um dos critérios suportados e criar uma coleção de ordens à mercado e posições.

Todos os arquivos da versão atual da biblioteca estão anexados abaixo, juntamente com os arquivos de teste do EA para você testar e baixá-lo.
Deixe suas perguntas, comentários e sugestões nos comentários.

Voltar ao conteúdo


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

Arquivos anexados |
MQL5.zip (22.89 KB)
Estudo de técnicas de análise de velas (parte III): Biblioteca para trabalhar com os padrões Estudo de técnicas de análise de velas (parte III): Biblioteca para trabalhar com os padrões
O objetivo deste artigo é criar uma ferramenta personalizada que permita aos usuários receber e usar todo o array de informações sobre os padrões discutidos anteriormente. Nós vamos criar uma biblioteca de funções relacionadas aos padrões que você poderá usar em seus próprios indicadores, painéis de negociação, Expert Advisors, etc.
Extraindo dados estruturados de páginas HTML através de seletores CSS Extraindo dados estruturados de páginas HTML através de seletores CSS
O artigo descreve um método universal para analisar e converter dados de documentos HTML com base em seletores CSS. Em MQL estão disponíveis relatórios de negociação e de teste, calendários econômicos, sinais públicos e monitoramento de contas, fontes de cotações on-line adicionais.
Raspagem de dados da web sobre a rentabilidade dos títulos públicos Raspagem de dados da web sobre a rentabilidade dos títulos públicos
Automatize a coleta de dados sobre a taxa de juros para melhorar o desempenho de um Expert Advisor.
Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte I). Conceito, gerenciamento de dados e primeiros resultados Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte I). Conceito, gerenciamento de dados e primeiros resultados
Ao analisar um grande número de estratégias de negociação, pedidos de desenvolvimento de aplicativos para os terminais MetaTrader 5 e MetaTrader 4 e vários sites sobre MetaTrader, eu cheguei à conclusão de que toda essa diversidade é baseada principalmente nas mesmas funções elementares, ações e valores que aparecem regularmente em diferentes programas. Isso resultou na biblioteca multi-plataforma DoEasy para o desenvolvimento fácil e rápido de aplicativos para a МetaТrader 5 e МetaТrader 4.