Автоматическая оптимизация советника в MetaTrader 5

15 октября 2018, 17:16
BPASoftware Thai Co. Ltd
2
4 347

Введение

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

Это параметры:

  • SL - стоп-лосс
  • TP - тейк-профит
  • STOFilter - фильтр
  • STOTimeFrameFilter - фильтр таймфрейма

Нереально запускать такой процесс каждую неделю вручную, поэтому мы попытались найти существующие механизмы для выполнения повторяющихся задач. Так как мы не нашли готовых решений для MetaTrader 5, мы решили разработать свой собственный механизм.

Выражаем благодарность Игорю Мальцеву, автору статьи "Автоматическая оптимизация торгового робота в процессе реальной торговли" для терминала MetaTrader 4.


Принцип работы


Первый экземпляр терминала MetaTrader 5 работает в режиме 24/7 — в этом терминале запущен советник Buddy Ilan и эксперт, над которым мы будем работать в этой статье (Optimizer EA). Этот эксперт будет запускать процесс оптимизации на втором экземпляре терминала MetaTrader 5.

По окончании процесса советник Optimizer EA установит оптимизированные значения в глобальных переменных, которые и будет читать запущенный эксперт Buddy Ilan.

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


Копирование данных

Как было сказано выше, нам нужно два экземпляра терминала MetaTrader 5.

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

По соображениям безопасности в MetaTrader 5 доступ к файлам вне песочницы невозможен, поэтому для копирования данных между двумя средами будем использовать команду MS-DOS "xcopy".

Для этого используем DLL на основе библиотек Windows, которую объявим следующим образом:

#import  "shell32.dll"
int ShellExecuteW(int hwnd,string Operation,string
                  File,string Parameters,string Directory,int ShowCmd);
#import

Вот вызов этой функции:

string PathIniFile = sTerminalTesterDataPath + "\\config\\common.ini";
string PathTester=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\";

int ret=ShellExecuteW(0,"Open","xcopy","\""+PathIniFile+"\" \""+PathTester+"\" /y","",0);

Эта функция будет также вызываться для запуска оптимизаций, например:

