Bibliotecas: MT4Orders QuickReport - página 5

 
Forester #:

Servidor: MetaQuotes-Demo Hedge
Lide com o tíquete 99 na página dois.

Um pouco localizado.

#include <MT4Orders.mqh>

void OnTick ()
{
  static int Count = 0;
  
  if (Count > 6)
    return;
  
  MqlTick Tick;
  SymbolInfoTick(_Symbol, Tick);
  
  const double Offset = 5 * _Point;
  bool Buy =  false;
  bool Sell =  false;

  for (uint i = OrdersTotal(); (bool)i--;)
    if (OrderSelect(i, SELECT_BY_POS))         
    {
      if(OrderMagicNumber())
        switch (OrderType())
        {
        case OP_BUY:
          OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.bid + Offset, 0);
          Buy = true;
         
         break;
        case OP_SELL:
          OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.ask - Offset, 0);
          Sell = true;
         
         break;
        case OP_BUYLIMIT:
          OrderModify(OrderTicket(), Tick.ask - Offset, 0, 0, 0);
          Buy = true;
         
         break;
        case OP_SELLLIMIT:          
          OrderModify(OrderTicket(), Tick.bid + Offset, 0, 0, 0);
          Sell = true;
         
         break;
        }
      else
        OrderDelete(OrderTicket());
    }

  if (!Buy)
    OrderSend(_Symbol, OP_BUYLIMIT, 1, Tick.ask - Offset, 0, 0, 0, NULL, ++Count);

  if (!Sell)
    OrderSend(_Symbol, OP_SELLLIMIT, 1, Tick.bid + Offset, 0, 0, 0, NULL, ++Count);
  
  OrderSend(_Symbol, OP_BUYLIMIT, 1,  Tick.ask - Offset, 0, Tick.ask - Offset, Tick.ask - Offset);
  Count++;
}

string TimeToString( const long Time )
{
  return((string)(datetime)(Time / 1000) + "." + IntegerToString(Time % 1000, 3, '0'));
}

void OnDeinit( const int )
{
  if (HistorySelect(0, INT_MAX))
    for (uint i = HistoryOrdersTotal(); (bool)i--;)
    {
      const ulong Ticket = HistoryOrderGetTicket(i);
      
      Print((string)i + ": " + (string)Ticket + " " + TimeToString(HistoryOrderGetInteger(Ticket, ORDER_TIME_DONE_MSC)));
    }
}


Não importa o que o EA está fazendo. O principal é o código destacado, que simplesmente exibe as ordens MT5 do histórico de negociação: o local da ordem, seu tíquete e a hora em que ela entrou no histórico.

11: 13 2023.05.29 23:54:39.425
10: 12 2023.05.29 00:04:25.870
 9: 11 2023.05.29 00:03:59.331
 8: 10 2023.05.29 00:03:59.430
 7: 9 2023.05.29 00:03:59.281
 6: 8 2023.05.29 00:03:59.281
 5: 7 2023.05.29 00:03:59.227
 4: 3 2023.05.29 00:03:59.331
 3: 6 2023.05.29 00:03:18.390
 2: 5 2023.05.29 00:03:18.390
 1: 4 2023.05.29 00:02:41.107
 0: 2 2023.05.29 00:02:41.107

Na tabela do histórico, as ordens MT5 não são classificadas por tíquete ou hora. Não vejo sentido em relatar esse comportamento do MQ-Tester aos desenvolvedores. Afinal de contas, "as tarefas são exageradas".

Portanto, eu não padronizaria o MQ-Tester.

 
fxsaber #:

Um pouco localizado.


Não importa o que o EA faz. O principal é um código dedicado que simplesmente gera ordens do MT5 a partir do histórico de negociação: o local da ordem, seu tíquete e a hora em que entrou no histórico.

Na tabela do histórico, as ordens MT5 não são classificadas por tíquete ou hora. Não vejo sentido em relatar esse comportamento do MQ-Tester aos desenvolvedores. Afinal de contas, "as tarefas são excessivas".

Portanto, eu não padronizaria o MQ-Tester.

Acho que as ordens de limite têm sua própria fila de transferência para o histórico quando são fechadas. Não em cada tick.
Se eles não precisarem corrigir bugs óbvios com as primeiras negociações de teste e swaps (que eu descontei há algumas semanas), então é apenas um recurso. A matriz de confusão é mais importante....
 
