Библиотеки: MT4Orders - страница 82

 

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

Билд 3802, __MT4ORDERS__ "2022.07.20" 

Условная функция, вызываемая в эксперте на каждом тике. Тест в тестере стратегий мт5.  

	datetime get_last_order_close_time () {
                datetime last_close_time=0;

                for ( int i = OrdersHistoryTotal() - 1; i >= 0; i-- ) {
                        if ( !OrderSelect ( i, SELECT_BY_POS, MODE_HISTORY )) {
                                continue;
                        }
         		last_close_time=OrderCloseTime();
		        return last_close_time;
                }

                return last_close_time;
        }

Количество сделок в районе 26 тысяч. Время теста  около 1 часа 10 минут.

Убираем функцию из кода, время теста стало около 17 минут.

Переписываю эту же функцию с использованием функционала МТ5:

	datetime get_last_order_close_timeMT5 () {
                datetime last_close_time=0;
                HistorySelect(0,TimeCurrent()); 

                for ( int i = HistoryDealsTotal() - 1; i >= 0; i-- ) {
                        
                        ulong ticket=HistoryDealGetTicket(i);
                        
                        if((ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY)==DEAL_ENTRY_OUT)
                        {
                           last_close_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
                           return last_close_time;
                        }                       
                }

                return last_close_time;
        }

Время теста в районе 18 минут.

Откатываю библиотеку до версии  __MT4ORDERS__ "2020.01.12" и компилю эксперта  в билде 2980.

Время работы эксперта с функцией get_last_order_close_time  - в районе 20 минут.

 
elavr #:

Не могу понять, можно ли решить эту проблему со скоростью тестирования, не используя функции языка MT5.

Во всех трех случаях конечный результат совпадает?
 
fxsaber #:
Во всех трех случаях конечный результат совпадает?

Да, конечно.

Это стало происходить после очередного обновления имено терминала. Вашу библиотеку я не менял, и чтобы все работало как раньше компилировал бота в старом терминале. 

 
elavr #:

Это стало происходить после очередного обновления имено терминала. Вашу библиотеку я не менял, и чтобы все работало как раньше компилировал бота в старом терминале. 

Сделал исследование.


Советник.

#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006

#define VIRTUAL_SNAPSHOT_REFRESHTIME 1000
#include <fxsaber\Virtual\Virtual.mqh> // https://www.mql5.com/ru/code/22577

input int inMod = 5;
input int inRange = 0;
input bool inVirtual = false;

const bool Init = inVirtual ? VIRTUAL::SelectByHandle(VIRTUAL::Create()) : false;;

#define Bid SymbolInfoDouble(_Symbol, SYMBOL_BID)
#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

ulong lOnTester = 0;

void OnTick()
{  
  static int i = 0;
  
  VIRTUAL::NewTick();
  
  if (!(i++ % inMod))
    OrderClose(OrderSend(_Symbol, OP_BUY, 0.1, Ask, 0, 0, 0), 0.1, Bid, 0);
    
//  VIRTUAL::Snapshot();  
  lOnTester += LastCloseTimeMQL4() % 100;
  
//  lOnTester += LastCloseTimeMQL5() % 100;
}

double OnTester()
{
  if (HistorySelect(0, INT_MAX))
    Print(HistoryDealsTotal());
  
  return((double)lOnTester);
}

На каждом inMod-тике открывается и закрывается позиция. И на каждом тике вычисляется OrderCloseTime.

OnTester служит критерием проверки идентичности результатов при разных конфигурациях.


Соответствующие функции работы с историей.

datetime LastCloseTimeMQL4()
{  
  datetime Res = 0;
  
  for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderType() <= OP_SELL))
    {
      Res = OrderCloseTime();
      
      break;
    }

  return(Res);
}

datetime LastCloseTimeMQL5()
{
  datetime Res = 0;
  
  if (HistorySelect(0, INT_MAX))
    for (int i = HistoryDealsTotal() - 1; i >= 0; i--)
    {
      const ulong Ticket = HistoryDealGetTicket(i);
      
      if (HistoryDealGetInteger(Ticket, DEAL_ENTRY) != DEAL_ENTRY_IN)
      {
        Res = (datetime)HistoryDealGetInteger(Ticket, DEAL_TIME);
        
        break;
      }
    }
    
  return(Res);
}

#define MACROS(A, B)          \
  datetime A##_2()            \
  {                           \
    static datetime Res = 0;  \
    static int PrevTotal = 0; \
                              \
    const int Total = B;      \
                              \
    if (PrevTotal != Total)   \
    {                         \
      Res = A();              \
                              \
      PrevTotal = Total;      \
    }                         \
                              \
    return(Res);              \
  }

// LastCloseTimeMQL4_2
MACROS(LastCloseTimeMQL4, OrdersHistoryTotal())

