Индикаторы пропускают тики на Бирже

 

Индикатор показывает сколько тиков пропускает событие Calculate по сравнению с Историей

long GetTime( void )
{
  MqlTick Tick;

  return(SymbolInfoTick(_Symbol, Tick) ? Tick.time_msc : -1);
}

int GetAmountTicks( const ulong From )
{
  MqlTick Ticks[];

  const int Amount = CopyTicks(_Symbol, Ticks, COPY_TICKS_ALL, From);

  int i = -1;

  if ((Amount > 0) && (Ticks[0].time_msc == From) && (Ticks[Amount - 1].time_msc != From))
    for (i = 0; i < Amount; i++)
      if (Ticks[i].time_msc != From)
        break;

  return(i);
}

#define INDICATOR // Переключение между индикатором и экспертом

#ifdef INDICATOR
  #define NAME "Indicator: "

  #property indicator_chart_window
  #property indicator_buffers 0
  #property indicator_plots   0

  int OnCalculate( const int rates_total,
                   const int prev_calculated,
                   const datetime &time[],
                   const double &open[],
                   const double &high[],
                   const double &low[],
                   const double &close[],
                   const long &tick_volume[],
                   const long &volume[],
                   const int &spread[] )
#else
  #define NAME "Expert: "

  void OnTick( void )
#endif
{
  static long PrevTime = 0;
  static int Amount = 0;

  const long NowTime = GetTime();

  if (NowTime > PrevTime)
  {
    if (PrevTime > 0)
    {
      if (Amount > 0)
      {
        const int HistoryAmount = GetAmountTicks(PrevTime);

        if ((HistoryAmount > 0)/* && (Amount != HistoryAmount)*/)
          Print(NAME + "Ticks with time " + (string)((datetime)(PrevTime / 1000)) + ". " + (string)(PrevTime % 1000) +
                ": missing " + (string)(HistoryAmount - Amount) + " (= " + (string)HistoryAmount + " - " + (string)Amount + ").");
      }

      Amount = 1;
    }

    PrevTime = NowTime;
  }
  else if (Amount > 0)
    Amount++;

#ifdef INDICATOR
  return(rates_total);
#endif
}

Результат

2016.09.14 16:35:06.882 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:48. 301: missing 0 (= 1 - 1).
2016.09.14 16:35:06.702 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:48. 83: missing 0 (= 1 - 1).
2016.09.14 16:35:06.236 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:47. 819: missing 0 (= 1 - 1).
2016.09.14 16:35:06.206 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:47. 598: missing -16 (= 1 - 17).
2016.09.14 16:35:05.933 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:47. 486: missing 8 (= 9 - 1).
2016.09.14 16:35:05.478 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:47. 31: missing 0 (= 1 - 1).
2016.09.14 16:35:05.443 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:46. 996: missing 0 (= 1 - 1).
2016.09.14 16:35:05.411 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:46. 989: missing 0 (= 1 - 1).
2016.09.14 16:35:05.381 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:46. 552: missing 0 (= 1 - 1).
2016.09.14 16:35:04.966 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:46. 506: missing 0 (= 1 - 1).
2016.09.14 16:35:04.594 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:46. 165: missing 0 (= 1 - 1).
2016.09.14 16:35:04.557 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:46. 22: missing 0 (= 1 - 1).
2016.09.14 16:35:04.444 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:45. 900: missing -1 (= 1 - 2).
2016.09.14 16:35:04.299 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:45. 855: missing 0 (= 1 - 1).
2016.09.14 16:35:04.254 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:45. 553: missing 0 (= 1 - 1).
2016.09.14 16:35:03.962 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:44. 555: missing 0 (= 1 - 1).
2016.09.14 16:35:02.974 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:43. 904: missing 0 (= 1 - 1).
2016.09.14 16:35:02.304 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:43. 878: missing 0 (= 1 - 1).
2016.09.14 16:35:02.212 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:43. 439: missing 0 (= 1 - 1).
2016.09.14 16:35:01.529 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:43. 104: missing 0 (= 1 - 1).
2016.09.14 16:35:01.399 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:42. 960: missing 0 (= 1 - 1).
2016.09.14 16:35:01.127 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:42. 697: missing 0 (= 1 - 1).
2016.09.14 16:35:00.879 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:42. 455: missing 0 (= 1 - 1).
2016.09.14 16:35:00.697 Test (Si-9.16,M1)       Indicator: Ticks with time 2016.09.14 16:34:42. 270: missing 25 (= 26 - 1).

