English Русский Español Deutsch 日本語 Português
交易机器人在实际交易中的自动优化

交易机器人在实际交易中的自动优化

MetaTrader 4测试者 | 26 二月 2016, 11:34
3 588 0
Igor Malcev
Igor Malcev

简介

据推测,获得已根据历史记录调整的输入的 Expert Advisor 在首次(在相当短的时间内)交易中能够盈利。在我观看2006 自动交易锦标赛之后,这一推测得到了间接的证明。锦标赛刚开始时能盈利的智能交易系统很多,之后就大大减少,一些智能交易系统变得毫无竞争力。这就是我认为这些没能笑到最后的智能交易系统大部分都根据历史记录进行过调整的原因。

在实践中验证这一假设的想法源于此网站的俄语论坛中的理想的自动交易系统版块。主要的想法是每天自动优化一次 EA,然后分析获得的优化结果,并将它们记录到 EA 的变量中。

为了实施这一想法,我们决定采用 MetaTrader 4 客户终端中的现成 Expert Advisor(即 MACD 样本),并把我们自己的自动优化函数插入到该 Expert Advisor 中。稍后,该自动优化器的代码就编写完毕并上传到同一论坛中的自动优化器版块中。再过了一段时间,自动优化器的子版块中出现了对该想法的第一条确认消息。后来,此优化器被转变为一个 mqh 库以提高其可用度。


安装自动优化程序

以下是执行此任务的必要流程:

  • 将 MACD Sample_1.mq4 复制到已初步安装并连接到互联网的 MetaTrader 4 客户终端的“expert”文件夹中;并
  • 将该文件夹与已安装的 MetaTrader 4 客户终端一同复制到一个新位置上。

为方便起见,下文中我们将把原始终端称为“终端”,将副本称为“终端测试程序”。我们将使用起初由终端提供,后经略微更改的 Expert Advisor(MACD Sample_1.mq4)对时间范围 H1 内的 EURUSD 执行一次检查性测试。

终端测试程序

请勿忘记在终端测试程序中编译 MACD Sample_1.mq4。首先我们启动客户终端,然后启动策略测试程序,并按下方的屏幕截图进行设置。


优化将执行三天。这已足够检查自动优化程序了。我们将根据以下公式选择优化日期“开始日期”:当前日期减去三天。优化期间,必须下载选定交易品种(本案例中为 EURUSD)的必要历史记录。


首次执行优化的用户会在 MetaTrader 4 客户终端的“帮助”菜单中找到必要程序的说明:<帮助 - 帮助主题 F1 - 自动交易 - Expert 优化 - 设置>。或者可以阅读文章在 MetaTrader 4 客户终端中测试 Expert Advisor:外部一览


然后我们检查要优化的变量,如下方屏幕截图中所示。



自动优化仅限四个变量,不过用三个变量就足以达成我们的目的了,还能节省时间。选择这些变量后,将优化设置存储到名为 MACD Sample_1.set 的设置文件中。此文件必须保存到终端测试程序的“测试程序”文件夹内。然后启动预优化并记住开始时间。必须计算使用预设参数进行自动优化所需的时间。完成优化后,我们将计算必要的等待时间。然后必须关闭此终端,否则我们将无法用程序启动它。

终端中 Expert Advisor 的设置

要进行设置,让我们在 MetaEditor 中打开测试用 Expert Advisor MACD Sample_1.mq4,然后执行以下步骤:

- 设置自动优化的启动时间,例如设在每天的 00:01:
datetime SetHour    = 0;  // Optimization starting hour; 
datetime SetMinute  = 1;  // Optimization starting minute.

- 设置进行优化的天数(必须与预优化的设置天数相同):

int TestDay = 3;

- 设置我们之前计算出的优化结束等待时间(以分钟为单位),例如 4 分钟:

int TimeOut = 4;

- 键入 Expert Advisor 名称:

string NameMTS = "MACD Sample_1";  // EA's name

- 键入设置文件名称和设置:

// Set-file name with the settings
string NameFileSet = "MACD Sample_1.set";

- 键入包含已安装终端测试程序的文件夹路径,例如:

// Path to the tester        
string PuthTester = "D:\Program Files\Forex Best Trade Station";