// LastCloseTimeMQL5_2
MACROS(LastCloseTimeMQL5, HistorySelect(0, INT_MAX) ? HistoryDealsTotal() : 0)


Методика.

Одиночный запуск на настройках, как в исходнике (inMod = 5).

2023.07.06 23:59:59   28179
final balance 99996992.20 pips
OnTester result 2761115
EURUSD,M1: 274413 ticks, 70443 bars generated. Environment synchronized in 0:00:00.021. Test passed in 0:00:03.712 (including ticks preprocessing 0:00:00.031).

28K сделок, почти четыре секунды. Поскольку замерять производительность нужно в режиме оптимизации, то все следующие показания производительности делались так.

shortest pass 0:00:02.875, longest pass 0:00:03.094, average pass 0:00:02.919

С обязательной перекомпиляцией перед запуском и включенным только одним Агентом для последовательного выполнения проходов.


Производительность.

Таблица производительности (время выполнения в миллисекундах) для b3815 и b2958.

MT5 build LastCloseTimeMQL4 LastCloseTimeMQL5 LastCloseTimeMQL4_2 LastCloseTimeMQL4+VIRTUAL::Snapshot LastCloseTimeMQL4+VirtualTester
b3815 2875 113 708 732 45
b2958 2718 107 675 715 50

Везде использовалась MT4Orders от 20.07.2022.


Выводы.

  • Тормозит OrderSelect. Связано с тем, что при OrderSelect идет вычисление абсолютно всех данных выбранного ордера из истории (OrderPrint - бесплатный). Это большая комбинация HistoryOrderGet* и HistoryDealGet* функций, с обработкой любой сложности рыночных ситуаций и большого количества подводных камней. Посмотрите MT4ORDERS::GetHistoryPositionData(). Это единая функция для Терминала и для Тестера, но при этом для Тестера специально сделаны ускорения, т.к. многих подводных камней Терминала в Тестере нет. Примеры конфигураций: один, два, три.
  • Соответственно, нужно добиваться уменьшения вызовов OrderSelect для исторических ордеров. Этого можно добиться способами, что указаны в правых трех столбцах таблицы.
  • Самая быстрая работа (опережает чистый MQL5) - торговля в виртуальном окружении. Рекомендовал бы оптимизацию делать в виртуальном окружении, а одиночные проходы - вне его.
  • Производительность Тестера b2958 и b3815 почти идентична.
  • Не рекомендую логику ТС для Тестера завязывать на историю торговли с обращением к ней. Например, OrderCloseTime своей ТС можно знать без обращения к истории.
 
elavr #:

Время теста  около 1 часа 10 минут.

Откатываю библиотеку до версии  __MT4ORDERS__ "2020.01.12" и компилю эксперта  в билде 2980.

Время работы эксперта с функцией get_last_order_close_time  - в районе 20 минут.

Попробуйте код выше на старой версии библиотеки (у меня ее нет).

Если будет отличие в производительности, пришлите в ЛС.

 
Спасибо огромное! Посмотрю на следующей неделе!
 

Возможно ли, что происходит утечка памяти или использование памяти больше, чем нужно? Может быть, в this.tickets или в this.amount (::ArrayResize) или где-то еще?

Размер массивов только увеличивается со временем. Является ли это обязательным условием? Можно ли их очистить или, возможно, не загружать все предыдущие сделки?

 
pcdeni #:

Возможно ли, что происходит утечка памяти или использование памяти больше, чем нужно? Может быть, в this.tickets или в this.amount (::ArrayResize) или где-то еще?

Размер массивов только увеличивается со временем. Является ли это обязательным условием? Можно ли их очистить или, возможно, не загружать все предыдущие сделки?

Библиотека не полностью кэширует исторические данные. Получить нехватку памяти можно только в теории, но не на практике.

Напишите скрипт, который просматривает всю торговую историю с помощью библиотеки, и посмотрите, сколько памяти потребляется.

 
fxsaber #:

Библиотека не полностью кэширует исторические данные. Получить нехватку памяти можно только в теории, но не на практике.

Напишите скрипт, который сортирует всю историю торговли с помощью библиотеки, и посмотрите, сколько памяти при этом расходуется.

При тестировании стратегии ea использует 25 ГБ на ядро.

Редактировать: это тест на таймфрейме 1 год, так что не так уж и много.
 
pcdeni #:

при тестировании стратегии ea использует 25 Гб на ядро.

Редактировать: это тест на таймфрейме 1 год, так что не так уж и много.

Библиотека (MT4Orders.mqh) не потребляет такое количество памяти. Вы можете запустить, например, этот советник, чтобы убедиться в этом.

Скорее всего, вы неправильно работаете с индикаторами: создаете новые хэндлы индикаторов, но не удаляете старые.