MetaTrader 5 Strategy Tester! - страница 80

 
Renat Fatkhullin:

Почему не указываете и не прикладываете код?

У меня было представлено два варианта. Нужно использовать TestFitnessBetter.mq5

Мы будем делать оба теста. А вот почему Вы не провели тест для моего алгоритма - это действительно вопрос.

Andrey Dik:

Результаты тестов буду публиковать в этом посте частями. Пошагово.

1. Сначала повторю тесты, которые провел Ренат.

2. Создам отдельную библиотеку с ФФ Рената и проведу этот же тест но уже по стандарту подключения к библиотеке с сгенерированным автоматически советником (библиотека понадобится, если Ренат, и другие пользователи, захочет повторить тест и с моей библиотекой оптимизации тоже). Результат должен совпасть с результатом в п.1.

3. Проведу тест с моим алгоритмом и полученной в п2. библиотекой ФФ.

Далее, все те же 3 шага повторим для слегка изменённой ФФ Рената.  

 
Andrey Dik:
Покажите, пожалуйста код ФФ библиотеки, Вы сэкономите мне время на написание, пожалуйста.
#property library
#property strict

int    countRuns    = 0;
//string Key      = "A;a;B;b;C;c;D;d;E;e;F;f;G;g;H;h;I;i;J;j;K;k;L;l;M;m;N;n;O;o;P;p;Q;q;R;r;S;s;T;t;U;u;V;v;W;w;X;x;Y;y;Z;z";
string Key      = "a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p;q;r;s;t;u;v;w;x;y;z";
string KeyArray [];
int    KeyLen   = 0;
//string Text     = "SptstmLEjXhdESqotbRQbmsYKkJTZiOHBEenIbGqLHwxqfWTok";
//short  ExtOriginal[50]={ 'm','i','l','l','i','o','n','s','x','o','f','x','r','e','s','i','d','e','n','t','s','x','c','h','i','n','a','s','x','n','o','r','t','h','w','e','s','t','e','r','n','x','r','e','g','i','o','n','s','x' };
string Text     = "millionsxofxresidentsxchinasxnorthwesternxregionsx";
int    TextLen  = 0;
double best[];
//+------------------------------------------------------------------+
int GetParamCount () export
{
  TextLen = StringLen (Text);
  KeyLen  = StringSplit (Key, StringGetCharacter (";", 0), KeyArray);
  return (TextLen);
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
void GetParamProperties (double &min, double &max, double &step) export
{
  min = 0.0;
  max = KeyLen - 1;
  step = 1.0;
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
double FF (double &param []) export
{
  countRuns++;
  
  int sizeArray = ArraySize (param);
  if(sizeArray != TextLen)
    return (0.0);
  
  double ffVolue = 0;
  
  for(int i = 0; i < TextLen; i++)
  {
    if(GetCode (param [i]) == StringSubstr (Text, i, 1))
      ffVolue++;
      //ffVolue+=1 + i * 0.01;
  }
  
  // сохранение результатов
  if(CompareBests (ffVolue))
    {
     SaveResults (BestResults, ffVolue);
     ArrayCopy(best,param);
    }
  SaveResults (AllResults, ffVolue);
  
  return (double(ffVolue));
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
int GetCountRunsFF () export
{
  return (countRuns);
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
void SaveResultsToFiles () export
{
  string str = "";
  int handle = FileOpen ("AllResults.csv", FILE_WRITE | FILE_CSV | FILE_ANSI, ";");
  
  if(handle != INVALID_HANDLE)
  {
    for(int i = 0; i < ArraySize (AllResults); i++)
      str += (string)AllResults [i] + ";" + "\n";
    
    FileWriteString (handle, str, -1);
    FileClose (handle);
  }
  else
  {
    Print ("Ошибка записи в файл AllResults.csv");
  }
  
  str = "";
  handle = FileOpen ("BestResults.csv", FILE_WRITE | FILE_CSV | FILE_ANSI, ";");
  
  if(handle != INVALID_HANDLE)
  {
    for(int i = 0; i < ArraySize (BestResults); i++)
      str += (string)BestResults [i] + ";" + "\n";
    
    FileWriteString (handle, str, -1);
    FileClose (handle);
  }
  else
  {
    Print ("Ошибка записи в файл BestResults.csv");
  }
  
  str = "";
  handle = FileOpen ("ResultsString.csv", FILE_WRITE | FILE_CSV | FILE_ANSI, ";");
  
  if(handle != INVALID_HANDLE)
  {
    for(int i = 0; i < TextLen; i++)
      str += (string)KeyArray[(int)best [i]];
    
    FileWriteString (handle, str, -1);
    FileClose (handle);
  }
  else
  {
    Print ("Ошибка записи в файл BestResults.csv");
  }
}
//+------------------------------------------------------------------+

double AllResults  [];        // все результаты ФФ
double BestResults [];        // лучшие результаты ФФ
double BestResult = -DBL_MAX; //последний лучший результат

//+------------------------------------------------------------------+
bool CompareBests (double Res)
{
  if(Res > BestResult)
  {
    BestResult = Res;
    return (true);
  }
  
  return (false);
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
void SaveResults (double &SavedResults [], double Res)
{
  const int size = ArraySize (SavedResults);
  ArrayResize (SavedResults, size + 1, 10000);
  SavedResults [size] = Res;
  return;
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
string GetCode (double param)
{
  int p = (int)MathRound (param);
  if(p < 0)
    p = 0;
  if(p > KeyLen - 1)
    p = KeyLen - 1;
  
  return (KeyArray [p]);
}
//+------------------------------------------------------------------+

так же изменил чуток скрипт AO_runner_qscript6.mq5 для вывода получившейся строки:

#property script_show_inputs
#property strict

//+------------------------------------------------------------------+
// алгоритм оптимизации
#import "ao.ex5"
// инициализация АО
bool   InitAO (int paramCount, int maxFFruns);
// запуск АО
void   StartAlgo ();
// получить максимальное значение ФФ      
double GetMaxFF ();
#import
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
// тестовая фитнес функция
#import "ff.ex5"
// запросить количество параметров ФФ
int    GetParamCount ();
// произведённое количество запусков ФФ
int    GetCountRunsFF ();
// сохранение промежуточных и лучших результатов в файл
void   SaveResultsToFiles ();
#import
//+------------------------------------------------------------------+

//--- input parameters
input int MaxFFruns_P = 20000;

//+------------------------------------------------------------------+
void OnStart ()
{
  // узнаем, сколько параметров нужно оптимизировать
  int   paramCount = GetParamCount ();
  ulong startTime = GetMicrosecondCount ();
  
  //------------------------------------------------------------------
  if(!InitAO (paramCount, MaxFFruns_P))
  {
    Print ("Инициализация алгоритма завершилась неудачей!");
    return;
  }
  StartAlgo ();
  SaveResultsToFiles ();
  //------------------------------------------------------------------
  
  startTime = GetMicrosecondCount () - startTime;
  
  Print ("Макс: " + DoubleToString (GetMaxFF (), 8)+"  percent: "+DoubleToString(GetMaxFF()*100.0/50.0,2)+" %%" );
  Print ("Запусков ФФ: " + (string)GetCountRunsFF ());
  Print ("Время: " + (string)startTime + " мкс; " + DoubleToString ((double)startTime / 1000000.0, 8) + " c");

  string str = "";
  int handle = FileOpen ("ResultsString.csv", FILE_READ | FILE_CSV | FILE_ANSI, ";");
  if(handle!=INVALID_HANDLE) Print("Result: ",FileReadString(handle));
  FileClose(handle);
  Print ("---------------------------------");
  
}
//+------------------------------------------------------------------+


 

 
Renat Fatkhullin:

Почему не указываете и не прикладываете код?

У меня было представлено два варианта. Нужно использовать TestFitnessBetter.mq5

Второй вариант не делал, только первый TestFitness.mq5.
 
Sergey Chalyshev:

Спасибо.

Проверил код, вроде всё корректно. Продолжаю тесты (с оформлением результатов в том посте в котором начал). 

 
Sergey Chalyshev:
Второй вариант не делал, только первый TestFitness.mq5.

Второй вариант  TestFitnessBetter.mq5:

в фф нужно закомментировать первую строку и раскомментировать вторую

      ffVolue++;
      //ffVolue+=1 + i * 0.01;

результаты:

DO      0       14:35:20.955    AO_runner_qscript6 (USDCHF,H1)  ---------------------------------
KN      0       14:35:25.645    AO_runner_qscript6 (USDCHF,H1)  Макс: 61.25000000  Запусков ФФ: 20000
CE      0       14:35:25.645    AO_runner_qscript6 (USDCHF,H1)  Время: 840406 мкс; 0.84040600 c
NN      0       14:35:25.646    AO_runner_qscript6 (USDCHF,H1)  Original Text: millionsxofxresidentsxchinasxnorthwesternxregionsx
PL      0       14:35:25.646    AO_runner_qscript6 (USDCHF,H1)    Result Text: cillionsxofxresidentsxchinasxnorthwesternxregionsx
QO      0       14:35:25.646    AO_runner_qscript6 (USDCHF,H1)  percent: 98.0%%
LJ      0       14:35:25.646    AO_runner_qscript6 (USDCHF,H1)  ---------------------------------
CQ      0       14:35:33.836    AO_runner_qscript6 (USDCHF,H1)  Макс: 59.90000000  Запусков ФФ: 20000
PP      0       14:35:33.836    AO_runner_qscript6 (USDCHF,H1)  Время: 874659 мкс; 0.87465900 c
HK      0       14:35:33.836    AO_runner_qscript6 (USDCHF,H1)  Original Text: millionsxofxresidentsxchinasxnorthwesternxregionsx
PK      0       14:35:33.836    AO_runner_qscript6 (USDCHF,H1)    Result Text: millionsxofxreoidentsdchinasxnorthwesternxregionsx
QD      0       14:35:33.836    AO_runner_qscript6 (USDCHF,H1)  percent: 96.0%%
JQ      0       14:35:33.836    AO_runner_qscript6 (USDCHF,H1)  ---------------------------------
GD      0       14:35:42.073    AO_runner_qscript6 (USDCHF,H1)  Макс: 58.03000000  Запусков ФФ: 20000
EO      0       14:35:42.073    AO_runner_qscript6 (USDCHF,H1)  Время: 772534 мкс; 0.77253400 c
PP      0       14:35:42.074    AO_runner_qscript6 (USDCHF,H1)  Original Text: millionsxofxresidentsxchinasxnorthwesternxregionsx
MF      0       14:35:42.074    AO_runner_qscript6 (USDCHF,H1)    Result Text: yillcotsxofxyesidentsxchinasxnorthwesternxregionsx
EI      0       14:35:42.074    AO_runner_qscript6 (USDCHF,H1)  percent: 92.0%%
RL      0       14:35:42.074    AO_runner_qscript6 (USDCHF,H1)  ---------------------------------
KO      0       14:35:47.275    AO_runner_qscript6 (USDCHF,H1)  Макс: 58.68000000  Запусков ФФ: 20000
FJ      0       14:35:47.275    AO_runner_qscript6 (USDCHF,H1)  Время: 867415 мкс; 0.86741500 c
NM      0       14:35:47.275    AO_runner_qscript6 (USDCHF,H1)  Original Text: millionsxofxresidentsxchinasxnorthwesternxregionsx
CL      0       14:35:47.275    AO_runner_qscript6 (USDCHF,H1)    Result Text: millionbxofxresidentsxccinazxnorthwesternxregionsx
EN      0       14:35:47.275    AO_runner_qscript6 (USDCHF,H1)  percent: 94.0%%
LK      0       14:35:47.275    AO_runner_qscript6 (USDCHF,H1)  ---------------------------------
LR      0       14:36:05.313    AO_runner_qscript6 (USDCHF,H1)  Макс: 59.93000000  Запусков ФФ: 20000
JQ      0       14:36:05.313    AO_runner_qscript6 (USDCHF,H1)  Время: 906410 мкс; 0.90641000 c
RJ      0       14:36:05.313    AO_runner_qscript6 (USDCHF,H1)  Original Text: millionsxofxresidentsxchinasxnorthwesternxregionsx
IH      0       14:36:05.313    AO_runner_qscript6 (USDCHF,H1)    Result Text: millioysxofxresidentsxchinwsxnorthwesternxregionsx
GS      0       14:36:05.313    AO_runner_qscript6 (USDCHF,H1)  percent: 96.0%%
PF      0       14:36:05.313    AO_runner_qscript6 (USDCHF,H1)  ---------------------------------

в скрипте пришлось вставить оригинал текста для подсчета процентов совпадений:

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property script_show_inputs
#property strict

//+------------------------------------------------------------------+
// алгоритм оптимизации
#import "ao.ex5"
// инициализация АО
bool   InitAO(int paramCount,int maxFFruns);
// запуск АО
void   StartAlgo();
// получить максимальное значение ФФ      
double GetMaxFF();
#import
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
// тестовая фитнес функция
#import "ff.ex5"
// запросить количество параметров ФФ
int    GetParamCount();
// произведённое количество запусков ФФ
int    GetCountRunsFF();
// сохранение промежуточных и лучших результатов в файл
void   SaveResultsToFiles();
#import
//+------------------------------------------------------------------+

//--- input parameters
input int MaxFFruns_P=20000;

//+------------------------------------------------------------------+
void OnStart()
  {
// узнаем, сколько параметров нужно оптимизировать
   int   paramCount= GetParamCount();
   ulong startTime = GetMicrosecondCount();

//------------------------------------------------------------------
   if(!InitAO(paramCount,MaxFFruns_P))
     {
      Print("Инициализация алгоритма завершилась неудачей!");
      return;
     }
   StartAlgo();
   SaveResultsToFiles();
//------------------------------------------------------------------

   startTime=GetMicrosecondCount()-startTime;

   Print("Макс: "+DoubleToString(GetMaxFF(),8),"  Запусков ФФ: "+(string)GetCountRunsFF());
   Print("Время: "+(string)startTime+" мкс; "+DoubleToString((double)startTime/1000000.0,8)+" c");

   string res = "";
   int handle = FileOpen ("ResultsString.csv", FILE_READ | FILE_CSV | FILE_ANSI, ";");
   if(handle!=INVALID_HANDLE) res=FileReadString(handle);
   FileClose(handle);

   double exact=0;
   string OriginalText="millionsxofxresidentsxchinasxnorthwesternxregionsx";

   for(int i=0;i<paramCount;i++)
      if(StringGetCharacter(res,i)==StringGetCharacter(OriginalText,i))
         exact++;
//---
   Print("Original Text: ",OriginalText);
   Print("  Result Text: ",res);
   Print("percent: ",exact*100.0/paramCount,"%%");

   Print("---------------------------------");
  }
//+------------------------------------------------------------------+


p.s. на время выполнения не обращайте внимания, делал на ноутбуке.
 

 

 
Sergey Chalyshev:

Второй вариант  TestFitnessBetter.mq5:


p.s. на время выполнения не обращайте внимания, делал на ноутбуке.

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

Итак:

Первый тест (оформленный по первоначальной схеме)

у алгоритма от MQ 41.33 при среднем вызове ФФ 20906, у алгоритма от Joo 46.6 при ровно 20000 вызовов.

Второй тест (изменённый в соответствии с требованием Рената) 

у алгоритма от MQ 50.2 при среднем вызове ФФ 21760, у алгоритма от Joo 59.75 при ровно 20000 вызовов. 

Вот это я называю объективным тестированием.

Сергей, если у Вас есть ещё немного времени, попробуйте тесты с другими какими нибудь ФФ, или просто предложите свою ФФ, желательно со многими параметрами, а не с 1-2... Например, можете взять классические тестовые функции (в основном они гладкие, как нравится Ренату) и смикшировать из них одну ФФ, так берутся несколько функций с 2 мя параметрами, раскидываются на 50-100 переменных, потом переменные перемешиваются между собой. Но, боюсь что штатный тестер не осилит такую ацкую смесь, поскольку не сможет оптимизировать столько переменных с таким малым шагом. Если Ренату не понравится слишком мелкий шаг, можно сделать покрупнее, что бы тесты могли пройти в штатном оптимизаторе.

В общем, пробуйте, смотрите, проверяйте. Пробуйте разные сложные гладкие и не гладкие функции что бы складывалась объективная картина. Мой алгоритм доступен там же, когда был размещён 3 дня назад.
Надеюсь, теперь всем понятно, что я не мухлевал и не подделывал результаты тестов. И, естественно, ни о каком вшивании в алгоритм заранее известных ФФ речи не может быть. Есть мой опубликованный алгоритм, есть алгоритм от MQ, любой может провести свои тесты, о каком мошенничестве шла речь, Ренат? Даже в попытке упростить задачу:

Renat Fatkhullin:

Поставим задачу просто и чисто для проверки способностей тестера подбирать целевую функцию:

  • 50 оптимизируемых переменных, которые являются символами от 'a' до 'z' английского алфавита (от 97 до 122 с шагом 1)
  • нужно получить целевую строку "millionsxofxresidentsxchinasxnorthwesternxregionsx" в 50 символов. чтобы упростить перебор, пробелы заменены на x. на суть это не влияет
  • исходная рандомная строка не нужна - она всегда заполняется входными параметрами

В первую очередь надо понять область просчета - это 26(сколько символов в алфавите) в степени 50(символов в тексте). Это 5.6061+e70 вариантов переборов - такое безумное число в реальности.

Генетическому алгоритму нужно умудриться в пределах 1-2 десятков тысяч попыток уложиться и найти приемлемые результаты. Я бы сказал четче - задача экстремально сложна(безнадежна) и все зависит от функции фитнеса. 

 ничего не вышло, я блин усложняю задачу, что бы всем алгоримтам усложнить оптимизацию, а Ренат зачем то пытается упростить? Так что же такое штатный оптимизатор? Игрушка способная работать с простыми задачами с весьма ограниченным полем поиска (не удастся оптимизировать, например нейронную сеть или более менее сложный советник), или всё таки универсальный СЕРЪЁЗНЫЙ инструмент в руках исследователя которым он и позиционируется?

 
Справедливости ради замечу - алгоритм от Joo написан на языке MQL5 от компании MetaQuotes, спасибо за такой прекрасный язык открывающий беспредельные возможности для исследователей в плане создания кастомных решений тестирования и оптимизации, намного превосходящие штатные возможности платформы МТ5.
 
Andrey Dik:
Справедливости ради замечу - алгоритм от Joo написан на языке MQL5 от компании MetaQuotes, спасибо за такой прекрасный язык открывающий беспредельные возможности для исследователей в плане создания кастомных решений тестирования и оптимизации, намного превосходящие штатные возможности платформы МТ5.

Почему о себе в третьем лице, или я не так понял и Joo не Вы, а группа людей?

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

К примеру как быстро алгоритм поймет, что изменение параметра не приводит к изменению результатов - сколько он сделает попыток изменить параметр, что б это понять?

 
-Aleks-:

1. Почему о себе в третьем лице, или я не так понял и Joo не Вы, а группа людей?

2. Все эти ФФ интересно, но куда прагматичней было бы наблюдать за поиском решения на примере конкретного советника с рядом не очевидных параметров.

К примеру как быстро алгоритм поймет, что изменение параметра не приводит к изменению результатов - сколько он сделает попыток изменить параметр, что б это понять?

1. Так скромнее просто.

2. Можно и наверное нужно бы сделать. Но сложно в реализации объективного теста (обязательно обвинят в мухлеже). Для этого понадобится написать два эксперта, один для тестера МТ, другой для кастомного тестера, после этого нужно будет добится идентичных результатов в одиночном тесте в обоих тестерах. Только после этого можно будет приступать к тетсированию оптимизатора. Есть множество нерешённых проблем до сих пор, например в штатном оптимизаторе не удаляется хендл индикатора после каждого прогона оптимизатора, а это было бы необходимо для сравнения кастомным оптимизатором, так уже через несколько секунд оптимизатор МТ наглухо подвешивает операционную систему из за моментального переполнения оперативной памяти, даже не надейтесь, что Вам хватит 8, 16, 32 Гига, не хватит! Вот когда будут решены подобные проблемы висящие годами, тогда можно говорить по Вашему вопросу. 

 
-Aleks-:

К примеру как быстро алгоритм поймет, что изменение параметра не приводит к изменению результатов - сколько он сделает попыток изменить параметр, что б это понять?

Вот кстати пример задачи с текстом это и демонстрирует - изменение параметра не даёт никакого изменения ФФ. Но кому это интересно? - по крайней мере не MQ.

В советниках (по крайней мере торговых советниках для рынка) не бывает гладких ФФ, любое изменение параметра либо не даёт никакого изменения ФФ либо скачкообразно её меняет. Это просто и логично вытекает из за дискретности рыночной информации и дискретности торговой активности. 

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