Тоже самое, конечно, происходит и с экспертами (событие Tick). При этом индикаторы на FOREX не пропускают тики (не поймал), советники - пропускают.

Обратите внимание, что есть ситуации, когда в истории тиков (с точностью до 1мс) записей с одним и тем же временем меньше, чем вызовов индикатора. В данном случае индикатор 17 раз вызывался с тиками одинакового времени, а в истории такой тик только один.

Обнаруженный баг, когда CopyTicks и Event не синхронизированы на последнем тике, учтен. 

 

Советники могут пропускать тики. Об этом явно сказано в документации

Событие NewTick генерируется при поступлении новых котировок и обрабатывается функцией OnTick() у присоединенных советников. Если при поступлении новой котировки выполнялась функция OnTick, запущенная на предыдущей котировке, то пришедшая котировка будет проигнорирована советником, так как соответствующее событие не будет поставлено в очередь событий эксперта.

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

 
Slawa:

Советники могут пропускать тики. Об этом явно сказано в документации

Я плохо акцент сделал по-русски. Исправляюсь
fxsaber:

Тоже самое, конечно, происходит и с экспертами (событие Tick).

 

Индикаторы не должны пропускать тики. С этим мы разберёмся.

У Вас ведь открыта соответствующая заявка в сервис деске

 
Slawa:

Индикаторы не должны пропускать тики. С этим мы разберёмся.

У Вас ведь открыта соответствующая заявка в сервис деске

Да, продуктивно общаемся.

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

Например, тики игрут с огромной частотой. Допустим, каждые 10мс. А OnCalculate выполеняется за 15мс.

Если индикатор не будет пропускать тики, то в таком случае произойдет зависание системы. 

 
1430 - не работает.
 
fxsaber:

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

Например, тики игрут с огромной частотой. Допустим, каждые 10мс. А OnCalculate выполеняется за 15мс.

Если индикатор не будет пропускать тики, то в таком случае произойдет зависание системы. 

Сообщение "indicator is too slow, XXX ms. rewrite the indicator, please" в журнале появляется, когда время расчета превышает жестко-заданный порог или на ходу вычисляемый?

По логике, это сообщение надо выдавать, когда в очереди на выполнение собралось определенное количество тиков с другим временем.

 
fxsaber:

Сообщение "indicator is too slow, XXX ms. rewrite the indicator, please" в журнале появляется, когда время расчета превышает жестко-заданный порог или на ходу вычисляемый?

По логике, это сообщение надо выдавать, когда в очереди на выполнение собралось определенное количество тиков с другим временем.

Скрипт
#property script_show_inputs

sinput int Count = 100000; // Количество тиков на анализ

int GetMaxQueue( const MqlTick &Ticks[], const int ExecutionTime )
{
  int MaxQueue = 0;
  long NextTime = 0;
  const int Amount = ArraySize(Ticks);

  for (int i = 0; i < Amount; i++)
  {
    const long NowTime = Ticks[i].time_msc;
    const int Queue = (int)(NextTime - NowTime);

    if (Queue > 0)
    {
      if (Queue > MaxQueue)
        MaxQueue = Queue;
    }
    else
      NextTime = NowTime;

    NextTime += ExecutionTime;
  }

  return(MaxQueue);
}

void OnStart( void )
{
  MqlTick Ticks[];

  CopyTicks(_Symbol, Ticks, COPY_TICKS_ALL, 0, Count);

  for (int i = 0; i < 100; i++)
    Print("ExecutionTime = " + (string)i + " ms., MaxQueue = " + (string)GetMaxQueue(Ticks, i) + " ms.");
}

