English Русский Español Deutsch 日本語 Português
在一些指标中多次重新计算基础柱体

在一些指标中多次重新计算基础柱体

MetaTrader 4示例 | 6 十二月 2006, 10:52
6 207 1
Nikolay Kositsin
Nikolay Kositsin


在这篇文章中,我想讨论一下 MetaTrader 4 客户端中当基础柱体改变时多次重新计算指标值。它的核心问题是,你能够在网上找到许多好的指标,他们只对于历史数据运作正常,但当交易平台连接上服务器时,它们得出的结果,说得婉转一些,就是不能实现设置在这些指标中的运算规则!

通常,这些指标的作者,在斟酌了这个问题后,最终找到了一个简单但不聪明得解决方法:他们重新计算他们的指标图表中所有的柱体在每次运行 int start() 函数时的值,来得出最后那个基础柱体的值。

第一眼看上去所有问题好象都这样解决了,但是事实上,问题转移到了另一个范畴。这样的指标占用系统资源,结果会导致电脑死机。

为了解决这个问题,我们首先应该考虑指标被建立的一般思路。每个指标都是含有一些变量的函数:


Indicator = Function (Variable1, Variable2, Variable3, .... etc.).

所有的指标可以被分成两大类:

  • 第一类 - 这类指标的所有变量只使用安全价位和外部变量进行计算;对于任何柱体,这些变量的计算都不用考虑之前柱体的相应变量。
  • 第二类 - 在这类指标中,至少有一个变量是通过之前柱体的相应变量计算而来的:

    VariableN(i) = FunctionN(VariableN(i+1)),

    左边的值根据第 i 个柱体而得,右边括号里的值根据第 i+1 个柱体而得。或者至少这个变量是通过先前柱体的另一个变量而计算初的:

    VariableN(i) = FunctionR(VariableX(i+1)),

    同样地,左边的值是根据第 i 个柱体而得,右边括号里的值根据第 i+1 个柱体而得。

我们对第二类指标感兴趣,因为它引出了上面的问题。指标在哪里需要在基础柱体上被多次重算,这些变量在逻辑上应该和另一些柱体开始对所有柱体多次重新计算的值一样,即使这个指标是用 IndicatorCounted() 函数只依靠对基础柱体重新计算而编制的。这种指标被证明对于实时行情是完全没用的。为了解释这些,让我们来看一下这个特殊的指标:


//+------------------------------------------------------------------+
//|                                                           T3.mq4 |
//|                                                           MojoFX |
//| http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/ |
//+------------------------------------------------------------------+
#property copyright "MojoFX - Conversion only"
 
#property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/"
//----
#property indicator_chart_window
#property indicator_buffers 1
 
#property indicator_color1 Red
//----
extern int MA_Period = 14;
extern double b = 0.7;
 
//----
double MapBuffer[];
double e1, e2, e3, e4, e5, e6;
 
double c1, c2, c3, c4;
double n, w1, w2, b2, b3;
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
    SetIndexStyle(0, DRAW_LINE);
    IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS));
    IndicatorShortName("T3" + MA_Period);
    SetIndexBuffer(0, MapBuffer);
    b2 = b * b;
    b3 = b2 * b;
    c1 = -b3;
    c2 = (3 * (b2 + b3));
    c3 = -3 * (2 * b2 + b + b3);
    c4 = (1 + 3 * b + b3 + 3 * b2);
    n = MA_Period;
    if(n < 1) 
        n=1;
    n = 1 + 0.5 * (n - 1);
    w1 = 2 / (n + 1);
    w2 = 1 - w1;
    //----
 
    return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
 
  {
    // In this case, indicator's values are fully recalculated 
    // on all bars at every launch of the start() function
    for(int bar = Bars-1; bar >= 0; bar--)
 
    /*
          If the line named "for(int bar=Bars-1; bar>=0; bar--)" is replaced with the four lines below
 
          for recounting of the indicator on only last bars 
          at each launch of the start() function, this indicator will work properly 
          only on historical data:
 
         int  limit,counted_bars=IndicatorCounted();
         if(counted_bars>0) counted_bars--;
         limit=Bars-1-counted_bars;
         for(int bar=limit; bar>=0; bar--)
         */
      {
        // Variables e1,e2,e3,e4,e5,e6 are functions of themselves 
        // calculated on the preceding bar  
        e1 = w1 * Close[bar] + w2 * e1;
        e2 = w1 * e1 + w2 * e2;
        e3 = w1 * e2 + w2 * e3;
        e4 = w1 * e3 + w2 * e4;
        e5 = w1 * e4 + w2 * e5;
        e6 = w1 * e5 + w2 * e6;
 
        MapBuffer[bar]=c1 * e6 + c2 * e5 + c3 * e4 + c4 * e3;
      }
 
    //----
    return(0);
  }
//+------------------------------------------------------------------+


在这个案例中,最简单的解决方法是用我曾经在指标代码中提到过的数组来代替变量:

//+------------------------------------------------------------------+
//| T3.mq4                                                           |
//| MojoFX                                                           |
//| http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/ |
//+------------------------------------------------------------------+
#property copyright "MojoFX - Conversion only"
 
#property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
 
extern int T3_Period = 14;
extern double b = 0.7;
 
double MapBuffer[];
//---- Turning of variables into buffers
double e1[], e2[], e3[], e4[], e5[], e6[];
 
//----
double c1, c2, c3, c4;
double n, w1, w2, b2, b3;
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- 
   SetIndexStyle(0, DRAW_LINE);
 
   IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS));
   IndicatorShortName("T3" + T3_Period);
 
   SetIndexBuffer(0, MapBuffer);
//---- Writing of variables into indicator buffers
   IndicatorBuffers(7);
 
   SetIndexBuffer(1, e1);
   SetIndexBuffer(2, e2);
   SetIndexBuffer(3, e3);
 
   SetIndexBuffer(4, e4);
   SetIndexBuffer(5, e5);
   SetIndexBuffer(6, e6);
 
//----
   b2=b*b;
   b3=b2*b;
   c1=-b3;
 
   c2=(3*(b2+b3));
   c3=-3*(2*b2+b+b3);
 
   c4=(1+3*b+b3+3*b2);
 
   n=T3_Period;
   if (n<1) n=1;
 
   n = 1 + 0.5*(n-1);
   w1 = 2 / (n + 1);
 
   w2 = 1 - w1;
//----
   return(0);
 
  }
//+-----------------------------------------------------------------------+
//| Custom indicator iteration function                                   |
//+-----------------------------------------------------------------------+
int start()
  {
 
//----+ check whether the amount of bars is sufficient for correct 
//      calculation of the indicator
   if(Bars - 1 < T3_Period)
       return(0);
 
//----+ Entering of integer variables and obtaining of bars already counted
   int MaxBar, limit, counted_bars = IndicatorCounted();
 
//---- check for possible errors
   if(counted_bars < 0)
       return(-1);
//---- the last counted bar must be re-counted
 
   if(counted_bars > 0) 
       counted_bars--;
//---- determining of the oldest bar number, starting from which
//     all bars will be re-counted
   MaxBar = Bars - 1 - T3_Period;
 
//---- determining of the oldest bar number, starting from which
//     only new bars will be re-counted
   limit = (Bars - 1 - counted_bars);
 
//---- initialization of null
   if(limit > MaxBar)
     {
       for(int bar = Bars - 1; bar >= limit; bar--)
 
           MapBuffer[bar] = 0.0;
       limit = MaxBar; 
     }
//+--- basic loop of indicator calculation
 
   for(bar = limit; bar >= 0; bar--)
     {  
       e1[bar] = w1*Close[bar] + w2*e1[bar+1];
       e2[bar] = w1*e1[bar] + w2*e2[bar+1];
       e3[bar] = w1*e2[bar] + w2*e3[bar+1];
       e4[bar] = w1*e3[bar] + w2*e4[bar+1];
       e5[bar] = w1*e4[bar] + w2*e5[bar+1];
       e6[bar] = w1*e5[bar] + w2*e6[bar+1];
       MapBuffer[bar] = c1*e6[bar] + c2*e5[bar] + c3*e4[bar] + c4*e3[bar];
     } 
 
//+--- termination of the basic loop
   return(0);
  }
//+----------------------------------------------------------------+

问题被解决了,但既然这样,这是解决特殊问题的特殊办法:这样会有非常多的变量,这也是为什么决不能把所有的变量都放入指标缓冲区。在这种情况下,通常的解决方法都是这样的,为了正常地多次重算指标值,我们只需要依靠第二个柱体来计算出的指标而获得的变量值,而这不但是重新计算最终值,也是重新计算只有一个柱体的最终值的更好的更广泛的方法!

因此,在第二个柱体循环结束时的那些变量值必须被存储在那些并不包含在指标的任一程序块中的用来存储的变量里,也就是那些在指标代码开头被定义的变量。这些存储变量可以被编入初学者的文章,在 int start() 函数里介绍。当指标计算循环钱每次运行 start() 函数时,如果被计算的柱体之一不等于零(if (IndicatorCounted()!=0),从存储变量中提取值赋予当前的指标变量。这此之后,没有计算过的柱体可以当作开始时那样,被同样的代码进行计算!大家最好记住这些变量不是在第二个柱体的循环结束时,而是在第一个柱体的开始处。这是我们在更复杂的例子中要做的!下面是用这种思路编写的同样的指标:


//+-------------------------------------------------------------------------+
//|                                                           T3.mq4        |
//|                              Copyright  2005,            MojoFX         | 
//|  http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators        | 
//+-------------------------------------------------------------------------+
 
#property copyright "MojoFX - Conversion only"
#property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/"
#property indicator_chart_window
 
#property indicator_buffers  1
#property indicator_color1  Yellow 
//---- 
extern int  T3_Period = 8;  
 
extern double b = 0.7;
//---- 
//---- 
double MapBuffer[];
 
//----  
double e1, e2, e3, e4, e5, e6;
 
double n, c1, c2, c3, c4, w1, w2, b2, b3;
 
//---- introduction of variables to save variables e1,e2,e3,e4,e5,e6
int time2; double E1, E2, E3, E4, E5, E6;
 
//+--------------------------------------------------------------------------+ 
//|  T3 initialization function                                              |
//+--------------------------------------------------------------------------+
int init()
  {
//---- indicators setting
   SetIndexStyle(0, DRAW_LINE);
 
   IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS));
   IndicatorShortName("T3" + T3_Period);
 
   SetIndexBuffer(0, MapBuffer);
   b2 = b*b;
 
   b3 = b2*b;
   c1 = -b3;
   c2 = (3*(b2 + b3));
 
   c3 = -3*(2*b2 + b + b3);
   c4 = (1 + 3*b + b3 + 3*b2);
 
   if(T3_Period < 1) 
       T3_Period = 1;
   n = 1 + 0.5*(T3_Period - 1);
 
   w1 = 2 / (n + 1);
   w2 = 1 - w1;
 
//---- initialization complete
   return(0);
  }
//+---------------------------------------------------------------------------+
//| T3 iteration function                                                     |
//+---------------------------------------------------------------------------+
 
int start()
  {
//----+ check whether the amount of bars is enough for correct 
//      indicator calculation
   if(Bars-1 < T3_Period)
       return(0);
 
//----+ introduction of integer variables and getting of bars already counted
   int MaxBar, limit, counted_bars = IndicatorCounted();
 
//---- check for possible errors
   if(counted_bars < 0)
       return(-1);
 
//---- the last counted bar must be re-counted
   if(counted_bars > 0) 
       counted_bars--;
//---- determining of the oldest bar number, starting from which 
//     all bars will be re-counted
   MaxBar = Bars - 1 - T3_Period;
 
//---- determining of the oldest bar number, starting from which 
//     only new bars will be re-counted
   limit = (Bars - 1 - counted_bars);
//---- initialization of null
 
   if(limit > MaxBar)
     {
       for(int bar = Bars - 1; bar >= MaxBar; bar--)
 
           MapBuffer[bar] = 0.0;
       limit = MaxBar; 
     }
 
//+--- before the basic loop of indicator calculation, restore values
//     of variables as they were after counting on the second bar
//+--- restore values of the variables +=======+
   int Tnew = Time[limit+1];
 
   if(limit < MaxBar)
   if(Tnew == time2)
 
     {
       e1 = E1; 
       e2 = E2; 
 
       e3 = E3; 
       e4 = E4; 
       e5 = E5; 
 
       e6 = E6;  
     }
   else 
     {
       if(Tnew > time2)
           Print("ERROR01");
       else 
           Print("ERROR02");
       return(-1);
     }
 
//+--- +==========================================+
//+--- Basic loop to calculate the indicator
   for(bar = limit; bar >= 0; bar--)
 
     {
       //+--- Memorize values of variables as they were after 
       //     the second bar
       //+--- Save values of the variables +=============+ 
       if(bar == 1)
 
           if(((limit == 1)&&(time2 != Time[2])) || (limit > 1))
 
             {
               time2 = Time[2];
               E1 = e1; 
 
               E2 = e2; 
               E3 = e3; 
               E4 = e4; 
               E5 = e5; 
 
               E6 = e6;
 
             }
       //+---+============================================+
       e1 = w1*Close[bar] + w2*e1;
 
       e2 = w1*e1 + w2*e2;
       e3 = w1*e2 + w2*e3;
       e4 = w1*e3 + w2*e4;
       e5 = w1*e4 + w2*e5;
       e6 = w1*e5 + w2*e6;
       MapBuffer[bar]=c1*e6 + c2*e5 + c3*e4 + c4*e3;
     } 
 
   //+--- terminate the basic loop
   return(0);
  }
//+-----------------------------------------------------------------+

和前面的比较,这个指标需要更少的信息存储在内存中的变量里。但它看上去比前一个更复杂!

下面这段代码是同一个指标的,使用了 int start() 函数,提供给能够将智能交易程序和代码结合的高级开发者。在这段代码里,智能交易程序只在基础柱体上计算指标。当然代码里的这个变量只适合作为历史数据的测试程序。对于智能交易程序的在线运作,我们不得不使用另一个代码里的变量,来自于我们在最后的例子中研究的指标。假设,如果一个新的基础柱体开始形成,在第一个柱体上的指标值完全被计算出并且不应该被重新计算。同样也适用于柱体变化时被储存的变量。这里需要强调,如果这样一段复杂的代码没有写入智能交易程序,就不可能明白这样的程序怎么样进行计算,在什么基础上来进行交易!如果代替这段代码,用被证实的变量,每个价位都在所有的柱体上重新进行计算指标,最后得出基础柱体,我们可能用一个月的时间来等结果!

int start()
  {
//----+ check whether the amount of bars is enough for correct 
//      indicator calculation
   if(Bars-1 < T3_Period)

       return(0);
//---- determine the oldest bar number, starting from which 
//     all bars will be re-counted
   int MaxBar = Bars - 1 - T3_Period;

//---- initialization of null
   if(MaxBar = 0)
       for(int bar = Bars - 1; bar > 0; bar--)
           MapBuffer[bar] = 0.0;

//+--- before basic indicator calculation, restore values 
//     of variables as they were after calculation on the first bar
//+--- restoring values of variables +=======+
   int Tnew0 = Time[2];
   int Tnew1 = Time[2+1];

   if(Tnew0 == time2)
     {
       e1 = E1; 
       e2 = E2; 

       e3 = E3; 
       e4 = E4; 
       e5 = E5; 
       e6 = E6;  
     }

   else 
       if(Tnew1 != time2)
         {

           if(Tnew1 > time2)
               Print("ERROR01");
           else 

               Print("ERROR02");
           return(-1);
         }

//+--- +==============================================+
//+--- Memorize values of variables as they were after 
//     the first bar
//+--- Saving of values of variables +================+ 
   if(Tnew0 != time2)
     {

       time2 = Tnew0;
       E1 = e1; 
       E2 = e2; 
       E3 = e3; 
       E4 = e4; 
       E5 = e5; 
       E6 = e6;
     }

//+---+============================================+
 
//+--- indicator calculation (calculation is made always 
//     only on the null bar)
   e1 = w1*Close[0] + w2*e1;

   e2 = w1*e1 + w2*e2;
   e3 = w1*e2 + w2*e3;

   e4 = w1*e3 + w2*e4;
   e5 = w1*e4 + w2*e5;

   e6 = w1*e5 + w2*e6;
   MapBuffer[0] = c1*e6 + c2*e5 + c3*e4 + c4*e3;

//----+ ------------------------------------------------+
//----+ The code of your expert must be placed here     |
//----+ ------------------------------------------------+
   return(0);
  }
//+----------------------------------------------------------------+


当然,这段代码变得复杂了一些!

下面是个可仿效的指标,在这个指标里,为了运作正常,当运行 int start() 函数时,只有一个逻辑变量必须被储存。但是如果没有这个几乎不被察觉的变化,指标不能适当地运作:


//+------------------------------------------------------------------+
//|                                                   3LineBreak.mq4 |
//|                               Copyright 2004, Poul_Trade_Forum   |
//|                                                         Aborigen |
//+------------------------------------------------------------------+ 
#property indicator_chart_window 
#property indicator_buffers 2
#property indicator_color1 Gold
#property indicator_color2 Magenta
 
//---- 
extern int Lines_Break = 3;
//---- 
double HighBuffer[];
 
double LowBuffer [];
//---- 
double VALUE1, VALUE2, Swing = 1, OLDSwing;
 
//---- Introduction of variables for multiple re-count of bar 
int time2, SWING;
//+---------------------------------------------------------------------+
//| 3LineBreak initialization function                                  |
//+---------------------------------------------------------------------+ 
int init()
 
  {   
//---- Chart is performed as a hystogram 
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexStyle(1, DRAW_HISTOGRAM);
 
//---- 2 indicator buffers are used for counting.
   SetIndexBuffer(0, HighBuffer);
   SetIndexBuffer(1, LowBuffer );
 
//---- setting of indicator values that will not be visible on the chart
   SetIndexEmptyValue(0, 0);
   SetIndexEmptyValue(1, 0);
 
//---- names for data windows and labels for subwindows.
   IndicatorShortName("3LineBreak");
   SetIndexLabel   (0, "3LineBreak");
 
//---- setting of the bar number, starting from which the indicator 
//     will be drawn  
   SetIndexDrawBegin(0, Lines_Break);
   SetIndexDrawBegin(1, Lines_Break);
 
//---- termination of the initialization
   return(0);
  }
//+------------------------------------------------------------------+
//| 3LineBreak iteration function                                    |
//+------------------------------------------------------------------+ 
int start()
 
  {
//----+ Introduction of integer variables and getting of bars already counted
   int MaxBar, limit, counted_bars = IndicatorCounted();
 
//---- check for possible errors
   if(counted_bars < 0)
       return(-1);
//---- the last counted bar must be re-counted )
 
   if(counted_bars > 0) 
       counted_bars--;
//---- determining of the oldest bar number, starting from which 
//     all bars will be re-counted
   MaxBar = Bars - 1 - Lines_Break;
 
//---- determining of the oldest bar number, starting from which 
//     only new bars will be re-counted
   limit = (Bars - 1 - counted_bars);
 
//---- initialization of null
   if(limit > MaxBar)
     {
       for(int bar = limit; bar > MaxBar; bar--)
 
         { 
           HighBuffer[bar] = 0.0; 
           LowBuffer[bar] = 0.0; 
         }
 
       limit=MaxBar;
     }
//----
//+--- restoring of values of variables +================+
   int Tnew = Time[limit+1];
 
   if(limit < MaxBar)
   if(Tnew == time2)
       Swing = SWING; 
   else
 
     {
       if(Tnew > time2)
           Print("ERROR01");
       else 
 
           Print("ERROR02");
       return(-1);  
     }
 
//+--- +==================================================+
//+--- basic loop of indicator calculation
   for(bar = limit; bar >= 0; bar--)
 
     {
       //+--- Saving of values of variables +=============+ 
       if(bar == 1)
           if(((limit == 1) && (time2 != Time[2]))||(limit > 1))
 
             {
               time2 = Time[2];
               SWING = Swing;
             }
 
       //+---+============================================+
       OLDSwing = Swing;
       //----
       VALUE1 = High[Highest(NULL, 0, MODE_HIGH, Lines_Break, bar + 1)];
       VALUE2 = Low[Lowest(NULL, 0, MODE_LOW, Lines_Break, bar + 1)];
       //----
 
       if(OLDSwing == 1 &&  Low [bar] < VALUE2) 
           Swing = -1;
       if(OLDSwing == -1 &&  High[bar] > VALUE1) 
           Swing = 1;
       //----
 
       if(Swing == 1)
         { 
           HighBuffer[bar] = High[bar]; 
           LowBuffer [bar] = Low [bar]; 
         }
 
       if(Swing == -1)
         { 
           LowBuffer[bar] = High[bar]; 
           HighBuffer[bar] = Low[bar]; 
         }   
     }
 
//+--- termination of the basic loop
   return(0);
  }

下面是类似的情况:


//+------------------------------------------------------------------+
//|                                                  BrainTrend1.mq4 |
//|                                     BrainTrading Inc. System 7.0 |
//|                                     http://www.braintrading.com  |
//+------------------------------------------------------------------+
#property copyright "BrainTrading Inc. System 7.0"
 
#property link      "http://www.braintrading.com"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Red
 
#property indicator_color2 Lime
//---- 
double Ind_Buffer1[];
double Ind_Buffer2[];
double value2, Range, val1, val2, d, val3;
 
int    f, p, x1, x2, value11;
//+------------------------------------------------------------------+
//| BrainTrend1 initialization function                              |
//+------------------------------------------------------------------+
int init()
  {
//---- 
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexBuffer(0, Ind_Buffer1);
 
//---- 
   SetIndexStyle(1, DRAW_HISTOGRAM);
   SetIndexBuffer(1, Ind_Buffer2);
 
//----   
   string short_name;
   short_name = "BrainTrend1";
   IndicatorShortName(short_name);
   SetIndexLabel(0, "" + short_name + "_Down");
   SetIndexLabel(1, "" + short_name + "_Up");
   IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS));
 
//----  
   f = 7; 
   d = 2.3; 
 
   x1 = 53; 
   x2 = 47; 
   value11 = 9;
 
//---- termination of the initialization
   return(0);
  }
//+------------------------------------------------------------------+
//| BrainTrend1 iteration function                                   |
//+------------------------------------------------------------------+
int start()
 
  {
//---- check whether the amount of bars is enough to calculate
   if(Bars < 11)
       return(0);
 
//---- Introduction of statistical memory variables for multiple 
//     recalculation of the null bar 
   static int MEMORY, time2;
//----+ Introduction of integer variables and getting of counted bars
   int limit, MaxBar,bar, counted_bars = IndicatorCounted();
 
//---- check for possible errors
   if(counted_bars < 0)
       return(-1);
//---- the last counted bar must be re-counted 
 
   if(counted_bars > 0) 
       counted_bars--;
//---- determining of the oldest bar number, starting from which 
//     all bars will be re-counted
   MaxBar = Bars - 1 - 10;
 
//---- determining of the oldest bar number, starting from which 
//     only new bars will be re-counted
   limit = Bars - counted_bars - 1; 
   if(limit > MaxBar)
 
   limit = MaxBar;
   Comment("BrainTrading Inc. System 7.0");
//+--- restoring of values of variables +================+
   int Tnew = Time[limit+1];
 
   if(limit < MaxBar)
   if(Tnew == time2)
 
       p=MEMORY; 
   else
     {
       if(Tnew > time2)
           Print("ERROR01");
       else 
 
           Print("ERROR02");
       return(-1);  
     }
//+--- +===================================================+
 
   bar = limit;
   while(bar >= 0)
     {
 
       //+--- Saving of values of variables           +====+ 
       if(bar == 1)
           if(((limit == 1) && (time2 != Time[2])) || (limit > 1))
 
             {
               time2 = Time[2];
               MEMORY = p;
             }
 
       //+---+====================================+
       Range = iATR(NULL, 0, f, bar) / d;
       value2 = iStochastic(NULL, 0, value11, value11, 1, 0, 0, 0, bar);
       val1 = 0.0;
       val2 = 0.0;
       val3 = MathAbs(Close[bar] - Close[bar+2]);
       if(value2 < x2 && val3 > Range) 
           p = 1;
       if(value2 > x1 && val3 > Range) 
           p = 2;
       if(value2 < x2 && (p == 1||p == 0))
 
         {
           if(val3 > Range)
             {
 
               val1 = High[bar];
               val2 = Low [bar];
             }
 
         }
       if(value2 > x1 && (p == 2||p == 0))
 
         {
           val2 = High[bar];
           val1 = Low [bar];
         }
 
       Ind_Buffer1[bar] = val1;
       Ind_Buffer2[bar] = val2;     
       bar--;
     } 
 
//+--- termination of the basic loop
   return(0);
  }

为了让下面的指标运作正常,要重建的不仅是标准的变量,还有缓冲区:

//+------------------------------------------------------------------+
//|                                                  BrainTrend2.mq4 |
//|                                     BrainTrading Inc. System 7.0 |
//|                                     http://www.braintrading.com  |
//+------------------------------------------------------------------+
#property copyright "BrainTrading Inc. System 7.0"
#property link      "http://www.braintrading.com"
 
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red
 
//---- 
double Ind_Buffer1[];
double Ind_Buffer2[];
double spread;
//----
 
bool   river = True;
int    artp, limit, Curr, glava;
 
double dartp, cecf, Emaxtra, widcha, TR;
double Values[1], ATR, Weight, val1, val2, low, high, Series1;
 
//---- Introduction of variables for multiple re-counting of the null bar 
bool   RIVER; int time2, GLAVA; double EMAXTRA,VALUES[1];
 
//+------------------------------------------------------------------+
//| BrainTrend2 initialization function                              |
//+------------------------------------------------------------------+
int init()
  {
//---- 
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexBuffer(0, Ind_Buffer1);
   SetIndexStyle(1, DRAW_HISTOGRAM);
   SetIndexBuffer(1, Ind_Buffer2);
   spread = MarketInfo(Symbol(), MODE_SPREAD)*Point;
 
//----  
   dartp = 7.0; cecf = 0.7; artp = 7;  
 
//---- change of the buffer size to the required size
   ArrayResize(Values, artp);
//---- similar change of the memory buffer size in the first measuring
//     to the required size
   ArrayResize(VALUES, artp);
 
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| BrainTrend2 iteration function                                   |
//+------------------------------------------------------------------+
int start()
 
  {
//---- check whether the amount of bars is enough to calculate
   if(Bars < 11)
       return(0);
 
//----+ Introduction of integer variables and getting of bars already counted
   int limit, MaxBar, bar, J, counted_bars = IndicatorCounted();
 
//---- check for possible errors
   if(counted_bars < 0)
      return(-1);
//---- the last counted bar must be re-counted 
 
   if(counted_bars > 0) 
       counted_bars--;
//---- determining of the oldest bar number, starting from which 
//     all bars will be re-counted
   MaxBar = Bars - 3;
 
//---- determining of the oldest bar number, starting from which 
//     only new bars will be re-counted
   limit = (Bars - 1 - counted_bars);
 
//---- initialization of null
   if(limit >= MaxBar)
     {
       limit = MaxBar;
       Emaxtra = Close[limit+1];
       glava = 0;
       double T_Series2 = Close[limit+2];
       double T_Series1 = Close[limit+1];
       if(T_Series2 > T_Series1) 
           river = True; 
       else 
 
           river = False;
       for(int ii = Bars - 1; ii > MaxBar; ii--)
 
         { 
           Ind_Buffer1[ii] = 0.0;
           Ind_Buffer2[ii] = 0.0;        
 
         }
     } 
//----
//+--- restoring of values of variables +================+
   int Tnew = Time[limit+1];
 
   if(limit < MaxBar)
       if(Tnew == time2)
         {
 
           for(int xx = 0;xx <= artp - 1; xx++)
 
               Values[xx] = VALUES[xx];
           glava = GLAVA;
           Emaxtra = EMAXTRA;
           river = RIVER;
         }  
       else
 
         {
           if(Tnew > time2)
               Print("ERROR01");
           else 
 
               Print("ERROR02");
           return(-1);  
         }
 
//+--- +==================================================+
//+--- Basic loop of the indicator calculation 
   bar = limit;
   while(bar >= 0)      
     {  
       //+--- Saving values of variables +================+ 
 
       if(bar == 1)
           if(((limit == 1) && (time2 != Time[2])) || (limit > 1))
 
             {
               for(int kk = 0;kk <= artp - 1; kk++)
 
                 VALUES[kk] = Values[kk];
               GLAVA = glava;
               EMAXTRA = Emaxtra;
               RIVER = river;
               time2 = Time[2];
             }
 
       //+---+============================================+
       Series1 = Close[bar+1];
       low = Low[bar];
 
       high = High[bar];
       TR = spread + high - low;
       if(MathAbs(spread + high - Series1) > TR ) 
 
           TR = MathAbs(spread + high - Series1);
       if(MathAbs(low - Series1) > TR)  
           TR = MathAbs(low - Series1);
       if(bar == MaxBar)
 
           for(J = 0; bar <= artp - 1; J++)
 
               Values[J] = TR;    
       Values[glava] = TR;
       ATR = 0;
       Weight = artp;
       Curr = glava;
       for(J = 0; J <= artp - 1; J++) 
         {
 
           ATR += Values[Curr]*Weight;
           Weight -= 1.0;
           Curr--;
           if(Curr == -1) 
               Curr = artp - 1;
         }
 
       ATR = 2.0*ATR / (dartp*(dartp + 1.0));
       glava++;
       if(glava == artp) 
           glava = 0;
       widcha = cecf*ATR;
       if(river && low < Emaxtra - widcha) 
         {
 
           river = False;
           Emaxtra = spread + high;
         }
 
       if(!river && spread + high > Emaxtra + widcha) 
         {
 
           river = True;
           Emaxtra = low;
         }
       if(river && low > Emaxtra) 
         {
 
           Emaxtra = low;
         }
       if(!river && spread + high < Emaxtra ) 
         {
 
           Emaxtra = spread + high;
         }
       //Range1 = iATR(NULL,0,10,bar);
       if(river==true ) 
         {
 
           val1 = high;
           val2 = low;
         } 
       else 
         {
 
           val1 = low;
           val2 = high;
         }
       Ind_Buffer1[bar] = val1;
 
       Ind_Buffer2[bar] = val2;  
       bar--;
     }  
 
//+--- termination of the basic loop
   return(0);
  }

好了,最后很招人爱的 ZigZag 指标,如我们在技术分析里看到的,也是在所有的柱体上重新计算的,因此,提出这个问题!我想没必要在这篇文章中将这个指标的代码贴出来,因为可以在 MetaTrader 4 客户端的 "indicators" 文件夹中将其打开。

当然,在这个指标中,综合上述思路编写的更多使用电脑资源的存储代码看起来非常易使人上当的,可怕的和麻烦的。此时,我们可以表现得不同。如果重新计算指标后,我们对最后版本的 ZigZag 指标虚线记录坐标和最后两个值,我们将在将来,下一次运行 int start() 函数完全正确的重算没有计算过的,与这两个坐标最近的指标值。而这两个最后的没有计算的的高点可以从内存中取值。必须说的是,这个指标不能完全正常的运作,并且周期性的会偏离正确的运作,但用来和前面的指标组合,它还是受人喜欢的。既然 ZigZag 指标至少有三个最高点总是会与图表偏离,我们将开始严密地指标计算,从这个类型到指标的虚线变形开始的最后处。在这个案例里,代码应该这样改变:


//+------------------------------------------------------------------+
//|                                                       ZigZag.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_chart_window
#property indicator_buffers  1
#property indicator_color1 Red
 
#property indicator_width1 0
#property indicator_style1 1
//---- 
extern int ExtDepth = 12;
 
extern int ExtDeviation = 5;
extern int ExtBackstep = 3;
 
//---- 
double ZigZagBuffer[];
//+------------------------------------------------------------------+
//| ZigZag initialization function                                   |
//+------------------------------------------------------------------+
int init()
 
  {
    //---- 
    SetIndexBuffer(0, ZigZagBuffer); 
    SetIndexStyle(0, DRAW_SECTION);
    SetIndexEmptyValue(0, 0.0);
    IndicatorShortName("ZigZag(" + ExtDepth + "," + ExtDeviation + "," +
 
                      ExtBackstep + ")");
    //---- 
    return(0);
 
  }
 
//+------------------------------------------------------------------+
//|  ZigZag iteration function                                       |
//+------------------------------------------------------------------+
int start()
  {
    //+ check whether the amount of bars is sufficient for correct
    //  calculation of the indicator
 
    if(Bars - 1 < ExtDepth)
        return(0);
    //+ Introduction of integer memory variables to re-count the indicator 
    //  on uncounted bars only
 
    static int time2, time3, time4;  
    //+ Introduction of floating-point variables to re-count 
    //  the indicator on uncounted bars only
    static  double ZigZag2, ZigZag3, ZigZag4;
    //+ Introduction of integer variables to re-count the indicator only
    //  on uncounted bars and getting of indicators already counted
 
    int MaxBar, limit, supr2_bar, supr3_bar, supr4_bar;
    int counted_bars = IndicatorCounted();
    // check for possible errors
 
    if(counted_bars < 0)
        return(-1);
    // the last counted bar must be re-counted
 
    if(counted_bars > 0) 
        counted_bars--;
    //----+ Introduction of variables    
    int shift, back, lasthighpos, lastlowpos;
    double val, res, TempBuffer[1];
    double curlow, curhigh, lasthigh, lastlow;
    // determining of the oldest bar number, starting from which
 
    // all bars will be fully re-counted
 
    MaxBar = Bars - ExtDepth; 
    // determining of the start bar number in the loop, starting from 
    // which new bars will be re-counted
    if(counted_bars == 0)
 
        limit = MaxBar;
    else 
      {
        //----
        supr2_bar = iBarShift(NULL, 0, time2, TRUE);
        supr3_bar = iBarShift(NULL, 0, time3, TRUE);
        supr4_bar = iBarShift(NULL, 0, time4, TRUE);
        //----
 
        limit = supr3_bar;      
        if((supr2_bar < 0) || (supr3_bar < 0) || (supr4_bar < 0))
 
          {
            limit = MaxBar;
            Print("Start bar was not found,",
 
            " the indicator will be re-counted on all bars" );
          }
      }
    // initialization of null
    if(limit >= MaxBar) 
      {
 
        for(shift = Bars - 1; shift >= MaxBar; shift--)
 
            ZigZagBuffer[shift] = 0.0; 
        limit = MaxBar; 
      } 
    // change of the temporary buffer size
 
    if(ArrayResize(TempBuffer, Limit + ExtBackstep + 1)!=
 
       limit + ExtBackstep + 1)
        return(-1);
 
    //+ start of the first large loop
    for(shift = limit; shift >= 0; shift--)
 
      {
        //--- 
        val = Low[Lowest(NULL, 0, MODE_LOW, ExtDepth, shift)];
        if(val == lastlow) 
 
            val = 0.0;
        else 
          { 
            lastlow = val; 
            if((Low[shift] - val) > (ExtDeviation*Point)) 
                val = 0.0;
            else
 
              {
                for(back = 1; back <= ExtBackstep; back++)
 
                  {
                    res = ZigZagBuffer[shift+back];
                    if((res !=0 ) && (res > val)) 
 
                        ZigZagBuffer[shift+back] = 0.0; 
                  }
              }
 
          } 
        ZigZagBuffer[shift] = val;
        //--- 
        val = High[Highest(NULL, 0, MODE_HIGH, ExtDepth, shift)];
        if(val == lasthigh) 
 
            val = 0.0;
        else 
          {
            lasthigh = val;
            if((val - High[shift]) > (ExtDeviation*Point)) 
                val = 0.0;
            else
 
              {
                for(back = 1; back <= ExtBackstep; back++)
 
                  {
                    res = TempBuffer[shift+back];
                    if((res != 0) && (res < val)) 
 
                    TempBuffer[shift+back] = 0.0; 
                  } 
              }
 
          }
        TempBuffer[shift] = val;
      }
    //+ end of the first large loop 
 
    // final cutting 
    lasthigh = -1; 
    lasthighpos = -1;
    lastlow = -1; 
 
    lastlowpos = -1;
    //----+ start of the second large loop
    for(shift = limit; shift >= 0; shift--)
 
      {
        curlow = ZigZagBuffer[shift];
        curhigh = TempBuffer[shift];
        if((curlow == 0) && (curhigh == 0)) 
            continue;
        //---
 
        if(curhigh != 0)
          {
            if(lasthigh > 0) 
              {
 
                if(lasthigh < curhigh) 
                    TempBuffer[lasthighpos] = 0;
                else 
 
                    TempBuffer[shift] = 0;
              }
            if(lasthigh < curhigh || lasthigh < 0)
 
              {
                lasthigh = curhigh;
                lasthighpos = shift;
              }
 
            lastlow = -1;
          }
        //----
        if(curlow != 0)
 
          {
            if(lastlow > 0)
              {
 
                if(lastlow > curlow) 
                    ZigZagBuffer[lastlowpos] = 0;
                else 
                  ZigZagBuffer[shift] = 0;
              }
 
            //---
            if((curlow < lastlow) || (lastlow < 0))
 
              {
                lastlow = curlow;
                lastlowpos = shift;
              } 
            lasthigh = -1;
          }
 
      }
    //+ end of the second large loop
    //+ start of the third loop
    for(shift = limit; shift >= 0; shift--)
 
      {
        res = TempBuffer[shift];
        if(res != 0.0) 
            ZigZagBuffer[shift] = res;
      }
 
    //+ end of the third loop
    //+ Restoring of values of the indicator buffer that 
    //  could be lost 
    if(limit < MaxBar)
      {
 
        ZigZagBuffer[supr2_bar] = ZigZag2; 
        ZigZagBuffer[supr3_bar] = ZigZag3; 
        ZigZagBuffer[supr4_bar] = ZigZag4; 
        for(int qqq = supr4_bar - 1; qqq > supr3_bar; qqq--)
 
            ZigZagBuffer[qqq] = 0; 
        for(int ggg=supr3_bar - 1; ggg > supr2_bar; ggg--)
 
            ZigZagBuffer[ggg] = 0;
      }
    //+ correction of hills 
    double vel1, vel2, vel3, vel4;
    int bar1, bar2, bar3, bar4;
    int count;
    if(limit == MaxBar)
        supr4_bar = MaxBar;
    for(int bar = supr4_bar; bar >= 0; bar--)
 
      {
        if(ZigZagBuffer[bar] != 0)
          {
 
            count++;
            vel4 = vel3;
            bar4 = bar3;
            vel3 = vel2;
            bar3 = bar2;
            vel2 = vel1;
            bar2 = bar1;
            vel1 = ZigZagBuffer[bar];
            bar1 = bar;
            if(count < 3)
                continue; 
 
            if((vel3 < vel2) && (vel2 < vel1))
                ZigZagBuffer[bar2] = 0;
            if((vel3 > vel2) && (vel2 > vel1))
 
                ZigZagBuffer[bar2] = 0;
            if((vel2 == vel1) && (vel1 != 0))
 
                ZigZagBuffer[bar1] = 0;      
          }
      } 
    //+ memorizing of the last three inflections of the ZigZag and 
    //  the indicator values at these points 
 
    time2 = Time[bar2];
    time3 = Time[bar3];
    time4 = Time[bar4];
    ZigZag2 = vel2;  
    ZigZag3 = vel3; 
    ZigZag4 = vel4; 
 
    //---- completion of calculating the indicator values
    return(0);
  }
 //---+ +----------------------------------------------------------+


按照现在的情况,ZigZag 占用的宝贵的电脑资源少了,从以前的经验来看,不管其可用性多高,总是不足的。我为指标缓冲改了个更明显的名字 "ZigZagBuffer"。 我把第二个缓冲用来存储临时数据,替代了指标缓存因为这儿并不需要它,并且改名为 "TempBuffer"。在三个指标计算的循环里,我把变量 "limit" 作为开始的柱体数,只有没计算过的柱体值从这儿开始重新计算。

每个指标都是唯一的,几乎不可能创建一个在全部指标中都能同样运行的方法。但是我假设这样的方法的通常思路是相当清楚的:

1. 在先前的价位上确定所有的变量是最难的。我们必须考虑到,有时需要记录一些变量和柱体数,这个柱体可以在下一个价位改变,而保存的值却没有任何改变。在这个案例中,柱体开始的时间必须被记录(MEMORY_bar_time = Time[lastlowBar])。然后当前的柱体状态可以通过被记录的时间重建(iBarShift(NULL,0,MEMORY_bar_time,TRUE))。指标计算了几个循环后,每个循环都有变量要储存,同样的变量在不同的循环里必须被分开来储存。
2. 初始化的变量要与申明的变量名字一致。最好在指标代码的开始处申明全局变量。在 start() 运作后,在指标代码里,这些变量经常被立即申明作为静态变量。
3. 在所有指标计算的循环前,必须写变量重建的代码。
4. 在每一个包含当前变量的循环里,应该添加存储这些变量的代码。


最后,我想说的是所有在本文中作为例子的指标,都可以在网络的不同论坛里获得源代码。 我把它们只作为例子分享,纠正其中的错误,如果有任何侵权的责任应归于把他们放到网站上的人。

Nikolay Kositsin

MetaQuotes Software Corp. 翻译自俄语
原文: http://articles.mql4.com/ru/articles/1411

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

附加的文件 |
NullBarReCount.zip (12.86 KB)
最近评论 | 前往讨论 (1)
Jinsong Zhang
Jinsong Zhang | 14 2月 2008 在 11:36
值得收藏啊
MetaTrader 4 客户端的秘密: MetaEditor 里的文件库 MetaTrader 4 客户端的秘密: MetaEditor 里的文件库
当我们编写程序时,代码的编辑是非常重要的。MetaEditor 作为 MQL 4 的编辑器,为我们提供了许多快捷便利的功能,大多数程序都能在已有的代码基础上完成。您是否还没有找到完全符合您期望的指标和脚本?您可以在我们的网站下载代码并加以定制。
交易策略 交易策略
各种交易策略的分类都是任意的,下面这种分类强调从交易的基本概念上分类。
简单的订单管理 简单的订单管理
本文涉及多种控制开仓和待办定单的方法,致力于简化编写 Expert Advisors 程序。
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。