int start = ShellExecuteW(0, "Open", sTerminalTesterPath + "\\terminal64.exe", "/config:" + TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\Optimiser\\optimise.ini", "", 0);
if(start<32)
  {
   Print("Ошибка запуска тестера");
   return false;
  }

Для этого советника необходимо разрешить импорт DLL:

Импорт DLL


Автоматическая оптимизация

Платформу MetaTrader 5 можно запускать командами (См. "Запуск торговой платформы"). Точно так же можно запускать автоматические задачи.

Например, можно добавить блок запуска "[Tester]" в файл конфигурации, используемый по умолчанию (common.ini) - это позволит запускать автоматическую оптимизацию при запуске MetaTrader 5.

Именно этим мы и займемся.


Реализация

Советнику Optimizer EA нужно знать пути экземпляра MetaTrader 5, используемого для тестирования. Эти пути будут указаны в качестве параметров.

input string sTerminalTesterPath = "C:\\Program Files\\ForexTime MT5";
input string sTerminalTesterDataPath="C:\\Users\\BPA\\AppData\\Roaming\\MetaQuotes\\Terminal\\5405B7A2ED87FF45712A041DEF45780";

Мы определили рабочий каталог в первом терминале MetaTrader 5: "MQL5\Files\Optimiser".

Далее функция "CopyAndMoveCommonIni()" копирует стандартный файл конфигурации "common.ini" из экземпляра MetaTrader 5 для тестирования в рабочий каталог и переименовывает его в "optimise.ini".

bool CopyAndMoveCommonIni()
  {
   string PathIniFile= sTerminalTesterDataPath+"\\config\\common.ini";
   string PathTester = TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\";

   int ret=ShellExecuteW(0,"Open","xcopy","\""+PathIniFile+"\" \""+PathTester+"\" /y","",0);

// Дожидаемся копирования файла
   Sleep(2500);
   if(ret<32)
     {
      Print("Ошибка копирования файла ini");
      return false;
     }

// Теперь мы работаем в песочнице и можем использовать обычные файловые команды MetaTrader 5
   string IniFileName="Optimiser\\common.ini";
   string CopyTo="Optimiser\\optimise.ini";

   return FileMove( IniFileName, 0, CopyTo, 0 );
  }

Более подробную информацию о работе функции ShellExecuteW можно найти в документации Microsoft к функции ShellExecuteW. Функция не дожидается выполнения команды MS-DOS, поэтому используется задержка (Sleep 2500).

Теперь добавим в файл блок "Tester":

bool AddTesterStanza()
  {
   int filehandle=FileOpen("Optimiser\\Optimise.ini",FILE_READ|FILE_WRITE|FILE_TXT);

   if(filehandle!=INVALID_HANDLE)
     {
      FileSeek(filehandle,0,SEEK_END);

      FileWrite(filehandle,"[Tester]\n",
                "Expert=BuddyIlan\\BuddyIlan\n",
                "ExpertParameters=BuddyIlanTester.set\n",
                "Symbol="+_Symbol+"\n",
                "Period=M15\n",
                "Login=\n",
                "Model=4\n",
                "ExecutionMode=0\n",
                "Optimization=2\n",
                "OptimizationCriterion=0\n",
                "FromDate="+TimeToString(TimeGMT()-InpTesterPeriod*86400,TIME_DATE)+"\n",
                "ToDate="+TimeToString(TimeGMT(),TIME_DATE)+"\n",
                "ForwardMode=0\n",
                "Report=MQL5\\Files\\Reports\\BuddyIlanReport\n",
                "ReplaceReport=1\n",
                "ShutdownTerminal=1\n",
                "Deposit=10000\n",
                "Currency=EURUSD\n",
                "Leverage=1:100\n",
                "UseLocal=1\n",
                "UseRemote=0\n",
                "UseCloud=0\n",
                "Visual=1\n");

      FileClose(filehandle);
     }
   else
     {
      Print("FileOpen, error ",GetLastError());
      return false;
     }
   return true;
  }

Здесь мы определяем советник, который будем оптимизировать ("BuddyIlan") — этот советник обязательно должен присутствовать во второй среде. Также определяем файл параметров советника "BuddyIlanTester.set" (название должно отличаться от имени эксперта), устанавливаем интервал (от FromDate до ToDate) и все параметры, необходимые для оптимизации.

Устанавливаем "ShutdownTerminal=1" — это означает, что терминал будет закрыт после окончания оптимизации.

Также будет сформирован файл с отчетом "Files\Reports\BuddyIlanReport", при этом платформа добавит расширение ".xlm".

Если вы запускаете советники в терминале, работающем на виртуальном сервере с ограниченными вычислительными ресурсами, можете использовать для оптимизации удаленные или облачные агенты тестирования ("UseRemote" или "UseCloud").


Файл параметров

Далее надо сформировать определенный выше файл параметров (BuddyIlanTester.set) — в нем будут находиться значения каждого оптимизируемого параметра советника (Buddy Ilan).

Значения этих параметров по умолчанию устанавливаются пользователем (определяются как параметры):

input _TradingMode TradingMode = Dynamic;             // Фиксированный или динамический объем
input double  InpIlanFixedVolume = 0.1;               // Размер фиксированного объема (если используется)

input int InpNCurrencies=1;                           // Количество экземпляров советника Buddy Ilan на счете

input double  LotExponent = 1.4;
input bool    DynamicPips = true;
input int     DefaultPips = 15;

input int Glubina=24;                                 // Количество последних баров для расчета волатильности
input int DEL=3;

input int TakeProfit = 40.0;                          // Тейк-профит в пунктах
input int Stoploss = 1000.0;                          // Стоп-лосс в пунктах

input bool InpIlanTrailingStop = true;                // Использовать трейлинг-стоп
input int InpIlanDistanceTS = 5;                      // Расстояние трейлинг-стопа в пунктах

input int MaxTrades=10;
input int InpDeviation=10;                            // Максимально допустимое отклонение в пунктах

input bool bSTOFilter = true;                         // Динамический фильтр тренда
input bool bSTOTimeFrameFilter = false;               // Динамический фильтр таймфрейма
input int InpMaxTf = 60;                              // Максимальный таймфрейм

Приведенная ниже функция принимает 8 аргументов, первые 4 из которых соответствуют оптимизируемым параметрам (SL, TP, STOFilter и STOTimeFrameFilter). При значении true в конце соответствующей строки параметров добавляется "Y". Следующие четыре аргумента соответствуют уже оптимизированным значениям, которые надо учитывать при следующей оптимизации.

Как видно из названия, функция также копирует файл параметров в соответствующий каталог экземпляра терминала MetaTrader 5, используемого для тестирования (MQL5\Profiles\Tester).

bool CreateAndCopyParametersFile( bool SL, bool TP, bool STOFilter, bool STOTimeFrameFilter, int SLValue, int TPValue, bool STOFilterValue, bool STOTimeFrameFilterValue )
  {
   int filehandle=FileOpen("Optimiser\\BuddyIlanTester.set",FILE_WRITE|FILE_TXT);

   if(filehandle!=INVALID_HANDLE)
     {
      FileWrite(filehandle,
                "_EA_IDENTIFIER=Buddy Ilan\n",
                "_EA_MAGIC_NUMBER=1111||0||1||10||N\n",
                StringFormat("TradingMode=%d||0||0||0||N\n",TradingMode),
                StringFormat("InpIlanFixedVolume=%lf||0.0||0.000000||0.000000||N\n",InpIlanFixedVolume),
                StringFormat("InpNCurrencies=%d||0||1||10||N\n",InpNCurrencies),
                StringFormat("LotExponent=%lf||0.0||0.000000||0.000000||N\n",LotExponent),
                StringFormat("DynamicPips=%s||false||0||true||N\n",(DynamicPips==true)?"true":"false"),
                StringFormat("DefaultPips=%d||0||1||10||N\n",DefaultPips),
                StringFormat("Glubina=%d||0||1||10||N\n",Glubina),
                StringFormat("DEL=%d||0||1||10||N\n",DEL),

                StringFormat("TakeProfit=%d||30||10||70||%s\n",(TPValue==0)?30:TPValue,(TP==true)?"Y":"N"),
                StringFormat("Stoploss=%d||500||250||1500||%s\n",(SLValue==0)?1000:SLValue,(SL==true)?"Y":"N"),

                StringFormat("InpIlanTrailingStop=%s||false||0||true||N\n",(InpIlanTrailingStop==true)?"true":"false"),
                StringFormat("InpIlanDistanceTS=%d||0||1||10||N\n",InpIlanDistanceTS),
                StringFormat("MaxTrades=%d||0||1||10||N\n",MaxTrades),
                StringFormat("InpDeviation=%d||0||1||10||N\n",InpDeviation),

                StringFormat("bSTOFilter=%s||false||0||true||%s\n",(STOFilterValue==true)?"true":"false",(STOFilter==true)?"Y":"N"),
                StringFormat("bSTOTimeFrameFilter=%s||false||0||true||%s\n",(STOTimeFrameFilterValue==true)?"true":"false",(STOTimeFrameFilter==true)?"Y":"N"),
                StringFormat("InpMaxTf=%d||0||1||10||N\n",InpMaxTf));

      FileClose(filehandle);
     }
   else
     {
      Print("FileOpen BuddyIlanTester.set, error ",GetLastError());
      return false;
     }

   Sleep(1500);

   string PathTester=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\BuddyIlanTester.set";
   string PathProfile=sTerminalTesterDataPath+"\\MQL5\\Profiles\\Tester\\";

// Копируем файл ini в каталог тестера 
   int ret=ShellExecuteW(0,"Open","xcopy","\""+PathTester+"\" \""+PathProfile+"\" /y","",0);

// Дожидаемся копирования файла
   Sleep(2500);
   if(ret<32)
     {
      Print("Ошибка копирования файла параметров");
      return false;
     }
   return true;
  }


Запуск оптимизации

Следующая функция запускает тестерный экземпляр MetaTrader 5, при этом оптимизация начнется автоматически с указанными нами параметрами. Этот второй экземпляр сформирует файл с результатами, после чего терминал будет закрыт.

bool StartOptimizer()
  {
// Удаляем предыдущий отчет
   FileDelete("Optimiser\\BuddyIlanReport.xml");

// Удаляем предыдущий отчет (второй экземпляр MetaTrader 5)
   string PathReport=sTerminalTesterDataPath+"\\MQL5\\Files\\Reports\\BuddyIlanReport.xml";

   ShellExecuteW(0,"Open","cmd.exe"," /C del "+PathReport,"",0);

   Sleep(2500);

   string sTerminalPath=TerminalInfoString(TERMINAL_PATH);

// Запуск процесса оптимизации
   int start=ShellExecuteW(0,"Open",sTerminalTesterPath+"\\terminal64.exe","/config:"+TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\Optimiser\\optimise.ini","",0);
   if(start<32)
     {
      Print("Ошибка запуска Тестера");
      return false;
     }
   Sleep(15000);
   return true;
  }

Самый простой способ узнать об окончании оптимизации из первого терминала — проверить наличие файла отчета.

После создания файла отчета копируем его в рабочий каталог.

bool CopyReport()
  {
   int nTry=0;

// Ждем и копируем файл отчета

   while(nTry++<500) // Timeout: 2 часа
     {
      string PathReport = sTerminalTesterDataPath + "\\MQL5\\Files\\Reports\\BuddyIlanReport.xml";
      string PathTarget = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\Optimiser\\";

      int ret=ShellExecuteW(0,"Open","xcopy","\""+PathReport+"\" \""+PathTarget+"\" /y","",0);

      if(ret<32)
        {
         PrintFormat("Ожидание формирование отчета (%d) ...",nTry);
         Sleep(15000);
        }
      else
        {
         if(FileIsExist("Optimiser\\BuddyIlanReport.xml")==true)
           {
            PrintFormat("Найден отчет (ret=%d) ...",ret);
            Sleep(2500);
            return true;
           }
         else
           {
            PrintFormat("Ожидание отчета (%d) ...",nTry);
            Sleep(15000);
           }
        }
     }
   return false;
  }


Чтение результатов

Файл отчета создается в формате XML. К счастью, у нас есть библиотека для работы с такими данными, написанная Полом ван Хемменем, за что ему большая благодарность. Скачать библиотеку можно здесь: https://www.mql5.com/ru/code/1998.

Добавим эту библиотеку в наш советник:

#include <EasyXML\EasyXml.mqh>

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

//+------------------------------------------------------------------+
//| Load XML by given file                                           |
//+------------------------------------------------------------------+
bool CEasyXml::loadXmlFromFullPathFile(string pFilename)
  {
   string sStream;
   int    iStringSize;

   Print("Loading XML File ",pFilename);
   int hFile=FileOpen(pFilename,FILE_ANSI|FILE_READ,0,CP_UTF8);
   if(hFile==INVALID_HANDLE)
     {
      Err=EASYXML_ERR_CONNECTION_FILEOPEN;
      PrintFormat("[%s] Err=%d",pFilename,GetLastError());
      return(Error());
     }

   while(!FileIsEnding(hFile))
     {
      iStringSize = FileReadInteger(hFile, INT_VALUE);
      sStream    += FileReadString(hFile, iStringSize);
     }

   FileClose(hFile);

   return(loadXmlFromString(sStream));
  }

Доступ к данным организован довольно просто: несколько функций позволяют анализировать результаты и читать интересующие нас данные.

bool LoadResults( OptimisationType eType )
  {
// Переменная Init
   BetterProfit=0.0;

// Загрузка результатов
   CEasyXml EasyXmlDocument;
   EasyXmlDocument.setDebugging(false);

   if(EasyXmlDocument.loadXmlFromFullPathFile("Optimiser\\BuddyIlanReport.xml")==true)
     {
      str="";
      CEasyXmlNode *RootNode=EasyXmlDocument.getDocumentRoot();
      for(int j=0; j<RootNode.Children().Total(); j++)
        {
         CEasyXmlNode *ChildNode=RootNode.Children().At(j);
         for(int i=0; i<ChildNode.Children().Total(); i++)
           {
            CEasyXmlNode *cNode=ChildNode.Children().At(i);
            if(cNode.getName() == "Worksheet" )
              {
               switch(eType)
                 {
                  case _SL :
                     DisplayNodesSL(cNode);
                     PrintFormat("-> SL=%d (Profit=%.2lf)",BetterSL,BetterProfit);
                     break;

                  case _TP :
                     DisplayNodesTP(cNode);
                     PrintFormat("-> TP=%d (Profit=%.2lf DD=%lf)",BetterTP,BetterProfit,BetterDD);
                     break;

                  case _STO :
                     DisplayNodesSTO(cNode);
                     PrintFormat("-> STOFilter=%s STOTimeFrameFilter=%s (Profit=%.2lf)",(BetterSTOFilter==true)?"true":"false",(BetterSTOTimeFrameFilter==true)?"true":"false",BetterProfit);
                     break;
                 }
               break;
              }
           }
        }
     }
   else
      PrintFormat("Ошибка");
   return true;
  }

Поскольку нам надо оптимизировать несколько параметров и их результаты придется анализировать по-разному, нам нужна отдельная функция для каждой оптимизации (для параметров SL, TP и STO). Это рекурсивные функции.

Вот функция для анализа результатов оптимизации параметра SL:

void DisplayNodesSL( CEasyXmlNode *Node )
  {
   for(int i=0; i<Node.Children().Total(); i++)
     {
      CEasyXmlNode *ChildNode=Node.Children().At(i);

      if(ChildNode.Children().Total()==0)
        {
         str+=ChildNode.getValue()+",";
        }
      else
        {
         DisplayNodesSL(ChildNode);

         if(Node.getName()=="Table" && ChildNode.getName()=="Row")
           {
            string res[];
            StringSplit(str,',',res);

            // Обход заголовков столбцов
            if(StringCompare(res[0],"Pass",true)!=0)
              {
               double profit=StringToDouble(res[2]);
               int sl=(int) StringToInteger(res[10]);

               PrintFormat("[%s]  Profit=%.2lf StopLoss=%d DD=%s",str,profit,sl,res[8]);

               if(profit>BetterProfit || (profit==BetterProfit && sl<BetterSL))
                 {
                  BetterProfit=profit;
                  BetterSL=sl;
                 }
              }
           }
         if(Node.getName()=="Table")
            str="";
        }
     }
  }

Эта функция вызывается для каждой строки и ячейки.

Если у узла нет потомков, это означает, что он содержит данные — сохраняем эти данные в строковом типе, разделяем в конце строки.

if( ChildNode.Children().Total() == 0 )
  {
   str+=ChildNode.getValue()+",";
  }

Таким образом, значения для каждого столбца доступны в массиве "res[]", и мы можем выбрать желаемые результаты.


Тело советника

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

void OnTimer()
  {
   MqlDateTime dt;

   datetime now=TimeLocal(dt);

// В субботу
   if(dt.day_of_week!=6)
     {
      bOptimisationDone=false;
      return;
     }

// В 6:00
   if(dt.hour<6)
      return;

// Уже сделано?
   if(bOptimisationDone==true)
      return;

// Удаляем предыдущий файл "optimise.ini"
   FileDelete("Optimiser\\Optimise.ini");

// Создаем конфигурационный файл советника и копируем его в папку \MQL5\Profiles\Test (экземпляр для тестирования)
   if(CreateAndCopyParametersFile(true,false,false,false,0,0,true,false)==false)
      return;

// Копируем common.ini -> optimise.ini
   if(CopyAndMoveCommonIni()==false)
      return;

// Добавляем запуск [Tester] в optimise.ini - https://www.metatrader5.com/ru/terminal/help/start_advanced/start
   if(AddTesterStanza()==false)
      return;

   Print("=======================\nОптимизация SL-1");

// Запуск первой оптимизации SL
   StartOptimizer();

// Копируем файл отчета в рабочий каталог
   if(CopyReport()==false)
      return;

// Анализируем отчеты   
   if(LoadResults(_SL)==false)
      return;

   Print("=======================\nОптимизация STO");

// Создаем файл параметров для оптимизации STO (одновременно будут оптимизированы 2 параметра) 
   if(CreateAndCopyParametersFile(false,false,true,true,BetterSL,0,true,false)==false)
      return;

// Запуск оптимизации STO
   StartOptimizer();

// Копируем файл отчета в рабочий каталог
   if(CopyReport()==false)
      return;

   if(LoadResults(_STO)==false)
      return;

   Print("=======================\nОптимизация SL-2");

// Создаем файл параметров для оптимизации SL (пересчет с новыми значениями параметра STO)
   if(CreateAndCopyParametersFile(true,false,false,false,0,0,BetterSTOFilter,BetterSTOTimeFrameFilter)==false)
      return;

// Запуск оптимизатора   
   StartOptimizer();

   if(CopyReport()==false)
      return;

   if(LoadResults(_SL)==false)
      return;

   Print("=======================\nОптимизация TP");

// Создаем файл параметров для оптимизации TP
   if(CreateAndCopyParametersFile(false,true,false,false,BetterSL,0,BetterSTOFilter,BetterSTOTimeFrameFilter)==false)
      return;

// Запуск оптимизатора  
   StartOptimizer();

   if(CopyReport()==false)
      return;

   if(LoadResults(_TP)==false)
      return;

// Заключение

   PrintFormat("=======================\nSL=%d TP=%d STOFilter=%s STOTimeFrameFilter=%s (Profit=%.2lf DD=%lf)\n=======================",
               BetterSL,BetterTP,(BetterSTOFilter==true)?"true":"false",(BetterSTOTimeFrameFilter==true)?"true":"false",BetterProfit,BetterDD);

// Устанавливаем глобальные переменные - работающий советник BuddyIlan будет читать и использовать эти новые значения

// Если обнаружится просадка более 50%, советник остановит торговлю
   if(BetterDD>50.0 && GlobalVariableSet(gVarStop,1.0)==false)
     {
      PrintFormat("Ошибка установки глобальной переменной [%s]",gVarStop);
     }

   if(GlobalVariableSet(gVarSL,BetterSL)==false)
     {
      PrintFormat("Ошибка установки глобальной переменной [%s]=%d",gVarSL,BetterSL);
     }

   if(GlobalVariableSet(gVarTP,BetterTP)==false)
     {
      PrintFormat("Ошибка установки глобальной переменной [%s]=%d",gVarTP,BetterTP);
     }

   if(GlobalVariableSet(gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0)==false)
     {
      PrintFormat("Ошибка установки глобальной переменной [%s]=%.1lf",gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0);
     }

   if(GlobalVariableSet(gVarSTOTimeFrameFilter,(BetterSTOTimeFrameFilter==true)?1.0:0.0)==false)
     {
      PrintFormat("Ошибка установки глобальной переменной [%s]=%.1lf",gVarSTOTimeFrameFilter,(BetterSTOTimeFrameFilter==true)?1.0:0.0);
     }

   bOptimisationDone=true;
  }

Имена глобальных переменных создаются в функции OnInit():

int OnInit()
  {
//Глобальные переменные

   gVarStop="BuddyIlan."+_Symbol+".Stop";
   gVarSL = "BuddyIlan." + _Symbol + ".SL";
   gVarTP = "BuddyIlan." + _Symbol + ".TP";
   gVarSTOFilter="BuddyIlan."+_Symbol+".STOFilter";
   gVarSTOTimeFrameFilter="BuddyIlan."+_Symbol+".STOTimeFrameFilter";

Ниже показан весь процесс оптимизации:

2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_PATH = C:\Program Files\MetaTrader 5 - ActivTrades
2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_DATA_PATH = C:\Users\BPA\AppData\Roaming\MetaQuotes\Terminal\FE0E65DDB0B7B40DE125080872C34D61
2018.07.07 13:20:15.978 BuddyIlanOptimizer (EURGBP,M15) TERMINAL_COMMONDATA_PATH = C:\Users\BPA\AppData\Roaming\MetaQuotes\Terminal\Common
2018.07.07 13:20:32.586 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:20:32.586 BuddyIlanOptimizer (EURGBP,M15) Optimization SL-1
2018.07.07 13:20:50.439 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:21:05.699 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:21:20.859 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:21:35.952 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:21:38.471 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:21:38.486 BuddyIlanOptimizer (EURGBP,M15) [0,11032.2600,1032.2600,3.3406,1.7096,1.5083,0.1558,0,6.2173,309,500,]  Profit=1032.26 StopLoss=500 DD=6.2173
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [2,11463.8000,1463.8000,4.7837,2.0386,0.8454,0.1540,0,15.4222,306,1000,]  Profit=1463.80 StopLoss=1000 DD=15.4222
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [4,11444.1000,1444.1000,4.7348,2.0340,0.8340,0.1529,0,15.4493,305,1500,]  Profit=1444.10 StopLoss=1500 DD=15.4493
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [1,11297.1900,1297.1900,4.2392,1.8414,0.8180,0.1400,0,14.1420,306,750,]  Profit=1297.19 StopLoss=750 DD=14.1420
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) [3,11514.0800,1514.0800,4.9158,2.3170,1.4576,0.2055,0,9.3136,308,1250,]  Profit=1514.08 StopLoss=1250 DD=9.3136
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) -> SL=1250 (Profit=1514.08)
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:21:38.487 BuddyIlanOptimizer (EURGBP,M15) Optimization STO
2018.07.07 13:22:02.660 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:22:17.768 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:22:32.856 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:22:47.918 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ...
2018.07.07 13:23:02.982 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:23:05.485 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [0,11463.5000,1463.5000,4.4483,2.0614,0.8452,0.1540,0,15.4267,329,false,false,]  Profit=1463.50 false false  DD=15.4267
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [1,11444.1000,1444.1000,4.7348,2.0340,0.8340,0.1529,0,15.4493,305,true,false,]  Profit=1444.10 true false  DD=15.4493
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [2,11430.5300,1430.5300,5.1090,2.1548,0.8917,0.1717,0,14.4493,280,false,true,]  Profit=1430.53 false true  DD=14.4493
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) [3,11470.7100,1470.7100,6.2851,1.8978,0.8146,0.1288,0,17.3805,234,true,true,]  Profit=1470.71 true true  DD=17.3805
2018.07.07 13:23:05.499 BuddyIlanOptimizer (EURGBP,M15) -> STOFilter=true STOTimeFrameFilter=true (Profit=1470.71)
2018.07.07 13:23:05.500 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:23:05.500 BuddyIlanOptimizer (EURGBP,M15) Optimization SL-2
2018.07.07 13:23:29.921 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:23:45.043 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:24:00.170 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:24:15.268 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ...
2018.07.07 13:24:30.340 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:24:32.854 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [0,9269.9000,-730.1000,-2.7760,0.7328,-0.3644,-0.0532,0,19.4241,263,500,]  Profit=-730.10 StopLoss=500 DD=19.4241
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [4,11470.7100,1470.7100,6.2851,1.8978,0.8146,0.1288,0,17.3805,234,1500,]  Profit=1470.71 StopLoss=1500 DD=17.3805
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [3,11475.9500,1475.9500,6.2806,1.8995,0.8175,0.1290,0,17.3718,235,1250,]  Profit=1475.95 StopLoss=1250 DD=17.3718
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [2,11400.7500,1400.7500,5.8609,1.8442,0.7759,0.1292,0,17.3805,239,1000,]  Profit=1400.75 StopLoss=1000 DD=17.3805
2018.07.07 13:24:32.872 BuddyIlanOptimizer (EURGBP,M15) [1,10662.5500,662.5500,2.8807,1.3618,0.3815,0.0862,0,16.7178,230,750,]  Profit=662.55 StopLoss=750 DD=16.7178
2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) -> SL=1250 (Profit=1475.95)
2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:24:32.873 BuddyIlanOptimizer (EURGBP,M15) Optimization TP
2018.07.07 13:24:57.175 BuddyIlanOptimizer (EURGBP,M15) Waiting report (1) ...
2018.07.07 13:25:12.311 BuddyIlanOptimizer (EURGBP,M15) Waiting report (2) ...
2018.07.07 13:25:27.491 BuddyIlanOptimizer (EURGBP,M15) Waiting report (3) ...
2018.07.07 13:25:42.613 BuddyIlanOptimizer (EURGBP,M15) Waiting report (4) ...
2018.07.07 13:25:57.690 BuddyIlanOptimizer (EURGBP,M15) Report found (ret=42) ...
2018.07.07 13:26:00.202 BuddyIlanOptimizer (EURGBP,M15) Loading XML File Optimiser\BuddyIlanReport.xml
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [1,11768.5700,1768.5700,8.2259,2.4484,1.1024,0.2233,0,14.1173,215,40,]  Profit=1768.57 TakeProfit=40 DD=14.117300
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [4,12343.5200,2343.5200,13.5464,2.5709,1.3349,0.2519,0,15.0389,173,70,]  Profit=2343.52 TakeProfit=70 DD=15.038900
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [0,11243.4600,1243.4600,5.2913,1.6399,0.6887,0.1039,0,17.3805,235,30,]  Profit=1243.46 TakeProfit=30 DD=17.380500
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [3,12292.3500,2292.3500,11.8162,2.5837,0.9257,0.2538,0,20.4354,194,60,]  Profit=2292.35 TakeProfit=60 DD=20.435400
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) [2,12146.3900,2146.3900,11.0639,2.4416,1.2226,0.2292,0,15.0772,194,50,]  Profit=2146.39 TakeProfit=50 DD=15.077200
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) -> TP=70 (Profit=2343.52 DD=15.038900)
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) =======================
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) SL=1250 TP=70 STOFilter=true STOTimeFrameFilter=true (Profit=2343.52 DD=15.038900)
2018.07.07 13:26:00.219 BuddyIlanOptimizer (EURGBP,M15) =======================


