English Русский 中文 Español 日本語 Português
preview
Zeitreihen in der Bibliothek DoEasy (Teil 51): Zusammengesetzte Standardindikatoren für mehrere Symbole und Perioden

Zeitreihen in der Bibliothek DoEasy (Teil 51): Zusammengesetzte Standardindikatoren für mehrere Symbole und Perioden

MetaTrader 5Beispiele | 10 Dezember 2020, 10:39
369 0
Artyom Trishkin
Artyom Trishkin

Inhaltsverzeichnis


Konzept

Heute schließe ich die Erstellung von Objekten mit den Standardindikatoren für mehrere Symbole und Perioden ab. Und das Ganze abzurunden, ich ein sehr gutes Beispiel für die Erstellung ausgesucht, den Ichimoku Kinko Hyo Indikator. Um ihn zu zeichnen, müssen wir nicht nur alle seine signifikanten Puffer erstellen, die im Terminaldatenfenster angezeigt werden, sondern auch zwei zusätzliche Puffer hinzufügen, um den Bereich zwischen seinen beiden Linien 'Senkou Span A' und 'Senkou Span B' mit Hilfe von zwei Histogrammen, die zwischen zwei Werten gezeichnet werden, farblich auszufüllen. Dabei muss jedes der Histogramme den Stil und die Farbe der Linie wiederholen, auf die es sich bezieht.
Die Erstellung eines solchen Indikators wird ein gutes Beispiel dafür sein, wie man mit Hilfe dieser Bibliothek eigene zusammengesetzte nutzerdefinierte Indikatoren erstellen kann.
Zum Schluss werde ich das letzte Objekt eines Indikatoren für mehrere Symbole und Perioden aus dem vollständigen Satz von Standardindikatoren des MetaTrader5-Terminals erstellen — Bill Williams' Indikator Gator Oscillator, konstruiert auf der Grundlage seines anderen Indikators Alligator, der im vorherigen Artikel besprochen wurde.

Da wir beliebig komplexe Indikatoren erstellen können, die verschiedene Linien verschiedener Zeichnungsarten mit den entsprechenden Pufferobjekten enthalten können, aber alle diese Puffer zu einem einzigen Indikatorobjekt gehören werden, müssen wir eine weitere Eigenschaft für das Pufferobjekt einführen - eine Reihe von zusätzlichen Indikatorlinien (Hilfspuffer zum Zeichnen zusätzlicher Indikatorlinien, die zu seiner Gestaltung dienen). Anhand der Nummer dieser Linie werden wir also die erforderliche Hilfslinie (Pufferobjekt) eines beliebigen Indikatorobjekts genau bestimmen.
Wenn wir z.B. möchten, dass der Indikator, der den gleitenden Durchschnitt zeichnet, bestimmte Zustände seiner Hauptlinie anzeigt, wie z.B. das Überqueren der Linie durch den Preis, die Interaktion der Linie mit anderen Indikatoren usw., können wir unserem nutzerdefinierten Indikator ein oder mehrere Pufferobjekte hinzufügen und durch diesen Puffer im Chart die erforderlichen Daten in den erforderlichen Momenten anzeigen - um Pfeile zu setzen, Flächen zu malen usw.


Verbesserungen der Bibliotheks-Klassen und -Methoden

Tragen wir zunächst die neue Bibliotheks-Textnachricht in die Datei \MQL5\Include\DoEasy\Data.mqh ein.

Neuen Nachrichtenindices hinzufügen:

//--- 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)

und die Texte, der den neu hinzugefügten Indices entsprechen:

   {"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)"},

In der Datei \MQL5\Include\DoEasy\Defines.mqh mit der Enumeration der Indikatorlinientypen fügen wir neue Linien für Ichimoku Kinko Hyo Indikator und eine weitere Linie als Hilfslinie hinzu — zum Zeichnen unserer Indikatoren:

//+------------------------------------------------------------------+
//| 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
  };
//+------------------------------------------------------------------+

Da ich im vorigen Artikel identische Werte für gleichartige Indikatorlinien in dieser Enumeration festgelegt und Handles verschiedener Objekte von Standardindikatoren zu einem einzigen vereinigt habe, sehen wir jetzt bei der Anzeige von Linientyp-Beschreibungen aus einem Pufferobjekt Beschreibungen der Linien, die den allerersten angetroffenen Werten dieser Enumeration entsprechen. Wenn ich z.B. die Beschreibung der Linie Jaws des Standardindikators Alligator darstelle und der Wert der Konstante INDICATOR_LINE_MODE_JAWS in dieser Aufzählung gleich Null ist, wird die Beschreibung der ersten Konstante aus dieser Enumeration angezeigt, deren Wert ebenfalls gleich Null ist - die Konstanten INDICATOR_LINE_MODE_MAIN.
Dies ist kein Fehler, sondern eine unangenehmes Durcheinander. Um das zu vermeiden, müssen wir für jede Enumerationskonstante einen eindeutigen Wert haben. Aber in diesem Fall müssen die Bearbeitung erneut aufgeteilt werden, was viel schlimmer ist. Wir werden also wie folgt vorgehen: Wir fügen eine weitere Enumeration hinzu und zeigen die Beschreibung der Linie des Pufferobjekts an, indem wir genau prüfen, welche Linie von welchem Indikator genau der Puffer anzeigt, und zeigen den Wert der neuen Enumeration an, der dem Pufferobjekt entspricht.

Fügen Sie diese Enumeration hinzu:

//+------------------------------------------------------------------+
//| 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
  };
//+------------------------------------------------------------------+

In dieser Enumeration hat jede Konstante ihren eigenen eindeutigen Wert im Bereich von 0 bis 15, und jetzt können wir die erforderlichen Werte für jede spezifische Linie eines bestimmten Indikators leicht anzeigen. Machen wir das so.

In derselben Datei fügen wir eine weitere Pufferobjekt-Integer-Eigenschaft hinzu, gleichzeitig erhöhen wir die Anzahl der Pufferobjekt-Integer-Eigenschaften von 24 auf 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
//+------------------------------------------------------------------+

Um Pufferobjekte nach einer neuen Eigenschaft suchen und sortieren zu können fügen wir dieser Eigenschaft zur Enumeration möglicher Sortierkriterien hinzu:

//+------------------------------------------------------------------+
//| 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
  };
//+------------------------------------------------------------------+

Verbessern wir jetzt noch etwas die abstrakte Pufferobjektklasse in \MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh.

Wir schreiben im 'public' Teil der Klasse die Methoden zum Setzen und zur Rückgabe zusätzliche Liniennummer zurück:

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);              }

Da ich nun die Beschreibung der Indikatorlinie aus einer anderen Enumeration (oben implementiert) anzeigen werde, wird die Methode IndicatorLineMode() nun einen ganzzahligen Wert anstelle des Enumerationswertes ENUM_INDICATOR_LINE_MODE zurückgeben.

Im gleichen 'public' Teil der Klasse deklarieren wir die Methode, die die Beschreibung der Indikatorlinie zurückgibt:

//--- 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;

und schreiben seine Implementierung außerhalb des Klassenkörpers:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Hier deklarieren wir die Variable, die den Verschiebungswert speichert, um den die Werte der Enumerationskonstanten ENUM_INDICATOR_LINE_MODE erhöht werden müssen, um an den Anfang der Deklaration der Zeilenkonstanten des entsprechenden Indikators in Enumeration ENUM_INDICATOR_LINE zu gelangen.
Wenn wir zum Beispiel die Beschreibung der Linie Teeth des Allegator-Indikators anzeigen müssen, ist der Verschiebungswert gleich 5, was auf die Konstante INDICATOR_LINE_JAWS der Enumeration ENUM_INDICATOR_LINE zeigt:

//+------------------------------------------------------------------+
//| 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
  };
//+------------------------------------------------------------------+

Und da unser Puffer den Wert der Linie Teeth aus der Methode GetProperty(BUFFER_PROP_IND_LINE_MODE) zurückgibt und dieser Wert gleich eins ist, ergibt die Addition des Wertes von 5 zu eins einen konstanten Index, der gleich 6 ist, was auf die Konstante INDICATOR_LINE_TEETH hinweist.

Als Ergebnis gibt die Methode die Textbeschreibung der erhaltenen Konstante reduziert auf den Wert "LINE_TEETH" zurück.

In der Klasse geschlossener Konstruktor setzen wir den Standardwert auf eine neue Eigenschaft des Pufferobjekts als -1, was keine zusätzliche Indikatorlinie bedeutet:

//+------------------------------------------------------------------+
//| 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=
     (

In der Methode, die die Beschreibung der ganzzahligen Eigenschaft des Pufferobjekts zurückgibt, fügen wir einen Codeblock für die Rückgabe der neuen Eigenschaftsbeschreibung hinzu und verbessern den Codeblock, der die Beschreibung der Indikatorlinie anzeigt (jetzt werden wir die Beschreibung mit einer neuen Methode anzeigen, die speziell für diesen Zweck geschrieben wurde):

//+------------------------------------------------------------------+
//| 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()
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Da wir eine neue ganzzahlige Eigenschaft hinzugefügt haben, führen wir in allen Klassen von nachkommenden Objekten des abstrakten Pufferobjekts eine Verbesserung in der virtuellen Methode durch, die das Flag der Unterstützung durch das Objekt dieser neuen Eigenschaft zurückgibt (am Beispiel der Klassenmethode 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;
  }
//+------------------------------------------------------------------+

Die gleichen Änderungen wurden in allen Dateien aller Pufferobjekte vorgenommen, wie z.B. BufferArrow.mqh, BufferBars.mqh, BufferCandles.mqh, BufferFilling.mqh, BufferHistogram.mqh, BufferHistogram2.mqh, BufferLine.mqh, BufferSection.mqh und BufferZigZag.mqh.

Alle Methoden zum Anlegen der Objekte von Standardindikatoren befinden sich in der Kollektionsklasse der Puffer
im Ordner \MQL5\Include\DoEasy\Collections\BuffersCollection.mqh. Bevor wir zwei Methoden zur Erstellung von Objekten der Standardindikatoren Ichimoku Kinko Hyo und Gator Oscillator hinzufügen, wollen wir die Methode zur Vorbereitung der Daten des angegebenen Standardindikators für die Einstellung von Werten auf dem aktuellen Symbolchart etwas verbessern. Da der Ichimoku Kinko Hyo-Indikator fünf zu zeichnende Puffer hat, aber nur drei Zeiger auf Standardindikator-Pufferobjekte an die Methode und jeweils sechs Variablen übergeben werden - durch die Verknüpfung (zwei für jeden Puffer), um Werte von Indikatorlinien in sie zu schreiben, ist es notwendig, der Methode die Übergabe von vier zusätzlichen Zeigern auf Pufferobjekte (zwei für jeden gezeichneten und berechneten einen) und die Übergabe von vier weiteren Variablen durch die Verknüpfung hinzuzufügen.

Fügen wir im Klassenkörper die Methodendeklaration mit den erforderlichen Werten hinzu:

//--- 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,

Bei der Implementierung der außerhalb des Klassenkörpers geschriebenen Methode fügen wir die notwendige Änderungen hinzu:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Wir haben einfach die gleiche Behandlung wie bei Pufferobjekten, die bereits in der Methode verfügbar sind, zu zwei neuen Pufferobjektzeigern hinzugefügt, auf die der Methode übergeben werden; und Schreiben von Werten in die Variablen, die den Puffern entsprechen, die der Methode durch die Verknüpfung übergeben werden.

Da zwischen zwei Linien des Standardindikators Ichimoku Kinko Hyo Schraffuren gezeichnet werden, wobei für jede Linie die Art der Schraffur und die Farbe festgelegt wird, die dem Typ und der Farbe der Linie entspricht:


... wir brauchen eine Methode, die den Zeiger auf das Standardindikator-Pufferobjekt nach Indikatortyp, seiner ID und Linie zurückgibt, so dass wir alle Parameter aus ihm nehmen können, die für das Zeichnen seiner Linien gesetzt sind, und sie für ein Hilfspufferobjekt setzen können, das zur Gestaltung des Erscheinungsbildes unseres nutzerdefinierten Indikators dient.

Im 'public' Teil der Klasse deklarieren wir diese Methode

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

und schreiben seine Implementierung außerhalb des Klassenkörpers:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Hier ist alles ganz einfach: Zuerst wird die Liste der Pufferobjekte nach dem Typ des Standardindikators und seiner ID geholt, dann wird die erhaltene Liste nach dem Linientyp des Standardindikators sortiert und schließlich werden von den übrigen Objekten nur diejenigen in der Liste belassen, die die ID des Hilfspuffers haben (standardmäßig wird allen Puffern der Wert -1 zugewiesen, was das Fehlen einer solchen ID bedeutet).
Die Methode gibt das erste Objekt aus der sortierten Liste zurück.

Ergänzung einer Methode, die berechnete Pufferdaten des angegebenen Standardindikators für die Standardindikatoren Ichimoku Kinko Hyo und Gator Oszillator vorbereitet.
Wir brauchen nur die Handhabung hinzuzufügen, die dem Indikatortyp entspricht. Diese Behandlung ist für alle Indikatoren identisch und bereits in der Methode implementiert. Aber es gibt einen kleinen Unterschied für den Standardindikator Gator-Oszillator sein zweiter Puffer hat den Index 2 anstelle von 1, wie es andere Indikatoren mit zwei Puffern tun denn der Puffer mit Index 1 gehört zum Farbpuffer des Datenpuffers mit Index 0. Ich werde keine Standardindikator-Farbpuffer verwenden, da ich bereits die Handhabung und Einstellung der Farbe für Indikator-Linien erstellt habe, außerdem kann ich jedem Balken die erforderliche Farbe zuweisen, daher wird die Farbe der Spalten des Gator-Oszillator standardmäßig automatisch von der Bibliothek berechnet. Und eine solche Berechnung wird bereits durchgeführt. Wo es angebracht ist, kann der Nutzer die erforderliche Farbe für jeden Balken an Datenzeichnungsmethoden von Standardindikatoren übergeben, um eine eigene Farbgebung des Indikators zu erstellen.
Für den Indikator Ichimoku Kinko Hyo ist die Datenaufbereitung identisch mit der Datenaufbereitung anderer Standardindikatoren - nur zwei Puffer mehr
.

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Zur Methode zum Löschen der Datenpuffer des angegebenen Standardindikators durch den Zeitreihenindex fügen wir die Handhabung von Puffern für Ichimoku Kinko Hyo-Indikator hinzu:

//+------------------------------------------------------------------+
//| 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;
     }
  }
//+------------------------------------------------------------------+

Da ich weiterhin das Objekt des Ichimoku Kinko Hyo Standardindikators erstellen werde und es zwei zusätzliche Histogramm-Puffer für die Gestaltung des Indikator-Erscheinungsbildes braucht, sind die Methodencode-Blöcke für die Datenlöschung dieser beiden Hilfspuffer bereits hinzugefügt worden.
Der Rest ist identisch mit dem Pufferdaten-Clearing anderer Standardindikatoren, die in früheren Artikeln implementiert wurden.

Verbessern wir die Methode, die Werte für das aktuelle Chart auf Puffer des angegebenen Standardindikators durch den Zeitreihenindex in Übereinstimmung mit Pufferobjektsymbol/Periode setzt.

Nun wird die Methode mehr Pufferobjekte haben, da Ichimoku Kinko Hyo fünf davon hat, plus zwei Hilfshistogrammpuffer zur Gestaltung des Erscheinungsbildes des Indikators. Dementsprechend hat sich die Anzahl der Variablen zur Speicherung der Werte aller Pufferobjektlinien erhöht:

//+------------------------------------------------------------------+
//| 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

In jedem Codeblock, der seinen Satz von Standardindikatoren hat, werden jetzt mehr Werte an die Puffer-Datenvorbereitungsmethode PreparingSetDataStdInd() übergeben:

        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);

In method end add handlers of standard indicators Ichimoku Kinko Hyo and Gator Oscillator:

      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;

Der Code ist mit Kommentaren zu den Aktionen versehen, die sich von denselben Code-Blöcken für die Behandlung anderer Standardindikatoren unterscheiden, die in früheren Artikeln betrachtet wurden. Dies betraf nur die Beschaffung und Behandlung von Daten für die Gestaltung des Ichimoku Kinko Hyo-Indikators. Für den Gator-Oszillator-Indikator blieb die gesamte Logik die gleiche wie für die anderen Standardindikatoren.

Jetzt schreiben wir Methoden für die Erstellung von Objekten der Standardindikatoren Ichimoku Kinko Hyo und Gator Oszillator.

Die Methode zur Erstellung des Gator-Oszillators:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Bei der Erstellung des Indikator-Handles übergeben wir ihm die Daten zur Verschiebung der Linien des Alligator-Indikators, auf denen die Daten des Gator berechnet werden, wie sie in den Eingaben sind, unabhängig davon, dass der Indikator auf "nicht einheimischen" Zeitrahmen gezeichnet werden kann - alle diese Daten werden für die interne Berechnung des Indikators benötigt. Visuelle Verschiebung der Linien des Gator-Standardindikators wird als Minimalwert aus den Werten der Verschiebung der Linien von Teeth und Jaw des Alligator-Indikators berechnet, aus denen der Gator berechnet wird. Und diese visuelle Verschiebung muss mit einer Anzahl von Balken multipliziert werden, die im aktuellen Zeitrahmen angezeigt werden sollten. Und wir tun es, indem wir den Verschiebungswert für die gezeichneten Pufferobjekte des Indikators einstellen . Für berechnete Pufferobjekte stellen wir die Verschiebung ohne Multiplikation mit einer Anzahl von Balken ein .

Die Methode für die Erstellung von 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;
  }
//+------------------------------------------------------------------+

Hier, wie auch bei der Erstellung des Objekts des Gator-Standardindikators bei der Erstellung des Handles zu ihm, werden Eingaben ohne Änderung und bei der Erstellung von Pufferobjekten für die Anzeige von Linien der Senkou-Spanne A und der Senkou-Spanne B und zusätzlichen Puffern für die Gestaltung des Bereichs zwischen diesen beiden Linien als Histogramm multipliziert, um die erforderliche Anzahl von Balken zu erhalten, die auf dem aktuellen Chart angezeigt werden müssen. Bei der Erstellung von Objekten aus berechneten Puffern stellen Sie die Verschiebung ohne Multiplikation mit einer Anzahl von Balken des aktuellen Charts ein.
Die Berechnungsperiode der Linien Kijun-Sen dient als Verschiebung für die Linien Senkou Span A und Senkou Span B.
Wenn Sie zusätzliche Histogrammpuffer erstellen setzen Sie zuerst alle Standardparameter des Indikators und dann holen Sie das Pufferobjekt der Linie, die dem Histogramm entspricht und setzen Sie die Zeichenparameter für das Histogramm auf die gleichen wie für die Indikatorlinie, die Werte aus dem Puffer der Linie erhält.

Für Pufferobjekte von Histogrammen setzen Sie eine Eigenschaft nicht auf das Darstellen seiner Linie im Datenfenster - diese Puffer sind nur für das Design notwendig und ihre Werte entsprechen vollständig den Indikatorlinien, aus denen sie ihre Daten beziehen.

Damit ist die Verbesserung der Klassen und Methoden der Bibliothek zur Erstellung von Mehrsymbol- und Mehrperioden-Standardindikatoren abgeschlossen. Jetzt verfügen wir über den vollständigen Satz von Methoden zur Erstellung beliebiger Standard- und nutzerdefinierter Multi-Indikatoren in nutzerdefinierten Programmen. Sicherlich gibt es bei der Weiterentwicklung der Bibliotheksfunktionalität noch Unzulänglichkeiten, die nach und nach behoben werden müssen.

Test

Um den Test durchzuführen, nehmen wir den Indikator aus dem vorherigen Artikel und erstellen zwei neue Indikatoren in dem neuen Ordner \MQL5\Indikatoren\TestDoEasy\Teil51\
unter den Namen TestDoEasyPart51_1.mq5 und TestDoEasyPart51_2.mq5.

Sie werden sich nur durch den Parameter #property indicator_chart_window oder #property indicator_separate_window unterscheiden, da einer von ihnen auf dem Hauptchart und der zweite in einem Unterfenster gezeichnet wird. Außerdem werden wir in einem Fall den Indikator Ichimoku Kinko Hyo und im zweiten Fall den Gator-Oszillator erstellen.

Löschen der Text-Eingaben, die den Indikatortyp und eine Verschiebung der Linien festlegen:

sinput   ENUM_INDICATOR       InpIndType        =  IND_AC;        // Type standard indicator
sinput   int                  InpShift          =  0;             // Indicator line shift

In OnInit() in der Datei TestDoEasyPart51_1.mq5 erzeugen wir das Objekt des 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);
  }
//+------------------------------------------------------------------+

In OnCalculate() behandeln nur einen erstellten Indikator:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Nehmen Sie in der Datei TestDoEasyPart51_2.mq5 die gleichen Änderungen vor, aber anstatt den Ichimoku Kinko Hyo Gator-Oszillator zu erstellen und zu verwenden, erstellen und verwenden Sie Ichimoku Kinko Hyo. Und einen Hinweis setzen, damit der Präprozessor einen Indikator erstellt, der in einem Unterfenster arbeitet:

//+------------------------------------------------------------------+
//|                                           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

Starten Sie beide Indikatoren auf dem EURUSD H1 Chart, nachdem Sie in den Indikatoreneinstellungen angegeben haben, Daten von EURUSD H4 für die Berechnung zu verwenden. Und vergleichen Sie sie mit Standardindikatoren:


Wie Sie sehen können, stimmen die Daten beider Indikatoren mit den Daten der Standardindikatoren überein.

Die vollständigen Codes beider Indikatoren sind in den beigefügten Dateien enthalten.

Was kommt als Nächstes?

Im nächsten Artikel werden wir mit der Arbeit an der Kompatibilität der Objektklassen von Standardindikatoren mit MQL4 beginnen.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit den Testindikator-Dateien angehängt. Sie können sie herunterladen und alles testen.
Hinterlassen Sie Ihre Kommentare, Fragen und Vorschläge in den Kommentaren zum Artikel.
Bitte denken Sie daran, dass ich hier MQL5-Testindikatoren für MetaTrader 5 entwickelt habe.
Die angehängten Dateien sind nur für MetaTrader 5 bestimmt. Die aktuelle Bibliotheksversion wurde nicht mit dem MetaTrader 4 getestet.

Zurück zum Inhalt

Frühere Artikel dieser Serie:

Zeitreihen in der Bibliothek DoEasy (Teil 35): das Balkenobjekt und die Liste der Zeitreihen eines Symbols
Zeitreihen in der Bibliothek DoEasy (Teil 36): Objekt der Zeitreihe für alle verwendeten Symbolzeitrahmen
Zeitreihen in der Bibliothek DoEasy (Teil 37): Kollektion von Zeitreihen - Datenbank der Zeitreihen nach Symbolen und Zeitrahmen
Zeitreihen in der Bibliothek DoEasy (Teil 38): Kollektion von Zeitreihen - Aktualisierungen in Echtzeit und Datenzugriff aus dem Programm
Zeitreihen in der Bibliothek DoEasy (Teil 39): Bibliotheksbasierte Indikatoren - Vorbereitung der Daten und Zeitreihen
Zeitreihen in der Bibliothek DoEasy (Teil 40): Bibliotheksbasierte Indikatoren - Aktualisierung der Daten in Echtzeit
Zeitreihen in der Bibliothek DoEasy (Teil 41): Beispiel eines Multi-Symbol- und Multi-Zeitrahmen-Indikators
Zeitreihen in der Bibliothek DoEasy (Teil 42): Abstrakte Objektklasse der Indikatorpuffer
Zeitreihen in der Bibliothek DoEasy (Teil 43): Klassen der Objekte von Indikatorpuffern
Zeitreihen in der Bibliothek DoEasy (Teil 44): Kollektionsklasse der Objekte von Indikatorpuffern
Zeitreihen in der Bibliothek DoEasy (Teil 45): Puffer für Mehrperiodenindikator
Zeitreihen in der Bibliothek DoEasy (Teil 46): Mehrperioden-Multisymbol-Indikatorpuffer
Zeitreihen in der Bibliothek DoEasy (Teil 47): Standardindikatoren für mehrere Symbole und Perioden
Zeitreihen in der Bibliothek DoEasy (Teil 48): Mehrperioden-Multisymbol-Indikatoren mit einem Puffer in einem Unterfenster
Zeitreihen in der Bibliothek DoEasy (Teil 49): Standardindikatoren mit mehreren Puffern für mehrere Symbole und Perioden
Zeitreihen in der Bibliothek DoEasy (Teil 50): Verschieben der Standardindikatoren für mehrere Symbole und Perioden

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/8354

Beigefügte Dateien |
MQL5.zip (3770.76 KB)
Fortschrittliches Resampling und Auswahl von CatBoost-Modellen durch die Brute-Force-Methode Fortschrittliches Resampling und Auswahl von CatBoost-Modellen durch die Brute-Force-Methode
Dieser Artikel beschreibt einen der möglichen Ansätze zur Datentransformation mit dem Ziel, die Verallgemeinerbarkeit des Modells zu verbessern, und erörtert auch die Stichprobenziehung und Auswahl von CatBoost-Modellen.
Ein wissenschaftlicher Ansatz für die Entwicklung von Handelsalgorithmen Ein wissenschaftlicher Ansatz für die Entwicklung von Handelsalgorithmen
Der Artikel befasst sich mit der Methodik zur Entwicklung von Handelsalgorithmen, bei der ein konsistenter, wissenschaftlicher Ansatz zur Analyse möglicher Kursmuster und zur Erstellung von Handelsalgorithmen auf der Grundlage dieser Muster verwendet wird. Die Entwicklungsideale werden anhand von Beispielen demonstriert.
Kontinuierliche Walk-Forward-Optimierung (Teil 8): Programmverbesserungen und Korrekturen Kontinuierliche Walk-Forward-Optimierung (Teil 8): Programmverbesserungen und Korrekturen
Das Programm wurde aufgrund von Kommentaren und Wünschen von Nutzern und Lesern dieser Artikelserie geändert. Dieser Artikel enthält eine neue Version des Auto-Optimierers. Diese Version implementiert gewünschte Funktionen und bietet weitere Verbesserungen, die ich bei der Arbeit mit dem Programm gefunden habe.
Zeitreihen in der Bibliothek DoEasy (Teil 50): Verschieben der Standardindikatoren für mehrere Symbole und Perioden Zeitreihen in der Bibliothek DoEasy (Teil 50): Verschieben der Standardindikatoren für mehrere Symbole und Perioden
In diesem Artikel wollen wir die Bibliotheksmethoden für die korrekte Anzeige von Mehrsymbol- und Mehrperioden-Standardindikatoren verbessern, wobei die Linien auf dem aktuellen Symbol-Chart mit einer in den Einstellungen festgelegten Verschiebung angezeigt werden. Außerdem sollten wir die Methoden für die Arbeit mit Standardindikatoren in Ordnung bringen und den redundanten Code für den Bibliotheksbereich im endgültigen Indikatorprogramm entferne.