Especialistas: Programação no MQL5 para traders: códigos-fonte retirados do livro. Parte 6 - página 2

 
Stanislav Korotky #:
De qualquer forma, ordens, negócios e posições não estão relacionados a períodos de tempo. Ou você entendeu algo errado ou seu texto está incorreto.
Desculpe-me, acho que minha escolha de palavras está confusa. Por"período de tempo" quero dizer "intervalo de datas". Digamos que eu queira selecionar negócios/ordens transacionados em um determinado intervalo de datas, por exemplo, negócios de 2025-10-01 00:00:00 a 2025-10-22 23:59:59.
 
pauldic #:
Desculpe-me, mas acho que minha escolha de palavras está confusa. Por"período de tempo" quero dizer "intervalo de datas". Digamos que eu queira selecionar transações/pedidos realizados em um determinado intervalo de datas, por exemplo, transações de 2025-10-01 00:00:00 a 2025-10-22 23:59:59.

Se você quiser analisar um subintervalo de um histórico de negociações, é mais eficiente solicitar apenas essa parte do histórico antes da filtragem, sem afetar o próprio código de filtragem:

input datetime SubrangeFrom = 0;
input datetime SubrangeTo = 0;

...

{
   HistorySelect(SubrangeFrom, SubrangeTo);
   // ... o código do filtro fica aqui como está
}

Se, por algum motivo, você quiser selecionar um subintervalo (mais restrito) dentro do intervalo global que você aplicou com HistorySelect, ainda poderá fazer isso no código de filtragem da seguinte forma:

{
      // alguns deles estão aqui

      // HistorySelect(0, LONG_MAX);
      // HistorySelectByPosition(PositionID);
      ...
      DealTuple deals[];
      if(SubrangeFrom != SubrangeTo && SubrangeFrom < SubrangeTo)
      {
         filter.let(DEAL_TIME, SubrangeFrom - 1, IS::GREATER).let(DEAL_TIME, SubrangeTo + 1, IS::LESS);
      }
      filter.let(DEAL_POSITION_ID, PositionID).select(deals, true);
      ...
}

A linha destacada em amarelo define duas condições para o intervalo de data e hora [SubrangeFrom, SubrangeTo] usando qualificadores adicionais IS::GREATER e IS::LESS (por padrão, eles não são especificados em outras chamadas para let(), e IS::EQUAL é normalmente usado para campos de valor único).

Conheço apenas um motivo para aplicar o subfiltro por intervalo de datas: é o tempo de configuração das ordens (ORDER_TIME_SETUP), porque o HistorySelect é aplicado a outra propriedade de data e hora das ordens, ou seja, o tempo de execução da ordem (ORDER_TIME_DONE). Também pode ser interessante filtrar um subintervalo de ordens ativas (não no histórico), se houver muitas delas.

Você pode dar uma olhada no script de exemplo MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5, como ponto de partida.
 
Stanislav Korotky #:

Se você quiser analisar um subintervalo de um histórico de negociação, é mais eficiente solicitar apenas essa parte do histórico antes da filtragem, sem afetar o próprio código de filtragem:

Se, por algum motivo, você quiser selecionar um subintervalo (mais estreito) dentro do intervalo global que aplicou com HistorySelect, ainda poderá fazer isso no código de filtragem da seguinte forma:

A linha destacada em amarelo define duas condições para o intervalo de datetime [SubrangeFrom, SubrangeTo] usando qualificadores adicionais IS::GREATER e IS::LESS (por padrão, eles não são especificados em outras chamadas para let(), e IS::EQUAL é normalmente usado para campos de valor único).

Conheço apenas um motivo para aplicar o subfiltro por intervalo de datas: é o tempo de configuração das ordens (ORDER_TIME_SETUP), porque o HistorySelect é aplicado a outra propriedade de data e hora das ordens, ou seja, o tempo de execução da ordem (ORDER_TIME_DONE). Também pode ser interessante filtrar um subintervalo de ordens ativas (não no histórico), se houver muitas delas.

