MQL4 iCustom始终返回相同(错误)的值(0x7FFFFFFF)



我编写了一个自定义指标Speed.mq4如下:

double         SpeedBuffer[];                     // a Custom Indicator BUFFER
int OnInit() {
    SetIndexBuffer( 0, SpeedBuffer );             // an access INDEX 0->BUFFER
    ...
    }
int OnCalculate( const int        rates_total,
                 const int        prev_calculated,
                 const datetime  &time[],
                 const double    &open[],
                 const double    &high[],
                 const double    &low[],
                 const double    &close[],
                 const long      &tick_volume[],
                 const long      &volume[],
                 const int       &spread[] 
                 ) {
   int start;
   if (   prev_calculated == 0 ) start = 1;
   else                          start = prev_calculated - 1;
   for ( int i = start; i < rates_total - 1 ; i++ ) {                   // CPU-WASTED BY AN INEFFICIENT BACK-STEPPING IN TIME
         double curTypical  = typical( high[i],  low[i],  close[i]   );
         double prevTypical = typical( high[i+1],low[i+1],close[i+1] ); // CPU-WASTED, NO NEED TO RECALC ...
         double curSpeed    = curTypical - prevTypical;
         SpeedBuffer[i]     = curSpeed;
     }
//--- return value of prev_calculated for next call
   return( rates_total );
  }

指示器在应用程序中运行良好,图表绘制正确。

当我尝试在ExpertAdvisor中检索最后一个值时,我总是收到相同的值:

double speed = iCustom( NULL, 0, "Speed", 2, 0, 0 );
Print( "speed is: " + speed );

打印:

速度为:2147483647

它总是相同的数字。我不确定问题出在哪里。

从指标中的CCD_ 2可以看出这些值是正确计算的。但当我使用iCustom时,我只收到该值。

MQL4自定义指示器iCustom()机制

MQL4甚至New-MQL4(有时称为MQL4.5)使用相当复杂的接口模型来处理Expert Advisor调用/自定义指示符计算。

首先要意识到的是,iCustom()不是对函数的调用,而是一种方法,该方法通过引用自定义指示符的文件名间接"请求""预先计算"的DataSTORE中检索一个特定的值

虽然这听起来可能很复杂,但这正是CPU高效计算工厂的本质,定制指标是在MQL4世界的早期设计的。

因此,iCustom()只是启动检索方法的语法糖,它将相关的预计算值重新交到Expert Advisor手中。

自定义指标将所有预先计算的值放入BUFFER(s)中,与DataSTORE单元格排序的TimeSeries样式一致([0]="现在,当前条形图",前进[1]、[2]、[3]……越来越深入历史)

iCustom()传递shift值,作为一个条形数,即检索方法必须深入历史的深度,以便从各个BUFFER以及BUFFER标识INDEX(在我们上面的例子中为0,因为只有一个BUFFER,INDEX=0)中选择请求的值。这是为了EA完全不知道自定义指标内部变量名称等。

只需询问哪个BufferINDEX用于想要从哪个BarNUMBER读取值。

缓冲区是应该为(错误的)值负责的人

代码的第一行写着:

double         SpeedBuffer[];                     // a Custom Indicator BUFFER

如果在OnInit(){}中不进行其他处理,SpeedBuffer中的所有单元格都将具有EMPTY_VALUE

指示符缓冲区中的空值默认为该值== 2147483647 (0x7FFFFFFF),如上文所述。

Q.E.D.

可以在OnInit(){ ArrayInitialize( SpeedBuffer, 0.123456 ); }中声明具有用于单元初始化的任何其他值(对于TimeSeries联盟的BUFFER,在每个新的Bar事件时发生(所有单元向后重新排列一个&cell[0]变为"空",预加载此处讨论的默认值)。

还可以在指示符OnCalculate(){ ... SpeedBuffer[0] = -9.87654; ...}中添加一个步骤,以避免使单元格[0]处于上下文不一致的状态,而不是处于"刚刚"初始化的状态/值。


调用方接口(如何降低弱集成接口的风险)

然而,值检索的责任在Expert Advisor方面,因为它填充了iCustom()接口代理的参数。

可以使用预防步骤,如>>所示https://stackoverflow.com/a/26389823/3666197一旦调用外部自定义指标来检索一组值,就可以最大限度地降低参数排序/值不正确的风险。

一旦具有多个指示器缓冲区的富extern参数化自定义指示器由于提供"错误"数字而陷入可疑状态(只是由于iCustom()调用参数被""看不见"顺序/上下文不正确),这种简单的方法可以为您节省数十人日的测试/调试时间。

当自定义指标在图表上显示不同的值并报告给ExpertAdvisor时,需要记住的另一件事是,ExpertAdvisor通过OnCalculate()的执行流需要与图表不同;具体来说,图表最初以prev_calculated=0开始调用OnCalculate(),而EA(无论是使用Strategy Tester运行还是实时运行)将始终具有prev_cCalculated=rates_total-1,因此要计算指标值的条形数为rates_total-prev_clculated=1(即仅为当前条形)。

通过设置start,你确实在代码中考虑到了这一点,但通常情况下,对于复杂的指标(通常涉及到引用的不仅仅是前一条),你需要注意这种差异,永远不要认为如果指标在图表上看起来不错,那就意味着它确实有效。它需要与EA单独测试。

我查看了我的代码,最终发现:

 double speed=iCustom(NULL,0,"Speed",2,0,0);

正在使用最后一个值,该值尚未由自定义指标计算

将其更改为:

 double speed=iCustom(NULL,0,"Speed",2,0,1);

成功了。

最新更新