Заключение

Для реализации этого процесса нужны минимальные знания терминала MetaTrader 5, его механизмов оптимизации и программирования.

К статье приложены исходные коды этого советника, утилита XML Parser от Пола ван Хеммена и измененный файл "EasyXml.mqh".

Надеюсь, статья окажется для вас полезной.

Перевод с английского произведен MetaQuotes Software Corp.
Оригинальная статья: https://www.mql5.com/en/articles/4917

Прикрепленные файлы |
Files.zip (14.39 KB)
Dimitri Wagner
Dimitri Wagner | 28 окт 2018 в 08:46
Статья использует DLL для работы функции ShellExecuteW. Насколько это опасно? Можно ли сделать всё это без DLL?
Vitaly Muzichenko
Vitaly Muzichenko | 28 окт 2018 в 09:36
dimok_w74:
Статья использует DLL для работы функции ShellExecuteW. Насколько это опасно? Можно ли сделать всё это без DLL?

Опасно ровно на столько, сколько опасности несёт само использование систем Windows

Реализация Take Profit в виде лимитных ордеров без изменения оригинального кода советника Реализация Take Profit в виде лимитных ордеров без изменения оригинального кода советника

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

100 лучших проходов оптимизации (Часть 1). Cоздание анализатора оптимизаций 100 лучших проходов оптимизации (Часть 1). Cоздание анализатора оптимизаций

В данной статье я расскажу, как создать приложение для отбора лучших проходов оптимизаций по нескольким возможным вариантам. Данное приложение умеет фильтровать и сортировать оптимизационные результаты по множеству коэффициентов. Проходы оптимизации записываются в базу данных, поэтому вы всегда можете отобрать новые параметры робота без необходимости переоптимизирования. Вдобавок ко всему это позволяет увидеть все проходов оптимизации на едином графике, рассчитывать параметрические VaR коэффициенты и строить график нормального распределения проходов и результатов торговли конкретного выделенного варианта сочетания коэффициентов. Также строятся графики некоторых из рассчитываемых коэффициентов в динамике, начиная с момента старта оптимизации (или с выбранной даты до другой выбранной даты).

Гэп - доходная стратегия или 50/50? Гэп - доходная стратегия или 50/50?

Исследование явления гэпа — ситуации существенной разницы между ценой закрытия предыдущего таймфрейма и ценой открытия следующего, и в какую сторону пойдёт дневной бар. Применение системной DLL функции GetOpenFileName.

Разворотные паттерны: Тестируем паттерн "Двойная вершина/дно" Разворотные паттерны: Тестируем паттерн "Двойная вершина/дно"

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