我编写了一个自定义指标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);
成功了。