English Русский Español Deutsch 日本語 Português
自动优化 MetaTrader 5 专用 EA

自动优化 MetaTrader 5 专用 EA

MetaTrader 5测试者 | 23 十月 2018, 10:15
5 940 2
BPASoftware Thai Co. Ltd
Bruno Paulet

概述

我们的 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 导入:

DLL Import


自动优化

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

附加的文件 |
Files.zip (14.39 KB)
最近评论 | 前往讨论 (2)
Zhiqiang Zhu
Zhiqiang Zhu | 10 6月 2019 在 10:34
MetaQuotes Software Corp.:

新文章 自动优化 MetaTrader 5 专用 EA已发布:

作者:BPASoftware Thai Co. Ltd

优化的前提是,过去可以代表未来,如果这个前提不成立,那,再多的优化,只是数据拟合而已!对未来没有任何意义!

那,过去的价格,K线,任何事物,能够在未来又重新出现吗·?简单的举例:前一周的某一天价格到达RSI指标的日周期25的值,随后反弹了。

这周的某一天也到达了25的值,同样反弹了吗?结果没有反弹,继续下探到15,才反弹。所以真正市场的价格跳动,都不会简单的历史重复。

即时人的行为是简单的重复,反映到价格图上也不会简单的与历史一模一样。

结论:

重复的优化,有可能在一段时间内好像有效。但长期来看,就是个陷阱。而且一直循环下去,特别在价格波动走出与历史不同的走势后,优化将失去有效化!比如:

震荡走向趋势,趋势走向震荡,行情变化时,优化是无效的。更可拍的是,行情一直处于变化,无可预测的结构下的。

dongzz
dongzz | 20 4月 2020 在 15:42

我认为都是概率问题。拟合以后的参数,大概率会更好适应未来。

根据指定的分布法则为自定义品种的时间序列建模 根据指定的分布法则为自定义品种的时间序列建模
本文概述终端创建和运用自定义品种的能力,提供了使用自定义品种模拟交易历史、趋势和各种图表形态的选项。
反向交易: 圣杯还是危险的假象 反向交易: 圣杯还是危险的假象
在这篇文章中,我们将会学习反向马丁格尔技术,并且将会了解是否值得使用它,以及它是否有助于提高您的交易策略。我们将会创建一个 EA 交易来在历史数据上运行, 检查哪个指标是最适合于反向交易技术的 。我们还将验证是否可以不使用任何指标,以独立的交易系统来使用它。另外,我们还将验证反向交易是否可以把一个亏损系统转变为盈利的系统。
100 个最佳优化递次(第 1 部分)。 开发优化分析器 100 个最佳优化递次(第 1 部分)。 开发优化分析器
本文详细阐述了运用若干种可能选项开发选择最佳优化递次的应用程序。 该应用程序能够通过各种因素来筛选优化结果。 优化递次始终写入数据库,因此您总能无需重新优化即可选择新的机器人参数。 此外,您可在单个图表上查看所有优化递次,计算参数 VaR 比率,并构建递次与特定比率集和的交易结果的正态分布图。 以及,自优化伊始(或从选定日期到另一个选定日期)开始动态构建一些计算比率的图形。
利用指标实时优化智能交易系统 利用指标实时优化智能交易系统
任何交易机器人的效率均取决于正确选择(优化)其参数。 然而,在某个时间区间内被认为是最佳的参数可能无法在另一个交易历史区间保持其有效性。 此外,在测试期间表现良好的 EA 在实时状态下最终会亏损。 持续优化的问题就此凸显出来。 当面对大量重复性工作时,人类总会寻找自动化方法。 在本文中,我提出了一种解决此问题的非标准方法。