Às vezes é bom saber.
// Duração máxima do drawdown a partir do tempo definido.
int MaxLengthDD( datetime &BeginDD, datetime &EndDD, const datetime From = 0 )
{
  const int Total = OrdersHistoryTotal();
  
  double Profit = 0;
  double MaxProfit = 0;
  datetime Begin = 0;
  
  BeginDD = 0;
  EndDD = 0;
  
  for (int i = 0; i < Total; i++)
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderType() <= OP_SELL))
    {
      if (!Begin && (OrderOpenTime() > From))
        Begin = OrderOpenTime();
        
      Profit += OrderProfit() + OrderSwap() + OrderCommission();
      
      if ((Profit > MaxProfit) || (i == Total - 1))
      {
        MaxProfit = Profit;
        
        const datetime End = OrderCloseTime();        
        
        if (Begin && (End - Begin > EndDD - BeginDD))
        {
          BeginDD = Begin;
          EndDD = End;
        }
        
        if (Begin)
          Begin = End;
      }
    }
    
  return((int)(EndDD - BeginDD));
}

void PrintMaxLengthDD( const datetime &From[] )
{
  const int Size = ArraySize(From);
  
  datetime BeginDD, EndDD;
  
  for (int i = 0; i < Size; i++)
    Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);  
}
 

fxsaber #:
Иногда полезно знать.

Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);

É melhor não escrever de forma tão empacotada e frívola (não apenas aqui, mas também em outras fontes). A ordem dos cálculos de operandos com a mesma prioridade não é definida rigidamente - o compilador pode otimizá-la com base em suas próprias considerações, e então você pode obter efeitos colaterais diferentes. Se funcionar agora, isso não significa que não deixará de funcionar mais tarde, pois a implementação interna do compilador muda o tempo todo.

 
Stanislav Korotky #:

É melhor não escrever de forma tão empacotada e frívola (não apenas aqui, mas também em outras fontes). A ordem dos cálculos de operandos com a mesma prioridade não é definida rigidamente - o compilador pode otimizá-la com base em suas próprias considerações, e então você pode obter efeitos colaterais diferentes. Se funcionar agora, isso não significa que não deixará de funcionar mais tarde, pois a implementação interna do compilador muda o tempo todo.

Obrigado pelo bom conselho! Infelizmente, é difícil me forçar a abandonar o estilo "conciso" em favor do estilo correto. Há muito código "errado" escrito e usado.

 
fxsaber #:
// Duração máxima do drawdown a partir de um determinado momento.
A partir da data de início do forward?
Stanislav Korotky #:

É melhor não escrever de forma tão empacotada e frívola (não apenas aqui, mas também em outras fontes). A ordem dos cálculos de operandos com a mesma prioridade não é definida rigidamente - o compilador pode otimizá-la com base em suas próprias considerações, e então você pode obter efeitos colaterais diferentes. Se funcionar agora, isso não significa que não deixará de funcionar mais tarde, pois a implementação interna do compilador muda o tempo todo.

O que há de errado com ele?

Eu apenas

/ (25 * 3600)
Eu não gosto. Há 24 horas em um dia, não 25.
 

Forester #:
C даты начала форварда?

Qualquer pessoa.

O que há de errado nisso?

Não há uma ordem inequívoca na qual a string para o Print será formada. Se for da direita para a esquerda, o resultado será diferente do pretendido.

    Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);  


Gostaria que não houvesse ambiguidade em um caso como esse.

int MaxLengthDD( const datetime &BeginDD, const datetime &EndDD, const datetime From = 0 )
 
fxsaber #:

Obrigado pelo bom conselho! Infelizmente, é difícil me forçar a abandonar o estilo "conciso" em favor do estilo correto. Há muito código "errado" escrito e usado.

Eu quase sempre reduzo funções e outros códigos em uma linha se o código já foi trabalhado/testado e não pretendo voltar a ele. Apenas para economizar espaço.
E é mais conveniente ler o código sem rolar para frente e para trás quando se pode ver tudo em uma única tela. Especialmente em editores que realçam a palavra destacada (infelizmente o Metaeditor não é um deles).
 
Forester #:
Eu quase sempre recolho funções e outros códigos em uma única linha se o código já foi trabalhado/testado e não pretendo voltar a ele. Apenas para economizar espaço.
Além disso, é mais conveniente ler o código sem rolar para frente e para trás quando se pode ver tudo em uma única tela. Especialmente em editores que destacam a palavra destacada (infelizmente, o Metaeditor não é um deles).

Infelizmente, essa prática pode levar a erros muito difíceis de serem vistos quando você muda de compilador.

No entanto, há situações em que você só precisa usar a ordem definida no compilador. E aí eu não sei como contornar isso de modo que não haja UB.

 
fxsaber #:

De qualquer pessoa.

As informações sobre o drawdown máximo longo são interessantes. Eu a criei para toda a matriz de strings. Ainda não atualizei o código no site.
Mas não está muito claro para que serve a data. Se fizermos uma divisão em testes back/forward (como sugeri), precisaremos calcular as estatísticas sobre eles separadamente em duas tabelas (os períodos máximos de drawdown também estarão lá).
E apenas para uma data é, de certa forma, muito específico e incompreensível.