Непонятки с CHashMap из стандартной библиотеки - страница 4

 
Alexey Volchanskiy:

Артем, так у меня голый файл из статьи https://www.mql5.com/ru/articles/1334#summary не компилируется под МТ4, под МТ5 все ок.

Глянь - мож получится:
Любые вопросы новичков по MQL4, помощь и обсуждение по алгоритмам и кодам
Любые вопросы новичков по MQL4, помощь и обсуждение по алгоритмам и кодам
  • 2018.02.22
  • www.mql5.com
В этой ветке я хочу начать свою помощь тем, кто действительно хочет разобраться и научиться программированию на новом MQL4 и желает легко перейти н...
 
Alexey Volchanskiy:

Зашибись! По какому-то наитию решил попробовать скомпилировать код из предыдущего поста под редактором из МТ5.

'TestUnion.mq4' TestUnion.mq4 1 1

0 error(s), 0 warning(s), compile time: 401 msec 1 1

!!!!!!!! И после этого они говорят, что компилятор МТ4 одинаковый в МТ4 и МТ5!!

Сейчас попробую и остальное там скомпилить

CDictionary в режиме MQL4 компилируется без ошибок и варнингов. 

И тест тоже работает. Пипец, это значит, метаквоты вообще забили на МТ4, даже такие грубейшие ошибки не правят и не тестируют...Печально. Пишу в СД.

 
Alexey Volchanskiy:

CDictionary в режиме MQL4 компилируется без ошибок и варнингов. 

И тест тоже работает. Пипец, это значит, метаквоты вообще забили на МТ4, даже такие грубейшие ошибки не правят и не тестируют...Печально. Пишу в СД.

Мой прошлый пост видел?

 
Alexey Volchanskiy:

CDictionary в режиме MQL4 компилируется без ошибок и варнингов. 

И тест тоже работает. Пипец, это значит, метаквоты вообще забили на МТ4, даже такие грубейшие ошибки не правят и не тестируют...Печально. Пишу в СД.

Это же так просто - посмотреть номер билда и сопоставить с датой релиза, где была добавлена поддержка union -  Новая версия платформы MetaTrader 5 build 1640: создание и тестирование собственных финансовых инструментов


 
Rashid Umarov:

Это же так просто - посмотреть номер билда и сопоставить с датой релиза, где была добавлена поддержка union -  Новая версия платформы MetaTrader 5 build 1640: создание и тестирование собственных финансовых инструментов


Рашид, у меня почему-то МТ4 обновил терминал до последнего билда 1090, а вот редактор остался на 1061, который не понимает union. Я уже это нашел, просто написать не успел. Заменил на 1601, теперь все компилирует нормально.

 

И проверяем напоследок замечание Василия, что надо задавать емкость хеш-таблицы. Замечание верное, сильно влияет на скорость заполнения, что и понятно.

Без инициализации емкости

2018.02.22 23:08:01.702 TestHashTable (EURUSD,M5) Время добавления 10000000 элементов = 3.0796 сек,  0.3080  мкс/объект

2018.02.22 23:08:02.509 TestHashTable (EURUSD,M5) Время поиска 10000000 элементов = 0.8074 сек,  0.0807  мкс/объект

2018.02.22 23:08:03.061 TestHashTable (EURUSD,M5) Время удаления 10000000 элементов = 0.5512 сек,  0.0551  мкс/объект

2018.02.22 23:08:03.184 TestHashTable (EURUSD,M5) CheckDictVS()

2018.02.22 23:08:17.076 TestHashTable (EURUSD,M5) Время добавления 10000000 элементов = 13.8917 сек,  1.3892  мкс/объект

2018.02.22 23:08:21.074 TestHashTable (EURUSD,M5) Время поиска 10000000 элементов = 3.9984 сек,  0.3998  мкс/объект

2018.02.22 23:08:32.831 TestHashTable (EURUSD,M5) Время удаления 10000000 элементов = 11.7564 сек,  1.1756  мкс/объект

С инициализацией емкости

