DoEasyライブラリの時系列(第48部): 複数銘柄・複数期間指標バッファ
内容
概念
現段階では、ライブラリには、複数期間指標バッファを作成および追跡するための機能がすでに含まれています。次に、カスタムプログラムで使用するライブラリツールの開発を目的とした追加のタスクを処理できるように、複数銘柄モードで作業するための機能を追加します。
以前の作業により、バッファオブジェクトクラスはすでにそのような機能を備えていますが、改良が必要です。したがって、本日は最後の準備をおこない、複数銘柄・複数期間標準指標の簡略化された開発に進みます。
これを実現するには、計算バッファオブジェクトクラスを改善して、標準指標ハンドルによって配列データをその配列に受け入れることができるようにする必要があります。ライブラリではこれをすでにおこなうことができますが、これから実装しようとしている小さな追加により、タスクが大幅に容易になり、任意の銘柄/期間の標準指標から現在のチャートにデータを表示できるようになります。
次の記事では、現在の概念をクラスに適用して、任意の銘柄/期間の標準指標データを操作し、複数銘柄・複数期間標準指標を作成するタスクを簡略化します。
任意の銘柄を操作するためのバッファオブジェクトクラスの改善
基本抽象バッファオブジェクトのクラスには、現在の指標バッファの後に作成できる後続指標バッファの配列インデックス値が含まれています。この現在のオブジェクトでは、現在のバッファオブジェクトのタイプとその描画スタイルに応じて、後続指標バッファのインデックスの単純な計算に頼る必要がありますが、計算では、「fill with color between two levels」(2つのレベルの間の色で塗りつぶす)描画スタイルの指標バッファにカラーバッファがないことも考慮されます。
後続バッファのインデックスを計算するタスクを簡素化し、さまざまな要因を考慮したときに計算の明確さを妨げないようにするために、バッファオブジェクトの構築に使用されるすべての配列の数を含むさらに別のクラスメンバー変数を導入します。この厳密に設定された値は、子孫クラスコンストラクタのパラメータのprotected基本オブジェクトクラスコンストラクタに必要な値を渡すことにより、各バッファオブジェクト(抽象バッファクラスの子孫)を作成するときに指定されます。
これは扱いにくく思えますが、実際にはすべてが非常に単純です。新しい指標バッファオブジェクトの作成時にはすでに、バッファオブジェクトクラスコンストラクタのいくつかの値をその親クラスコンストラクタに渡しています。さらに、もう1つの値、つまり各バッファオブジェクトの構築に必要な配列の数を渡します。
指標バッファ基本オブジェクトの抽象クラスのファイル(\MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh) に必要な変更を加えます。
クラスのprivateセクションで新しい変数を宣言します。
//+------------------------------------------------------------------+ //| Abstract indicator buffer class | //+------------------------------------------------------------------+ class CBuffer : public CBaseObj { private: long m_long_prop[BUFFER_PROP_INTEGER_TOTAL]; // Integer properties double m_double_prop[BUFFER_PROP_DOUBLE_TOTAL]; // Real properties string m_string_prop[BUFFER_PROP_STRING_TOTAL]; // String properties bool m_act_state_trigger; // Auxiliary buffer status switch flag uchar m_total_arrays; // Total number of buffer arrays
protectedパラメトリッククラスコンストラクタを宣言するときは、入力にさらに別の変数を追加します。この変数は、このバッファオブジェクトの作成中に、すべてのバッファオブジェクト配列の数をクラスに渡すのに使用されます。
//--- Default constructor CBuffer(void){;} protected: //--- Protected parametric constructor CBuffer(ENUM_BUFFER_STATUS status_buffer, ENUM_BUFFER_TYPE buffer_type, const uint index_plot, const uint index_base_array, const int num_datas, const uchar total_arrays, const int width, const string label); public:
コンストラクタ実装コードで、この変数を入力リストに追加し、渡された値を以前に宣言されたprivate変数に割り当てます。次に、この値を使用して、次のバッファオブジェクトの基本配列インデックスを計算します。カラー配列インデックスを計算するときは、バッファタイプを確認します。これが描画バッファの場合は、すべてのデータ配列の数を基本配列インデックスに追加してインデックスを計算します。計算バッファの場合はカラー配列がないため、ゼロを追加します。
//+------------------------------------------------------------------+ //| Closed parametric constructor | //+------------------------------------------------------------------+ CBuffer::CBuffer(ENUM_BUFFER_STATUS buffer_status, ENUM_BUFFER_TYPE buffer_type, const uint index_plot, const uint index_base_array, const int num_datas, const uchar total_arrays, const int width, const string label) { this.m_type=COLLECTION_BUFFERS_ID; this.m_act_state_trigger=true; this.m_total_arrays=total_arrays; //--- Save integer properties this.m_long_prop[BUFFER_PROP_STATUS] = buffer_status; this.m_long_prop[BUFFER_PROP_TYPE] = buffer_type; ENUM_DRAW_TYPE type= ( !this.TypeBuffer() || !this.Status() ? DRAW_NONE : this.Status()==BUFFER_STATUS_FILLING ? DRAW_FILLING : ENUM_DRAW_TYPE(this.Status()+8) ); this.m_long_prop[BUFFER_PROP_DRAW_TYPE] = type; this.m_long_prop[BUFFER_PROP_TIMEFRAME] = PERIOD_CURRENT; this.m_long_prop[BUFFER_PROP_ACTIVE] = true; this.m_long_prop[BUFFER_PROP_ARROW_CODE] = 0x9F; this.m_long_prop[BUFFER_PROP_ARROW_SHIFT] = 0; this.m_long_prop[BUFFER_PROP_DRAW_BEGIN] = 0; this.m_long_prop[BUFFER_PROP_SHOW_DATA] = (buffer_type>BUFFER_TYPE_CALCULATE ? true : false); this.m_long_prop[BUFFER_PROP_SHIFT] = 0; this.m_long_prop[BUFFER_PROP_LINE_STYLE] = STYLE_SOLID; this.m_long_prop[BUFFER_PROP_LINE_WIDTH] = width; this.m_long_prop[BUFFER_PROP_COLOR_INDEXES] = (this.Status()>BUFFER_STATUS_NONE ? (this.Status()!=BUFFER_STATUS_FILLING ? 1 : 2) : 0); this.m_long_prop[BUFFER_PROP_COLOR] = clrRed; this.m_long_prop[BUFFER_PROP_NUM_DATAS] = num_datas; this.m_long_prop[BUFFER_PROP_INDEX_PLOT] = index_plot; this.m_long_prop[BUFFER_PROP_INDEX_BASE] = index_base_array; this.m_long_prop[BUFFER_PROP_INDEX_COLOR] = this.GetProperty(BUFFER_PROP_INDEX_BASE)+ (this.TypeBuffer()!=BUFFER_TYPE_CALCULATE ? this.GetProperty(BUFFER_PROP_NUM_DATAS) : 0); this.m_long_prop[BUFFER_PROP_INDEX_NEXT_BASE] = index_base_array+this.m_total_arrays; this.m_long_prop[BUFFER_PROP_INDEX_NEXT_PLOT] = (this.TypeBuffer()>BUFFER_TYPE_CALCULATE ? index_plot+1 : index_plot); //--- Save real properties this.m_double_prop[this.IndexProp(BUFFER_PROP_EMPTY_VALUE)] = (this.TypeBuffer()>BUFFER_TYPE_CALCULATE ? EMPTY_VALUE : 0); //--- Save string properties this.m_string_prop[this.IndexProp(BUFFER_PROP_SYMBOL)] = ::Symbol(); this.m_string_prop[this.IndexProp(BUFFER_PROP_LABEL)] = (this.TypeBuffer()>BUFFER_TYPE_CALCULATE ? label : NULL); //--- If failed to change the size of the indicator buffer array, display the appropriate message indicating the string if(::ArrayResize(this.DataBuffer,(int)this.GetProperty(BUFFER_PROP_NUM_DATAS))==WRONG_VALUE) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_DRAWING_ARRAY_RESIZE),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",(string)::GetLastError()); //--- If failed to change the size of the color array (only for a non-calculated buffer), display the appropriate message indicating the string if(this.TypeBuffer()>BUFFER_TYPE_CALCULATE) if(::ArrayResize(this.ArrayColors,(int)this.ColorsTotal())==WRONG_VALUE) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",(string)::GetLastError()); //--- For DRAW_FILLING, fill in the color array with two default colors if(this.Status()==BUFFER_STATUS_FILLING) { this.SetColor(clrBlue,0); this.SetColor(clrRed,1); } //--- Bind indicator buffers with arrays //--- In a loop by the number of indicator buffers int total=::ArraySize(DataBuffer); for(int i=0;i<total;i++) { //--- calculate the index of the next array and //--- bind the indicator buffer by the calculated index with the dynamic array //--- located by the i loop index in the DataBuffer array int index=(int)this.GetProperty(BUFFER_PROP_INDEX_BASE)+i; ::SetIndexBuffer(index,this.DataBuffer[i].Array,(this.TypeBuffer()==BUFFER_TYPE_DATA ? INDICATOR_DATA : INDICATOR_CALCULATIONS)); //--- Set indexation flag as in the timeseries to all buffer arrays ::ArraySetAsSeries(this.DataBuffer[i].Array,true); } //--- Bind the color buffer with the array (only for a non-calculated buffer and not for the filling buffer) if(this.Status()!=BUFFER_STATUS_FILLING && this.TypeBuffer()!=BUFFER_TYPE_CALCULATE) { ::SetIndexBuffer((int)this.GetProperty(BUFFER_PROP_INDEX_COLOR),this.ColorBufferArray,INDICATOR_COLOR_INDEX); ::ArraySetAsSeries(this.ColorBufferArray,true); } //--- If this is a calculated buffer, all is done if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE) return; //--- Set integer parameters of the graphical series ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_TYPE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_TYPE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_CODE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_SHIFT)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_BEGIN,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_BEGIN)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHOW_DATA,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHOW_DATA)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHIFT)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_STYLE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_STYLE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_WIDTH,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_WIDTH)); this.SetColor((color)this.GetProperty(BUFFER_PROP_COLOR)); //--- Set real parameters of the graphical series ::PlotIndexSetDouble((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_EMPTY_VALUE,this.GetProperty(BUFFER_PROP_EMPTY_VALUE)); //--- Set string parameters of the graphical series ::PlotIndexSetString((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LABEL,this.GetProperty(BUFFER_PROP_LABEL)); } //+------------------------------------------------------------------+
これで、抽象バッファ基本オブジェクトの子孫オブジェクトのすべてのクラスが、クラスコンストラクタの初期化リストでバッファを構築するために使用する必要のある配列の数を渡すことで補完されます。
配列バッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferArrow.mqh):
//+------------------------------------------------------------------+ //| Buffer with the "Drawing with arrows" drawing style | //+------------------------------------------------------------------+ class CBufferArrow : public CBuffer { private: public: //--- Constructor CBufferArrow(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_ARROW,BUFFER_TYPE_DATA,index_plot,index_base_array,1,2,1,"Arrows") {}
ラインバッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferLine.mqh):
//+------------------------------------------------------------------+ //| Buffer of the Line drawing style | //+------------------------------------------------------------------+ class CBufferLine : public CBuffer { private: public: //--- Constructor CBufferLine(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_LINE,BUFFER_TYPE_DATA,index_plot,index_base_array,1,2,1,"Line") {}
セクションバッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferSection.mqh):
//+------------------------------------------------------------------+ //| Buffer of the Section drawing style | //+------------------------------------------------------------------+ class CBufferSection : public CBuffer { private: public: //--- Constructor CBufferSection(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_SECTION,BUFFER_TYPE_DATA,index_plot,index_base_array,1,2,1,"Section") {}
ゼロラインからのヒストグラムバッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferHistogram.mqh):
//+------------------------------------------------------------------+ //| Buffer of the "Histogram from the zero line" drawing style | //+------------------------------------------------------------------+ class CBufferHistogram : public CBuffer { private: public: //--- Constructor CBufferHistogram(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_HISTOGRAM,BUFFER_TYPE_DATA,index_plot,index_base_array,1,2,2,"Histogram") {}
2つの指標バッファのヒストグラムバッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferHistogram2.mqh):
//+--------------------------------------------------------------------+ //|Buffer of the "Histogram on two indicator buffers" drawing style | //+--------------------------------------------------------------------+ class CBufferHistogram2 : public CBuffer { private: public: //--- Constructor CBufferHistogram2(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_HISTOGRAM2,BUFFER_TYPE_DATA,index_plot,index_base_array,2,3,8,"Histogram2 0;Histogram2 1") {}
ジグザグバッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferZigZag.mqh):
//+------------------------------------------------------------------+ //|Buffer of the ZigZag drawing style | //+------------------------------------------------------------------+ class CBufferZigZag : public CBuffer { private: public: //--- Constructor CBufferZigZag(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_ZIGZAG,BUFFER_TYPE_DATA,index_plot,index_base_array,2,3,1,"ZigZag 0;ZigZag 1") {}
塗りつぶしバッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferFilling.mqh):
//+------------------------------------------------------------------+ //|Buffer of the "Color filling between two levels" drawing style | //+------------------------------------------------------------------+ class CBufferFilling : public CBuffer { private: public: //--- Constructor CBufferFilling(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_FILLING,BUFFER_TYPE_DATA,index_plot,index_base_array,2,2,1,"Filling 0;Filling 1") {}
バー描画バッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferBars.mqh):
//+------------------------------------------------------------------+ //|Buffer of the Bars drawing style | //+------------------------------------------------------------------+ class CBufferBars : public CBuffer { private: public: //--- Constructor CBufferBars(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_BARS,BUFFER_TYPE_DATA,index_plot,index_base_array,4,5,2,"Bar Open;Bar High;Bar Low;Bar Close") {}
ローソク足描画バッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferCandles.mqh):
//+------------------------------------------------------------------+ //|Buffer of the Candles drawing style | //+------------------------------------------------------------------+ class CBufferCandles : public CBuffer { private: public: //--- Constructor CBufferCandles(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_CANDLES,BUFFER_TYPE_DATA,index_plot,index_base_array,4,5,1,"Candle Open;Candle High;Candle Low;Candle Close") {}
計算バッファ(\MQL5\Include\DoEasy\Objects\Indicators\BufferCalculate.mqh):
//+------------------------------------------------------------------+ //| Calculated buffer | //+------------------------------------------------------------------+ class CBufferCalculate : public CBuffer { private: public: //--- Constructor CBufferCalculate(const uint index_plot,const uint index_array) : CBuffer(BUFFER_STATUS_NONE,BUFFER_TYPE_CALCULATE,index_plot,index_array,1,1,0,"Calculate") {}
このような変更により、各バッファタイプに常に同じ数の配列が使用されるため、後続の作成されたバッファのインデックスを計算するためにバッファタイプと描画スタイルのチェックを実行する必要がなくなります。この値は、バッファ作成時に、厳密に指定された形式で渡されます。
計算バッファクラスに新しいメソッドを追加して、標準の指標ハンドルから計算バッファ配列にデータを書き込みます。
//+------------------------------------------------------------------+ //| Calculated buffer | //+------------------------------------------------------------------+ class CBufferCalculate : public CBuffer { private: public: //--- Constructor CBufferCalculate(const uint index_plot,const uint index_array) : CBuffer(BUFFER_STATUS_NONE,BUFFER_TYPE_CALCULATE,index_plot,index_array,1,1,0,"Calculate") {} //--- Supported integer properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_INTEGER property); //--- Supported real properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_DOUBLE property); //--- Supported string properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_STRING property); //--- Display a short buffer description in the journal virtual void PrintShort(void); //--- Set the value to the data buffer array void SetData(const uint series_index,const double value) { this.SetBufferValue(0,series_index,value); } //--- Return the value from the data buffer array double GetData(const uint series_index) const { return this.GetDataBufferValue(0,series_index); } //--- Copy data of the specified indicator to the buffer object array int FillAsSeries(const int indicator_handle,const int buffer_num,const int start_pos,const int count); int FillAsSeries(const int indicator_handle,const int buffer_num,const datetime start_time,const int count); int FillAsSeries(const int indicator_handle,const int buffer_num,const datetime start_time,const datetime stop_time); }; //+------------------------------------------------------------------+
クラス本体の外側で実装しましょう。
//+------------------------------------------------------------------+ //| Copy data of the specified indicator to the buffer object array | //+------------------------------------------------------------------+ int CBufferCalculate::FillAsSeries(const int indicator_handle,const int buffer_num,const int start_pos,const int count) { return ::CopyBuffer(indicator_handle,buffer_num,start_pos,count,this.DataBuffer[0].Array); } //+------------------------------------------------------------------+ int CBufferCalculate::FillAsSeries(const int indicator_handle,const int buffer_num,const datetime start_time,const int count) { return ::CopyBuffer(indicator_handle,buffer_num,start_time,count,this.DataBuffer[0].Array); } //+------------------------------------------------------------------+ int CBufferCalculate::FillAsSeries(const int indicator_handle,const int buffer_num,const datetime start_time,const datetime stop_time) { return ::CopyBuffer(indicator_handle,buffer_num,start_time,stop_time,this.DataBuffer[0].Array); } //+------------------------------------------------------------------+
3つのメソッドはすべて、CopyBuffer()オーバーロード関数の3つのバリアントを使用します。適切な指標バッファによって割り当てられた配列は、受信配列として使用されます。適切な指標バッファとは、必要な指標データをそのハンドルによってオブジェクト配列に書き込むためのメソッドを呼び出すバッファです。
次に、複数銘柄モードでのバッファオブジェクト操作を実装します。まず、前の記事の資料を準備するときにおこなったいくつかの仮定に対処する必要があります。この記事では、複数期間モードを実装しました。
指標バッファコレクションクラスで、単一のバッファバーを操作するために必要な時系列とバーのデータを受信するためのメソッドを作成しました。このメソッドは、チャート期間に必要なすべてのデータ(現在および割り当てられたバッファオブジェクト)と、銘柄に必要なすべてのデータ(現在および割り当てられたバッファオブジェクト)を備えています。以下は前の記事のメソッドです。
//+------------------------------------------------------------------+ //| Get data of the necessary timeseries and bars | //| for working with a single bar of the buffer | //+------------------------------------------------------------------+ int CBuffersCollection::GetBarsData(CBuffer *buffer,const int series_index,int &index_bar_period) { //--- Get timeseries of the current chart and the chart of the buffer timeframe CSeriesDE *series_current=this.m_timeseries.GetSeries(buffer.Symbol(),PERIOD_CURRENT); CSeriesDE *series_period=this.m_timeseries.GetSeries(buffer.Symbol(),buffer.Timeframe()); if(series_current==NULL || series_period==NULL) return WRONG_VALUE; //--- Get the bar object of the current timeseries corresponding to the required timeseries index CBar *bar_current=series_current.GetBar(series_index); if(bar_current==NULL) return WRONG_VALUE; //--- Get the timeseries bar object of the buffer chart period corresponding to the time the timeseries bar of the current chart falls into CBar *bar_period=m_timeseries.GetBarSeriesFirstFromSeriesSecond(NULL,PERIOD_CURRENT,bar_current.Time(),NULL,series_period.Timeframe()); if(bar_period==NULL) return WRONG_VALUE; //--- Write down the bar index on the current timeframe which falls into the bar start time of the buffer object chart index_bar_period=bar_period.Index(PERIOD_CURRENT); //--- Calculate the amount of bars of the current timeframe included into one bar of the buffer object chart period //--- and return this value (1 if the result is 0) int num_bars=::PeriodSeconds(bar_period.Timeframe())/::PeriodSeconds(bar_current.Timeframe()); return(num_bars>0 ? num_bars : 1); } //+------------------------------------------------------------------+
ここでは、必要な銘柄から2つの文字列でデータを取得できませんでした。現在のチャート時系列では、バッファオブジェクトに割り当てられた銘柄のチャートからデータを取得しました。バッファオブジェクト銘柄を取得する必要があるポイントで現在のチャート銘柄を取得する2番目の文字列では、ケースはまったく逆です。
結果的に、すべての修正は、2つのコード文字列の2つの修正のみに要約されます。
以下は、修正されたメソッドの完全なコードです。
//+------------------------------------------------------------------+ //| Get data of the necessary timeseries and bars | //| for working with a single bar of the buffer | //+------------------------------------------------------------------+ int CBuffersCollection::GetBarsData(CBuffer *buffer,const int series_index,int &index_bar_period) { //--- Get timeseries of the current chart and the chart of the buffer timeframe CSeriesDE *series_current=this.m_timeseries.GetSeries(Symbol(),PERIOD_CURRENT); CSeriesDE *series_period=this.m_timeseries.GetSeries(buffer.Symbol(),buffer.Timeframe()); if(series_current==NULL || series_period==NULL) return WRONG_VALUE; //--- Get the bar object of the current timeseries corresponding to the required timeseries index CBar *bar_current=series_current.GetBar(series_index); if(bar_current==NULL) return WRONG_VALUE; //--- Get the timeseries bar object of the buffer chart period corresponding to the time the timeseries bar of the current chart falls into CBar *bar_period=m_timeseries.GetBarSeriesFirstFromSeriesSecond(NULL,PERIOD_CURRENT,bar_current.Time(),buffer.Symbol(),series_period.Timeframe()); if(bar_period==NULL) return WRONG_VALUE; //--- Write down the bar index on the current timeframe which falls into the bar start time of the buffer object chart index_bar_period=bar_period.Index(PERIOD_CURRENT); //--- Calculate the amount of bars of the current timeframe included into one bar of the buffer object chart period //--- and return this value (1 if the result is 0) int num_bars=::PeriodSeconds(bar_period.Timeframe())/::PeriodSeconds(bar_current.Timeframe()); return(num_bars>0 ? num_bars : 1); } //+------------------------------------------------------------------+
準備完了です。これで、バッファオブジェクトは複数銘柄モードでも機能できるようになりました。
現在のチャートの指定されたバーのインデックスが該当する銘柄/期間チャートのバーインデックスを返すメソッドはまだありません。このメソッドは、メイン指標ループで、現在のチャートに別の銘柄/期間からのデータを正しく表示するために必要です。
このようなメソッドに最適な場所は、時系列コレクションクラスの \MQL5\Include\DoEasy\Collections\TimeSeriesCollection.mqhです。
ここに新しいメソッドを宣言します。
//--- Return the bar object of the specified timeseries of the specified symbol of the specified position (1) by index, (2) by time //--- bar object of the first timeseries corresponding to the bar open time on the second timeseries (3) by index, (4) by time CBar *GetBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const int index,const bool from_series=true); CBar *GetBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime bar_time); CBar *GetBarSeriesFirstFromSeriesSecond(const string symbol_first,const ENUM_TIMEFRAMES timeframe_first,const int index, const string symbol_second=NULL,const ENUM_TIMEFRAMES timeframe_second=PERIOD_CURRENT); CBar *GetBarSeriesFirstFromSeriesSecond(const string symbol_first,const ENUM_TIMEFRAMES timeframe_first,const datetime first_bar_time, const string symbol_second=NULL,const ENUM_TIMEFRAMES timeframe_second=PERIOD_CURRENT); //--- Return the bar index on the specified timeframe chart by the current chart's bar index | int IndexBarPeriodByBarCurrent(const int series_index,const string symbol,const ENUM_TIMEFRAMES timeframe); //--- Return the flag of opening a new bar of the specified timeseries of the specified symbol bool IsNewBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime time=0);
クラス本体の外側で実装しましょう。
//+------------------------------------------------------------------+ //| Return the bar index on the specified timeframe chart | //| by the current chart's bar index | //+------------------------------------------------------------------+ int CTimeSeriesCollection::IndexBarPeriodByBarCurrent(const int series_index,const string symbol,const ENUM_TIMEFRAMES timeframe) { CSeriesDE *series=this.GetSeries(::Symbol(),(ENUM_TIMEFRAMES)::Period()); if(series==NULL) return WRONG_VALUE; CBar *bar=series.GetBar(series_index); if(bar==NULL) return WRONG_VALUE; return ::iBarShift(symbol,timeframe,bar.Time()); } //+------------------------------------------------------------------+
このメソッドは、現在のチャートバーインデックスと、チャートの銘柄および期間を受け取ります。メソッドに渡された現在のチャートインデックスの時間に対応するバーインデックスを返す必要があります。
さらに、現在のチャート時系列へのポインタを取得し、現在の時系列インデックスによってバーオブジェクトへのポインタを取得します。また、バー時間を使用して、必要な時系列の対応するバーのインデックスを返します。
計算バッファは、指標が基づいている時系列に従って指標バッファのデータを完全に格納するため、このメソッドを使用して、現在のチャートで指定されたバーインデックスに対応する計算バッファ配列のインデックスを取得します( ここでは、指標ループインデックスを実際の例として使用できます)。2つのさまざまな時系列の間でこのような一致を確立できれば、これらのデータを必要なチャートに正しく表示できます。
カスタムプログラムからメソッドにアクセスするには、CEngineライブラリのメインオブジェクトクラス(\MQL5\Include\DoEasy\Engine.mqh)からメソッドへのアクセスを提供する必要があります。
//--- Clear data by the timeseries index for the (1) arrow, (2) line, (3) section, (4) zero line histogram, //--- (5) histogram on two buffers, (6) zigzag, (7) filling, (8) bars and (9) candles void BufferArrowClear(const int number,const int series_index) { this.m_buffers.ClearBufferArrow(number,series_index); } void BufferLineClear(const int number,const int series_index) { this.m_buffers.ClearBufferLine(number,series_index); } void BufferSectionClear(const int number,const int series_index) { this.m_buffers.ClearBufferSection(number,series_index); } void BufferHistogramClear(const int number,const int series_index) { this.m_buffers.ClearBufferHistogram(number,series_index); } void BufferHistogram2Clear(const int number,const int series_index) { this.m_buffers.ClearBufferHistogram2(number,series_index);} void BufferZigZagClear(const int number,const int series_index) { this.m_buffers.ClearBufferZigZag(number,series_index); } void BufferFillingClear(const int number,const int series_index) { this.m_buffers.ClearBufferFilling(number,series_index); } void BufferBarsClear(const int number,const int series_index) { this.m_buffers.ClearBufferBars(number,series_index); } void BufferCandlesClear(const int number,const int series_index) { this.m_buffers.ClearBufferCandles(number,series_index); } //--- Return the bar index on the specified timeframe chart by the current chart's bar index int IndexBarPeriodByBarCurrent(const int series_index,const string symbol,const ENUM_TIMEFRAMES timeframe) { return this.m_time_series.IndexBarPeriodByBarCurrent(series_index,symbol,timeframe); } //--- Display short description of all indicator buffers of the buffer collection void BuffersPrintShort(void);
これで、複数銘柄・複数期間指標の開発と処理をテストするためのライブラリクラスの改善が完了しました。
テストを実行するには、移動平均とMACDの2つの複数銘柄・複数期間指標を作成して、現在のチャートの指定された銘柄/期間から取得したデータを描画します。指標設定で、標準指標データの取得元となる指標のパラメータとチャート期間/銘柄を設定します。
テスト: 複数銘柄・複数期間移動平均
テストを実行するには、前の記事のテスト指標を、\MQL5\Indicators\TestDoEasy\Part45\TestDoEasyPart46.mq5として保存します。
指標は、設定で指定された銘柄/期間のローソク足を別のサブウィンドウに表示します。指定されたパラメータと同じ銘柄/期間の移動平均が同じサブウィンドウに表示されます。
チャートサブウィンドウで指標データを表示を設定し、指標の銘柄値とチャート期間を入力し、移動平均入力を設定します。また、入力されたMAパラメータを調整するためのグローバル変数を設定します。
//+------------------------------------------------------------------+ #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 8 #property indicator_plots 2 //--- classes //--- enums //--- defines //--- structures //--- input variables sinput string InpUsedSymbols = "GBPUSD"; // Used symbol (one only) sinput ENUM_TIMEFRAMES InpPeriod = PERIOD_M30; // Used chart period //--- sinput uint InpPeriodMA = 14; // MA Period sinput int InpShiftMA = 0; // MA Shift sinput ENUM_MA_METHOD InpMethodMA = MODE_SMA; // MA Method sinput ENUM_APPLIED_PRICE InpPriceMA = PRICE_CLOSE; // MA Applied Price //--- sinput bool InpUseSounds = true; // Use sounds //--- indicator buffers CArrayObj *list_buffers; // Pointer to the buffer object list //--- 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 int handle_ma; // МА handle int period_ma; // Moving Average calculation period //+------------------------------------------------------------------+
OnInit()ハンドラーで、3つのバッファオブジェクトを作成します。最初のオブジェクトはМАライン、2番目のオブジェクトは選択した銘柄ローソク足、3番目は選択した銘柄/期間から取得した移動平均データを格納するために計算されたものです。
次に、ローソク足バッファの4つのデータウィンドウバッファ配列すべての説明を設定します。また、MAラインバッファに対しても同じことを実行します。完了したら、移動平均指標ハンドルを作成します。
//+------------------------------------------------------------------+ //| 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(); IndicatorSetInteger(INDICATOR_DIGITS,(int)SymbolInfoInteger(InpUsedSymbols,SYMBOL_DIGITS)+1); //--- Set indicator global variables prefix=engine.Name()+"_"; //--- Get the index of the maximum used timeframe in the array, //--- 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 index=ArrayMaximum(ArrayUsedTimeframes); int num_bars=NumberBarsInTimeframe(ArrayUsedTimeframes[index]); min_bars=(index>WRONG_VALUE ? (num_bars>2 ? num_bars : 2) : 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 engine.BufferCreateLine(); // 2 arrays engine.BufferCreateCandles(); // 5 arrays engine.BufferCreateCalculate(); // 1 array //--- Check the number of buffers specified in the 'properties' block if(engine.BuffersPropertyPlotsTotal()!=indicator_plots) Alert(TextByLanguage("Внимание! Значение \"indicator_plots\" должно быть ","Attention! Value of \"indicator_plots\" should be "),engine.BuffersPropertyPlotsTotal()); if(engine.BuffersPropertyBuffersTotal()!=indicator_buffers) Alert(TextByLanguage("Внимание! Значение \"indicator_buffers\" должно быть ","Attention! Value of \"indicator_buffers\" should be "),engine.BuffersPropertyBuffersTotal()); //--- Create the color array and set non-default colors to all buffers within the collection color array_colors[]={clrDodgerBlue,clrRed,clrGray}; engine.BuffersSetColors(array_colors); //--- Set МА period period_ma=int(InpPeriodMA<2 ? 2 : InpPeriodMA); //--- In a loop by the list of collection buffer objects, for(int i=0;i<engine.GetListBuffers().Total();i++) { //--- get the next buffer CBuffer *buff=engine.GetListBuffers().At(i); if(buff==NULL) continue; //--- and set its display in the data window depending on its specified usage //--- and also a chart period and symbol selected in the settings buff.SetShowData(true); buff.SetTimeframe(InpPeriod); buff.SetSymbol(InpUsedSymbols); if(buff.Status()==BUFFER_STATUS_CANDLES) { string pr=InpUsedSymbols+" "+TimeframeDescription(InpPeriod)+" "; string label=pr+"Open;"+pr+"High;"+pr+"Low;"+pr+"Close"; buff.SetLabel(label); } if(buff.Status()==BUFFER_STATUS_LINE) { string label="MA("+(string)period_ma+")"; buff.SetLabel(label); } } //--- Display short descriptions of created indicator buffers engine.BuffersPrintShort(); //--- Create МА handle handle_ma=iMA(InpUsedSymbols,InpPeriod,period_ma,InpShiftMA,InpMethodMA,InpPriceMA); if(handle_ma==INVALID_HANDLE) return INIT_FAILED; //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
OnCalculate()ハンドラーのデータ準備ブロックで、MAデータを計算バッファにコピーします。
各ティックでMAデータ配列全体がコピーされないようにするには、「limit」変数が最初の起動時または履歴データの変更時に1を超えるように計算され、新しいバーが開いた場合は1に等しく、それ以外では各ティックで0であるよう注意する必要があります。
ゼロバーをコピーすることはできないので、「limit」値に基づいてデータをコピーすることはできません。つまり、「limit」がゼロに等しい場合はバーを1つコピーし、それ以外の場合は、「limit」で指定された数だけコピーします。これで、関連するMAデータを計算バッファにコピーするのに、リソースを節約できます。
//--- Prepare data CBufferCalculate *buff_calc=engine.GetBufferCalculate(0); int total_copy=(limit<2 ? 1 : limit); int copied=buff_calc.FillAsSeries(handle_ma,0,0,total_copy); if(copied<total_copy) return 0;
メイン指標ループで、最初に描画されたすべての指標バッファの現在のバーを消去し(不要な値を取り除くため)、次に選択した銘柄のMAラインとローソク足を再計算しながら現在のチャートでの表示を再計算します。
//--- Main calculation loop of the indicator for(int i=limit; i>WRONG_VALUE && !IsStopped(); i--) { //--- Clear the current bar of all created buffers engine.BufferLineClear(0,0); engine.BufferCandlesClear(0,0); //--- Get the timeseries bar corresponding to the loop index time on the chart period specified in the settings bar=engine.SeriesGetBar(InpUsedSymbols,InpPeriod,time[i]); if(bar==NULL) continue; //--- Calculate the color index depending on the candle direction on the timeframe specified in the settings color_index=(bar.TypeBody()==BAR_BODY_TYPE_BULLISH ? 0 : bar.TypeBody()==BAR_BODY_TYPE_BEARISH ? 1 : 2); //--- Calculate the MA line buffer int index=engine.IndexBarPeriodByBarCurrent(i,InpUsedSymbols,InpPeriod); if(index<0) continue; engine.BufferSetDataLine(0,i,buff_calc.GetData(index),color_index); //--- Calculate the candle buffer engine.BufferSetDataCandles(0,i,bar.Open(),bar.High(),bar.Low(),bar.Close(),color_index); } //--- return value of prev_calculated for next call
完全な指標コードは、以下に添付されているファイルで提供されます。
GBPUSD M30と、期間が14でシフトが0の単純な終値による移動平均を指定してEURUSD M15で指標を起動します。
比較のために、同じパラメータを持つ移動平均指標を使用したGBPUSDチャートを開きました。
テスト: 複数銘柄・複数期間MACD
それでは、複数銘柄・複数期間MACDを作成しましょう。新しく作成した指標をTestDoEasyPart46_2.mq5として保存します。
MACDの入力と、その計算と表示に必要なすべてのバッファを設定します。現在のチャートにMACDを表示するための2つ(ヒストグラムとライン)の描画バッファ、および設定で指定された銘柄/期間から取得したヒストグラムデータとMACDシグナル線を格納するための2つの計算バッファが必要になります。
すべてのアクションとロジックの詳細はコードコメントで説明してみたので、ここでは前の指標と比較した基本的な変更についてのみ説明します。
//+------------------------------------------------------------------+ //| TestDoEasyPart46_2.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 6 #property indicator_plots 2 //--- classes //--- enums //--- defines //--- structures //--- input variables sinput string InpUsedSymbols = "GBPUSD"; // Used symbol (one only) sinput ENUM_TIMEFRAMES InpPeriod = PERIOD_M30; // Used chart period //--- sinput uint InpPeriodFastEMA = 12; // MACD Fast EMA Period sinput uint InpPeriodSlowEMA = 26; // MACD Slow EMA Period sinput uint InpPeriodSignalMA = 9; // MACD Signal MA Period sinput ENUM_APPLIED_PRICE InpPriceMACD = PRICE_CLOSE; // MA Applied Price //--- sinput bool InpUseSounds = true; // Use sounds //--- indicator buffers CArrayObj *list_buffers; // Pointer to the buffer object list //--- 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 int handle_macd; // МАCD handle int fast_ema_period; // Fast EMA calculation period int slow_ema_period; // Slow EMA calculation period int signal_period; // MACD signal line calculation period //+------------------------------------------------------------------+ //| 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(); IndicatorSetInteger(INDICATOR_DIGITS,(int)SymbolInfoInteger(InpUsedSymbols,SYMBOL_DIGITS)+1); //--- 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 MACD engine.BufferCreateHistogram(); // 2 arrays engine.BufferCreateLine(); // 2 arrays engine.BufferCreateCalculate(); // 1 array for MACD histogram data from the specified symbol/period engine.BufferCreateCalculate(); // 1 array for MACD signal line from the specified symbol/period //--- Check the number of buffers specified in the 'properties' block if(engine.BuffersPropertyPlotsTotal()!=indicator_plots) Alert(TextByLanguage("Внимание! Значение \"indicator_plots\" должно быть ","Attention! Value of \"indicator_plots\" should be "),engine.BuffersPropertyPlotsTotal()); if(engine.BuffersPropertyBuffersTotal()!=indicator_buffers) Alert(TextByLanguage("Внимание! Значение \"indicator_buffers\" должно быть ","Attention! Value of \"indicator_buffers\" should be "),engine.BuffersPropertyBuffersTotal()); //--- Create the color array and set non-default colors to all buffers within the collection color array_colors[]={clrDodgerBlue,clrRed,clrGray}; engine.BuffersSetColors(array_colors); //--- Set МАCD calculation periods fast_ema_period=int(InpPeriodFastEMA<1 ? 1 : InpPeriodFastEMA); slow_ema_period=int(InpPeriodSlowEMA<1 ? 1 : InpPeriodSlowEMA); signal_period=int(InpPeriodSignalMA<1 ? 1 : InpPeriodSignalMA); //--- Get the histogram buffer (the first drawn buffer) //--- It has the index of 0 considering that the starting point is zero CBufferHistogram *buff_hist=engine.GetBufferHistogram(0); if(buff_hist!=NULL) { //--- Set the line width for the histogram buff_hist.SetWidth(3); //--- Set the graphical series description for the histogram string label="MACD ("+(string)fast_ema_period+","+(string)slow_ema_period+","+(string)signal_period+")"; buff_hist.SetLabel(label); //--- and set display in the data window for the buffer //--- and also a chart period and symbol selected in the settings buff_hist.SetShowData(true); buff_hist.SetTimeframe(InpPeriod); buff_hist.SetSymbol(InpUsedSymbols); } //--- Get the signal line buffer (the first drawn buffer) //--- It has the index of 0 considering that the starting point is zero CBufferLine *buff_line=engine.GetBufferLine(0); if(buff_line!=NULL) { //--- Set the signal line width buff_line.SetWidth(1); //--- Set the graphical series description for the signal line string label="Signal"; buff_line.SetLabel(label); //--- and set display in the data window for the buffer //--- and also a chart period and symbol selected in the settings buff_line.SetShowData(true); buff_line.SetTimeframe(InpPeriod); buff_line.SetSymbol(InpUsedSymbols); } //--- Get the first calculated buffer //--- It has the index of 0 considering that the starting point is zero CBufferCalculate *buff_calc=engine.GetBufferCalculate(0); if(buff_calc!=NULL) { //--- Set the description of the first calculated buffer as the "MACD histogram temporary array"" buff_calc.SetLabel("MACD_HIST_TMP"); //--- and set a chart period and symbol selected in the settings for it buff_calc.SetTimeframe(InpPeriod); buff_calc.SetSymbol(InpUsedSymbols); } //--- Get the second calculated buffer //--- It has the index of 1 considering that the starting point is zero buff_calc=engine.GetBufferCalculate(1); if(buff_calc!=NULL) { //--- Set the description of the second calculated buffer as the "MACD signal line temporary array"" buff_calc.SetLabel("MACD_SIGN_TMP"); //--- and set a chart period and symbol selected in the settings for it buff_calc.SetTimeframe(InpPeriod); buff_calc.SetSymbol(InpUsedSymbols); } //--- Display short descriptions of created indicator buffers engine.BuffersPrintShort(); //--- Create МАCD handle handle_macd=iMACD(InpUsedSymbols,InpPeriod,fast_ema_period,slow_ema_period,signal_period,InpPriceMACD); if(handle_macd==INVALID_HANDLE) return INIT_FAILED; //--- IndicatorSetString(INDICATOR_SHORTNAME,InpUsedSymbols+" "+TimeframeDescription(InpPeriod)+" MACD("+(string)fast_ema_period+","+(string)slow_ema_period+","+(string)signal_period+")"); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Remove indicator graphical objects by an object name prefix ObjectsDeleteAll(0,prefix); Comment(""); } //+------------------------------------------------------------------+ //| 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 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(); } //--- Prepare data int total_copy=(limit<2 ? 1 : limit); //--- Get the first calculated buffer by its number CBufferCalculate *buff_calc_hist=engine.GetBufferCalculate(0); //--- Fill in the first calculated buffer with MACD histogram data int copied=buff_calc_hist.FillAsSeries(handle_macd,0,0,total_copy); if(copied<total_copy) return 0; //--- Get the second calculated buffer by its number CBufferCalculate *buff_calc_sig=engine.GetBufferCalculate(1); //--- Fill in the second calculated buffer with MACD signal line data copied=buff_calc_sig.FillAsSeries(handle_macd,1,0,total_copy); if(copied<total_copy) return 0; //--- Calculate the indicator CBar *bar=NULL; // Bar object for defining the candle direction uchar color_index=0; // Color index to be set for the buffer depending on the candle direction //--- Main calculation loop of the indicator for(int i=limit; i>WRONG_VALUE && !IsStopped(); i--) { //--- Clear the current bar of all created buffers engine.BufferHistogramClear(0,0); engine.BufferLineClear(0,0); //--- Get the timeseries bar corresponding to the loop index time on the chart period specified in the settings bar=engine.SeriesGetBar(InpUsedSymbols,InpPeriod,time[i]); if(bar==NULL) continue; //--- Calculate the color index depending on the candle direction on the timeframe specified in the settings color_index=(bar.TypeBody()==BAR_BODY_TYPE_BULLISH ? 0 : bar.TypeBody()==BAR_BODY_TYPE_BEARISH ? 1 : 2); //--- Calculate the MACD histogram buffer int index=engine.IndexBarPeriodByBarCurrent(i,InpUsedSymbols,InpPeriod); if(index<0) continue; engine.BufferSetDataHistogram(0,i,buff_calc_hist.GetData(index),color_index); //--- Calculate MACD signal line buffer engine.BufferSetDataLine(0,i,buff_calc_sig.GetData(index),color_index); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
各バーのヒストグラムとシグナル線の列の色は、MACDが基づく銘柄/期間ローソク足の方向に対応しています。
指標は、GBPUSDM30に基づくMACDのデフォルト設定でEURUSDM15で起動されます。より明確にするために、同じパラメータを持つ標準MACDを使用したGBPUSDM30チャートを開きます。
次の段階
次の記事では、複数銘柄・複数期間標準指標の作成を容易にする機能をライブラリに追加します。
現在のバージョンのライブラリのすべてのファイルは、テスト用EAファイルと一緒に以下に添付されているので、テストするにはダウンロードしてください。
質問、コメント、提案はコメント欄にお願いします。テスト指標は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部): 複数期間指標バッファ
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/8115
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索