English Русский Español Deutsch 日本語 Português
如何实施你自己的优化标准

如何实施你自己的优化标准

MetaTrader 4测试者 | 16 三月 2016, 13:44
1 571 0
Nikolai Shevchuk
Nikolai Shevchuk

简介

我们不时会听到关于在 MT4 测试程序中扩展优化标准集的必要性的意见。可以想见,无论开发者添加什么标准,始终会有用户和情形需要其他标准。这个问题是否能在 MQL4 和 MetaTrader 内部解决呢?答案是肯定的。本文通过标准 Expert Advisor 移动平均线的例子演示自定义优化标准的使用。这里的标准是获利/亏损关系。



Expert Advisor

让我们从优化标准开始。关于其计算,我们需要在测试最大盈余和亏损时追踪。为了不依赖于 Expert Advisor 运行的逻辑,我们在 start() 函数的开始处添加现有的代码串。

   if (AccountEquity() > MaxEqu) MaxEqu = AccountEquity();
   if (MaxEqu-AccountEquity() > MaxDD) MaxDD = MaxEqu-AccountEquity();

为了处理最后的价格变动,它们应该在 deinit() 中重复。之后可以计算优化标准的值。

    Criterion = (AccountBalance()-StartBalance)/MaxDD;

现在可以开始主体部分——优化过程的维护。我们有一个问题——MQL4 没有决定优化结束的内置方法。我所知道的唯一方法是所谓的“计数器的优化”。含义如下:Expert Advisor 的唯一可更换参数是特殊的外部变量——计数器。这里仍有一个严重的后果——我们丧失了以标准方式更改 Expert Advisor 的真实参数的可能性,应该自行提供。另一个缺陷是来自朋友的优化缓存变成了敌人。但结果肯定了这种方法,所以我们将继续。

我们来添加外部变量:

extern int Counter                    = 1;    // Counter of the tester's running
extern int TestsNumber                = 200;  // he check digit - total number of runs 
extern int MovingPeriodStepsNumber    = 20;   // Number of optimization steps for MovingPeriod 
extern int MovingShiftStepsNumber     = 10;   // Number of optimization steps for MovingShift
extern double MovingPeriodLow         = 150;  // Lower limit of the optimization range for MovingPeriod
extern double MovingShiftLow          = 1;    // Lower limit of the optimization range for MovingShift
extern double MovingPeriodStep        = 1;    // Optimization step for MovingPeriod 
extern double MovingShiftStep         = 1;    // Optimization step for MovingShift

首先是计数器。下一个变量是检查变量(和信息)。然后为用于优化的移动平均线的两个内置变量指定步数、下限和优化步长。可以看到一些冗余:如果打算进行完整的检验(我们接下来即如此做),MovingPeriodStepsNumber 和 MovingShiftStepsNumber 之积应该等于 TestsNumber。

每次测试后,Expert Advisor 彻底结束运行,下一次运行可以视为再生。我们有两种方式来组织“遗传存储”:全局变量和单独的文件。我们两种都会使用。

让我们来修改 init() 函数:

int init() {
  if (IsTesting() && TestsNumber > 0) {
    if (GlobalVariableCheck("FilePtr")==false || Counter == 1) {
      FilePtr = 0; 
      GlobalVariableSet("FilePtr",0); 
    } else {
      FilePtr = GlobalVariableGet("FilePtr"); 
    }
    MovingPeriod = MovingPeriodLow+((Counter-1)/MovingShiftStepsNumber)*MovingPeriodStep;
    MovingShift = MovingShiftLow+((Counter-1)%MovingShiftStepsNumber)*MovingShiftStep;
    StartBalance = AccountBalance();
    MaxEqu = 0;
    MaxDD = 0;
  }   
  return(0);
}

我们的补充仅位于测试程序运行条件内部和非零的 TestsNumber。因此,TestsNumber=0 会将 Expert Advisor 变成一个标准移动平均线。在讨论优化过程时,我们必须尽可能的加快进程。这就是为什么代码以使用全局变量管理全程(贯穿测试程序运行)文件指针的规定开始。然后计算可更换参数的值,并初始化用于优化标准计算的变量。

主体工作应该在函数 deinit() 完成。在测试结果上,我们将在文本文件中保存优化标准的值、已优化的参数值和测试运行的数量。在优化结束后,结果将根据优化标准分类并保存在相同的文件。所以,我们需要处理三种情形:第一次启动、最后一次启动和所有其他启动。我们使用测试程序运行计数器对其进行区分。
处理第一次启动:

    if (Counter == 1) {
// First run, create/initialize a datafile.
      h=FileOpen("test.txt",FILE_CSV|FILE_WRITE,';');
      FileWrite(h,Criterion,MovingPeriod,MovingShift,Counter);
// Remember the position of the file pointer after writing in the global variable
      FilePtr = FileTell(h); 
      GlobalVariableSet("FilePtr",FilePtr);
      FileClose(h);

处理其他启动的特殊性在于有新数据添加到文件:

    } else {
//  After the first start is processed, the data are added into the file
      h=FileOpen("test.txt",FILE_CSV|FILE_READ|FILE_WRITE,';');
//  It is time to use the file pointer written in the global variable
      FilePtr = GlobalVariableGet("FilePtr");
      FileSeek(h,FilePtr, SEEK_SET);
      FileWrite(h,Criterion,MovingPeriod,MovingShift,Counter);
//  Remember the file pointer position once again
      FilePtr = FileTell(h); 
      GlobalVariableSet("FilePtr",FilePtr);

现在我们来处理最后一次启动:

      if (Counter == TestsNumber) {
        ArrayResize(Data,TestsNumber); 
// Returns the file pointer to the beginning       
        FileSeek(h,0,SEEK_SET);
// Read from the file the results of all testings
        int i = 0;
        while (i<TestsNumber && FileIsEnding(h)== false) {
          for (int j=0;j<4;j++) {
            Data[i][j]=FileReadNumber(h); 
          }
          i++;
        } 
// Sort the array according to our optimization criterion
        ArraySort(Data,WHOLE_ARRAY,0,MODE_DESCEND);
// Now let us arrange the results. Reopen the file        
        FileClose(h); 
        h=FileOpen("test.txt",FILE_CSV|FILE_WRITE,' ');
        FileWrite(h,"  Criterion","     MovingPeriod"," MovingShift"," Counter");
        for (i=0;i<TestsNumber;i++) {
          FileWrite(h,DoubleToStr(Data[i][0],10),"        ",Data[i][1],"        ",Data[i][2],"        ",Data[i][3]);
        }

数组最初初始化为 double Data[][4]。就是这些。我们来改进:

        GlobalVariableDel("FilePtr");
      }
      FileClose(h); 
    }
  }

编译、打开测试程序并选择 Expert Advisor。然后打开 Expert Advisor 的属性表并检查四个位置:

- MovingPeriodStepsNumber 和 MovingShiftStepsNumber 之积必须等于 TestsNumber。
- 优化必须只对计数器进行,
- 优化范围必须从 1 到 TestsNumber,步长为 1。
-必须禁用遗传算法。

开始优化。结束后,前往 [Meta Trader]\tester\files 文件夹并在 test.txt 文件查看结果。作者从 2004 年年中在开盘价上对 EURUSD_H1 处理,得到以下结果:

现在让我们回到缓存是我们的敌人的话题。实际上,当我们从缓存得到测试结果时,函数 init() 和 deinit() 没有启动。因此,在优化重新启动时全部或部分变体未予说明。此外,实际运行数将少于 TestsNumber,Data 数组将包含一些零。作者建议两种消除“缓存效应”的方法:重新编译 Expert Advisor 或关闭/暂停/打开测试程序窗口。
缓存干扰可以通过独立的测试运行计数检测出。对于使用特殊的全局变量组织这种计数有三个注释插入,如所附的 EA 代码中所示:

// Code of the independent counter
    if (GlobalVariableCheck("TestsCnt")==false || Counter == 1) {
      TestsCnt = 0; 
      GlobalVariableSet("TestsCnt",0); 
    } else {
      TestsCnt = GlobalVariableGet("TestsCnt"); 
    }
 

// Code of the independent counter
    TestsCnt++;
    GlobalVariableSet("TestsCnt",TestsCnt); 
 

// Code of the independent counter
        GlobalVariableDel("TestsCnt");

还有最后一点。留心的读者一定注意到:我们不使用 FilePtr 变量(以及伴随的全局变量)也无妨——数据写在文件最后,从头读取。那么它有什么用呢?答案如下:该 Expert Advisor 用于优化维护方法的演示。该方法可以使用之前测试的结果管理实时运行。在这里,全程文件指针以及独立计数器会非常有用。作为要求使用之前实时结果的任务示例,我们可以对样本外测试的管理和自己的遗传算法实施进行命名。



总结

对该问题的兴趣源自于以下论坛的话题:http://forum.mql4.com


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

附加的文件 |
指标和提醒的盈利能力可视化测试 指标和提醒的盈利能力可视化测试
通过这些提醒进行 EA 测试时,通常将决定是使用交易提醒的哪个指标或只是指标计算方式。但是,为每个指标编写一个 EA 并非总是可能/必要/合理的。你可以通过自己收集提醒并绘制理想交易图像的特殊指标,快速计算出基于其他指标提醒的交易盈利能力。这可帮助你既对所得结果进行可视化估计,又快速选择了最优参数。
面向初学者的 MQL4 语言。技术指标和内置函数 面向初学者的 MQL4 语言。技术指标和内置函数
这是&ldquo;面向初学者的 MQL4 语言&rdquo;系列的第三篇文章。现在我们将学习使用内置函数和用于技术指标的函数。后者对于以后开发你自己的 Expert Advisor 和指标至关重要。另外,我们将通过一个简答的例子,解释如何追踪进入市场的交易信号,以及如何正确使用指标。在文章的末尾,你将学到一些关于语言本身的新鲜有趣的内容。
MQL 中的对象方法 MQL 中的对象方法
本文对于所有在 MQL 环境下编程的人员,无论是初学者还是专业人士,将会非常有趣。而且 MQL 环境下的开发人员和理论家阅读此文也会相当有帮助,因为这里所分析的问题可能会成为将来实施 MetaTrader 和 MQL 的项目。
通用的 Expert Advisor 模板 通用的 Expert Advisor 模板
本文将帮助交易新手创建可灵活调整的 Expert Advisor。