DoEasyライブラリの時系列(第48部): 単一サブウィンドウでの単一バッファ複数銘柄・複数期間指標
Artyom Trishkin | 11 12月, 2020
内容
概念
前回の記事では、Accelerator Oscillator標準指標を使用して、現在のチャートの任意の銘柄/時間枠で計算された標準指標のデータを表示する原理と方法を強調しました。次に、他の標準指標を開発できるようにする方法を収集する必要があります。これを達成する準備はほぼできています。本稿では、メソッド内の同様のコード構造を判別するためのテストを実行して、繰り返しコードブロックを別々のメソッドに移動します。これは、単一バッファの標準指標(1つのバッファのみを使用してデータを表示する指標)を操作するために必要な最も簡単なことです。
次の記事では、本稿で改善されたメソッドおよび次の記事で開発されるマルチバッファ標準指標使用メソッドに基づいて、コードを削減および最適化するために何を改善できるかを定義します。
今日は、現在のチャートのサブウィンドウに、設定で選択された標準指標を表示するカスタム指標の例を開発します。これは、単一の描画バッファを備え、そのデータをメインチャートサブウィンドウに表示する標準指標の1つです。これを行うには、ライブラリクラスを少し改善する必要があります。これは、残りの標準指標を使用するメソッドを作成するための重要な準備手順になります。
ライブラリクラスの改善
まず、ライブラリメッセージを\MQL5\Include\DoEasy\Datas.mqhに追加します。
新しいメッセージインデックスを追加します。
MSG_LIB_TEXT_BUFFER_TEXT_INVALID_PROPERTY_BUFF, // Invalid number of indicator buffers (#property indicator_buffers) MSG_LIB_TEXT_BUFFER_TEXT_MAX_BUFFERS_REACHED, // Reached maximum possible number of indicator buffers MSG_LIB_TEXT_BUFFER_TEXT_NO_BUFFER_OBJ, // No buffer object for standard indicator MSG_LIB_TEXT_BUFFER_TEXT_STATUS_NONE, // No drawing
また、新しく追加したインデックスに対応するメッセージテキストも追加します。
{"Неправильно указано количество буферов индикатора (#property indicator_buffers)","Number of indicator buffers incorrect (#property indicator_buffers)"}, {"Достигнуто максимально возможное количество индикаторных буферов","Maximum number of indicator buffers reached"}, {"Нет ни одного объекта-буфера для стандартного индикатора","There is no buffer object for the standard indicator"}, {"Нет отрисовки","No drawing"},
現在のすべての改善は、 \MQL5\Include\DoEasy\Collections\BuffersCollection.mqhの指標バッファコレクションクラスと、当然のことながらCEngineクラスに関連しています。
BuffersCollection.mqhに作成されたすべての標準指標の計算バッファのデータを準備するための単一のメソッドを追加して、プログラムからコマンドを受け取った後にライブラリが独自にそれを実行できるようにする必要があります。これにより、最終的なプログラムコードが簡素化されます。必要なオブジェクトを検索して取得する必要がなくなります。
クラスのpublicセクションでメソッドを宣言します。
//--- Prepare calculated buffer data of (1) the specified standard indicator and (2) all created standard indicators int PreparingDataBufferStdInd(const ENUM_INDICATOR std_ind,const int id,const int total_copy); bool PreparingDataAllBuffersStdInd(void); //--- Clear buffer data of the specified standard indicator by the timeseries index
クラス本体外に実装します。
//+------------------------------------------------------------------+ //| Prepare the calculated buffer data | //| of all created standard indicators | //+------------------------------------------------------------------+ bool CBuffersCollection::PreparingDataAllBuffersStdInd(void) { CArrayObj *list=this.GetListBuffersWithID(); if(list==NULL || list.Total()==0) { ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_NO_BUFFER_OBJ)); return false; } bool res=true; int total=list.Total(); for(int i=0;i<total;i++) { CBuffer *buff=list.At(i); if(buff==NULL || buff.TypeBuffer()==BUFFER_TYPE_DATA || buff.IndicatorType()==WRONG_VALUE) continue; CSeriesDE *series=this.m_timeseries.GetSeries(buff.Symbol(),buff.Timeframe()); if(series==NULL) continue; int used_data=(int)series.AvailableUsedData(); int copied=this.PreparingDataBufferStdInd(buff.IndicatorType(),buff.ID(),used_data); if(copied<used_data) res &=false; } return res; } //+------------------------------------------------------------------+
標準指標の計算に使用される各バッファオブジェクトには、標準指標タイプ(ENUM_INDICATOR)に従って自動的に割り当てられるか、必要なバッファオブジェクトを作成するときにプログラムから手動で割り当てられるIDがあります。
IDが-1に等しくないバッファオブジェクトのリストは、ここで最初に取得するものです。
リストが空の場合は、標準指標用に作成されたバッファオブジェクトがないというメッセージを表示し、falseを返します。次に、標準の指標IDを持つすべてのバッファオブジェクトの数によるループで、次のバッファオブジェクトを取得します。各標準指標は、この種のバッファオブジェクトを少なくとも2つ(計算および描画)備えています。計算バッファのみが必要ですが現在のループではそれらを選択しません。前の記事で検討したPreparingDataBufferStdInd()メソッドでさらに処理するためには計算バッファのみが選択されるためです。(このメソッドは後で改善します)。したがって、ここではこの選択を繰り返すつもりはありません。
次に、取得したバッファオブジェクトが作成された銘柄/期間にあるバーの数を定義する必要があります。この値は、そのためのバッファオブジェクトにコピーする標準指標データの量を定義するために必要です。これを行うには、必要な時系列をバッファオブジェクトの銘柄と時間枠値で取得し、利用可能なデータの量をそこから取得します。
その後、PreparingDataBufferStdInd()メソッドを呼び出して、必要な量のデータを指標ハンドルから計算さバッファオブジェクトにコピーします。
コピーされたデータの量が必要量より少ない場合、res変数はfalseを受け取ります。既存のバッファオブジェクトの少なくとも1つについて必要量がコピーされていない場合、res変数にはfalseが含まれます。そして、変数値が返されるのはこのメソッドからです。計算されたすべてのバッファオブジェクトのすべてのデータが正常にコピーされた場合、メソッドはtrue を返します。
これまでのところ、このメソッドは既存のすべてのデータを指標ハンドルから計算バッファにコピーします。もちろん、各ティックで複数指標の大量のデータをコピーすることは、かなり非現実的です。ただし、今は標準指標を使用するための機能を作成しているので、この動作はそのままにしておきます。ここでは、速度よりもロジックの方が重要です。後で、必要な条件(最初の起動、履歴データの変更)でのみデータがコピーされるようにします。それ以外の場合は、必要な量のデータ(1つまたは2つのバー)のみがコピーされます。
前の記事で、標準指標ハンドルとそれに付随するバッファを作成するためのすべてのメソッドをすでに宣言しましたが、まだ実装していません(ACおよびAD指標を作成するための2つのメソッドを除いて)。今日は、単一指標バッファ用の標準の指標ハンドルとそのバッファオブジェクトを作成するメソッドを実装します。指標は、メインチャートサブウィンドウに独自にデータを描画します。
また、作成した指標の色を、デフォルトで適切な標準指標の色に対応させたいと思います。これらのバッファオブジェクトに独自の色を設定することはできます。これを行うには、メインループでバッファを計算するときに、必要な色のインデックスを渡す必要があります。
AcceleratorOscillator標準指標のバッファ作成メソッドに加えられた変更について考えてみましょう。
//+------------------------------------------------------------------+ //| Create multi-symbol multi-period AC | //+------------------------------------------------------------------+ int CBuffersCollection::CreateAC(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id=WRONG_VALUE) { //--- Create the indicator handle and set the default ID int handle=::iAC(symbol,timeframe); int identifier=(id==WRONG_VALUE ? IND_AC : id); color array_colors[3]={clrGreen,clrRed,clrGreen}; CBuffer *buff=NULL; if(handle!=INVALID_HANDLE) { //--- Create the histogram buffer from the zero line this.CreateHistogram(); //--- Get the last created (drawn) buffer object and set all the necessary parameters to it buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_AC); buff.SetShowData(true); buff.SetLabel("AC("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorName("Accelerator Oscillator"); buff.SetColors(array_colors); //--- Create a calculated buffer storing standard indicator data this.CreateCalculate(); //--- Get the last created (calculated) buffer object and set all the necessary parameters to it buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_AC); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLabel("AC("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorName("Accelerator Oscillator"); } return handle; } //+------------------------------------------------------------------+
Accelerator Oscillatorの標準指標は、その値を表示するために2色を備えているため、サイズ3のカラー配列を宣言します。これらはすぐに3色で初期化されます。何故3色なのでしょうか。インデックスが0の色は指標ラインの昇順の値を表示し、インデックスが1の色は降順の値を表示するためです。ただし、指標ラインの2つの隣接するバーの等しい値を表示するもう1つの色が必要です。標準のAccelerator Oscillatorでは、値の昇順の色で表示されます。したがって、3色が必要です。
描画バッファオブジェクトを作成したら、この配列から描画色を設定します。
最後に作成されたバッファオブジェクトへのポインタを取得するときに、ポインタが誤って取得される可能性があります。以前は、この状況は考慮されていなかったため、潜在的な危険がありました。無効なポインタでアクセスすると、プログラムがクラッシュするということです。
したがって、この場合、メソッドを終了してINVALID_HANDLEを返す必要があります。
描画色が1つしかない標準の指標の場合、 1つの要素のみのカラー配列を設定します。これが、カラー標準指標とそのバッファオブジェクトのハンドルを作成するメソッドと、モノクロ標準指標を作成する方法との違いです。
たとえば、以下はAverage True Range標準指標を作成するメソッドです。
//+------------------------------------------------------------------+ //| Create multi-symbol multi-period ATR | //+------------------------------------------------------------------+ int CBuffersCollection::CreateATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period,const int id=WRONG_VALUE) { //--- Create the indicator handle and set the default ID int handle=::iATR(symbol,timeframe,ma_period); int identifier=(id==WRONG_VALUE ?IND_ATR : id); color array_colors[1]={clrLightSeaGreen}; CBuffer *buff=NULL; if(handle!=INVALID_HANDLE) { //--- Create the line buffer this.CreateLine(); //--- Get the last created (drawn) buffer object and set all the necessary parameters to it buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ATR); buff.SetShowData(true); buff.SetLabel("ATR("+symbol+","+TimeframeDescription(timeframe)+": "+(string)ma_period+")"); buff.SetIndicatorName("Average True Range"); buff.SetColors(array_colors); //--- Create a calculated buffer storing standard indicator data this.CreateCalculate(); //--- Get the last created (calculated) buffer object and set all the necessary parameters to it buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ATR); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLabel("ATR("+symbol+","+TimeframeDescription(timeframe)+": "+(string)ma_period+")"); buff.SetIndicatorName("Average True Range"); } return handle; } //+------------------------------------------------------------------+
今日は、以下の標準指標についてサブウィンドウに描画される単一バッファのメソッドを実装します。
- ACオシレーター(Accelerator Oscillator)
- 累積/分布(Accumulation/Distribution)
- オーサムオシレータ(Awesome Oscillator)
- 平均真(Average True Range)
- ベアパワー(Bears Power)
- ブルパワー(Bulls Power)
- チャイキンオシレータ(Chaikin Oscillator)
- コモディティチャネルインデックス(Commodity Channel Index)
- デマーカー(DeMarker)
- 勢力指数(Force Index)
- モメンタム
- マネーフローインデックス(Money Flow Index)
- オシレータ移動平均(Average of Oscillator)
- オンバランスボリューム
- 相対強度指数(Relative Strength Index)
- 標準偏差
- 三重指数平均
- ウィリアムズ%R(William's Percent Range)
- ボリューム
上記の複数銘柄・複数期間指標を作成するメソッドはすでに作成されています。ここでそれらを検討する意味はありません。それらは考慮されたメソッドと同一であり、以下の添付ファイルで提供されます。
上記のリストには、単一の描画バッファを備えてサブウィンドウに描画されるMarket Facilitation Index 指標が含まれていないことに気付かれたと思います。一見すると、両方の条件が満たされています。ただし、ヒストグラムの列の色を計算するには、さらに別の計算されたバッファ、つまりボリューム指標バッファも必要です。したがって、この指標はサブウィンドウ内のマルチバッファ指標と見なされます。
PreparingDataBufferStdInd()メソッドは、計算されたバッファオブジェクト配列に指標ハンドルからのデータを入力します。このメソッドについては前回の記事ですでに検討しましたが、当時はAC指標バッファの書き入れのみを実装しました。
//+------------------------------------------------------------------+ //| Prepare the calculated buffer data | //| of the specified standard indicator | //+------------------------------------------------------------------+ int CBuffersCollection::PreparingDataBufferStdInd(const ENUM_INDICATOR std_ind,const int id,const int total_copy) { CArrayObj *list=this.GetListBufferByTypeID(std_ind,id); list=CSelect::ByBufferProperty(list,BUFFER_PROP_TYPE,BUFFER_TYPE_CALCULATE,EQUAL); if(list==NULL || list.Total()==0) return 0; CBufferCalculate *buffer=NULL; int copies=WRONG_VALUE; switch((int)std_ind) { case IND_AC : buffer=list.At(0); if(buffer==NULL) return 0; copies=buffer.FillAsSeries(buffer.IndicatorHandle(),0,0,total_copy); return copies; case IND_AD : break; case IND_ADX : break; case IND_ADXW : break; case IND_ALLIGATOR : break; case IND_AMA : break; case IND_AO : break; case IND_ATR : break; case IND_BANDS : break; case IND_BEARS : break; case IND_BULLS : break; case IND_BWMFI : break; case IND_CCI : break; case IND_CHAIKIN : break; case IND_DEMA : break; case IND_DEMARKER : break; case IND_ENVELOPES : break; case IND_FORCE : break; case IND_FRACTALS : break; case IND_FRAMA : break; case IND_GATOR : break; case IND_ICHIMOKU : break; case IND_MA : break; case IND_MACD : break; case IND_MFI : break; case IND_MOMENTUM : break; case IND_OBV : break; case IND_OSMA : break; case IND_RSI : break; case IND_RVI : break; case IND_SAR : break; case IND_STDDEV : break; case IND_STOCHASTIC : break; case IND_TEMA : break; case IND_TRIX : break; case IND_VIDYA : break; case IND_VOLUMES : break; case IND_WPR : break; default: break; } return 0; } //+------------------------------------------------------------------+
最も興味深いのは、まったく同じアクションを他の単一バッファ指標に対して実行する必要があることです。ここで、switch演算子は、式の値をすべての caseバリアントの定数と比較するために使用されるため役立ちます。 式の値に一致する演算子に制御を渡します。各caseは、breakまたはreturn演算子のいずれかで終了します。case内にこれらの演算子が設定されていない場合、必要なcaseで式の値が処理された後、制御は次のcaseに渡されます。
したがって、同様の必要な操作を同じ操作を実行するすべてのcaseにコピーするのではなく、単にそのようなすべてのcaseをreturnまたはbreak演算子で1つに組み合わせる方が合理的です。
//+------------------------------------------------------------------+ //| Prepare the calculated buffer data | //| of the specified standard indicator | //+------------------------------------------------------------------+ int CBuffersCollection::PreparingDataBufferStdInd(const ENUM_INDICATOR std_ind,const int id,const int total_copy) { CArrayObj *list=this.GetListBufferByTypeID(std_ind,id); list=CSelect::ByBufferProperty(list,BUFFER_PROP_TYPE,BUFFER_TYPE_CALCULATE,EQUAL); if(list==NULL || list.Total()==0) { ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_NO_BUFFER_OBJ)); return 0; } CBufferCalculate *buffer=NULL; int copies=WRONG_VALUE; switch((int)std_ind) { //--- Single-buffer standard indicators in a subwindow case IND_AC : case IND_AD : case IND_AO : case IND_ATR : case IND_BEARS : case IND_BULLS : case IND_CHAIKIN : case IND_CCI : case IND_DEMARKER : case IND_FORCE : case IND_MOMENTUM : case IND_MFI : case IND_OSMA : case IND_OBV : case IND_RSI : case IND_STDDEV : case IND_TRIX : case IND_VOLUMES : case IND_WPR : buffer=list.At(0); if(buffer==NULL) return 0; copies=buffer.FillAsSeries(buffer.IndicatorHandle(),0,0,total_copy); return copies; case IND_ADX : break; case IND_ADXW : break; case IND_ALLIGATOR : break; case IND_AMA : break; case IND_BANDS : break; case IND_BWMFI : break; case IND_DEMA : break; case IND_ENVELOPES : break; case IND_FRACTALS : break; case IND_FRAMA : break; case IND_GATOR : break; case IND_ICHIMOKU : break; case IND_MA : break; case IND_MACD : break; case IND_RVI : break; case IND_SAR : break; case IND_STOCHASTIC : break; case IND_TEMA : break; case IND_VIDYA : break; default: break; } return 0; } //+------------------------------------------------------------------+
指定された標準指標のバッファデータをクリアするメソッドでも同じことを行います。
//+------------------------------------------------------------------+ //| Clear buffer data of the specified standard indicator | //| by the timeseries index | //+------------------------------------------------------------------+ void CBuffersCollection::ClearDataBufferStdInd(const ENUM_INDICATOR std_ind,const int id,const int series_index) { //--- Get the list of buffer objects by type and ID CArrayObj *list=this.GetListBufferByTypeID(std_ind,id); if(list==NULL || list.Total()==0) return; list=CSelect::ByBufferProperty(list,BUFFER_PROP_TYPE,BUFFER_TYPE_DATA,EQUAL); if(list.Total()==0) return; CBuffer *buffer=NULL; switch((int)std_ind) { //--- Single-buffer standard indicators in a subwindow case IND_AC : case IND_AD : case IND_AO : case IND_ATR : case IND_BEARS : case IND_BULLS : case IND_CHAIKIN : case IND_CCI : case IND_DEMARKER : case IND_FORCE : case IND_MOMENTUM : case IND_MFI : case IND_OSMA : case IND_OBV : case IND_RSI : case IND_STDDEV : case IND_TRIX : case IND_VOLUMES : case IND_WPR : buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); break; case IND_ADX : break; case IND_ADXW : break; case IND_ALLIGATOR : break; case IND_AMA : break; case IND_BANDS : break; case IND_BWMFI : break; case IND_DEMA : break; case IND_ENVELOPES : break; case IND_FRACTALS : break; case IND_FRAMA : break; case IND_GATOR : break; case IND_ICHIMOKU : break; case IND_MA : break; case IND_MACD : break; case IND_RVI : break; case IND_SAR : break; case IND_STOCHASTIC : break; case IND_TEMA : break; case IND_VIDYA : break; default: break; } } //+------------------------------------------------------------------+
指定された標準指標のバッファデータの値を設定するメソッドでも同じことを行います。
//+------------------------------------------------------------------+ //| Set values for the current chart to the specified buffer | //| of the standard indicator by the timeseries index according to | //| the buffer object symbol/period | //+------------------------------------------------------------------+ bool CBuffersCollection::SetDataBufferStdInd(const ENUM_INDICATOR ind_type,const int id,const int series_index,const datetime series_time,const char color_index=WRONG_VALUE) { //--- Get the list of buffer objects by type and ID CArrayObj *list=this.GetListBufferByTypeID(ind_type,id); if(list==NULL || list.Total()==0) { ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_NO_BUFFER_OBJ)); return false; } //--- Get the list of drawn objects with ID CArrayObj *list_data=CSelect::ByBufferProperty(list,BUFFER_PROP_TYPE,BUFFER_TYPE_DATA,EQUAL); list_data=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_TYPE,ind_type,EQUAL); //--- Get the list of calculated buffers with ID CArrayObj *list_calc=CSelect::ByBufferProperty(list,BUFFER_PROP_TYPE,BUFFER_TYPE_CALCULATE,EQUAL); list_calc=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_TYPE,ind_type,EQUAL); //--- Exit if any of the lists is empty if(list_data.Total()==0 || list_calc.Total()==0) return false; //--- Declare the necessary objects and variables CBuffer *buffer_data=NULL; CBuffer *buffer_calc=NULL; int index_period=0; int series_index_start=0; int num_bars=1,index=0; datetime time_period=0; double value0=EMPTY_VALUE, value1=EMPTY_VALUE; //--- Depending on the standard indicator type switch((int)ind_type) { //--- Single-buffer standard indicators case IND_AC : case IND_AD : case IND_AO : case IND_ATR : case IND_BEARS : case IND_BULLS : case IND_CHAIKIN : case IND_CCI : case IND_DEMARKER : case IND_FORCE : case IND_MOMENTUM : case IND_MFI : case IND_OSMA : case IND_OBV : case IND_RSI : case IND_STDDEV : case IND_TRIX : case IND_VOLUMES : case IND_WPR : //--- Get drawn and calculated buffer objects buffer_data=list_data.At(0); buffer_calc=list_calc.At(0); if(buffer_calc==NULL || buffer_data==NULL || buffer_calc.GetDataTotal(0)==0) return false; //--- Find the bar index corresponding to the current bar start time index_period=::iBarShift(buffer_calc.Symbol(),buffer_calc.Timeframe(),series_time,true); if(index_period==WRONG_VALUE || index_period>buffer_calc.GetDataTotal()-1) return false; //--- Get the value by the index from the indicator buffer value0=buffer_calc.GetDataBufferValue(0,index_period); if(buffer_calc.Symbol()==::Symbol() && buffer_calc.Timeframe()==::Period()) { series_index_start=series_index; num_bars=1; } else { //--- Get the bar time the bar with the index_period index falls into on the calculated buffer period and symbol time_period=::iTime(buffer_calc.Symbol(),buffer_calc.Timeframe(),index_period); if(time_period==0) return false; //--- Get the appropriate current chart bar series_index_start=::iBarShift(::Symbol(),::Period(),time_period,true); if(series_index_start==WRONG_VALUE) return false; //--- Calculate the number of bars on the current chart which should be filled with calculated buffer data num_bars=::PeriodSeconds(buffer_calc.Timeframe())/::PeriodSeconds(PERIOD_CURRENT); if(num_bars==0) num_bars=1; } //--- Take values to calculate colors value1=(series_index_start+num_bars>buffer_data.GetDataTotal()-1 ? value0 : buffer_data.GetDataBufferValue(0,series_index_start+num_bars)); //--- In the loop by the number of bars in num_bars, fill in the drawn buffer with the calculated buffer value taken by the index_period index //--- and set the color of the drawn buffer depending on the value0 and value1 values ratio for(int i=0;i<num_bars;i++) { index=series_index_start-i; buffer_data.SetBufferValue(0,index,value0); buffer_data.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value0>value1 ? 0 : value0<value1 ? 1 : 2) : color_index); } return true; case IND_ADX : break; case IND_ADXW : break; case IND_ALLIGATOR : break; case IND_AMA : break; case IND_BANDS : break; case IND_BWMFI : break; case IND_DEMA : break; case IND_ENVELOPES : break; case IND_FRACTALS : break; case IND_FRAMA : break; case IND_GATOR : break; case IND_ICHIMOKU : break; case IND_MA : break; case IND_MACD : break; case IND_RVI : break; case IND_SAR : break; case IND_STOCHASTIC : break; case IND_TEMA : break; case IND_VIDYA : break; default: break; } return false; } //+------------------------------------------------------------------+
前の記事では3つのメソッドすべてを検討しました。本稿では、caseを組み合わせ、同じハンドラを作成するだけです。
switch値の処理が別のハンドラを持つ他のcaseに渡されないために、ハンドラの最後にはreturnまたはbreak演算子が必要です。
次に、 \MQL5\Include\DoEasy\Engine.mqhでCEngineライブラリのメインオブジェクトクラスを改善します。
標準指標とそれらのバッファオブジェクトを作成するためのメソッドは、バッファコレクションクラスに設定され(まだ検討されていない一部のメソッドは単にINVALID_HANDLEを返す)、CEngineクラスのプログラム用にこれらすべてのメソッドへのアクセスを設定する必要があります 。
クラスのpublicセクションで、これらのメソッドの呼び出しを記述します。//--- The methods of creating standard indicators and buffer objects for them //--- Create the standard Accelerator Oscillator indicator bool BufferCreateAC(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id) { return(this.m_buffers.CreateAC(symbol,timeframe,id)!=INVALID_HANDLE); } //--- Create the standard Accumulation/Distribution indicator bool BufferCreateAD(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume,const int id) { return(this.m_buffers.CreateAD(symbol,timeframe,applied_volume,id)!=INVALID_HANDLE); } //--- Create the standard ADX indicator bool BufferCreateADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period,const int id) { return(this.m_buffers.CreateADX(symbol,timeframe,adx_period,id)!=INVALID_HANDLE); } //--- Create the standard ADX Wilder indicator bool BufferCreateADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period,const int id) { return(this.m_buffers.CreateADXWilder(symbol,timeframe,adx_period,id)!=INVALID_HANDLE); } //--- Create the standard Alligator indicator bool BufferCreateAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period,const int jaw_shift, const int teeth_period,const int teeth_shift, const int lips_period,const int lips_shift, const ENUM_MA_METHOD ma_method,const ENUM_APPLIED_PRICE applied_price,const int id) { return(this.m_buffers.CreateAlligator(symbol,timeframe, jaw_period,jaw_shift, teeth_period,teeth_shift, lips_period,lips_shift, ma_method,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Adaprive Moving Average indicator bool BufferCreateAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ama_period, const int fast_ema_period, const int slow_ema_period, const int ama_shift, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateAMA(symbol,timeframe, ama_period, fast_ema_period,slow_ema_period, ama_shift,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Awesome Oscillator indicator bool BufferCreateAO(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id) { return(this.m_buffers.CreateAO(symbol,timeframe,id)!=INVALID_HANDLE); } //--- Create the standard Average True Range indicator bool BufferCreateATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period,const int id) { return(this.m_buffers.CreateATR(symbol,timeframe,ma_period,id)!=INVALID_HANDLE); } //--- Create the standard Bollinger Bands indicator bool BufferCreateBands(const string symbol,const ENUM_TIMEFRAMES timeframe, const int bands_period, const int bands_shift, const double deviation, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateBands(symbol,timeframe, bands_period,bands_shift, deviation,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Bears Power indicator bool BufferCreateBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period,const int id) { return(this.m_buffers.CreateBearsPower(symbol,timeframe,ma_period,id)!=INVALID_HANDLE); } //--- Create the standard Bulls Power indicator bool BufferCreateBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period,const int id) { return(this.m_buffers.CreateBullsPower(symbol,timeframe,ma_period,id)!=INVALID_HANDLE); } //--- Create the standard Chaikin Oscillator indicator bool BufferCreateChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ma_period, const int slow_ma_period, const ENUM_MA_METHOD ma_method, const ENUM_APPLIED_VOLUME applied_volume, const int id) { return(this.m_buffers.CreateChaikin(symbol,timeframe, fast_ma_period,slow_ma_period, ma_method,applied_volume,id)!=INVALID_HANDLE); } //--- Create the standard Commodity Channel Index indicator bool BufferCreateCCI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateCCI(symbol,timeframe,ma_period,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard DEMA indicator bool BufferCreateDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const int ma_shift, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateDEMA(symbol,timeframe,ma_period,ma_shift,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard DeMarker indicator bool BufferCreateDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period,const int id) { return(this.m_buffers.CreateDeMarker(symbol,timeframe,ma_period,id)!=INVALID_HANDLE); } //--- Create the standard Envelopes indicator bool BufferCreateEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const int ma_shift, const ENUM_MA_METHOD ma_method, const ENUM_APPLIED_PRICE applied_price, const double deviation, const int id) { return(this.m_buffers.CreateEnvelopes(symbol,timeframe, ma_period,ma_shift,ma_method, applied_price,deviation,id)!=INVALID_HANDLE); } //--- Create the standard Force Index indicator bool BufferCreateForce(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const ENUM_MA_METHOD ma_method, const ENUM_APPLIED_VOLUME applied_volume, const int id) { return(this.m_buffers.CreateForce(symbol,timeframe,ma_period,ma_method,applied_volume,id)!=INVALID_HANDLE); } //--- Create the standard Fractals indicator bool BufferCreateFractals(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id) { return(this.m_buffers.CreateFractals(symbol,timeframe,id)!=INVALID_HANDLE); } //--- Create the standard FrAMA indicator bool BufferCreateFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const int ma_shift, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateFrAMA(symbol,timeframe,ma_period,ma_shift,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Gator indicator bool BufferCreateGator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, const int jaw_shift, const int teeth_period, const int teeth_shift, const int lips_period, const int lips_shift, const ENUM_MA_METHOD ma_method, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateGator(symbol,timeframe, jaw_period,jaw_shift, teeth_period,teeth_shift, lips_period,lips_shift, ma_method,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Ichimoku indicator bool BufferCreateIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe, const int tenkan_sen, const int kijun_sen, const int senkou_span_b, const int id) { return(this.m_buffers.CreateIchimoku(symbol,timeframe,tenkan_sen,kijun_sen,senkou_span_b,id)!=INVALID_HANDLE); } //--- Create the standard BW MFI indicator bool BufferCreateBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume, const int id) { return(this.m_buffers.CreateBWMFI(symbol,timeframe,applied_volume,id)!=INVALID_HANDLE); } //--- Create the standard Momentum indicator bool BufferCreateMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe, const int mom_period, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateMomentum(symbol,timeframe,mom_period,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Money Flow Index indicator bool BufferCreateMFI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const ENUM_APPLIED_VOLUME applied_volume, const int id) { return(this.m_buffers.CreateMFI(symbol,timeframe,ma_period,applied_volume,id)!=INVALID_HANDLE); } //--- Create the standard Moving Average indicator bool BufferCreateMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const int ma_shift, const ENUM_MA_METHOD ma_method, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateMA(symbol,timeframe,ma_period,ma_shift,ma_method,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Moving Average of Oscillator indicator bool BufferCreateOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, const int slow_ema_period, const int signal_period, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateOsMA(symbol,timeframe,fast_ema_period,slow_ema_period,signal_period,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard MACD indicator bool BufferCreateMACD(const string symbol,const ENUM_TIMEFRAMES timeframe, const int fast_ema_period, const int slow_ema_period, const int signal_period, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateMACD(symbol,timeframe,fast_ema_period,slow_ema_period,signal_period,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard On Balance Volume indicator bool BufferCreateOBV(const string symbol,const ENUM_TIMEFRAMES timeframe, const ENUM_APPLIED_VOLUME applied_volume, const int id) { return(this.m_buffers.CreateOBV(symbol,timeframe,applied_volume,id)!=INVALID_HANDLE); } //--- Create the standard Parabolic SAR indicator bool BufferCreateSAR(const string symbol,const ENUM_TIMEFRAMES timeframe, const double step, const double maximum, const int id) { return(this.m_buffers.CreateSAR(symbol,timeframe,step,maximum,id)!=INVALID_HANDLE); } //--- Create the standard Relative Strength Index indicator bool BufferCreateRSI(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateRSI(symbol,timeframe,ma_period,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard RVI indicator bool BufferCreateRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period,const int id) { return(this.m_buffers.CreateRVI(symbol,timeframe,ma_period,id)!=INVALID_HANDLE); } //--- Create the standard Standart Deviation indicator bool BufferCreateStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const int ma_shift, const ENUM_MA_METHOD ma_method, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateStdDev(symbol,timeframe,ma_period,ma_shift,ma_method,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Stochastic indicator bool BufferCreateStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe, const int Kperiod, const int Dperiod, const int slowing, const ENUM_MA_METHOD ma_method, const ENUM_STO_PRICE price_field, const int id) { return(this.m_buffers.CreateStochastic(symbol,timeframe,Kperiod,Dperiod,slowing,ma_method,price_field,id)!=INVALID_HANDLE); } //--- Create the standard TEMA indicator bool BufferCreateTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const int ma_shift, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateTEMA(symbol,timeframe,ma_period,ma_shift,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Triple Exponential Average indicator bool BufferCreateTriX(const string symbol,const ENUM_TIMEFRAMES timeframe, const int ma_period, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateTriX(symbol,timeframe,ma_period,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard William's Percent Range indicator bool BufferCreateWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int calc_period,const int id) { return(this.m_buffers.CreateWPR(symbol,timeframe,calc_period,id)!=INVALID_HANDLE); } //--- Create the standard VIDYA indicator bool BufferCreateVIDYA(const string symbol,const ENUM_TIMEFRAMES timeframe, const int cmo_period, const int ema_period, const int ma_shift, const ENUM_APPLIED_PRICE applied_price, const int id) { return(this.m_buffers.CreateVIDYA(symbol,timeframe,cmo_period,ema_period,ma_shift,applied_price,id)!=INVALID_HANDLE); } //--- Create the standard Volumes indicator bool BufferCreateVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume,const int id) { return(this.m_buffers.CreateVolumes(symbol,timeframe,applied_volume,id)!=INVALID_HANDLE); } //--- Initialize all drawn buffers by a (1) specified value, (2) empty value set for the buffer object
コレクションクラスのメソッドは、int型、より正確には、作成された標準指標のハンドルを返します。ここでは、bool型の値の戻りを実装します。これにより、最終プログラムのメソッドの操作が簡単になります。したがって、これらのメソッドは、バッファコレクションクラスの適切なメソッドによって返された値を INVALID_HANDLE値と比較した結果を返します。
クラスのpublicセクションで、作成されたすべての標準指標の計算バッファデータを準備して、上記で検討した同じ名前のバッファオブジェクトコレクションクラスメソッドの結果を返すメソッドと標準の指標タイプとそのIDでバッファオブジェクトの説明を返すメソッドの2つを宣言します。
//--- Prepare data of the calculated buffer of all created standard indicators bool BufferPreparingDataAllBuffersStdInd(void) { return this.m_buffers.PreparingDataAllBuffersStdInd(); } //--- Return the standard indicator buffer description by type and ID string BufferGetLabelByTypeID(const ENUM_INDICATOR ind_type,const int id); //--- Display short description of all indicator buffers of the buffer collection void BuffersPrintShort(void);
クラス本体の外にメソッドを実装します。
//+------------------------------------------------------------------+ //| Return the standard indicator buffer description | //| by type and ID | //+------------------------------------------------------------------+ string CEngine::BufferGetLabelByTypeID(const ENUM_INDICATOR ind_type,const int id) { CArrayObj *list=m_buffers.GetListBufferByTypeID(ind_type,id); if(list==NULL || list.Total()==0) return ""; CBuffer *buff=list.At(0); if(buff==NULL) return ""; return buff.Label(); } //+------------------------------------------------------------------+
ここではすべて簡単です。適切な標準指標タイプ(メソッドに渡される)とそのIDを持つバッファオブジェクトのリストを取得します。
したがって、リストにはそのようなバッファオブジェクトが2つ(計算および描画)あります。両方のオブジェクトに同様のデータが含まれているため、データを受信する正確なオブジェクトを気にする必要はありません。したがって、リストの最初のバッファオブジェクトへのポインタを取得し、その説明を返します。
「New bar」イベント処理ブロックにOnDoEasyEvent()メソッドを実装する際に、コピーされたデータの量を取得するのを少し修正しましょう。
//--- Handling timeseries events else if(idx>SERIES_EVENTS_NO_EVENT && idx<SERIES_EVENTS_NEXT_CODE) { //--- "New bar" event if(idx==SERIES_EVENTS_NEW_BAR) { ::Print(DFUN,TextByLanguage("Новый бар на ","New Bar on "),sparam," ",TimeframeDescription((ENUM_TIMEFRAMES)dparam),": ",TimeToString(lparam)); CArrayObj *list=this.m_buffers.GetListBuffersWithID(); if(list!=NULL) { int total=list.Total(); for(int i=0;i<total;i++) { CBuffer *buff=list.At(i); if(buff==NULL) continue; string symbol=sparam; ENUM_TIMEFRAMES timeframe=(ENUM_TIMEFRAMES)dparam; if(buff.TypeBuffer()==BUFFER_TYPE_DATA || buff.IndicatorType()==WRONG_VALUE) continue; if(buff.Symbol()==symbol && buff.Timeframe()==timeframe ) { CSeriesDE *series=this.SeriesGetSeries(symbol,timeframe); if(series==NULL) continue; int count=::fmin((int)series.AvailableUsedData(),::fmin(buff.GetDataTotal(),buff.IndicatorBarsCalculated())); this.m_buffers.PreparingDataBufferStdInd(buff.IndicatorType(),buff.ID(),count); } } } } //--- "Bars skipped" event if(idx==SERIES_EVENTS_MISSING_BARS) { ::Print(DFUN,TextByLanguage("Пропущены бары на ","Missed bars on "),sparam," ",TimeframeDescription((ENUM_TIMEFRAMES)dparam),": ",(string)lparam); } } //--- Handling trading events
以前は、強調表示された文字列で、バッファオブジェクトデータの合計量と計算された標準指標データから最小値を取得していました。
int count=::fmin(buff.GetDataTotal(),buff.IndicatorBarsCalculated());
ただし、使用される時系列データの数はライブラリ(したがってプログラム)で1000バーに設定されているため、バッファオブジェクトデータの総数、計算された標準指標データ、 デフォルトデータの量(1000)の3つのデータソースから最小値をコピーします。通常、1000の値は常に他の2つよりも小さく、これはデータを一括コピーするときにより役立ちます。
これで、ライブラリクラスの現在の改善は終わりです。
検証
サブウィンドウに描画される単一バッファ、複数銘柄・複数期間標準指標の作成をテストするために、次のようにします。
設定で次の選択肢を持つカスタム指標を作成します。
- 標準指標が作成された銘柄
- 標準指標が作成されたチャート期間(時間枠)
- 作成された単一バッファ複数銘柄・複数期間標準指標のタイプ
選択した標準指標のデータは、現在の銘柄/期間メインチャートのサブウィンドウに表示されます。
前の記事のテスト指標を\MQL5\Indicators\TestDoEasy\Part48\TestDoEasyPart48.mq5として保存します。
指標の入力で、表示する標準指標を選択できるようにするパラメータを追加します。
//| TestDoEasyPart48.mq5 | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //--- includes #include <DoEasy\Engine.mqh> //--- properties #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 1 //--- classes //--- enums //--- defines //--- structures //--- input variables sinput string InpUsedSymbols = "GBPUSD"; // Used symbol (one only) sinput ENUM_TIMEFRAMES InpPeriod = PERIOD_M30; // Used chart period sinput ENUM_INDICATOR InpIndType = IND_AC; // Type standard indicator //--- sinput bool InpUseSounds = true; // Use sounds //--- indicator buffers //--- global variables ENUM_SYMBOLS_MODE InpModeUsedSymbols= SYMBOLS_MODE_DEFINES; // Mode of used symbols list ENUM_TIMEFRAMES_MODE InpModeUsedTFs = TIMEFRAMES_MODE_LIST; // Mode of used timeframes list string InpUsedTFs; // List of used timeframes CEngine engine; // CEngine library main object string prefix; // Prefix of graphical object names int min_bars; // The minimum number of bars for the indicator calculation int used_symbols_mode; // Mode of working with symbols string array_used_symbols[]; // The array for passing used symbols to the library string array_used_periods[]; // The array for passing used timeframes to the library //+------------------------------------------------------------------+
カスタム指標を使用できるのは、構築用のバッファが1つあり、サブウィンドウに表示される標準指標のみです。OnInit()ハンドラでは、適切なタイプの標準指標がライブラリに作成されます。残りの指標のエラーメッセージを実装しましょう。
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Write the name of the working timeframe selected in the settings to the InpUsedTFs variable InpUsedTFs=TimeframeDescription(InpPeriod); //--- Initialize DoEasy library OnInitDoEasy(); //--- Set indicator global variables prefix=engine.Name()+"_"; //--- calculate the number of bars of the current period fitting in the maximum used period //--- Use the obtained value if it exceeds 2, otherwise use 2 int num_bars=NumberBarsInTimeframe(InpPeriod); min_bars=(num_bars>2 ? num_bars : 2); //--- Check and remove remaining indicator graphical objects if(IsPresentObectByPrefix(prefix)) ObjectsDeleteAll(0,prefix); //--- Create the button panel //--- Check playing a standard sound using macro substitutions engine.PlaySoundByDescription(SND_OK); //--- Wait for 600 milliseconds engine.Pause(600); engine.PlaySoundByDescription(SND_NEWS); //--- indicator buffers mapping //--- Create all the necessary buffer objects for constructing a selected standard indicator bool success=false; switch(InpIndType) { case IND_AC : success=engine.BufferCreateAC(InpUsedSymbols,InpPeriod,1); break; case IND_AD : success=engine.BufferCreateAD(InpUsedSymbols,InpPeriod,VOLUME_TICK,1); break; case IND_AO : success=engine.BufferCreateAO(InpUsedSymbols,InpPeriod,1); break; case IND_ATR : success=engine.BufferCreateATR(InpUsedSymbols,InpPeriod,14,1); break; case IND_BEARS : success=engine.BufferCreateBearsPower(InpUsedSymbols,InpPeriod,13,1); break; case IND_BULLS : success=engine.BufferCreateBullsPower(InpUsedSymbols,InpPeriod,13,1); break; case IND_CHAIKIN : success=engine.BufferCreateChaikin(InpUsedSymbols,InpPeriod,3,10,MODE_EMA,VOLUME_TICK,1); break; case IND_CCI : success=engine.BufferCreateCCI(InpUsedSymbols,InpPeriod,14,PRICE_TYPICAL,1); break; case IND_DEMARKER : success=engine.BufferCreateDeMarker(InpUsedSymbols,InpPeriod,14,1); break; case IND_FORCE : success=engine.BufferCreateForce(InpUsedSymbols,InpPeriod,13,MODE_SMA,VOLUME_TICK,1); break; case IND_MOMENTUM : success=engine.BufferCreateMomentum(InpUsedSymbols,InpPeriod,14,PRICE_CLOSE,1); break; case IND_MFI : success=engine.BufferCreateMFI(InpUsedSymbols,InpPeriod,14,VOLUME_TICK,1); break; case IND_OSMA : success=engine.BufferCreateOsMA(InpUsedSymbols,InpPeriod,12,26,9,PRICE_CLOSE,1); break; case IND_OBV : success=engine.BufferCreateOBV(InpUsedSymbols,InpPeriod,VOLUME_TICK,1); break; case IND_RSI : success=engine.BufferCreateRSI(InpUsedSymbols,InpPeriod,14,PRICE_CLOSE,1); break; case IND_STDDEV : success=engine.BufferCreateStdDev(InpUsedSymbols,InpPeriod,20,0,MODE_SMA,PRICE_CLOSE,1); break; case IND_TRIX : success=engine.BufferCreateTriX(InpUsedSymbols,InpPeriod,14,PRICE_CLOSE,1); break; case IND_WPR : success=engine.BufferCreateWPR(InpUsedSymbols,InpPeriod,14,1); break; case IND_VOLUMES : success=engine.BufferCreateVolumes(InpUsedSymbols,InpPeriod,VOLUME_TICK,1); break; default: break; } if(!success) { Print(TextByLanguage("Ошибка. Индикатор не создан","Error. Indicator not created")); return INIT_FAILED; } //--- Check the number of buffers specified in the 'properties' block
サブウィンドウに描画される各標準指標には、独自の小数点以下の桁数が表示されます。その上、それらのいくつかは水平線も描きます。使用する標準指標ごとに個別のセットを作成しましょう。ここでは、表示されるデータの小数点以下の桁を指定し、標準指標にレベルがある場合はレベルを定義します。
//--- Display short descriptions of created indicator buffers engine.BuffersPrintShort(); //--- Set levels where they are required and define the data decimal capacity int digits=(int)SymbolInfoInteger(InpUsedSymbols,SYMBOL_DIGITS); switch(InpIndType) { case IND_AC : digits+=2; break; case IND_AD : digits=0; break; case IND_AO : digits+=1; break; case IND_ATR : break; case IND_BEARS : digits+=1; break; case IND_BULLS : digits+=1; break; case IND_CHAIKIN : digits=0; break; case IND_CCI : IndicatorSetInteger(INDICATOR_LEVELS,2); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,100); IndicatorSetDouble(INDICATOR_LEVELVALUE,1,-100); digits=2; break; case IND_DEMARKER : IndicatorSetInteger(INDICATOR_LEVELS,2); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,0.7); IndicatorSetDouble(INDICATOR_LEVELVALUE,1,0.3); digits=3; break; case IND_FORCE : digits+=1; break; case IND_MOMENTUM : digits=2; break; case IND_MFI : IndicatorSetInteger(INDICATOR_LEVELS,2); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,80); IndicatorSetDouble(INDICATOR_LEVELVALUE,1,20); break; case IND_OSMA : digits+=2; break; case IND_OBV : digits=0; break; case IND_RSI : IndicatorSetInteger(INDICATOR_LEVELS,3); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,70); IndicatorSetDouble(INDICATOR_LEVELVALUE,1,50); IndicatorSetDouble(INDICATOR_LEVELVALUE,2,30); digits=2; break; case IND_STDDEV : digits+=1; break; case IND_TRIX : break; case IND_WPR : IndicatorSetInteger(INDICATOR_LEVELS,2); IndicatorSetDouble(INDICATOR_LEVELVALUE,0,-80); IndicatorSetDouble(INDICATOR_LEVELVALUE,1,-20); digits=2; break; case IND_VOLUMES : digits=0; break; default: IndicatorSetInteger(INDICATOR_LEVELS,0); break; } //--- Set the short name for the indicator and bit depth string label=engine.BufferGetLabelByTypeID(InpIndType,1); IndicatorSetString(INDICATOR_SHORTNAME,label); IndicatorSetInteger(INDICATOR_DIGITS,digits); //--- Successful return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
OnCalculate()ハンドラは、以前のテスト指標と比較して大幅に簡素化されています。これは、標準指標を操作するために必要なメソッドを作成したためです。必要なのは、標準指標データを準備し、メインループで現在のチャートに標準指標の計算データを表示することだけです 。
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //+------------------------------------------------------------------+ //| OnCalculate code block for working with the library: | //+------------------------------------------------------------------+ //--- Pass the current symbol data from OnCalculate() to the price structure and set the "as timeseries" flag to the arrays CopyDataAsSeries(rates_total,prev_calculated,time,open,high,low,close,tick_volume,volume,spread); //--- Check for the minimum number of bars for calculation if(rates_total<min_bars || Point()==0) return 0; //--- Handle the Calculate event in the library //--- If the OnCalculate() method of the library returns zero, not all timeseries are ready - leave till the next tick if(engine.0) return 0; //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(rates_data); // Working in the library timer engine.EventsHandling(); // Working with library events } //+------------------------------------------------------------------+ //| OnCalculate code block for working with the indicator: | //+------------------------------------------------------------------+ //--- Check and calculate the number of calculated bars //--- If limit = 0, there are no new bars - calculate the current one //--- If limit = 1, a new bar has appeared - calculate the first and the current ones //--- limit > 1 means the first launch or changes in history - the full recalculation of all data int limit=rates_total-prev_calculated; //--- Recalculate the entire history if(limit>1) { limit=rates_total-1; engine.BuffersInitPlots(); engine.BuffersInitCalculates(); engine.BufferPreparingDataAllBuffersStdInd(); } //--- Prepare data //--- Fill in calculated buffers of all created standard indicators with data int bars_total=engine.SeriesGetBarsTotal(InpUsedSymbols,InpPeriod); int total_copy=(limit<min_bars ? min_bars : fmin(limit,bars_total)); if(!engine.BufferPreparingDataAllBuffersStdInd()) return 0; //--- Calculate the indicator //--- Main calculation loop of the indicator for(int i=limit; i>WRONG_VALUE && !IsStopped(); i--) { engine.GetBuffersCollection().SetDataBufferStdInd(InpIndType,1,i,time[i]); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
テスト指標を作成するために必要なのはこれですべてです。
完全な指標コードは、以下に添付されているファイルで提供されます。
作成した指標をコンパイルし、設定でGBPUSD M5を設定し、EURUSD M1で指標を起動します。
図はすべての可能な指標を示しているわけではありませんが、主なものが表示されます。指標は、現在のチャートデータとは異なるデータに基づいて選択された標準指標を描画します。レベルラインは必要に応じて描画されます。
次の段階
次の記事では、標準の指標を作成し、メインチャートウィンドウにデータを表示し、複数のバッファが描画された指標の実装を開始します。
ライブラリの現在のバージョンのすべてのファイルは、テスト指標ファイルと一緒に以下に添付されています。ダウンロードしてテストしてください。
質問、コメント、提案はコメント欄にお願いします。テスト指標はMQL5向けに開発されたのでご注意ください。
添付ファイルはMetaTrader 5のみを対象としています。現在のライブラリバージョンはMetaTrader 4ではテストされていません。
指標バッファ操作を開発してテストした後で、MetaTrader 4にいくつかのMQL5機能を実装してみます。
シリーズのこれまでの記事:
DoEasyライブラリの時系列(第35部): バーオブジェクトと銘柄の時系列リストDoEasyライブラリの時系列(第36部): すべての使用銘柄期間の時系列オブジェクト
DoEasyライブラリの時系列(第37部): すべての使用銘柄期間の時系列オブジェクト
DoEasyライブラリの時系列(第38部): 時系列コレクション-リアルタイムの更新とプログラムからのデータへのアクセス
DoEasyライブラリの時系列(第39部): ライブラリに基づいた指標 - データイベントと時系列イベントの準備
DoEasyライブラリの時系列(第40部): ライブラリに基づいた指標 - 実時間でのデータ更新
DoEasyライブラリの時系列(第41部): 複数銘柄・複数期間指標の例
DoEasyライブラリの時系列(第42部): 抽象指標バッファオブジェクトクラス
DoEasyライブラリの時系列(第43部): 指標バッファオブジェクトクラス
DoEasyライブラリの時系列(第44部): 指標バッファオブジェクトのコレクションクラス
DoEasyライブラリの時系列(第45部): 複数期間指標バッファ
DoEasyライブラリの時系列(第46部): 複数銘柄・複数期間指標バッファ
DoEasyライブラリの時系列(第47部): 複数銘柄・複数期間標準指標