在上一篇文章中,我们创建了抽象指标缓冲区对象,其中包含指标缓冲区的一些常用属性,并提供了操控它们的方法。 在此,我们将创建的对象派生自抽象缓冲区对象类。 此类对象的每一个都是独立的指标缓冲区对象,各自拥有独有的图形构造类型。
如前所述,所有指标缓冲区都带颜色。 然而,如果需要单色缓冲区,则缓冲区在最初创建时会只用一种颜色。 备案则是,我们可在指标操作期间设置缓冲区可用的颜色数量。
首先,我们添加新的函数库消息。
打开 \MQL5\Include\DoEasy\Datas.mqh,并添加新消息的索引:
MSG_LIB_SYS_FAILED_CREATE_BAR_OBJ, // Failed to create the \"Bar\" object MSG_LIB_SYS_FAILED_SYNC_DATA, // Failed to synchronize data with the server MSG_LIB_SYS_FAILED_DRAWING_ARRAY_RESIZE, // Failed to change the array size of drawn buffers MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE, // Failed to change the color array size
...
MSG_LIB_TEXT_BUFFER_TEXT_LINE_WIDTH, // Line width MSG_LIB_TEXT_BUFFER_TEXT_ARROW_SIZE, // Arrow size MSG_LIB_TEXT_BUFFER_TEXT_COLOR_NUM, // Number of colors MSG_LIB_TEXT_BUFFER_TEXT_COLOR, // Drawing color MSG_LIB_TEXT_BUFFER_TEXT_EMPTY_VALUE, // Empty value for plotting where nothing will be drawn MSG_LIB_TEXT_BUFFER_TEXT_SYMBOL, // Buffer symbol MSG_LIB_TEXT_BUFFER_TEXT_LABEL, // Name of the graphical indicator series displayed in DataWindow MSG_LIB_TEXT_BUFFER_TEXT_STATUS_NAME, // Indicator buffer with graphical construction type MSG_LIB_TEXT_BUFFER_TEXT_INVALID_PROPERTY_BUFF, // Invalid number of indicator buffers in #property indicator_buffers
...
MSG_LIB_TEXT_BUFFER_TEXT_TYPE_CALCULATE, // Calculated buffer MSG_LIB_TEXT_BUFFER_TEXT_TYPE_DATA, // Colored data buffer MSG_LIB_TEXT_BUFFER_TEXT_BUFFER, // Buffer MSG_LIB_TEXT_BUFFER_TEXT_STYLE_SOLID, // Solid line MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASH, // Dashed line MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DOT, // Dotted line MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOT, // Dot-dash line MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOTDOT, // Dash - two dots };
接下来,添加与索引相对应的新文本消息:
{"Не удалось создать объект \"Бар\"","Failed to create object \"Bar\""}, {"Не удалось синхронизировать данные с сервером","Failed to sync data with server"}, {"Не удалось изменить размер массива рисуемых буферов","Failed to resize drawing buffers array"}, {"Не удалось изменить размер массива цветов","Failed to resize color array"},
...
{"Толщина линии отрисовки","Thickness of drawing line"}, {"Размер значка стрелки","Arrow icon size"}, {"Количество цветов","Number of colors"}, {"Цвет отрисовки","Index of buffer containing drawing color"}, {"Пустое значение для построения, для которого нет отрисовки","Empty value for plotting, for which there is no drawing"}, {"Символ буфера","Buffer Symbol"}, {"Имя индикаторной графической серии, отображаемое в окне DataWindow","Name of indicator graphical series to display in DataWindow"}, {"Индикаторный буфер с типом графического построения","Indicator buffer with graphic plot type"}, {"Неправильно указано количество буферов индикатора (#property indicator_buffers)","Number of indicator buffers is incorrect (#property indicator_buffers)"},
...
{"Расчётный буфер","Calculated buffer"}, {"Цветной буфер данных","Colored Data buffer"}, {"Буфер","Buffer"}, {"Сплошная линия","Solid line"}, {"Прерывистая линия","Broken line"}, {"Пунктирная линия","Dotted line"}, {"Штрих-пунктирная линия","Dash-dot line"}, {"Штрих - две точки","Dash - two points"}, }; //+---------------------------------------------------------------------+
在 \MQL5\Include\DoEasy\Defines.mqh 里,用宏替换指定可设置的最大指标缓冲区颜色数量,并将其添加到宏替换部分:
//+------------------------------------------------------------------+ //| Macro substitutions | //+------------------------------------------------------------------+ //--- Describe the function with the error line number #define DFUN_ERR_LINE (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(string)__LINE__+": ") #define DFUN (__FUNCTION__+": ") // "Function description" #define COUNTRY_LANG ("Russian") // Country language #define END_TIME (D'31.12.3000 23:59:59') // End date for account history data requests #define TIMER_FREQUENCY (16) // Minimal frequency of the library timer in milliseconds #define TOTAL_TRY (5) // Default number of trading attempts #define IND_COLORS_TOTAL (64) // Maximum possible number of indicator buffer colors //--- Standard sounds
这样做即可避免实现超过 64 种指定颜色数量的验证,尤其是考虑到有一天它们可能会增加。
现在,我们稍微改进一下抽象缓冲区对象类。
指标缓冲区当前位于类的公开部分里,数据和颜色索引缓冲区都是实数型数组。 将它们移至受保护部分。 由于我们可能有若干个指标构造缓冲区,因此创建的缓冲区结构包含单个数组。
我们为什么需要这个?
由于指标缓冲区只能由一维 double 数组表示,因此我们将用单个数组来实现该结构,以便创建缓冲区数组(可能有多于一个数组)。 在此情况下,于这种结构的数组里,我们将拥有构建指标所需的所有数据数组(指标缓冲区)。 它们可按所需数组的索引进行访问。
为避免因意外传递不正确的索引而造成数组超界,创建一个方法来调整所传递的数组索引,以防索引指向数组以外。 在此情况下,调整索引,指定结构数组的最后一个元素。 如果是单个数组,则索引指向它。
在抽象缓冲区对象文件 \MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh (私密部分)里,声明返回调整后的缓冲区数组索引的方法,
而在受保护的部分中,声明缓冲区数组的结构,带结构类型的缓冲区的数组对象,颜色缓冲区数组,和为指标结构着色的 已用颜色数组:
//+------------------------------------------------------------------+ //| Abstract indicator buffer class | //+------------------------------------------------------------------+ class CBuffer : public CBaseObj { private: long m_long_prop[BUFFER_PROP_INTEGER_TOTAL]; // Integer properties double m_double_prop[BUFFER_PROP_DOUBLE_TOTAL]; // Real properties string m_string_prop[BUFFER_PROP_STRING_TOTAL]; // String properties //--- Return the index of the array the buffer's (1) double and (2) string properties are located at int IndexProp(ENUM_BUFFER_PROP_DOUBLE property) const { return(int)property-BUFFER_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_BUFFER_PROP_STRING property) const { return(int)property-BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_DOUBLE_TOTAL; } //--- Set the graphical construction type void SetDrawType(void); //--- Return the adjusted buffer array index int GetCorrectIndexBuffer(const uint buffer_index) const; protected: //--- Structure for storing buffer object buffer arrays struct SDataBuffer { double Array[]; }; //--- Array of (1) all indicator buffer object buffers, (2) color buffer, (3) for storing colors SDataBuffer DataBuffer[]; double ColorBufferArray[]; int ArrayColors[]; public:
从类的公开部分里删除目前尚不需要的数据和颜色数组:
public: //--- Array of the (1) drawn indicator buffer and (2) color buffer double DataArray[]; double ColorArray[];
在上一篇文章中,我把受保护的抽象缓冲区对象构造函数变作公开,从而我们能够从指标程序访问它。 现在将其封闭,以便在创建指定类型的指标缓冲区时能从类的派生对象里访问它。 只需将该行取消注释,然后在受保护的构造函数里添加几个新的变量,来澄清创建的缓冲区属性。 这些属性包括数据窗口中构造的缓冲区数量,线宽和缓冲区描述:
protected: //--- Protected parametric constructor CBuffer(ENUM_BUFFER_STATUS status_buffer, ENUM_BUFFER_TYPE buffer_type, const uint index_plot, const uint index_base_array, const int num_datas, const int width, const string label); public:
现在,我们已有了一个方法 SetColor() 来为指标缓冲区设置单一颜色。 不过,由于我们所有的缓冲区都要着色,所以我们还需要能够为现有缓冲区添加新的颜色,或者一次性为该缓冲区设置用到的所有颜色。
声明另外两个设置颜色的方法:
void SetColor(const color colour); void SetColor(const color colour,const uchar index); void SetColors(const color &array_colors[]); void SetEmptyValue(const double value); virtual void SetLabel(const string label);
第一个方法按指定索引将新颜色添加到缓冲区对象的颜色数组当中,而第二个方法能够为缓冲区对象设置全部用到的颜色,并把颜色数组传递给方法。
在返回缓冲区对象属性值的方法模块里,重命名 NumberColors() 方法,以便返回缓冲区用到的颜色数量,并添加返回绘制缓冲区对象数据所需缓冲区数组数量的方法:
//--- Return (1) the serial number of the drawn buffer, (2) bound array index, (3) color buffer index, //--- (4) index of the first free bound array, (5) buffer data period (timeframe) (6) buffer status, //--- (7) buffer type, (8) buffer usage flag, (9) arrow code, (10) arrow shift for DRAW_ARROW style, //--- (11) Number of initial bars that are not drawn and values in DataWindow, (12) graphical construction type, //--- (13) flag of displaying construction values in DataWindow, (14) indicator graphical construction shift along the time axis, //--- (15) drawing line style, (16) drawing line width, (17) number of colors, (18) drawing color, number of buffers for construction //--- (19) set empty value, (20) buffer symbol and (21) name of the indicator graphical series displayed in DataWindow int IndexPlot(void) const { return (int)this.GetProperty(BUFFER_PROP_INDEX_PLOT); } int IndexBase(void) const { return (int)this.GetProperty(BUFFER_PROP_INDEX_BASE); } int IndexColor(void) const { return (int)this.GetProperty(BUFFER_PROP_INDEX_COLOR); } int IndexNextBuffer(void) const { return (int)this.GetProperty(BUFFER_PROP_INDEX_NEXT); } ENUM_TIMEFRAMES Timeframe(void) const { return (ENUM_TIMEFRAMES)this.GetProperty(BUFFER_PROP_TIMEFRAME); } ENUM_BUFFER_STATUS Status(void) const { return (ENUM_BUFFER_STATUS)this.GetProperty(BUFFER_PROP_STATUS); } ENUM_BUFFER_TYPE TypeBuffer(void) const { return (ENUM_BUFFER_TYPE)this.GetProperty(BUFFER_PROP_TYPE); } bool IsActive(void) const { return (bool)this.GetProperty(BUFFER_PROP_ACTIVE); } uchar ArrowCode(void) const { return (uchar)this.GetProperty(BUFFER_PROP_ARROW_CODE); } int ArrowShift(void) const { return (int)this.GetProperty(BUFFER_PROP_ARROW_SHIFT); } int DrawBegin(void) const { return (int)this.GetProperty(BUFFER_PROP_DRAW_BEGIN); } ENUM_DRAW_TYPE DrawType(void) const { return (ENUM_DRAW_TYPE)this.GetProperty(BUFFER_PROP_DRAW_TYPE); } bool IsShowData(void) const { return (bool)this.GetProperty(BUFFER_PROP_SHOW_DATA); } int Shift(void) const { return (int)this.GetProperty(BUFFER_PROP_SHIFT); } ENUM_LINE_STYLE LineStyle(void) const { return (ENUM_LINE_STYLE)this.GetProperty(BUFFER_PROP_LINE_STYLE); } int LineWidth(void) const { return (int)this.GetProperty(BUFFER_PROP_LINE_WIDTH); } int ColorsTotal(void) const { return (int)this.GetProperty(BUFFER_PROP_COLOR_INDEXES); } color Color(void) const { return (color)this.GetProperty(BUFFER_PROP_COLOR); } int BuffersTotal(void) const { return (int)this.GetProperty(BUFFER_PROP_NUM_DATAS); } double EmptyValue(void) const { return this.GetProperty(BUFFER_PROP_EMPTY_VALUE); } string Symbol(void) const { return this.GetProperty(BUFFER_PROP_SYMBOL); } string Label(void) const { return this.GetProperty(BUFFER_PROP_LABEL); }
在返回缓冲区对象属性描述的方法模块里,添加返回指定缓冲区图形颜色描述的方法:
//--- Return descriptions of the (1) buffer status, (2) buffer type, (3) buffer usage flag, (4) flag of displaying construction values in DataWindow, //--- (5) drawing line style, (6) set empty value, (7) graphical construction type and (8) used timeframe and (9) specified colors string GetStatusDescription(bool draw_type=false)const; string GetTypeBufferDescription(void) const; string GetActiveDescription(void) const; string GetShowDataDescription(void) const; string GetLineStyleDescription(void) const; string GetEmptyValueDescription(void) const; string GetDrawTypeDescription(void) const; string GetTimeframeDescription(void) const; string GetColorsDescription(void) const;
在类主体的最后,添加处理缓冲区对象的方法模块:
//--- Return the size of the data buffer array virtual int GetDataTotal(const uint buffer_index=0) const; //--- Return the value from the specified index of the specified (1) data and (2) color buffer arrays virtual double GetDataBufferValue(const uint buffer_index,const uint series_index) const; virtual color GetColorBufferValue(const uint series_index) const; //--- Set the value to the specified index of the specified (1) data and (2) color buffer arrays virtual void SetBufferValue(const uint buffer_index,const uint series_index,const double value); virtual void SetBufferColorIndex(const uint series_index,const uchar color_index); //--- Initialize all object buffers by (1) a specified value, (2) the empty value specified for the object virtual void InitializeBuffers(const double value,const uchar color_index); virtual void InitializeBuffers(void); //--- Fill all data buffers with empty values in the specified timeseries index void ClearData(const int series_index); }; //+------------------------------------------------------------------+
该方法的实现将在以后研究。
封闭的参数类构造函数已修改:
//+------------------------------------------------------------------+ //| Closed parametric constructor | //+------------------------------------------------------------------+ CBuffer::CBuffer(ENUM_BUFFER_STATUS buffer_status, ENUM_BUFFER_TYPE buffer_type, const uint index_plot, const uint index_base_array, const int num_datas, const int width, const string label) { this.m_type=COLLECTION_BUFFERS_ID; //--- Save integer properties this.m_long_prop[BUFFER_PROP_STATUS] = buffer_status; this.m_long_prop[BUFFER_PROP_TYPE] = buffer_type; ENUM_DRAW_TYPE type= ( !this.TypeBuffer() || !this.Status() ? DRAW_NONE : this.Status()==BUFFER_STATUS_FILLING ? DRAW_FILLING : ENUM_DRAW_TYPE(this.Status()+8) ); this.m_long_prop[BUFFER_PROP_DRAW_TYPE] = type; this.m_long_prop[BUFFER_PROP_TIMEFRAME] = PERIOD_CURRENT; this.m_long_prop[BUFFER_PROP_ACTIVE] = true; this.m_long_prop[BUFFER_PROP_ARROW_CODE] = 0x9F; this.m_long_prop[BUFFER_PROP_ARROW_SHIFT] = 0; this.m_long_prop[BUFFER_PROP_DRAW_BEGIN] = 0; this.m_long_prop[BUFFER_PROP_SHOW_DATA] = (buffer_type>BUFFER_TYPE_CALCULATE ? true : false); this.m_long_prop[BUFFER_PROP_SHIFT] = 0; this.m_long_prop[BUFFER_PROP_LINE_STYLE] = STYLE_SOLID; this.m_long_prop[BUFFER_PROP_LINE_WIDTH] = width; this.m_long_prop[BUFFER_PROP_COLOR_INDEXES] = (this.Status()!=BUFFER_STATUS_FILLING ? 1 : 2); this.m_long_prop[BUFFER_PROP_COLOR] = clrRed; this.m_long_prop[BUFFER_PROP_NUM_DATAS] = num_datas; this.m_long_prop[BUFFER_PROP_INDEX_PLOT] = index_plot; this.m_long_prop[BUFFER_PROP_INDEX_BASE] = index_base_array; this.m_long_prop[BUFFER_PROP_INDEX_COLOR] = this.GetProperty(BUFFER_PROP_INDEX_BASE)+this.GetProperty(BUFFER_PROP_NUM_DATAS); this.m_long_prop[BUFFER_PROP_INDEX_NEXT] = this.GetProperty(BUFFER_PROP_INDEX_COLOR)+(this.Status()!=BUFFER_STATUS_FILLING ? 1 : 0); //--- Save real properties this.m_double_prop[this.IndexProp(BUFFER_PROP_EMPTY_VALUE)] = EMPTY_VALUE; //--- Save string properties this.m_string_prop[this.IndexProp(BUFFER_PROP_SYMBOL)] = ::Symbol(); this.m_string_prop[this.IndexProp(BUFFER_PROP_LABEL)] = (this.TypeBuffer()>BUFFER_TYPE_CALCULATE ? label : NULL); //--- If failed to change the size of the drawn buffer array, display the appropriate message indicating the string if(::ArrayResize(this.DataBuffer,(int)this.GetProperty(BUFFER_PROP_NUM_DATAS))==WRONG_VALUE) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_DRAWING_ARRAY_RESIZE),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",(string)::GetLastError()); //--- If failed to change the size of the color array, display the appropriate message indicating the string if(::ArrayResize(this.ArrayColors,(int)this.ColorsTotal())==WRONG_VALUE) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",(string)::GetLastError()); //--- For DRAW_FILLING, fill in the color array with two default colors if(this.Status()==BUFFER_STATUS_FILLING) { this.SetColor(clrBlue,0); this.SetColor(clrRed,1); } //--- Bind indicator buffers with arrays //--- In a loop by the number of drawn buffers int total=::ArraySize(DataBuffer); for(int i=0;i<total;i++) { //--- calculate the index of the next array and //--- bind the indicator buffer by the calculated index with the dynamic array //--- located by the i loop index in the DataBuffer array int index=(int)this.GetProperty(BUFFER_PROP_INDEX_BASE)+i; ::SetIndexBuffer(index,this.DataBuffer[i].Array,INDICATOR_DATA); //--- Set indexation flag as in the timeseries to all buffer arrays ::ArraySetAsSeries(this.DataBuffer[i].Array,true); } //--- Binding the color buffer with the array if(this.Status()!=BUFFER_STATUS_FILLING) { ::SetIndexBuffer((int)this.GetProperty(BUFFER_PROP_INDEX_COLOR),this.ColorBufferArray,INDICATOR_COLOR_INDEX); ::ArraySetAsSeries(this.ColorBufferArray,true); } //--- Set integer buffer parameters ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_TYPE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_TYPE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_CODE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_SHIFT)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_BEGIN,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_BEGIN)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHOW_DATA,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHOW_DATA)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHIFT)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_STYLE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_STYLE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_WIDTH,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_WIDTH)); this.SetColor((color)this.GetProperty(BUFFER_PROP_COLOR)); //--- Set real buffer parameters ::PlotIndexSetDouble((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_EMPTY_VALUE,this.GetProperty(BUFFER_PROP_EMPTY_VALUE)); //--- Set string buffer parameters ::PlotIndexSetString((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LABEL,this.GetProperty(BUFFER_PROP_LABEL)); } //+------------------------------------------------------------------+
设置缓冲区类型:
ENUM_DRAW_TYPE type=
(
!this.TypeBuffer() || !this.Status() ? DRAW_NONE :
this.Status()==BUFFER_STATUS_FILLING ? DRAW_FILLING :
ENUM_DRAW_TYPE(this.Status()+8)
);
this.m_long_prop[BUFFER_PROP_DRAW_TYPE] = type;
上一篇文章中详细讲述的 SetDrawType() 方法可令我们能够确定图形类型:
所有缓冲区均被着色。 为了设置绘图样式,检查传递给 SetDrawType() 方法的缓冲区状态和绘图类型,并根据其设置:不绘图;或设置两个价位间用颜色填充空间;或将状态枚举索引偏移 8 个单位,以便令常数值对应于来自绘图样式枚举的颜色缓冲区常数。
在类主体之外,实现该方法:
//+------------------------------------------------------------------+ //| Set the graphical construction type | //+------------------------------------------------------------------+ void CBuffer::SetDrawType(void) { ENUM_DRAW_TYPE type=(!this.TypeBuffer() || !this.Status() ? DRAW_NONE : this.Status()==BUFFER_STATUS_FILLING ? DRAW_FILLING : ENUM_DRAW_TYPE(this.Status()+8)); this.SetProperty(BUFFER_PROP_DRAW_TYPE,type); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_TYPE,type); } //+------------------------------------------------------------------+
如果缓冲区类型为 BUFFER_TYPE_CALCULATE(0) 或 BUFFER_STATUS_NONE(0),则绘图样式设置为“不绘图” 。 如果缓冲区状态为 BUFFER_STATUS_FILLING(用颜色填充),则设置相应的绘图样式。 所有剩余值简单地加 8。 该偏移指示彩色绘图样式的常数。
于此,在类构造函数里,我们用相同的方法来计算缓冲区类型。
SetDrawType() 方法暂时保留在类中。 貌似,只在创建对象时才需要将其完全删除。 而这无需进一步修改绘图类型。
暂时将它保留,万一很快找到其他方式呢。
线宽现在由构造函数参数传递,因此构造函数的值设为默认值,而所有图形构造类型的默认颜色数量设为一(排除 DRAW_FILLING)— 在此图形类型中始终仅用到两种颜色。 我们来设置它们:
this.m_long_prop[BUFFER_PROP_LINE_WIDTH] = width; this.m_long_prop[BUFFER_PROP_COLOR_INDEXES] = (this.Status()!=BUFFER_STATUS_FILLING ? 1 : 2);
绘图数据缓冲区的数量现在也要在构造函数参数里传递。我们来加上它们:
this.m_long_prop[BUFFER_PROP_NUM_DATAS] = num_datas; this.m_long_prop[BUFFER_PROP_INDEX_PLOT] = index_plot; this.m_long_prop[BUFFER_PROP_INDEX_BASE] = index_base_array; this.m_long_prop[BUFFER_PROP_INDEX_COLOR] = this.GetProperty(BUFFER_PROP_INDEX_BASE)+this.GetProperty(BUFFER_PROP_NUM_DATAS); this.m_long_prop[BUFFER_PROP_INDEX_NEXT] = this.GetProperty(BUFFER_PROP_INDEX_COLOR)+(this.Status()!=BUFFER_STATUS_FILLING ? 1 : 0);
为了计算下一个数组的索引,该值将分配为下一个缓冲区对象的第一个数据缓冲区数组,我们需要考虑到 DRAW_FILLING 图形缓冲区的构造类型不需要颜色缓冲区。 故此,应将颜色缓冲区从这种图形类型的缓冲区里排除,而这正是我在此所做的工作 — 对于所有图形类型,在计算颜色缓冲区索引值里加一,而在“颜色填充”的情况下则需加上 — 下一个缓冲区的索引已经等于对象中不存在的颜色缓冲区的已计算索引。
其余动作均在代码注释中讲述。
颜色现在要用相应的方法设置,因为在该方法中已直接为对象属性设置了颜色。 此外,随后按索引获得所需颜色并填充颜色数组:
//--- Set integer buffer parameters ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_TYPE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_TYPE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_CODE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_SHIFT)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_BEGIN,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_BEGIN)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHOW_DATA,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHOW_DATA)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHIFT)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_STYLE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_STYLE)); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_WIDTH,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_WIDTH)); this.SetColor((color)this.GetProperty(BUFFER_PROP_COLOR));
返回指标宽度描述和彩色线的方法已修改,现在返回整数型属性描述:
//+------------------------------------------------------------------+ //| Return description of a buffer's integer property | //+------------------------------------------------------------------+ string CBuffer::GetPropertyDescription(ENUM_BUFFER_PROP_INTEGER property) { return ( // ... Removed unnecessary strings // ... // ... property==BUFFER_PROP_LINE_STYLE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_LINE_STYLE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetLineStyleDescription() ) : property==BUFFER_PROP_LINE_WIDTH ? (this.Status()==BUFFER_STATUS_ARROW ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_ARROW_SIZE) : CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_LINE_WIDTH))+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_COLOR_INDEXES ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_COLOR_NUM)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_COLOR ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_COLOR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetColorsDescription() ) : property==BUFFER_PROP_INDEX_BASE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INDEX_BASE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : // ... // ... // ... Removed unnecessary strings "" ); } //+------------------------------------------------------------------+
为了返回线宽描述,需检查缓冲区状态。 如果此为箭头指标,则其中没有曲线 — 返回箭头大小。
若要返回颜色,现在利用 GetColorsDescription() 方法。 该方法返回所有用到的缓冲区颜色描述。 缓冲区本身将在下面讨论。
返回指定空值描述的方法现将设置 EMPTY_VALUE 的负数值作为缓冲区的“空值”:
//+------------------------------------------------------------------+ //| Return description of the set empty value | //+------------------------------------------------------------------+ string CBuffer::GetEmptyValueDescription(void) const { double value=fabs(this.EmptyValue()); return(value<EMPTY_VALUE ? ::DoubleToString(this.EmptyValue(),(this.EmptyValue()==0 ? 1 : 8)) : (this.EmptyValue()>0 ? "EMPTY_VALUE" : "-EMPTY_VALUE")); } //+------------------------------------------------------------------+
该方法返回为缓冲区对象设置的颜色描述:
//+------------------------------------------------------------------+ //| Return description of specified colors | //+------------------------------------------------------------------+ string CBuffer::GetColorsDescription(void) const { int total=this.ColorsTotal(); if(total==1) return ::ColorToString(this.Color(),true); string res=""; for(int i=0;i<total;i++) { res+=::ColorToString(this.ArrayColors[i],true)+(i<total-1 ? "," : ""); } return res; } //+------------------------------------------------------------------+
如果仅设置了一种颜色,则返回存储缓冲区对象属性颜色值的字符串描述,
如果颜色数组中包含若干种颜色,则在循环里用它们的描述组成字符串,并返回所获值。
返回缓冲区对象颜色数量的方法:
//+------------------------------------------------------------------+ //| Set the number of colors | //+------------------------------------------------------------------+ void CBuffer::SetColorNumbers(const int number) { if(number>IND_COLORS_TOTAL) return; int n=(this.Status()!=BUFFER_STATUS_FILLING ? number : 2); this.SetProperty(BUFFER_PROP_COLOR_INDEXES,n); ::ArrayResize(this.ArrayColors,n); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_COLOR_INDEXES,n); } //+------------------------------------------------------------------+
如果传递给该方法的数量超出最大可能数量,则退出该方法。
如果曲线绘制型不是 DRAW_FILLING,则用所传递数字设置数量,否则,将其设置为两个。
然后修改颜色数组的大小,并为缓冲区设置新值。
为缓冲区对象设置一个绘图颜色的方法:
//+------------------------------------------------------------------+ //| Set a single specified drawing color for the buffer | //+------------------------------------------------------------------+ void CBuffer::SetColor(const color colour) { if(this.Status()==BUFFER_STATUS_FILLING) return; this.SetColorNumbers(1); this.SetProperty(BUFFER_PROP_COLOR,colour); this.ArrayColors[0]=colour; ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_COLOR,0,this.ArrayColors[0]); } //+------------------------------------------------------------------+
如果绘图样式为 DRAW_FILLING,则退出方法 — 该绘图样式始终拥有两种颜色。
接下来,将颜色数量设置为一个,将缓冲区对象属性设置为所传递颜色,将传递的颜色写入唯一的颜色数组单元格,并设置指标缓冲区的颜色。
若要重新绘制指标线,为需要修改颜色的时间序列索引设置颜色索引(从已用到的颜色列表中)。
例如,如果我们使用三种颜色,则它们的索引分别为 0, 1, 2。 若要以三种颜色中的任何之一为指标线着色,简单地将所需颜色编号写入颜色缓冲区即可。 如果索引 0 存储蓝色,而索引 1 存储红色,则将颜色编号写到指标颜色缓冲区以便重新绘制指标线,写入 0 为蓝色,写入1 则为红色 。
为了能够修改缓冲区对象设置的颜色,我们需要将新颜色写入指定指标缓冲区颜色索引的方法。
为指定的颜色索引设置绘图颜色的方法:
//+------------------------------------------------------------------+ //| Set the drawing color to the specified color index | //+------------------------------------------------------------------+ void CBuffer::SetColor(const color colour,const uchar index) { if(index>IND_COLORS_TOTAL-1) return; if(index>this.ColorsTotal()-1) this.SetColorNumbers(index+1); this.ArrayColors[index]=colour; if(index==0) this.SetProperty(BUFFER_PROP_COLOR,(color)this.ArrayColors[0]); ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_COLOR,index,this.ArrayColors[index]); } //+------------------------------------------------------------------+
获得颜色和颜色索引的方法。
如果所传递的颜色索引超过了指标的颜色最大可用数量,则退出。
如果索引超出了缓冲区对象颜色的现有数量,则 为缓冲区对象设置新的颜色数量。
接下来,按指定索引将所传递颜色写到颜色数组之中。 如果传递的是零索引,则 为缓冲区颜色属性设置为传递给该方法的颜色,最后按传递给方法的索引在指标缓冲区里设置新的颜色值。
自传递的颜色数组为缓冲区对象设置颜色的方法:
//+------------------------------------------------------------------+ //| Set drawing colors from the color array | //+------------------------------------------------------------------+ void CBuffer::SetColors(const color &array_colors[]) { //--- Exit if the passed array is empty if(::ArraySize(array_colors)==0) return; //--- Copy the passed array to the array of buffer object colors ::ArrayCopy(this.ArrayColors,array_colors,0,0,IND_COLORS_TOTAL); //--- Exit if the color array was empty and not copied for some reason int total=::ArraySize(this.ArrayColors); if(total==0) return; //--- If the drawing style is not DRAW_FILLING if(this.Status()!=BUFFER_STATUS_FILLING) { //--- if the new number of colors exceeds the currently set one, //--- set the new value for the number of colors if(total>this.ColorsTotal()) this.SetColorNumbers(total); } //--- If the drawing style is DRAW_FILLING, set the number of colors equal to 2 else total=2; //--- Set the very first color from the color array (for a single color) to the buffer object color property this.SetProperty(BUFFER_PROP_COLOR,(color)this.ArrayColors[0]); //--- Set the new number of colors for the indicator buffer ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_COLOR_INDEXES,total); //--- In the loop by the new number of colors, set all colors by their indices for the indicator buffer for(int i=0;i<total;i++) ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_COLOR,i,this.ArrayColors[i]); } //+------------------------------------------------------------------+
所有方法代码均在注释里加以详细描述。
该方法返回所需缓冲区数组调整后的索引:
//+------------------------------------------------------------------+ //| Return the adjusted buffer array index | //+------------------------------------------------------------------+ int CBuffer::GetCorrectIndexBuffer(const uint buffer_index) const { return int(buffer_index<this.GetProperty(BUFFER_PROP_NUM_DATAS) ? buffer_index : this.GetProperty(BUFFER_PROP_NUM_DATAS)-1); } //+------------------------------------------------------------------+
由于指标缓冲区的所有数据数组现在都位于 SDataBuffer 结构类型的 DataBuffer[ ]数组之中,因此我们将利用方法调整传递来的错误数组索引,从而避免超出数组限制。
如果传递的索引小于构造缓冲区的总数,则返回所传递的索引。
在任何其他情况下,返回最后一个数组元素的索引。
如果是单个数组,则最后一个元素等于第一个元素。
该方法返回指定数据缓冲区数组的大小:
//+------------------------------------------------------------------+ //| Return the array size of the specified data buffer | //+------------------------------------------------------------------+ int CBuffer::GetDataTotal(const uint buffer_index=0) const { int index=this.GetCorrectIndexBuffer(buffer_index); return(index>WRONG_VALUE ? ::ArraySize(this.DataBuffer[index].Array) : 0); } //+------------------------------------------------------------------+
该方法更适用于调试和内部使用。
按其在 DataBuffer[] 数组中的索引,返回为指标缓冲区分配的数组大小。
OnInit() 始终收到零值。 OnCalculate() 接收 rates_total。
该方法按指定的时间序列索引返回指定的数据缓冲区值:
//+------------------------------------------------------------------+ //| Return the value from the specified timeseries index | //| of the specified data buffer array | //+------------------------------------------------------------------+ double CBuffer::GetDataBufferValue(const uint buffer_index,const uint series_index) const { int correct_buff_index=this.GetCorrectIndexBuffer(buffer_index); int data_total=this.GetDataTotal(correct_buff_index); if(data_total==0) return this.EmptyValue(); int data_index=((int)series_index<data_total ? (int)series_index : data_total-1); return this.DataBuffer[correct_buff_index].Array[data_index]; } //+------------------------------------------------------------------+
该方法按时间序列索引从指定的指标缓冲区里获取和接收数据。
首先,调整获得的所需缓冲区的索引,检查缓冲区中的数据量,如果数据不存在,返回为缓冲区对象所设置的空值 。 接下来,检查时间序列索引是否超出缓冲区中的数据量。 如果时间序列索引超出数组界限,则返回最后一个缓冲区元素,否则按时间序列索引返回来自指定缓冲区的数据。
按指定时间序列索引返回颜色缓冲区值的方法:
//+------------------------------------------------------------------+ //| Return the value from the specified timeseries index | //| of the specified color buffer array | //+------------------------------------------------------------------+ color CBuffer::GetColorBufferValue(const uint series_index) const { int data_total=this.GetDataTotal(0); if(data_total==0) return clrNONE; int data_index=((int)series_index<data_total ? (int)series_index : data_total-1); int color_index=(this.ColorsTotal()==1 ? 0 : (int)this.ColorBufferArray[data_index]); return (color)this.ArrayColors[color_index]; } //+------------------------------------------------------------------+
该方法与刚刚研究的方法几乎相同,只是我们始终只有一个颜色缓冲区,且不需要获取和调整所需缓冲区的索引。 在此,我们立即检查时间序列索引,并按调整后的索引(如果所传递索引无效)从缓冲区返回数据。
按指定时间序列索引为指定的数据缓冲区的设置数值的方法:
//+------------------------------------------------------------------+ //| Set the value to the specified timeseries index | //| for the specified data buffer array | //+------------------------------------------------------------------+ void CBuffer::SetBufferValue(const uint buffer_index,const uint series_index,const double value) { if(this.GetDataTotal(buffer_index)==0) return; int correct_buff_index=this.GetCorrectIndexBuffer(buffer_index); int data_total=this.GetDataTotal(buffer_index); int data_index=((int)series_index<data_total ? (int)series_index : data_total-1); this.DataBuffer[correct_buff_index].Array[data_index]=value; } //+------------------------------------------------------------------+
该方法与上述研究的按时间序列索引从指定缓冲区获取数据的方法相同。 不过,该方法将传递的数值按指定时间序列索引写入指定的数据缓冲区,替换了原来的返回数值。
按指定时间序列索引设置颜色缓冲区值的方法:
//+------------------------------------------------------------------+ //| Set the color index to the specified timeseries index | //| of the color buffer array | //+------------------------------------------------------------------+ void CBuffer::SetBufferColorIndex(const uint series_index,const uchar color_index) { if(this.GetDataTotal(0)==0 || color_index>this.ColorsTotal()-1 || this.Status()==BUFFER_STATUS_FILLING) return; int data_total=this.GetDataTotal(0); int data_index=((int)series_index<data_total ? (int)series_index : data_total-1); if(::ArraySize(this.ColorBufferArray)==0) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INVALID_PROPERTY_BUFF)); this.ColorBufferArray[data_index]=color_index; } //+------------------------------------------------------------------+
该方法与前述从指定时间序列索引中获取颜色索引的方法相同。 不过,该方法将传递的数值按指定时间序列索引写入指定的颜色缓冲区,替换了原来的返回数值。
此外,如果数据数组没有合适的数据(为空),或者所传递的颜色索引超过了颜色数组,或者缓冲区对象的绘制样式为 DRAW_FILLING(无颜色缓冲区),则离开方法 。
如果颜色缓冲区大小为零,则在 #property indicator_buffers 中设置的值很可能有误 — 显示相应的消息,然后显示数组超界且无法处理错误,由于日志记录允许我们在指标属性中正确设置缓冲区数目。
用指定数据和颜色缓冲区值初始化所有缓冲区对象缓冲区的方法:
//+------------------------------------------------------------------+ //| Initialize all object buffers by the specified value | //+------------------------------------------------------------------+ void CBuffer::InitializeBuffers(const double value,const uchar color_index) { for(int i=0;i<this.GetProperty(BUFFER_PROP_NUM_DATAS);i++) ::ArrayInitialize(this.DataBuffer[i].Array,value); if(this.Status()!=BUFFER_STATUS_FILLING) ::ArrayInitialize(this.ColorBufferArray,(color_index>this.ColorsTotal()-1 ? 0 : color_index)); } //+------------------------------------------------------------------+
循环遍历所有数据缓冲区列表,用指定的数值初始化每个数组。
如果缓冲区对象的绘制样式不是 DRAW_FILLING,则用指定的数值初始化颜色缓冲区,以防颜色数组超界导致退出。
采用为缓冲区对象指定的“空”值初始化所有缓冲区对象缓冲区数组的方法:
//+------------------------------------------------------------------+ //| Initialize all object buffers | //| by the empty value set for the object | //+------------------------------------------------------------------+ void CBuffer::InitializeBuffers(void) { for(int i=0;i<this.GetProperty(BUFFER_PROP_NUM_DATAS);i++) ::ArrayInitialize(this.DataBuffer[i].Array,this.EmptyValue()); if(this.Status()!=BUFFER_STATUS_FILLING) ::ArrayInitialize(this.ColorBufferArray,0); } //+------------------------------------------------------------------+
该方法与上面研究的方法相同,除了初始化值取自为对象设置的“空”值。 还有,最初的颜色索引用于初始化。
通常需要在填充指标之前,先要清除指标中所有缓冲区的值,以避免图形失真。
下一个方法是清除指定时间序列索引中的所有缓冲区。
用空值填充缓冲区对象的所有指标缓冲区的方法:
//+------------------------------------------------------------------+ //| Fill all data buffers with the empty value | //| in the specified timeseries index | //+------------------------------------------------------------------+ void CBuffer::ClearData(const int series_index) { for(int i=0;i<this.GetProperty(BUFFER_PROP_NUM_DATAS);i++) this.SetBufferValue(i,series_index,this.EmptyValue()); this.SetBufferColorIndex(series_index,0); } //+------------------------------------------------------------------+
循环遍历缓冲区对象的所有存在缓冲区数组,利用上面研究的 SetBufferValue() 方法,按指定时间序列索引为缓冲区对象写入设置的空值。 上面也提到过 SetBufferColorIndex() 方法,允许我们为指定的时间序列索引设置颜色索引。
旨在创建和操控抽象缓冲区对象类的派生对象的修改至此完毕。
通常情况下,几乎所有函数库对象都拥有相似的结构:存在一个通用的抽象对象,其派生对象共享其属性和方法,而每个派生对象都指定了抽象对象数据。 我曾在第一篇(抽象对象)和第二篇(衍生对象及其集合)文章里讲述过函数库对象的概念。
缓冲区对象也不例外。 每个此种对象都是具有其特定绘制样式的指标缓冲区。 对象是根据其绘画样式命名的。
第一个缓冲区对象具有 Arrows 绘制样式,并被相应命名。
在 \MQL5\Include\DoEasy\Objects\Indicators\ 里,创建含有 CBufferArrow 类的 BufferArrow.mqh 文件,其基类是 CBuffer 抽象缓冲区的对象:
//+------------------------------------------------------------------+ //| BufferArrow.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Buffer.mqh" //+------------------------------------------------------------------+ //| Buffer with the "Drawing with arrows" drawing style | //+------------------------------------------------------------------+ class CBufferArrow : public CBuffer { private: public: //--- Constructor CBufferArrow(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_ARROW,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Arrows") {} //--- Supported integer properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_INTEGER property); //--- Supported real properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_DOUBLE property); //--- Supported string properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_STRING property); //--- Display a short buffer description in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+
如我们所见,类清单里没有任何多余的内容。
声明虚方法,其一返回对象支持的整数型、实数型和字符串型属性的标志,其二显示缓冲区简述。
类构造函数接收需创建的指标绘制缓冲区的索引(所有指标缓冲区列表中的缓冲区序列号),和已创建的新缓冲区的第一个 double 数组实际关联的基本缓冲区数组的索引 。
构造函数初始化清单里含有父类受保护构造函数的初始化功能:
CBufferArrow(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_ARROW,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Arrows") {}
其中第一个参数为“绘制箭头样式的缓冲区”缓冲区状态,第二个参数为“彩色数据缓冲区”缓冲区类型。 另外,传递绘制缓冲区索引值和基本数组,需构造的缓冲区数量,线宽(此处的参数表示箭头大小),和显示在数据窗口中的图形序列的名称。 因此,在创建新缓冲区对象时,我们要将已创建缓冲区的类型及其参数告知基类。
该方法返回指示 缓冲区支持该整数型属性的标志:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferArrow::SupportProperty(ENUM_BUFFER_PROP_INTEGER property) { if(property==BUFFER_PROP_LINE_STYLE || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT)) return false; return true; } //+------------------------------------------------------------------+
如果将“线型”属性传递给方法,或此为已计算的缓冲区,而不是“缓冲区类型”,或“下一个绘制缓冲区索引”属性,则不予支持,并返回 false 。 在其他情况下,返回 true 。
该方法返回表示缓冲区支持该实数型属性的标志:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferArrow::SupportProperty(ENUM_BUFFER_PROP_DOUBLE property) { if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE) return false; return true; } //+------------------------------------------------------------------+
如果这是一个计算用缓冲区,则不支持任何实数型属性(只有一个实数型属性:“无任何内容绘制的空值”)— 返回 false 。 在其他情况下,返回 true。
该方法返回表示缓冲区支持字符串型属性的标志:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| string property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferArrow::SupportProperty(ENUM_BUFFER_PROP_STRING property) { if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE) return false; return true; } //+------------------------------------------------------------------+
如果这是计算用缓冲区,则不支持任何字符串型属性 — 返回 false。 在其他情况下,返回 true。
在日志里显示缓冲区对象简述的方法:
//+------------------------------------------------------------------+ //| Display short buffer description in the journal | //+------------------------------------------------------------------+ void CBufferArrow::PrintShort(void) { ::Print ( CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_BUFFER),"(",(string)this.IndexPlot(),"): ", this.GetStatusDescription(true)," ",this.Symbol()," ",TimeframeDescription(this.Timeframe()) ); } //+------------------------------------------------------------------+
该方法从 Buffer 头部创建字符串,该字符串指定绘制缓冲区索引(数据窗口中的缓冲区序列号),描述缓冲区状态(绘图样式),品种和时间帧。
例如,形式为:
Buffer(0): Drawing with arrows EURUSD H1
整个缓冲区对象类是“绘制箭头”类型。
在以下位置创建线状绘制样式,其为 CBufferLine 抽象缓冲区对象的新衍生类 \MQL5\Include\DoEasy\Objects\Indicators\BufferLine.mqh:
//+------------------------------------------------------------------+ //| BufferLine.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Buffer.mqh" //+------------------------------------------------------------------+ //| Buffer of the Line drawing style | //+------------------------------------------------------------------+ class CBufferLine : public CBuffer { private: public: //--- Constructor CBufferLine(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_LINE,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Line") {} //--- Supported integer properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_INTEGER property); //--- Supported real properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_DOUBLE property); //--- Supported string properties of a buffer virtual bool SupportProperty(ENUM_BUFFER_PROP_STRING property); //--- Display a short buffer description in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_INTEGER property) { if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT) ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_DOUBLE property) { if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| string property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_STRING property) { if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE) return false; return true; } //+------------------------------------------------------------------+ //| Display short buffer description in the journal | //+------------------------------------------------------------------+ void CBufferLine::PrintShort(void) { ::Print ( CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_BUFFER),"(",(string)this.IndexPlot(),"): ", this.GetStatusDescription(true)," ",this.Symbol()," ",TimeframeDescription(this.Timeframe()) ); } //+------------------------------------------------------------------+
与处理用缓冲区类相比,在类构造函数中,线形状态和线形图形序列名称被传递给初始化清单中的基本缓冲区对象构造函数。 其余参数与箭头缓冲区对象相同:
CBufferLine(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_LINE,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Line") {}
返回指示缓冲区支持整数型属性的标志的方法也已修改:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_INTEGER property) { if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT) ) return false; return true; } //+------------------------------------------------------------------+
如果这是“箭头代码”或“垂直箭头移位”属性,或者计算用缓冲区不是“缓冲区类型”或“下一个绘制缓冲区索引”属性 ,则不支持它,并返回 false。 在其他情况下,返回 true 。
在以下位置中创建 Section 绘图样式的 CBufferSection 抽象缓冲区对象的新衍生类 \MQL5\Include\DoEasy\Objects\Indicators\BufferSection.mqh。
只需进一步研究新类的构造函数和支持整数型属性的方法,因为其他所有内容都与已将述的两个类相同。
在类构造函数中,将线段状态和线段图形序列名称传递给初始化清单中的基本缓冲区对象构造函数。
CBufferSection(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_SECTION,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Section") {}
该方法返回指示 缓冲区支持该整数型属性的标志:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferSection::SupportProperty(ENUM_BUFFER_PROP_INTEGER property) { if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT) ) return false; return true; } //+------------------------------------------------------------------+
如果这是“箭头代码”或“垂直箭头移位”属性,或者计算用缓冲区不是“缓冲区类型”或“下一个绘制缓冲区索引”属性 ,则不支持它,并返回 false。 在其他情况下,返回 true 。
在以下位置创建“从零轴开始的直方图”绘制样式的 CBufferHistogram 抽象缓冲区对象的新衍生类 \MQL5\Include\DoEasy\Objects\Indicators\BufferHistogram.mqh。
在类构造函数中,“从零轴开始的直方图”状态,和直方图图形序列名称传递给 初始化清单,而直方图的线宽默认等于 2。
CBufferHistogram(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_HISTOGRAM,BUFFER_TYPE_DATA,index_plot,index_base_array,1,2,"Histogram") {}
其余方法与 Section 缓冲区对象类相同。
在以下位置创建“两个指标缓冲区上的直方图”绘制样式的 CBufferHistogram2 抽象缓冲区对象的新衍生类 \MQL5\Include\DoEasy\Objects\Indicators\BufferHistogram2.mqh。
在类构造函数中,“两个指标缓冲区上的</ s2>直方图”状态,“直方图2 0;直方图2 1” 图形序列名称,和两个构造缓冲区被传递给初始化清单中的基本缓冲区对象构造函数。 直方图的线宽默认等于 8。。
CBufferHistogram2(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_HISTOGRAM2,BUFFER_TYPE_DATA,index_plot,index_base_array,2,8,"Histogram2 0;Histogram2 1") {}
为什么直方图的线宽等于 8?
在 MQL5 里,即在基于两个缓冲区的直方图指标中,这是直方图的最大列宽,具体取决于水平图表的比例:
在最大图表比例(5)下,直方图列宽具有最大值。 若您需要较小的宽度,在创建缓冲区后使用 SetWidth() 方法设置新的宽度值。
为什么会有“直方图2 0;直方图2 1” 这样的图形序列名称?
在使用多个缓冲区构造的指标中,每个缓冲区的名称在图形序列名称中指定。 若您需要为每个缓冲区设置唯一的名称,在指定图形序列名称时用分号(;)分隔。
在此,为第一个缓冲区设置名称 “Histogram2 0”(零表示第一个缓冲区索引),而第二个缓冲区名为“ Histogram2 1”(一表示第二个缓冲区索引)。
在数据窗口里如下所示:
如有必要,可在创建缓冲区后利用 SetLabel() 方法设置新的缓冲区名称。
其余方法与 Section 缓冲区对象类相同。
在以下位置创建 Zigzag 绘图样式的 CBufferZigZag 抽象缓冲区对象的新衍生类: \MQL5\Include\DoEasy\Objects\Indicators\BufferZigZag.mqh。
在类构造函数中, Zigzag 状态,“ ZigZag 0;ZigZag 1” 图形序列名称和两个构造缓冲区被传递给初始化清单里的基本缓冲区对象构造函数。 之字折线线宽默认等于 1 。
CBufferZigZag(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_ZIGZAG,BUFFER_TYPE_DATA,index_plot,index_base_array,2,1,"ZigZag 0;ZigZag 1") {}
其余方法与 Section 缓冲区对象类相同。
在以下位置创建 CBufferFilling 抽象缓冲区对象的新衍生类,该对象的绘画风格为“两个级别之间填充颜色” \MQL5\Include\DoEasy\Objects\Indicators\BufferFilling.mqh。
在类构造函数中,“两个级别之间填充颜色”状态,“填充 0;填充 1”图形序列名称,和两个构造缓冲区传递给初始化清单中的基本缓冲区对象构造函数。 默认情况下,线宽等于 1(此绘图样式无需画线,因此该属性无关紧要)。
CBufferFilling(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_FILLING,BUFFER_TYPE_DATA,index_plot,index_base_array,2,1,"Filling 0;Filling 1") {}
该方法返回指示缓冲区支持该整数型属性的标志:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferFilling::SupportProperty(ENUM_BUFFER_PROP_INTEGER property) { if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || property==BUFFER_PROP_LINE_STYLE || property==BUFFER_PROP_LINE_WIDTH || property==BUFFER_PROP_INDEX_COLOR || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT) ) return false; return true; } //+------------------------------------------------------------------+
如果这是“箭头代码”,“垂直箭头偏移”,“线型”,“线宽”属性,颜色缓冲区索引,或不是“缓冲区类型”的计算用缓冲区,或“下一个绘制的缓冲区索引”属性,则不支持该属性,并返回 false。 在其他情况下,返回 true 。
其余方法与 Section 缓冲区对象类相同。
在以下位置创建“显示柱线”绘图样式的 CBufferBars 抽象缓冲对象的新衍生类 \MQL5\Include\DoEasy\Objects\Indicators\BufferBars.mqh。
在类构造函数中,“显示为柱线”状态,“柱线开盘;柱线最高价;;柱线最低价条;柱线收盘价”图形序列名称,和四个构造缓冲区传递给初始化清单中的基本缓冲区对象构造函数。 默认情况下,柱线宽度等于 2。。
CBufferBars(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_BARS,BUFFER_TYPE_DATA,index_plot,index_base_array,4,2,"Bar Open;Bar High;Bar Low;Bar Close") {}
该方法返回指示缓冲区支持该整数型属性的标志:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferBars::SupportProperty(ENUM_BUFFER_PROP_INTEGER property) { if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || property==BUFFER_PROP_LINE_STYLE || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT) ) return false; return true; } //+------------------------------------------------------------------+
如果这是“箭头代码”,“垂直箭头偏移”,或“线形样式”属性,或计算用缓冲区,而不是“缓冲区类型”或“下一个绘制的缓冲区索引” 属性,则不支持它,并返回 false。 在其他情况下,返回 true 。
其余方法与 Section 缓冲区对象类相同。
在以下位置创建“显示为蜡烛”绘图样式的 CBufferCandles 抽象缓冲区对象的新衍生类 \MQL5\Include\DoEasy\Objects\Indicators\BufferCandles.mqh。
在类构造函数中,“”显示为蜡烛“状态,和”蜡烛开盘价;蜡烛最高价;蜡烛最低价;蜡烛收盘价”图形序列名称,和四个构造缓冲区传递给初始化清单中的基本缓冲区对象构造函数。 默认情况下,蜡烛宽度等于 1(该参数不会影响实际图形宽度,因为蜡烛宽度始终等于图表蜡烛宽度,具体取决于其水平比例)。
CBufferCandles(const uint index_plot,const uint index_base_array) : CBuffer(BUFFER_STATUS_CANDLES,BUFFER_TYPE_DATA,index_plot,index_base_array,4,1,"Candle Open;Candle High;Candle Low;Candle Close") {}
该方法返回指示缓冲区支持该整数型属性的标志:
//+------------------------------------------------------------------+ //| Return 'true' if a buffer supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CBufferCandles::SupportProperty(ENUM_BUFFER_PROP_INTEGER property) { if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || property==BUFFER_PROP_LINE_STYLE || property==BUFFER_PROP_LINE_WIDTH || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT) ) return false; return true; } //+------------------------------------------------------------------+
如果这是“箭头代码”,“垂直箭头平移”,“线条样式”或“线条宽度” 属性,或这是计算用缓冲区,而不是“缓冲区类型” 或“下一个绘制的缓冲区索引”属性,则不支持该属性,并返回 false。 在其他情况下,返回 true 。
其余方法与 Section 缓冲区对象类相同。
抽象缓冲区对象的所有衍生缓冲区对象类均已创建完毕。
在文后的附件文件里可找到这些类的完整清单。
与其引入管理图表上显示缓冲区线条的按钮,不如我们在指标设置中设置必要的图形构造。 我们能够选择要显示的缓冲区,再启动指标。
为了能够选择必要的图形构造,将新的枚举添加到输入枚举文件 \MQL5\Include\DoEasy\InpDatas.mqh 里,来表示英语和俄语编译语言:
//+------------------------------------------------------------------+ //| InpDatas.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" //+------------------------------------------------------------------+ //| Macro substitutions | //+------------------------------------------------------------------+ #define COMPILE_EN // Comment out the string for compilation in Russian //+------------------------------------------------------------------+ //| Input enumerations | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| English language inputs | //+------------------------------------------------------------------+ #ifdef COMPILE_EN //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work only with the current Symbol SYMBOLS_MODE_DEFINES, // Work with a given list of Symbols SYMBOLS_MODE_MARKET_WATCH, // Working with Symbols from the "Market Watch" window SYMBOLS_MODE_ALL // Work with a complete list of Symbols }; //+------------------------------------------------------------------+ //| Mode of working with timeframes | //+------------------------------------------------------------------+ enum ENUM_TIMEFRAMES_MODE { TIMEFRAMES_MODE_CURRENT, // Work only with the current timeframe TIMEFRAMES_MODE_LIST, // Work with a given list of timeframes TIMEFRAMES_MODE_ALL // Work with a complete list of timeframes }; //+------------------------------------------------------------------+ //| "Yes"/"No" | //+------------------------------------------------------------------+ enum ENUM_INPUT_YES_NO { INPUT_NO = 0, // No INPUT_YES = 1 // Yes }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Russian language inputs | //+------------------------------------------------------------------+ #else //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Работа только с текущим символом SYMBOLS_MODE_DEFINES, // Работа с заданным списком символов SYMBOLS_MODE_MARKET_WATCH, // Работа с символами из окна "Обзор рынка" SYMBOLS_MODE_ALL // Работа с полным списком символов }; //+------------------------------------------------------------------+ //| Mode of working with timeframes | //+------------------------------------------------------------------+ enum ENUM_TIMEFRAMES_MODE { TIMEFRAMES_MODE_CURRENT, // Работа только с текущим таймфреймом TIMEFRAMES_MODE_LIST, // Работа с заданным списком таймфреймов TIMEFRAMES_MODE_ALL // Работа с полным списком таймфреймов }; //+------------------------------------------------------------------+ //| "Yes"/"No" | //+------------------------------------------------------------------+ enum ENUM_INPUT_YES_NO { INPUT_NO = 0, // Нет INPUT_YES = 1 // Да }; //+------------------------------------------------------------------+ #endif //+------------------------------------------------------------------+
这在设置中提供了选择:
若要执行测试,我们将借用上一篇文章中的指标,并将其保存在 \MQL5\Indicators\TestDoEasy\Part43\ 之下,命名为 TestDoEasyPart43.mq5。
将所有已创建缓冲区的文件包含到指标文件当中,将已用缓冲区的数量设置为 27,而绘制缓冲区数量设置为 9:
//+------------------------------------------------------------------+ //| TestDoEasyPart43.mq5 | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //--- includes #include <DoEasy\Engine.mqh> #include <DoEasy\Objects\Indicators\BufferArrow.mqh> // 1 construction buffer + 1 color buffer #include <DoEasy\Objects\Indicators\BufferLine.mqh> // 1 construction buffer + 1 color buffer #include <DoEasy\Objects\Indicators\BufferSection.mqh> // 1 construction buffer + 1 color buffer #include <DoEasy\Objects\Indicators\BufferHistogram.mqh> // 1 construction buffer + 1 color buffer #include <DoEasy\Objects\Indicators\BufferHistogram2.mqh> // 2 construction buffers + 1 color buffer #include <DoEasy\Objects\Indicators\BufferZigZag.mqh> // 2 construction buffers + 1 color buffer #include <DoEasy\Objects\Indicators\BufferFilling.mqh> // 2 construction buffers + 1 color buffer #include <DoEasy\Objects\Indicators\BufferBars.mqh> // 4 construction buffer + 1 color buffer #include <DoEasy\Objects\Indicators\BufferCandles.mqh> // 4 construction buffer + 1 color buffer //--- In total: 18 construction buffers + 9 color buffers: 27 indicator buffers, of which 9 are drawn ones //--- properties #property indicator_chart_window #property indicator_buffers 27 #property indicator_plots 9
在输入模块里,注释掉 sinput 修饰符,以便选择品种的操控方式(默认情况下为当前),从设置中隐藏已用品种的列表 ,默认设置选择当前工作时间帧模式,从设置中隐藏所用的时间帧列表,并添加选择在哪个缓冲区上显示设置中的图表的功能:
//--- classes //--- enums //--- defines //--- structures //--- input variables /*sinput*/ ENUM_SYMBOLS_MODE InpModeUsedSymbols= SYMBOLS_MODE_CURRENT; // Mode of used symbols list /*sinput*/ string InpUsedSymbols = "EURUSD,AUDUSD,EURAUD,EURGBP,EURCAD,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY"; // List of used symbols (comma - separator) /*sinput*/ ENUM_TIMEFRAMES_MODE InpModeUsedTFs = TIMEFRAMES_MODE_CURRENT; // Mode of used timeframes list /*sinput*/ string InpUsedTFs = "M1,M5,M15,M30,H1,H4,D1,W1,MN1"; // List of used timeframes (comma - separator) sinput ENUM_INPUT_YES_NO InpDrawArrow = INPUT_YES; // Draw Arrow sinput ENUM_INPUT_YES_NO InpDrawLine = INPUT_NO; // Draw Line sinput ENUM_INPUT_YES_NO InpDrawSection = INPUT_NO; // Draw Section sinput ENUM_INPUT_YES_NO InpDrawHistogram = INPUT_NO; // Draw Histogram sinput ENUM_INPUT_YES_NO InpDrawHistogram2 = INPUT_NO; // Draw Histogram2 sinput ENUM_INPUT_YES_NO InpDrawZigZag = INPUT_NO; // Draw ZigZag sinput ENUM_INPUT_YES_NO InpDrawFilling = INPUT_NO; // Draw Filling sinput ENUM_INPUT_YES_NO InpDrawBars = INPUT_NO; // Draw Bars sinput ENUM_INPUT_YES_NO InpDrawCandles = INPUT_YES; // Draw Candles sinput bool InpUseSounds = true; // Use sounds
添加指向 CObject 实例的动态指针数组的声明,代替声明若干个 double 指标缓冲区数组。 该列表存储为测试而创建的指标缓冲区对象:
//--- indicator buffers CArrayObj list_buffers; // Temporary list for storing buffer objects //--- global variables CEngine engine; // CEngine library main object string prefix; // Prefix of graphical object names int min_bars; // The minimum number of bars for the indicator calculation int used_symbols_mode; // Mode of working with symbols string array_used_symbols[]; // The array for passing used symbols to the library string array_used_periods[]; // The array for passing used timeframes to the library //+------------------------------------------------------------------+
在指标的 OnInit() 应答程序中,创建所有缓冲区对象,将它们添加到列表之中,设置非默认颜色(三种颜色),并在日志里显示每个所创建缓冲区对象的数据:
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Initialize DoEasy library OnInitDoEasy(); //--- Set indicator global variables prefix=engine.Name()+"_"; //--- Get the index of the maximum used timeframe in the array, //--- calculate the number of bars of the current period fitting in the maximum used period //--- Use the obtained value if it exceeds 2, otherwise use 2 int index=ArrayMaximum(ArrayUsedTimeframes); int num_bars=NumberBarsInTimeframe(ArrayUsedTimeframes[index]); min_bars=(index>WRONG_VALUE ? (num_bars>2 ? num_bars : 2) : 2); //--- Check and remove remaining indicator graphical objects if(IsPresentObectByPrefix(prefix)) ObjectsDeleteAll(0,prefix); //--- Create the button panel //--- Check playing a standard sound using macro substitutions engine.PlaySoundByDescription(SND_OK); //--- Wait for 600 milliseconds engine.Pause(600); engine.PlaySoundByDescription(SND_NEWS); //--- indicator buffers mapping //--- Create all buffer objects CBuffer *buffer0=new CBufferArrow(0,0); CBuffer *buffer1=new CBufferLine(1,buffer0.IndexNextBuffer()); CBuffer *buffer2=new CBufferSection(2,buffer1.IndexNextBuffer()); CBuffer *buffer3=new CBufferHistogram(3,buffer2.IndexNextBuffer()); CBuffer *buffer4=new CBufferHistogram2(4,buffer3.IndexNextBuffer()); CBuffer *buffer5=new CBufferZigZag(5,buffer4.IndexNextBuffer()); CBuffer *buffer6=new CBufferFilling(6,buffer5.IndexNextBuffer()); CBuffer *buffer7=new CBufferBars(7,buffer6.IndexNextBuffer()); CBuffer *buffer8=new CBufferCandles(8,buffer7.IndexNextBuffer()); //--- Add buffers to the list of indicator buffers list_buffers.Add(buffer0); list_buffers.Add(buffer1); list_buffers.Add(buffer2); list_buffers.Add(buffer3); list_buffers.Add(buffer4); list_buffers.Add(buffer5); list_buffers.Add(buffer6); list_buffers.Add(buffer7); list_buffers.Add(buffer8); //--- Create color array color array_colors[]={clrDodgerBlue,clrRed,clrGray}; //--- Set non-default buffer color values for(int i=0;i<list_buffers.Total();i++) { CBuffer *buff=list_buffers.At(i); buff.SetColors(array_colors); //--- Print data on the next buffer buff.Print(); } //--- Set the label size for the arrow buffer and the line width for ZigZag buffer0.SetWidth(2); buffer5.SetWidth(2); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
在 OnCalculate() 应答程序里
当初始化或更改历史数据时,初始化所有已创建缓冲区,并显示其简称。
在新柱线或当前即时报价上,将价格值写入缓冲区:
单一缓冲区 — 收盘价格,
两个缓冲区 — 第一个是开盘价,而第二个是收盘价
四个缓冲区 — 在每个缓冲区里写入相应的 OHLC 价格:
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //+------------------------------------------------------------------+ //| OnCalculate code block for working with the library: | //+------------------------------------------------------------------+ //--- Pass the current symbol data from OnCalculate() to the price structure CopyData(rates_total,prev_calculated,time,open,high,low,close,tick_volume,volume,spread); //--- Check for the minimum number of bars for calculation if(rates_total<min_bars || Point()==0) return 0; //--- Handle the Calculate event in the library //--- If the OnCalculate() method of the library returns zero, not all timeseries are ready - leave till the next tick if(engine.0) return 0; //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(rates_data); // Working in the library timer EventsHandling(); // Working with library events } //+------------------------------------------------------------------+ //| OnCalculate code block for working with the indicator: | //+------------------------------------------------------------------+ //--- Set OnCalculate arrays as timeseries ArraySetAsSeries(open,true); ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(close,true); ArraySetAsSeries(time,true); ArraySetAsSeries(tick_volume,true); ArraySetAsSeries(volume,true); ArraySetAsSeries(spread,true); //--- Check and calculate the number of calculated bars //--- If limit = 0, there are no new bars - calculate the current one //--- If limit = 1, a new bar has appeared - calculate the first and the current ones //--- limit > 1 means the first launch or changes in history - the full recalculation of all data int limit=rates_total-prev_calculated; //--- Recalculate the entire history if(limit>1) { //--- In a loop by the number of buffers in the list for(int i=0;i<list_buffers.Total();i++) { //--- get the next buffer and display the type of its graphical construction to the journal //--- together with the double array assigned to the buffer (if all is correct, the size is equal to rates_total) CBuffer *buff=list_buffers.At(i); buff.PrintShort(); buff.InitializeBuffers(); } limit=rates_total-1; } //--- Prepare data //--- Calculate the indicator for(int i=limit; i>WRONG_VALUE && !IsStopped(); i--) { //--- In a loop by the number of buffers in the list for(int j=0;j<list_buffers.Total();j++) { //--- get the next buffer and CBuffer *buff=list_buffers.At(j); //--- clear its current data buff.ClearData(0); //--- If drawing is not used, move on to the next one if(!IsUse(buff.Status())) continue; //--- Depending on the number of buffers, fill them with price data //--- one buffer if(buff.BuffersTotal()==1) buff.SetBufferValue(0,i,close[i]); //--- two buffers - the first one is to store the bar open price, while the second one is to store the bar close price else if(buff.BuffersTotal()==2) { buff.SetBufferValue(0,i,open[i]); buff.SetBufferValue(1,i,close[i]); } //--- four buffers - each buffer is to store OHLC bar prices else if(buff.BuffersTotal()==4) { buff.SetBufferValue(0,i,open[i]); buff.SetBufferValue(1,i,high[i]); buff.SetBufferValue(2,i,low[i]); buff.SetBufferValue(3,i,close[i]); } //--- Set the buffer color depending on the candle direction if(open[i]<close[i]) buff.SetBufferColorIndex(i,0); else if(open[i]>close[i]) buff.SetBufferColorIndex(i,1); else buff.SetBufferColorIndex(i,2); } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
我们用以下函数来定义是否启用绘制指标线:
//+---------------------------------------------------------------------+ //| Return the flag indicating the appropriate drawing style is enabled | //+---------------------------------------------------------------------+ bool IsUse(const ENUM_BUFFER_STATUS status) { switch(status) { case BUFFER_STATUS_FILLING : return (bool)InpDrawFilling; case BUFFER_STATUS_LINE : return (bool)InpDrawLine; case BUFFER_STATUS_HISTOGRAM : return (bool)InpDrawHistogram; case BUFFER_STATUS_ARROW : return (bool)InpDrawArrow; case BUFFER_STATUS_SECTION : return (bool)InpDrawSection; case BUFFER_STATUS_HISTOGRAM2 : return (bool)InpDrawHistogram2; case BUFFER_STATUS_ZIGZAG : return (bool)InpDrawZigZag; case BUFFER_STATUS_BARS : return (bool)InpDrawBars; case BUFFER_STATUS_CANDLES : return (bool)InpDrawCandles; default: return false; } } //+------------------------------------------------------------------+
该函数接收缓冲区状态,并返回与传递给该函数的状态相对应的输入值。
完整的指标代码在下面的文件中提供。
编译指标,并在图表上启动它。
在初始化期间,日志显示已创建的九个指标缓冲区的所有属性:
Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.) 10425.23 USD, 1:100, Hedge, MetaTrader 5 demo --- Initializing "DoEasy" library --- Working with the current symbol only: "EURUSD" Working with the current timeframe only: H1 EURUSD symbol timeseries: - Timeseries "EURUSD" H1: Requested: 1000, Actual: 0, Created: 0, On the server: 0 Library initialization time: 00:00:00.156 ============= Parameter list start: Colored data buffer[0] "Drawing with arrows" ================== Plotted buffer serial number: 0 Buffer status: Indicator buffer with graphical construction type "Drawing with arrows" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Drawing with arrows Arrow code: 159 The vertical shift of the arrows: 0 Arrow size: 1 The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 1 Base data buffer index: 0 Color buffer index: 1 Index of the array to be assigned as the next indicator buffer: 2 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Arrows ================== Parameter list end: Colored data buffer[0] "Drawing with arrows" ================== ============= Parameter list start: Colored data buffer[1] "Line" ================== Plotted buffer serial number: 1 Buffer status: Indicator buffer with graphical construction type "Line" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Line Line style: Solid line Line width: 1 The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 1 Base data buffer index: 2 Color buffer index: 3 Index of the array to be assigned as the next indicator buffer: 4 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Line ================== Parameter list end: Colored data buffer[1] "Line" ================== ============= Parameter list start: Colored data buffer[2] "Section" ================== Plotted buffer serial number: 2 Buffer status: Indicator buffer with graphical construction type "Section" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Section Line style: Solid line Line width: 1 The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 1 Base data buffer index: 4 Color buffer index: 5 Index of the array to be assigned as the next indicator buffer: 6 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Section ================== Parameter list end: Colored data buffer[2] "Section" ================== ============= Parameter list start: Colored data buffer[3] "Histogram from the zero line" ================== Plotted buffer serial number: 3 Buffer status: Indicator buffer with graphical construction type "Histogram from the zero line" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Histogram from the zero line Line style: Solid line Line width: 2 The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 1 Base data buffer index: 6 Color buffer index: 7 Index of the array to be assigned as the next indicator buffer: 8 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Histogram ================== Parameter list end: Colored data buffer[3] "Histogram from the zero line" ================== ============= Parameter list start: Colored data buffer[4] "Histogram on two indicator buffers" ================== Plotted buffer serial number: 4 Buffer status: Indicator buffer with graphical construction type "Histogram on two indicator buffers" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Histogram on two indicator buffers Line style: Solid line Line width: 8 The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 2 Base data buffer index: 8 Color buffer index: 10 Index of the array to be assigned as the next indicator buffer: 11 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Histogram2 0;Histogram2 1 ================== Parameter list end: Colored data buffer[4] "Histogram on two indicator buffers" ================== ============= Parameter list start: Colored data buffer[5] "Zigzag" ================== Plotted buffer serial number: 5 Buffer status: Indicator buffer with graphical construction type "Zigzag" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Zigzag Line style: Solid line Line width: 1 The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 2 Base data buffer index: 11 Color buffer index: 13 Index of the array to be assigned as the next indicator buffer: 14 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: ZigZag 0;ZigZag 1 ================== Parameter list end: Colored data buffer[5] "Zigzag" ================== ============= Parameter list start: Colored data buffer[6] "Color filling between two levels" ================== Plotted buffer serial number: 6 Buffer status: Indicator buffer with graphical construction type "Color filling between two levels" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Color filling between two levels The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 2 Drawing color: clrDodgerBlue,clrRed Number of data buffers: 2 Base data buffer index: 14 Index of the array to be assigned as the next indicator buffer: 16 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Filling 0;Filling 1 ================== Parameter list end: Colored data buffer[6] "Color filling between two levels" ================== ============= Parameter list start: Colored data buffer[7] "Display as bars" ================== Plotted buffer serial number: 7 Buffer status: Indicator buffer with graphical construction type "Display as bars" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Display as bars Line width: 2 The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 4 Base data buffer index: 16 Color buffer index: 20 Index of the array to be assigned as the next indicator buffer: 21 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Bar Open;Bar High;Bar Low;Bar Close ================== Parameter list end: Colored data buffer[7] "Display as bars" ================== ============= Parameter list start: Colored data buffer[8] "Display as candles" ================== Plotted buffer serial number: 8 Buffer status: Indicator buffer with graphical construction type "Display as candles" Buffer type: Colored data buffer Buffer data period (timeframe): Current chart period (H1) Active: Yes Graphical construction type: Display as candles The number of initial bars that are not drawn and values in DataWindow: 0 Display construction values in DataWindow: Yes Indicator graphical construction shift by time axis in bars: 0 Number of colors: 3 Drawing color: clrDodgerBlue,clrRed,clrGray Number of data buffers: 4 Base data buffer index: 21 Color buffer index: 25 Index of the array to be assigned as the next indicator buffer: 26 ------ Empty value for plotting where nothing will be drawn: EMPTY_VALUE ------ Buffer symbol: EURUSD Name of the graphical indicator series displayed in DataWindow: Candle Open;Candle High;Candle Low;Candle Close ================== Parameter list end: Colored data buffer[8] "Display as candles" ==================
首次启动后,初始化函数库和所有指标缓冲区时,会在日志中输出以下记录:
"EURUSD" H1 timeseries created successfully: - Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6230 Buffer(0): Drawing with arrows EURUSD H1 Buffer(1): EURUSD H1 line Buffer(2): EURUSD H1 sections Buffer(3): Histogram from the zero line EURUSD H1 Buffer(4): Histogram on two indicator buffers EURUSD H1 Buffer(5): EURUSD H1 zigzag Buffer(6): Color filling between two levels EURUSD H1 Buffer(7): Display as EURUSD H1 bars Buffer(8): Display as EURUSD H1 candles
我们切换权限,从而在设置中显示指标线:
在下一篇文章中,我们将开始创建指标缓冲区的集合类。 当创建指标缓冲区并用函数库开发自定义指标程序时,以及在创建指标缓冲区并将其用于任何品种和图表周期时,该类提供了最大的灵活性和便利性。
以下附件是函数库当前版本的所有文件,以及测试 EA 文件,供您测试和下载。
将您的问题、评论和建议留在评论中。
请记住,此处我已经为 MetaTrader 5 开发了 MQL5 测试指标。
附件仅适用于 MetaTrader 5。 当前函数库版本尚未在 MetaTrader 4 里进行测试。
创建并测试指标缓冲区集合后,我将尝试在 MetaTrader 4 中实现一些 MQL5 功能。
返回内容目录
该系列中的先前文章:
DoEasy 函数库中的时间序列(第三十五部分):柱线对象和品种时间序列列表
DoEasy 函数库中的时间序列(第三十六部分):所有用到的品种周期的时间序列对象
DoEasy 函数库中的时间序列(第三十七部分):时间序列集合 - 按品种和周期的时间序列数据库
DoEasy 函数库中的时间序列(第三十八部分):时间序列集合 - 实时更新以及从程序访问数据
DoEasy 函数库中的时间序列(第三十九部分):基于函数库的指标 - 准备数据和时间序列事件
DoEasy 函数库中的时间序列(第四十部分):基于函数库的指标 - 实时刷新数据
DoEasy 函数库中的时间序列(第四十一部分):多品种多周期指标样品
DoEasy 函数库中的时间序列(第四十二部分):抽象指标缓冲区对象类
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程