English Русский Español Deutsch 日本語 Português
创建自定义指标的特性

创建自定义指标的特性

MetaTrader 4示例 | 15 一月 2016, 11:59
5 499 0
MetaQuotes
MetaQuotes

在MetaTrader交易系统中创建自定义指标有一些特性.

  • 对于考虑做成自定义指标的程序, 一定要作如下二选一的定义:

    #property  indicator_chart_window      // 指标在主图表窗口绘制

    或者

    #property  indicator_separate_window   // 指标在独立窗口中绘制
  • 为了设置独立指标窗口的尺度, 要使用如下定义:

    #property  indicator_minimum Min_Value
    #property  indicator_maximum Max_Value
    

    其中 "Min_Value" 和 "Max_Value" 是对应的数值. 例如, 对于自定义指标 RSI 来说, 这些数值必须为0和100.

  • 为绘制指标所需的指标数组的数量必须如下定义:

    #property  indicator_buffers N

    其中N可以在从1到8之间选择.

  • 指标线的颜色可以由以下定义设置:

    #property  indicator_color1  Silver
    #property  indicator_color2  Red
    ...
    #property  indicator_colorN  <SomeColor>
    

    其中 N 就是使用 "#define indicator_buffer" 定义的指标数组的数量.

  • 还有一些用于控制指标计算和显示的函数. 这里使用 Ishimoku Kinko Hyo 自定义指标做说明:

    //+------------------------------------------------------------------+
    //|                                                     Ichimoku.mq4 |
    //|                      Copyright © 2004, MetaQuotes Software Corp. |
    //|                                       https://www.metaquotes.net/ |
    //+------------------------------------------------------------------+
    #property copyright "Copyright © 2004, MetaQuotes Software Corp."
    #property link      "https://www.metaquotes.net/"
     
    #property indicator_chart_window
    #property indicator_buffers 7
    #property indicator_color1 Red
    #property indicator_color2 Blue
    #property indicator_color3 SandyBrown
    #property indicator_color4 Thistle
    #property indicator_color5 Lime
    #property indicator_color6 SandyBrown
    #property indicator_color7 Thistle
    //---- 输入参数
    extern int Tenkan=9;
    extern int Kijun=26;
    extern int Senkou=52;
    //---- 指标缓冲区
    double Tenkan_Buffer[];
    double Kijun_Buffer[];
    double SpanA_Buffer[];
    double SpanB_Buffer[];
    double Chinkou_Buffer[];
    double SpanA2_Buffer[];
    double SpanB2_Buffer[];
    //---- span_a 开始绘制
    int a_begin;
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    int init()
      {
    //----
       SetIndexStyle(0,DRAW_LINE);
       SetIndexBuffer(0,Tenkan_Buffer);
       SetIndexDrawBegin(0,Tenkan-1);
       SetIndexLabel(0,"Tenkan Sen");
    //----
       SetIndexStyle(1,DRAW_LINE);
       SetIndexBuffer(1,Kijun_Buffer);
       SetIndexDrawBegin(1,Kijun-1);
       SetIndexLabel(1,"Kijun Sen");
    //----
       a_begin=Kijun; if(a_begin&lt;Tenkan) a_begin=Tenkan;
       SetIndexStyle(2,DRAW_HISTOGRAM,STYLE_DOT);
       SetIndexBuffer(2,SpanA_Buffer);
       SetIndexDrawBegin(2,Kijun+a_begin-1);
       SetIndexShift(2,Kijun);
       SetIndexLabel(2,NULL);
       SetIndexStyle(5,DRAW_LINE,STYLE_DOT);
       SetIndexBuffer(5,SpanA2_Buffer);
       SetIndexDrawBegin(5,Kijun+a_begin-1);
       SetIndexShift(5,Kijun);
       SetIndexLabel(5,"Senkou Span A");
    //----
       SetIndexStyle(3,DRAW_HISTOGRAM,STYLE_DOT);
       SetIndexBuffer(3,SpanB_Buffer);
       SetIndexDrawBegin(3,Kijun+Senkou-1);
       SetIndexShift(3,Kijun);
       SetIndexLabel(3,NULL);
       SetIndexStyle(6,DRAW_LINE,STYLE_DOT);
       SetIndexBuffer(6,SpanB2_Buffer);
       SetIndexDrawBegin(6,Kijun+Senkou-1);
       SetIndexShift(6,Kijun);
       SetIndexLabel(6,"Senkou Span B");
    //----
       SetIndexStyle(4,DRAW_LINE);
       SetIndexBuffer(4,Chinkou_Buffer);
       SetIndexShift(4,-Kijun);
       SetIndexLabel(4,"Chinkou Span");
    //----
       return(0);
      }
    //+------------------------------------------------------------------+
    //| Ichimoku Kinko Hyo                                               |
    //+------------------------------------------------------------------+
    int start()
      {
       int    i,k;
       int    counted_bars=IndicatorCounted();
       double high,low,price;
    //----
       if(Bars&lt;=Tenkan || Bars&lt;=Kijun || Bars&lt;=Senkou) return(0);
    //---- 用0初始化
       if(counted_bars&lt;1)
         {
          for(i=1;i&lt;=Tenkan;i++)    Tenkan_Buffer[Bars-i]=0;
          for(i=1;i&lt;=Kijun;i++)     Kijun_Buffer[Bars-i]=0;
          for(i=1;i&lt;=a_begin;i++) { SpanA_Buffer[Bars-i]=0; SpanA2_Buffer[Bars-i]=0; }
          for(i=1;i&lt;=Senkou;i++)  { SpanB_Buffer[Bars-i]=0; SpanB2_Buffer[Bars-i]=0; }
         }
    //---- Tenkan Sen
       i=Bars-Tenkan;
       if(counted_bars>Tenkan) i=Bars-counted_bars-1;
       while(i>=0)
         {
          high=High[i]; low=Low[i]; k=i-1+Tenkan;
          while(k>=i)
            {
             price=High[k];
             if(high&lt;price) high=price;
             price=Low[k];
             if(low>price)  low=price;
             k--;
            }
          Tenkan_Buffer[i]=(high+low)/2;
          i--;
         }
    //---- Kijun Sen
       i=Bars-Kijun;
       if(counted_bars>Kijun) i=Bars-counted_bars-1;
       while(i>=0)
         {
          high=High[i]; low=Low[i]; k=i-1+Kijun;
          while(k>=i)
            {
             price=High[k];
             if(high<price) high=price;
             price=Low[k];
             if(low>price)  low=price;
             k--;
            }
          Kijun_Buffer[i]=(high+low)/2;
          i--;
         }
    //---- Senkou Span A
       i=Bars-a_begin+1;
       if(counted_bars>a_begin-1) i=Bars-counted_bars-1;
       while(i>=0)
         {
          price=(Kijun_Buffer[i]+Tenkan_Buffer[i])/2;
          SpanA_Buffer[i]=price;
          SpanA2_Buffer[i]=price;
          i--;
         }
    //---- Senkou Span B
       i=Bars-Senkou;
       if(counted_bars>Senkou) i=Bars-counted_bars-1;
       while(i>=0)
         {
          high=High[i]; low=Low[i]; k=i-1+Senkou;
          while(k>=i)
            {
             price=High[k];
             if(high&lt;price) high=price;
             price=Low[k];
             if(low>price)  low=price;
             k--;
            }
          price=(high+low)/2;
          SpanB_Buffer[i]=price;
          SpanB2_Buffer[i]=price;
          i--;
         }
    //---- Chinkou Span
       i=Bars-1;
       if(counted_bars>1) i=Bars-counted_bars-1;
       while(i>=0) { Chinkou_Buffer[i]=Close[i]; i--; }
    //----
       return(0);
      }
    //+------------------------------------------------------------------+
    
  • "SetIndexStyle" 函数控制一个指标数组的绘制参数. DRAW_LINE 绘制模式规定, 在对应指标数组中定义的数值之间使用直线来绘制. DRAW_HISTOGRAM 绘制模式用于主窗口指标的绘制, 它也有其特性. 柱状图绘制在两个索引数组中的数值之间: 一个偶数数组(这里是 SpanA_Buffer) 和一个奇数数组(这里是 SpanB_Buffer). 另外, 索引更高的数组用于颜色数值.

  • "SetIndexDrawBegin" 函数制定了从指标数组的那个元素开始绘制.

  • "SetIndexBuffer" 函数允许把任何类型为"double"的一维数组声明为索引数组. 然后, 系统将管理索引数组. 这就是为什么其中有些数组不需要被特别指定.

    //---- 指标缓冲区
    double Tenkan_Buffer[];
    double Kijun_Buffer[];
    double SpanA_Buffer[];
    double SpanB_Buffer[];
    double Chinkou_Buffer[];
    double SpanA2_Buffer[];
    double SpanB2_Buffer[];
    

    ArrayResize 函数不能应用于指标数组, 因为它不起作用. 同样, 在指标数组中使用ArrayInitialize函数也是不起作用的, 当指标缓冲区尚未分配时, 就更加不需要"初始化"功能. 指标数组是在内存的分配和重新分配时自动初始化的. 是使用 EMPTY_VALUE, 或者 SetIndexEmptyValue 函数指定的数值作为初始值的. "空"数值不会显示.

  • "SetIndexLabel" 函数用于设置显示于工具提示和数据窗口中数值的名称, (默认为"ValueN", 其中N就是数组的索引编号). 如果传入NULL而不是名称, 对应的数值就不会在工具提示和数据窗口中显示. 在以上的例子中, 云使用了柱形图做阴影, 而以线为框. 其中, 对应的"线"和"柱形图"数组是相同的, 也可以只显示它们中的一个.

  • "IndicatorCounted" 函数可以使指标计算更加经济. 这个函数返回指标载入时到某一时刻的柱的数量, 也就是说, 已经计算过的柱数(潜在要求是之前载入没有错误), 它们不需要重新计算了. 自定义指标重新初始化或者历史数据有了大的更新时, 此数量会被自动重设为0.

  • 让我们多讨论一个实例. 这个自定义指标称为加速/减速震荡指标:

    //+------------------------------------------------------------------+
    //|                                                  Accelerator.mq4 |
    //|                      Copyright © 2005, MetaQuotes Software Corp. |
    //|                                       https://www.metaquotes.net/ |
    //+------------------------------------------------------------------+
    #property  copyright "Copyright © 2005, MetaQuotes Software Corp."
    #property  link      "https://www.metaquotes.net/"
    //---- 指标设置
    #property  indicator_separate_window
    #property  indicator_buffers 3
    #property  indicator_color1  Black
    #property  indicator_color2  Green
    #property  indicator_color3  Red
    //---- 指标缓冲区
    double     ExtBuffer0[];
    double     ExtBuffer1[];
    double     ExtBuffer2[];
    double     ExtBuffer3[];
    double     ExtBuffer4[];
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    int init()
      {
    //---- 使用额外两个缓冲区进行计数.
       IndicatorBuffers(5);
    //---- 绘图设置
       SetIndexStyle(0,DRAW_NONE);
       SetIndexStyle(1,DRAW_HISTOGRAM);
       SetIndexStyle(2,DRAW_HISTOGRAM);
       IndicatorDigits(Digits+2);
       SetIndexDrawBegin(0,38);
       SetIndexDrawBegin(1,38);
       SetIndexDrawBegin(2,38);
    //---- 4个指标缓冲区的镜像
       SetIndexBuffer(0,ExtBuffer0);
       SetIndexBuffer(1,ExtBuffer1);
       SetIndexBuffer(2,ExtBuffer2);
       SetIndexBuffer(3,ExtBuffer3);
       SetIndexBuffer(4,ExtBuffer4);
    //---- 数据窗口和指标子窗口的标签名称
       IndicatorShortName("AC");
       SetIndexLabel(1,NULL);
       SetIndexLabel(2,NULL);
    //---- 初始化完成
       return(0);
      }
    //+------------------------------------------------------------------+
    //| 加速/减速振荡指标                                                  |
    //+------------------------------------------------------------------+
    int start()
      {
       int    limit;
       int    counted_bars=IndicatorCounted();
       double prev,current;
    //---- 最后计数的柱将要重新计数
       if(counted_bars>0) counted_bars--;
       limit=Bars-counted_bars;
    //---- macd 计数的额外一个缓冲区
       for(int i=0; i&lt;limit; i++)
          ExtBuffer3[i]=iMA(NULL,0,5,0,MODE_SMA,PRICE_MEDIAN,i)-
                        iMA(NULL,0,34,0,MODE_SMA,PRICE_MEDIAN,i);
    //---- 信号线计数的第二个额外缓冲区
       for(i=0; i<limit; i++)
          ExtBuffer4[i]=iMAOnArray(ExtBuffer3,Bars,5,0,MODE_SMA,i);
    //---- 在两个缓冲区之间分发数据
       bool up=true;
       for(i=limit-1; i>=0; i--)
         {
          current=ExtBuffer3[i]-ExtBuffer4[i];
          prev=ExtBuffer3[i+1]-ExtBuffer4[i+1];
          if(current>prev) up=true;
          if(current&lt;prev) up=false;
          if(!up)
            {
             ExtBuffer2[i]=current;
             ExtBuffer1[i]=0.0;
            }
          else
            {
             ExtBuffer1[i]=current;
             ExtBuffer2[i]=0.0;
            }
           ExtBuffer0[i]=current;
         }
    //---- 完成
       return(0);
      }
    //+------------------------------------------------------------------+
    
  • "IndicatorBuffers" 函数指定了在指标计算过程中用到的缓冲区数量. 通常情况下, 如果绘制指标需要更多索引数组时会调用它. 这样系统会管理额外的数组.

  • "SetIndexDigits" 函数管理输出信息的精确度. 在本例中, 当计算两个移动平均之差以及信号线时, 标准的小数点后四位精确度是不够的.

  • "SetIndexDrawBegin" 函数指定了指标数组中元素开始计算的位置. 在我们的例子中, 信号线是按另外一条简单移动平均的简单移动平均来计算的. 这就是为何指标的前38个值不会绘制而作为空值存在.

  • "IndicatorShortName" 函数设置指标的短名称, 它将显示在指标窗口的左上角以及"数据窗口"中. 如果没有设置段名称, 就会使用自定义指标的名字. 在本例中, 不需要SetIndexLabel函数, 因为只有一个输出值. 所以, 指标的名称对于一个值就足够了.

  • "SetIndexStyle" 函数管理指标数组的绘制参数. DRAW_NONE 绘制模式表示该线无需绘制. 重要的是, 指标的柱形图必须使用两种不同颜色. 来自ExtBuffer0 的数据被分配在另外两个数组中, ExtBuffer1 和 ExtBuffer2. 为了不在工具提示和数据窗口中显示数据, 要在SetIndexLabel函数的参数中使用NULL. 在独立窗口的指标中使用 DRAW_HISTOGRAM 模式可以在0值和对应的数组(和以上描述的在主窗口中画柱形图做比较)绘制柱形图.

  • 用于自定义指标计算的输入参数和函数必须被定义为"extern", 可以是任何类型.

  • 如果自定义指标没有设置任何输入参数, 它将以最简单的形式被调用.

    double current_AC = iCustom( NULL, 0, "Accelerator", 0, 0 );

    前面两个参数分别传入"NULL"和"0"表示会使用当前的图表. 自定义指标的名称使用的是对应文件的名字(不包括mq4的扩展名). 如果倒数第二个参数设为0, 它表示我们只对第一个指标数组有兴趣. 最后一个参数是0表示我们只关心所需指标数组的最后一个元素(也就是说, 最新的, 当前的数值).

  • 参数就是按照上面描述的方式通过函数传给自定义指标计算的. 例如, 自定义指标名称为 "Ichimoku", 它的参数有(9,26,52), 将被如下调用:

    iCustom( NULL, 0, "Ichimoku", 9, 26, 52, 0, shift );

    严格来说, 不一定要把参数传给传给自定义指标函数. 如果程序中没有外部变量, 也就不用传参数. 或者, 如果需要, 可以使用参数描述中的初始值. 例如, 不使用参数调用相同的自定义指标可以如下调用:

    iCustom( NULL, 0, "Ichimoku", 0, shift );

    这表示变量将使用初始值, 即 "Tenkan", "Kijun", "Senkou", 以及, 9, 26, 和 52. 然而, 如果是在EA交易中调用具有多组参数的自定义指标, 并不推荐使用默认设置.

请必须注意, 使用过多的自定义指标或者指标编写得不正确, 都有可能使客户终端的运行明显变慢!

警告: MetaQuotes Software Corp. 保有这些资料的全部权利. 全部或部分复制都是禁止的.

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

市场理论 市场理论
逻辑上完整的市场理论应该包含所有品类的商品和服务市场,像外汇这种微观和宏观市场到目前为止还不包括其中。本文介阐释基于盈利分析的新市场理论的精髓。揭示了当前价格变化的运行机制和原则,即通过形成能对实际价格产生控制影响的虚拟价格链,来找到最优定价。市场趋势的形成和改变机制在这里将得到阐释。
无缝图表 无缝图表
本文介绍了没有跳空柱形图表的实现.
EA交易, 脚本程序和指标的同步 EA交易, 脚本程序和指标的同步
本文介绍了开发捆绑程序, 即可能同时包含EA交易, 脚本程序和指标的程序集合的必要性以及通用原则.
MetaTrader 4 中的事件 MetaTrader 4 中的事件
本文介绍的是使用编程方法追踪MetaTrader 4客户终端中的事件, 它的目标读者是对终端的操作和MQL4编程具有基本知识和技能的人员.