- 设置过滤优先级:

// Sorting by Maximal profit
int Gross_Profit = 1;                      
// Sorting by Maximal profit factor        
int Profit_Factor = 2;     
// Sorting by Maximal expected payoff
int Expected_Payoff = 3;

- 写入用于优化的变量名称:

string Per1 = "FastEMA";
string Per2 = "SlowEMA";
string Per3 = "SignalSMA";
string Per4 = "";

- 将随附文件 auto_optimization.mqh 复制到“include”文件夹中;
- 在 Expert Advisor 中包括此库文件:

//--- Including the auto optimizer's library
#include <auto_optimization.mqh>

- 剩下的就是将下方的代码复制到您 Expert Advisor 的 start() 函数的开头。MACD Sample_1.mq4 中已包含该代码。


// Not to be launched at testing and optimizing   
  if(!IsTesting() && !IsOptimization())
    {                
      // Compare the current hour with that preset for launching
      if(TimeHour(TimeLocal()) == SetHour)
        {
          // Protection against restarting
          if(!StartTest)
            {
              // Compare the minute range to the minute
              // preset for launching
              if(TimeMinute(TimeLocal()) > SetMinute - 1)
                {     
                  // the range is necessary, in case that for some reasons 
                  // no new tick is available for a long time
                  if(TimeMinute(TimeLocal()) < SetMinute + 1)
                    {  
                      // Flag of tester launching
                      StartTest    = true;
                      TimeStart    = TimeLocal();
                      Tester(TestDay, NameMTS, NameFileSet, PuthTester, 
                             TimeOut, Gross_Profit, Profit_Factor, 
                             Expected_Payoff, Per1, Per2, Per3, Per4);
                    
                    }
                }
            }
        }
    }
    
                        
   FastEMA      = GlobalVariableGet(Per1);
   SlowEMA      = GlobalVariableGet(Per2);
   SignalSMA    = GlobalVariableGet(Per3);
   TrailingStop = GlobalVariableGet(Per4);  
// If the tester launching is flagged  
  if(StartTest)
    {                                        
      // If more time has elapsed the launching than it was set 
      // to be the test waiting time
      if(TimeLocal() - TimeStart > TimeOut*60)
        {            
          // Zeroize the flag
          StartTest = false;                              
        }
    }

这就完成了。重新编译自动优化程序之后可以启动它,但它仅适用于执行预优化时所用的交易品种和时间范围。在我们的案例中,是 H1 时间范围上的 EURUSD 交易品种。要检查自动优化程序,可将下方给出的代码插入到 int init () 函数中,之后将在 Expert Advisor 启动时启动自动优化程序。

Tester(TestDay,NameMTS,NameFileSet,PuthTester,TimeOut, Gross_Profit,Profit_Factor, 
       Expected_Payoff, Per1,Per2,Per3,Per4);

自动优化程序如何工作

自动优化程序的工作原理是使用终端测试程序在终端中优化连接到图表的 Expert Advisor 的参数。为此,程序向终端测试程序发送一个包含优化参数 (optimise.ini) 的文件,并在优化模式下启动终端测试程序。然后,它将获取的结果 "FileReport........htm" 复制回终端,从获取的结果中筛选最佳值。



有关自动优化程序如何工作的更多详情

在预设时间(例如 00.01),自动优化程序应会启动。变量应填写值。

// Path to the terminal 
string PuthTerminal = TerminalPath() + "\experts\files";
// Name of the ini file for the tester
string FileOptim    = "optimise.ini";
string FileOptim1   = "\optimise.ini";                                  
// Calculation of the starting date
datetime DayStart   = TimeLocal()-86400*TestDay;
// Optimization starting date
string DateStart    = TimeToStr(DayStart,TIME_DATE);
// Optimization ending date
string DateStop     = TimeToStr(TimeLocal(),TIME_DATE);
// Tester report file name
string FileReport   = "FileReport_" + Symbol() + "_" + DateStop + ".htm";
string FileReport1  = "\FileReport_" + Symbol() + "_" + DateStop + ".htm";
// Limitation for the minimum amount of trades per day
double MinTr        = TestDay - 2;
// Limitation for maximal amount of trades per day
double MaxTr        = (60 / Period()*TestDay) + 2;
// The amount of attempts to copy the report file
int    KvoPptk      = 10;
// The amount of lines for sorting
int    StepRes      = 12;

