目录
概念
在有关使用时间序列的主题的最后,组织存储,搜索和分类存储在指标缓冲区中的数据,这将允许根据要在程序库中基于库创建的指标值来进一步执行分析。
指标数据时间序列构造的概念类似于时间序列集合构造的概念:为每个指标创建一个列表以存储其所有缓冲区的所有数据。指标缓冲区列表中的数据量将与在其上计算指标的相应时间序列的数据量相对应。库的所有集合类的一般概念允许轻松地在相应的集合中找到必要的数据。分别地,在今天创建的类中同样可能。
此外,我将创建类以对库中存储的所有数据进行分析。这将提供一个非常灵活的工具,可以在对图书馆馆藏的任何数据进行全范围比较时进行统计研究。
改善图书馆课程
指标缓冲区数据的收集类将自动更新当前栏上所有已创建指标的数据;当出现一个新的条时,它将创建指标缓冲区的新数据并将其放置到集合中。
在 NewBarObj.mqh 文件中,我们已经有“ New bar”类,该类是为时间序列收集创建的。
它存储在库目录\ MQL5 \ Include \ DoEasyPart57 \ Objects \ Series \中的时间序列类文件夹中。
现在,还需要跟踪指标缓冲区数据收集类中的新柱。
因此,将其移动到服务功能和库\ MQL5 \ Include \ DoEasy \的类的文件夹中服务\.
删除文件的先前位置。
由于“时间序列”类使用“新栏”类,因此 此类的旧路径必须更改 在“时间序列”类文件\ MQL5 \ Include \ DoEasy \ Objects \ Series \中系列DE.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 \数据量:
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 "},
...
{"在dicator buffer number"}, {"在dicator 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对象列表中选择一个指标,以获取与时间序列栏打开时间相对应的任何指标缓冲区的数据。当然,该列表将能够自动更新,搜索和按存储在其中的对象的属性进行排序。
在文件夹\ MQL5 \ Include \ DoEasy \ Objects \指标\ create a new class CSeriesDataInd 在文件中 SeriesDataInd.mqh.
类对象 必须从CBaseObj库的所有对象的基础对象派生.
用所有变量和方法分析类主体:
//+------------------------------------------------------------------+ //| SeriesDataInd.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| //tbxfkj.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property 链接 "//tbxfkj.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 | //+------------------------------------------------------------------+ 类 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(假) { //--- 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类的对象 将被存储,并为列表设置排序列表的标志。这些对象的最佳排序方式是按时间排序:以确保其在列表中的位置与指标的物理缓冲区中的数据位置相对应。
设置交易品种和时限的方法 require no comments:
//+------------------------------------------------------------------+ //| Set a symbol | //+------------------------------------------------------------------+ void CSeriesDataInd::SetSymbol(const string symbol) { if(this.m_symbol==symbol) return; this.m_symbol=(symbol==空值 || 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 假; } //--- 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 假; } //+------------------------------------------------------------------+
为了在指示器中工作,其他类已经可用,因此立即检查启动程序的类型。如果这是一个指示器,则会显示一条消息并 假 返回。在创建时间序列类时,分析了类似方法的工作 第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类的新对象,并将指针返回到新创建的对象,或者 空值 如果没有创建对象。
指标数据时间序列表的创建方法:
//+------------------------------------------------------------------+ //| 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 假; } //--- 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==空值) { 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==空值) 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==空值) 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); } //+------------------------------------------------------------------+
这里: 获取包含与指定时间对应的指标数据对象的列表,
然后 过滤接收到的列表,以便仅将指定指标缓冲区的对象保留在其中.
该列表将仅包含一个对象。把它返还.
通过条和缓冲区号返回指标数据对象的方法:
//+------------------------------------------------------------------+ //| 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 空值; 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==空值 ? 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==空值 ? EMPTY_VALUE : data_ind.BufferValue()); } //+------------------------------------------------------------------+
这里: 使用GetIndDataByBar()方法获取数据对象 和 返回写入对象的缓冲区值或“空值”(如果未接收到对象).
程序中创建的所有指标均应移动 指示第54条中创建的对象集合。每个此类对象均具有标准或自定义指标的所有数据。但是,必须补充一些数据。为了始终知道要由此类对象描述的指示符拥有多少个缓冲区,必须向其中添加一个用于存储指示符缓冲区数量的变量。这与自定义指标特别相关,因为您无法提前知道要绘制的缓冲区数量。另外,我必须添加指标缓冲区数据收集列表,该列表刚刚创建。在这种情况下,指示符对象还将存储其所有缓冲区的数据列表。从它们可以接收每个指示器缓冲器的每个条上的数据。
打开指标对象类文件\ MQL5 \ Include \ DoEasy \ Objects \ Indicators \指标DE.mqh 和 对其进行所有必要的改进:
//+------------------------------------------------------------------+ //| Ind.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| //tbxfkj.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property 链接 "//tbxfkj.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 | //+------------------------------------------------------------------+ 类 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=假); //--- 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 在包含文件的部分中。
在该类的保护区域中声明指标数据收集类的对象 m_series_data.
m_buffers_total 变量将存储绘制的指标缓冲区的总数。所有这些缓冲区的数据对象将存储在指标缓冲区数据集合中。
方法 SetBuffersTotal() 和 BuffersTotal() 设置/返回绘制的指标缓冲区的总数。
方法 GetSeriesData() 返回指向指标缓冲区数据收集的指针。
现在,打开指标收集类\ MQL5 \ Include \ DoEasy \ Collections \的文件指标Collection.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=空值,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==空值) 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()方法,因此在所有指标对象创建方法中,必须添加缓冲区编号值的传递。对于标准指标,其确切编号是已知的,而对于自定义指标,此编号在其创建方法中传递。
所有此类方法都已进行了更改。让我们只考虑其中一些。
加速器振荡器指标的创建方法:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
调用将指标对象添加到集合列表的方法时 我另外指定 该指标有一个绘制的缓冲区.
平均方向运动指标指标的创建方法:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
调用将指标对象添加到集合列表的方法时 我另外指定 该指标具有三个绘制的缓冲区.
自定义指标创建方法:
//+------------------------------------------------------------------+ //| 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==空值) 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==空值) return 空值; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data==空值) return 空值; 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==空值) return 假; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data!=空值) { 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!=空值 ? buffers_data.Create(required)>0 : 假); } //+------------------------------------------------------------------+
这里: 方法接收指向指标对象的指针 和 所需的指标缓冲区数据条的创建数量.
从指标对象 获取指向其缓冲区数据集合的指针,
设置数据收集的所有必要参数 和
返回创建请求数量的指标缓冲区数据的结果.
创建所有收集指标使用的所有时间序列的方法:
//+------------------------------------------------------------------+ //| 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&=假; } return res; } //+------------------------------------------------------------------+
这里: 在循环中按集合中指标对象的总数 获取指向进一步指标对象的指针 和 至 资源 变量添加创建其缓冲区数据的时间序列的结果 使用上述考虑的方法。 循环完成后,返回变量的值 资源。如果未创建至少一个缓冲区数据时间序列,则此变量将具有 假 value.
所有采集指标缓冲区数据的更新方法:
//+------------------------------------------------------------------+ //| 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==空值) continue; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data==空值) 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==空值) return; CSeriesDataInd *buffers_data=indicator.GetSeriesData(); if(buffers_data==空值) 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==空值) return EMPTY_VALUE; CSeriesDataInd *series=indicator.GetSeriesData(); return(series!=空值 && 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==空值) return EMPTY_VALUE; CSeriesDataInd *series=indicator.GetSeriesData(); return(series!=空值 && series.DataTotal()>0 ? series.BufferValue(buffer_num,shift) : EMPTY_VALUE); } //+------------------------------------------------------------------+
方法彼此相同,除了在第一个方法中传递了小节打开时间,而在第二个方法中传递了小节索引。
获取指向集合中必要指标的指针, 获取指向其缓冲区数据收集对象的指针 和 返回指定缓冲区的值 使用重载的方法BufferValue()。
要将图书馆课程与“外部世界”联系起来,主图书馆课程 C引擎 用来。它位于文件\ MQL5 \ Include \ DoEasy \Engine.mqh 从程序访问所有库方法的方法所在的位置。
到公开课部分 添加用于处理指标缓冲区数据收集的方法://--- 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 //--- } //+------------------------------------------------------------------+
上课计时器 添加代码块以按计时器和滴答处理指示器缓冲区数据的时间序列 (in tester):
//+------------------------------------------------------------------+ //| 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!=空值) { //--- 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!=空值) { //--- 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!=空值) { //--- 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!=空值) { //--- 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!=空值) { //--- 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!=空值) { //--- 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!=空值) { //--- 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中相同的方式执行测试:四个指标,其中两个是标准指标,两个是自定义指标。
不同之处在于,在先前的EA中,我立即在其中创建了所有类的对象,而现在,我将使用已创建指标的缓冲区数据收集类的对象以及在库中创建了哪些对象。
来自全球 删除指向指标数据对象的指针:
//--- Pointers to indicator data objects CDataInd *data_ma1_0=空值; CDataInd *data_ma1_1=空值; CDataInd *data_ma2_0=空值; CDataInd *data_ma2_1=空值; CDataInd *data_ama1_0=空值; CDataInd *data_ama1_1=空值; CDataInd *data_ama2_0=空值; CDataInd *data_ama2_1=空值; //+------------------------------------------------------------------+
在处理程序中 OnInit() EA 添加缓冲区数 自定义指标的创建:
//--- Create indicators ArrayResize(param_ma1,4); //--- Name of indicator 1 param_ma1[0].type=TYPE_STRING; param_ma1[0].string_value="例子\\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(空值,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="例子\\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(空值,PERIOD_CURRENT,MA2,1,INDICATOR_GROUP_TREND,param_ma2);
在处理程序中 OnDeinit() EA 删除删除创建的指标对象:
//+------------------------------------------------------------------+ //| 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 Software Corp.从俄语翻译而来。
来源文章: //www.tbxfkj.com/ru/articles/8787