
いくつかのインジケーターにおけるマルチNullバー再計算
この記事では、Nullバーが変化した際のMetaTrader4クライアントターミナルのインジケーター値に関する問題について言及したいと思います。履歴データのみで稼働できるたくさんの良いインジケーターをウェブ上で見つけることができますが、トレーディングプラットフォームがサーバーに接続されれば、これらのインジケーターとは全く関係のない結果を出力します。
普段、そのようなインジケーターの作成者はその問題に取り組んだのち、最も簡単で、賢くはないソリューションんを見つけます:最後のNullバーの値を計算するため、start()関数にてチャートのすべてのバーにおけるインジケーター値を再計算させます。
一見、すべての問題が解決されているように思えますが、実際は問題は別の区域に移動したただけなのです。そのようなインジケーターはリソースを吸収し、コンピューターの容量を食うだけです!
この問題から抜け出すため、インジケーターがいかに構築されているかについて考える必要があります。すべてのインジケーターは、いくつかの変数を持つ関数です:
すべてのインジケーターは二つの大きなグループに分けることができます;
- グループ 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





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索