然后在字符串数组中写入 ini 文件的参数:

// Prepare the ini file for optimization
ArrayOpttim[0] = ";optimise strategy tester";             
// Enable/Disable Expert Advisors
ArrayOpttim[1] = "ExpertsEnable = false";
// Name of the EA file
ArrayOpttim[2] = "TestExpert=" + NameMTS;
// Name of the file containing parameters
ArrayOpttim[3] = "TestExpertParameters=" + NameFileSet;
// Symbol
ArrayOpttim[4] = "TestSymbol=" + Symbol();
// Timeframe
ArrayOpttim[5] = "TestPeriod=" + Period();
// Modeling mode
ArrayOpttim[6] = "TestModel=" + 0;
// Recalculate
ArrayOpttim[7] = "TestRecalculate=false";
// Optimization
ArrayOpttim[8] = "TestOptimization=true";
// Use date
ArrayOpttim[9] = "TestDateEnable=true";
// From
ArrayOpttim[10] = "TestFromDate=" + DateStart;
// To
ArrayOpttim[11] = "TestToDate=" + DateStop;
// Report file name
ArrayOpttim[12] = "TestReport=" + FileReport;
// Rewrite the report file
ArrayOpttim[13] = "TestReplaceReport=true";
// Shut down the terminal upon completion
ArrayOpttim[14] = "TestShutdownTerminal=true";

从数组中将优化参数记录到 ini 文件中。也可阅读 MetaTrader 4 客户终端“帮助”中有关如何创建 ini 文件的内容,详见 <帮助 - 帮助主题 F1 - 工具 - 启动时的配置>。

// Write data into the ini file                
// Find out about the array size
OptimArraySize = ArraySize(ArrayOpttim);
// Open a file to write
opttim = FileOpen(FileOptim, FILE_CSV|FILE_WRITE, 0x7F);
if(opttim > 0)
  {
    for(int i = 0; i < OptimArraySize; i++)
      {
        // from the array into the variable
        ini = ArrayOpttim[i];                                     
        // from the variable into the file
        FileWrite(opttim, ini);
      } 
    // close the file
    FileClose(opttim);
  }
else
  {
    Print("Failed writing data into the ini file. Error No ", 
          GetLastError());
    return(0);
  }

将参数记录到 ini 文件后,连接 Windows 标准交付内容中包含的 shell32.dll,并启动函数 ShellExecuteA。

#import  "shell32.dll"               //Connect a dll (provided with Windows)       
  int ShellExecuteA(int hwnd,string Operation,string File,string Parameters,string Directory,int ShowCmd); 
#import

包含这些参数的文件将被发送到“终端测试程序”文件夹中。

// copy the ini file into the tester folder 
copyini = ShellExecuteA(0,"Open","xcopy", "\"" + PuthTerminal + 
                        FileOptim1 + "\" \"" + PuthTester + "\" /y", 
                        "", 3);
// wait until the file is copied
Sleep(1200);                                                    
if(copyini < 0)
  {
    Print("Failed copying ini file");
    return(0);
  }

然后启动测试程序,开始优化预定义变量。优化期间,Expert Advisor 处于暂停状态。

// Start Tester 
start = ShellExecuteA(0, "Open", "terminal.exe", FileOptim,
                      PuthTester, 3);
if(start < 0)
  {
    Print("Failed starting Tester");
    return(0);
  }
Comment("Wait until optimization is complete");
// wait until optimization is complete
Sleep(60000*TimeOut);

优化完成后,测试程序将自动把结果记录到报告文件中。该文件将被复制到包含终端的文件夹中。

for(Pptk = 0; Pptk < KvoPptk; Pptk++)
  {                    
    //Start a cycle attempting to compy the resport file
    Comment("Attempt # " + Pptk + " to copy the report file");
    ShellExecuteA(0, "Open", "xcopy", "\"" + PuthTester + FileReport1 + 
                  "\" \"" + PuthTerminal + "\" /y", "", 3);
    // wait until the file is copied
    Sleep(1200);
    // Try to open the report file
    file = FileOpen(FileReport, FILE_READ, 0x7F);
    if(file < 0)
      {
        // if it fails to open, wait some more and try again
        Sleep(60000);
      }                    
    else 
        break;             
  }
