如何在另一指标的基础上编写一个指标

Dmitry Fedoseev | 4 十月, 2013

简介

在 MQL5 中,除了如“MQL5:创建您自己的指标”文中所述那样从头创建一个新的自定义指标之外,您还可以根据客户端内置或自定义的另一个指标来编写一个。有两种方式:第一种是对某指标做出改进,添加新的计算和标绘(此情形仅适用于拥有开源代码的自定义指标);第二种方式是使用终端内置的某个指标,或是通过 iCustom()IndicatorCreate() 函数使用某现有自定义指标。

第一种方式:添加一个标绘

我们根据“将一个指标应用到另一个指标”一文来改进 True_Strength_Index_ver3 指标的示例,仔细研究一下这种指标创建方式。我们来添加一条带有选择指标类型与平滑周期可能性的信号线。整个流程分 8 个阶段。

1. 制作一份文件复本

于 MetaEditor 中打开 True_Strength_Index_ver3 指标并以新名称保存,比如 TSIs。新文件必须保存到终端根文件夹的 MQL5/Indicators 目录中。

2. 更改指标属性

于指标代码中搜索 indicator_buffersindicator_plots 属性indicator_buffers 属性决定指标中使用的指标缓冲区的总数量,而 indicator_plots 属性则决定图表上显示的缓冲区数量。指标当前使用 8 个缓冲区;其中一个显示于图表上。我们需要再添加一个显示于图表上的缓冲区。将 indicator_buffersindicator_plots 的值加 1。

#property indicator_buffers 8 #property indicator_plots 2

3. 确定新缓冲区的显示属性

设置新缓冲区的显示属性。采用已通过此指标准备好的代码。利用鼠标,复制确定指标首行显示属性的所有代码。

//---- TSI 绘图
#property indicator_label1 "TSI"
#property indicator_type1 DRAW_LINE
#property indicator_color1 Blue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1

将其插入首行属性的下方并修改。

//---- TSISignal 绘图
#property indicator_label2 "TSISignal" // 线的名称,当鼠标光标停留在线上有弹出帮助时会显示
#property indicator_type2 DRAW_LINE    // 缓冲区类型 
#property indicator_color2 Red         // 线的颜色
#property indicator_style2 STYLE_SOLID // 风格
#property indicator_width2 1           // 线粗

首先,将属性编号从 1 改为 2,因为其为第二缓冲区的属性。将 indicator_label2 属性改为 TSISignal - 此行名会在鼠标指针放在此行上方时在一个弹出帮助中显示,还会显示于数据窗口。indicator_type2 属性应保持不变,缓冲区应作为行显示。将 indicator_color2 属性改为 Red - 新行将标红色。indicator_style2 属性保持不变 - 信号线是与主线类似的实线。indicator_width2 属性亦应保持不变 - 新行有 1 像素厚。

4. 声明外部变量

可通过指标修改的外部变量(以 "input" 开头的行)位于代码中行属性的下方。信号线亦应有其参数 - 平滑周期与类型。

声明其值为 5 的 int 类型外部变量并命名为 "sp" (平滑周期),将 ENUM_MA_METHOD 类型变量命名为 "sm" (平滑方法),且值为 MODE_EMA (信号线平滑周期为 5,默认指数型平滑)。现在,包含外部变量的代码段如下:

input int r=25;
input int s=13;
input int sp=5;
input ENUM_MA_METHOD sm=MODE_EMA;

5. 为新缓冲区声明一个数组

我们声明一个将来供指标缓冲区使用的数组。于代码中搜索 OnInit() 函数,并查找 SetIndexBuffer() 函数的调用位置,以引导自己通过指标中指标缓冲区的现有数组。True_Strength_Index_ver3 指标中的这些数组分别为 TSIBuffer、MTMBuffer、AbsMTMBuffer、EMA_MTMBuffer、EMA2_MTMBuffer、EMA_AbsMTMBuffer、EMA2_AbsMTMBuffer。

TSIBuffer 数组的 SetIndexBuffer() 函数利用 INDICATOR_DATA 参数调用,这就意味着该缓冲区显示于图表上方。所有其它数组均利用 INDICATOR_CALCULATIONS 参数调用。这就意味着这些数组为辅数组,用于中间计算。

新缓冲区要显示于图表上,所以我们在 TSIBuffer 数组的声明之后声明它,保持逻辑顺序,以备进一步改进该指标时代码中的定向更方便。

由此,我们首先声明两个显示于图表上的缓冲区数组,然后再是用于中间计算的缓冲区数组。

//--- 指标缓冲区
double TSIBuffer[];
double TSISigBuffer[]; // 用于信号线新缓冲区的数组
double MTMBuffer[];
double AbsMTMBuffer[];
double EMA_MTMBuffer[];
double EMA2_MTMBuffer[];
double EMA_AbsMTMBuffer[];
double EMA2_AbsMTMBuffer[]; 

6. 将一个数组关联一个缓冲区

现在到了非常重要的一步,此步骤要求投以格外的注意力和谨慎度 - 将一个数组与一个指标缓冲区关联。关联利用 SetIndexBuffer() 函数执行。函数调用中的第一个参数为数组索引,第二个是数组名称,第三个则是指明缓冲区用途的标识符。缓冲区均按索引(第一个参数)排列于指标属性窗口中的 "Colors" 选项卡,顺序与其于图表上的绘制顺序相同,第一个为 0 缓冲区,然后是 1 缓冲区,以此类推。

没必要针对索引 0、1、2……顺序调用 SetIndexBuffer() 函数,我们干脆保持 theSetIndexBuffer() 函数的调用顺序即可。调用 TSIBuffer 数组函数后,执行 TSISigBuffer 数组调用。主线缓冲区(TSIBuffer 数组)索引为 0,这意味着下一个缓冲区(TSISigBuffer 数组)的索引应为 1。

调用 TSISigBuffer 数组 SetIndexBuffer() 函数的第三个参数为 INDICATOR_DATA 变量(此缓冲区显示于图表上)。

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);

将其余要利用第一个参数的顺序递增值调用的 SetIndexBuffer() 函数缓冲区重新索引。

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);
SetIndexBuffer(2,MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(4,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(5,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(6,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(7,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);

针对这种特定情况,建议按照递增索引来保持调用 SetIndexBufer() 函数的顺序。由此,也会减少进一步改进时的耗时耗力。

现在我们有 8 个缓冲区,其中两个显示于图表上。确保亦于 indicator_buffersindicator_plots 指标的属性中指定相同的值(步骤 2)。

7. 计算信号线的值

信号线是指根据指标主线数据绘制的一条移动平均线。我们无需为此执行任何计算;客户端交付中包括根据一个信息数组计算移动平均线的库(MovingAverages.mqh 文件)。顺便说一下,其已包含于指标代码中(第 14 行):

#include <MovingAverages.mqh>

只剩下使用其功能一件事了。

OnCalculate() 函数中找到指标主线计算完成的点(TSIBuffer 数组)。我们来使用搜索功能;选择 TSIBuffer 数组的名称,比如在其声明的代码部分中(图 1)。然后执行 "Main Menu" - "Edit" - "Find and replace" - "Find" 命令或使用 Ctrl+F 组合键。


图 1. 选取的数组名称。

"TSIBuffer" 一词已被键入到打开的 "Find" 窗口的 "Find what" 字段中。于 "Direction" 区段中选择 "Up" 。现在,打开 "Find" 窗口后,将指针置于 OnCalculate() 函数的后面,按一次 "Find Next" 按钮,您马上就会找到 TSIBuffer 数组计算结束的位置。计算于 "for" 循环中执行。我们紧随此循环之后,添加信号线计算的代码(图 2)。


TSIBuffer 计算值的最后找到位置(红色箭头)。红框标注为执行计算循环的位置。
图 2. TSIBuffer 计算值的最后找到位置(红色箭头)。红框标注为执行计算循环的位置。

全部四种主要移动平均线类型计算的函数,均被纳入 MovingAverages.mqh 库中:

上述所有函数都拥有一个相同的参数集:

const int rates_total, const int prev_calculated, const int begin, const int period, const double& price[],double& buffer[]

此函数的 price[] 参数会确定一个数组,该数组包含待执行移动平均线计算的初始数据。buffer 参数是存储移动平均线值的数组。rates_totalprev_calculated 参数与 onCalculate() 函数的 rates_total 和 prev_calculated 参数相同,它们会确定 price[] 数组的大小以及该数组已处理元素的数量。begin 参数是重要数据开头数组某元素的索引。

鉴于 MovingAverages.mqh 库中移动平均线计算各算法的独特性(此功能于本文主题不相关),我们需要一种谨慎的方法来设置 begin 参数。

此参数任何情况下均不得设置到比源数据起始值(TSIBuffer 数组)更早的数组元素。如果不会导致计算错误,则允许其指定一个较晚的元素。

为确定一个可接受的 begin 值,要格外注意 for cycle 参数,TSIBuffer 数组值于此计算 - 周期始于 start 变量值。我们需要找到其于指标首次计算期间拥有的 start 变量值(当 prev_calculated 值为 0 时)。"start" 变量的值就在此周期之前、当 prev_calculated=0 时计算;计算利用下述公式执行:

start=begin+r+s-1;

被传递至移动平均线计算函数的 begin 变量值,必须等于该值。

计算循环过后,TSIBuffer 数组就会声明 begin2 变量并将 begin+r+s-1 值分配给它。

int begin2=begin+r+s-1; 

如欲根据外部参数 "sm" 的值提供使用不同平滑函数的可能性,则使用 switch 操作符。针对 sm 变量值的每一种情形,编写相应函数的调用。

switch(sm)
  {
   case MODE_EMA:
      ExponentialMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_LWMA:
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMA:
      SimpleMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMMA:
      SmoothedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
  }

之后我们就能看到带有信号线的指标了。按下 "Compile" 按钮,打开客户端并将此指标附至图表(图 3)。



图 3. 指标 TSIs,蓝色 - 主线,红色 - 新的,信号线。

8. 切掉缓冲区绘图的开头部分

如果您将含有指标的图表滚动至左边缘,就会看到值未被计算的部分的指标绘线。看起来很不美观(图 4)。



图 4. 未执行计算部分的指标绘图。

采用通过 PLOT_DRAW_BEGIN 标识符调用的 PlotIndexSetInteger() 函数,确定未被绘制缓冲区区域的首柱数量。此函数的调用应于该指标的 OnInit() 函数内完成。于 OnInit() 的结尾添加此函数调用,当然,还要在 return(0) 调用之前。

PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,r+s+sp);

再次按下 "Compile" 按钮,以获取指标绘制的正确开头(图 5)。 



图 5. 指标绘制的正确开头。

第二种方式。基于现有指标创建一个新的指标


我们会利用创建 TSIs 指标主线和信号线平滑异同指标的一个示例来研究这种方式。该指标会被绘制为一个直方图且有两种颜色,与 AOAC 指标相同。如果指标值增长,则此直方图标以绿色;如果减少,则标以红色。前面的简介中我们提到过,如欲引用另一个指标,您可以使用 iCustom()IndicatorCreate() 函数。首先,我们来讲讲利用 iCustom() 函数创建一个指标。

利用 iCustom() 函数创建指标


1. 创建新指标

我们来创建一个新指标。想在 MetaEditor 中创建一个新指标,您应执行 "Main Menu" - "File" - "New" - "Custom Indicator" 命令或按下 "Ctrl+N" 组合键。在出现窗口的 "Name" 字段中指定新指标的名称 - TSIsCDiCust,再按下 "Add" 按钮。添加一个外部参数,其名称并没有确定代码中外部参数某个部分那么重要;而且它会方便由 TSIs 指标复制所有外部参数(图 6)。


利用向导创建一个自定义指标的第一步。
图 6. 利用向导创建一个自定义指标的第一步。

按下 "Next" 按钮。

在下个窗口中指定将于某个独立窗口中绘制的指标。不要界定最小值与最大值。按下 "Add" 按钮,指标缓冲区列表中就会出现一个新的缓冲区;指定其名称 - TSIsCD (如果您将鼠标指针置于指标行上方和数据窗口中时,它就会于一个弹出帮助中显示) 及其类型 - 彩色直方图。

此后,"Color" 字段中就会出现几种颜色示例。为第一个示例指定绿色,第二个指定红色,其它保持不变。再添加两个名为 Tsi 和 TsiSignal 的缓冲区,它们将用于接收和存储 TSIs 指标的值(图 7)。


利用向导创建一个自定义指标的第二步。 
图 7. 利用向导创建一个自定义指标的第二步。

按下 "Finish" 按钮,新指标的模板就会在 MetaEditor 中打开。

2. 编辑指标与指标缓冲区的属性

我们已于步骤 1 中确定了 3 个缓冲区,但是,#property indicator_buffers 的值为 4。问题是一个彩色直方图使用了两个缓冲区 - 一个显示于图表上,打算为指标值所用;还有一个则用于确定第一缓冲区的显示颜色。#property indicator_buffers 值保持不变。将 #property indicator_plots 值改为 1 - 图表上只应显示一个缓冲区。

Tsi 与 TsiSignal 缓冲区不得显示于图表上,所以删除其所有属性(以 2 和 3 结尾的所有指标属性)。

//--- Tsi 绘图
#property indicator_label2 "Tsi"
#property indicator_type2 DRAW_LINE
#property indicator_color2 Red
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
//--- TsiSignal 绘图
#property indicator_label3 "TsiSignal"
#property indicator_type3 DRAW_LINE
#property indicator_color3 Red
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
OnInit() 函数中查找上述缓冲区的 SetIndexBuffer() 函数调用(数组名称为 TsiBuffer 与 TsiSignalBuffer),将第三参数的值由 INDICATOR_DATA 改为 INDICATOR_CALCULATIONS
SetIndexBuffer(2,TsiBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,TsiSignalBuffer,INDICATOR_CALCULATIONS);

修改 indicator_color1 属性 - 只保留前两种颜色。

#property indicator_color1 Green,Red

3. 声明外部参数

于 MetaEditor 中打开 TSIs 指标,并由其复制所有外部变量,利用这些参数替换当前的外部变量 Input1

//--- 输入参数
input int r=25;
input int s=13;
input int sp=5;                 // 平滑周期
input ENUM_MA_METHOD sm=MODE_EMA; // 平滑类型

4. 为指标句柄声明一个变量并调用此指标

于指标的共用区段中声明一个 int 类型变量并命名为 Handle。于 OnInit() 的最底部调用 iCustom() 函数。此函数会返回所创建指标的句柄;我们则需要用它来接收指标值。将此函数返回的值赋给 Handle 变量。

iCustom() 函数的前两个参数会确定交易品种和时间表,这些数据会被用于计算指标。我们来指定指标所附的交易品种和时间表 - _SymbolPERIOD_CURRENT。第三个参数是自定义指标的名称,本例中是 TSIs。被调用指标的所有外部参数进一步列出如下:

Handle=iCustom(_Symbol,PERIOD_CURRENT,"TSIs",r,s,sp,sm);

5. 制备 OnCalculate() 函数

我们转到 OnCalculate() 函数上来。TSIs 指标根据数据的一个缓冲区计算,所以我们会采用 OnCalculate() 函数的第一种形式。在模板中将 OnCalculate() 函数现有的第二种形式改为第一种。

int OnCalculate(const int rates_total,         // price[] 数组的大小
                const int prev_calculated,   // 在前一次调用中处理的柱数
                const int begin,             // 大数据起点
                const double &price[]        // 用于计算的数组
                )
  {
   return(rates_total);
  }

有关指标的进一步工作均将于此函数内完成。

6. 确定指标计算的极限

任何指标开发过程中,最优先最重要的都是确定处理柱的限制范围。指标启动时,我们应在其运行期间履行指标每柱的计算 - 仅针对当前形成的一个。您可以通过 prev_calculated 变量的值探测到指标启动的时机。如果此值为零,则这是自指标启动以来首次执行 OnCalculate() 函数。

首次执行 OnCalculate() 函数时,您要确定计算起始的首柱的索引。其值由指标值计算所需的柱数确定(索引由左向右执行)。

指标线的倾斜由两个柱确定,所以我们还需要另一个前柱。柱索引,price[] 数组起始的重要数据已知 - 即 begin 变量的值;所以我们从 start=begin+1 柱开始柱计算。

此外,指标工作期间,计算起始的柱索引是由 prev_calculated 变量的值确定的 - 此变量中包含已经处理的柱的数量。因此,想要查出已执行计算的上一个柱,您要从 prev_calculated 减 1。

上一个已经处理的柱会被再次纳入计算 - 因为它可能是一个成形柱。计算的限值由 price[] 数组的大小确定 - rates_total 变量。已执行计算的上一个柱的索引为 rates_total-1 (比数组大小小 1)。

因为指标会使用另一指标的数据供其计算,所以我们要获取该数据。您可以利用 CopyBuffer() 函数获取另一指标的数据。您应于函数的第一个参数中指定指标的句柄,复制其相关数据(句柄已于阶段 4 中获取);于第二个参数中指定被复制缓冲区的索引(必要值可通过被复制指标属性的 "Color" 选项卡确定,从零开始计数)。

第三个参数是复制起始柱的索引;本例中的索引是从右到左执行,所以最右边的柱为零。第四个参数为待复制的数组元素数量。确定被复制元素数量时,应像确定纳入计算的柱的范围一样小心谨慎。它会影响到指标的性能。指标计算起始的柱索引已初步确定,所以被复制元素数量则按 rates_total-start 计算。工作过程中,如果只计算成形柱指标,则仅复制数组的一个元素。

如在尝试复制信息时 CopyBuffer() 函数返回 -1,则意味着此数据不得复制,所以也就无需执行计算了。此错误应予处理。于 CopyBuffer() 的最开头声明一个 bool 类型的静态变量并命名为 "error"。如在指标计算过程中出现错误,尤其是复制指标数据的错误,则为此变量赋 True 值,并结束 OnCalculate() 函数的执行。

如果错误值显示此前执行的 OnCalculate() 函数有误,则在下一个订单号再次重新计算整个指标。由此,OnCalculate() 函数的开头如下:

   static bool error=true; 
   int start;
   if(prev_calculated==0) // 在开始指标后第一次执行OnCalculate()函数
     {
      error=true; // 把值设为 True 用于计算所有柱
     }
   if(error) // 如果 error=true, 说明是在开始指标后第一次执行 
             // 或者之前开始时复制数据出错
     {
      start=begin+1;
      error=false;
     }
   else
     {
      start=prev_calculated-1;
     }

   if(CopyBuffer(Handle,0,0,rates_total-start,TsiBuffer)==-1) // 复制指标主线的数据
     {
      error=true; // 复制数据失败, 把error变量的值设为 True 准备下次调用 
                 // OnCalculate() 的时候全部重新计算指标
      return(0);  // 退出函数工作
     }
   if(CopyBuffer(Handle,1,0,rates_total-start,TsiSignalBuffer)==-1) // 复制指标的信号线数据
     {
      error=true; // 复制数据失败, 把 error 变量的值设为 true 准备下次调用
                 // OnCalculate() 函数的时候全部重新计算指标
      return(0);  // 退出函数工作
     }

指标计算的限值已经确定,再于这个柱范围内制作一个计算循环

for(int i=start;i<rates_total;i++)
  {

  }

计算指标值(代码位于刚刚创建的循环中)。

TsiCDBuffer[i]=TsiBuffer[i]-TsiSignalBuffer[i];

现在到了大家最感兴趣的部分了 - 缓冲区上色。在此前的阶段 1 中,我们已经确定了指标缓冲区彩色直方图的使用。该绘制类型要求有两个缓冲区 - 一个用于指标值,另一个用于颜色。颜色列表于 indicator_color1 属性中设置。如果缓冲区元素值设置为 0,则指标以绿色显示;如果值设置为 1,则指标为红色(按照它们在列表 indicator_color1 中的位置;从零开始计数)。

不可避免会产生两个相邻柱的指标值相等的情况,这种情况下,指标应以此前的颜色显示(因为我们用以显示上下动作的颜色只有两种)。因此,计算开始时,我们会复制前柱上 TsiCDColors 缓冲区的值:

TsiCDColors[i]=TsiCDColors[i-1];

向上移动时,指标上绿色

if(TsiCDBuffer[i]>TsiCDBuffer[i-1])TsiCDColors[i]=0;

向下移动时,指标上红色

if(TsiCDBuffer[i]<TsiCDBuffer[i-1])TsiCDColors[i]=1;

我们快要看到指标相关工作胜利的曙光了 - 只剩下确定指标绘制的开头。

7. 完成指标相关工作 

尽管 begin 变量用于确定指标的计算,但并不意味着指标数据从被标识为 begin 变量的柱开始。如果不清楚某自定义指标的算法,想探测到指标计算所需的柱数几乎是不可能的。正因如此,此阶段亦可跳过,或者您也可以根据经验探测某值。但是我们知道 TSIs 指标的算法,所以可精确地探测到此指标的开头。将带有 PLOT_DRAW_BEGIN 标识符的 PlotIndexSetInteger() 函数调用添加到 OnInit() 函数。

PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,r+s+sp);

TSIs 指标的显示值精确到两位小数;利用带有 INDICATOR_DIGITS 标识符的 IndicatorSetInteger() 函数设置同样的精确度:

IndicatorSetInteger(INDICATOR_DIGITS,2);

对指标进行编译,并将其附至图表(图 8)。

 
图 8. 指标 TSIsCDiCust。

利用 IndicatorCreate() 函数创建指标


利用 IndicatorCreate() 函数与利用 iCustom() 函数创建指标基本相同,只是步骤 4 有所区别 - 是利用 IndicatorCreate() 函数,而非 iCustom()。

1. 保存 TSIsCDiCust 指标的一份复本并命名为 TSIsCDiCreate。

2. 查找 iCustom() 函数于代码中何处被调用。自此以后,IndicatorCreate() 函数的调用将取代 iCustom() 执行。与 iCustom() 相同,IndicatorCreate() 函数的前两个参数会确定将用于指标计算的交易品种和时间表。第三个参数是指标类型的一个标识符,对于某个自定义指标而言即 IND_CUSTOM。创建指标的参数被传递至采用 MqlParam 结构数组的函数。

MqlParam 包含四个变量 - 其中三个都是用于下述值的不同类型的变量:double_value、integer_value 与 string_value;另一个为 type,它会确定使用变量的类型。TSIs 指标拥有四个外部参数。因是自定义指标,所以数组的第一个元素会确定自定义指标的名称,由此,数组应包含五个元素。声明一个结构数组(代码位于 iCustom() 被调用的地方):

MqlParam Params[5];

将相应值填入数组:

   Params[0].type=TYPE_STRING;
   Params[0].string_value="TSIs"; // 在第一个参数中指定调用自定义指标的名称
   
   Params[1].type=TYPE_INT;
   Params[1].integer_value=r;
   
   Params[2].type=TYPE_INT;
   Params[2].integer_value=s;   
   
   Params[3].type=TYPE_INT;
   Params[3].integer_value=sp;      
   
   Params[4].type=TYPE_INT;
   Params[4].integer_value=sm;  

传递至 IndicatorCreate() 函数的四个参数,我们已经处理了前三个。参数数组的大小则通过第四个参数传递;最后这个参数是一个带有自身参数的数组:

Handle=IndicatorCreate(_Symbol,PERIOD_CURRENT,IND_CUSTOM,5,Params);

它被留作按下 "Compile" 按钮并于客户端中检查指标用途。

总结

我们简要回顾一下根据另一指标创建自定义指标时您应注意到的几个主要概念。

改进某指标时,您要正确指定缓冲区的数量和待绘制缓冲区的数量(indicator_buffersindicator_plots 属性);您应确定新缓冲区的属性(indicator_labelindicator_typeindicator_colorindicator_styleindicator_width 属性)。调用新缓冲区的 SetIndexBufer() 函数时,您应指定第三个参数的正确值(INDICATOR_DATAINDICATOR_CALCULATIONS);并正确指定第一个参数的值(缓冲区索引);必要时执行缓冲区的重新索引。

利用另一个自定义指标创建一个新指标时,您要将参数正确地传递至 iCustom() 函数;并在使用 IndicatorCreate() 函数时填写参数结构。这里您还应注意到调用 SetIndexBuffer() 函数时参数的正确规范;而且重要的是不要忘记执行新缓冲区的 SetIndexBuffer() 函数调用。

每次使用指标,您都应重视柱计算的范围 - 利用 prev_calculatedrates_totalbegin 变量的值。MetaEditor 会帮助您处理编程过程中可能出现的其它错误(编译期间出现的错误信息会显示于 "Errors" 选项卡)。