Библиотеки: TesterCache - страница 11

 
Forester #:

очень больших не увидел.

Файл же на 99% - это небольшой массив довольно мелких структур.

 
Forester #:

Улучшение.

Вместо того, чтобы задавать тип оптимизации вручную

и перекомпилировать скрипт, можно его считать из файла такой функцией:

и затем выбрать автоматически тип:

И проверять тип Res = this.IsCorrectType() в Load() уже не обязательно.

Поторопился с этой идеей. На тот момент тестировал мат. режим и все было хорошо.
Начал добавлять обычный и возникла проблема с типами. Этот код не компилируется:

Ошибка

undeclared identifier    TesterCache_Example.mq5    55    29
   in template 'bool OptReports(TESTERCACHE<T>&)' specified with [T=MATHEMATICS]    TesterCache_Example.mq5    44    6
   see template instantiation 'OptReports<MATHEMATICS>'    TesterCache_Example.mq5    32    7

#property script_show_inputs

input string inFileName = "Tester.opt"; // opt-FileName
input int inNum = 0;                    // Какую запись показать

#include <fxsaber\TesterCache\TesterCache.mqh> // Чтение/Запись opt-файлов оптимизационных кешей MT5-тестера.


void OnStart(){
   StartOpt(inFileName);
}

void StartOpt(string file_name){
   TESTERCACHE<ExpTradeSummary> Cache0;         // Стандартная оптимизация
   uchar Bytes[];
   const int handle = ::FileOpen(file_name, FILE_READ | FILE_BIN);
   if (handle == INVALID_HANDLE){Print("Wrong file or file not found:",file_name,"   Return!");return; }
   uint len= FileReadArray(handle,Bytes);
   ::FileClose(handle);
   
   Cache0.Load(Bytes);

   if(Cache0.GetType()==2){
      TESTERCACHE<TestCacheSymbolRecord> Cache;   // Оптимизация по символам
      Cache.Load(Bytes); ::ArrayFree(Bytes);
      OptReports(Cache);
   }
   else if(Cache0.GetType()==3){
      TESTERCACHE<MATHEMATICS> Cache;             // Оптимизация в мат. режиме
      //TESTERCACHE<ExpTradeSummary> Cache;
      Cache.Load(Bytes); ::ArrayFree(Bytes);
      OptReports(Cache);
   }
   else if(Cache0.GetType()==1){
      ::ArrayFree(Bytes);
      OptReports(Cache0);// Стандартная оптимизация
   }
}


template <typename T>


bool OptReports(TESTERCACHE<T> &Cache){
   Print("Header");    Print(Cache.Header.ToString()); // Вывели основные данные оптимизационного кеша.
   Print("Inputs");ArrayPrint(Cache.Inputs);Print("Parameters");ArrayPrint(Cache.ParametersBuffer);Print("UnknownNums");ArrayPrint(Cache.UnknownNums);
   if(Cache.Header.passes_passed==0){Print("Passes = 0. Return!");return false;}
   MqlParam Params[][5];// https://www.mql5.com/ru/docs/constants/indicatorconstants/enum_datatype

      for(int p=0;p<Cache.Header.passes_passed;p++){
          const int Size = Cache.GetInputs(p, Params); // Считали соответствующие оптимизируемые входные параметры.
          Print("Result:"); Print(Cache[p].ToString()); // Вывели стат. данные запрошенной записи
          Print("Params:"); ArrayPrint(Params);             // Вывели ее оптимизируемые входные параметры.
          if(Cache.GetType()==1){// Стандартная оптимизация
             Print(Cache[p].initial_deposit);
          }else if(Cache.GetType()==3){// Оптимизация в мат. режиме
             Print(Cache[p].Pass," = ",Cache[p].custom_fitness);
          }else{
          
          }
       }
   return true;  
}

Я не разбираюсь в template <typename T>

Компилятор видит, будто бы функция OptReports() вызвана как MATHEMATICS поэтому не дает напечатать параметр из структуры ExpTradeSummary

Но там еще 2 варианта есть кроме MATHEMATICS , в том числе ExpTradeSummary.

Или баг компилятора или я что-то не так сделал.

Пока вижу только вариант - сделать 3 функции копии для каждого типа.

 
Forester #:

Поторопился с этой идеей. На тот момент тестировал мат. режим и все было хорошо.
Начал добавлять обычный и возникла проблема с типами.

Здесь делал иначе.

bool Load( const uchar &Bytes[], TESTERCACHE<ExpTradeSummary> &CacheClassic, TESTERCACHE<MATHEMATICS> &CacheMath, bool &IsMath )
{
  bool Res = false;
  
  IsMath = (Res = CacheMath.Load(Bytes)) || !(Res = CacheClassic.Load(Bytes));
  
  return(Res);
}
      TESTERCACHE<ExpTradeSummary> CacheClassic;
      TESTERCACHE<MATHEMATICS> CacheMath;
      bool IsMath;
      
//      if (Cache.Load(Bytes)) // Прочитали оптимизационный кеш.
      if (::Load(Bytes, CacheClassic, CacheMath, IsMath)) // Прочитали оптимизационный кеш.
      {
      // https://www.mql5.com/ru/forum/497682/page10#comment_58431996
      #define CACHE2(A) (IsMath ? CacheMath##A : CacheClassic##A)
      #define CACHE(A) CACHE2(A)

          if (IsMath)
            CorrectMathHeader(CacheMath);

          int Pos[];
          
          // https://www.mql5.com/ru/forum/170952/page317#comment_58432151
          const int Size = StatMode ? CACHE(.SortByStat(Stat, Pos))
                                    : CACHE(.SortByCrit((Criterion == -1) ? CACHE(.Header.last_criterion) : Criterion, Pos));
          
          const datetime From = CACHE(.Header.date_from);
          const datetime To = CACHE(.Header.date_to);

Для оптимизации по символам не стал даже заморачиваться (для стат. сравнений только использую). А реализация выше - просто выходит, пусть и костыльно.

TesterDashboard - эффективное привлечение эволюционной интеллектуальной машины к поиску закономерностей.
TesterDashboard - эффективное привлечение эволюционной интеллектуальной машины к поиску закономерностей.
  • 2021.10.14
  • www.mql5.com
Идея не нова, вопрос был только в реализации. Платформа MetaTrader 5 обладает возможностями автоматизации Тестера. Расчет огромного количества данных на истории реальных тиков - обыденность . Проверка
 
fxsaber #:

Здесь делал иначе.

Для оптимизации по символам не стал даже заморачиваться (для стат. сравнений только использую). А реализация выше - просто выходит, пусть и костыльно.

Спасибо.
 

Сделал как мне понятнее:

Первоначально считываю ExpTradeSummary. Если тип не совпадает, то считываю правильный тип. Потом через if(){} работаю с нужным типом.
Выкладываю код с авто определением типа, может кому пригодится:

#property script_show_inputs
input string inFileName = "Tester.opt"; // opt-FileName
#include <fxsaber\TesterCache\TesterCache.mqh> // Чтение/Запись opt-файлов оптимизационных кешей MT5-тестера.
void OnStart(){ OptReports(inFileName);}

//int GetType( TestCacheHeader &h ){return( (h.symbol[] == ""   ? 3 : (h.opt_mode == 2 ? 2 : 1 )));}// 1=TradeSummary, 2=all Symbols,3=math 
int GetType( TestCacheHeader &h ){return( ((h.ticks_mode == 3) ? 3 : (h.opt_mode == 2 ? 2 : 1 )));}// 1=TradeSummary, 2=all Symbols,3=math 

bool OptReports(string file_name){
   uchar Bytes[];
   const int handle = ::FileOpen(file_name, FILE_READ | FILE_BIN);
   if (handle == INVALID_HANDLE){Print("Wrong file or file not found:",file_name,"   Return!"); return false; }
   uint len_file= FileReadArray(handle,Bytes);
   ::FileClose(handle);
   
   TESTERCACHE<ExpTradeSummary> Cache;        // Стандартная оптимизация
   TESTERCACHE<TestCacheSymbolRecord> Cache2; // Оптимизация по символам
   TESTERCACHE<MATHEMATICS> Cache3;           // Оптимизация в мат. режиме
   
   Cache.Load(Bytes);
   TestCacheHeader h=Cache.Header;
   int type=GetType(h);
   if(type==2){Cache2.Load(Bytes);} else if(type==3){Cache3.Load(Bytes);}
   ::ArrayFree(Bytes);
   Print ("Type: ",type);
   if(type==1){
      Print("Header");    Print(Cache.Header.ToString()); // Вывели основные данные оптимизационного кеша.
      Print("Inputs");ArrayPrint(Cache.Inputs); Print("Parameters");ArrayPrint(Cache.ParametersBuffer); Print("UnknownNums");ArrayPrint(Cache.UnknownNums);
   }
   else if(type==2){
      Print("Header");    Print(Cache2.Header.ToString()); // Вывели основные данные оптимизационного кеша.
      Print("Inputs");ArrayPrint(Cache2.Inputs); Print("Parameters");ArrayPrint(Cache2.ParametersBuffer); Print("UnknownNums");ArrayPrint(Cache2.UnknownNums);
   }
   else {
      Print("Header");    Print(Cache3.Header.ToString()); // Вывели основные данные оптимизационного кеша.
      Print("Inputs");ArrayPrint(Cache3.Inputs); Print("Parameters");ArrayPrint(Cache3.ParametersBuffer); Print("UnknownNums");ArrayPrint(Cache3.UnknownNums);
   }

   int len=h.passes_passed;
   if(len==0){Print("Passes = 0. Return!");return false;}
   MqlParam Params[][5];
      for(uint p=0;p<len;p++){
         Print("Result:"); if(type==1){Print(Cache[p].ToString());}else if(type==2){Print(Cache2[p].ToString());}else{Print(Cache3[p].ToString());} // Вывели стат. данные запрошенной записи
         if(type==1){Cache.GetInputs(p, Params);}else if(type==2){Cache2.GetInputs(p, Params);}else{Cache3.GetInputs(p, Params);} // Считали Params оптимизируемые входные параметры.
         Print("Params:"); ArrayPrint(Params);             // Вывели ее оптимизируемые входные параметры.
         if(type==1){// Стандартная оптимизация
            Print(Cache[p].Pass," ",Cache[p].initial_deposit);
         }else if(type==2){   // Оптимизация по символам
            Print(Cache2[p].Pass," ",Cache2[p].initial_deposit," ",Cache2[p].symbol[]);//мат режим: d=0 => 2
          }else{// Оптимизация в мат. режиме
            Print(Cache3[p].Pass," ",Cache3[p].custom_fitness);//мат режим: d=0 => 2
         }
      }
   return true;  
}
Получение типа сделал отдельной функцией, без корректировки библиотеки
int GetType( TestCacheHeader &h ){return( ((h.ticks_mode == 3) ? 3 : (h.opt_mode == 2 ? 2 : 1 )));}// 1=TradeSummary, 2=all Symbols,3=math 

Мат. режим определяю по h.ticks_mode == 3, а не по h.symbol=="". Оба варианта рабочие.

 

Поправьте пожалуйста в\TestCacheHeader.mqh

#define UINT16 short

на

#define UINT16 ushort

W1 со знаком минус получался. С ushort все работает.

 
Forester #:

W1 со знаком минус получался. С ushort все работает.

Спасибо, поправлю.
 
fxsaber #:
Спасибо, поправлю.
Обновил.
 
fxsaber #:
Обновил.

Спасибо.

У меня почему то библиотека не может открывать .opt файлы от форварда.

Заголовок читает, а дальше

Inputs
Parameters
UnknownNums

пустые.
И при печати результатов проходов
Result:

ошибка

Type: 1
Header
version = 515
copyright = Copyright 2000-2025, MetaQuotes Ltd.
name = TesterOptCache
header_size = 18705
record_size = 304
expert_name = StepTpSl
expert_path = Experts\StepTpSl.ex5
server = RannForex-Server
symbol = EURUSD
(ENUM_TIMEFRAMES)period = PERIOD_M1
date_from = 2023.04.10 00:00:00
date_to = 2023.05.01 00:00:00
date_forward = 2023.03.01 00:00:00
opt_mode = 3
ticks_mode = 4
last_criterion = 6
msc_min = 1552
msc_max = 13246
msc_avg = 4747
group = demo (hedging)
trade_currency = USD
trade_deposit = 10000
trade_condition = 0
trade_leverage = 100
trade_hedging = 2
trade_currency_digits = 2
trade_pips = 0
parameters_size = 719
parameters_total = 94
opt_params_size = 24
opt_params_total = 3
dwords_cnt = 0
snapshot_size = 4
passes_total = 100
passes_passed = 100

Inputs
Parameters
UnknownNums
Result:
array out of range in 'TesterCache.mqh' (312,24)

У бек теста заголовок такой же с отличиями в датах и милисекундах. И заполнены:

Inputs
Parameters
UnknownNums
Result:

Т.е. там все работает. Формат/структура что ли другие? Пробовал подставлять структуру от теста по всем символам - не помогло.

Приложил файлы бек и форвард. Попробуйте и со своими opt файлами, т.к. у меня МТ5 последней для Win7 версии. Хотя сам свои он должен бы читать.

Я еще минимум 2-3 дня буду HTML отчетом заниматься. Раньше до этого бага времени не будет.

Файлы:
Desktop.zip  33 kb
 
Forester #:

У меня почему то библиотека не может открывать .opt файлы от форварда.

Не знаю, когда буду разбираться. Пока такая рабочая альтернатива.
// https://www.mql5.com/ru/forum/459079/page5#comment_58714877
#include <MQL5Book\OptReader.mqh> // https://www.mql5.com/ru/code/45596

void OnStart()
{
  string OptFilename = "StepTpSl.EURUSD.M1.20230410.20230501.43.6AE68C8F21A3DBD44F9C65A2630B8E8F.opt";
    
  OptReader reader(OptFilename);
  reader.print();
  reader.header2CSV(OptFilename + "-header.csv");
  reader.inputs2CSV(OptFilename + "-inputs.csv");
  reader.export2CSV(OptFilename + "-data.csv");
}