if(file < 0)
  {
    Print("Failed copying the report file");
    return(0);
  }

然后该报告文件中的数据将被放到字符串数组中,进行进一步的处理。

// Read from file into the array
// Cycle, until the file ends
while(FileIsEnding(file) == false)
  {                 
    // Read a string from the report file
    FileLine = FileReadString(file);
    // Find the necessary string and set the reference point there
    index = StringFind(FileLine, "title", 20);
    if(index > 0)
      {
        // Increase the array in size
        ArrayResize(ArrayStrg, NumStr + 1);
        // Record the strings from the file in the array
        ArrayStrg[NumStr] = FileLine;
        NumStr++;
      }
  }
// Close the file
FileClose(file);
// Delete the file in order not to produce too many copies
FileDelete(FileReport);
// Set the array size by the amount of data read from the file
ArrayResize(ArrayData, NumStr);

之后,在数组中选择必要的值:

for(text = 0; text < NumStr; text++)
     {
      select = ArrayStrg[text]; 
    //-------------------------------------------------------------------------
    //   Reporting text processing (These are apples and oranges)              | 
    //-------------------------------------------------------------------------
    // Position Pass 
    ClStep=StringFind(select, "; \">",20)+4;
    // Find the end of position
    ClStepRazm = StringFind(select, "td>", ClStep);
    // Read the value
    CycleStep = StringSubstr(select, ClStep, ClStepRazm - ClStep);
    // Position Profit 
    // Find the beginning of the position
    GrProf = StringFind(select, "", ClStepRazm);
    // Find the end of position
    GrProfRazm = StringFind(select, "td>", GrProf);
    // Read value
    GrossProfit = StringSubstr(select, GrProf+4, GrProfRazm - (GrProf + 4));
    // Position Total Trades
    // Find the beginning of position
    TotTrad = StringFind(select, "", GrProfRazm);
    // Find the end of position
    TotTradRazm = StringFind(select, "td>", TotTrad);
    // Read the value
    TotalTrades = StringSubstr(select, TotTrad+4, TotTradRazm - 
                               (TotTrad + 4));
    // Position Profitability
    // Find the beginning of position
    ProfFact = StringFind(select, "", TotTradRazm);
    // Find the end of position
    ProfFactRazm = StringFind(select, "td>", ProfFact);
    // Read the value
    ProfitFactor = StringSubstr(select, ProfFact + 4, ProfFactRazm - 
                                (ProfFact + 4));
    // Position Expected Payoff 
    // Find the beginning of position
    ExpPay = StringFind(select, "", ProfFactRazm);
    // Find the dn of position
    ExpPayRazm=StringFind(select, "td>", ExpPay);
    // Read the value
    ExpectedPayoff = StringSubstr(select, ExpPay+4, ExpPayRazm - 
                                  (ExpPay + 4));
    // Variables' positions starting with the second one
    // Find the beginning of position
    P1 = StringFind(select, Per1, 20);
    // Find the end of position
    P1k = StringFind(select, ";", P1);
    // Read the Variable
    Perem1 = StringSubstr(select, P1 + StringLen(Per1) + 1, P1k - 
                          (P1 + 1 + StringLen(Per1)));
    // Find the beginning of position
    P2 = StringFind(select, Per2, 20);
    // Find the end of position
    P2k = StringFind(select, ";", P2); 
    // Read the Variable
    Perem2 = StringSubstr(select, P2 + StringLen(Per2) + 1, P2k - 
                          (P2 + 1 + StringLen(Per2)));
    // Find the beginning of position
    P3 = StringFind(select, Per3, 20);
    // Find the end of position
    P3k = StringFind(select, ";", P3);
    // Read the Variable
    Perem3 = StringSubstr(select, P3 + StringLen(Per3) + 1, P3k - 
                          (P3 + 1 + StringLen(Per3)));
    // Find the beginning of position
    P4 = StringFind(select, Per4, 20);
    // Find the end of position
    P4k = StringFind(select, ";", P4);
    // Read the Variable 
    Perem4 = StringSubstr(select, P4 + StringLen(Per4) + 1, P4k - 
                          (P4 + 1 + StringLen(Per4)));
    Comment("The obtained results are being analyzed");

之后,获取的结果在被转变为数字格式之前,已按最小和最大交易金额进行了筛选。Profit_Factor 值中的 0 替换为 1000,以便进行正确的排序和后续的筛选。

// Transform into number format
TotalTradesTransit = StrToDouble(TotalTrades);
GrossProfitTransit = StrToDouble(GrossProfit);
ExpectedPayoffTran = StrToDouble(ExpectedPayoff);
nodubl = true;
if(MinTr < TotalTradesTransit && MaxTr > TotalTradesTransit)
  {                    
    // Filter by the amount of trades
    PrFactDouble = StrToDouble(ProfitFactor);
    // Replace 0 in the Profit_Factor for proper analysis
    if(PrFactDouble == 0)
      {
        PrFactDouble = 1000;
      }

然后检查这些值,以进行复制和筛除。

// Filter data having identical values
for(Dubl = 0; Dubl <= ResizeArayNew; Dubl++)
  {                    
    // Start the loop searching for identical values
    if(GrossProfitTransit == ArrayData[Dubl][1])
      {          
        // check whether the results for maximal profit coincide
        if(TotalTradesTransit == ArrayData[Dubl][2])
          {       
            // check whether the results for the amount of trades coincide
            if(PrFactDouble == ArrayData[Dubl][3])
              {          
                // check whether the results for Profit Factor coincide
                if(ExpectedPayoffTran == ArrayData[Dubl][4])
                  { 
                    // check whether the results for expected payoff coincide
                    nodubl=false;                              
                    // If everything coincides, flag it as coincided
                  }
              }
          }
      }
  }

在数组中写入用于排序的值。

// Write the filtered data in the array
if(nodubl)
  {
    ArrayData[text][1] = GrossProfitTransit;                                
    ArrayData[text][2] = TotalTradesTransit;
    ArrayData[text][3] = PrFactDouble;
    ArrayData[text][4] = ExpectedPayoffTran;
    ArrayData[text][5] = StrToDouble(Perem1);
    ArrayData[text][6] = StrToDouble(Perem2);
    ArrayData[text][7] = StrToDouble(Perem3);
    ArrayData[text][8] = StrToDouble(Perem4);
    ResizeArayNew++; 
  }

然后开始以预设优先顺序分析数据。分析程序如下:

  • 循环启动,在第一遍时,按第一个参数对值进行排序,例如按最大利润排序;选择一些(默认为 12 个)最佳值,其他的被删除;
  • 在第二遍时,按第二个参数对值进行排序,例如按获利因子排序;选择一些最佳值,数量是第一次排序后数量的一半,其他的被删除。
  • 在第三遍时,对第三个参数进行最后一次排序,例如按预期收益排序;取第二次排序后一半数量的值,其他的被删除。
// Analyzer
// Analyzing principle is the sequential checking of maximal 
// values according to the predefined filtering priority   
ArrayResize(ArrayTrans, ResizeArayNew - 1);
for(int PrioStep = 1; PrioStep < 4; PrioStep++)
  {
    for(PrCycle = 0; PrCycle < ResizeArayNew; PrCycle++)
      {
        Sort     = ArrayData[PrCycle][0];
        Prior1   = ArrayData[PrCycle][1];             
        transit  = ArrayData[PrCycle][2];
        Prior2   = ArrayData[PrCycle][3];             
        Prior3   = ArrayData[PrCycle][4];             
        transit1 = ArrayData[PrCycle][5];
        transit2 = ArrayData[PrCycle][6];
        transit3 = ArrayData[PrCycle][7];
        transit4 = ArrayData[PrCycle][8]; 
           
        if(PrioStep == 1)
          {
            //Prepare for the 1st sorting
            if(Gross_Profit ==1)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 1)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 1)
              {
                SortTrans = Prior3;
              }
          }
        if(PrioStep == 2)
          {
            // Restore
            if(Gross_Profit ==1)
              {
                Prior1 = Sort;
              }
            if(Profit_Factor == 1)
              {
                Prior2 = Sort;
              }
            if(Expected_Payoff == 1)
              {
                Prior3 = Sort;
              } 
            //Prepare for the 2nd sorting
            if(Gross_Profit == 2)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 2)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 2)
              {
                SortTrans = Prior3;
              }
          }
        if(PrioStep == 3)
          {
            // Restore
            if(Gross_Profit == 2)
              {
                Prior1 = Sort;
              }
            if(Profit_Factor == 2)
              {
                Prior2 = Sort;
              }
            if(Expected_Payoff == 2)
              {
                Prior3 = Sort;
              } 
            //Prepare for the 3rd sorting
            if(Gross_Profit ==3)
              {
                SortTrans = Prior1;
              }
            if(Profit_Factor == 3)
              {
                SortTrans = Prior2;
              }
            if(Expected_Payoff == 3)
              {
                SortTrans = Prior3;
              }
          }          
        ArrayTrans[PrCycle][0] = SortTrans;
        ArrayTrans[PrCycle][1] = Prior1;
        ArrayTrans[PrCycle][2] = transit;
        ArrayTrans[PrCycle][3] = Prior2;
        ArrayTrans[PrCycle][4] = Prior3;
        ArrayTrans[PrCycle][5] = transit1;
        ArrayTrans[PrCycle][6] = transit2;
        ArrayTrans[PrCycle][7] = transit3;
        ArrayTrans[PrCycle][8] = transit4;
      }
    ArraySort(ArrayTrans,StepRes, 0, MODE_DESCEND); // Sort the array
    ArrayResize(ArrayTrans, StepRes);               // Cut off the unnecessary things
    for(int CopyAr = 0; CopyAr < StepRes; CopyAr++)
      {
        ArrayData[CopyAr][0] = ArrayTrans[CopyAr][0];
        ArrayData[CopyAr][1] = ArrayTrans[CopyAr][1];
        ArrayData[CopyAr][2] = ArrayTrans[CopyAr][2];
        ArrayData[CopyAr][3] = ArrayTrans[CopyAr][3];
        ArrayData[CopyAr][4] = ArrayTrans[CopyAr][4];             
        // Per1    Variable 1
        ArrayData[CopyAr][5] = ArrayTrans[CopyAr][5];              
        // Per2    Variable 2
        ArrayData[CopyAr][6] = ArrayTrans[CopyAr][6];
        // Per3    Variable 3
        ArrayData[CopyAr][7] = ArrayTrans[CopyAr][7];
        // Per4    Variable 4
        ArrayData[CopyAr][8] = ArrayTrans[CopyAr][8];
      }
   StepRes = StepRes / 2;
  }

以这种方式过滤后的值被写入到全局变量中。全局变量中的值将在 EA 中被替换。

// Write the obtained results in variables
   double Peremen1 = ArrayTrans[0][5];                         
   double Peremen2 = ArrayTrans[0][6];
   double Peremen3 = ArrayTrans[0][7];
   double Peremen4 = ArrayTrans[0][8];
   // If the variable name is specified, write the result in 
   // global variables
   if(Per1 != "")
     {
       GlobalVariableSet(Per1, Peremen1);
     }             
   if(Per2 != "")
     {
       GlobalVariableSet(Per2,Peremen2);
     }
   if(Per3 != "")
     {
       GlobalVariableSet(Per3,Peremen3);
     }
   if(Per4 != "")
     {
       GlobalVariableSet(Per4,Peremen4);
     }
   Comment(Per1, " ", Peremen1, "  | ", Per2, " ", Peremen2, "  | ", Per3, 
           " ", Peremen3, "  | ", Per4, " ", Peremen4);
   Print(Per1, " ", Peremen1, "  | ", Per2, " ", Peremen2, "  | ", Per3, 
         " ", Peremen3,"  | ",Per4," ",Peremen4);
  }  // Function ends. That's all, automated optimization is complete.


自动优化程序运行结果

可通过图表左上角显示的消息查看自动优化程序的运行结果,如下方的屏幕截图中所示:


优化完成参考时间。


优化后所获值的分析

结果变量值。

如果消息中显示了优化结果,则表示优化已完成并已收到数据。

要独立估算自动优化程序的工作,用户需要浏览所有包含中间数据的文件以及在工作流程期间保存的文件。测试程序将数据存储在名称为 "FileReport_EURUSD_2007.03.12. htm" 的文件中,此文件名中的交易品种和日期就是根据选定交易品种和当前优化日期进行替换的。可在“终端测试程序”文件夹中找到此文件。这些文件和报告不会被自动删除,因此用户可以用它们检查参数的更改情况。



下一个文件 FileTest1.csv 是在按交易金额过滤值并删除了副本之后保存的。此文件的保存路径:D:\Program Files\terminal_folder_ame\experts\files



然后,每次筛选操作后得到的值被保存到 FileTest2.csv。此文件也保存到上述路径:D:\Program Files\terminal_folder_name\experts\files



上表显示所获值的过滤方法。过滤顺序默认设置为:1- Gross_Profit,2- Profit_Factor,3- Expected_Payoff。

自动优化程序的代码包含详细注释,必要时可以填入最合适的变量参数。例如,您要针对非最近日期的一段时间优化您的 EA,或是您计划在优化时段内增加/减少交易金额。要达到这个目的,您只需在 auto_optimization.mqh 中直接更改对应的变量。
// Limitation of minimal amount of trades per day
double MinTr   = TestDay - 2; 
// Limitation on maximal amount of trades per day
double MaxTr   = (60 / Period()*TestDay) + 2;
// The amount of attempts to copy the report file
int    KvoPptk = 10;
// The amount of strings to be sorted
int    StepRes = 12;

总结

本文并非用于让新手学习优化元素,因此强烈建议在设置您的 Expert Advisor 的自动优化之前先了解正常的优化方式。最好在选择了可在不同时间以不同方式影响您的 Expert Advisor 的基本变量之后,再使用自动优化程序。即,最好使用此自动优化程序以匹配一些变量参数,这些变量的变化对 EA 操作产生的影响比其他变量的变化大,具体要看市场波幅。

除此之外,最好不要设置很长的自动优化时段。假设 Expert Advisor 总是每天要优化 6-12 个小时。那么就会出现一个问题:什么时候进行交易?换句话说,优化自身并不是必要的。建议根据 EA 要进行交易的时间范围设置优化时段(即优化程序启动的时段)。这意味着必须考虑到,一旦启动测试程序终端,就将汲取历史数据,并且有可能出现经纪人并没有指定时间段的必要历史数据。要验证本文开头的假设,您需要 24 小时稳定的互联网连接。


已开发的自动优化程序位于以下随附文件中:auto_optimization.mqh - 库自身、MACD Sample_1.mq4 - MetaTrader 4 客户终端标准交付内容中略有更改的 Expert Advisor。


本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1467

附加的文件 |
MACD_Sample_1.mq4 (8.01 KB)
ZUP - 派斯温托通用锯齿形调整浪模式。第 1 部分 ZUP - 派斯温托通用锯齿形调整浪模式。第 1 部分
本文简要描述了指标 ZUP(派斯温托通用锯齿形调整浪模式)的基本原理。文章还描述了 ZUP 中内置的各个锯齿形调整浪指标。
帮助定义市场趋势的枢轴点 帮助定义市场趋势的枢轴点
枢轴点是价格图上的一条线,显示货币对的进一步趋势。如果价格在该线之上,则趋于上升。如果价格在该线之下,则相应的趋于下降。
一目平衡表替代指标 - 设置和应用示例 一目平衡表替代指标 - 设置和应用示例
如何正确设置一目平衡表替代指标?请阅读参数设置的说明。本文不仅会帮助你理解设置一目平衡表指标参数的方法,你还能更好的理解如何设置标准的一目平衡表。
基于枢纽点分析的交易策略 基于枢纽点分析的交易策略
枢轴点(PP)分析是对于日内大幅波动市场最简单和最为有效的策略之一。它早在计算机出现之前已经投入使用,那时证券交易者除了算盘和计数器之外,还无法使用任何自动数据处理设备。