Тестер стратегий MetaTrader 5: ошибки, баги, предложения по улучшению работы - страница 34

 
Artyom Trishkin:

Тоже никогда не гляжу на него. Но полезное место занимает...

Однако, пригодилось.

 
Artyom Trishkin:

Тоже никогда не гляжу на него. Но полезное место занимает...

Никого не будет шокировать когда сначала идут сообщения тестера о синхронизации, загрузке эксперта etc с локальным временем, а потом пойдут сообщения от эксперта и тестового торгового сервера с тестовым временем, иногда перемежаясь с сообщениями тестера с локальным временем?
 
Нашел одно из мест, где Тестер можно ускорить. Оказывается, каждый раз, когда Тестер сравнивает две цены (например, BuyLimit и Tick.ask), он это делает через дорогую нормализацию. Не нужно этого делать!
 
Slava:
Никого не будет шокировать когда сначала идут сообщения тестера о синхронизации, загрузке эксперта etc с локальным временем, а потом пойдут сообщения от эксперта и тестового торгового сервера с тестовым временем, иногда перемежаясь с сообщениями тестера с локальным временем?

Слава, сидел обдумывал как лучше организовать сиё. Хотел предложить именно чтобы сначала шли сообщения о времени запуска, синхронизации, etc, а уже далее - остальное - от эксперта и тестера с важными сообщениями.

По моему - это то же самое, что ты предложил :)

 
fxsaber:
Нашел одно из мест, где Тестер можно ускорить. Оказывается, каждый раз, когда Тестер сравнивает две цены (например, BuyLimit и Tick.ask), он это делает через дорогую нормализацию. Не нужно этого делать!

Цены в истории Терминала не нормализованы!

bool IsNorm( const double Price )
{
  return(NormalizeDouble(Price, _Digits) == Price);
}

#define TOSTRING(A) #A + " = " + DoubleToString(A, 16) + " "
#define PRINT(A) Print(TOSTRING(A) + TOSTRING(NormalizeDouble(A, _Digits)))
#define ISNORM(A) if (!IsNorm(A)) { PRINT(A); Count++; };

void OnStart()
{
  MqlTick Ticks[];
  
  const int Size = CopyTicksRange(_Symbol, Ticks, COPY_TICKS_ALL, 1000 * (long)D'2019.12.01');
  Print(Size);
  
  for (int i = 0, Count  = 0; (i < Size) && (Count < 10); i++)
  {
    ISNORM(Ticks[i].bid)
    ISNORM(Ticks[i].ask)
    ISNORM(Ticks[i].last)
  }
}


Результат (EURUSD, MQ-Beta)

Ticks[i].bid = 1.1024100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1024099999999999 
Ticks[i].bid = 1.1024100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1024099999999999 
Ticks[i].bid = 1.1024100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1024099999999999 
Ticks[i].bid = 1.1024100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1024099999999999 
Ticks[i].bid = 1.1023100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1023099999999999 
Ticks[i].bid = 1.1023100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1023099999999999 
Ticks[i].bid = 1.1023100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1023099999999999 
Ticks[i].bid = 1.1023100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1023099999999999 
Ticks[i].bid = 1.1023100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1023099999999999 
Ticks[i].bid = 1.1023100000000001 NormalizeDouble(Ticks[i].bid,_Digits) = 1.1023099999999999 


Это как так получается? Ошибка на стороне торгового сервера?

Как следствие, Тестер гонит советники по кривым ценам даже на реальных символах.


ЗЫ Похоже, проблема в применении разработчиками иного алгоритма нормализации.

 
Andrey Khatimlianskii:

Воспроизвел баг с пустым значением в инпут-параметрах.

1. Собираем советника:

2. Оптимизируем на чем угодно оба параметра:

3. Снимаем галку с энама и оптимизируем только х:

4. Загружаем 1-й кэш оптимизации, потом 2-й, из результатов запускаем одиночный прогон. Вместо -1 получаем INT_MAX:


Актуально для всех enum-ов, начинающихся с -1.

Есть подозрение, когда снимаете галку с t, input полностью отключается
и переменная t содержит неинициализированное значение  INT_MAX, а не пустое.

 
fxsaber:

Цены в истории Терминала не нормализованы!


Результат (EURUSD, MQ-Beta)


Это как так получается? Ошибка на стороне торгового сервера?

Как следствие, Тестер гонит советники по кривым ценам даже на реальных символах.


ЗЫ Похоже, проблема в применении разработчиками иного алгоритма нормализации.

Это - не кривые цены! Вполне себе нормализованные. Это очень хорошо видно из вашего принта

В торговом сервере при торговых операциях всегда используется эпсилон для сравнения пришедшей цены и текущей цены.

Вы в курсе, что результат <some_real_number>*0.5 может отличаться от результата <the_same_real_number>/2.0?

Вы в курсе, что некоторые компиляторы при оптимизации кода могут заменить одну операцию на другую? При чём, в одном случае заменить, а в другом случае - нет, в пределах одного проекта. Без объявления войны.

 
Roman:

Есть подозрение, когда снимаете галку с t, input полностью отключается
и переменная t содержит неинициализированное значение  INT_MAX, а не пустое.

Какая там внутри причина — не важно.

Важно, чтобы воспроизвели и исправили. Баг давний.

 
Slava:

Это - не кривые цены! Вполне себе нормализованные. Это очень хорошо видно из вашего принта

Цена является нормализованной только в том случае, если проходит это условие.

В торговом сервере при торговых операциях всегда используется эпсилон для сравнения пришедшей цены и текущей цены.

Это правильно, что торговый сервер делает именно так.

Вы в курсе, что результат <some_real_number>*0.5 может отличаться от результата <the_same_real_number>/2.0?

Вы в курсе, что некоторые компиляторы при оптимизации кода могут заменить одну операцию на другую? При чём, в одном случае заменить, а в другом случае - нет, в пределах одного проекта. Без объявления войны.

На оба вопрос ответ утвердительный - в курсе.


Еще раз, исходные цены в Терминале не нормализованы. Отсюда легко возникает эта ситуация.

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

Ненормализованные цены в MT4

fxsaber, 2019.02.20 23:03

А вот ситуация гораздо хуже, и при этом на MQ-Demo
// 15326434
// wmefo5sa
// MetaQuotes-Demo
void OnStart()
{
  const double Price1 = HistoryOrderSelect(356138100) ? HistoryOrderGetDouble(HistoryOrderGetTicket(0), ORDER_PRICE_CURRENT) : 0;
  const double Price2 = PositionSelectByTicket(356138100) ? PositionGetDouble(POSITION_PRICE_OPEN) : 0;  
  
  Print(Price1 - Price2); // -2.220446049250313e-16
}


Цена открытия текущей позиции не равна цене своих ордера/сделки.

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