Результат
2016.09.20 12:09:19.714 Test (RTS-12.16,M1)     ExecutionTime = 10 ms., MaxQueue = 9778 ms.
2016.09.20 12:09:19.714 Test (RTS-12.16,M1)     ExecutionTime = 9 ms., MaxQueue = 8525 ms.
2016.09.20 12:09:19.714 Test (RTS-12.16,M1)     ExecutionTime = 8 ms., MaxQueue = 7273 ms.
2016.09.20 12:09:19.714 Test (RTS-12.16,M1)     ExecutionTime = 7 ms., MaxQueue = 6040 ms.
2016.09.20 12:09:19.711 Test (RTS-12.16,M1)     ExecutionTime = 6 ms., MaxQueue = 4807 ms.
2016.09.20 12:09:19.711 Test (RTS-12.16,M1)     ExecutionTime = 5 ms., MaxQueue = 3575 ms.
2016.09.20 12:09:19.711 Test (RTS-12.16,M1)     ExecutionTime = 4 ms., MaxQueue = 2361 ms.
2016.09.20 12:09:19.711 Test (RTS-12.16,M1)     ExecutionTime = 3 ms., MaxQueue = 1464 ms.
2016.09.20 12:09:19.711 Test (RTS-12.16,M1)     ExecutionTime = 2 ms., MaxQueue = 820 ms.
2016.09.20 12:09:19.711 Test (RTS-12.16,M1)     ExecutionTime = 1 ms., MaxQueue = 325 ms.
2016.09.20 12:09:19.711 Test (RTS-12.16,M1)     ExecutionTime = 0 ms., MaxQueue = 0 ms.

Подробнее начало графика 


Если индикатор выполняется 1 мс, то он в состоянии лагать на несколько сотен мс. Иногда лагать на 5 секунд он уже будет при исполнении OnCalculate за 6 ms. Ну а если OnCalculate вычисляется аж 50мс, то лаг может превосходить минуту! И размер лага очень сильно зависит от инструмента. Чем больше частота прихода тиков, тем выше лаг индикатора.

Однозначно, ни о каком выполнении индикаторов на каждом тике (типа, индикаторы не должны пропускать тики) и речи быть не может!

 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Тестируем 'CopyTicks'

Slawa, 2016.09.20 09:37

Сначала с CopyTicks до конца разберёмся, чтобы не оставалось вопросов. Без вызова OnCalculate на каждом тике не обойтись пока.

А там будем думать. Возможно вызывать OnCalculate только когда, что-то изменилось в MqlRates - цена, спред или объёмы. Если тик не вызвал изменений, то пересчёт и не вызывать. Думать надо.

Возможно, что ничего с этим менять и не нужно.

 

Представим, что индикатор/советник на каждом тике должен пересчитываться - ну такое обязательное условие, чтобы он мог сосчитать то, что хочет.

Если использовать схему вызова индикатора/советника не на каждом тике, то надо будет тогда получать историю тиков через CopyTicks и пропущенные N-тиков пересчитывать в цикле. Таким образом лаг индикатора/советника никак не изменится от того, как часто наступает событие Tick/Calculate.

Выходит, что все держится исключительно на производительности расчета ОДНОГО тика. И если 1 тик рассчитывается в среднем за 1 мс - то по цифрам видно, что лаг будет не заметен. А что такое 1 мс на обработку? Ну это, наверное, много. Если не использовать файловые операции и других тормозов.

В справке об этом нюансе написать и всего делов. Пущай код свой оптимизируют.

 
fxsaber:

Возможно, что ничего с этим менять и не нужно.

 

Представим, что индикатор/советник на каждом тике должен пересчитываться - ну такое обязательное условие, чтобы он мог сосчитать то, что хочет.

Если использовать схему вызова индикатора/советника не на каждом тике, то надо будет тогда получать историю тиков через CopyTicks и пропущенные N-тиков пересчитывать в цикле. Таким образом лаг индикатора/советника никак не изменится от того, как часто наступает событие Tick/Calculate.

Выходит, что все держится исключительно на производительности расчета ОДНОГО тика. И если 1 тик рассчитывается в среднем за 1 мс - то по цифрам видно, что лаг будет не заметен. А что такое 1 мс на обработку? Ну это, наверное, много. Если не использовать файловые операции и других тормозов.

В справке об этом нюансе написать и всего делов. Пущай код свой оптимизируют.

а как узнать, сколько пропущено тиков?

 
Виктор Астахов:

а как узнать, сколько пропущено тиков?

Посчитать через CopyTicks.

Причина обращения: