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

 
Nikolai Semko:

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

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

 
Alexey Navoykov:

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

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

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

 
ikolai Semko:

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

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

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

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

 
Alexey Navoykov:

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

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

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

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

 

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

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

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

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

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

 
Alexey Navoykov:

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


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

 
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 миллисекунд. И это никак не обойти. 
Но зато фатальных последствий не будет при переходе на зимнее (летнее) время, смене поясов, обновлении времени по интернету. 

Файлы:
 
Nikolai Semko:


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

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

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

 

Вот вариант с использованием 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);
  }
}
Причина обращения: