非交易 EA 的测试指标

Sergey Kravchuk | 17 三月, 2016

简介

全部指标可以分为两组:静态指标(一旦显示后始终保持不变,不随新报价变化)和动态指标(仅显示当前时刻的状态,新价格出现时要完全重新绘制)。静态指标的效力在图表上直接可见。但如何检验动态指标的有效性呢?这是本文要探讨的问题。

技术分析中使用的绝大多数指标是静态的。以 MACD 为例。新报价的出现只会影响其最近的周期,更准确的说,是其最后的阶段的显示。但是,其图表历史部分仍“固若金汤”。要检验静态指标是否有效,只要调查其在历史数据上的指示即可。如果有多个可用指标,你要选择最佳的一个用于交易 - 也没有问题:只要将所有指标添加到图表,然后选择其中产生“最正确”的指示结果的指标。

对于动态指标,情况更加复杂,几乎接近“不可能”。几乎所有的通道指标都可当做这种指标使用。一般来讲,这些指标绘制一条或多条线,显示价格波动的范围。当然,这些线用于当前的时刻。因此,跟最近价格显著不同的新价格出现时,会在数秒钟之内使图表内线条排列变的截然不同。仅靠当前价格的最后一个点来评估指标对所有可能的价格态势作用的正确性,是不可能的。你会看到,在几个小时内指标工作良好,认为它没问题。但是,就在你决定开始交易时,可能会发生使其工作错误的市场情况(下面给出了由其中一个指标错误构建的 Barishpolets 移动通道示例),你可能会在不利的方向打开交易。指标在几个柱之后会“修正”其指示。但对你来说已经太晚了,因为已经亏损了头寸。

在测试程序中测试指标

策略测试程序的主要目的是测试 Expert Advisor。由于一些 EA 在其运行中使用指标,测试程序应该也可以测试指标。我们将利用该特性!

可以在两种模式下测试 Expert Advisor:标准和可视。在标准模式下,测试程序在 EA 历史中处理所有命令,并在进行测试的货币对不再有可用的历史数据时给出最终结果。在可视模式下,除以上所述,测试程序另外绘制图表的每个柱/价格变动,模拟实时模式下的市场运行。在测试程序中,可以加速、减速甚至停止时间,这对我们测试指标非常有用。

非交易截屏的 Expert Advisor

但是,在开始测试指标前,我们必须准备一个非同寻常的 EA。为了达到我们的目的,该 EA 不应该交易。其运行不应脱离测试指标的目的,这显然更加重要。由于交易错误初步损失的保证金不应停止指标测试。我将创建一个什么都不做的 EA。

其仅有的功能是对当前交易状态截屏。这在我们开始逐步分析指标的运行时非常有用。下面是 EA 代码:

//+-----------------------------------------------------------------------------+
//|                                                         IndicatorTester.mq4 |
//|                                      Copyright © 2006-2008, Sergey Kravchuk |
//|                                                    http://forextools.com.ua |
//+-----------------------------------------------------------------------------+
 
#property copyright "Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua"
#property link      "http://forextools.com.ua"
 
//+-----------------------------------------------------------------------------+
 
extern datetime ScreenShotStart=0; // date and time of the first screenshotting
extern int ScreenShotMax=100;      // how many screenshots should be made
extern int ScreenShotStep=0;       // screenshotting step: <=0-not applicable, N-on each Nth bar
extern string FilesPrefix="_";     // prefix for screenshot filenames
 
//+-----------------------------------------------------------------------------+
 
datetime   NextScreenShot=0;       // date and time for making the next screenshot
double ScreenShotCnt=0;            // prepare a screenshot counter
double ScreenShotCur=0.001;        // number of the initial screenshot
string FileName;                   // filename to save the next screenshot
 
//+-----------------------------------------------------------------------------+
//| expert start function                                                       |
//+-----------------------------------------------------------------------------+
 
int start()
{
  if(ScreenShotStep>0                       // is it necessary to make screenshots?      
    && ScreenShotStart<=Time[0]             // is it time for screenshotting?
    && NextScreenShot<=Time[0]              // is it time to make the next screenshot?
    && ScreenShotCur*1000<=ScreenShotMax+1) // have all screenshots not been made?
  {
    // compose the filename and save the screenshot under it
    FileName=FilesPrefix+StringSubstr(DoubleToStr(ScreenShotCur,3),2)+".gif";   
    WindowScreenShot(FileName,800,600);
   
    // give a prompt
    Comment("Saved file "+FileName+
    "\nThere are "+DoubleToStr((ScreenShotMax-ScreenShotCur*1000),0) +" pcs. left");
   
    // shift the data and the counter to the next screenshot
    ScreenShotCur+=0.001;
    NextScreenShot=Time[0]+ScreenShotStep*Period()*60;   
  }
 
  if(ScreenShotCur*1000>ScreenShotMax+1) Comment("All screenshots are saved");
 
  return(0);
}
//+-----------------------------------------------------------------------------+
截屏算法非常简单:我们等待时间的到来,从该时间开始一系列的截屏(ScreenShotStart)并在每个 ScreenShotStep 柱进行最多 ScreenShotMax 个截屏。每个截屏保存在一个文件,文件名称以预设的前缀开始,FilesPrefix,截屏编号会添加到名称中。

要形成以零开头的编号(这对截屏的正确排序非常必要,使 _1.gif 后紧随 _2.gif 而不是 _10.gif),我们使用一种不太寻常的编号方法。编号始于 ScreenShotCur=0.001,然后伴随着步长 0.001(ScreenShotCur+=0.001;)。编号自身是将小数改动为字符串获得,从第三个字符开始,其子字符串作为数字被选定。这样,我们去掉了起始“0”并获得了数位前的先导零。这种方法可以收集多达一千个截屏,超过了我们的分析需要。但是,如果对你还不够,增加初始数字的“精细度”,使步长精细度达到 0.0001。这样你就能够积累多达 10000 个截屏。

进入测试

现在,当我们一切就绪且 EA 编译无误时,开始进行测试。使用 View/Tester 菜单或者 Ctrl+R 组合键启动测试程序。在“Expert Advisor”字段,选择我们的 EA - IndicatorTester。然后选择要测试的交易品种和周期。如果必要,可以通过选中“Use date”字段并指定“From”和“To”日期选择测试范围。要启用可视测试模式,选中“可视模式”字段。现在可以按“Expert properties”按钮并为截屏指定所有必要的输入。

恩,基本上一切都准备好了。按下“Start”按钮,之后迅速按下位于可视化速度调节滑块右侧的“||”按钮。EA 将终止测试。现在可以将待测指标添加到图表,在松开“||”按钮后,继续测试 EA。我们都还记得,EA 并不进行任何交易。但测试程序对此并不知情,对报价按照价格变动和柱逐个仔细处理。由于只是添加了一个或几个指标到图表,测试程序必须对其重新计算和重新绘制,正常的 EA 一定会使用从这些指标获得的数据。

就是这些。现在,如一些编程者在弹出窗口中所写,“坐好并观察”指标的运行。你可以随时暂停测试(通过按“||”按钮)或对其加速或减速。当测试程序达到你在 ScreenShotStart 中预设的日期/时间后,将按照预设的周期性进行截屏,并将截屏保存在 c:\Program Files\MetaTrader 4\tester\files 目录下。如果你不需要截屏,只想看到指标工作的情况,在按“Start”按钮前设置 EA 的参数 ScreenShotStep 小于或等于零,这样就会禁用截屏。

使用示例

当希望为研究找到“最正确”的 Barishpolets 移动通道指标时,我自己第一次进行了该任务。在如何建立通道描述中,其中几点可能导致通道构建的错误。首先,是出现两个极值点彼此邻近的情况,需绘制穿过该极值点的其中一条通道线。在这种情况下,一些指标开始将通道从向下的 45 度“抛”为向上的 45 度,然后再从向上到向下 - 诸如此类。不幸的是,指标的开发者绝对相信 Barishpolets 的权威,只是机械的实现了他的规则(必须注意,在绝大多数情况下,规则没有问题)。但他们却忘记了,市场可能会出乎我们的预料。在这种情况下,指标的“顶”开始被击穿,指标变成亏损的原因,而不是获利的有用工具。

为了比较构建 Barishpolets 移动通道的不同方法,我也编写了自己的构建通道的指标,但是以“更加客观”的方式 - 通过平均价格移动平均线。它跟标准工具 Equidistant Channel 的实现方式非常类似,但通道边界的算法略有不同(你可以在我的网站 双通道方法(俄语) 找到更多详细信息)。现在我们来看一下位于 CodeBase 的 Barishpolets 移动通道指标之一(SHI_Channel_true)跟“正确”的平均价格通道比较的结果如何。测试中的指标线为绿色,双通道指标的长通道线(周线)为橙色,短通道线(33 小时线)为浅蓝色。当它们接近通道边界时,变为红色。

影片是影片,我们来仔细看一些截屏。

从 2007 年 12 月 4 日至 7 日期间(EURUSD M30),我们可以看到 Barishpolets 移动通道指标“转向”并回归平均价格移动线的次数。

这里,有可能会突破通道(通道的绘制并非非常准确,价格到达周通道的边界)。你可以看指标如何表现。通道在下一个柱转向,恰好符合周通道。

这是因为,新的极值点已经形成,指标对其处理很好。但是,只有一些柱超过了边界 - 它再次转向,返回不正确的位置。


这是因为新报价将极值点拉回正常的内部点,指标再次处理这种改变。新的转向在下一个柱出现:

两或三个柱后,又一次转向:

在图表上,我们可以看到构建 Barishpolets 移动通道的另一个“极值” - 两个靠近的极值设定一个通道边界,尽管在图表中可以看到非常明显的图形:33 小时短期通道内的价格正趋于周通道的边界,并很可能从这里折回周通道内。事实上,会出现以下情况 - 在第二天时我们看到自己“预测”的图形:

因此,使用非交易截屏 EA,我们可以对指标 SHI_Channel_true 进行合理的验证这是一个非常“不同”的工具。对其进行认真的修改前,我不会将保证金委托给它(这就是我创建双通道方法的原因之一)。

总结

上述代码的应用领域不仅限于指标测试。你可以将相同的机制嵌入到交易 EA。这样,你既可以“封存”调试好的代码,又可以收集 EA 及其指标表现的历史记录,为用于计算 EA 信号的指标分析 EA 交易结果。这可以在真实账户上加快 EA 交易的调试。

提到的指标测试方法的重要特色之一是可以截屏。很多图像查看器(例如,免费的 IrfanView)可以分页模式显示文件。按 PageDown,可以进入下一个截屏,如同在测试程序中手动前往下一个柱。你无法在测试程序中完成但可以在 IrfanView 中轻松实现的是前往之前的柱。只要按 PageUp - 你就可以“后退”。再按一次 - 进入更早的历史记录。这可以让你查看指标表现并进行研究,找出它们工作不正确的原因。