Características da linguagem mql5, subtilezas e técnicas - página 235

 
Marat Sultanov #:
Costumava ser possível (mesmo em compilações mais antigas) usar uma classe antes de ela ser declarada:
Mas agora recebemos um erro ao compilar:
undefined class 'A' cannot be used

Se ele parar de funcionar, seria bom saber se está correto.

Se você criar ponteiros em vez de objetos, a versão antiga também funcionará.

 
fxsaber #:

Se ele parou de funcionar, é bom saber se é a coisa certa a fazer.

Se você criar ponteiros em vez de objetos, a versão antiga também funcionará.

Ótimo argumento e obrigado pela dica!

Sim, de fato, a situação é perfeitamente resolvida com um ponteiro:

class A;

class B
{
   public: A * a;
   public: int Val;
};

class A
{
   public: B * b;
   public: int Test() {return b.Val + 1;}
};

//+------------------------------------------------------------------+
//|                                                                                |
//+------------------------------------------------------------------+
void OnStart()
{
   B b;
   A a;
   
   b.a = GetPointer(a);
   b.a.b = GetPointer(b);
   b.Val = 1;
   
   Print(b.a.Test());
}
 

Fãs de algoritmos rápidos. Aqueles que lutam por nanossegundos :)


Tarefa: encontrar o horário de abertura da barra de acordo com o horário e o TF fornecidos, quando se sabe que a barra existe nesse horário. Por exemplo, pelo tempo das posições de abertura e fechamento.

A maioria dos programadores usará uma combinação de iTime e iBarShift. Essa será a implementação mais lenta, especialmente porque requer um histórico atualizado de dados carregados ou matrizes combinadas. Além disso, essa abordagem pode gerar erros se o histórico necessário estiver faltando.

Programadores mais avançados resolverão esse problema com a estrutura MqlDateTime e a função TimeToStruct(). Essa não é uma solução ruim e é rápida o suficiente.

Mas há uma terceira solução, que é várias vezes mais produtiva do que a anterior:

//+------------------------------------------------------------------+
// получает время открытия виртуального бара по входному времени и Таймфрейму, вне зависимости от того, существует реальный бар или нет.
// корректно считает только до 28.02.2100 !!!!
// не является заменой iBarShift!!! Не зависит от истории баров.  
datetime getStartTimeOfBarFast(ENUM_TIMEFRAMES tf, datetime t) {
   if (tf==0) tf=_Period;

   int ts=0;
   if (tf<PERIOD_MN1) {
      ushort i_tf= ushort(tf);
      uchar _i =uchar(i_tf>>14);
      int n = i_tf & 0x0FFF;
      ts = (_i==0)?n*60:(_i==1)?n*60*60:60*60*24*7;
   }
   if (tf<PERIOD_W1) return t-t%ts;
   if (tf==PERIOD_W1) return t-(t+4*24*60*60)%ts;
   else { // Period MN1
      static int dm[12] = {0,31,61,92,122,153,184, 214, 245, 275, 306, 337};
      static int last_days = 0;
      static datetime last_result = 0;
      int days = int(t/(24*60*60));
      if (last_days!=days) {
         last_days = days;
         int d1 = (days+306+365)%1461;
         int y = d1/365;
         datetime t1 = t - t%(24*60*60) - d1*24*60*60;
         int m = 0;
         if (d1==1460) {
            m=11;
            y--;
         };
         int d = d1-y*365+1;
         if (d!=31) if (d==276) m = 9;
            else m = int (d/30.68);
         if (m<0 || m>11) return -1;
         last_result = t1+y*365*24*60*60+dm[m]*24*60*60;
      }
      return last_result;
   }
}
//+------------------------------------------------------------------+

A principal dificuldade desse algoritmo é calcular a hora do início do mês (destacada em verde). Há mágica acontecendo ali, que é o resultado de ir do simples para o complexo. O caminho inverso, de complexo para simples, será muito mais difícil de percorrer.

O ganho de desempenho também é proporcionado pelo algoritmo de obtenção de segundos em uma barra a partir do TF em vez da função PeriodSeconds() padrão - destacada em amarelo.


Anexei um script de teste que calcula e compara o desempenho de todos os três métodos:

2023.11.14 12:15:29.145 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_MN1========
2023.11.14 12:15:29.146 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 21.20 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:29.146 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 6.10 наносекунд - Быстрый расчет
2023.11.14 12:15:29.147 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 142.00 наносекунд - Расчет через iBarShift
2023.11.14 12:15:29.147 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:34.226 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_MN1========
2023.11.14 12:15:34.227 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 19.80 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:34.227 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 6.70 наносекунд - Быстрый расчет
2023.11.14 12:15:34.228 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11987239507200, время выполнения 1 иттерации = 127.50 наносекунд - Расчет через iBarShift
2023.11.14 12:15:34.228 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:39.856 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_W1========
2023.11.14 12:15:39.856 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11997367833600, время выполнения 1 иттерации = 2.80 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:39.856 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11997367833600, время выполнения 1 иттерации = 1.50 наносекунд - Быстрый расчет
2023.11.14 12:15:39.857 timeToStartMonth (EURUSD,M1)    контрольная сумма - 11997367833600, время выполнения 1 иттерации = 98.30 наносекунд - Расчет через iBarShift
2023.11.14 12:15:39.857 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:52.770 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_H2========
2023.11.14 12:15:52.771 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000355999200, время выполнения 1 иттерации = 4.10 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:52.771 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000355999200, время выполнения 1 иттерации = 1.50 наносекунд - Быстрый расчет
2023.11.14 12:15:54.255 timeToStartMonth (EURUSD,M1)    контрольная сумма - 0, время выполнения 1 иттерации = 148466.50 наносекунд - Расчет через iBarShift
2023.11.14 12:15:54.255 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:15:58.759 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_M4========
2023.11.14 12:15:58.759 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000391999920, время выполнения 1 иттерации = 3.60 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:15:58.759 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000391999920, время выполнения 1 иттерации = 1.50 наносекунд - Быстрый расчет
2023.11.14 12:15:59.864 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000017286960, время выполнения 1 иттерации = 110555.70 наносекунд - Расчет через iBarShift
2023.11.14 12:15:59.864 timeToStartMonth (EURUSD,M1)    ========================================================================

A soma de verificação com o iBarShift não coincidirá , porque o iBarShift trabalha com barras reais. A soma de verificação coincidirá apenas nos períodos de tempo MN1 e W1, porque não há buracos no histórico dessas barras.
O desempenho será maior se você usar uma pequena etapa de tempo no loop (menos de um dia) quando o algoritmo começar a funcionar para salvar os cálculos anteriores:

2023.11.14 12:14:10.714 timeToStartMonth (EURUSD,M1)    =====LOOP=1000000========STEPS=1000 seconds======PERIOD_MN1========
2023.11.14 12:14:10.722 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 8.03 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:14:10.723 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 1.18 наносекунд - Быстрый расчет
2023.11.14 12:14:10.860 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 136.80 наносекунд - Расчет через iBarShift
2023.11.14 12:14:10.860 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:14:17.502 timeToStartMonth (EURUSD,M1)    =====LOOP=1000000========STEPS=1000 seconds======PERIOD_MN1========
2023.11.14 12:14:17.510 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 7.70 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:14:17.511 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 1.18 наносекунд - Быстрый расчет
2023.11.14 12:14:17.648 timeToStartMonth (EURUSD,M1)    контрольная сумма - 1198674131961600, время выполнения 1 иттерации = 137.54 наносекунд - Расчет через iBarShift
2023.11.14 12:14:17.648 timeToStartMonth (EURUSD,M1)    ========================================================================


Valores excessivos para o algoritmo via iBarShift (destacados em azul) são causados pela atual falta de histórico necessário ou de TFs calculados pela matriz, que inicia seu carregamento.
Após o carregamento, o resultado será o seguinte:

2023.11.14 12:47:06.158 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_H2========
2023.11.14 12:47:06.158 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000379996800, время выполнения 1 иттерации = 4.60 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:47:06.158 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000379996800, время выполнения 1 иттерации = 2.60 наносекунд - Быстрый расчет
2023.11.14 12:47:06.159 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000009103200, время выполнения 1 иттерации = 129.10 наносекунд - Расчет через iBarShift
2023.11.14 12:47:06.159 timeToStartMonth (EURUSD,M1)    ========================================================================
2023.11.14 12:47:13.899 timeToStartMonth (EURUSD,M1)    =====LOOP=10000========STEPS=100000 seconds======PERIOD_M4========
2023.11.14 12:47:13.899 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000411199920, время выполнения 1 иттерации = 2.80 наносекунд - Расчет через структуру MqlDateTime
2023.11.14 12:47:13.899 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000411199920, время выполнения 1 иттерации = 1.40 наносекунд - Быстрый расчет
2023.11.14 12:47:13.903 timeToStartMonth (EURUSD,M1)    контрольная сумма - 12000038634480, время выполнения 1 иттерации = 381.30 наносекунд - Расчет через iBarShift
2023.11.14 12:47:13.903 timeToStartMonth (EURUSD,M1)    ========================================================================

Arquivos anexados:
 
Nikolai Semko #:

Fãs de algoritmos rápidos. Aqueles que lutam por nanossegundos :)

...

😮😲😳🥴🤪

...

ah...

mmm....

oooh....

gkghm... Não achei que minha simples pergunta sairia assim.

Assim mesmo. Oh.

 
Artyom Trishkin #:

😮😲😳🥴🤪

...

ah...

mmm.

ohhhh....

ahem. Não achei que minha pergunta simples seria respondida dessa forma.

Ah.

Sim, Artem, você me enganou por um tempo.
Foi um interesse esportivo.
Espero que seja útil para alguém, inclusive para mim. :))

 
Nikolai Semko #:

Sim, Artem, você me enganou por um tempo.
Trabalhei com interesse esportivo.
Espero que seja útil para alguém, e para mim, entre outros. :))

É claro que será. Ótimo. Mais uma vez, obrigado!

S.F. Isso me divertiu: "conta corretamente somente até 28.02.2100 !!!!".

O que faremos depois disso?

 
Artyom Trishkin #:

É claro que será útil. Muito bom. Mais uma vez, obrigado!

S.F. Isso me divertiu: "counts correctly only until 28.02.2100 !!!!".

O que faremos depois disso?

haha.
Duvido que esse algoritmo seja solicitado daqui a 75 anos. Os computadores quânticos provavelmente já estarão dominando o mundo, com uma programação completamente diferente.
Para ser honesto, foi preguiça de levar em conta o calendário gregoriano. 2000 era um ano de alto risco, 2100 não é mais.

 
Nikolai Semko #:

haha.
Duvido que esse algoritmo seja solicitado daqui a 75 anos. Os computadores quânticos provavelmente já dominarão o mundo, com uma programação completamente diferente.
Para ser honesto, foi preguiçoso levar em conta o calendário gregoriano completamente. 2000 era um ano de alto risco, 2100 não é mais.

Para o MN, você pode usar uma matriz pré-calculada, não há quase nada nela

Ln2(12 meses * cem anos)... 11 if`s e comparações na pesquisa binária, mas sem outros cálculos.

 
Maxim Kuznetsov #:

Você pode usar uma matriz pré-calculada para o MN, pois quase não há dados lá.

Ln2(12 meses * cem anos)... 11 if`s e comparações na pesquisa binária, mas sem outros cálculos.

Não há dificuldades. Eu sei como implementá-lo.
Só não quero fazer algo que eu tenha 100% de certeza de que nunca será útil.
 
Maxim Kuznetsov #:

Você pode usar uma matriz pré-calculada para o MN, pois quase não há dados lá.

Ln2(12 meses * cem anos)... 11 if`s e comparações na pesquisa binária, mas sem outros cálculos.

Ah, eu li errado no início.
Não, você está errado. O aumento de desempenho não funcionará. Você ainda ficará preso nos cálculos. E o acesso aos elementos da matriz torna o algoritmo muito mais lento.