Автоматическая оптимизация советника в MetaTrader 5
Введение
В нашем советнике 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:
Автоматическая оптимизация
Платформу 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 Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/4917
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Статья использует DLL для работы функции ShellExecuteW. Насколько это опасно? Можно ли сделать всё это без DLL?
Опасно ровно на столько, сколько опасности несёт само использование систем Windows
Не запускается
imported DLL "shell32.dll" not allowed in Cloud Network