
DoEasyライブラリの時系列(第58部): 指標バッファデータの時系列
目次
概念
時系列の操作に関するトピックの結論として、指標バッファに格納されているストレージ、検索、およびデータの並べ替えを整理します。これにより、プログラムでライブラリベースで作成される指標の値に基づいて分析をさらに実行できます。指標データの時系列構築の概念は、時系列コレクション構築の概念に似ています。指標ごとに、すべてのバッファのすべてのデータを格納するリストを作成します。指標バッファリストのデータ量は、指標が計算された対応する時系列のデータ量に対応します。ライブラリのすべてのコレクションクラスの一般的な概念により、対応するコレクションで必要なデータを簡単に見つけることができます。それぞれ、今日作成されたクラスでも同じことが可能です。
さらに、ライブラリに保存されているすべてのデータを分析するためのクラスを作成します。これは、ライブラリコレクションのデータを全範囲で比較して統計調査を実行するための非常に柔軟なツールとなります。
ライブラリクラスの改善
指標バッファデータのコレクションクラスは、現在のバーで作成されたすべての指標のデータを自動的に更新します。新しいバーが表示されると、指標バッファの新しいデータが作成され、コレクションに配置されます。
NewBarObj.mqhファイルには、時系列コレクション用に作成された「新規バー」クラスがすでにあります。
これは、ライブラリディレクトリ\MQL5\Include\DoEasyPart57\Objects\Series\の時系列クラスフォルダに保存されています。
指標バッファデータのコレクションクラスの新規バーも追跡する必要があります。
したがって、ライブラリのサービス関数とクラスのフォルダ\MQL5\Include\DoEasy\Services\に移動します。
以前の場所にあるファイルを削除します。
「Timeseries」クラスは「新規バー」クラスを使用するため、「Timeseries」クラスファイル\MQL5\Include\DoEasy\Objects\Series\SeriesDE.mqhのインクルードファイルブロックでこのクラスへの古いパスを変更する必要があります。
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\..\Services\Select.mqh" #include "NewBarObj.mqh" #include "Bar.mqh" //+------------------------------------------------------------------+
新しいパスは以下の通りです。
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\..\Services\Select.mqh" #include "..\..\Services\NewBarObj.mqh" #include "Bar.mqh" //+------------------------------------------------------------------+
新しいメッセージインデックスを\MQL5\Include\DoEasy\Data.mqhに追加します。
MSG_LIB_SYS_ERROR_FAILED_GET_PRICE_ASK, // Failed to get Ask price. Error MSG_LIB_SYS_ERROR_FAILED_GET_PRICE_BID, // Failed to get Bid price. Error MSG_LIB_SYS_ERROR_FAILED_GET_TIME, // Failed to get time. Error MSG_LIB_SYS_ERROR_FAILED_OPEN_BUY, // Failed to open Buy position. Error
...
//--- CDataInd MSG_LIB_TEXT_IND_DATA_IND_BUFFER_NUM, // Indicator buffer number MSG_LIB_TEXT_IND_DATA_BUFFER_VALUE, // Indicator buffer value //--- CSeriesDataInd MSG_LIB_TEXT_METHOD_NOT_FOR_INDICATORS, // The method is not intended to handle indicator programs MSG_LIB_TEXT_IND_DATA_FAILED_GET_SERIES_DATA, // Failed to get indicator data timeseries MSG_LIB_TEXT_IND_DATA_FAILED_GET_CURRENT_DATA, // Failed to get current data of indicator buffer MSG_LIB_SYS_FAILED_CREATE_IND_DATA_OBJ, // Failed to create indicator data object MSG_LIB_TEXT_IND_DATA_FAILED_ADD_TO_LIST, // Failed to add indicator data object to list }; //+------------------------------------------------------------------+
新しく追加したインデックスに対応するメッセージテキストも追加します。
{"Could not get Ask price. Error "}, {"Could not get Bid price. Error "}, {"Could not get time. Error "}, {"Failed to open a Buy position. Error "},
...
{"Indicator buffer number"}, {"Indicator buffer value"}, {"The method is not intended for working with indicator programs"}, {"Failed to get indicator data timeseries"}, {"Failed to get the current data of the indicator buffer"}, {"Failed to create indicator data object"}, {"Failed to add indicator data object to the list"}, }; //+---------------------------------------------------------------------+
今日は新しいコレクションを作成するので、コレクションIDを設定しましょう。それとは別に、指標バッファデータはタイマーで自動的に更新されるため、新しいコレクションタイマーのパラメータの定数を作成します。
新しいデータをファイル\MQL5\Include\DoEasy\Defines.mqhに追加します。
//--- Parameters of the timeseries collection timer #define COLLECTION_TS_PAUSE (64) // Timeseries collection timer pause in milliseconds #define COLLECTION_TS_COUNTER_STEP (16) // Timeseries timer counter increment #define COLLECTION_TS_COUNTER_ID (6) // Timeseries timer counter ID //--- Parameters of the timer of indicator data timeseries collection #define COLLECTION_IND_TS_PAUSE (64) // Pause of the timer of indicator data timeseries collection in milliseconds #define COLLECTION_IND_TS_COUNTER_STEP (16) // Increment of indicator data timeseries timer counter #define COLLECTION_IND_TS_COUNTER_ID (7) // ID of indicator data timeseries timer counter //--- Collection list IDs #define COLLECTION_HISTORY_ID (0x777A) // Historical collection list ID #define COLLECTION_MARKET_ID (0x777B) // Market collection list ID #define COLLECTION_EVENTS_ID (0x777C) // Event collection list ID #define COLLECTION_ACCOUNT_ID (0x777D) // Account collection list ID #define COLLECTION_SYMBOLS_ID (0x777E) // Symbol collection list ID #define COLLECTION_SERIES_ID (0x777F) // Timeseries collection list ID #define COLLECTION_BUFFERS_ID (0x7780) // Indicator buffer collection list ID #define COLLECTION_INDICATORS_ID (0x7781) // Indicator collection list ID #define COLLECTION_INDICATORS_DATA_ID (0x7782) // Indicator data collection list ID
コレクション内の指標バッファデータを検索するには、さらに指標ハンドルによってデータを検索する必要があります(データはこの指標に関連付けられ、データを検索する場合、指標との関連付けの正確なIDを使用しないのは奇妙なためです)。
指標データの整数プロパティに新しいプロパティを追加し、プロパティ数を5から6に増やします。
//+------------------------------------------------------------------+ //| Integer properties of indicator data | //+------------------------------------------------------------------+ enum ENUM_IND_DATA_PROP_INTEGER { IND_DATA_PROP_TIME = 0, // Start time of indicator data bar period IND_DATA_PROP_PERIOD, // Indicator data period (timeframe) IND_DATA_PROP_INDICATOR_TYPE, // Indicator type IND_DATA_PROP_IND_BUFFER_NUM, // Indicator data buffer number IND_DATA_PROP_IND_ID, // Indicator ID IND_DATA_PROP_IND_HANDLE, // Indicator handle }; #define IND_DATA_PROP_INTEGER_TOTAL (6) // Total number of indicator data integer properties #define IND_DATA_PROP_INTEGER_SKIP (0) // Number of indicator data properties not used in sorting //+------------------------------------------------------------------+
それぞれ、新しい整数プロパティを追加したので、可能な並べ替え条件のリストに追加して、このプロパティによって検索および並べ替えできるようにします。
//+------------------------------------------------------------------+ //| Possible criteria for indicator data sorting | //+------------------------------------------------------------------+ #define FIRST_IND_DATA_DBL_PROP (IND_DATA_PROP_INTEGER_TOTAL-IND_DATA_PROP_INTEGER_SKIP) #define FIRST_IND_DATA_STR_PROP (IND_DATA_PROP_INTEGER_TOTAL-IND_DATA_PROP_INTEGER_SKIP+IND_DATA_PROP_DOUBLE_TOTAL-IND_DATA_PROP_DOUBLE_SKIP) enum ENUM_SORT_IND_DATA_MODE { //--- Sort by integer properties SORT_BY_IND_DATA_TIME = 0, // Sort by bar period start time of indicator data SORT_BY_IND_DATA_PERIOD, // Sort by indicator data period (timeframe) SORT_BY_IND_DATA_INDICATOR_TYPE, // Sort by indicator type SORT_BY_IND_DATA_IND_BUFFER_NUM, // Sort by indicator data buffer number SORT_BY_IND_DATA_IND_ID, // Sort by indicator ID SORT_BY_IND_DATA_IND_HANDLE, // Sort by indicator handle //--- Sort by real properties SORT_BY_IND_DATA_BUFFER_VALUE = FIRST_IND_DATA_DBL_PROP, // Sort by indicator data value //--- Sort by string properties SORT_BY_IND_DATA_SYMBOL = FIRST_IND_DATA_STR_PROP, // Sort by indicator data symbol SORT_BY_IND_DATA_IND_NAME, // Sort by indicator name SORT_BY_IND_DATA_IND_SHORTNAME, // Sort by indicator short name }; //+------------------------------------------------------------------+
コレクションに保存されている指標バッファデータは、前の記事で作成された指標バッファデータクラスによって表示されます。
次に、それに(ファイル\MQL5\Include\DoEasy\Objects\Indicators\DataInd.mqhで)指標ハンドルのインストールメソッドを追加します。このバッファのデータはこのクラスのオブジェクトに保存されます。また、クラスコンストラクタに、指標ハンドルパラメータの受け渡しとそのバッファの値を追加します。これにより、オブジェクトの作成中にこれらのパラメータの値を設定できるようになります。
//--- Set (1) symbol, timeframe and time for the object, (2) indicator type, (3) number of buffers, (4) number of data buffer, //--- (5) ID, (6) handle, (7) data value, (8) name, (9) indicator short name void SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime time); void SetIndicatorType(const ENUM_INDICATOR type) { this.SetProperty(IND_DATA_PROP_INDICATOR_TYPE,type); } void SetBufferNum(const int num) { this.SetProperty(IND_DATA_PROP_IND_BUFFER_NUM,num); } void SetIndicatorID(const int id) { this.SetProperty(IND_DATA_PROP_IND_ID,id); } void SetIndicatorHandle(const int handle) { this.SetProperty(IND_DATA_PROP_IND_HANDLE,handle); } void SetBufferValue(const double value) { this.SetProperty(IND_DATA_PROP_BUFFER_VALUE,value); } void SetIndicatorName(const string name) { this.SetProperty(IND_DATA_PROP_IND_NAME,name); } void SetIndicatorShortname(const string shortname) { this.SetProperty(IND_DATA_PROP_IND_SHORTNAME,shortname); } //--- Compare CDataInd objects with each other by all possible properties (for sorting the lists by a specified property of data object ) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CDataInd objects with each other by all properties (to search equal objects) bool IsEqual(CDataInd* compared_data) const; //--- Constructors CDataInd(){;} CDataInd(const ENUM_INDICATOR ind_type, const int ind_handle, const int ind_id, const int buffer_num, const string symbol, const ENUM_TIMEFRAMES timeframe, const datetime time, const double value);
オブジェクトプロパティへの簡単なアクセスのためのメソッドのブロックに指標ハンドルを返すメソッドを追加し、指標バッファデータの値を返すメソッドの名前を変更します(旧称PriceValue())。
//+------------------------------------------------------------------+ //| Methods of simplified access to object properties | //+------------------------------------------------------------------+ //--- Return (1) bar period start time, (2) timeframe, (3) indicator type, //--- (4) number of buffers, (5) buffer number, (6) ID, (7) indicator handle datetime Time(void) const { return (datetime)this.GetProperty(IND_DATA_PROP_TIME); } ENUM_TIMEFRAMES Timeframe(void) const { return (ENUM_TIMEFRAMES)this.GetProperty(IND_DATA_PROP_PERIOD); } ENUM_INDICATOR IndicatorType(void) const { return (ENUM_INDICATOR)this.GetProperty(IND_DATA_PROP_INDICATOR_TYPE); } int BufferNum(void) const { return (ENUM_INDICATOR)this.GetProperty(IND_DATA_PROP_IND_BUFFER_NUM); } int IndicatorID(void) const { return (ENUM_INDICATOR)this.GetProperty(IND_DATA_PROP_IND_ID); } int IndicatorHandle(void) const { return (ENUM_INDICATOR)this.GetProperty(IND_DATA_PROP_IND_HANDLE); } //--- Return the value of indicator buffer data double BufferValue(void) const { return this.GetProperty(IND_DATA_PROP_BUFFER_VALUE); }
クラスコンストラクタの本体で、新しいオブジェクトを作成するときに渡される新しいプロパティの値を設定します。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CDataInd::CDataInd(const ENUM_INDICATOR ind_type, const int ind_handle, const int ind_id, const int buffer_num, const string symbol, const ENUM_TIMEFRAMES timeframe, const datetime time, const double value) { this.m_type=COLLECTION_INDICATORS_DATA_ID; this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS)+1; this.m_period_description=TimeframeDescription(timeframe); this.SetSymbolPeriod(symbol,timeframe,time); this.SetIndicatorType(ind_type); this.SetIndicatorHandle(ind_handle); this.SetBufferNum(buffer_num); this.SetIndicatorID(ind_id); this.SetBufferValue(value); } //+------------------------------------------------------------------+
整数プロパティの説明を返すメソッドに指標ハンドルの説明を表示するためのコードブロックを追加します。
//+------------------------------------------------------------------+ //| Return description of object's integer property | //+------------------------------------------------------------------+ string CDataInd::GetPropertyDescription(ENUM_IND_DATA_PROP_INTEGER property) { return ( property==IND_DATA_PROP_TIME ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS) ) : property==IND_DATA_PROP_PERIOD ? CMessage::Text(MSG_LIB_TEXT_IND_TEXT_TIMEFRAME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.m_period_description ) : property==IND_DATA_PROP_INDICATOR_TYPE ? CMessage::Text(MSG_LIB_TEXT_IND_TEXT_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.IndicatorTypeDescription() ) : property==IND_DATA_PROP_IND_BUFFER_NUM ? CMessage::Text(MSG_LIB_TEXT_IND_DATA_IND_BUFFER_NUM)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==IND_DATA_PROP_IND_ID ? CMessage::Text(MSG_LIB_TEXT_IND_TEXT_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==IND_DATA_PROP_IND_HANDLE ? CMessage::Text(MSG_LIB_TEXT_IND_TEXT_HANDLE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : "" ); } //+------------------------------------------------------------------+
指標バッファデータの時系列クラス
ライブラリ内のすべてのコレクションクラスは、標準ライブラリのCObjectクラスとその子孫のインスタンスへのポインタの動的配列のクラスに基づいて作成されます。指標バッファデータのコレクションクラスは除外されません。
このクラスを使用すると、CArrayObjオブジェクトのリストに1つの指標のバッファデータのオブジェクトを格納して、時系列バーの開いた時間に対応する指標バッファのデータを取得できます。当然、リストは、リストに格納されているオブジェクトのプロパティによって自動的に更新、検索、および並べ替えることができます。
フォルダ\MQL5\Include\DoEasy\Objects\Indicators\で、新しいクラスCSeriesDataIndをファイルSeriesDataInd.mqhに作成します。
クラスオブジェクトは、CBaseObjライブラリのすべてのオブジェクトの基本オブジェクトから派生している必要があります。
すべての変数とメソッドを使用してクラス本体を分析します。
//+------------------------------------------------------------------+ //| SeriesDataInd.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\..\Services\Select.mqh" #include "..\..\Services\NewBarObj.mqh" #include "DataInd.mqh" //+------------------------------------------------------------------+ //| “Indicator data list” class | //+------------------------------------------------------------------+ class CSeriesDataInd : public CBaseObj { private: ENUM_TIMEFRAMES m_timeframe; // Timeframe ENUM_INDICATOR m_ind_type; // Indicator type string m_symbol; // Symbol string m_period_description; // Timeframe string description int m_ind_handle; // Indicator handle int m_ind_id; // Indicator ID int m_buffers_total; // Number of indicator buffers uint m_amount; // Amount of applied timeseries data uint m_required; // Required amount of applied timeseries data uint m_bars; // Number of bars in history by symbol and timeframe bool m_sync; // Synchronized data flag CArrayObj m_list_data; // Indicator data list CNewBarObj m_new_bar_obj; // "New bar" object //--- Create a new indicator data object, return pointer to it CDataInd *CreateNewDataInd(const int buffer_num,const datetime time,const double value); public: //--- Return (1) oneself, (2) the full list of indicator data CSeriesDataInd *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list_data; } //--- Return the list of indicator data by selected (1) double, (2) integer and (3) string property fitting a compared condition CArrayObj *GetList(ENUM_IND_DATA_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByIndicatorDataProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_IND_DATA_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByIndicatorDataProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_IND_DATA_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByIndicatorDataProperty(this.GetList(),property,value,mode); } //--- Return indicator data object by (1) time, (2) bar number and buffer number CDataInd *GetIndDataByTime(const int buffer_num,const datetime time); CDataInd *GetIndDataByBar(const int buffer_num,const uint shift); //--- Set (1) symbol, (2) timeframe, (3) symbol and timeframe, (4) amount of applied timeseries data, //--- (5) handle, (6) ID, (7) number of indicator buffers void SetSymbol(const string symbol); void SetTimeframe(const ENUM_TIMEFRAMES timeframe); void SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe); bool SetRequiredUsedData(const uint required); void SetIndHandle(const int handle) { this.m_ind_handle=handle; } void SetIndID(const int id) { this.m_ind_id=id; } void SetIndBuffersTotal(const int total) { this.m_buffers_total=total; } //--- Return (1) symbol, (2) timeframe, number of (3) used and (4) requested timeseries data, //--- (5) number of bars in timeseries, (6) handle, (7) ID, (8) number of indicator buffers string Symbol(void) const { return this.m_symbol; } ENUM_TIMEFRAMES Timeframe(void) const { return this.m_timeframe; } ulong AvailableUsedData(void) const { return this.m_amount; } ulong RequiredUsedData(void) const { return this.m_required; } ulong Bars(void) const { return this.m_bars; } int IndHandle(void) const { return this.m_ind_handle; } int IndID(void) const { return this.m_ind_id; } int IndBuffersTotal(void) const { return this.m_buffers_total; } bool IsNewBar(const datetime time) { return this.m_new_bar_obj.IsNewBar(time); } bool IsNewBarManual(const datetime time) { return this.m_new_bar_obj.IsNewBarManual(time); } //--- Return real list size int DataTotal(void) const { return this.m_list_data.Total(); } //--- Save the new bar time during the manual time management void SaveNewBarTime(const datetime time) { this.m_new_bar_obj.SaveNewBarTime(time); } //--- (1) Create, (2) update the indicator data list int Create(const uint required=0); void Refresh(void); //--- Return data of specified indicator buffer by (1) open time, (2) bar index double BufferValue(const int buffer_num,const datetime time); double BufferValue(const int buffer_num,const uint shift); //--- Constructors CSeriesDataInd(void){;} CSeriesDataInd(const int handle, const ENUM_INDICATOR ind_type, const int ind_id, const int buffers_total, const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0); }; //+------------------------------------------------------------------+
オブジェクトには、ライブラリのすべてのオブジェクトに固有の既知のメソッドと、オブジェクトパラメータを格納するためのクラスメンバー変数のセットが表示されます。
クラスのpublicセクションで、オブジェクトプロパティへのアクセスを簡素化し、外部からインストールするためのメソッドを宣言します。
クラスメソッドの実装を見てみましょう。
パラメトリッククラスコンストラクタには、オブジェクトの作成に必要なプロパティのすべての値が渡されます。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CSeriesDataInd::CSeriesDataInd(const int handle, const ENUM_INDICATOR ind_type, const int ind_id, const int buffers_total, const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0) : m_bars(0), m_amount(0),m_required(0),m_sync(false) { //--- To the object set indicator data collection list ID this.m_type=COLLECTION_INDICATORS_DATA_ID; //--- Clear the list and set for it the flag of the list sorted by time this.m_list_data.Clear(); this.m_list_data.Sort(SORT_BY_IND_DATA_TIME); //--- Set values for all object variables this.SetSymbolPeriod(symbol,timeframe); this.m_sync=this.SetRequiredUsedData(required); this.m_period_description=TimeframeDescription(this.m_timeframe); this.m_ind_handle=handle; this.m_ind_type=ind_type; this.m_ind_id=ind_id; this.m_buffers_total=buffers_total; } //+------------------------------------------------------------------+
指標バッファデータの時系列コレクションのオブジェクトセットIDについて、CDataIndクラスのオブジェクトが格納されるリストをクリアし、並び替え済みリストのフラグをリストに設定します。これらのオブジェクトに最適な並べ替えモードは、時間による並べ替えです。これは、リスト内のオブジェクトの場所と、指標の物理バッファ内のデータの場所が確実に一致するようにします。
銘柄と時間枠を設定するメソッドにはコメントはいりません。
//+------------------------------------------------------------------+ //| Set a symbol | //+------------------------------------------------------------------+ void CSeriesDataInd::SetSymbol(const string symbol) { if(this.m_symbol==symbol) return; this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); } //+------------------------------------------------------------------+ //| Set a timeframe | //+------------------------------------------------------------------+ void CSeriesDataInd::SetTimeframe(const ENUM_TIMEFRAMES timeframe) { if(this.m_timeframe==timeframe) return; this.m_timeframe=(timeframe==PERIOD_CURRENT ? (ENUM_TIMEFRAMES)::Period() : timeframe); } //+------------------------------------------------------------------+ //| Set a symbol and timeframe | //+------------------------------------------------------------------+ void CSeriesDataInd::SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe) { this.SetSymbol(symbol); this.SetTimeframe(timeframe); } //+------------------------------------------------------------------+
以下は、指標バッファデータの必要量を設定するメソッドです。
//+------------------------------------------------------------------+ //| Set the amount of necessary data | //+------------------------------------------------------------------+ bool CSeriesDataInd::SetRequiredUsedData(const uint required) { //--- If this is indicator program - report and leave if(this.m_program==PROGRAM_INDICATOR) { ::Print(CMessage::Text(MSG_LIB_TEXT_METHOD_NOT_FOR_INDICATORS)); return false; } //--- Set the necessary amount of data - if less than 1 is passed use by default (1000), or else - the passed value this.m_required=(required<1 ? SERIES_DEFAULT_BARS_COUNT : required); //--- Launch download of historical data (relevant for the “cold” start) datetime array[1]; ::CopyTime(this.m_symbol,this.m_timeframe,0,1,array); //--- Set the number of available timeseries bars this.m_bars=(uint)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_BARS_COUNT); //--- If succeeded to set the number of available history bars, set the amount of data in the list: if(this.m_bars>0) { //--- if zero 'required' value is passed, //--- use either the default value (1000 bars) or the number of available history bars - the least one of them //--- if non-zero 'required' value is passed, //--- use either the 'required' value or the number of available history bars - the least one of them this.m_amount=(required==0 ? ::fmin(SERIES_DEFAULT_BARS_COUNT,this.m_bars) : ::fmin(required,this.m_bars)); return true; } return false; } //+------------------------------------------------------------------+
指標内で作業するには他のクラスがすでに利用可能であるため、開始されたプログラムのタイプが一度にチェックされます。指標の場合は、そのメッセージが表示され、falseが返されます。第35部で時系列クラスが作成されたときに、同様のメソッドの作業が分析されました。
以下は、新しい指標データオブジェクトを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create a new indicator data object, return the pointer | //+------------------------------------------------------------------+ CDataInd* CSeriesDataInd::CreateNewDataInd(const int buffer_num,const datetime time,const double value) { CDataInd* data_ind=new CDataInd(this.m_ind_type,this.m_ind_handle,this.m_ind_id,buffer_num,this.m_symbol,this.m_timeframe,time,value); return data_ind; } //+------------------------------------------------------------------+
CDataIndクラスの新しいオブジェクトを作成し、新しく作成されたオブジェクトへのポインタ、または、オブジェクトが作成されていない場合はNULLを返します。
以下は、指標データの時系列リストを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create indicator data timeseries list | //+------------------------------------------------------------------+ int CSeriesDataInd::Create(const uint required=0) { //--- If this is indicator program - report and leave if(this.m_program==PROGRAM_INDICATOR) { ::Print(CMessage::Text(MSG_LIB_TEXT_METHOD_NOT_FOR_INDICATORS)); return false; } //--- If the required history depth is not set for the list yet, //--- display the appropriate message and return zero, if(this.m_amount==0) { ::Print(DFUN,this.m_symbol," ",TimeframeDescription(this.m_timeframe),": ",CMessage::Text(MSG_LIB_TEXT_BAR_TEXT_FIRS_SET_AMOUNT_DATA)); return 0; } //--- otherwise, if the passed 'required' value exceeds zero and is not equal to the one already set, //--- while the passed ‘required’ value is less than the available bar number, //--- set the new value of the required history depth for the list else if(required>0 && this.m_amount!=required && required<this.m_bars) { //--- If failed to set a new value, return zero if(!this.SetRequiredUsedData(required)) return 0; } //--- For the data[] array we are to receive historical data to, //--- set the flag of direction like in the timeseries, //--- clear the list of indicator data objects and set the flag of sorting by timeseries bar time double data[]; ::ArraySetAsSeries(data,true); this.m_list_data.Clear(); this.m_list_data.Sort(SORT_BY_IND_DATA_TIME); ::ResetLastError(); int err=ERR_SUCCESS; //--- In a loop by the number of indicator data buffers for(int i=0;i<this.m_buffers_total;i++) { //--- Get historical data of i buffer of indicator to data[] array starting from the current bar in the amount of m_amount, //--- if failed to get data, display the appropriate message and return zero int copied=::CopyBuffer(this.m_ind_handle,i,0,this.m_amount,data); if(copied<1) { err=::GetLastError(); ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_IND_DATA_FAILED_GET_SERIES_DATA)," ",this.m_symbol," ",TimeframeDescription(this.m_timeframe),". ", CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(err),CMessage::Retcode(err)); return 0; } //--- In the loop by amount of required data for(int j=0;j<(int)this.m_amount;j++) { //--- Get time of j bar ::ResetLastError(); datetime time=::iTime(this.m_symbol,this.m_timeframe,j); //--- If failed to get time //--- display the appropriate message with the error description in the journal and move on to the next loop iteration by data (j) if(time==0) { err=::GetLastError(); ::Print( DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TIME),CMessage::Text(err),CMessage::Retcode(err)); continue; } //--- If failed to create a new indicator data object from i buffer //--- display the appropriate message with the error description in the journal and move on to the next loop iteration by data (j) CDataInd* data_ind=CreateNewDataInd(i,time,data[j]); if(data_ind==NULL) { err=::GetLastError(); ::Print ( DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_IND_DATA_OBJ)," ",::TimeToString(time),". ", CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(err),CMessage::Retcode(err) ); continue; } //--- If failed to add a new indicator data object to list //--- display the appropriate message with the error description in the journal, remove data object //--- and move on to the next loop iteration by data if(!this.m_list_data.Add(data_ind)) { err=::GetLastError(); ::Print ( DFUN,CMessage::Text(MSG_LIB_TEXT_IND_DATA_FAILED_ADD_TO_LIST)," ",::TimeToString(time),". ", CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(err),CMessage::Retcode(err) ); delete data_ind; continue; } } } //--- Return the size of the created list of indicator data objects return this.m_list_data.Total(); } //+------------------------------------------------------------------+
すべてのメソッドロジックは、そのコードに詳細に説明されています。メソッドは、すべての指標バッファからのデータを配列にコピーします。これらのデータで新しい指標データオブジェクトCDataIndを作成し、コレクションリストに配置します。
以下は、指標データコレクションリストを更新するメソッドです。
//+------------------------------------------------------------------+ //| Update indicator data timeseries list and data | //+------------------------------------------------------------------+ void CSeriesDataInd::Refresh(void) { //--- If this is indicator program - report and leave if(this.m_program==PROGRAM_INDICATOR) { ::Print(CMessage::Text(MSG_LIB_TEXT_METHOD_NOT_FOR_INDICATORS)); return; } //--- If indicator data timeseries is not used, exit if(!this.m_available) return; double data[1]; //--- Get the current bar time int err=ERR_SUCCESS; ::ResetLastError(); datetime time=::iTime(this.m_symbol,this.m_timeframe,0); //--- If failed to get time //--- display the appropriate message with the error description in the journal and exit if(time==0) { err=::GetLastError(); ::Print( DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TIME),CMessage::Text(err),CMessage::Retcode(err)); return; } //--- Set the flag of sorting the data list by time this.m_list_data.Sort(SORT_BY_IND_DATA_TIME); //--- If a new bar is present on a symbol and period if(this.IsNewBarManual(time)) { //--- create new indicator data objects by the number of buffers and add them to the list end for(int i=0;i<this.m_buffers_total;i++) { //--- Get data of the current bar of indicator’s i buffer to data[] array, //--- if failed to get data, display the appropriate message and exit int copied=::CopyBuffer(this.m_ind_handle,i,0,1,data); if(copied<1) { err=::GetLastError(); ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_IND_DATA_FAILED_GET_CURRENT_DATA)," ",this.m_symbol," ",TimeframeDescription(this.m_timeframe),". ", CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(err),CMessage::Retcode(err)); return; } //--- Create a new data object of indicator’s i buffer CDataInd* data_ind=CreateNewDataInd(i,time,data[0]); if(data_ind==NULL) return; //--- If the created object was not added to the list - remove this object and exit from the method if(!this.m_list_data.InsertSort(data_ind)) { delete data_ind; return; } } //--- if the size of indicator data timeseries has ecxeeded the requested number of bars, remove the earliest data object if(this.m_list_data.Total()>(int)this.m_required) this.m_list_data.Delete(0); //--- save the new bar time as the previous one for the subsequent new bar check this.SaveNewBarTime(time); } //--- Get the list of indicator data objects by the time of current bar start CArrayObj *list=CSelect::ByIndicatorDataProperty(this.GetList(),IND_DATA_PROP_TIME,time,EQUAL); //--- In the loop, by the number of indicator buffers get indicator data objects from the list by loop index for(int i=0;i<this.m_buffers_total;i++) { //--- If failed to get object from the list - exit CDataInd *data_ind=this.GetIndDataByTime(i,time); if(data_ind==NULL) return; //--- Copy data of indicator’s i buffer from current bar int copied=::CopyBuffer(this.m_ind_handle,i,0,1,data); if(copied<1) { err=::GetLastError(); ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_IND_DATA_FAILED_GET_CURRENT_DATA)," ",this.m_symbol," ",TimeframeDescription(this.m_timeframe),". ", CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(err),CMessage::Retcode(err)); return; } //--- Add received value of indicator’s i buffer to indicator data object data_ind.SetBufferValue(data[0]); } } //+------------------------------------------------------------------+
メソッド操作のロジックは、そのコードに詳細に説明されています。メソッドは、現在のバーのすべての指標バッファのデータを更新します。新しいバーでは現在のバーの新しいオブジェクトを作成し、コレクションリストに追加します。コレクションリストのサイズが必要な値を超えると、最も古いオブジェクトがリストから削除されます。
以下は、時間とバッファ番号によって指標データオブジェクトを返すメソッドです。
//+------------------------------------------------------------------+ //| Return indicator data object by time and buffer number | //+------------------------------------------------------------------+ CDataInd* CSeriesDataInd::GetIndDataByTime(const int buffer_num,const datetime time) { CArrayObj *list=GetList(IND_DATA_PROP_TIME,time,EQUAL); list=CSelect::ByIndicatorDataProperty(list,IND_DATA_PROP_IND_BUFFER_NUM,buffer_num,EQUAL); return list.At(0); } //+------------------------------------------------------------------+
ここでは、指定された時間に対応する指標データオブジェクトを含むリストを取得して、
受信したリストをフィルターして、指定した指標バッファのオブジェクトのみがそこに残るようにします。
リストには1つのオブジェクトのみが含まれます。それを返します。
以下は、バーとバッファ番号によって指標データオブジェクトを返すメソッドです。
//+------------------------------------------------------------------+ //| Return indicator data object by bar and buffer number | //+------------------------------------------------------------------+ CDataInd* CSeriesDataInd::GetIndDataByBar(const int buffer_num,const uint shift) { datetime time=::iTime(this.m_symbol,this.m_timeframe,(int)shift); if(time==0) return NULL; return this.GetIndDataByTime(buffer_num,time); } //+------------------------------------------------------------------+
ここでは、指定されたインデックスでバーの開く時間を取得してから、上記のメソッドを使用して受け取ったオブジェクトを返します。
以下は、指定された指標バッファのデータを時間によって返すメソッドです。
//+------------------------------------------------------------------+ //| Return data of specified indicator buffer by time | //+------------------------------------------------------------------+ double CSeriesDataInd::BufferValue(const int buffer_num,const datetime time) { CDataInd *data_ind=this.GetIndDataByTime(buffer_num,time); return(data_ind==NULL ? EMPTY_VALUE : data_ind.BufferValue()); } //+------------------------------------------------------------------+
ここでは、GetIndDataByTime()メソッドを使用してデータオブジェクトを取得し、オブジェクトに書き込まれたバッファ値を返すか、オブジェクトが受信されなかった場合は「空の値」を返します。
以下は、指定された指標バッファのデータをバーインデックスによって返すメソッドです。
//+------------------------------------------------------------------+ //| Return data of specified indicator buffer by bar index | //+------------------------------------------------------------------+ double CSeriesDataInd::BufferValue(const int buffer_num,const uint shift) { CDataInd *data_ind=this.GetIndDataByBar(buffer_num,shift); return(data_ind==NULL ? EMPTY_VALUE : data_ind.BufferValue()); } //+------------------------------------------------------------------+
ここでは、GetIndDataByBar()メソッドを使用してデータオブジェクトを取得し、オブジェクトに書き込まれたバッファ値を返すか、オブジェクトが受信されなかった場合は「空の値」を返します。
プログラムで作成されたすべての指標は、第54部で作成された指標オブジェクトコレクションに移動されます。このような各オブジェクトは、標準またはカスタム指標のすべてのデータを備えています。ただし、一部のデータの補足が必要です。このクラスのオブジェクトによって記述される指標が所有するバッファの数が常にわかるように、指標バッファの数を格納するための変数を追加する必要があります。これは、描画するバッファの数が事前にわからないカスタム指標に特に関係があります。また、クラスを作成したばかりの指標バッファデータコレクションリストを追加する必要があります。このような場合、指標オブジェクトはそのすべてのバッファのデータリストも保存します。それらから、各指標バッファの各バーのデータを受信することができます。
指標オブジェクトクラスファイル\MQL5\Include\DoEasy\Objects\Indicators\IndicatorDE.mqhを開き、必要なすべての改善を行います。
//+------------------------------------------------------------------+ //| Ind.mqh | //| 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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\..\Services\Select.mqh" #include "..\..\Objects\BaseObj.mqh" #include "..\..\Objects\Indicators\SeriesDataInd.mqh" //+------------------------------------------------------------------+ //| Abstract indicator class | //+------------------------------------------------------------------+ class CIndicatorDE : public CBaseObj { protected: MqlParam m_mql_param[]; // Array of indicator parameters CSeriesDataInd m_series_data; // Timeseries object of indicator buffer data private: long m_long_prop[INDICATOR_PROP_INTEGER_TOTAL]; // Integer properties double m_double_prop[INDICATOR_PROP_DOUBLE_TOTAL]; // Real properties string m_string_prop[INDICATOR_PROP_STRING_TOTAL]; // String properties string m_ind_type_description; // Indicator type description int m_buffers_total; // Total number of indicator buffers //--- Return the index of the array the buffer's (1) double and (2) string properties are actually located at int IndexProp(ENUM_INDICATOR_PROP_DOUBLE property) const { return(int)property-INDICATOR_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_INDICATOR_PROP_STRING property) const { return(int)property-INDICATOR_PROP_INTEGER_TOTAL-INDICATOR_PROP_DOUBLE_TOTAL;} //--- Comare (1) structures MqlParam, (2) array of structures MqlParam between each other bool IsEqualMqlParams(MqlParam &struct1,MqlParam &struct2) const; bool IsEqualMqlParamArrays(MqlParam &compared_struct[]) const; protected: //--- Protected parametric constructor CIndicatorDE(ENUM_INDICATOR ind_type, string symbol, ENUM_TIMEFRAMES timeframe, ENUM_INDICATOR_STATUS status, ENUM_INDICATOR_GROUP group, string name, string shortname, MqlParam &mql_params[]); public: //--- Default constructor CIndicatorDE(void){;} //--- Destructor ~CIndicatorDE(void); //--- Set buffer's (1) integer, (2) real and (3) string property void SetProperty(ENUM_INDICATOR_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_INDICATOR_PROP_DOUBLE property,double value) { this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_INDICATOR_PROP_STRING property,string value) { this.m_string_prop[this.IndexProp(property)]=value; } //--- Return buffer’s (1) integer, (2) real and (3) string property from the properties array long GetProperty(ENUM_INDICATOR_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_INDICATOR_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_INDICATOR_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } //--- Return description of buffer's (1) integer, (2) real and (3) string property string GetPropertyDescription(ENUM_INDICATOR_PROP_INTEGER property); string GetPropertyDescription(ENUM_INDICATOR_PROP_DOUBLE property); string GetPropertyDescription(ENUM_INDICATOR_PROP_STRING property); //--- Return the flag of the buffer supporting the property virtual bool SupportProperty(ENUM_INDICATOR_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_INDICATOR_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_INDICATOR_PROP_STRING property) { return true; } //--- Compare CIndicatorDE objects by all possible properties (for sorting the lists by a specified indicator object property) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CIndicatorDE objects by all properties (to search equal indicator objects) bool IsEqual(CIndicatorDE* compared_obj) const; //--- Set indicator’s (1) group, (2) empty value of buffers, (3) name, (4) short name, (5) ID void SetGroup(const ENUM_INDICATOR_GROUP group) { this.SetProperty(INDICATOR_PROP_GROUP,group); } void SetEmptyValue(const double value) { this.SetProperty(INDICATOR_PROP_EMPTY_VALUE,value); } void SetName(const string name) { this.SetProperty(INDICATOR_PROP_NAME,name); } void SetShortName(const string shortname) { this.SetProperty(INDICATOR_PROP_SHORTNAME,shortname); } void SetID(const int id) { this.SetProperty(INDICATOR_PROP_ID,id); } void SetBuffersTotal(const int buffers_total) { this.m_buffers_total=buffers_total; } //--- Return indicator’s (1) status, (2) group, (3) timeframe, (4) type, (5) handle, (6) ID, //--- (7) empty value of buffers, (8) name, (9) short name, (10) symbol, (11) number of buffers ENUM_INDICATOR_STATUS Status(void) const { return (ENUM_INDICATOR_STATUS)this.GetProperty(INDICATOR_PROP_STATUS);} ENUM_INDICATOR_GROUP Group(void) const { return (ENUM_INDICATOR_GROUP)this.GetProperty(INDICATOR_PROP_GROUP); } ENUM_TIMEFRAMES Timeframe(void) const { return (ENUM_TIMEFRAMES)this.GetProperty(INDICATOR_PROP_TIMEFRAME); } ENUM_INDICATOR TypeIndicator(void) const { return (ENUM_INDICATOR)this.GetProperty(INDICATOR_PROP_TYPE); } int Handle(void) const { return (int)this.GetProperty(INDICATOR_PROP_HANDLE); } int ID(void) const { return (int)this.GetProperty(INDICATOR_PROP_ID); } double EmptyValue(void) const { return this.GetProperty(INDICATOR_PROP_EMPTY_VALUE); } string Name(void) const { return this.GetProperty(INDICATOR_PROP_NAME); } string ShortName(void) const { return this.GetProperty(INDICATOR_PROP_SHORTNAME); } string Symbol(void) const { return this.GetProperty(INDICATOR_PROP_SYMBOL); } int BuffersTotal(void) const { return this.m_buffers_total; } //--- Return description of (1) type, (2) status, (3) group, (4) timeframe, (5) empty value of indicator, (6) parameter of m_mql_param array string GetTypeDescription(void) const { return m_ind_type_description; } string GetStatusDescription(void) const; string GetGroupDescription(void) const; string GetTimeframeDescription(void) const; string GetEmptyValueDescription(void) const; string GetMqlParamDescription(const int index) const; //--- Return indicator data timeseries CSeriesDataInd *GetSeriesData(void) { return &this.m_series_data; } //--- Display the description of indicator object properties in the journal (full_prop=true - all properties, false - supported ones only) void Print(const bool full_prop=false); //--- Display (1) a short description, (2) description of indicator object parameters in the journal (implementation in the descendants) virtual void PrintShort(void) {;} virtual void PrintParameters(void) {;} //--- Return data of specified buffer from specified bar (1) by index, (2) by bar time double GetDataBuffer(const int buffer_num,const int index); double GetDataBuffer(const int buffer_num,const datetime time); }; //+------------------------------------------------------------------+
クラスに指標データコレクションクラスのオブジェクトを提示するために、インクルードファイルのセクションにそのファイルSeriesDataInd.mqhをインクルードしました。
クラスのprotectedセクションで、指標データコレクションクラスm_series_dataのオブジェクトを宣言します。
m_buffers_total変数は、描画された指標バッファの総数を格納します。これらすべてのバッファのデータオブジェクトは、指標バッファのデータコレクションに保存されます。
メソッドSetBuffersTotal()およびBuffersTotal()は、描画された指標バッファの総数を設定/返します。
メソッドGetSeriesData()は、指標バッファデータコレクションへのポインタを返します。
ここで、指標コレクションクラスファイル\MQL5\Include\DoEasy\Collections\IndicatorsCollection.mqhを開き、必要な改善を追加します。
指標の作成時に、作成された指標のタイプに対応するすべてのデータを明確にして、抽象指標クラスのオブジェクトが作成されます。次に、この指標オブジェクトがコレクションリストに追加されます。作成された指標オブジェクトがAddIndicatorToList()メソッドを使用してコレクションに追加されると、さらに、指標の必要なパラメータがその正確な識別のために設定されます。
このメソッドに、描画される指標バッファの数と必要なバッファデータの量の仕様を追加します。
//--- (1) Create, (2) add to collection list a new indicator object and set an ID for it CIndicatorDE *CreateIndicator(const ENUM_INDICATOR ind_type,MqlParam &mql_param[],const string symbol_name=NULL,const ENUM_TIMEFRAMES period=PERIOD_CURRENT); int AddIndicatorToList(CIndicatorDE *indicator,const int id,const int buffers_total,const uint required=0);
カスタム指標作成メソッドでは、描画されたバッファの総数を追加で渡します。
int CreateCustom(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id,const int buffers_total, ENUM_INDICATOR_GROUP group, MqlParam &mql_param[]);
指標バッファ時系列のデータオブジェクトへのポインタを指定された時間によって返すメソッドと、指標バッファデータコレクションからデータを作成、更新、および返すメソッドを宣言します。
//--- Return (1) indicator object by its ID, (2) the data object of indicator buffer timeseries by time CIndicatorDE *GetIndByID(const uint id); CDataInd *GetDataIndObj(const uint ind_id,const int buffer_num,const datetime time); //--- Display (1) the complete and (2) short collection description in the journal void Print(void); void PrintShort(void); //--- Create (1) timeseries of specified indicator data, (2) all timeseries used of all collection indicators bool SeriesCreate(CIndicatorDE *indicator,const uint required=0); bool SeriesCreateAll(const uint required=0); //--- Update buffer data of all indicators void SeriesRefreshAll(void); void SeriesRefresh(const int ind_id); //--- Return by bar (1) time, (2) number the value of the buffer specified by indicator ID double GetBufferValue(const uint ind_id,const int buffer_num,const datetime time); double GetBufferValue(const uint ind_id,const int buffer_num,const uint shift); //--- Constructor CIndicatorsCollection(); }; //+------------------------------------------------------------------+
AddIndicatorToList()メソッドの実装では、指標バッファの数の設定とその時系列の作成を追加します。
//+------------------------------------------------------------------+ //| Add a new indicator object to collection list | //+------------------------------------------------------------------+ int CIndicatorsCollection::AddIndicatorToList(CIndicatorDE *indicator,const int id,const int buffers_total,const uint required=0) { //--- If invalid indicator is passed to the object - return INVALID_HANDLE if(indicator==NULL) return INVALID_HANDLE; //--- If such indicator is already in the list int index=this.Index(indicator); if(index!=WRONG_VALUE) { //--- Remove the earlier created object, get indicator object from the list and return indicator handle delete indicator; indicator=this.m_list.At(index); } //--- If indicator object is not in the list yet else { //--- If failed to add indicator object to the list - display a corresponding message, //--- remove object and return INVALID_HANDLE if(!this.m_list.Add(indicator)) { ::Print(CMessage::Text(MSG_LIB_SYS_FAILED_ADD_IND_TO_LIST)); delete indicator; return INVALID_HANDLE; } } //--- If indicator is successfully added to the list or is already there... //--- If indicator with specified ID (not -1) is not in the list - set ID if(id>WRONG_VALUE && !this.CheckID(id)) indicator.SetID(id); //--- Set the total number of buffers and create data timeseries of all indicator buffers indicator.SetBuffersTotal(buffers_total); this.SeriesCreate(indicator,required); //--- Return handle of a new indicator added to the list return indicator.Handle(); } //+------------------------------------------------------------------+
指標バッファの総数もAddIndicatorToList()メソッドに渡されるため、指標オブジェクトを作成するすべてのメソッドで、バッファ数の値の受け渡しを追加する必要があります。標準指標の場合、それらの正確な数はわかっていますが、カスタム指標の場合、この数はその作成メソッドで渡されます。
このようなすべてのクラスメソッドには、すでに変更が加えられています。それらのうちいくつかを見てみましょう。
以下は、Accelerator Oscillator指標の作成メソッドです。
//+------------------------------------------------------------------+ //| Create a new indicator object Accelerator Oscillator | //| and place it to the collection list | //+------------------------------------------------------------------+ int CIndicatorsCollection::CreateAC(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id) { //--- AC indicator possesses no parameters - resize the array of parameter structures ::ArrayResize(this.m_mql_param,0); //--- Create indicator object CIndicatorDE *indicator=this.CreateIndicator(IND_AC,this.m_mql_param,symbol,timeframe); //--- Return indicator handle received as a result of adding the object to collection list return this.AddIndicatorToList(indicator,id,1); } //+------------------------------------------------------------------+
指標オブジェクトをコレクションリストに追加するメソッドを呼び出す際に、さらにこの指標には1つの描画バッファがあることを指定します。
以下は、平均方向移動指数(Average Directional Movement Index)指標の作成メソッドです。
//+------------------------------------------------------------------+ //| Create new indicator object | //| Average Directional Movement Index | //| and place it to the collection list | //+------------------------------------------------------------------+ int CIndicatorsCollection::CreateADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id,const int adx_period=14) { //--- Add required indicator parameters to the array of parameter structures ::ArrayResize(this.m_mql_param,1); this.m_mql_param[0].type=TYPE_INT; this.m_mql_param[0].integer_value=adx_period; //--- Create indicator object CIndicatorDE *indicator=this.CreateIndicator(IND_ADX,this.m_mql_param,symbol,timeframe); //--- Return indicator handle received as a result of adding the object to collection list return this.AddIndicatorToList(indicator,id,3); } //+------------------------------------------------------------------+
指標オブジェクトをコレクションリストに追加するメソッドを呼び出す際に、さらにこの指標には3つの描画バッファがあることを指定します。
以下は、カスタム指標の作成メソッドです。
//+------------------------------------------------------------------+ //| Create a new object - custom indicator | //| and place it to the collection list | //+------------------------------------------------------------------+ int CIndicatorsCollection::CreateCustom(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id, const int buffers_total, ENUM_INDICATOR_GROUP group, MqlParam &mql_param[]) { //--- Create indicator object CIndicatorDE *indicator=this.CreateIndicator(IND_CUSTOM,mql_param,symbol,timeframe); if(indicator==NULL) return INVALID_HANDLE; //--- Set a group for indicator object indicator.SetGroup(group); //--- Return indicator handle received as a result of adding the object to collection list return this.AddIndicatorToList(indicator,id,buffers_total); } //+------------------------------------------------------------------+
メソッドの入力変数で指標の描画バッファの数の値を渡し、指標オブジェクトをコレクションリストに追加するメソッドを呼び出す際にメソッドに渡された描画バッファの数を指定します 。
以下は、指標バッファ時系列のデータオブジェクトへのポインタを時間によって返すメソッドです。
//+------------------------------------------------------------------+ //| Return data object of indicator buffer timeseries by time | //+------------------------------------------------------------------+ CDataInd *CIndicatorsCollection::GetDataIndObj(const uint ind_id,const int buffer_num,const datetime time) { CIndicatorDE *indicator=this.GetIndByID(ind_id); if(indicator==NULL) return NULL; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data==NULL) return NULL; return buffers_data.GetIndDataByTime(buffer_num,time); } //+------------------------------------------------------------------+
ここでは、IDによってコレクションから指標オブジェクトを取得し、
バッファデータのコレクションリストへのポインタを取得し、
指定されたバッファのデータを時系列バーの開いた時間によって返します。
以下は、指定された指標のデータ時系列を作成するメソッドです。
//+------------------------------------------------------------------+ //| Create data timeseries of the specified indicator | //+------------------------------------------------------------------+ bool CIndicatorsCollection::SeriesCreate(CIndicatorDE *indicator,const uint required=0) { if(indicator==NULL) return false; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data!=NULL) { buffers_data.SetSymbolPeriod(indicator.Symbol(),indicator.Timeframe()); buffers_data.SetIndHandle(indicator.Handle()); buffers_data.SetIndID(indicator.ID()); buffers_data.SetIndBuffersTotal(indicator.BuffersTotal()); buffers_data.SetRequiredUsedData(required); } return(buffers_data!=NULL ? buffers_data.Create(required)>0 : false); } //+------------------------------------------------------------------+
ここでは、メソッドは指標オブジェクトへのポインタおよび指標バッファデータの作成されたバーの必要な数を受け取ります。
指標オブジェクトからそのバッファデータコレクションへのポインタを取得し、
データコレクションに必要なすべてのパラメータを設定し、
要求された数の指標バッファデータの作成結果を返します。
以下は、すべてのコレクション指標で使用されるすべての時系列を作成するメソッドです。
//+------------------------------------------------------------------+ //| Create all timeseries used of all collection indicators | //+------------------------------------------------------------------+ bool CIndicatorsCollection::SeriesCreateAll(const uint required=0) { bool res=true; for(int i=0;i<m_list.Total();i++) { CIndicatorDE *indicator=m_list.At(i); if(!this.SeriesCreate(indicator,required)) res&=false; } return res; } //+------------------------------------------------------------------+
ここでは、コレクション内の指標オブジェクトの総数によるループで、さらに指標オブジェクトへのポインターを取得し、上記で検討した方法を使用してバッファデータの時系列を作成した結果をres変数に追加します。 ループが完了したら、変数resの値を返します。少なくとも1つのバッファデータ時系列が作成されなかった場合、この変数はfalse値になります。
以下は、すべてのコレクション指標のバッファデータの更新メソッドです。
//+------------------------------------------------------------------+ //| Update buffer data of all indicators | //+------------------------------------------------------------------+ void CIndicatorsCollection::SeriesRefreshAll(void) { for(int i=0;i<m_list.Total();i++) { CIndicatorDE *indicator=m_list.At(i); if(indicator==NULL) continue; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data==NULL) continue; buffers_data.Refresh(); } } //+------------------------------------------------------------------+
ここでは、コレクション内の指標オブジェクトの総数によるループで、さらに指標オブジェクトへのポインターを取得し、バッファ時系列のデータオブジェクトへのポインタを取得し、Refresh()メソッドを使用して時系列を更新します。
以下は、指定された指標のバッファデータの更新メソッドです。
//+------------------------------------------------------------------+ //| Update buffer data of the specified indicator | //+------------------------------------------------------------------+ void CIndicatorsCollection::SeriesRefresh(const int ind_id) { CIndicatorDE *indicator=this.GetIndByID(ind_id); if(indicator==NULL) return; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data==NULL) return; buffers_data.Refresh(); } //+------------------------------------------------------------------+
メソッドは必要な指標のIDを受け取ります。GetIndByID()メソッドを使用して必要な指標へのポインタを取得し、バッファデータの時系列オブジェクトを取得し、Refresh()メソッドを使用して時系列を更新します。
以下は、指定された指標の指定されたバッファの値を時間またはバーインデックスによって返すメソッドです。
//+------------------------------------------------------------------+ //| Return buffer value by bar time | //| specified by indicator ID | //+------------------------------------------------------------------+ double CIndicatorsCollection::GetBufferValue(const uint ind_id,const int buffer_num,const datetime time) { CIndicatorDE *indicator=GetIndByID(ind_id); if(indicator==NULL) return EMPTY_VALUE; CSeriesDataInd *series=indicator.GetSeriesData(); return(series!=NULL && series.DataTotal()>0 ? series.BufferValue(buffer_num,time) : EMPTY_VALUE); } //+------------------------------------------------------------------+ //| Return by bar number the buffer value | //| specified by indicator ID | //+------------------------------------------------------------------+ double CIndicatorsCollection::GetBufferValue(const uint ind_id,const int buffer_num,const uint shift) { CIndicatorDE *indicator=GetIndByID(ind_id); if(indicator==NULL) return EMPTY_VALUE; CSeriesDataInd *series=indicator.GetSeriesData(); return(series!=NULL && series.DataTotal()>0 ? series.BufferValue(buffer_num,shift) : EMPTY_VALUE); } //+------------------------------------------------------------------+
これらのメソッドは、最初のメソッドにはバーの開いた時間が渡される一方2番目のメソッドにはバーのインデックスが渡されることを除いて同じです。
コレクション内の必要な指標へのポインタを取得し、バッファデータのコレクションオブジェクトへのポインタを取得し、オーバーロードされたメソッドBufferValue()を使用して指定されたバッファの値を返します 。
ライブラリクラスを「外部世界」に接続するには、メインライブラリクラスCEngineを使用します。これはプログラムからすべてのライブラリメソッドにアクセスするメソッドが配置されている\MQL5\Include\DoEasy\Engine.mqhにあります。
クラスのpublicセクションに指標バッファデータのコレクションを処理するためのメソッドを追加します。//--- Return (1) the indicator collection, (2) the indicator list from the collection CIndicatorsCollection *GetIndicatorsCollection(void) { return &this.m_indicators; } CArrayObj *GetListIndicators(void) { return this.m_indicators.GetList(); } //--- Create all timeseries used of all collection indicators bool IndicatorSeriesCreateAll(void) { return this.m_indicators.SeriesCreateAll();} //--- Update buffer data of all indicators void IndicatorSeriesRefreshAll(void) { this.m_indicators.SeriesRefreshAll(); } void IndicatorSeriesRefresh(const int ind_id) { this.m_indicators.SeriesRefresh(ind_id);} //--- Return the value of the specified buffer by (1) time, (2) number of the bar specified by indicator ID double IndicatorGetBufferValue(const uint ind_id,const int buffer_num,const datetime time) { return this.m_indicators.GetBufferValue(ind_id,buffer_num,time); } double IndicatorGetBufferValue(const uint ind_id,const int buffer_num,const uint shift) { return this.m_indicators.GetBufferValue(ind_id,buffer_num,shift); }
これらのメソッドはすべて、上記の指標のコレクションクラスに追加された対応するメソッドを呼び出します。
クラスコンストラクタで、指標バッファデータのコレクションを更新するための新しいタイマーを作成します。
//+------------------------------------------------------------------+ //| CEngine constructor | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true), m_last_trade_event(TRADE_EVENT_NO_EVENT), m_last_account_event(WRONG_VALUE), m_last_symbol_event(WRONG_VALUE), m_global_error(ERR_SUCCESS) { this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_is_tester=::MQLInfoInteger(MQL_TESTER); this.m_program=(ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE); this.m_name=::MQLInfoString(MQL_PROGRAM_NAME); this.m_list_counters.Sort(); this.m_list_counters.Clear(); this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE); this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE); this.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1); this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2); this.CreateCounter(COLLECTION_REQ_COUNTER_ID,COLLECTION_REQ_COUNTER_STEP,COLLECTION_REQ_PAUSE); this.CreateCounter(COLLECTION_TS_COUNTER_ID,COLLECTION_TS_COUNTER_STEP,COLLECTION_TS_PAUSE); this.CreateCounter(COLLECTION_IND_TS_COUNTER_ID,COLLECTION_IND_TS_COUNTER_STEP,COLLECTION_IND_TS_PAUSE); ::ResetLastError(); #ifdef __MQL5__ if(!::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TIMER),(string)::GetLastError()); this.m_global_error=::GetLastError(); } //---__MQL4__ #else if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TIMER),(string)::GetLastError()); this.m_global_error=::GetLastError(); } #endif //--- } //+------------------------------------------------------------------+
クラスタイマーで、タイマーおよびティックごとに指標バッファデータの時系列を処理するためのコードブロックを追加します(テスター内)。
//+------------------------------------------------------------------+ //| CEngine timer | //+------------------------------------------------------------------+ void CEngine::OnTimer(SDataCalculate &data_calculate) { //--- If this is not a tester, work with collection events by timer if(!this.IsTester()) { //--- Timer of the collections of historical orders and deals, as well as of market orders and positions int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID); CTimerCounter* cnt1=this.m_list_counters.At(index); if(cnt1!=NULL) { //--- If unpaused, work with the order, deal and position collections events if(cnt1.IsTimeDone()) this.TradeEventsControl(); } //--- Account collection timer index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID); CTimerCounter* cnt2=this.m_list_counters.At(index); if(cnt2!=NULL) { //--- If unpaused, work with the account collection events if(cnt2.IsTimeDone()) this.AccountEventsControl(); } //--- Timer 1 of the symbol collection (updating symbol quote data in the collection) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1); CTimerCounter* cnt3=this.m_list_counters.At(index); if(cnt3!=NULL) { //--- If the pause is over, update quote data of all symbols in the collection if(cnt3.IsTimeDone()) this.m_symbols.RefreshRates(); } //--- Timer 2 of the symbol collection (updating all data of all symbols in the collection and tracking symbl and symbol search events in the market watch window) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2); CTimerCounter* cnt4=this.m_list_counters.At(index); if(cnt4!=NULL) { //--- If the pause is over if(cnt4.IsTimeDone()) { //--- update data and work with events of all symbols in the collection this.SymbolEventsControl(); //--- When working with the market watch list, check the market watch window events if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH) this.MarketWatchEventsControl(); } } //--- Trading class timer index=this.CounterIndex(COLLECTION_REQ_COUNTER_ID); CTimerCounter* cnt5=this.m_list_counters.At(index); if(cnt5!=NULL) { //--- If unpaused, work with the list of pending requests if(cnt5.IsTimeDone()) this.m_trading.OnTimer(); } //--- Timeseries collection timer index=this.CounterIndex(COLLECTION_TS_COUNTER_ID); CTimerCounter* cnt6=this.m_list_counters.At(index); if(cnt6!=NULL) { //--- If the pause is over, work with the timeseries list (update all except the current one) if(cnt6.IsTimeDone()) this.SeriesRefreshAllExceptCurrent(data_calculate); } //--- Timer of timeseries collection of indicator buffer data index=this.CounterIndex(COLLECTION_IND_TS_COUNTER_ID); CTimerCounter* cnt7=this.m_list_counters.At(index); if(cnt7!=NULL) { //--- If the pause is over, work with the timeseries list of indicator data (update all except for the current one) if(cnt7.IsTimeDone()) this.IndicatorSeriesRefreshAll(); } } //--- If this is a tester, work with collection events by tick else { //--- work with events of collections of orders, deals and positions by tick this.TradeEventsControl(); //--- work with events of collections of accounts by tick this.AccountEventsControl(); //--- update quote data of all collection symbols by tick this.m_symbols.RefreshRates(); //--- work with events of all symbols in the collection by tick this.SymbolEventsControl(); //--- work with the list of pending orders by tick this.m_trading.OnTimer(); //--- work with the timeseries list by tick this.SeriesRefresh(data_calculate); //--- work with the timeseries list of indicator buffers by tick this.IndicatorSeriesRefreshAll(); } } //+------------------------------------------------------------------+
改善は今のところこれですべてです。
テスト
テストを実行するには、前の記事のEAを使用して、新しいフォルダ\MQL5\Experts\TestDoEasy\Part58\で新しくTestDoEasyPart58.mq5として保存します。
以前のEAで行ったのと同じ方法でテストを実行します。4つの指標(2つは標準で、2つはカスタム)があります。
違いは、以前のEAではすべてのクラスのオブジェクトをすぐに作成した一方、今度は作成された指標のバッファデータコレクションクラスのオブジェクトとライブラリで作成されたオブジェクトを使用するということです。
グローバルセクションから指標オブジェクトへのポインタを削除します。
//--- Pointers to indicator data objects CDataInd *data_ma1_0=NULL; CDataInd *data_ma1_1=NULL; CDataInd *data_ma2_0=NULL; CDataInd *data_ma2_1=NULL; CDataInd *data_ama1_0=NULL; CDataInd *data_ama1_1=NULL; CDataInd *data_ama2_0=NULL; CDataInd *data_ama2_1=NULL; //+------------------------------------------------------------------+
EAのOnInit()ハンドラで作成されたカスタム指標のバッファ数を追加します。
//--- Create indicators ArrayResize(param_ma1,4); //--- Name of indicator 1 param_ma1[0].type=TYPE_STRING; param_ma1[0].string_value="Examples\\Custom Moving Average.ex5"; //--- Calculation period param_ma1[1].type=TYPE_INT; param_ma1[1].integer_value=13; //--- Horizontal shift param_ma1[2].type=TYPE_INT; param_ma1[2].integer_value=0; //--- Smoothing method param_ma1[3].type=TYPE_INT; param_ma1[3].integer_value=MODE_SMA; //--- Create indicator 1 engine.GetIndicatorsCollection().CreateCustom(NULL,PERIOD_CURRENT,MA1,1,INDICATOR_GROUP_TREND,param_ma1); ArrayResize(param_ma2,5); //--- Name of indicator 2 param_ma2[0].type=TYPE_STRING; param_ma2[0].string_value="Examples\\Custom Moving Average.ex5"; //--- Calculation period param_ma2[1].type=TYPE_INT; param_ma2[1].integer_value=13; //--- Horizontal shift param_ma2[2].type=TYPE_INT; param_ma2[2].integer_value=0; //--- Smoothing method param_ma2[3].type=TYPE_INT; param_ma2[3].integer_value=MODE_SMA; //--- Calculation price param_ma2[4].type=TYPE_INT; param_ma2[4].integer_value=PRICE_OPEN; //--- Create indicator 2 engine.GetIndicatorsCollection().CreateCustom(NULL,PERIOD_CURRENT,MA2,1,INDICATOR_GROUP_TREND,param_ma2);
EAのOnDeinit()ハンドラで作成された指標オブジェクトを削除します。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Remove EA graphical objects by an object name prefix ObjectsDeleteAll(0,prefix); Comment(""); //--- Remove created data objects of MA indicators if(CheckPointer(data_ma1_0)==POINTER_DYNAMIC) delete data_ma1_0; if(CheckPointer(data_ma1_1)==POINTER_DYNAMIC) delete data_ma1_1; if(CheckPointer(data_ma2_0)==POINTER_DYNAMIC) delete data_ma2_0; if(CheckPointer(data_ma2_1)==POINTER_DYNAMIC) delete data_ma2_1; //--- Remove created data objects of AMA indicators if(CheckPointer(data_ama1_0)==POINTER_DYNAMIC) delete data_ama1_0; if(CheckPointer(data_ama1_1)==POINTER_DYNAMIC) delete data_ama1_1; if(CheckPointer(data_ama2_0)==POINTER_DYNAMIC) delete data_ama2_0; if(CheckPointer(data_ama2_1)==POINTER_DYNAMIC) delete data_ama2_1; //--- Deinitialize library engine.OnDeinit(); } //+------------------------------------------------------------------+
以前のEAと比較して、OnTick()ハンドラがはるかに短くなりました。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Handle the NewTick event in the library engine.OnTick(rates_data); //--- If work in tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(rates_data); // Work in timer PressButtonsControl(); // Button press control engine.EventsHandling(); // Work with events } //--- Get indicator values by their IDs from data collections of their buffers from bars 0 and 1 double ma1_value0=engine.IndicatorGetBufferValue(MA1,0,0), ma1_value1=engine.IndicatorGetBufferValue(MA1,0,1); double ma2_value0=engine.IndicatorGetBufferValue(MA2,0,0), ma2_value1=engine.IndicatorGetBufferValue(MA2,0,1); double ama1_value0=engine.IndicatorGetBufferValue(AMA1,0,0), ama1_value1=engine.IndicatorGetBufferValue(AMA1,0,1); double ama2_value0=engine.IndicatorGetBufferValue(AMA2,0,0), ama2_value1=engine.IndicatorGetBufferValue(AMA2,0,1); //--- Display the values of indicator buffers to comment on the chart from data objects Comment ( "ma1(1)=",DoubleToString(ma1_value1,6),", ma1(0)=",DoubleToString(ma1_value0,6)," ", "ma2(1)=",DoubleToString(ma2_value1,6),", ma2(0)=",DoubleToString(ma2_value0,6),", \n", "ama1(1)=",DoubleToString(ama1_value1,6),", ama1(0)=",DoubleToString(ama1_value0,6)," ", "ama1(1)=",DoubleToString(ama2_value1,6),", ama1(0)=",DoubleToString(ama2_value0,6) ); //--- If the trailing flag is set if(trailing_on) { TrailingPositions(); // Trailing positions TrailingOrders(); // Trailing of pending orders } } //+------------------------------------------------------------------+
EAをコンパイルし、現在の銘柄と時間枠のみを使用するように事前に設定されているチャートで起動します。チャートのコメントには、作成されたすべての指標の最初とゼロ(現在)バーのデータが表示されます。
より明確にするために、同じ設定の同じ指標がチャートにプロットされます。チャートのコメントとデータウィンドウ(Ctrl + D)の指標データは、現在のバーの更新の値と一致します。
次の段階
次の記事では、ティックと板情報を処理するクラスを作成するための準備を開始します。
現在のライブラリバージョンのすべてのファイルは、MQL5のテストEAファイルと一緒に以下に添付されています。ダウンロードし、すべてを検証することが可能です。
質問や提案は記事のコメント欄にお願いします。
シリーズのこれまでの記事:
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部): 複数銘柄・複数期間標準指標
DoEasyライブラリの時系列(第48部): 単一サブウィンドウでの単一バッファ複数銘柄・複数期間指標
DoEasyライブラリの時系列(第49部): 複数銘柄・複数期間の複数バッファ標準指標
DoEasyライブラリの時系列(第50部): シフト付き複数銘柄・複数期間標準指標
DoEasyライブラリの時系列(第51部): 複数銘柄・複数期間の複合標準指標
DoEasyライブラリの時系列(第52部): 複数銘柄・複数期間の単一バッファ標準指標のクロスプラットフォーム化
DoEasyライブラリの時系列(第53部): 抽象基本指標クラス
DoEasyライブラリの時系列(第54部): 抽象基本指標の子孫クラス
DoEasyライブラリの時系列(第55部): 指標コレクションクラス
DoEasyライブラリの時系列(第56部): カスタム指標オブジェクト、コレクション内指標オブジェクトからのデータ取得
DoEasyライブラリの時系列(第57部): 指標バッファデータオブジェクト
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/8787





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