Новая версия платформы MetaTrader 5 build 5660: улучшения и исправления - страница 10

 
fxsaber #:

На каждом, конечно.

Весьма категоричное утверждение.

Давайте поставим экскремент.

Запускаем советник в тестере в режиме реальных тиков.

void OnTick()
  {
   static int TickVolume = 0; // Тиковый объем текущего бара.
   static datetime NextTime = 0;
   static double PrevPrice;

   const datetime CurrTime = TimeCurrent();

// Если следующий бар.
   if(CurrTime >= NextTime)
     {
      NextTime = (CurrTime / PeriodSeconds(PERIOD_CURRENT) + 1) * PeriodSeconds(PERIOD_CURRENT);
      Print(TickVolume);
      TickVolume = 0;
      PrevPrice = 0;
     }

   MqlRates Rates[];
   MqlTick Tick;

   if(SymbolInfoTick(_Symbol, Tick) && (Tick.bid != PrevPrice))
      TickVolume++;

   //Sleep(1000);
  }

Получаем такой результат


Теперь раскомментируем Sleep(1000); и снова запустим.


Разница есть.

Это говорит о том, что далеко не всегда OnTick() вызывается на каждом тике.

ЗЫ. Понимаю, это другое. Не настаиваю, просто ради истины.

 
Aleksandr Slavskii #:

Это говорит о том, что далеко не всегда OnTick() вызывается на каждом тике.

ЗЫ. Понимаю, это другое. Не настаиваю, просто ради истины.

Ну сами ответили. Занудства ради - не на каждом. Если Sleep сделать длинною в месяц, то раз в месяц.
 
b5686, на нулевом баре в режиме Тестера по реальным тикам происходит заглядывание в будущее: становится известно, какой БУДЕТ минимальный спред.
void OnTick()
{
  static datetime NextTime = 0;
  
  const datetime CurrTime = TimeCurrent();
  
  // Если следующий бар.
  if (CurrTime >= NextTime)
  {
    NextTime = (CurrTime / PeriodSeconds(PERIOD_CURRENT) + 1) * PeriodSeconds(PERIOD_CURRENT);

    MqlRates Rates[1];

    if ((CopyRates(_Symbol, PERIOD_CURRENT, 0, 1, Rates) > 0) && (Rates[0].spread != SymbolInfoInteger(_Symbol, SYMBOL_SPREAD))    )
    {
    #define PRINT(A) Print(#A + "= " + (string)(A))
      PRINT(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD));
      
      ArrayPrint(Rates);
      
      DebugBreak();
    }
  }
}


2026.01.02 01:00:02   SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)= 50
2026.01.02 01:00:02                    [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume]
2026.01.02 01:00:02   [0] 2026.01.02 01:00:00 4327.84 4327.84 4327.84 4327.84             1        8             0

Строка для поискаOshibka 167.

 
fxsaber #:

Как объяснить такую дикую разницу в производительности? Предполагаю, что иногда Агент подключается к частично загруженному (другими фоновыми задачами) CPU-ядру, а иногда - к свободному. Есть способ всегда заставлять Агент одиночного прохода выполняться на свободном CPU-ядре? Уж больно огромна разница в производительности.

Агент вроде бы привязан к конкретному ядру. Я поэтому обычно использую не первого агента (который занят ОС обычно).
 
Andrey Khatimlianskii #:
Агент вроде бы привязан к конкретному ядру. Я поэтому обычно использую не первого агента (который занят ОС обычно).
Где-то выкладывал, как смочь отключить первый агент. Но забыл уже.
 

b5686, в режиме Тестера по реальным тикам нулевой бар может не соответствовать пришедшему тику.

void OnTick()
{
  static datetime NextTime = 0;
  
  const datetime CurrTime = TimeCurrent();
  
  // Если время следующего бара.
  if (CurrTime >= NextTime)
  {
    MqlRates Rates[1];

    if ((CopyRates(_Symbol, PERIOD_CURRENT, 0, 1, Rates) > 0) && // Запрашиваем нулевой бар.
         (Rates[0].time < NextTime))                             // Если новый бар не сформировался.
    {
    #define PRINT(A) Print(#A + "= " + (string)(A))
      PRINT(TimeCurrent());
      
      ArrayPrint(Rates);
      
      DebugBreak();
    }
    
    NextTime = (CurrTime / PeriodSeconds(PERIOD_CURRENT) + 1) * PeriodSeconds(PERIOD_CURRENT);    
  }
}


2026.01.02 01:04:00   TimeCurrent()= 2026.01.02 01:04:00
2026.01.02 01:04:00                    [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume]
2026.01.02 01:04:00   [0] 2026.01.02 01:03:00 4330.88 4330.88 4326.41 4326.63           122        8             0


Чтобы не было расхождений баровой истории и тиковой, тестировал и на кастомных символах. Поведение повторяется.

Строка для поискаOshibka 168.

 
fxsaber #:

b5686, в режиме Тестера по реальным тикам нулевой бар может не соответствовать пришедшему тику.

Это вроде всегда так потенциально могло случаться, потому что бары могут не успевать моментально строиться по тикам.
 
Stanislav Korotky #:
Это вроде всегда так потенциально могло случаться, потому что бары могут не успевать моментально строиться по тикам.
В Тестере?
 
fxsaber #:
b5686, на нулевом баре в режиме Тестера по реальным тикам происходит заглядывание в будущее: становится известно, какой БУДЕТ минимальный спред.


Строка для поискаOshibka 167.

Это - спред, оставшийся от бара, предшествующего нулевому. Почему бы не распечатать информацию сразу по двум барам?

Тестер не заглядывает в будущее

 
Slava #:

Это - спред, оставшийся от бара, предшествующего нулевому. Почему бы не распечатать информацию сразу по двум барам?

Первый тик одиночного прохода.

Скрин показывает, что Ваше утверждение ошибочно.


Теперь смотрим баровую историю на наличие места, где спред бара меняется. Подгоняем Визуализатор (PAUSE+F12) до первого тика этого бара.

Снова скрин показывает, что Ваше утверждение ошибочно.


Тестер не заглядывает в будущее

По ходу выяснил, что спред бара вообще не меняется по ходу формирования этого бара, а просто берется из истории баров, что является заглядыванием в будущее.