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

 
Nikolai Semko:

  1. ver o meu post anterior
  2. Eu tenho muitos exemplos com benefícios práticos de microssegundos.

Até agora, vejo apenas uma desvantagem mencionada do GetTickCount - o facto de estar limitado pela resolução do temporizador do sistema, é um problema sério. E o resto não tem qualquer utilidade prática particular.O que você está fazendo são testes ultra curtos de 15 milissegundos - ninguém faz isso. Tais resultados são instáveis. Você precisa fazer o teste durar pelo menos meio segundo e então você pode dizer algo sobre isso.

 
Alexey Navoykov:

Ninguém faz testes ultra-curtos de 15 milissegundos. Esses resultados são instáveis. Você precisa de pelo menos meio segundo para que o teste dure, então você pode falar sobre algo.

Estás enganado. Durante estes 15 milisegundos, a função GetTickCount() é chamada mais de 6 000 000 de vezes.

Os meus cálculos estão correctos. O valor GetTickCount() muda a cada 1/(2^6)=1/64 segundos (15625 microssegundos).
Desenvolvedores, por favor, confirmem.

 
ikolai Semko:

Errado.A função GetTickCount() é chamada mais de 6 000 000 de vezesnesses 15 milissegundos.

Quando medimos o desempenho de um código de trabalho (não um cavalo esférico no vácuo), ele é executado por um intervalo de tempo suficiente (centenas de milissegundos ou mais). A razão é que o desempenho e a carga de trabalho do sistema estão em constante mudança. Um momento é um, enquanto o momento seguinte é diferente. Assim, os resultados variam muito de teste para teste em intervalos curtos. É por isso que precisamos de um intervalo mais longo, mas os microssegundos já não importam lá.

Além disso, temos citações em milissegundos e os pings também estão em milissegundos, por isso não consigo ver onde devem ser colocados os microssegundos. De qualquer forma, não é essa a questão.

Agora tenho que inventar uma solução, como sair desta situação para evitar desvantagens de ambas as funções. Não há muita esperança para os desenvolvedores.

 
Alexey Navoykov:

Agora temos que descobrir como contornar as deficiências de ambas as funções. Não há muita esperança para os desenvolvedores.

Acho que é possível com uma fórmula como esta à primeira aproximação:

ulong RealGetMicrosecondCount=(GetTickCount()-StartGetTickCount)*1000+x+GetMicrosecondCount()%15625;

Até agora, é só uma ideia em voz alta.

 

Alguns lugares onde eu uso microssegundos

  • TimeCurrent personalizado, com precisão aproximada a msec.
  • Cálculo do tempo de execução da ordem de negociação.
  • Cálculo do tempo de sincronização do histórico de negociação no Terminal.
  • Atraso do terminal (~ 5 ms) - por quanto o tick está desatualizado na hora do seu OnTick/OnCalculate.
  • Correção do OnTimer para que a distância entre quaisquer eventos temporais (não apenas vizinhos) seja um múltiplo do tempo especificado.
 
fxsaber:

Alguns lugares onde eu uso microssegundos

  • Ajuste do OnTimer para que a distância entre quaisquer eventos de tempo (não apenas adjacentes) seja um múltiplo do tempo dado.

Em segundo lugar, seu erro é o mesmo que no GetTickCount(), ou seja, 15 milisegundos. É por isso que o significado de microssegundos não é muito claro. Suponha que você tenha calculado um intervalo preciso para micro, mas na verdade ele virá vários MILHÕES de segundos mais tarde ou mais cedo.

 
Alexey Navoykov:

Em segundo lugar, seu erro é o mesmo que GetTickCount(), ou seja, 15 milisegundos, então o que é o ponto de microssegundos aqui não é muito claro. Suponha que você calcule o intervalo com micro precisão, mas na verdade ele virá vários MILHÕES de segundos mais tarde ou mais cedo.


Também os comandos ficam em fila de espera e a execução pode ser em 5 segundos.

 
Alexey Navoykov:

Agora temos que descobrir como contornar as deficiências de ambas as funções. Não há muita esperança para os desenvolvedores.


Infelizmente.
Só lhe posso oferecer esta variante da função:

ulong RealMicrosecondCount()
  {
   static bool first=true;
   static ulong sum=0;
   static long delta;
   static long shift=0;
   static ulong  lasttickcount;
   ulong i=GetTickCount()+sum;
   ulong t=GetMicrosecondCount();
   if(first) // если первый вход, то вычисляем разницу GetMicrosecondCount и GetTickCount
     {
      lasttickcount=i;
      delta=((long)i*1000-long(t));
      first=false;
     }
   long curdelta=((long)i*1000-long(t));
   long d=curdelta-delta;
   if(fabs(d-shift)>20000) shift=d;
   if(i<lasttickcount) sum+=0x100000000;
   lasttickcount=i;
   return (t+shift);
  }

Porquê, infelizmente?
Porque se você mudar a hora local ou apenas tiver um programa desligado, um erro de até 16 milissegundos pode ser adicionado à funçãoRealMicrosecondCount. Não há como evitá-lo.
Mas não haverá consequências fatais ao mudar para a hora de Verão, mudança de fuso horário, actualização da hora através da Internet.

Arquivos anexados:
 
Nikolai Semko:


Infelizmente,
só pode oferecer esta versão da função:

Porquê, infelizmente?
Porque em caso de mudança de hora local ou apenas desligar o software, um erro de até 16 milissegundos pode ser adicionado à funçãoRealMicrosecondCount. Não há como contornar isso.
Mas não haverá consequências fatais ao mudar para a hora de Verão, mudança de fuso horário, actualização da hora via Internet.

Ainda não verificado, mas não tenho tanta certeza sobre 16 ms. Quando pesquisei o assunto no Google, geralmente o erro do temporizador do sistema é dado como cerca de 10 ms, ou 10-16 ms.

 

Aqui está uma variante que utiliza um timer winapi de alta resolução, dando uma precisão de3,8e-07 segundos.

#import "Kernel32.dll"
  int QueryPerformanceCounter(ulong &lpPerformanceCount);
  int QueryPerformanceFrequency(ulong &lpFrequency);
#import


ulong QueryPerfomanceCounter() { ulong value;  if (QueryPerformanceCounter(value)) return value;  return 0; } 

ulong QueryPerformanceFrequency() { ulong freq;  if (QueryPerformanceFrequency(freq)) return freq;  return 0; }  


long GetPerfomanceCount_mcs()
{ 
  static long freq= QueryPerformanceFrequency();
  return freq ? QueryPerfomanceCounter()*1000000/freq : 0;
}


void OnStart()
{
  Print("Resolution of perfomance counter:  ",1.0/QueryPerformanceFrequency()," s");
  ulong  perfcount= GetPerfomanceCount_mcs(); 
  
  while(!IsStopped())
  {
    Comment((GetPerfomanceCount_mcs()-perfcount)/1000000.0);
    Sleep(10);
  }
}
Razão: