English Русский 中文 Español Deutsch Português
いくつかのインジケーターにおけるマルチNullバー再計算

いくつかのインジケーターにおけるマルチNullバー再計算

MetaTrader 4 | 16 2月 2016, 11:37
2 013 0
Nikolay Kositsin
Nikolay Kositsin


この記事では、Nullバーが変化した際のMetaTrader4クライアントターミナルのインジケーター値に関する問題について言及したいと思います。履歴データのみで稼働できるたくさんの良いインジケーターをウェブ上で見つけることができますが、トレーディングプラットフォームがサーバーに接続されれば、これらのインジケーターとは全く関係のない結果を出力します。

普段、そのようなインジケーターの作成者はその問題に取り組んだのち、最も簡単で、賢くはないソリューションんを見つけます:最後のNullバーの値を計算するため、start()関数にてチャートのすべてのバーにおけるインジケーター値を再計算させます。

一見、すべての問題が解決されているように思えますが、実際は問題は別の区域に移動したただけなのです。そのようなインジケーターはリソースを吸収し、コンピューターの容量を食うだけです!

この問題から抜け出すため、インジケーターがいかに構築されているかについて考える必要があります。すべてのインジケーターは、いくつかの変数を持つ関数です:


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

すべてのインジケーターは二つの大きなグループに分けることができます;

  • グループ 1 - すべての変数はセキュリティ価格と外部変数によってのみ決定されるインジケーター;これらの変数は先行するバーの同じ変数の値と関連付けられずすべてのバーのために計算されます。

  • グループ2 - すくなくとも一つの変数が先行するバーでのインジケーターの計算の結果として取得された値に依存するインジケーター:

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

    左の値はi番目のバーにて取得され、i番目のバーと右側のカッコ内の値はバーi+1番目のバーにて取得されます。すくなくとも一つの変数がその他の変数に基づきます。その変数の値は先行するバーのインジケーターの計算にて取得されます。

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

    同様に、左側の値はi番目のバーにて取得され、右側カッコ内の値は1+1番目のバーで取得されます。

上記の問題を作成するインジケーターであるため、グループ2のインジケーターが興味深く思われます。インジケーターはNullバーにて再計算され、その他のバーのいて同じ値を持つ必要のある変数は、たとえインジケーターがIndicatorCounted()関数を用いてNullバーを再計算するために記述されていたとしても、複数回にわたって全バーにて再計算され始めます。そのようなインジケーターは確実に実際のマーケットで稼働させる上で役に立ちません。すべて説明しましたので、特定のインジケーターへ進みましょう。


//+------------------------------------------------------------------+
//|                                                           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);
  }
//+----------------------------------------------------------------+

その問題は解決されましたが、この場合、それはこの特定の問題に対するソリューションです:その他のにたくさんの変数があり、そのため、すべての変数がインジケーターバッファーとして決して記載できないのです。そのような状況において、最も一般的な解決方法は以下の手順になります。標準のインジケーターの再計算を行う為に、2番目のバーのインジケーターの計算の後に取得される変数値のみを必要とし、そのため、最後のみだけではなく、最後から1番目のインジケーターを再度数えることがより完全な方法です。



従って、2番目のバーのループの最後にこれらの変数の値は、インジケータープログラムブロックのローカル上ではないメモリ変数に記憶されなければなりません。すなわち、インジケーターコードの最初に初期化されます。これらのメモリ変数は、統計的なデータになり、テキストの最初のstart()関数に渡されます。そして、インジケーターの計算ループの前、start()関数が呼ばれるたびにもし数えられたバーが0でなければ (if (IndicatorCounted()!=0)、その実際のインジケーターの変数にメモリ変数から値を割り当てます。その後、数えられていないバーは、最初から同じコード上で計算されます。2番目のバーのループの最後ではなく、1番目のバーの最初にこれらの変数を保存する方が時折良い方法ではあります。これは、今後の例にて紹介いたします。以下は、これらのアイディアを考慮して記述された同じインジケーターです。

//+-------------------------------------------------------------------------+
//|                                                           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);
  }
//+-----------------------------------------------------------------+


以前のものと比較して、このインジケーターはメモリ内の変数を保存するためにより少ない情報を必要とします。しかし、前回のものよりもさらに複雑に見えます。

インジケーターとEAを組み合わせるEAの熟練の開発者の大半のために、start()関数の中にて、同じインジケーターのコードの一部が記載されています。このコードでは、EAは常にNullバーにてのみインジケーターを計算します。このコードのバージョンは履歴データでのテストエキスパートにのみ適しているのは当然です。エキスパートアドバイザーのオンライン処理において、最後の例にて考察したインジケーターからそのコードの別のバージョンを持つ必要があります。もし新しいnullバーが形成され始めたら、一番目のバーのインジケーター値は数えられ、再度数えられないと想定されます。同様のことが、バーの変化時に記憶される変数にも当てはまります。もしそのような複雑なコードがエキスパートのために記述されなければ、そのようなエキスパートが何を数えるかを理解し、どのような基準でトレードするかについて理解することはできないということに注意する必要があります。もしこのコードの代わりに、最後のnullバーの値を取得するためだけに全てのバーの全てのティックにおいてインジケーターを再度数えるバージョンを使用すれば、結果が出るまで1ヶ月も待つ必要があります。

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);
  }
//+----------------------------------------------------------------+


もちろん、そのコードはさらに複雑になります。

以下は、正しく動作するため論理変数がstart()関数の稼働時に際保存される模範的なインジケーターです。しかし、このほとんど認識できない変化なしでは、インジケーターは適切に作動しません:

//+------------------------------------------------------------------+
//|                                                   3LineBreak.mq4 |
//|                               Copyright © 2004, Poul_Trade_Forum |
//|                                                         Aborigen |
//+------------------------------------------------------------------+ 
#property copyright "Poul Trade Forum"
#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インジケーターは、問題を示しています。MetaTrader4クライアントターミナルの”indicators”フォルダからいつでも取得できるので、この記事にこのインジケーターのコードを追加する必要はありません。

もちろん、このインジケーターにおいては、上記すべてのアイディアを考慮し記載されているコンピューターリソースを使用することをさらに控えるためのコードはかなり注意をひく素晴らしいもののようです。この状況では、異なる形で動くことができます。もしインジケーターの再計算の後に最後と最後から2番目の値をZigZagインジケーターの破線の最後の屈折に登録すれば、将来次のstart()関数の呼び出し時にこれら二つの座標に近いところからインジケーターの値を数えることができます。そして、最後の二つの頂点の計算がメモリから取得されます。このインジケーターはあまり正しく動作せず、定期的に除外すべき異常な丘を形成し、以前のものとこのタスクを組み合わせることが望まれます。少なくともZigZagインジケーターの3つの頂点は、常にチャートから丘を排除するよう要求されているため、インジケーターの破線の屈折の最初から最後までインジケーターの計算を開始します。こちらがそのコードがどのように変わったかを示したものです:

//+------------------------------------------------------------------+
//|                                                       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は以前の経験から、いくら使用できても不幸にも常に不十分である貴重なCPリソースを比較的消費しません。そのインジケーターバッファ名をよりわかりやすい"ZigZagBuffer"に変更しました。そこにある必要がないため、一時的なデータを持った2番目のバッファをそのインジケータバッファから取り、"TempBuffer"という名前に変更しました。。そして、インジケーターの計算の3つのループにて、スタートバー番号として”limit”という変数を導入し、その番号から数えられていないバーのみ再度数えられ始めます。

すべてのインジケーターがユニークなものであることは当然です。また、すべてのインジケーターにおいて等しく動作するアプローチを作成することは不可能です。しかし、そのようなアプローチの一般的な考えはかなり明確です。

1. 最も難しい点は、以前のティックに蓄積された値を持つ変数を決定することです。時折いくつかの変数やバー番号を記憶する必要があり、次のティックにてバーが変化し、これらの保存された値はその時には無駄になるということは考慮する筆ようがあります。そのような場合、バーのオープンの時刻は記憶される必要があります。 (MEMORY_bar_time = Time[lastlowBar]). それから、そのバーの現在の状況はこの記憶された時間を用いて保存されます (iBarShift(NULL,0,MEMORY_bar_time, TRUE)). インジケーターの計算のいくつかのループがあり、すべてのループは記憶される必要のある変数を保持しています。異なるループの同じ変数は記憶される必要があり、2番目と一番目のバーの最後、もしくは一番目とnullバーのループの最初にて記憶される必要があります。
2. 初期の変数と一致する名前を持つ変数を導入することが望ましいです。インジケーターコードの最初にグローバルスコープにてこれらの変数を宣言することがベターです。インジケータコード内にてstart()オペレーターの後に、これらの変数は静的なものとして宣言されます。
3. 変数を保存するコードは、インジケーターの計算のループの前に導入される必要があります。
4. 実際の変数を保持するすべてのループにおいて、これらの変数を記憶するコードが追加される必要があります。


その最後に、例として使用されたすべてのインジケーターはインターネット上の様々なオープンソース上から取得されていることを付け加えて述べなければなりません。彼らが保持するエラーを正すために例としてここに提示しました。コピーや配布、再コンパイルなどには責任を持たず、また、その他の誰かによる公的なウェブサイトへの投稿のための著作権違反には一切関与いたしません。

Nikolay Kositsin


MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1411

添付されたファイル |
NullBarReCount.zip (12.86 KB)
初めてのGrail 初めてのGrail
初心者プログラマが「金のなる木」を作成させる最も頻度の高い失敗が調査されました。テスターではすばらしい結果を示したが、実際のトレーディングでは損失を出したエキスパートが示されています。
トレーダーツール、上級者向けのテクニカル分析のためのMQL4 トレーダーツール、上級者向けのテクニカル分析のためのMQL4
まず、トレーディングは確率の計算です。進展のエンジンとなる無為に関することわざは、それらのインジケーターやトレーディングシステムが開発された理由を明らかにします。トレーディングの多くの新人は「すでにできあがった」トレーディング理論を学習します。しかし、より多くの発見されていない市場の秘密があり、価格の動きの分析に使用されているツールは基本的に明らかにされていないテクニカルインジケーターや統計パッケージとして存在しています。マーケットの動向の理論への貢献において、Bill Williamsに感謝します。おそらくその漕ぎ手に頼るのは早すぎますが。
自分の DLL をデバッグするためのクラッシュログの利用方法 自分の DLL をデバッグするためのクラッシュログの利用方法
ユーザーから受け取った全クラッシュログ中25~30% はカスタム dll からインポートされた関数が実行されるときにおこるエラーが原因のようです。
オプティマイザでの遺伝的アルゴリズム vs シンプルな検索 オプティマイザでの遺伝的アルゴリズム vs シンプルな検索
この記事は、遺伝的アルゴリズムとシンプルな検索により取得されるものを用いて、エキスパートアドバイザーの最適化を行った結果とかかった時間を比較します。