Discussão do artigo "Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte XI). Compatibilidade com a MQL4 - Eventos de encerramento de posição"

 

Novo artigo Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte XI). Compatibilidade com a MQL4 - Eventos de encerramento de posição foi publicado:

Nós continuamos com o desenvolvimento de uma grande biblioteca multi-plataforma, simplificando o desenvolvimento de programas para as plataformas MetaTrader 5 e MetaTrader 4. Na décima parte, nós retomamos nosso trabalho sobre a compatibilidade da biblioteca com a MQL4 e definimos os eventos de abertura de posições e ativação de ordens pendentes. Neste artigo, nós definiremos os eventos de encerramento de posições e nos livraremos das propriedades de ordem não utilizadas.

Agora, os eventos de encerramento parcial e remoção de ordem pendente são definidos como eventos separados.

Inicie o EA novamente e clique nos botões observando as definição de eventos:


Como nós podemos ver, os eventos estão definidos corretamente. Um evento de encerramento é definido, modificações nos níveis de stop e preços de ordens pendentes também são rastreados.

Autor: Artyom Trishkin

 

Tenho algumas observações relacionadas ao efeito das variáveis de tempo de milissegundos e, particularmente, sobre afunção CHistoryCollection::GetListByTime(...) em relação à versão MQL5.

Elas são (em ordem decrescente de relevância):

1) Tanto as variáveis datetime quanto as variáveis de tempo de milissegundos longos representam o tempo decorrido desde 01/01/1970. No entanto, há um fator de 1000 entre os valores efetivamente armazenados. Portanto, os dois tipos não podem ser atribuídos diretamente um ao outro. Como consequência, o GetListByTime(...) parou de funcionar após a alteração, pois armazena diretamente os parâmetros de data e hora na propriedade time millisecond do COrder m_order_instance. Uma possível solução poderia ser incluir duas novas funções de conversão (provavelmente em delib.mqh) para cuidar desse fator 1000:

//+------------------------------------------------------------------+
//| Converte o tempo em milissegundos para datetime
//+------------------------------------------------------------------+
datetime TimeMSCtoDate(const long time_msc)
  {
   return datetime(time_msc/1000);
  }
//+------------------------------------------------------------------+
//| Converte datetime em tempo em milissegundos
//+------------------------------------------------------------------+
long DatetoTimeMSC(const datetime time_sec)
  {
   return long(time_sec * 1000);
  }
Esse tipo de problema não aconteceria se a MetaQuotes tivesse definido desde o início as variáveis datetime como o tempo decorrido em milissegundos, ou mesmo em microssegundos (quem disse que em dez anos os robôs não estarão negociando em menos de milissegundos?).
De qualquer forma, o problema também está presente pelo menos nas funções GetListByTime(...) nas classes CEventsCollection e CMarketCollection, talvez em outros lugares...
2) A coleção History é um objeto que sabe se está classificada ou não e, se estiver, qual é a propriedade de classificação (funçãoSortMode() ), enquanto a função GetListByTime(...) pressupõe que a coleção esteja classificada pelas propriedades ORDER_PROP_TIME_OPEN ou ORDER_PROP_TIME_CLOSE (apenas ORDER_PROP_TIME_OPEN nas versões CEventsCollection e CMarketCollection ). Seguindo a filosofia OOP, GetListByTime(...) deve verificar se a coleção está classificada corretamente antes de continuar.
De fato, o exemplo de programa TestDoEasyPart03_1.mq5 criou uma coleção de histórico ordenada por ORDER_PROP_TIME_OPEN (o padrão no MT5) e, em seguida, chamou GetListByTime(...,SELECT_BY_TIME_CLOSE). Com essa verificação, isso teria aparecido!
3) Não é grande coisa, mas como o MT5 deve ser o novo padrão, por que não deixar que SELECT_BY_TIME_OPEN seja o valor padrão do parâmetro select_time_mode da função CHistoryCollection::GetListByTime(...)?

Seguindo as sugestões anteriores, este seria o código da função CHistoryCollection::GetListByTime(...):

public:
        .......

   //--- Selecione os pedidos da coleção com o tempo de begin_time a end_time
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0,
                                   const ENUM_SELECT_BY_TIME select_time_mode=SELECT_BY_TIME_OPEN);
        .......

//+------------------------------------------------------------------+
//| Selecionar ordens da coleção com tempo
//| do begin_time ao end_time|
//+------------------------------------------------------------------+
CArrayObj *CHistoryCollection::GetListByTime(const datetime begin_time=0,const datetime end_time=0,
                                             const ENUM_SELECT_BY_TIME select_time_mode=SELECT_BY_TIME_OPEN)
  {
   ENUM_ORDER_PROP_INTEGER property=(select_time_mode==SELECT_BY_TIME_CLOSE ? ORDER_PROP_TIME_CLOSE : ORDER_PROP_TIME_OPEN);
   
   if(property != (ENUM_ORDER_PROP_INTEGER)m_list_all_orders.SortMode())
      {
      ::Print(DFUN+"History list not prpperly sorted");           //Talvez uma mensagem para adicionar ao ENUM_MESSAGES_LIB
      return NULL;
      }

   CArrayObj *list=new CArrayObj();
   if(list==NULL)
     {
      ::Print(DFUN+CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST));
      return NULL;
     }
   datetime begin=begin_time,end=(end_time==0 ? END_TIME : end_time);
   if(begin_time>end_time) begin=0;
   list.FreeMode(false);
   ListStorage.Add(list);
   //---
   this.m_order_instance.SetProperty(property,DatetoTimeMSC(begin));
   int index_begin=this.m_list_all_orders.SearchGreatOrEqual(&m_order_instance);
   if(index_begin==WRONG_VALUE)
      return list;
   this.m_order_instance.SetProperty(property,DatetoTimeMSC(end));
   int index_end=this.m_list_all_orders.SearchLessOrEqual(&m_order_instance);
   if(index_end==WRONG_VALUE)
      return list;
   for(int i=index_begin; i<=index_end; i++)
      list.Add(this.m_list_all_orders.At(i));
   return list;
  }



 
Alvaro Arioni :

Tenho algumas observações relacionadas ao efeito das variáveis de tempo de milissegundos e, particularmente, sobre a função CHistoryCollection::GetListByTime(...) em relação à versão MQL5.

Elas são (em ordem decrescente de relevância):

1) As variáveis datetime e long millisecond time representam o tempo decorrido desde 01/01/1970. No entanto, há um fator de 1000 entre os valores efetivamente armazenados. Portanto, os dois tipos não podem ser atribuídos diretamente um ao outro. Como consequência, o GetListByTime(...) parou de funcionar após a alteração, pois armazena diretamente os parâmetros de data e hora na propriedade time millisecond do COrder m_order_instance. Uma possível solução poderia ser incluir duas novas funções de conversão (provavelmente no delib.mqh ) para cuidar desse fator 1000:

Esse tipo de problema não aconteceria se o MetaQuotes tivesse definido desde o início as variáveis datetime como sendo o tempo decorrido em milissegundos, ou mesmo em microssegundos (quem disse que em dez anos os robôs não estarão negociando em menos de milissegundos?)
De qualquer forma, o problema também está presente pelo menos nas funções GetListByTime(...) nas classes CEventsCollection e CMarketCollection, talvez em outros lugares.
..

2) A coleção History é um objeto que sabe se está classificada ou não e, se estiver, qual é a propriedade de classificação (. SortMode() ), enquanto a função GetListByTime(...) pressupõe que a coleção esteja classificada pelas propriedades ORDER_PROP_TIME_OPEN ou ORDER_PROP_TIME_CLOSE (apenas ORDER_PROP_TIME_OPEN nas versões CEventsCollection e CMarketCollection ). Seguindo a filosofia OOP, GetListByTime(...) deve verificar se a coleção está classificada corretamente antes de continuar.
De fato, o exemplo de programa TestDoEasyPart03_1.mq5 criou uma coleção de histórico ordenada por ORDER_PROP_TIME_OPEN (o padrão no MT5) e, em seguida, chamou GetListByTime(...,SELECT_BY_TIME_CLOSE). Com essa verificação, isso teria aparecido!
3) Não é grande coisa, mas como o MT5 deve ser o novo padrão, por que não deixar que SELECT_BY_TIME_OPEN seja o valor padrão do parâmetro select_time_mode da função CHistoryCollection::GetListByTime(...)?

Seguindo as sugestões anteriores, este seria o código da função CHistoryCollection::GetListByTime(...):



Obrigado. Nas versões posteriores da biblioteca (nos artigos acima do XI), parece que a conversão de tempo já é usada (geralmente deixo o datetime - tudo está em long).

Eu não entendi um pouco sobre coleções - por favor, mostre um exemplo de classificação errada. Desejável no artigo mais recente disponível (já que os artigos descrevem a sequência de criação de uma biblioteca, e tudo muda)