Você pode dar uma olhada no script de exemplo MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5, como ponto de partida.
@StanislavKorotky Mais uma vez, obrigado... Esse é um ótimo ponto de partida para mim e começarei a trabalhar com ele
 

Correção de bug MQL5/Include/MQL5Book/TradeUtils.mqh.

   bool Equal(const double v1, const double v2)
   {
      return v1 == v2 || fabs(v1 - v2) < DBL_EPSILON * fmax(1.0, fmax(fabs(v1), fabs(v2)));
   }
Arquivos anexados:
TradeUtils.mqh  12 kb
 
pauldic #:

Use obotão CODE (Alt-S) ao inserir o código.

Um moderador formatou o código colado incorretamente. Normalmente, esse código é removido.

@StanislavKorotky Por favor, você pode ajudar a analisar esse erro? Acredito que ele tenha começado depois das atualizações do MT5 porque eu sabia que o código funcionava nos meses anteriores sem nenhuma modificação.

parameter convertion type 'long[][2]' to 'string[][] &' is not allowed SymbolFilter.mqh 199 20

O tipo de conversão de parâmetro 'double[][2]' para 'string[][] &' não é permitido TradeFilter.mqh 332 20
Não é permitida a conversão do parâmetro 'long[][2]' para 'string[][] &' TradeFilter.mqh 163 17


Acredito que o código abaixo ajudará a replicar o problema:


Olá @Paul Dick

Tente este https://www.mql5.com/pt/code/57233 para classificar matrizes

Introsort (Introspective sort) using Function Pointers
Introsort (Introspective sort) using Function Pointers
  • 2025.03.18
  • www.mql5.com
A hybrid sorting algorithm that provide fast performance for sorting arrays of simple types, structures or object pointers.
 

Estou anexando uma versão atualizada do arquivo de cálculo do critériode otimização personalizado baseado em R2 - RSquared.mqh, no qual o cálculo para o caso de lotes variáveis foi corrigido.

A qualidade da estimativa foi significativamente aprimorada - a julgar pela tabela de resultados de otimização, a combinação do fator de recuperação e dos parâmetros de Sharpe foi obtida.

Exemplo de uso.

double OnTester()
{
   HistorySelect(0, LONG_MAX);
   
   #define  STAT_PROPS 5
   
   const ENUM_DEAL_PROPERTY_DOUBLE props[STAT_PROPS] =
   {
      DEAL_PROFIT, DEAL_SWAP, DEAL_COMMISSION, DEAL_FEE, DEAL_VOLUME
   };
   double expenses[][STAT_PROPS];
   ulong tickets[]; // usado aqui apenas para corresponder ao protótipo 'select', mas útil para depuração
   
   DealFilter filter;
   filter.let(DEAL_TYPE, (1 << DEAL_TYPE_BUY) | (1 << DEAL_TYPE_SELL), IS::OR_BITWISE)
      .let(DEAL_ENTRY, (1 << DEAL_ENTRY_OUT) | (1 << DEAL_ENTRY_INOUT) | (1 << DEAL_ENTRY_OUT_BY), IS::OR_BITWISE)
      .select(props, tickets, expenses);

   const int n = ArraySize(tickets);
   
   double balance[];
   double volumes[]; // levar em conta os volumes de comércio para usar o critério R2
   
   ArrayResize(balance, n + 1);
   balance[0] = 0;
   ArrayResize(volumes, n + 1);
   volumes[0] = 0;
   
   for(int i = 0; i < n; ++i)
   {
      double result = 0;
      for(int j = 0; j < STAT_PROPS - 1; ++j)
      {
         result += expenses[i][j];
      }
      // usar volumes como modelo - mais investimentos - mais retornos esperados
      volumes[i + 1] = expenses[i][STAT_PROPS - 1] + volumes[i];
      balance[i + 1] = result + balance[i];
   }
   
   const double r2 = RSquaredTest(balance, volumes);
   
   #undef  STAT_PROPS
   
   return r2 * 100;
}
Arquivos anexados:
RSquared.mqh  4 kb