2018.02.22 23:09:46.894 TestHashTable (EURUSD,M5) CheckHashMap()

2018.02.22 23:09:47.617 TestHashTable (EURUSD,M5) Время добавления 10000000 элементов = 0.4631 сек,  0.0463  мкс/объект

2018.02.22 23:09:48.421 TestHashTable (EURUSD,M5) Время поиска 10000000 элементов = 0.8038 сек,  0.0804  мкс/объект

2018.02.22 23:09:48.996 TestHashTable (EURUSD,M5) Время удаления 10000000 элементов = 0.5754 сек,  0.0575  мкс/объект

2018.02.22 23:09:49.097 TestHashTable (EURUSD,M5) CheckDictVS()

2018.02.22 23:09:56.863 TestHashTable (EURUSD,M5) Время добавления 10000000 элементов = 7.6860 сек,  0.7686  мкс/объект

2018.02.22 23:10:01.175 TestHashTable (EURUSD,M5) Время поиска 10000000 элементов = 4.3118 сек,  0.4312  мкс/объект

2018.02.22 23:10:12.864 TestHashTable (EURUSD,M5) Время удаления 10000000 элементов = 11.6895 сек,  1.1690  мкс/объект


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

Да, посмотри конечно. Но пока буду твой класс использовать, так как нужен перебор. Сейчас вообще CList использую для хранения ордеров, надо что-то пошустрее и удобнее.

Покопаюсь в CHashMap, может там можно вынуть перебор наружу.

 
Alexey Volchanskiy:

Да, посмотри конечно. Но пока буду твой класс использовать, так как нужен перебор. Сейчас вообще CList использую для хранения ордеров, надо что-то пошустрее и удобнее.

Просьба поделиться потом своими изысканиями в этой области. Пример, как делал

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

Библиотека Generic классов - ошибки, описание, вопросы, особенности использования и предложения

fxsaber, 2017.12.08 22:46

Решил посмотреть скоростные характеристики предложенного решения. Советник для тестера

#include <MT4Orders.mqh>
#include <Generic\HashMap.mqh>

CHashMap<ulong, double> DealsProfit;

// Создаем историю из Amount сделок в тестере
void CreateHistory( const int Amount, const double Lots = 0.1 )
{
  MqlTick Tick;
  
  if (SymbolInfoTick(_Symbol, Tick) && Tick.ask && Tick.bid)
    for (int i = (Amount >> 1) - 1; i >= 0; i--)
      OrderClose(OrderSend(_Symbol, OP_BUY, Lots, Tick.ask, 0, 0, 0), Lots, Tick.bid, 0);
}

// Заполняем массив случайно выбранными сделками
void GetDeals( const int Amount, const int MaxDealTicket, ulong &Deals[] )
{
  for (int i = ArrayResize(Deals, Amount) - 1; i >= 0; i--)  
    Deals[i] = MathRand() * MaxDealTicket / SHORT_MAX;
}

// Заполнили HashMap
void SetHashMap()
{
  if (HistorySelect(0, INT_MAX))
    for (int i = HistoryDealsTotal() - 1; i >= 0; i--)
    {
      const ulong DealTicket = HistoryDealGetTicket(i);
      
      DealsProfit.Add(DealTicket, HistoryDealGetDouble(DealTicket, DEAL_PROFIT));
    }
}

double GetDealProfitHashClear( const ulong Deal )
{
  static double Profit = 0;
  
  return(DealsProfit.TryGetValue(Deal, Profit) ? Profit : 0);
}

double GetDealProfitFull( const ulong Deal )
{
  return(HistoryDealSelect(Deal) ? HistoryDealGetDouble(Deal, DEAL_PROFIT) : 0);
}

double GetDealProfitClear( const ulong Deal )
{
  return(HistoryDealGetDouble(Deal, DEAL_PROFIT));
}

typedef double (*GetDealProfit)( const ulong );

// Находим суммарный профит сделок из массива
double SumProfit( const ulong &Deals[], GetDealProfit DealProfit )
{
  double Profit = 0;
  
  for (int i = ArraySize(Deals) - 1; i >= 0; i--)
    Profit += DealProfit(Deals[i]);
    
  return(Profit);
}

#define BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
} 

int OnInit()
{
  const int Amount = 100000;  
  CreateHistory(Amount); // Создаем историю из Amount сделок в тестере
  
  ulong Deals[];
  GetDeals(Amount, Amount, Deals); // Заполняем массив случайно выбранными сделками

  // Находим суммарный профит сделок из массива
  
  BENCH(Print(SumProfit(Deals, GetDealProfitFull))); // Полноценная классическая реализация
  
  BENCH(SetHashMap()); // Заполнили HashMap
  BENCH(Print(SumProfit(Deals, GetDealProfitHashClear))); // Реализация через HashMap
  
  BENCH(HistorySelect(0, INT_MAX));
  BENCH(Print(SumProfit(Deals, GetDealProfitClear))); // Реализация с предварительно загруженной историей
  
  return(INIT_FAILED);
}

Советник открывает 100 000 сделок, затем ищет суммарный профит случайных сделок разными методами (см. комментарии). Результат

2017.12.05 00:00:00   -13133.19999999244
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitFull))] = 38082
2017.12.05 00:00:00   Time[SetHashMap()] = 57849
2017.12.05 00:00:00   -13133.19999999244
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitHashClear))] = 7437
2017.12.05 00:00:00   Time[HistorySelect(0,INT_MAX)] = 1
2017.12.05 00:00:00   -13133.19999999244
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitClear))] = 31669

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

В 4 раза - много это или мало для данной ситуации? Ну здесь это 24 миллсекунды. Если очень много раз обращаться к истории, то, наверное, получится заметно сэкономить. Но не уверен.


Для более реального тестерного случая (2000 сделок и 1 000 000 единичных обращений к истории) результат выглядит так

2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitFull))] = 122969
2017.12.05 00:00:00   Time[SetHashMap()] = 816
2017.12.05 00:00:00   4829800340.792288
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitHashClear))] = 23852
2017.12.05 00:00:00   Time[HistorySelect(0,INT_MAX)] = 1
2017.12.05 00:00:00   4829800340.792288
2017.12.05 00:00:00   Time[Print(SumProfit(Deals,GetDealProfitClear))] = 114427

Почти 100 мс экономии на проход! Если, допустим, делаем Оптимизацию на 10 000 полноценных проходов, то Hash-вариант закончится на 15 минут быстрее.

Разработчикам за реализацию работы с Историей твердую пятерку ставить пока рано. Видно, что могут ускорить, раз даже MQL-решение уделывает.


Результат

Очень хорошо будет, если сформируется оптимальное решение по скорости для Тестера.

 

Подскажите, пожалуйста, как реализовать хэш классов?

вот этот код не работает:

CHashMap<string, CObject*> *ghFMDini = new CHashMap<string, CObject*>;;

class cFMD { // структура - файлы с Маркет Датой для символа
        public:
                string file_trades;
                string file_orderbook;

        public:
           //--- Конструктор и деструктор
           cFMD(void){};
          ~cFMD(void){};
};

void OnStart() {
        cFMD * gacFMDini = new cFMD;

        gacFMDini.file_trades = "test";
        ghFMDini.Add("test1", gacFMDini);
        Print(gacFMDini.file_trades);
}

выдает ошибку:

'Add' - no one of the overloads can be applied to the function call     Test1.mq5       50      11
could be one of 4 function(s)   Test1.mq5       50      11
   bool CHashMap<string,CObject*>::Add(CKeyValuePair<string,CObject*>*) HashMap.mqh     93      22
   bool CHashMap<string,CObject*>::Add(string,CObject*) HashMap.mqh     94      22
   bool IMap<string,CObject*>::Add(string,CObject*)     IMap.mqh        17      14
   bool ICollection<CKeyValuePair<string,CObject*>*>::Add(CKeyValuePair<string,CObject*>*)      ICollection.mqh 14      14
Причина обращения: