今天,我会完成多品种、周期标准指标对象的创建。 顶重要的是,我留下了一个很好的创建 Ichimoku Kinko Hyo 指标的例子。 为了绘制它,我们不仅需要创建显示在终端数据窗口中的所有重要缓冲区,还需要添加两个额外的缓冲区,在其两条线 “Senkou Span A” 和 “Senkou Span B” 之间的区域上绘制两个直方图。 为此,每个直方图都必须重复其相关曲线的样式和颜色。
创建此类指标会是一个很好的示例,示意如何利用函数库创建自己的复合自定义指标。
最后,我将为 MetaTrader5 终端的全套标准指标创建一个多品种、多期指标的最后一个对象 — 比尔·威廉姆斯的鳄鱼(Gator)振荡器指标,它是基于威廉的另一个指标鳄嘴(Alligator),在上一篇文章中曾研究过。
鉴于我们能够创建任何复杂度的指标,其中可能包含各种图形类型的各种曲线,以及与之对应的缓冲区对象,但所有这些缓冲区都只属于一个指标对象,故我们必须为缓冲区对象引入另一个属性 - - 附加指标曲线的编号(依其设计,绘制附加指标曲线的辅助缓冲区)。 因此,按该曲线编号,我们能准确判断任何指标对象所需的辅助曲线(缓冲区对象)。
例如,如果我们希望指标绘制移动平均线,从而显示其主线的某些状态,例如曲线与价格交叉,与其他指标的曲线交叉,等等,我们可以在自定义指标中添加一个或若干个缓冲对象,然后 通过此缓冲区在图表上显示所需时刻的所需数据 - 放置箭头,在区域上绘图,等等。
首先,在文件 \MQL5\Include\DoEasy\Data.mqh 里输入新的函数库文本消息。
添加新的消息索引:
//--- CBuffer MSG_LIB_TEXT_BUFFER_TEXT_INDEX_BASE, // Base data buffer index MSG_LIB_TEXT_BUFFER_TEXT_INDEX_PLOT, // Plotted buffer serial number MSG_LIB_TEXT_BUFFER_TEXT_INDEX_COLOR, // Color buffer index MSG_LIB_TEXT_BUFFER_TEXT_NUM_DATAS, // Number of data buffers MSG_LIB_TEXT_BUFFER_TEXT_INDEX_NEXT_BASE, // Index of the array to be assigned as the next indicator buffer MSG_LIB_TEXT_BUFFER_TEXT_INDEX_NEXT_PLOT, // Index of the next drawn buffer MSG_LIB_TEXT_BUFFER_TEXT_ID, // Indicator buffers ID MSG_LIB_TEXT_BUFFER_TEXT_IND_LINE_MODE, // Indicator line MSG_LIB_TEXT_BUFFER_TEXT_IND_HANDLE, // Indicator handle that uses the buffer MSG_LIB_TEXT_BUFFER_TEXT_IND_HANDLE, // Indicator type that uses the buffer MSG_LIB_TEXT_BUFFER_TEXT_IND_LINE_ADDITIONAL_NUM, // Number of additional line MSG_LIB_TEXT_BUFFER_TEXT_TIMEFRAME, // Buffer data period (timeframe)
以及 与新索引相对应的文本:
{"Index of Base data buffer"}, {"Plot buffer sequence number"}, {"Color buffer index"}, {"Number of data buffers"}, {"Array index for assignment as the next indicator buffer"}, {"Index of the next drawable buffer"}, {"Indicator Buffer Id"}, {"Indicator line"}, {"Indicator handle that uses the buffer"}, {"Indicator type that uses the buffer"}, {"Additional line number"}, {"Buffer data Period (Timeframe)"},
在 \MQL5\Include\DoEasy\Defines.mqh 文件里,列举指标曲线类型,加入 Ichimoku Kinko Hyo 指标的新曲线 ,和其它曲线作为辅助 — 为了绘制我们的指标:
//+------------------------------------------------------------------+ //| Values of indicator lines in enumeration | //+------------------------------------------------------------------+ enum ENUM_INDICATOR_LINE_MODE { INDICATOR_LINE_MODE_MAIN = 0, // Main line INDICATOR_LINE_MODE_SIGNAL = 1, // Signal line INDICATOR_LINE_MODE_UPPER = 0, // Upper line INDICATOR_LINE_MODE_LOWER = 1, // Lower line INDICATOR_LINE_MODE_MIDDLE = 2, // Middle line INDICATOR_LINE_MODE_JAWS = 0, // Jaws line INDICATOR_LINE_MODE_TEETH = 1, // Teeth line INDICATOR_LINE_MODE_LIPS = 2, // Lips line INDICATOR_LINE_MODE_DI_PLUS = 1, // Line +DI INDICATOR_LINE_MODE_DI_MINUS = 2, // Line -DI INDICATOR_LINE_MODE_TENKAN_SEN = 0, // Line Tenkan-sen INDICATOR_LINE_MODE_KIJUN_SEN = 1, // Line Kijun-sen INDICATOR_LINE_MODE_SENKOU_SPANA = 2, // Line Senkou Span A INDICATOR_LINE_MODE_SENKOU_SPANB = 3, // Line Senkou Span B INDICATOR_LINE_MODE_CHIKOU_SPAN = 4, // Line Chikou Span INDICATOR_LINE_MODE_ADDITIONAL = 5, // Additional line }; //+------------------------------------------------------------------+
由于在上一篇文章里,我在此枚举中为相同类型的指标曲线设置了相同的数值,且将标准指标的不同对象的处理程序合并为一个,现在当显示缓冲区对象中的曲线类型描述时,我们所看到的曲线描述对应于此枚举的第一个匹配值。 例如,如果我显示鳄嘴标准指标的下颌线的描述,并且该枚举中 INDICATOR_LINE_MODE_JAWS 常数的值等于零,则显示该枚举中第一个常数的描述,因其也等于零 - 常数 INDICATOR_LINE_MODE_MAIN。
这并非错误,而是令人不愉快的混乱。 为了避免这种情况,我们必须为每个枚举常量都定义唯一值。 但是在这种情况下,必须重新划分处理程序,这更糟糕。 如此,我们需如下这样做:检查要显示指标曲线的确切缓冲区,以及与缓冲区对象相对应的枚举值,然后为该缓冲区对象添加另外的枚举值和描述。
加入该枚举:
//+------------------------------------------------------------------+ //| Enumeration of indicator lines | //+------------------------------------------------------------------+ enum ENUM_INDICATOR_LINE { INDICATOR_LINE_MAIN, // Main line INDICATOR_LINE_SIGNAL, // Signal line INDICATOR_LINE_UPPER, // Upper line INDICATOR_LINE_LOWER, // Lower line INDICATOR_LINE_MIDDLE, // Middle line INDICATOR_LINE_JAWS, // Jaws line INDICATOR_LINE_TEETH, // Teeth line INDICATOR_LINE_LIPS, // Lips line INDICATOR_LINE_DI_PLUS, // Line +DI INDICATOR_LINE_DI_MINUS, // Line -DI INDICATOR_LINE_TENKAN_SEN, // Line Tenkan-sen INDICATOR_LINE_KIJUN_SEN, // Line Kijun-sen INDICATOR_LINE_SENKOU_SPANA, // Line Senkou Span A INDICATOR_LINE_SENKOU_SPANB, // Line Senkou Span B INDICATOR_LINE_CHIKOU_SPAN, // Line Chikou Span INDICATOR_LINE_ADDITIONAL, // Additional line }; //+------------------------------------------------------------------+
在此枚举中,每个常量其值都唯一,范围从 0 到 15,现在我们可以轻松地显示特定指标的每条特定曲线所需的值。 我们如下操作。
在同一文件里加入另外的缓冲区对象整数型属性,同时增加缓冲区对象整数型属性的数量,从 24 至 25:
//+------------------------------------------------------------------+ //| Buffer integer properties | //+------------------------------------------------------------------+ enum ENUM_BUFFER_PROP_INTEGER { BUFFER_PROP_INDEX_PLOT = 0, // Plotted buffer serial number BUFFER_PROP_STATUS, // Buffer status (by drawing style) (from the ENUM_BUFFER_STATUS enumeration) BUFFER_PROP_TYPE, // Buffer type (from the ENUM_BUFFER_TYPE enumeration) BUFFER_PROP_TIMEFRAME, // Buffer data period (timeframe) BUFFER_PROP_ACTIVE, // Buffer usage flag BUFFER_PROP_DRAW_TYPE, // Graphical construction type (from the ENUM_DRAW_TYPE enumeration) BUFFER_PROP_ARROW_CODE, // Arrow code for DRAW_ARROW style BUFFER_PROP_ARROW_SHIFT, // The vertical shift of the arrows for DRAW_ARROW style BUFFER_PROP_LINE_STYLE, // Line style BUFFER_PROP_LINE_WIDTH, // Line width BUFFER_PROP_DRAW_BEGIN, // The number of initial bars that are not drawn and values in DataWindow BUFFER_PROP_SHOW_DATA, // Flag of displaying construction values in DataWindow BUFFER_PROP_SHIFT, // Indicator graphical construction shift by time axis in bars BUFFER_PROP_COLOR_INDEXES, // Number of colors BUFFER_PROP_COLOR, // Drawing color BUFFER_PROP_INDEX_BASE, // Base data buffer index BUFFER_PROP_INDEX_NEXT_BASE, // Index of the array to be assigned as the next indicator buffer BUFFER_PROP_INDEX_NEXT_PLOT, // Index of the next plotted buffer BUFFER_PROP_ID, // ID of multiple buffers of the same indicator BUFFER_PROP_IND_LINE_MODE, // Indicator line BUFFER_PROP_IND_HANDLE, // Indicator handle that uses the buffer BUFFER_PROP_IND_TYPE, // Indicator type that uses the buffer BUFFER_PROP_IND_LINE_ADDITIONAL_NUM, // Number of indicator additional line BUFFER_PROP_NUM_DATAS, // Number of data buffers BUFFER_PROP_INDEX_COLOR, // Color buffer index }; #define BUFFER_PROP_INTEGER_TOTAL (25) // Total number of buffer integer properties #define BUFFER_PROP_INTEGER_SKIP (2) // Number of buffer properties not used in sorting //+------------------------------------------------------------------+
为了能够按新属性搜索和排序缓冲区对象,将此属性添加到可能的排序准则枚举当中:
//+------------------------------------------------------------------+ //| Possible buffer sorting criteria | //+------------------------------------------------------------------+ #define FIRST_BUFFER_DBL_PROP (BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP) #define FIRST_BUFFER_STR_PROP (BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP+BUFFER_PROP_DOUBLE_TOTAL-BUFFER_PROP_DOUBLE_SKIP) enum ENUM_SORT_BUFFER_MODE { //--- Sort by integer properties SORT_BY_BUFFER_INDEX_PLOT = 0, // Sort by the plotted buffer serial number SORT_BY_BUFFER_STATUS, // Sort by buffer drawing style (status) (from the ENUM_BUFFER_STATUS enumeration) SORT_BY_BUFFER_TYPE, // Sort by buffer type (from the ENUM_BUFFER_TYPE enumeration) SORT_BY_BUFFER_TIMEFRAME, // Sort by the buffer data period (timeframe) SORT_BY_BUFFER_ACTIVE, // Sort by the buffer usage flag SORT_BY_BUFFER_DRAW_TYPE, // Sort by graphical construction type (from the ENUM_DRAW_TYPE enumeration) SORT_BY_BUFFER_ARROW_CODE, // Sort by the arrow code for DRAW_ARROW style SORT_BY_BUFFER_ARROW_SHIFT, // Sort by the vertical shift of the arrows for DRAW_ARROW style SORT_BY_BUFFER_LINE_STYLE, // Sort by the line style SORT_BY_BUFFER_LINE_WIDTH, // Sort by the line width SORT_BY_BUFFER_DRAW_BEGIN, // Sort by the number of initial bars that are not drawn and values in DataWindow SORT_BY_BUFFER_SHOW_DATA, // Sort by the flag of displaying construction values in DataWindow SORT_BY_BUFFER_SHIFT, // Sort by the indicator graphical construction shift by time axis in bars SORT_BY_BUFFER_COLOR_INDEXES, // Sort by a number of attempts SORT_BY_BUFFER_COLOR, // Sort by the drawing color SORT_BY_BUFFER_INDEX_BASE, // Sort by the basic data buffer index SORT_BY_BUFFER_INDEX_NEXT_BASE, // Sort by the index of the array to be assigned as the next indicator buffer SORT_BY_BUFFER_INDEX_NEXT_PLOT, // Sort by the index of the next drawn buffer SORT_BY_BUFFER_ID, // Sort by ID of multiple buffers of the same indicator SORT_BY_BUFFER_IND_LINE_MODE, // Sort by indicator line SORT_BY_BUFFER_IND_HANDLE, // Sort by indicator handle that uses the buffer SORT_BY_BUFFER_IND_TYPE, // Sort by indicator type that uses the buffer SORT_BY_BUFFER_IND_LINE_ADDITIONAL_NUM, // Sort by number of additional indicator line //--- Sort by real properties SORT_BY_BUFFER_EMPTY_VALUE = FIRST_BUFFER_DBL_PROP, // Sort by the empty value for plotting where nothing will be drawn //--- Sort by string properties SORT_BY_BUFFER_SYMBOL = FIRST_BUFFER_STR_PROP, // Sort by the buffer symbol SORT_BY_BUFFER_LABEL, // Sort by the name of the graphical indicator series displayed in DataWindow SORT_BY_BUFFER_IND_NAME, // Sort by indicator name that uses the buffer SORT_BY_BUFFER_IND_NAME_SHORT, // Sort by a short name of indicator that uses the buffer }; //+------------------------------------------------------------------+
现在,在 \MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh 里稍微改进一下抽象缓冲区对象类。
在类的公开部分中,编写设置并返回附加曲线编号的方法:
public: //--- Display the description of the buffer properties in the journal (full_prop=true - all properties, false - supported ones only) void Print(const bool full_prop=false); //--- Display a short buffer description in the journal (implementation in the descendants) virtual void PrintShort(void) {;} //--- Set (1) the arrow code, (2) vertical shift of arrows, (3) symbol, (4) timeframe, (5) buffer activity flag //--- (6) drawing type, (7) number of initial bars without drawing, (8) flag of displaying construction values in DataWindow, //--- (9) shift of the indicator graphical construction along the time axis, (10) line style, (11) line width, //--- (12) total number of colors, (13) one drawing color, (14) color of drawing in the specified color index, //--- (15) drawing colors from the color array, (16) empty value, (17) name of the graphical series displayed in DataWindow virtual void SetArrowCode(const uchar code) { return; } virtual void SetArrowShift(const int shift) { return; } void SetSymbol(const string symbol) { this.SetProperty(BUFFER_PROP_SYMBOL,symbol); } void SetTimeframe(const ENUM_TIMEFRAMES timeframe) { this.SetProperty(BUFFER_PROP_TIMEFRAME,timeframe); } void SetActive(const bool flag) { this.SetProperty(BUFFER_PROP_ACTIVE,flag); } void SetDrawType(const ENUM_DRAW_TYPE draw_type); void SetDrawBegin(const int value); void SetShowData(const bool flag); void SetShift(const int shift); void SetStyle(const ENUM_LINE_STYLE style); void SetWidth(const int width); void SetColorNumbers(const int number); 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); void SetID(const int id) { this.SetProperty(BUFFER_PROP_ID,id); } void SetIndicatorHandle(const int handle) { this.SetProperty(BUFFER_PROP_IND_HANDLE,handle); } void SetIndicatorType(const ENUM_INDICATOR type) { this.SetProperty(BUFFER_PROP_IND_TYPE,type); } void SetIndicatorName(const string name) { this.SetProperty(BUFFER_PROP_IND_NAME,name); } void SetIndicatorShortName(const string name) { this.SetProperty(BUFFER_PROP_IND_NAME_SHORT,name); } void SetLineMode(const ENUM_INDICATOR_LINE_MODE mode){ this.SetProperty(BUFFER_PROP_IND_LINE_MODE,mode); } void SetIndicatorLineAdditionalNumber(const int number){this.SetProperty(BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,number); } //--- 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) index of the next drawn buffer, (6) buffer data period, (7) buffer status, //--- (8) buffer type, (9) buffer usage flag, (10) arrow code, (11) arrow shift for DRAW_ARROW style, //--- (12) number of initial bars that are not drawn and values in DataWindow, (13) graphical construction type, //--- (14) flag of displaying construction values in DataWindow, (15) indicator graphical construction shift along the time axis, //--- (16) drawing line style, (17) drawing line width, (18) number of colors, (19) drawing color, (20) number of buffers for construction //--- (21) set empty value, (22) buffer symbol, (23) name of the indicator graphical series displayed in DataWindow //--- (24) buffer ID, (25) indicator handle, (26) standard indicator type, (27) standard indicator name, //--- (28) number of standard indicator calculated bars, (29) number of additional indicator line, (30) line type (main, signal, etc.) 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 IndexNextBaseBuffer(void) const { return (int)this.GetProperty(BUFFER_PROP_INDEX_NEXT_BASE); } int IndexNextPlotBuffer(void) const { return (int)this.GetProperty(BUFFER_PROP_INDEX_NEXT_PLOT); } 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); } int ID(void) const { return (int)this.GetProperty(BUFFER_PROP_ID); } int IndicatorHandle(void) const { return (int)this.GetProperty(BUFFER_PROP_IND_HANDLE); } ENUM_INDICATOR IndicatorType(void) const { return (ENUM_INDICATOR)this.GetProperty(BUFFER_PROP_IND_TYPE); } string IndicatorName(void) const { return this.GetProperty(BUFFER_PROP_IND_NAME); } string IndicatorShortName(void) const { return this.GetProperty(BUFFER_PROP_IND_NAME_SHORT); } int IndicatorBarsCalculated(void) const { return ::BarsCalculated((int)this.GetProperty(BUFFER_PROP_IND_HANDLE));} int IndicatorLineAdditionalNumber(void) const { return (int)this.GetProperty(BUFFER_PROP_IND_LINE_ADDITIONAL_NUM); } int IndicatorLineMode(void) const { return (int)this.GetProperty(BUFFER_PROP_IND_LINE_MODE); }
自现在起,我将显示来自另一个枚举的指标曲线的描述(实现如上),现在 IndicatorLineMode() 方法将返回整数值替代了枚举值 ENUM_INDICATOR_LINE_MODE。
在该类的同一公开部分,声明返回指标曲线描述的方法:
//--- 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, (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; string GetIndicatorLineModeDescription(void) const;
我们在类主体之外编写其实现:
//+------------------------------------------------------------------+ //| Return description of indicator buffer line | //+------------------------------------------------------------------+ string CBuffer::GetIndicatorLineModeDescription(void) const { uchar shift=0; switch(this.IndicatorType()) { case IND_ENVELOPES : case IND_FRACTALS : case IND_GATOR : case IND_BANDS : shift=2; break; case IND_ALLIGATOR : shift=5; break; case IND_ADX : case IND_ADXW : shift=8; break; case IND_ICHIMOKU : shift=10;break; default : shift=0; break; } return ::StringSubstr(::EnumToString(ENUM_INDICATOR_LINE(this.GetProperty(BUFFER_PROP_IND_LINE_MODE)+shift)),10); } //+------------------------------------------------------------------+
此处: 声明存储位移数值的变量,枚举常量值 ENUM_INDICATOR_LINE_MODE 必须增加,才能得到 ENUM_INDICATOR_LINE 枚举中相应指标曲线常量的声明开始。
例如,如果需要显示鳄嘴指标的牙齿线的描述,则位移值等于 5,它指向枚举 ENUM_INDICATOR_LINE 的常量 INDICATOR_LINE_JAWS :
//+------------------------------------------------------------------+ //| Enumeration of indicator lines | //+------------------------------------------------------------------+ enum ENUM_INDICATOR_LINE { INDICATOR_LINE_MAIN, // Main line INDICATOR_LINE_SIGNAL, // Signal line INDICATOR_LINE_UPPER, // Upper line INDICATOR_LINE_LOWER, // Lower line INDICATOR_LINE_MIDDLE, // Middle line INDICATOR_LINE_JAWS, // Jaws line INDICATOR_LINE_TEETH, // Teeth line INDICATOR_LINE_LIPS, // Lips line INDICATOR_LINE_DI_PLUS, // Line +DI INDICATOR_LINE_DI_MINUS, // Line -DI INDICATOR_LINE_TENKAN_SEN, // Line Tenkan-sen INDICATOR_LINE_KIJUN_SEN, // Line Kijun-sen INDICATOR_LINE_SENKOU_SPANA, // Line Senkou Span A INDICATOR_LINE_SENKOU_SPANB, // Line Senkou Span B INDICATOR_LINE_CHIKOU_SPAN, // Line Chikou Span INDICATOR_LINE_ADDITIONAL, // Additional line }; //+------------------------------------------------------------------+
并且由于我们的缓冲区从 GetProperty(BUFFER_PROP_IND_LINE_MODE) 方法返回牙齿线的值,且该值等于 1,因此将数值 5 加上 1 会导致常数索引等于 6,它指向常数 INDICATOR_LINE_TEETH。
结果则是,该方法返回收到的常量的字符串描述,其值降至 “LINE_TEETH”。
在类的封闭构造函数中,将缓冲区对象的新属性的默认值设置为 -1,这意味着没有附加指标曲线:
//+------------------------------------------------------------------+ //| Closed parametric constructor | //+------------------------------------------------------------------+ CBuffer::CBuffer(ENUM_BUFFER_STATUS buffer_status, ENUM_BUFFER_TYPE buffer_type, const uint index_plot, const uint index_base_array, const int num_datas, const uchar total_arrays, const int width, const string label) { this.m_type=COLLECTION_BUFFERS_ID; this.m_act_state_trigger=true; this.m_total_arrays=total_arrays; //--- Save integer properties this.m_long_prop[BUFFER_PROP_STATUS] = buffer_status; this.m_long_prop[BUFFER_PROP_TYPE] = buffer_type; this.m_long_prop[BUFFER_PROP_ID] = WRONG_VALUE; this.m_long_prop[BUFFER_PROP_IND_LINE_MODE] = INDICATOR_LINE_MODE_MAIN; this.m_long_prop[BUFFER_PROP_IND_HANDLE] = INVALID_HANDLE; this.m_long_prop[BUFFER_PROP_IND_TYPE] = WRONG_VALUE; this.m_long_prop[BUFFER_PROP_IND_LINE_ADDITIONAL_NUM] = WRONG_VALUE; ENUM_DRAW_TYPE type= (
在返回缓冲区对象整数型属性描述的方法当中,添加返回新属性描述的代码模块,并改进显示指标曲线描述的代码模块(现在,我们将用专门为此目的编写的新方法显示说明):
//+------------------------------------------------------------------+ //| Return description of a buffer's integer property | //+------------------------------------------------------------------+ string CBuffer::GetPropertyDescription(ENUM_BUFFER_PROP_INTEGER property) { return ( property==BUFFER_PROP_INDEX_PLOT ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INDEX_PLOT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_STATUS ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_STATUS)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetStatusDescription() ) : property==BUFFER_PROP_TYPE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetTypeBufferDescription() ) : property==BUFFER_PROP_TIMEFRAME ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_TIMEFRAME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetTimeframeDescription() ) : property==BUFFER_PROP_ACTIVE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_ACTIVE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetActiveDescription() ) : property==BUFFER_PROP_DRAW_TYPE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_DRAW_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetDrawTypeDescription() ) : property==BUFFER_PROP_ARROW_CODE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_ARROW_CODE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_ARROW_SHIFT ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_ARROW_SHIFT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : 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_DRAW_BEGIN ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_DRAW_BEGIN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_SHOW_DATA ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_SHOW_DATA)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetShowDataDescription() ) : property==BUFFER_PROP_SHIFT ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_SHIFT)+ (!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_INDEX_COLOR ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INDEX_COLOR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : 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) ) : property==BUFFER_PROP_INDEX_NEXT_BASE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INDEX_NEXT_BASE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_INDEX_NEXT_PLOT ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INDEX_NEXT_PLOT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_ID ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_IND_LINE_MODE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_IND_LINE_MODE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetIndicatorLineModeDescription() ) : property==BUFFER_PROP_IND_HANDLE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_IND_HANDLE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BUFFER_PROP_IND_TYPE ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_IND_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::StringSubstr(::EnumToString((ENUM_INDICATOR)this.GetProperty(property)),4) ) : property==BUFFER_PROP_IND_LINE_ADDITIONAL_NUM ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_IND_LINE_ADDITIONAL_NUM)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property)==WRONG_VALUE ? CMessage::Text(MSG_LIB_PROP_NOT_SET) : (string)this.GetProperty(property)) ) : property==BUFFER_PROP_NUM_DATAS ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_NUM_DATAS)+ (!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() ) : "" ); } //+------------------------------------------------------------------+
由于我们添加了一个新的整数型属性,因此在抽象缓冲区对象的所有衍生对象类中,针对返回对象支持此新属性标志的虚拟方法进行了改进(以 CBufferArrow 类方法作为 一个例子):
//+------------------------------------------------------------------+ //| 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_BASE && property!=BUFFER_PROP_IND_LINE_MODE && property!=BUFFER_PROP_IND_HANDLE && property!=BUFFER_PROP_IND_TYPE && property!=BUFFER_PROP_IND_LINE_ADDITIONAL_NUM && property!=BUFFER_PROP_ID ) ) return false; return true; } //+------------------------------------------------------------------+
所有缓冲区对象的所有文件均进行了相同的修改,诸如 BufferArrow.mqh, BufferBars.mqh, BufferCandles.mqh, BufferFilling.mqh, BufferHistogram.mqh, BufferHistogram2.mqh, BufferLine.mqh, BufferSection.mqh 和 BufferZigZag.mqh。
创建标准指标对象的所有方法都位于缓冲区对象集合类当中,
文件位于 \MQL5\Include\DoEasy\Collections\BuffersCollection.mqh。 在加入两个创建 Ichimoku Kinko Hyo 和 Gator Oscillator 标准指标对象的方法之前,我们稍微改进一下在当前品种图表上为指定标准指标准备数据并设置数值的方法。 由于 Ichimoku Kinko Hyo 指标含有五个绘制缓冲区,但在标准指标缓冲区对象中,只能传递三个指标指针给方法,而分别的六个变量 - 依据连接(每个缓冲区两个)将指标曲线的数值写入它们,所以方法中必须添加四个附加指针,指向需写入数值的缓冲区对象(每条曲线各有一个绘制和计算缓冲区),并通过链接传递另外四个变量。
在类主体中,添加含有所需数值的方法声明:
//--- Set values for the current chart to buffers of the specified standard indicator by the timeseries index in accordance with buffer object symbol/period bool SetDataBufferStdInd(const ENUM_INDICATOR std_ind,const int id,const int series_index,const datetime series_time,const char color_index=WRONG_VALUE); private: //--- Prepare data of the specified standard indicator for setting values on the current symbol chart int PreparingSetDataStdInd(CBuffer *buffer_data0,CBuffer *buffer_data1,CBuffer *buffer_data2,CBuffer *buffer_data3,CBuffer *buffer_data4, CBuffer *buffer_calc0,CBuffer *buffer_calc1,CBuffer *buffer_calc2,CBuffer *buffer_calc3,CBuffer *buffer_calc4, const ENUM_INDICATOR ind_type, const int series_index, const datetime series_time, int &index_period, int &num_bars, double &value00, double &value01, double &value10, double &value11, double &value20, double &value21, double &value30, double &value31, double &value40, double &value41); public: //--- Return the buffer (1) by the graphical series name, (2) timeframe,
在类主体之外编写方法实现时,加入必要的修改:
//+------------------------------------------------------------------+ //| Prepare data of the specified standard indicator | //| for setting values on the current symbol chart | //+------------------------------------------------------------------+ int CBuffersCollection::PreparingSetDataStdInd(CBuffer *buffer_data0,CBuffer *buffer_data1,CBuffer *buffer_data2,CBuffer *buffer_data3,CBuffer *buffer_data4, CBuffer *buffer_calc0,CBuffer *buffer_calc1,CBuffer *buffer_calc2,CBuffer *buffer_calc3,CBuffer *buffer_calc4, const ENUM_INDICATOR ind_type, const int series_index, const datetime series_time, int &index_period, int &num_bars, double &value00, double &value01, double &value10, double &value11, double &value20, double &value21, double &value30, double &value31, double &value40, double &value41) { //--- Find bar index on a period which corresponds to the time of current bar beginning index_period=::iBarShift(buffer_calc0.Symbol(),buffer_calc0.Timeframe(),series_time,true); if(index_period==WRONG_VALUE || index_period>buffer_calc0.GetDataTotal()-1) return WRONG_VALUE; //--- Get the value by this index from indicator buffer if(buffer_calc0!=NULL) value00=buffer_calc0.GetDataBufferValue(0,index_period); if(buffer_calc1!=NULL) value10=buffer_calc1.GetDataBufferValue(0,index_period); if(buffer_calc2!=NULL) value20=buffer_calc2.GetDataBufferValue(0,index_period); if(buffer_calc3!=NULL) value30=buffer_calc3.GetDataBufferValue(0,index_period); if(buffer_calc4!=NULL) value40=buffer_calc4.GetDataBufferValue(0,index_period); int series_index_start=series_index; //--- For the current chart we don’t need to calculate a number of bars processed - only one bar is available if(buffer_calc0.Symbol()==::Symbol() && buffer_calc0.Timeframe()==::Period()) { series_index_start=series_index; num_bars=1; } else { //--- Get the bar time which the bar with index_period index falls into on a period and symbol of calculated buffer datetime time_period=::iTime(buffer_calc0.Symbol(),buffer_calc0.Timeframe(),index_period); if(time_period==0) return false; //--- Get the current chart bar which corresponds to the time series_index_start=::iBarShift(::Symbol(),::Period(),time_period,true); if(series_index_start==WRONG_VALUE) return WRONG_VALUE; //--- Calculate the number of bars on the current chart which are to be filled in with calculated buffer data num_bars=::PeriodSeconds(buffer_calc0.Timeframe())/::PeriodSeconds(PERIOD_CURRENT); if(num_bars==0) num_bars=1; } //--- Take values for color calculation if(buffer_calc0!=NULL) value01=(series_index_start+num_bars>buffer_data0.GetDataTotal()-1 ? value00 : buffer_data0.GetDataBufferValue(0,series_index_start+num_bars)); if(buffer_calc1!=NULL) value11=(series_index_start+num_bars>buffer_data1.GetDataTotal()-1 ? value10 : buffer_data1.GetDataBufferValue(0,series_index_start+num_bars)); if(buffer_calc2!=NULL) value21=(series_index_start+num_bars>buffer_data2.GetDataTotal()-1 ? value20 : buffer_data2.GetDataBufferValue(0,series_index_start+num_bars)); if(buffer_calc3!=NULL) value31=(series_index_start+num_bars>buffer_data3.GetDataTotal()-1 ? value30 : buffer_data3.GetDataBufferValue(0,series_index_start+num_bars)); if(buffer_calc4!=NULL) value41=(series_index_start+num_bars>buffer_data4.GetDataTotal()-1 ? value40 : buffer_data4.GetDataBufferValue(0,series_index_start+num_bars)); return series_index_start; } //+------------------------------------------------------------------+
我们只需将方法中已存在的,用于缓冲区对象的相同处理程序加入即可,两个新缓冲区对象指针也要传递给方法;并依据传递给方法的缓冲区链接,将数值写入与其相对应的变量。
由于在 Ichimoku Kinko Hyo 标准指标两条曲线之间绘制了阴影,故此,其阴影线类型和颜色应与相对应的每条曲线所设置的线型和颜色相同:
... 我们需要一个方法,可根据指标类型、其 ID 和曲线,返回指向标准指标缓冲区对象的指针,以便我们从中提取绘制曲线的参数集合,且我们正在设计的自定义指标外观可把其设置为辅助缓冲区绘制参数。
在类的公开部分声明该方法
public: //--- Return the buffer (1) by the graphical series name, (2) timeframe, //--- (3) Plot index, (4) object index in the collection list, (5) the last created, //--- (6) standard indicator buffer by indicator type, its ID and line CBuffer *GetBufferByLabel(const string plot_label); CBuffer *GetBufferByTimeframe(const ENUM_TIMEFRAMES timeframe); CBuffer *GetBufferByPlot(const int plot_index); CBuffer *GetBufferByListIndex(const int index_list); CBuffer *GetLastCreateBuffer(void); CBuffer *GetBufferStdInd(const ENUM_INDICATOR indicator_type,const int id,const ENUM_INDICATOR_LINE_MODE line_mode,const char additional_id=WRONG_VALUE); //--- Return buffer list (1) by ID, (2) standard indicator type, (3) type and ID
我们在类主体之外编写其实现:
//+------------------------------------------------------------------+ //| Return standard indicator buffer | //| by indicator type, its ID and line | //+------------------------------------------------------------------+ CBuffer *CBuffersCollection::GetBufferStdInd(const ENUM_INDICATOR indicator_type,const int id,const ENUM_INDICATOR_LINE_MODE line_mode,const char additional_id=WRONG_VALUE) { CArrayObj *list=this.GetListBufferByTypeID(indicator_type,id); list=CSelect::ByBufferProperty(list,BUFFER_PROP_IND_LINE_MODE,line_mode,EQUAL); list=CSelect::ByBufferProperty(list,BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,additional_id,EQUAL); if(list==NULL) return NULL; return list.At(0); } //+------------------------------------------------------------------+
在此,一切都很简单:首先,按标准指标类型及其 ID 获取缓冲区对象列表,然后按标准指标曲线的类型在所得列表里排序,最后 ,列表里仅保留具有辅助缓冲区 ID 的对象(默认情况下,所有缓冲区的值都分配为 -1,这意味着 ID 缺失)。
自该方法返回已排序列表中的第一个对象。
补充一个方法,该方法为处理 Ichimoku Kinko Hyo 和鳄鱼振荡的指定标准指标准备计算缓冲区数据。
我们只需添加与指标类型相对应的处理程序即可。 对于所有指标,这个处理程序都是相同的,并且已在该方法中实现。 但与标准指标鳄鱼振荡器略有不同 — 其第二个缓冲区的索引为 2,替代了其他双缓冲区指标所用的 1,因为索引为 1 的缓冲区从属于索引为 0 的数据缓冲区的颜色缓冲区。 我不会使用标准指标得颜色缓冲区,因为我已为指标曲线创建了颜色处理和设置程序,再加上我能够为每根柱线分配所需的颜色,故此,默认情况下,鳄鱼振荡器指标的直方条颜色会由函数库自动计算。 且这样的计算已制作完成。 在恰当的情况下,用户可将每根柱线所需的颜色传递给标准指标的数据绘制方法,从而创建自己的指标颜色。
对于 Ichimoku Kinko Hyo 指标,与其他标准指标的数据准备流程相同 - 仅多了两个缓冲区。
//+------------------------------------------------------------------+ //| Prepare calculated buffer data | //| of the specified standard indicator | //+------------------------------------------------------------------+ int CBuffersCollection::PreparingDataBufferStdInd(const ENUM_INDICATOR std_ind,const int id,const int total_copy) { CArrayObj *list_ind=this.GetListBufferByTypeID(std_ind,id); CArrayObj *list; list_ind=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_TYPE,BUFFER_TYPE_CALCULATE,EQUAL); if(list_ind==NULL || list_ind.Total()==0) { ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_NO_BUFFER_OBJ)); return 0; } CBufferCalculate *buffer=NULL; int copied=WRONG_VALUE; int idx0=0,idx1=1,idx2=2; switch((int)std_ind) { //--- Single-buffer standard indicators case IND_AC : case IND_AD : case IND_AMA : case IND_AO : case IND_ATR : case IND_BEARS : case IND_BULLS : case IND_BWMFI : case IND_CCI : case IND_CHAIKIN : case IND_DEMA : case IND_DEMARKER : case IND_FORCE : case IND_FRAMA : case IND_MA : case IND_MFI : case IND_MOMENTUM : case IND_OBV : case IND_OSMA : case IND_RSI : case IND_SAR : case IND_STDDEV : case IND_TEMA : case IND_TRIX : case IND_VIDYA : case IND_VOLUMES : case IND_WPR : buffer=list_ind.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),0,buffer.Shift(),total_copy); return copied; //--- Multi-buffer standard indicators case IND_ENVELOPES : case IND_FRACTALS : case IND_MACD : case IND_RVI : case IND_STOCHASTIC : case IND_GATOR : if(std_ind==IND_GATOR) { idx0=0; idx1=2; } else { idx0=0; idx1=1; } list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,0,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),idx0,buffer.Shift(),total_copy); if(copied<total_copy) return 0; list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,1,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),idx1,buffer.Shift(),total_copy); if(copied<total_copy) return 0; return copied; case IND_ALLIGATOR : case IND_ADX : case IND_ADXW : case IND_BANDS : if(std_ind==IND_BANDS) { idx0=1; idx1=2; idx2=0; } else { idx0=0; idx1=1; idx2=2; } list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,0,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),idx0,buffer.Shift(),total_copy); if(copied<total_copy) return 0; list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,1,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),idx1,buffer.Shift(),total_copy); if(copied<total_copy) return 0; list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,2,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),idx2,buffer.Shift(),total_copy); if(copied<total_copy) return 0; return copied; case IND_ICHIMOKU : list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_TENKAN_SEN,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),TENKANSEN_LINE,buffer.Shift(),total_copy); if(copied<total_copy) return 0; list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_KIJUN_SEN,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),KIJUNSEN_LINE,buffer.Shift(),total_copy); if(copied<total_copy) return 0; list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANA,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),SENKOUSPANA_LINE,buffer.Shift(),total_copy); if(copied<total_copy) return 0; list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANB,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),SENKOUSPANB_LINE,buffer.Shift(),total_copy); if(copied<total_copy) return 0; list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_CHIKOU_SPAN,EQUAL); buffer=list.At(0); if(buffer==NULL) return 0; copied=buffer.FillAsSeries(buffer.IndicatorHandle(),CHIKOUSPAN_LINE,buffer.Shift(),total_copy); if(copied<total_copy) return 0; return copied; default: break; } return 0; } //+------------------------------------------------------------------+
对于按时间序列索引清除指定标准指标缓冲区数据的方法,添加 Ichimoku Kinko Hyo 指标的缓冲区处理:
//+------------------------------------------------------------------+ //| Clear buffer data of the specified standard indicator | //| by the timeseries index | //+------------------------------------------------------------------+ void CBuffersCollection::ClearDataBufferStdInd(const ENUM_INDICATOR std_ind,const int id,const int series_index) { //--- Get the list of buffer objects by type and ID CArrayObj *list_ind=this.GetListBufferByTypeID(std_ind,id); CArrayObj *list=NULL; if(list_ind==NULL || list_ind.Total()==0) return; list_ind=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_TYPE,BUFFER_TYPE_DATA,EQUAL); if(list_ind.Total()==0) return; CBuffer *buffer=NULL; switch((int)std_ind) { //--- Single-buffer standard indicators case IND_AC : case IND_AD : case IND_AMA : case IND_AO : case IND_ATR : case IND_BEARS : case IND_BULLS : case IND_BWMFI : case IND_CCI : case IND_CHAIKIN : case IND_DEMA : case IND_DEMARKER : case IND_FORCE : case IND_FRAMA : case IND_MA : case IND_MFI : case IND_MOMENTUM : case IND_OBV : case IND_OSMA : case IND_RSI : case IND_SAR : case IND_STDDEV : case IND_TEMA : case IND_TRIX : case IND_VIDYA : case IND_VOLUMES : case IND_WPR : buffer=list_ind.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); break; //--- Multi-buffer standard indicators case IND_ENVELOPES : case IND_FRACTALS : case IND_MACD : case IND_RVI : case IND_STOCHASTIC : case IND_GATOR : list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,0,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,1,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); break; case IND_ALLIGATOR : case IND_ADX : case IND_ADXW : case IND_BANDS : list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,0,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,1,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,2,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); break; case IND_ICHIMOKU : list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_TENKAN_SEN,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_KIJUN_SEN,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANA,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANB,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_CHIKOU_SPAN,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_ADDITIONAL,EQUAL); list=CSelect::ByBufferProperty(list,BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,0,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); list=CSelect::ByBufferProperty(list_ind,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_ADDITIONAL,EQUAL); list=CSelect::ByBufferProperty(list,BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,1,EQUAL); buffer=list.At(0); if(buffer==NULL) return; buffer.SetBufferValue(0,series_index,buffer.EmptyValue()); break; default: break; } } //+------------------------------------------------------------------+
鉴于我会进一步创建 Ichimoku Kinko Hyo 标准指标的对象,而且它会含有两个设计由于指标外观的直方图缓冲区,故在代码模块里已添加了清除这两个辅助缓冲区数据的方法。
其余部分与先前文章里实现得清除其他标准指标缓冲区数据的流程相同。
改进根据缓冲区对象品种/周期,按时间序列索引为当前图表上的指定标准指标缓冲区设置数值的方法。
现在,该方法将含有更多的缓冲对象,因为 Ichimoku Kinko Hyo 有五个对象,加上为指标外观设计的两个辅助直方图缓冲区。 存储所有曲线缓冲区对象数量的变量也应分别增加:
//+------------------------------------------------------------------+ //| Sets values for the current chart to buffers of the specified | //| standard indicator by the timeseries index in accordance | //| with buffer object symbol/period | //+------------------------------------------------------------------+ bool CBuffersCollection::SetDataBufferStdInd(const ENUM_INDICATOR ind_type,const int id,const int series_index,const datetime series_time,const char color_index=WRONG_VALUE) { //--- Get the list of buffer objects by type and ID CArrayObj *list=this.GetListBufferByTypeID(ind_type,id); if(list==NULL || list.Total()==0) { ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_NO_BUFFER_OBJ)); return false; } //--- Get the list of drawn buffers with ID CArrayObj *list_data=CSelect::ByBufferProperty(list,BUFFER_PROP_TYPE,BUFFER_TYPE_DATA,EQUAL); list_data=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_TYPE,ind_type,EQUAL); //--- Get the list of calculated buffers with ID CArrayObj *list_calc=CSelect::ByBufferProperty(list,BUFFER_PROP_TYPE,BUFFER_TYPE_CALCULATE,EQUAL); list_calc=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_TYPE,ind_type,EQUAL); //--- Leave if any of the lists is empty if(list_data.Total()==0 || list_calc.Total()==0) return false; //--- Declare necessary objects and variables CBuffer *buffer_data0=NULL,*buffer_data1=NULL,*buffer_data2=NULL,*buffer_data3=NULL,*buffer_data4=NULL,*buffer_tmp0=NULL,*buffer_tmp1=NULL; CBuffer *buffer_calc0=NULL,*buffer_calc1=NULL,*buffer_calc2=NULL,*buffer_calc3=NULL,*buffer_calc4=NULL; double value00=EMPTY_VALUE, value01=EMPTY_VALUE; double value10=EMPTY_VALUE, value11=EMPTY_VALUE; double value20=EMPTY_VALUE, value21=EMPTY_VALUE; double value30=EMPTY_VALUE, value31=EMPTY_VALUE; double value40=EMPTY_VALUE, value41=EMPTY_VALUE; double value_tmp0=EMPTY_VALUE,value_tmp1=EMPTY_VALUE; long vol0=0,vol1=0; int series_index_start=series_index,index_period=0, index=0,num_bars=1; uchar clr=0; //--- Depending on standard indicator type
现在,在处理标准指标集合的每个代码模块里,会把更多数值传递给缓冲区数据准备方法 PreparingSetDataStdInd():
series_index_start=PreparingSetDataStdInd(buffer_data0,buffer_data1,buffer_data2,buffer_data3,buffer_data4, buffer_calc0,buffer_calc1,buffer_calc2,buffer_calc3,buffer_calc4, ind_type,series_index,series_time,index_period,num_bars, value00,value01,value10,value11,value20,value21,value30,value31,value40,value41);
在方法末尾加入标准指标 Ichimoku Kinko Hyo 和鳄鱼振荡器的处理程序:
case IND_ICHIMOKU : list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_TENKAN_SEN,EQUAL); buffer_data0=list.At(0); list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_KIJUN_SEN,EQUAL); buffer_data1=list.At(0); list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANA,EQUAL); buffer_data2=list.At(0); list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANB,EQUAL); buffer_data3=list.At(0); list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_CHIKOU_SPAN,EQUAL); buffer_data4=list.At(0); //--- Get the list of buffer objects which have ID of auxiliary line, and from it - buffer object with line number as 0 list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_ADDITIONAL,EQUAL); list=CSelect::ByBufferProperty(list,BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,0,EQUAL); buffer_tmp0=list.At(0); //--- Get the list of buffer objects which have ID of auxiliary line, and from it - buffer object with line number as 1 list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_ADDITIONAL,EQUAL); list=CSelect::ByBufferProperty(list,BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,1,EQUAL); buffer_tmp1=list.At(0); list=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_TENKAN_SEN,EQUAL); buffer_calc0=list.At(0); list=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_KIJUN_SEN,EQUAL); buffer_calc1=list.At(0); list=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANA,EQUAL); buffer_calc2=list.At(0); list=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_SENKOU_SPANB,EQUAL); buffer_calc3=list.At(0); list=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_LINE_MODE,INDICATOR_LINE_MODE_CHIKOU_SPAN,EQUAL); buffer_calc4=list.At(0); if(buffer_calc0==NULL || buffer_data0==NULL || buffer_calc0.GetDataTotal(0)==0) return false; if(buffer_calc1==NULL || buffer_data1==NULL || buffer_calc1.GetDataTotal(0)==0) return false; if(buffer_calc2==NULL || buffer_data2==NULL || buffer_calc2.GetDataTotal(0)==0) return false; if(buffer_calc3==NULL || buffer_data3==NULL || buffer_calc3.GetDataTotal(0)==0) return false; if(buffer_calc4==NULL || buffer_data4==NULL || buffer_calc4.GetDataTotal(0)==0) return false; series_index_start=PreparingSetDataStdInd(buffer_data0,buffer_data1,buffer_data2,buffer_data3,buffer_data4, buffer_calc0,buffer_calc1,buffer_calc2,buffer_calc3,buffer_calc4, ind_type,series_index,series_time,index_period,num_bars, value00,value01,value10,value11,value20,value21,value30,value31,value40,value41); if(series_index_start==WRONG_VALUE) return false; //--- In a loop, by the number of bars in num_bars fill in the drawn buffer with a value from the calculated buffer taken by index_period index //--- and set the drawn buffer color depending on a proportion of value00 and value01 values for(int i=0;i<num_bars;i++) { index=series_index_start-i; buffer_data0.SetBufferValue(0,index,value00); buffer_data1.SetBufferValue(0,index,value10); buffer_data2.SetBufferValue(0,index,value20); buffer_data3.SetBufferValue(0,index,value30); buffer_data4.SetBufferValue(0,index,value40); buffer_data0.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value00>value01 ? 0 : value00<value01 ? 1 : 2) : color_index); buffer_data1.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value10>value11 ? 0 : value10<value11 ? 1 : 2) : color_index); buffer_data2.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value20>value21 ? 0 : value20<value21 ? 1 : 2) : color_index); buffer_data3.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value30>value31 ? 0 : value30<value31 ? 1 : 2) : color_index); buffer_data4.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value40>value41 ? 0 : value40<value41 ? 1 : 2) : color_index); //--- Set values for indicator auxiliary lines depending on mutual position of Senkou Span A and Senkou Span B lines value_tmp0=buffer_data2.GetDataBufferValue(0,index); value_tmp1=buffer_data3.GetDataBufferValue(0,index); if(value_tmp0<value_tmp1) { buffer_tmp0.SetBufferValue(0,index,buffer_tmp0.EmptyValue()); buffer_tmp0.SetBufferValue(1,index,buffer_tmp0.EmptyValue()); buffer_tmp1.SetBufferValue(0,index,value_tmp0); buffer_tmp1.SetBufferValue(1,index,value_tmp1); } else { buffer_tmp0.SetBufferValue(0,index,value_tmp0); buffer_tmp0.SetBufferValue(1,index,value_tmp1); buffer_tmp1.SetBufferValue(0,index,buffer_tmp1.EmptyValue()); buffer_tmp1.SetBufferValue(1,index,buffer_tmp1.EmptyValue()); } } return true; case IND_GATOR : list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,0,EQUAL); buffer_data0=list.At(0); list=CSelect::ByBufferProperty(list_data,BUFFER_PROP_IND_LINE_MODE,1,EQUAL); buffer_data1=list.At(0); list=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_LINE_MODE,0,EQUAL); buffer_calc0=list.At(0); list=CSelect::ByBufferProperty(list_calc,BUFFER_PROP_IND_LINE_MODE,1,EQUAL); buffer_calc1=list.At(0); if(buffer_calc0==NULL || buffer_data0==NULL || buffer_calc0.GetDataTotal(0)==0) return false; if(buffer_calc1==NULL || buffer_data1==NULL || buffer_calc1.GetDataTotal(0)==0) return false; series_index_start=PreparingSetDataStdInd(buffer_data0,buffer_data1,buffer_data2,buffer_data3,buffer_data4, buffer_calc0,buffer_calc1,buffer_calc2,buffer_calc3,buffer_calc4, ind_type,series_index,series_time,index_period,num_bars, value00,value01,value10,value11,value20,value21,value30,value31,value40,value41); if(series_index_start==WRONG_VALUE) return false; //--- In a loop, by the number of bars in num_bars fill in the drawn buffer with a value from the calculated buffer taken by index_period index //--- and set the drawn buffer color depending on a proportion of value00 and value01 values for(int i=0;i<num_bars;i++) { index=series_index_start-i; buffer_data0.SetBufferValue(0,index,value00); buffer_data1.SetBufferValue(1,index,value10); buffer_data0.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value00>value01 ? 0 : value00<value01 ? 1 : 2) : color_index); buffer_data1.SetBufferColorIndex(index,color_index==WRONG_VALUE ? uchar(value10<value11 ? 0 : value10>value11 ? 1 : 2) : color_index); } return true; default: break;
若代码动作与先前文章中研究的处理其他标准指标的相同代码的动作不同,则会提供有关动作的注释。 这只涉及为 Ichimoku Kinko Hyo 指标设计的数据获取和处理程序。 对于鳄鱼振荡器指标,所有逻辑保持与其它标准指标相同。
现在,编写创建标准指标 Ichimoku Kinko Hyo 和鳄鱼振荡器对象的方法。
针对鳄鱼振荡器的创建方法:
//+------------------------------------------------------------------+ //| Create multi-symbol multi-period Gator | //+------------------------------------------------------------------+ int CBuffersCollection::CreateGator(const string symbol,const ENUM_TIMEFRAMES timeframe, const int jaw_period, const int jaw_shift, const int teeth_period, const int teeth_shift, const int lips_period, const int lips_shift, const ENUM_MA_METHOD ma_method, const ENUM_APPLIED_PRICE applied_price, const int id=WRONG_VALUE) { //--- Create indicator handle and set default ID int num_bars=::PeriodSeconds(timeframe)/::PeriodSeconds(PERIOD_CURRENT); int shift=::fmin(jaw_shift,teeth_shift); int handle=::iGator(symbol,timeframe,jaw_period,jaw_shift,teeth_period,teeth_shift,lips_period,lips_shift,ma_method,applied_price); int identifier=(id==WRONG_VALUE ? IND_GATOR : id); color array_colors[3]={clrGreen,clrRed,clrGreen}; CBuffer *buff=NULL; if(handle!=INVALID_HANDLE) { //--- Create histogram buffer from the zero line this.CreateHistogram(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters of Up buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(shift*num_bars); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_GATOR); buff.SetShowData(true); buff.SetLineMode(INDICATOR_LINE_MODE_UPPER); buff.SetIndicatorName("Gator Oscillator"); buff.SetIndicatorShortName("Gator("+symbol+","+TimeframeDescription(timeframe)+": "+(string)jaw_period+","+(string)teeth_period+","+(string)lips_period+")"); buff.SetLabel("Gator("+symbol+","+TimeframeDescription(timeframe)+": "+(string)jaw_period+","+(string)teeth_period+","+(string)lips_period+","+") Up"); buff.SetColors(array_colors); //--- Create histogram buffer from the zero line this.CreateHistogram(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters of Down buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(shift*num_bars); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_GATOR); buff.SetShowData(true); buff.SetLineMode(INDICATOR_LINE_MODE_LOWER); buff.SetIndicatorName("Gator Oscillator"); buff.SetIndicatorShortName("Gator("+symbol+","+TimeframeDescription(timeframe)+": "+(string)jaw_period+","+(string)teeth_period+","+(string)lips_period+")"); buff.SetLabel("Gator("+symbol+","+TimeframeDescription(timeframe)+": "+(string)jaw_period+","+(string)teeth_period+","+(string)lips_period+","+") Down"); buff.SetColors(array_colors); //--- Create calculated buffer of Up, in which standard indicator data will be stored this.CreateCalculate(); //--- Get the last created buffer object (calculated) and set to it all the necessary parameters of Up buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(shift); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_GATOR); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLineMode(INDICATOR_LINE_MODE_UPPER); buff.SetIndicatorName("Gator Oscillator"); buff.SetLabel("Gator("+symbol+","+TimeframeDescription(timeframe)+": "+(string)jaw_period+","+(string)teeth_period+","+(string)lips_period+","+") Up"); //--- Create calculated buffer of Teeth in which standard indicator data will be stored this.CreateCalculate(); //--- Get the last created buffer object (calculated) and set to it all the necessary parameters of Teeth buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(shift); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_GATOR); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLineMode(INDICATOR_LINE_MODE_LOWER); buff.SetIndicatorName("Gator Oscillator"); buff.SetLabel("Gator("+symbol+","+TimeframeDescription(timeframe)+": "+(string)jaw_period+","+(string)teeth_period+","+(string)lips_period+","+") Down"); } return handle; } //+------------------------------------------------------------------+
在创建指标句柄时,为其传递计算出的鳄嘴指标曲线相对于鳄鱼指标线的位移数据,就像它们在输入中一样,无论指标是否绘制在“非原生”时间帧 - 指标的内部计算都需要所有这些数据。 计算出的鳄鱼标准指标曲线的视觉偏移量,取自其关联鳄嘴指标的下颌线和牙齿线位移值中的最小值.。 并且此视觉位移必须乘以应在当前时间帧内显示的柱线数量。 然后我们为指标的绘制缓冲区对象设置位移值。对于计算缓冲对象,设置位移但无需乘以柱线数量。
针对 Ichimoku Kinko Hyo 的创建方法:
//+------------------------------------------------------------------+ //| Create multi-symbol multi-period Ichimoku | //+------------------------------------------------------------------+ int CBuffersCollection::CreateIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe, const int tenkan_sen, const int kijun_sen, const int senkou_span_b, const int id=WRONG_VALUE) { //--- Create indicator handle and set default ID int num_bars=::PeriodSeconds(timeframe)/::PeriodSeconds(PERIOD_CURRENT); int handle=::iIchimoku(symbol,timeframe,tenkan_sen,kijun_sen,senkou_span_b); int identifier=(id==WRONG_VALUE ? IND_ICHIMOKU : id); color array_colors[1]={clrRed}; CBuffer *buff=NULL; if(handle!=INVALID_HANDLE) { //--- Create line buffer this.CreateLine(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters of Tenkan-Sen buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_TENKAN_SEN); buff.SetShowData(true); buff.SetLabel("Tenkan-Sen("+symbol+","+TimeframeDescription(timeframe)+": "+(string)tenkan_sen+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetColors(array_colors); //--- Create line buffer this.CreateLine(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters of Kijun-Sen buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_KIJUN_SEN); buff.SetShowData(true); buff.SetLabel("Kijun-Sen("+symbol+","+TimeframeDescription(timeframe)+": "+(string)kijun_sen+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); array_colors[0]=clrBlue; buff.SetColors(array_colors); //--- Create line buffer this.CreateLine(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters of Senkou Span A buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(kijun_sen*num_bars); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_SENKOU_SPANA); buff.SetShowData(true); buff.SetLabel("Senkou Span A("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); array_colors[0]=clrSandyBrown; buff.SetColors(array_colors); buff.SetStyle(STYLE_DOT); //--- Create line buffer this.CreateLine(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters of Senkou Span B buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(kijun_sen*num_bars); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_SENKOU_SPANB); buff.SetShowData(true); buff.SetLabel("Senkou Span B("+symbol+","+TimeframeDescription(timeframe)+": "+(string)senkou_span_b+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); array_colors[0]=clrThistle; buff.SetColors(array_colors); buff.SetStyle(STYLE_DOT); //--- Create line buffer this.CreateLine(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters of Chikou Span buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_CHIKOU_SPAN); buff.SetShowData(true); buff.SetLabel("Chikou Span("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); array_colors[0]=clrLime; buff.SetColors(array_colors); //--- Create histogram buffer on two lines for displaying the histogram of Senkou Span A this.CreateHistogram2(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(kijun_sen*num_bars); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_ADDITIONAL); buff.SetShowData(false); buff.SetLabel("Senkou Span A("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorLineAdditionalNumber(0); //--- Get buffer data of Senkou Span A and set values of line color, width and style to the histogram CBuffer *tmp=GetBufferStdInd(IND_ICHIMOKU,identifier,INDICATOR_LINE_MODE_SENKOU_SPANA); array_colors[0]=(tmp!=NULL ? tmp.Color() : clrSandyBrown); buff.SetColors(array_colors); buff.SetWidth(tmp!=NULL ? tmp.LineWidth() : 1); buff.SetStyle(tmp!=NULL ? tmp.LineStyle() : STYLE_DOT); //--- Create histogram buffer on two lines for displaying the histogram of Senkou Span B this.CreateHistogram2(); //--- Get the last created buffer object (drawn) and set to it all the necessary parameters buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(kijun_sen*num_bars); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_ADDITIONAL); buff.SetShowData(false); buff.SetLabel("Senkou Span B("+symbol+","+TimeframeDescription(timeframe)+": "+(string)senkou_span_b+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorLineAdditionalNumber(1); //--- Get buffer data of Senkou Span B and set values of line color, width and style to the histogram tmp=GetBufferStdInd(IND_ICHIMOKU,identifier,INDICATOR_LINE_MODE_SENKOU_SPANB); array_colors[0]=(tmp!=NULL ? tmp.Color() : clrThistle); buff.SetColors(array_colors); buff.SetWidth(tmp!=NULL ? tmp.LineWidth() : 1); buff.SetStyle(tmp!=NULL ? tmp.LineStyle() : STYLE_DOT); //--- Create calculated buffer in which data of Tenkan-Sen line will be stored this.CreateCalculate(); //--- Get the last created buffer object (calculated) and set to it all the necessary parameters buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_TENKAN_SEN); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLabel("Tenkan-Sen("+symbol+","+TimeframeDescription(timeframe)+": "+(string)tenkan_sen+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); //--- Create calculated buffer in which data of Kijun-Sen line will be stored this.CreateCalculate(); //--- Get the last created buffer object (calculated) and set to it all the necessary parameters buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_KIJUN_SEN); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLabel("Kijun-Sen("+symbol+","+TimeframeDescription(timeframe)+": "+(string)kijun_sen+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); //--- Create calculated buffer in which data of Senkou Span A line will be stored this.CreateCalculate(); //--- Get the last created buffer object (calculated) and set to it all the necessary parameters buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(kijun_sen); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_SENKOU_SPANA); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLabel("Senkou Span A("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); //--- Create calculated buffer in which data of Senkou Span B line will be stored this.CreateCalculate(); //--- Get the last created buffer object (calculated) and set to it all the necessary parameters buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetShift(kijun_sen); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_SENKOU_SPANB); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLabel("Senkou Span B("+symbol+","+TimeframeDescription(timeframe)+": "+(string)senkou_span_b+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); //--- Create calculated buffer in which data of Chikou Span line will be stored this.CreateCalculate(); //--- Get the last created buffer object (calculated) and set to it all the necessary parameters buff=this.GetLastCreateBuffer(); if(buff==NULL) return INVALID_HANDLE; buff.SetSymbol(symbol); buff.SetTimeframe(timeframe); buff.SetID(identifier); buff.SetIndicatorHandle(handle); buff.SetIndicatorType(IND_ICHIMOKU); buff.SetLineMode(INDICATOR_LINE_MODE_CHIKOU_SPAN); buff.SetEmptyValue(EMPTY_VALUE); buff.SetLabel("Chikou Span("+symbol+","+TimeframeDescription(timeframe)+")"); buff.SetIndicatorName("Ichimoku Kinko Hyo"); buff.SetIndicatorShortName("Ichimoku("+symbol+","+TimeframeDescription(timeframe)+")"); } return handle; } //+------------------------------------------------------------------+
在此,就像创建鳄鱼标准指标对象时一样,在创建句柄时传递给它的输入不变,和在创建显示 Senkou Span A 和 Senkou Span B 曲线,以及设计用于绘制两条线之间区域直方图的附加缓冲对象时,位移值需要乘以在当前图表上必须显示的柱线数量。 创建计算缓冲区对象时,设置位移时不要乘以当前图表显示的柱线数量。
Kijun-Sen 曲线的计算周期用作 Senkou Span A 和 Senkou Span B 曲线的位移。
在创建附加直方图缓冲区时,首先为其设置所有指标的标准参数,然后获取直方图对应的缓冲区对象,并在为直方图设置绘制参数时,应与该曲线取值缓冲区的参数相同。
对于直方图的缓冲区对象,设置属性时不可在数据窗口中显示该曲线 - 这些缓冲区仅在设计时是必需的,且其参数值应与数据获取曲线的参数一致。
改进创建多品种、多周期标准指标的库类和方法至此结束。 现在,我们拥有了在自定义程序中创建任意标准和自定义复合指标的全套方法。 当然,在进一步开发函数库功能方面仍然存在一些缺陷,需要逐步解决。
为了执行测试,我们从上一篇文章中获取指标,并在新文件夹中创建两个新指标 \MQL5\Indicators\TestDoEasy\Part51\
命名为 TestDoEasyPart51_1.mq5 和 TestDoEasyPart51_2.mq5。
它们之间的区别仅在于参数 #property indicator_chart_window 或 #property indicator_separate_window,因为其中一个将绘制在主图表上,而第二个将绘制在子窗口之中。 此外,在第一种情况下,我们将创建 “Ichimoku Kinko Hyo” 指标,在第二种情况下,我们将创建 “鳄鱼振荡器”。
从输入里删除设置指标类型和曲线位移的代码:
sinput ENUM_INDICATOR InpIndType = IND_AC; // Type standard indicator
sinput int InpShift = 0; // Indicator line shift
在文件 TestDoEasyPart51_1.mq5 里的 OnInit() 处理程序中,创建 Ichimoku Kinko Hyo 的对象:
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Write the name of the working timeframe selected in the settings to the InpUsedTFs variable InpUsedTFs=TimeframeDescription(InpPeriod); //--- Initialize DoEasy library OnInitDoEasy(); //--- Set indicator global variables prefix=engine.Name()+"_"; //--- Calculate the number of bars of the current period fitting in the maximum used period //--- Use the obtained value if it exceeds 2, otherwise use 2 int num_bars=NumberBarsInTimeframe(InpPeriod); min_bars=(num_bars>2 ? num_bars : 2); //--- Check and remove remaining indicator graphical objects if(IsPresentObectByPrefix(prefix)) ObjectsDeleteAll(0,prefix); //--- Create the button panel //--- Check playing a standard sound using macro substitutions engine.PlaySoundByDescription(SND_OK); //--- Wait for 600 milliseconds engine.Pause(600); engine.PlaySoundByDescription(SND_NEWS); //--- indicator buffers mapping //--- Create all the necessary buffer objects for constructing the selected standard indicator if(!engine.BufferCreateIchimoku(InpUsedSymbols,InpPeriod,9,26,52,1)) { Print(TextByLanguage("Error. Indicator not created")); return INIT_FAILED; } //--- Check the number of buffers specified in the 'properties' block if(engine.BuffersPropertyPlotsTotal()!=indicator_plots) Alert(TextByLanguage("Attention! Value of \"indicator_plots\" should be "),engine.BuffersPropertyPlotsTotal()); if(engine.BuffersPropertyBuffersTotal()!=indicator_buffers) Alert(TextByLanguage("Attention! Value of \"indicator_buffers\" should be "),engine.BuffersPropertyBuffersTotal()); //--- Create the color array and set non-default colors to all buffers within the collection //--- (commented out since default colors are already set in methods of standard indicator creation) //--- (we can always set required colors either for all indicators like here or for each one individually) //color array_colors[]={clrGreen,clrRed,clrGray}; //engine.BuffersSetColors(array_colors); //--- Display short descriptions of created indicator buffers engine.BuffersPrintShort(); //--- Set a short name for the indicator, data capacity and levels string label=engine.BufferGetIndicatorShortNameByTypeID(IND_ICHIMOKU,1); IndicatorSetString(INDICATOR_SHORTNAME,label); SetIndicatorLevels(InpUsedSymbols,IND_ICHIMOKU); //--- Succeeded return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
在 OnCalculate() 处理程序之中,仅创建一个指标:
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //+------------------------------------------------------------------+ //| OnCalculate code block for working with the library: | //+------------------------------------------------------------------+ //--- Pass the current symbol data from OnCalculate() to the price structure and set the "as timeseries" flag to the arrays CopyDataAsSeries(rates_total,prev_calculated,time,open,high,low,close,tick_volume,volume,spread); //--- Check for the minimum number of bars for calculation if(rates_total<min_bars || Point()==0) return 0; //--- Handle the Calculate event in the library //--- If the OnCalculate() method of the library returns zero, not all timeseries are ready - leave till the next tick if(engine.OnCalculate(rates_data)==0) return 0; //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(rates_data); // Working in the library timer engine.EventsHandling(); // Working with library events } //+------------------------------------------------------------------+ //| OnCalculate code block for working with the indicator: | //+------------------------------------------------------------------+ //--- Check and calculate the number of calculated bars //--- If limit = 0, there are no new bars - calculate the current one //--- If limit = 1, a new bar has appeared - calculate the first and the current ones //--- If limit > 1 means the first launch or changes in history - the full recalculation of all data int limit=rates_total-prev_calculated; //--- Recalculate the entire history if(limit>1) { limit=rates_total-1; engine.BuffersInitPlots(); engine.BuffersInitCalculates(); } //--- Prepare data //--- Fill in calculated buffers of all created standard indicators with data int bars_total=engine.SeriesGetBarsTotal(InpUsedSymbols,InpPeriod); int total_copy=(limit<min_bars ? min_bars : fmin(limit,bars_total)); if(!engine.BufferPreparingDataAllBuffersStdInd()) return 0; //--- Calculate the indicator //--- Main calculation loop of the indicator for(int i=limit; i>WRONG_VALUE && !IsStopped(); i--) { engine.GetBuffersCollection().SetDataBufferStdInd(IND_ICHIMOKU,1,i,time[i]); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
在文件 TestDoEasyPart51_2.mq5 中,进行相同的修改,但要替换创建和处理 Ichimoku Kinko Hyo 和鳄鱼振荡器。 且为预处理器设置了一个提示,从而可以创建在子窗口中操作的指标:
//+------------------------------------------------------------------+ //| TestDoEasyPart51_2.mq5 | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //--- includes #include <DoEasy\Engine.mqh> //--- properties #property indicator_separate_window #property indicator_buffers 6 #property indicator_plots 2
在 EURUSD H1 图表上启动这两个指标,并在指标设置中指定使用 EURUSD H4 的数据进行计算。 并将它们与标准指标进行比较:
如您所见,两个指标的数据与标准指标的数据匹配。
这两个指标的完整代码在随附的文件中提供。
在下一篇文章中,我们将开始研究标准指标对象类与 MQL4 的兼容性。
函数库当前版本的所有文件,以及测试指标文件都随附于下。 您可以下载它们,并测试所有内容。
请在文章的评论中留下您的评论、问题和建议。
请记住,此处我已针对 MetaTrader 5 完成了 MQL5 测试指标开发。
附件仅适用于 MetaTrader 5。 当前函数库版本尚未在 MetaTrader 4 里进行测试。
返回内容目录
该系列中的先前文章:
DoEasy 函数库中的时间序列(第三十五部分):柱线对象和品种时间序列列表
DoEasy 函数库中的时间序列(第三十六部分):所有用到的品种周期的时间序列对象
DoEasy 函数库中的时间序列(第三十七部分):时间序列集合 - 按品种和周期的时间序列数据库
DoEasy 函数库中的时间序列(第三十八部分):时间序列集合 - 实时更新以及从程序访问数据
DoEasy 函数库中的时间序列(第三十九部分):基于函数库的指标 - 准备数据和时间序列事件
DoEasy 函数库中的时间序列(第四十部分):基于函数库的指标 - 实时刷新数据
DoEasy 函数库中的时间序列(第四十一部分):多品种多周期指标样品
DoEasy 函数库中的时间序列(第四十二部分):抽象指标缓冲区对象类
DoEasy 函数库中的时间序列(第四十三部分):指标缓冲区对象类
DoEasy 函数库中的时间序列(第四十四部分):指标缓冲区对象集合类
DoEasy 函数库中的时间序列(第四十五部分):多周期指标缓冲区
DoEasy 函数库中的时间序列(第四十六部分):多周期、多品种指标缓冲区
DoEasy 函数库中的时间序列(第四十七部分):多周期、多品种标准指标
DoEasy 函数库中的时间序列(第四十八部分):在单一子窗口里基于一个缓冲区的多周期、多品种指标
DoEasy 函数库中的时间序列(第四十九部分):多周期、多品种、多缓冲区标准指标
DoEasy 函数库中的时间序列(第五十部分):多周期、多品种带位移的标准指标
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程