DoEasy库中的时间序列(第58部分):指标缓冲区数据的时间序列

2021年1月25日,10:02
Artyom Trishkin
0
4 878

目录


概念

在有关使用时间序列的主题的最后,组织存储,搜索和分类存储在指标缓冲区中的数据,这将允许根据要在程序库中基于库创建的指标值来进一步执行分析。
指标数据时间序列构造的概念类似于时间序列集合构造的概念:为每个指标创建一个列表以存储其所有缓冲区的所有数据。指标缓冲区列表中的数据量将与在其上计算指标的相应时间序列的数据量相对应。库的所有集合类的一般概念允许轻松地在相应的集合中找到必要的数据。分别地,在今天创建的类中同样可能。

此外,我将创建类以对库中存储的所有数据进行分析。这将提供一个非常灵活的工具,可以在对图书馆馆藏的任何数据进行全范围比较时进行统计研究。


改善图书馆课程

指标缓冲区数据的收集类将自动更新当前栏上所有已创建指标的数据;当出现一个新的条时,它将创建指标缓冲区的新数据并将其放置到集合中。
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

附加的文件 |
MQL5.zip (3864 KB)
手动图表和交易工具包(第二部分)。图表图形绘图工具 手动图表和交易工具包(第二部分)。图表图形绘图工具

这是该系列的下一篇文章,其中我将展示如何使用键盘快捷键为手动绘制图表图形创建便利的库。使用的工具包括直线及其组合。在这一部分中,我们将查看如何使用第一部分中描述的功能来应用绘图工具。该库可以连接到任何EA或指标,这将大大简化制图任务。此解决方案不使用外部dll,而所有命令都是使用内置MQL工具实现的。

蛮力模式搜索(第二部分):浸入 蛮力模式搜索(第二部分):浸入

在本文中,我们将继续讨论蛮力方法。我将使用我的应用程序的新改进版本来尝试更好地解释该模式。我还将尝试使用不同的时间间隔和时间范围来找到稳定性方面的差异。

使用电子表格制定交易策略 使用电子表格制定交易策略

本文介绍了基本原理和方法,使您可以使用电子表格(Excel,Calc,Google)分析任何策略。将获得的结果与MetaTrader 5测试仪进行比较。

DoEasy库中的价格(第59部分):存储一跳数据的对象 DoEasy库中的价格(第59部分):存储一跳数据的对象

从本文开始,开始创建使用价格数据的库功能。今天,创建一个对象类,该对象类将存储所有带有另一个刻度的价格数据。