
自动优化 MetaTrader 5 专用 EA
概述
我们的 BuddyIlan EA 用到了 4 个主要参数,我们希望能够每周自动优化,以便更好地适应行情变化。
这些参数是:
- SL,
- TP,
- STOFilter,
- STOTimeFrameFilter.
每周手工启动这类流程是不现实的,因此我们尝试寻找现有的机制来执行这类重复性任务,但没有成功(针对 MetaTrader 5),因此我们自行开发了一个。
感谢 Igor Malcev 为 MetaTrader 4 撰写的文章“在真实交易中自动优化交易机器人”。
原理
第一个 MetaTrader 5 实例 7 天 24 小时运行,该实例托管 BuddyIlan EA 以及我们今天将在其上工作的 EA(优化器 EA),并在第二个 MetaTrader 5 实例上启动优化过程。
在流程结束时,优化器 EA 将在全局变量中设置优化值,这些值将由正在运行的 Buddy Ilan EA 读取。
优化日程安排在每周六,无需任何人工干预。
复制数据
如上所述,我们需要两个 MetaTrader 5 实例。
第一个 MetaTrader 5 实例负责在两个实例之间复制配置、参数和报告文件。
出于安全原因,在 MetaTrader 5 下无法访问沙箱外的文件,因此我们将使用 DOS 命令“xcopy” 在两个环境之间复制数据。
为此,我们需要使用 Windows 架构的 DLL,我们将按如下方式声明:
#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("Failed starting Tester"); return false; }
必须为此 EA 授权 DLL 导入:
自动优化
MetaTrader 5 可以通过命令行启动(参见:如何启动交易平台),也可以通过这种方式启动自动任务。
例如,您可以在默认配置文件(common.ini)中添加“[Tester]”部分,以便在 MetaTrader 5 启动时开始自动优化。
这就是我们要做的。
实现
优化器 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()”复制 MetaTrader 5 测试器实例的默认配置文件“common.ini”,并将其重命名为“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("Failed copying ini file"); return false; } // 我们现在正在沙箱中工作,我们可以正常使用 MetaTrader 5 文件命令 string IniFileName="Optimiser\\common.ini"; string CopyTo="Optimiser\\optimise.ini"; return FileMove( IniFileName, 0, CopyTo, 0 ); }
若对此感兴趣,可以在以下地址找到有关“ShellExecuteW”函数的更多信息:ShellExecuteW。 此函数不等待 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”) - 这个 EA 必须存在于第二个环境中 - 并且 ExpertParameters 文件为“BuddyIlanTester.set”(注意不要使用与您的 EA 相同的名称),我们设置周期(FromDate - ToDate)和优化所需的所有参数。
我们设置“ShutdownTerminal = 1”,这意味着终端将在优化结束时关闭。
报告将在文件“Files\Reports\BuddyIlanReport”中生成 - “.xlm”扩展名将由平台添加。
如果运行的 EA 位于 CPU 资源较低的虚拟服务器上,则可以使用某些远程或云代理(请参阅“UseRemote”或“UseCloud”)运行优化过程。
参数文件
然后我们必须创建上面定义的参数文件(BuddyIlanTester.set),其中包含我们想要优化的 EA(BuddyIlan)的每个参数值。
这些参数的默认值由用户设置(定义为参数):
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”。 以下 4 个参数对应于我们希望在下一次优化期间要参考的已优化值。
正如其名称所示,此函数还将参数文件复制到 MetaTrader 5 测试器实例的 ad hoc 目录(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 文件复制到 tester 文件夹中 int ret=ShellExecuteW(0,"Open","xcopy","\""+PathTester+"\" \""+PathProfile+"\" /y","",0); // 等到文件复制完成 Sleep(2500); if(ret<32) { Print("Failed copying parameters file"); 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("Failed starting Tester"); return false; } Sleep(15000); return true; }
从第一个 MetaTrader 5 实例中,检测优化是否完成的最简单方法是检查报告文件是否存在。
生成报告文件后,我们将其复制到我们的工作目录中。
bool CopyReport() { int nTry=0; // 等待并复制报告文件 while(nTry++<500) // 超时 : 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("Waiting generation report (%d) ...",nTry); Sleep(15000); } else { if(FileIsExist("Optimiser\\BuddyIlanReport.xml")==true) { PrintFormat("Report found (ret=%d) ...",ret); Sleep(2500); return true; } else { PrintFormat("Waiting report (%d) ...",nTry); Sleep(15000); } } } return false; }
读取结果
报告文件是 XML 格式。 幸运的是,Paul van Hemmen 已为 MetaTrader 5 编写了一个函数库来访问此类数据,该函数库可在以下地址获得:https://www.mql5.com/zh/code/1998 - 多谢他的贡献。
我们在 EA 中添加此函数库如下:
#include <EasyXML\EasyXml.mqh>
实际上,我们在下面添加了这个函数并修改了一些小地方以便令其适应我们的报告文件(参见附件)。
//+------------------------------------------------------------------+ //| 加载给定的 XML 文件 | //+------------------------------------------------------------------+ 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 ) { // 初始化变量 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("Error found"); 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[]”中可用,我们从中选择我们想要的结果。
EA 实体
我们现在拥有优化 4 个参数所需的所有模块,推导出最佳参数,并设置相应全局变量的值,这些变量将由正在运行的 BuddyIlan EA 读取。
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"); // 创建 EA 配置文件并将其复制到 \MQL5\Profiles\Test(测试器实例) if(CreateAndCopyParametersFile(true,false,false,false,0,0,true,false)==false) return; // 复制 common.ini -> optimise.ini if(CopyAndMoveCommonIni()==false) return; // 在 optimise.ini 里添加 [Tester] 部分- https://www.metatrader5.com/en/terminal/help/start_advanced/start if(AddTesterStanza()==false) return; Print("=======================\nOptimization SL-1"); // 开始第一次优化止损 StartOptimizer(); // 将报告文件复制到工作目录 if(CopyReport()==false) return; // 分析报告 if(LoadResults(_SL)==false) return; Print("=======================\nOptimization 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("=======================\nOptimization 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("=======================\nOptimization 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 EA 将读取并使用这些新值 // 如果发现回撤超过 50%,EA 停止交易 if(BetterDD>50.0 && GlobalVariableSet(gVarStop,1.0)==false) { PrintFormat("Error setting Global Variable [%s]",gVarStop); } if(GlobalVariableSet(gVarSL,BetterSL)==false) { PrintFormat("Error setting Global Variable [%s]=%d",gVarSL,BetterSL); } if(GlobalVariableSet(gVarTP,BetterTP)==false) { PrintFormat("Error setting Global Variable [%s]=%d",gVarTP,BetterTP); } if(GlobalVariableSet(gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0)==false) { PrintFormat("Error setting Global Variable [%s]=%.1lf",gVarSTOFilter,(BetterSTOFilter==true)?1.0:0.0); } if(GlobalVariableSet(gVarSTOTimeFrameFilter,(BetterSTOTimeFrameFilter==true)?1.0:0.0)==false) { PrintFormat("Error setting Global Variable [%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 优化机制和编程知识。
附件是此 EA 的源代码,Paul van Hemmen 的 XML 解析器文件和修改后的“EasyXml.mqh”文件。
希望这有所帮助。
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/4917
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.



你好@布鲁诺-波莱
我想问两件事
首先是关于这句话、
we define the Expert we want to optimize ("BuddyIlan") - this EA must be present in the second environment
我是否需要将 EA 放在指定位置?
第二,每当 EA 测试器启动时,它会立即关闭,我该如何解决这个问题?
如果我将 Python 脚本转换为 DLL 呢?