Особенности языка mql5, тонкости и приёмы работы - страница 89

Alexey Navoykov
4474
Alexey Navoykov  
Nikolai Semko:

  1. см. мое предыдущее сообщение
  2. У меня масса примеров с практической пользой от микросекунд.

Пока вижу только один упомянутый недостаток GetTickCount - то что он ограничен разрешающей способностью системного таймера, это да, серьёзная проблема.   А остальное - не имеет особой практической пользы.  То что вы проводите ультра-короткие тесты длительностью в 15 миллисекунд - так никто не делает.  Такие результаты нестабильны.     Нужно чтоб хотя бы полсекунды длился тест, тогда уже можно о чём-то говорить.

Nikolai Semko
5196
Nikolai Semko  
Alexey Navoykov:

 То что вы проводите ультра-короткие тесты длительностью в 15 миллисекунд - так никто не делает.  Такие результаты нестабильны.     Нужно чтоб хотя бы полсекунды длился тест, тогда уже можно о чём-то говорить.

Ошибаетесь. За эти 15 миллисекунд функция GetTickCount() вызывается более 6 000 000 раз.

Мой расчет верен. Смена значения GetTickCount() каждые 1/(2^6)=1/64 секунды (15625 микросекунды).
Разработчики, подтвердите пожалуйста.

Alexey Navoykov
4474
Alexey Navoykov  
ikolai Semko:

Ошибаетесь. За эти 15 миллисекунд функция GetTickCount() вызывается более 6 000 000 раз.

Когда замеряется производительность рабочего кода (а не сферического коня в вакууме), то он гоняется на достаточном промежутке времени (сотни миллисекунд и выше).  Это обусловлено тем, что производительность и загруженность системы постоянно меняется.  В один миг она одна, а в другой - уже другая.  И на коротких интервалах результаты будут сильно разниться от теста к тесту.   Поэтому необходим более длительный интервал, а там микросекунды уже не играют роли.

Далее.  Котировки у нас в миллисекундах.   Пинги тоже исчисляются в миллисекундах.  Поэтому куда тут присунуть микросекунды - я пока не вижу.  Впрочем это не суть. 

Сейчас нужно придумывать решение, как выкручиваться из ситуации, чтобы обойти недостатки обоих функций.   На разработчиков надежды мало.

Nikolai Semko
5196
Nikolai Semko  
Alexey Navoykov:

Сейчас нужно придумывать решение, как выкручиваться из ситуации, чтобы обойти недостатки обоих функций.   На разработчиков надежды мало.

я думаю это возможно с помощью типа такой формулы в первом приближении:

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

Пока это просто мысль вслух.

fxsaber
15397
fxsaber  

Некоторые места, где использую микросекунды

  • кастомный TimeCurrent, с примерной точностью до мс.
  • Вычисление времени выполнения торгового приказа.
  • Вычисление времени синхронизации торговой истории в Терминале.
  • Лаг Терминала (~ 5 мс) - на сколько тик устарел к моменту его OnTick/OnCalculate.
  • Корректировка OnTimer, чтобы расстояние между любыми (не только соседними) Time-событиями было кратно заданному времени.
Alexey Navoykov
4474
Alexey Navoykov  
fxsaber:

Некоторые места, где использую микросекунды

  • Корректировка OnTimer, чтобы расстояние между любыми (не только соседними) Time-событиями было кратно заданному времени.

Так таймер же, во-первых, миллисекундный.  Во-вторых, его погрешность такая же, как и GetTickCount(), т.е. 15 миллисекунд.   Поэтому какой смысл тут от микросекунд - не очень понятно.    Допустим вычислили вы интервал с точностью до микро, а по факту оно придёт на несколько МИЛЛИсекунд позже или раньше.

Vladislav Andruschenko
141823
Vladislav Andruschenko  
Alexey Navoykov:

Так таймер же, во-первых, миллисекундный.  Во-вторых, его погрешность такая же, как и GetTickCount(), т.е. 15 миллисекунд.   Поэтому какой смысл тут от микросекунд - не очень понятно.    Допустим вычислили вы интервал с точностью до микро, а по факту оно придёт на несколько МИЛЛИсекунд позже или раньше.


а еще команды становятся в очередь и выполнение по очереди может быть и через 5 секунд.. 

Nikolai Semko
5196
Nikolai Semko  
Alexey Navoykov:

Сейчас нужно придумывать решение, как выкручиваться из ситуации, чтобы обойти недостатки обоих функций.   На разработчиков надежды мало.


Увы. 
могу предложить лишь такой вариант функции:

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);
  }

Почему Увы?
Потому что в случае изменения локального времени или просто программного подвисания в функцию RealMicrosecondCount может добавляться погрешность до 16 миллисекунд. И это никак не обойти. 
Но зато фатальных последствий не будет при переходе на зимнее (летнее) время, смене поясов, обновлении времени по интернету. 

Файлы:
Alexey Navoykov
4474
Alexey Navoykov  
Nikolai Semko:


Увы. 
могу предложить лишь такой вариант функции:

Почему Увы?
Потому что в случае изменения локального времени или просто программного подвисания в функцию RealMicrosecondCount может добавляться погрешность до 16 миллисекунд. И это никак не обойти. 
Но зато фатальных последствий не будет при переходе на зимнее (летнее) время, смене поясов, обновлении времени по интернету. 

Пока не проверял, но вот насчёт 16 мс не очень уверен.  Когда я гуглил по этой теме, обычно приводится погрешность системного таймера около 10 мс, либо 10-16.

Alexey Navoykov
4474
Alexey Navoykov  

Вот вариант с использованием winapi-таймера высокого разрешения, дающего точность 3.8e-07 секунды.

#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);
  }
}