Zeitreihen in der Bibliothek DoEasy (Teil 43): Klassen der Objekte von Indikatorpuffern

Artyom Trishkin | 26 August, 2020

Inhalt


Konzept

Im vorigen Artikel haben wir das abstrakte Indikatorpufferobjekt erstellt, das einige gemeinsame Eigenschaften von Indikatorpuffern enthält und die Methoden für die Arbeit mit ihnen bereitstellt. Hier werden wir Objekte erstellen, die von der abstrakten Pufferobjektklasse abgeleitet sind. Jedes Objekt dieser Art ist ein unabhängiges Indikatorpufferobjekt mit seiner eigenen, einzigartigen Art der grafischen Konstruktion.
Wie bereits früher erwähnt, sind alle Indikatorpuffer farbig markiert. Wird jedoch ein einfarbiger benötigt, werden die Puffer zunächst einfarbig angelegt. Alternativ sind wir in der Lage, die Anzahl der Farben, die vom Puffer verwendet werden, während des Indikatorbetriebs direkt einzustellen.

Zuerst fügen wir die neuen Bibliotheksmeldungen hinzu.
Öffnen Sie \MQL5\Include\DoEasy\Datas.mqh und fügen Sie die Indizes für die neuen Nachrichten hinzu:

   MSG_LIB_SYS_FAILED_CREATE_BAR_OBJ,                 // Failed to create the \"Bar\" object
   MSG_LIB_SYS_FAILED_SYNC_DATA,                      // Failed to synchronize data with the server
   MSG_LIB_SYS_FAILED_DRAWING_ARRAY_RESIZE,           // Failed to change the array size of drawn buffers
   MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE,            // Failed to change the color array size

...

   MSG_LIB_TEXT_BUFFER_TEXT_LINE_WIDTH,               // Line width
   MSG_LIB_TEXT_BUFFER_TEXT_ARROW_SIZE,               // Arrow size
   MSG_LIB_TEXT_BUFFER_TEXT_COLOR_NUM,                // Number of colors
   MSG_LIB_TEXT_BUFFER_TEXT_COLOR,                    // Drawing color
   MSG_LIB_TEXT_BUFFER_TEXT_EMPTY_VALUE,              // Empty value for plotting where nothing will be drawn
   MSG_LIB_TEXT_BUFFER_TEXT_SYMBOL,                   // Buffer symbol
   MSG_LIB_TEXT_BUFFER_TEXT_LABEL,                    // Name of the graphical indicator series displayed in DataWindow
   MSG_LIB_TEXT_BUFFER_TEXT_STATUS_NAME,              // Indicator buffer with graphical construction type 
   MSG_LIB_TEXT_BUFFER_TEXT_INVALID_PROPERTY_BUFF,    // Invalid number of indicator buffers in #property indicator_buffers

...

   MSG_LIB_TEXT_BUFFER_TEXT_TYPE_CALCULATE,           // Calculated buffer
   MSG_LIB_TEXT_BUFFER_TEXT_TYPE_DATA,                // Colored data buffer
   MSG_LIB_TEXT_BUFFER_TEXT_BUFFER,                   // Buffer
   
   MSG_LIB_TEXT_BUFFER_TEXT_STYLE_SOLID,              // Solid line
   MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASH,               // Dashed line
   MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DOT,                // Dotted line
   MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOT,            // Dot-dash line
   MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOTDOT,         // Dash - two dots
   
  };

Als Nächstes fügen Sie die neuen Textnachrichten entsprechend den neu hinzugefügten Indizes hinzu:

   {"Не удалось создать объект \"Бар\"","Failed to create object \"Bar\""},
   {"Не удалось синхронизировать данные с сервером","Failed to sync data with server"},
   {"Не удалось изменить размер массива рисуемых буферов","Failed to resize drawing buffers array"},
   {"Не удалось изменить размер массива цветов","Failed to resize color array"},

...

   {"Толщина линии отрисовки","Thickness of drawing line"},
   {"Размер значка стрелки","Arrow icon size"},
   {"Количество цветов","Number of colors"},
   {"Цвет отрисовки","Index of buffer containing drawing color"},
   {"Пустое значение для построения, для которого нет отрисовки","Empty value for plotting, for which there is no drawing"},
   {"Символ буфера","Buffer Symbol"},
   {"Имя индикаторной графической серии, отображаемое в окне DataWindow","Name of indicator graphical series to display in DataWindow"},
   {"Индикаторный буфер с типом графического построения","Indicator buffer with graphic plot type"},
   {"Неправильно указано количество буферов индикатора (#property indicator_buffers)","Number of indicator buffers is incorrect (#property indicator_buffers)"},

...

   {"Расчётный буфер","Calculated buffer"},
   {"Цветной буфер данных","Colored Data buffer"},
   {"Буфер","Buffer"},
   
   {"Сплошная линия","Solid line"},
   {"Прерывистая линия","Broken line"},
   {"Пунктирная линия","Dotted line"},
   {"Штрих-пунктирная линия","Dash-dot line"},
   {"Штрих - две точки","Dash - two points"},
   
  };
//+---------------------------------------------------------------------+

Fügen Sie in \MQL5\Include\DoEasy\Defines.mqh, das Makro, das die maximal mögliche Anzahl der einstellbaren Indikatorpufferfarben angibt, im Abschnitt Makroersetzung hinzu:

//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
//--- Describe the function with the error line number
#define DFUN_ERR_LINE                  (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(string)__LINE__+": ")
#define DFUN                           (__FUNCTION__+": ")        // "Function description"
#define COUNTRY_LANG                   ("Russian")                // Country language
#define END_TIME                       (D'31.12.3000 23:59:59')   // End date for account history data requests
#define TIMER_FREQUENCY                (16)                       // Minimal frequency of the library timer in milliseconds
#define TOTAL_TRY                      (5)                        // Default number of trading attempts
#define IND_COLORS_TOTAL               (64)                       // Maximum possible number of indicator buffer colors
//--- Standard sounds

Dies geschieht, um zu vermeiden, dass die Überprüfung der Anzahl der spezifizierten Farben über 64 hinausgeht, vor allem wenn man bedenkt, dass sie möglicherweise eines Tages erhöht wird.

Nun wollen wir die abstrakte Pufferobjektklasse etwas verbessern.
Die Indikatorpuffer befinden sich derzeit im öffentlichen Bereich der Klasse in den Arrays des realen Datentyps für die Daten- und Farbindexpuffer. Entfernen Sie sie aus dem Abschnitt 'protected'. Da wir mehrere Indikator-Konstruktionspuffer haben können, erstellen Sie die Pufferstruktur, die ein einziges Array enthält.
Warum brauchen wir das?
Da der Indikatorpuffer nur durch ein eindimensionales Array mit Daten vom Typ double dargestellt werden kann, werden wir die Struktur mit einem einzigen Array implementieren, um das Pufferarray zu erstellen (es kann mehr als ein Array geben). In diesem Fall werden wir alle Daten-Arrays (Indikator-Puffer), die für die Konstruktion des Indikators erforderlich sind, in dem Array solcher Strukturen haben. Auf sie soll über den Index des erforderlichen Arrays zugegriffen werden.
Um zu vermeiden, dass Sie durch versehentliche Übergabe eines falschen Index über das Array hinausgehen, erstellen Sie die Methode, die übergebene Array-Indizes anpasst, falls der Index außerhalb des Arrays liegt. In diesem Fall wird der Index angepasst, um das allerletzte Element des Strukturarrays zu spezifizieren. Im Falle eines einzelnen Arrays zeigt der Index auf dieses Array.

Deklarieren Sie in der Datei des abstrakten Pufferobjekts \MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh (im 'private' Teil) die Methode, die den angepassten Pufferarray-Index zurückgibt,
während im 'protected' Teil die Struktur von Puffer-Arrays, das Array-Objekt von Puffern mit dem Strukturtyp, das Farbpuffer-Array und das verwendetes Farb-Array zur Einfärbung der Indikator-Konstruktionen deklariert wird:

//+------------------------------------------------------------------+
//| Abstract indicator buffer class                                  |
//+------------------------------------------------------------------+
class CBuffer : public CBaseObj
  {
private:
   long              m_long_prop[BUFFER_PROP_INTEGER_TOTAL];                     // Integer properties
   double            m_double_prop[BUFFER_PROP_DOUBLE_TOTAL];                    // Real properties
   string            m_string_prop[BUFFER_PROP_STRING_TOTAL];                    // String properties
//--- Return the index of the array the buffer's (1) double and (2) string properties are located at
   int               IndexProp(ENUM_BUFFER_PROP_DOUBLE property)           const { return(int)property-BUFFER_PROP_INTEGER_TOTAL;                           }
   int               IndexProp(ENUM_BUFFER_PROP_STRING property)           const { return(int)property-BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_DOUBLE_TOTAL;  }
//--- Set the graphical construction type
   void              SetDrawType(void);
//--- Return the adjusted buffer array index
   int               GetCorrectIndexBuffer(const uint buffer_index) const;

protected:
//--- Structure for storing buffer object buffer arrays
   struct SDataBuffer { double Array[]; };
//--- Array of (1) all indicator buffer object buffers, (2) color buffer, (3) for storing colors
   SDataBuffer       DataBuffer[];
   double            ColorBufferArray[];
   int               ArrayColors[];
   
public:

Entfernen Sie die nun überflüssigen Daten und Farbarrays aus dem 'public' Teil der Klasse:

public:
//--- Array of the (1) drawn indicator buffer and (2) color buffer
   double            DataArray[];
   double            ColorArray[];

Im vorigen Artikel habe ich den 'protected' Konstruktor des abstrakten Pufferobjekts in den 'public' Teil verschoben, damit wir vom Indikatorprogramm aus darauf zugreifen können. Schließen wir es nun, so dass beim Erstellen von Indikatorpuffern des angegebenen Typs von den Nachfolgeobjekten der Klasse aus darauf zugegriffen werden kann. Entkommentieren Sie die Zeile und fügen Sie mehrere neue Variablen zur Verdeutlichung der erzeugten Puffereigenschaften zum geschützten Konstruktor hinzu. Zu diesen Eigenschaften gehören die Anzahl der für die Konstruktion verwendeten Puffer, Linienbreite und Pufferbeschreibung im Datenfenster:

protected:
//--- Protected parametric constructor
                     CBuffer(ENUM_BUFFER_STATUS status_buffer,
                             ENUM_BUFFER_TYPE buffer_type,
                             const uint index_plot,
                             const uint index_base_array,
                             const int num_datas,
                             const int width,
                             const string label);
public:  

Jetzt haben wir die Methode zum Setzen einer einzelnen Farbe der SetColor()-Indikatorpuffer. Da jedoch alle unsere Puffer farbig sind, benötigen wir auch die Möglichkeit, eine neue Farbe zu den bereits vorhandenen Puffern hinzuzufügen oder alle vom Puffer verwendeten Farben auf einmal zu setzen.
Deklarieren wir noch zwei zusätzliche Methoden zum Einstellen der Farbe:

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

Die erste Methode fügt dem Array von Pufferobjektfarben eine neue Farbe mit dem angegebenen neuen Farbindex hinzu, während die zweite Methode es ermöglicht, alle vom Pufferobjekt verwendeten und an die Methode im Array übergebenen Farben einzustellen.

Im Block der Methoden zur Rückgabe der Eigenschaftswerte des Pufferobjekts benennen die Methode NumberColors() um, die die Anzahl der vom Puffer verwendeten Farben zurückgibt und die Methode, die die Anzahl der Puffer-Arrays zurückgibt, die zum Zeichnen der Pufferobjektdaten verwendet wurden:

//--- Return (1) the serial number of the drawn buffer, (2) bound array index, (3) color buffer index,
//--- (4) index of the first free bound array, (5) buffer data period (timeframe) (6) buffer status,
//--- (7) buffer type, (8) buffer usage flag, (9) arrow code, (10) arrow shift for DRAW_ARROW style,
//--- (11) Number of initial bars that are not drawn and values in DataWindow, (12) graphical construction type,
//--- (13) flag of displaying construction values in DataWindow, (14) indicator graphical construction shift along the time axis,
//--- (15) drawing line style, (16) drawing line width, (17) number of colors, (18) drawing color, number of buffers for construction
//--- (19) set empty value, (20) buffer symbol and (21) name of the indicator graphical series displayed in DataWindow
   int               IndexPlot(void)                           const { return (int)this.GetProperty(BUFFER_PROP_INDEX_PLOT);              }
   int               IndexBase(void)                           const { return (int)this.GetProperty(BUFFER_PROP_INDEX_BASE);              }
   int               IndexColor(void)                          const { return (int)this.GetProperty(BUFFER_PROP_INDEX_COLOR);             }
   int               IndexNextBuffer(void)                     const { return (int)this.GetProperty(BUFFER_PROP_INDEX_NEXT);              }
   ENUM_TIMEFRAMES   Timeframe(void)                           const { return (ENUM_TIMEFRAMES)this.GetProperty(BUFFER_PROP_TIMEFRAME);   }
   ENUM_BUFFER_STATUS Status(void)                             const { return (ENUM_BUFFER_STATUS)this.GetProperty(BUFFER_PROP_STATUS);   }
   ENUM_BUFFER_TYPE  TypeBuffer(void)                          const { return (ENUM_BUFFER_TYPE)this.GetProperty(BUFFER_PROP_TYPE);       }
   bool              IsActive(void)                            const { return (bool)this.GetProperty(BUFFER_PROP_ACTIVE);                 }
   uchar             ArrowCode(void)                           const { return (uchar)this.GetProperty(BUFFER_PROP_ARROW_CODE);            }
   int               ArrowShift(void)                          const { return (int)this.GetProperty(BUFFER_PROP_ARROW_SHIFT);             }
   int               DrawBegin(void)                           const { return (int)this.GetProperty(BUFFER_PROP_DRAW_BEGIN);              }
   ENUM_DRAW_TYPE    DrawType(void)                            const { return (ENUM_DRAW_TYPE)this.GetProperty(BUFFER_PROP_DRAW_TYPE);    }
   bool              IsShowData(void)                          const { return (bool)this.GetProperty(BUFFER_PROP_SHOW_DATA);              }
   int               Shift(void)                               const { return (int)this.GetProperty(BUFFER_PROP_SHIFT);                   }
   ENUM_LINE_STYLE   LineStyle(void)                           const { return (ENUM_LINE_STYLE)this.GetProperty(BUFFER_PROP_LINE_STYLE);  }
   int               LineWidth(void)                           const { return (int)this.GetProperty(BUFFER_PROP_LINE_WIDTH);              }
   int               ColorsTotal(void)                        const { return (int)this.GetProperty(BUFFER_PROP_COLOR_INDEXES);           }
   color             Color(void)                               const { return (color)this.GetProperty(BUFFER_PROP_COLOR);                 }
   int               BuffersTotal(void)                        const { return (int)this.GetProperty(BUFFER_PROP_NUM_DATAS);               }
   double            EmptyValue(void)                          const { return this.GetProperty(BUFFER_PROP_EMPTY_VALUE);                  }
   string            Symbol(void)                              const { return this.GetProperty(BUFFER_PROP_SYMBOL);                       }
   string            Label(void)                               const { return this.GetProperty(BUFFER_PROP_LABEL);                        }

Im Block der Methoden, die die Beschreibung der Eigenschaften des Pufferobjekts zurückgeben, fügen wir die Methode hinzu, die die Beschreibung der spezifizierten Pufferzeichenfarben 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 and (8) used timeframe and (9) specified colors
   string            GetStatusDescription(bool draw_type=false)const;
   string            GetTypeBufferDescription(void)            const;
   string            GetActiveDescription(void)                const;
   string            GetShowDataDescription(void)              const;
   string            GetLineStyleDescription(void)             const;
   string            GetEmptyValueDescription(void)            const;
   string            GetDrawTypeDescription(void)              const;
   string            GetTimeframeDescription(void)             const;
   string            GetColorsDescription(void)                const;

Fügen Sie ganz am Ende des Klassenkörpers den Block der Methoden für die Arbeit mit dem Pufferobjekt hinzu:

//--- Return the size of the data buffer array
   virtual int       GetDataTotal(const uint buffer_index=0)   const;
//--- Return the value from the specified index of the specified (1) data and (2) color buffer arrays
   virtual double    GetDataBufferValue(const uint buffer_index,const uint series_index) const;
   virtual color     GetColorBufferValue(const uint series_index)     const;
//--- Set the value to the specified index of the specified (1) data and (2) color buffer arrays
   virtual void      SetBufferValue(const uint buffer_index,const uint series_index,const double value);
   virtual void      SetBufferColorIndex(const uint series_index,const uchar color_index);
//--- Initialize all object buffers by (1) a specified value, (2) the empty value specified for the object
   virtual void      InitializeBuffers(const double value,const uchar color_index);
   virtual void      InitializeBuffers(void);
//--- Fill all data buffers with empty values in the specified timeseries index
   void              ClearData(const int series_index);
   
  };
//+------------------------------------------------------------------+

Die Umsetzung der Methoden wird zu einem späteren Zeitpunkt geprüft.

Der geschlossene parametrische Klassenkonstruktor wurde geändert:

//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
CBuffer::CBuffer(ENUM_BUFFER_STATUS buffer_status,
                 ENUM_BUFFER_TYPE buffer_type,
                 const uint index_plot,
                 const uint index_base_array,
                 const int num_datas,
                 const int width,
                 const string label)
  {
   this.m_type=COLLECTION_BUFFERS_ID;
//--- Save integer properties
   this.m_long_prop[BUFFER_PROP_STATUS]                        = buffer_status;
   this.m_long_prop[BUFFER_PROP_TYPE]                          = buffer_type;
   ENUM_DRAW_TYPE type=
     (
      !this.TypeBuffer() || !this.Status() ? DRAW_NONE      : 
      this.Status()==BUFFER_STATUS_FILLING ? DRAW_FILLING   : 
      ENUM_DRAW_TYPE(this.Status()+8)
     );
   this.m_long_prop[BUFFER_PROP_DRAW_TYPE]                     = type;
   this.m_long_prop[BUFFER_PROP_TIMEFRAME]                     = PERIOD_CURRENT;
   this.m_long_prop[BUFFER_PROP_ACTIVE]                        = true;
   this.m_long_prop[BUFFER_PROP_ARROW_CODE]                    = 0x9F;
   this.m_long_prop[BUFFER_PROP_ARROW_SHIFT]                   = 0;
   this.m_long_prop[BUFFER_PROP_DRAW_BEGIN]                    = 0;
   this.m_long_prop[BUFFER_PROP_SHOW_DATA]                     = (buffer_type>BUFFER_TYPE_CALCULATE ? true : false);
   this.m_long_prop[BUFFER_PROP_SHIFT]                         = 0;
   this.m_long_prop[BUFFER_PROP_LINE_STYLE]                    = STYLE_SOLID;
   this.m_long_prop[BUFFER_PROP_LINE_WIDTH]                    = width;
   this.m_long_prop[BUFFER_PROP_COLOR_INDEXES]                 = (this.Status()!=BUFFER_STATUS_FILLING ? 1 : 2);
   this.m_long_prop[BUFFER_PROP_COLOR]                         = clrRed;
   this.m_long_prop[BUFFER_PROP_NUM_DATAS]                     = num_datas;
   this.m_long_prop[BUFFER_PROP_INDEX_PLOT]                    = index_plot;
   this.m_long_prop[BUFFER_PROP_INDEX_BASE]                    = index_base_array;
   this.m_long_prop[BUFFER_PROP_INDEX_COLOR]                   = this.GetProperty(BUFFER_PROP_INDEX_BASE)+this.GetProperty(BUFFER_PROP_NUM_DATAS);
   this.m_long_prop[BUFFER_PROP_INDEX_NEXT]                    = this.GetProperty(BUFFER_PROP_INDEX_COLOR)+(this.Status()!=BUFFER_STATUS_FILLING ? 1 : 0);
   
//--- Save real properties
   this.m_double_prop[this.IndexProp(BUFFER_PROP_EMPTY_VALUE)] = EMPTY_VALUE;
//--- Save string properties
   this.m_string_prop[this.IndexProp(BUFFER_PROP_SYMBOL)]      = ::Symbol();
   this.m_string_prop[this.IndexProp(BUFFER_PROP_LABEL)]       = (this.TypeBuffer()>BUFFER_TYPE_CALCULATE ? label : NULL);

//--- If failed to change the size of the drawn buffer array, display the appropriate message indicating the string
   if(::ArrayResize(this.DataBuffer,(int)this.GetProperty(BUFFER_PROP_NUM_DATAS))==WRONG_VALUE)
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_DRAWING_ARRAY_RESIZE),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",(string)::GetLastError());
      
//--- If failed to change the size of the color array, display the appropriate message indicating the string
   if(::ArrayResize(this.ArrayColors,(int)this.ColorsTotal())==WRONG_VALUE)
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",(string)::GetLastError());

//--- For DRAW_FILLING, fill in the color array with two default colors
   if(this.Status()==BUFFER_STATUS_FILLING)
     {
      this.SetColor(clrBlue,0);
      this.SetColor(clrRed,1);
     }

//--- Bind indicator buffers with arrays
//--- In a loop by the number of drawn buffers
   int total=::ArraySize(DataBuffer);
   for(int i=0;i<total;i++)
     {
      //--- calculate the index of the next array and
      //--- bind the indicator buffer by the calculated index with the dynamic array
      //--- located by the i loop index in the DataBuffer array
      int index=(int)this.GetProperty(BUFFER_PROP_INDEX_BASE)+i;
      ::SetIndexBuffer(index,this.DataBuffer[i].Array,INDICATOR_DATA);
      //--- Set indexation flag as in the timeseries to all buffer arrays
      ::ArraySetAsSeries(this.DataBuffer[i].Array,true);
     }
//--- Binding the color buffer with the array
   if(this.Status()!=BUFFER_STATUS_FILLING)
     {
      ::SetIndexBuffer((int)this.GetProperty(BUFFER_PROP_INDEX_COLOR),this.ColorBufferArray,INDICATOR_COLOR_INDEX);
      ::ArraySetAsSeries(this.ColorBufferArray,true);
     }

//--- Set integer buffer parameters
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_TYPE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_TYPE));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_CODE));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_SHIFT));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_BEGIN,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_BEGIN));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHOW_DATA,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHOW_DATA));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHIFT));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_STYLE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_STYLE));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_WIDTH,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_WIDTH));
   this.SetColor((color)this.GetProperty(BUFFER_PROP_COLOR));

//--- Set real buffer parameters
   ::PlotIndexSetDouble((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_EMPTY_VALUE,this.GetProperty(BUFFER_PROP_EMPTY_VALUE));
//--- Set string buffer parameters
   ::PlotIndexSetString((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LABEL,this.GetProperty(BUFFER_PROP_LABEL));
  }
//+------------------------------------------------------------------+

Setzen des Puffertyps:

   ENUM_DRAW_TYPE type=
     (
      !this.TypeBuffer() || !this.Status() ? DRAW_NONE      : 
      this.Status()==BUFFER_STATUS_FILLING ? DRAW_FILLING   : 
      ENUM_DRAW_TYPE(this.Status()+8)
     );
   this.m_long_prop[BUFFER_PROP_DRAW_TYPE]                     = type;

Die Methode SetDrawType(), die im vorigen Artikel ausführlich beschrieben wurde, ermöglicht es uns, den Zeichentyp zu bestimmen:

Alle Puffer sollen farbig sein. Um den Zeichenstil festzulegen, überprüfen wir den Pufferstatus und den Zeichnungstyp, die an die Methode SetDrawType() übergeben werden, und setzen in Abhängigkeit davon entweder keine Zeichnung, oder setzen das Füllen des Raums zwischen den beiden Ebenen mit Farbe, oder verschieben den Status des Enumerationsindex um 8 Einheiten, so dass der konstante Wert dem des Farbpuffers aus der Enumeration der Zeichentypen entspricht.
Außerhalb des Klassenkörpers implementieren wir die Methode:

//+------------------------------------------------------------------+
//| Set the graphical construction type                              |
//+------------------------------------------------------------------+
void CBuffer::SetDrawType(void)
  {
   ENUM_DRAW_TYPE type=(!this.TypeBuffer() || !this.Status() ? DRAW_NONE : this.Status()==BUFFER_STATUS_FILLING ? DRAW_FILLING : ENUM_DRAW_TYPE(this.Status()+8));
   this.SetProperty(BUFFER_PROP_DRAW_TYPE,type);
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_TYPE,type);
  }
//+------------------------------------------------------------------+

Wenn der Puffertyp BUFFER_TYPE_CALCULATE (0) oder BUFFER_STATUS_NONE (0) ist, wird der Zeichenstil auf "Nicht Zeichnen" gesetzt. Wenn der Pufferstatus BUFFER_STATUS_FILLING (Füllen mit Farbe) ist, wird der entsprechende Zeichenstil gesetzt. Alle übrigen Werte werden einfach um 8 erhöht. Diese Verschiebung gibt die Konstante des farbigen Zeichenstils an.

Hier im Klassenkonstruktor verwenden wir die gleiche Methode zur Berechnung des Puffertyps.
Die Methode SetDrawType() bleibt vorerst innerhalb der Klasse. Höchstwahrscheinlich wird sie ganz entfernt werden, da sie nur beim Erstellen eines Objekts erforderlich ist. Es besteht keine Notwendigkeit, den Zeichnungstyp weiter zu ändern.
Sie wird temporär bleiben, falls später eine andere Art der Nutzung gefunden wird.


Die Linienbreite wird nun in den Konstruktorparametern übergeben, daher wird der an den Konstruktor übergebene Wert als Standardwert festgelegt, während die Anzahl der Standardfarben für alle grafischen Konstruktionstypen auf eins gesetzt wird ausgenommen DRAW_FILLING — es werden immer nur zwei Farben in diesem Zeichnungstyp immer verwendet. Legen wir sie fest:

   this.m_long_prop[BUFFER_PROP_LINE_WIDTH]                    = width;
   this.m_long_prop[BUFFER_PROP_COLOR_INDEXES]                 = (this.Status()!=BUFFER_STATUS_FILLING ? 1 : 2);

The number of drawing data buffers is now also passed in the constructor parameters. Let's add them:

   this.m_long_prop[BUFFER_PROP_NUM_DATAS]                     = num_datas;
   this.m_long_prop[BUFFER_PROP_INDEX_PLOT]                    = index_plot;
   this.m_long_prop[BUFFER_PROP_INDEX_BASE]                    = index_base_array;
   this.m_long_prop[BUFFER_PROP_INDEX_COLOR]                   = this.GetProperty(BUFFER_PROP_INDEX_BASE)+this.GetProperty(BUFFER_PROP_NUM_DATAS);
   this.m_long_prop[BUFFER_PROP_INDEX_NEXT]                    = this.GetProperty(BUFFER_PROP_INDEX_COLOR)+(this.Status()!=BUFFER_STATUS_FILLING ? 1 : 0);

Um den Index des nächsten Arrays zu berechnen, um es als erstes Datenpuffer-Array im nächsten Pufferobjekt zuzuweisen, müssen wir berücksichtigen, dass der Puffer des Grafiktyps DRAW_FILLING den Farbpuffer nicht anwendet. Daher sollte der Farbpuffer bei einem solchen Zeichnungstyp aus dem Puffer ausgeschlossen werden, was genau das ist, was ich hier tue — für alle Zeichnungstypen einen zum berechneten Farbpuffer-Indexwert addieren, während im Falle von "Farbfüllung" addieren — der Index des nächsten Puffers ist bereits gleich dem bereits berechneten Index des nicht im Objekt vorhandenen Farbpuffers.

Die übrigen Aktionen werden in den Kommentaren zum Code beschrieben.
Die Farben werden jetzt mit der entsprechenden Methode eingetragen, da Farben direkt in der Methode auf Objekteigenschaften gesetzt werden. Außerdem wird das Farbfeld, das anschließend verwendet wird, um die gewünschte Farbe per Index zu erhalten, gefüllt:

//--- Set integer buffer parameters
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_TYPE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_TYPE));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_CODE));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_ARROW_SHIFT));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_DRAW_BEGIN,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_DRAW_BEGIN));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHOW_DATA,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHOW_DATA));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_SHIFT,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_SHIFT));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_STYLE,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_STYLE));
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_WIDTH,(ENUM_PLOT_PROPERTY_INTEGER)this.GetProperty(BUFFER_PROP_LINE_WIDTH));
   this.SetColor((color)this.GetProperty(BUFFER_PROP_COLOR));

Die Rückgabe der Breite und der Farblinie des Indikators wurde in der Methode geändert, die die Beschreibung der ganzzahligen Eigenschaften zurückgibt:

//+------------------------------------------------------------------+
//| Return description of a buffer's integer property                |
//+------------------------------------------------------------------+
string CBuffer::GetPropertyDescription(ENUM_BUFFER_PROP_INTEGER property)
  {
   return
     (
   // ... Removed unnecessary strings
   // ...
   // ...

      property==BUFFER_PROP_LINE_STYLE    ?  CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_LINE_STYLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetLineStyleDescription()
         )  :
      property==BUFFER_PROP_LINE_WIDTH    ?  
         (this.Status()==BUFFER_STATUS_ARROW ? CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_ARROW_SIZE) :
          CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_LINE_WIDTH))+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==BUFFER_PROP_COLOR_INDEXES ?  CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_COLOR_NUM)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==BUFFER_PROP_COLOR         ?  CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_COLOR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetColorsDescription()
         )  :
      property==BUFFER_PROP_INDEX_BASE    ?  CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INDEX_BASE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
   
   // ...
   // ...
   // ... Removed unnecessary strings

      ""
     );
  }
//+------------------------------------------------------------------+

Um die Linienbreite zurückzugeben, wird der Pufferstatus überprüft. Wenn der Indikator Pfeile zeichnet, sind darin keine Linien enthalten — es wird die Pfeilgröße zurückgegeben.
Um die Farbe zurückzugeben, wird nun die Methode GetColorsDescription() verwendet. Die Methode gibt die Beschreibung aller verwendeten Pufferfarben zurück. Auf den Puffer selbst wird weiter unten eingegangen.

Die Methode zur Rückgabe eines spezifizierten leeren Wertes gibt nun den negativen EMPTY_VALUE als "leeren Wert" des Puffers zurück:

//+------------------------------------------------------------------+
//| Return description of the set empty value                        |
//+------------------------------------------------------------------+
string CBuffer::GetEmptyValueDescription(void) const
  {
   double value=fabs(this.EmptyValue());
   return(value<EMPTY_VALUE ? ::DoubleToString(this.EmptyValue(),(this.EmptyValue()==0 ? 1 : 8)) : (this.EmptyValue()>0 ? "EMPTY_VALUE" : "-EMPTY_VALUE"));
  }
//+------------------------------------------------------------------+

Die Methode, die die für das Pufferobjekt eingestellten Farben zurückgibt:

//+------------------------------------------------------------------+
//| Return description of specified colors                           |
//+------------------------------------------------------------------+
string CBuffer::GetColorsDescription(void) const
  {
   int total=this.ColorsTotal();
   if(total==1)
      return ::ColorToString(this.Color(),true);
   string res="";
   for(int i=0;i<total;i++)
     {
      res+=::ColorToString(this.ArrayColors[i],true)+(i<total-1 ? "," : "");
     }
   return res;
  }
//+------------------------------------------------------------------+

Wenn nur eine Farbe gesetzt ist, wird der Wert als Text der Pufferobjekteigenschaft, die den Farbwert speichert, zurückgegeben,
wenn mehrere Farben in der Farbpalette enthalten sind, wird die Zeichenkette, die aus ihren Beschreibungen besteht, in einer Schleife gebildet und es wird der erhaltene Wert zurückgegeben.

Die Methode, die die Anzahl der Pufferobjektfarben zurückgibt:

//+------------------------------------------------------------------+
//| Set the number of colors                                         |
//+------------------------------------------------------------------+
void CBuffer::SetColorNumbers(const int number)
  {
   if(number>IND_COLORS_TOTAL)
      return;
   int n=(this.Status()!=BUFFER_STATUS_FILLING ? number : 2);
   this.SetProperty(BUFFER_PROP_COLOR_INDEXES,n);
   ::ArrayResize(this.ArrayColors,n);
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_COLOR_INDEXES,n);
  }
//+------------------------------------------------------------------+

Wenn mehr als der maximal mögliche Betrag an die Methode übergeben wird, verlassen wir die Methode.
Wenn der Linienzeichnungstyp nicht DRAW_FILLING ist, wird die Zahl gleich der übergebenen Zahl gesetzt, andernfalls wird sie auf zwei gesetzt.
Dann ändern Sie die Größe des Farbfeldes und stellen Sie den neuen Wert für den Puffer ein.

Die Methode, die eine Zeichenfarbe für das Pufferobjekt festlegt:

//+------------------------------------------------------------------+
//| Set a single specified drawing color for the buffer              |
//+------------------------------------------------------------------+
void CBuffer::SetColor(const color colour)
  {
   if(this.Status()==BUFFER_STATUS_FILLING)
      return;
   this.SetColorNumbers(1);
   this.SetProperty(BUFFER_PROP_COLOR,colour);
   this.ArrayColors[0]=colour;
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_COLOR,0,this.ArrayColors[0]);
  }
//+------------------------------------------------------------------+

Wenn der Zeichenstil DRAW_FILLING ist, beenden wir die Methode — dieser Zeichenstil hat immer zwei Farben.
Als Nächstes setzen wir die Anzahl der Farben auf eins, tragen die übergebene Farbe in die Pufferobjekteigenschaft ein, schreiben die übergebene Farbe in die einzige Farbfeldzelle und setzen die Farbe des Indikatorpuffers.

Um die Indikatorlinien neu zu zeichnen, setzen wir den Farbindex (aus der Liste der verwendeten Farben) auf den erforderlichen Zeitreihenindex, bei dem die Farbe geändert werden soll.
Wenn wir zum Beispiel drei Farben verwenden, haben sie die Indizes 0,1,2. Um die Indikatorlinie in einer der drei Farben einzufärben, schreiben wir einfach die Nummer der gewünschten Farbe in den Farbpuffer. Wenn Index 0 die blaue Farbe speichert, während Index 1 die rote Farbe speichert, schreiben wir 0 für Blau oder 1 für Rot in den Indikator-Farbpuffer, um die Indikatorlinie neu zu zeichnen.
Um die für das Pufferobjekt eingestellten Farben ändern zu können, benötigen wir die Methode, die eine neue Farbe in den angegebenen Indikator Puffer-Farbindex schreibt.

Die Methode, die die Zeichenfarbe für den angegebenen Farbindex festlegt:

//+------------------------------------------------------------------+
//| Set the drawing color to the specified color index               |
//+------------------------------------------------------------------+
void CBuffer::SetColor(const color colour,const uchar index)
  {
   if(index>IND_COLORS_TOTAL-1)
      return;
   if(index>this.ColorsTotal()-1)
      this.SetColorNumbers(index+1);
   this.ArrayColors[index]=colour;
   if(index==0)
      this.SetProperty(BUFFER_PROP_COLOR,(color)this.ArrayColors[0]);
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_COLOR,index,this.ArrayColors[index]);
  }
//+------------------------------------------------------------------+

Die Methode erhält die Farbe und den Farbindex, mit dem sie geschrieben wird.
Sie wird beendet, wenn der übergebene Farbindex die maximal verfügbare Anzahl von Indikatorfarben überschreitet.
Wenn der Index die bereits vorhandene Anzahl von Pufferobjektfarben überschreitet,setzen wir die neue Anzahl von Pufferobjektfarben.
Als Nächste, schreiben wir die übergebene Farbe in das Farbfeld um den angegebenen Index. Wenn der Index Null übergeben wird, setzen wir die an die Methode übergebene Farbe auf die Pufferfarbeigenschaft und schließlich den neuen Farbwert auf den Indikatorpuffer durch den an die Methode übergebenen Index.

Die Methode, die Farben für das Pufferobjekt aus dem übergebenen Farbfeld setzt:

//+------------------------------------------------------------------+
//| Set drawing colors from the color array                          |
//+------------------------------------------------------------------+
void CBuffer::SetColors(const color &array_colors[])
  {
//--- Exit if the passed array is empty
   if(::ArraySize(array_colors)==0)
      return;
//--- Copy the passed array to the array of buffer object colors
   ::ArrayCopy(this.ArrayColors,array_colors,0,0,IND_COLORS_TOTAL);
//--- Exit if the color array was empty and not copied for some reason
   int total=::ArraySize(this.ArrayColors);
   if(total==0)
      return;
//--- If the drawing style is not DRAW_FILLING
   if(this.Status()!=BUFFER_STATUS_FILLING)
     {
      //--- if the new number of colors exceeds the currently set one, 
      //--- set the new value for the number of colors
      if(total>this.ColorsTotal())
         this.SetColorNumbers(total);
     }
   //--- If the drawing style is DRAW_FILLING, set the number of colors equal to 2
   else
      total=2;
//--- Set the very first color from the color array (for a single color) to the buffer object color property
   this.SetProperty(BUFFER_PROP_COLOR,(color)this.ArrayColors[0]);
//--- Set the new number of colors for the indicator buffer
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_COLOR_INDEXES,total);
//--- In the loop by the new number of colors, set all colors by their indices for the indicator buffer
   for(int i=0;i<total;i++)
      ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_LINE_COLOR,i,this.ArrayColors[i]);
  }
//+------------------------------------------------------------------+

Alle Methodenstrings werden in Kommentaren ausführlich beschrieben.

Die Methode, die den angepassten Index des erforderlichen Pufferarrays zurückgibt:

//+------------------------------------------------------------------+
//| Return the adjusted buffer array index                           |
//+------------------------------------------------------------------+
int CBuffer::GetCorrectIndexBuffer(const uint buffer_index) const
  {
   return int(buffer_index<this.GetProperty(BUFFER_PROP_NUM_DATAS) ? buffer_index : this.GetProperty(BUFFER_PROP_NUM_DATAS)-1);
  }
//+------------------------------------------------------------------+

Da sich nun alle Daten-Arrays für Indikatorpuffer im Array DataBuffer[] mit dem Strukturtyp SDataBuffer befinden, werden wir die Methode zur Anpassung eines falsch übergebenen Array-Index verwenden, um ein Überschreiten der Array-Grenzen zu vermeiden.
Wenn der übergebene Index kleiner als die Gesamtzahl der für die Konstruktion verwendeten Puffer ist, wird der übergebene Index zurückgegeben.
In jedem anderen Fall wird der Index des allerletzten Array-Elements zurückgegeben.
Im Falle eines einzelnen Arrays ist das allerletzte Element gleich dem allerersten.

Die Methode, die die Größe des angegebenen Datenpuffer-Arrays zurückgibt:

//+------------------------------------------------------------------+
//| Return the array size of the specified data buffer               |
//+------------------------------------------------------------------+
int CBuffer::GetDataTotal(const uint buffer_index=0) const
  {
    int index=this.GetCorrectIndexBuffer(buffer_index);
    return(index>WRONG_VALUE ? ::ArraySize(this.DataBuffer[index].Array) : 0);
  }
//+------------------------------------------------------------------+

Die Methode wird eher zur Fehlersuche und zur internen Verwendung eingesetzt.
Gibt die Größe des Arrays zurück, das durch seinen Index im Array DataBuffer[] als Indikator-Puffer zugewiesen wurde.
OnInit() wird immer Null übergeben. OnCalculate() erhält rates_total.

Die Methode, die den angegebenen Datenpufferwert durch den angegebenen Zeitreihenindex zurückgibt:

//+------------------------------------------------------------------+
//| Return the value from the specified timeseries index             |
//| of the specified data buffer array                               |
//+------------------------------------------------------------------+
double CBuffer::GetDataBufferValue(const uint buffer_index,const uint series_index) const
  {
   int correct_buff_index=this.GetCorrectIndexBuffer(buffer_index);
   int data_total=this.GetDataTotal(correct_buff_index);
   if(data_total==0)
      return this.EmptyValue();
   int data_index=((int)series_index<data_total ? (int)series_index : data_total-1);
   return this.DataBuffer[correct_buff_index].Array[data_index];
  }
//+------------------------------------------------------------------+

Die Methode wird verwendet, um Daten über den Zeitreihenindex aus dem angegebenen Indikatorpuffer zu erhalten und zu empfangen.
Zuerst passen wir den erhaltenen Index des erforderlichen Puffers an, überprüfen die Datenmenge im Puffer, und wenn die Daten fehlen, wird der für das Pufferobjekt gesetzten leeren Wert zurückgegeben. Als Nächstes prüfen wir, ob der Zeitreihenindex über die Datenmenge im Puffer hinausgeht. Wenn der Zeitreihenindex die Array-Grenzen überschreitet, geben wir das allerletzte Pufferelement zurück, andernfalls geben wir Daten aus dem angegebenen Puffer durch den Zeitreihenindex zurück.

Die Methode gibt den Farbpufferwert über den angegebenen Zeitreihenindex zurück:

//+------------------------------------------------------------------+
//| Return the value from the specified timeseries index             |
//| of the specified color buffer array                              |
//+------------------------------------------------------------------+
color CBuffer::GetColorBufferValue(const uint series_index) const
  {
   int data_total=this.GetDataTotal(0);
   if(data_total==0)
      return clrNONE;
   int data_index=((int)series_index<data_total ? (int)series_index : data_total-1);
   int color_index=(this.ColorsTotal()==1 ? 0 : (int)this.ColorBufferArray[data_index]);
   return (color)this.ArrayColors[color_index];
  }
//+------------------------------------------------------------------+

Die Methode ist fast identisch mit der gerade besprochenen, außer dass wir immer einen Farbpuffer haben und wir den Index des gewünschten Puffers nicht ermitteln und anpassen müssen. Hier prüfen wir sofort den Zeitreihenindex und geben die Daten aus dem Puffer über den angepassten Index zurück (falls ein ungültiger Index übergeben wurde).

Die Methode, die den Wert auf den angegebenen Datenpuffer durch den angegebenen Zeitreihenindex setzt:

//+------------------------------------------------------------------+
//| Set the value to the specified timeseries index                  |
//| for the specified data buffer array                              |
//+------------------------------------------------------------------+
void CBuffer::SetBufferValue(const uint buffer_index,const uint series_index,const double value)
  {
   if(this.GetDataTotal(buffer_index)==0)
      return;
   int correct_buff_index=this.GetCorrectIndexBuffer(buffer_index);
   int data_total=this.GetDataTotal(buffer_index);
   int data_index=((int)series_index<data_total ? (int)series_index : data_total-1);
   this.DataBuffer[correct_buff_index].Array[data_index]=value;
  }
//+------------------------------------------------------------------+

Die Methode ist identisch mit der Methode zur Gewinnung von Daten aus dem angegebenen Puffer durch den oben betrachteten Zeitreihenindex. Anstatt jedoch den Wert zurückzugeben, schreibt die Methode den übergebenen Wert durch den angegebenen Zeitreihenindex in den angegebenen Datenpuffer.

Die Methode setzt den Wert für den Farbpuffer durch den angegebenen Zeitreihenindex:

//+------------------------------------------------------------------+
//| Set the color index to the specified timeseries index            |
//| of the color buffer array                                        |
//+------------------------------------------------------------------+
void CBuffer::SetBufferColorIndex(const uint series_index,const uchar color_index)
  {
   if(this.GetDataTotal(0)==0 || color_index>this.ColorsTotal()-1 || this.Status()==BUFFER_STATUS_FILLING)
      return;
   int data_total=this.GetDataTotal(0);
   int data_index=((int)series_index<data_total ? (int)series_index : data_total-1);
   if(::ArraySize(this.ColorBufferArray)==0)
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_INVALID_PROPERTY_BUFF));
   this.ColorBufferArray[data_index]=color_index;
  }
//+------------------------------------------------------------------+

Die Methode ist identisch mit der Methode zur Abfrage des Farbindex aus dem angegebenen Zeitreihenindex. Anstatt jedoch den Wert zurückzugeben, schreibt die Methode den übergebenen Farbindexwert über den angegebenen Zeitreihenindex in den Farbpuffer.
Außerdem, wenn das Datenfeld keine entsprechenden Daten hat (es ist leer), oder der übergebene Farbindex das Farbfeld überschreitet, oder der Zeichenstil des Pufferobjekts DRAW_FILLING ist (kein Farbpuffer), wird die Methode verlassen.
Wenn die Farbpuffergröße null ist, sind die in #property indicator_buffers eingestellten Werte höchstwahrscheinlich falsch gesetzt — die entsprechende Meldung wird angezeigt gefolgt von dem Fehler des Zugriffs über die Array-Grenzen hinaus, was nicht absichtlich gehandhabt wird, da die Journaleinträge es uns erlauben, die Anzahl der Puffer in den Indikatoreigenschaften korrekt einzustellen.

Die Methode zur Initialisierung aller Puffer von Pufferobjekten durch die angegebenen Daten- und Farbpufferwerte:

//+------------------------------------------------------------------+
//| Initialize all object buffers by the specified value             |
//+------------------------------------------------------------------+
void CBuffer::InitializeBuffers(const double value,const uchar color_index)
  {
   for(int i=0;i<this.GetProperty(BUFFER_PROP_NUM_DATAS);i++)
      ::ArrayInitialize(this.DataBuffer[i].Array,value);
   if(this.Status()!=BUFFER_STATUS_FILLING)
      ::ArrayInitialize(this.ColorBufferArray,(color_index>this.ColorsTotal()-1 ? 0 : color_index));
  }
//+------------------------------------------------------------------+

Initialisierung von jedem folgenden Array mit dem angegebenen Wert in der Schleife durch die vollständige Liste aller Datenpuffer.
Wenn der Zeichenstil des Pufferobjekts nicht DRAW_FILLING ist, initialisieren wir den Farbpuffer mit dem angegebenen Wert, der im Falle eines Ausstiegs über die Farbfeldgrenzen hinaus angepasst wird.

Die Methode zur Initialisierung aller Pufferobjekt-Pufferanordnungen mit dem für das Pufferobjekt angegebenen "leeren" Wert:

//+------------------------------------------------------------------+
//| Initialize all object buffers                                    |
//| by the empty value set for the object                            |
//+------------------------------------------------------------------+
void CBuffer::InitializeBuffers(void)
  {
   for(int i=0;i<this.GetProperty(BUFFER_PROP_NUM_DATAS);i++)
      ::ArrayInitialize(this.DataBuffer[i].Array,this.EmptyValue());
   if(this.Status()!=BUFFER_STATUS_FILLING)
      ::ArrayInitialize(this.ColorBufferArray,0);
  }
//+------------------------------------------------------------------+

Die Methode ist identisch mit der oben betrachteten, außer dass der Initialisierungswert aus dem für das Objekt eingestellten "leeren" Wert übernommen wird. Außerdem wird der allererste Farbindex für die Initialisierung verwendet.

Es ist oft erforderlich, die Werte aller Puffer in den Indikatoren vor dem Füllen zu löschen, um grafische Artefakte zu vermeiden.
Die nächste Methode löscht alle Puffer im angegebenen Zeitreihenindex.
Die Methode, alle Indikatorpuffer des Pufferobjekts mit dem leeren Wert zu füllen:

//+------------------------------------------------------------------+
//| Fill all data buffers with the empty value                       |
//| in the specified timeseries index                                |
//+------------------------------------------------------------------+
void CBuffer::ClearData(const int series_index)
  {
   for(int i=0;i<this.GetProperty(BUFFER_PROP_NUM_DATAS);i++)
      this.SetBufferValue(i,series_index,this.EmptyValue());
   this.SetBufferColorIndex(series_index,0);
  }
//+------------------------------------------------------------------+

In der Schleife durch alle vorhandenen Puffer-Arrays des Pufferobjekts wird der leere Wert eingetragen, der für das Pufferobjekt durch den angegebenen Zeitreihenindex gesetzt wurde, unter Verwendung der oben betrachteten Methode SetBufferValue(). Die ebenfalls oben erwähnte Methode SetBufferColorIndex() ermöglicht es uns, den Farbindex auf den angegebenen Zeitreihenindex zu setzen.

Damit sind die Änderungen in der abstrakten Pufferobjektklasse abgeschlossen, die auf die Erstellung von und die Arbeit mit Nachfolgeobjekten der Klasse abzielen.

Pufferindikatorobjekte — Nachkommen des abstrakten Pufferobjekts

Wie es oft der Fall ist, haben fast alle Bibliotheksobjekte eine ähnliche Struktur: Es gibt ein allgemeines abstraktes Objekt mit Eigenschaften und Methoden, die von seinen Nachkommen geteilt werden, während jedes Nachkommenobjekt die Daten des abstrakten Objekts spezifiziert. Ich habe mich mit dem Konzept der Bibliotheksobjekte in den ersten (abstraktes Objekt) und zweiten Artikeln (Nachfolgeobjekte und ihre Sammlung) befasst.

Pufferobjekte sind keine Ausnahme. Jedes solche Objekt ist ein Indikatorpuffer mit einem für es spezifischen Zeichenstil. Objekte werden auf der Grundlage ihres Zeichenstils benannt.

Das erste Pufferobjekt hat den Zeichenstil Pfeile und wird entsprechend benannt.

In \MQL5\Include\DoEasy\Objects\Indicators\ erstellen wir BufferArrow.mqh die Datei der Klasse CBufferArrow, deren Basisklasse das Objekt des abstrakten Puffers CBuffer ist:

//+------------------------------------------------------------------+
//|                                                  BufferArrow.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Buffer.mqh"
//+------------------------------------------------------------------+
//| Buffer with the "Drawing with arrows" drawing style              |
//+------------------------------------------------------------------+
class CBufferArrow : public CBuffer
  {
private:

public:
//--- Constructor
                     CBufferArrow(const uint index_plot,const uint index_base_array) :
                        CBuffer(BUFFER_STATUS_ARROW,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Arrows") {}
//--- Supported integer properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_INTEGER property);
//--- Supported real properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_DOUBLE property);
//--- Supported string properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_STRING property);
//--- Display a short buffer description in the journal
   virtual void      PrintShort(void);
  };
//+------------------------------------------------------------------+

Wie wir sehen können, enthält der Klassencode nichts Zusätzliches.
Die virtuellen Methoden, die die Flags von Objekten zurückgeben, die ganzzahligen, reellen und Text-Eigenschaften unterstützen, sowie die virtuelle Methode, die die kurze Pufferbeschreibung anzeigt, werden deklariert.
Der Klassenkonstruktor erhält den Index des erstellten gezeichneten Indikatorpuffers (die Seriennummer des Puffers in der Liste aller Indikatorpuffer) und den Index des Basispuffer-Arrays, mit dem das erste double Array des erstellten neuen Puffers tatsächlich verbunden ist.
Die Initialisierung des Konstruktors enthält die Initialisierung des geschützten Konstruktors der Elternklasse:

CBufferArrow(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_ARROW,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Arrows") {}

wobei der erste Parameter der Pufferstatus des Puffertyps "Drawing with arrows" ist, der zweite Parameter ist der Puffertyp "Farbdatenpuffer". Übergeben wir außerdem die Werte des Zeichenpufferindexes und die Basisanordnung, die Anzahl der Puffer für die Konstruktion, die Linienbreite (hier gibt der Parameter die Pfeilgröße an) und den Namen der im Datenfenster angezeigten graphischen Reihe. Wenn wir also ein neues Pufferobjekt erzeugen, teilen wir der Basisklasse den Typ des erzeugten Puffers und seine Parameter mit.

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung von ganzzahligen Eigenschaften angibt:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CBufferArrow::SupportProperty(ENUM_BUFFER_PROP_INTEGER property)
  {
   if(property==BUFFER_PROP_LINE_STYLE || (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT))
      return false;
   return true;
  }
//+------------------------------------------------------------------+

Wenn der Methode die Eigenschaft "Linientyp" übergeben wird oder dies ist ein berechneter Puffer, der nicht die Eigenschaft "Buffertyp" oder "nächster gezeichneter Pufferindex" ist, wird das nicht unterstützt und false zurückgegeben. In anderen Fällen wird true zurückgegeben.

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung für reelle Eigenschaften angibt:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CBufferArrow::SupportProperty(ENUM_BUFFER_PROP_DOUBLE property)
  {
   if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE)
      return false;
   return true;
  }
//+------------------------------------------------------------------+

Wenn dies ein berechneter Puffer ist, werden keine reellen Eigenschaften unterstützt (es gibt nur eine reelle Eigenschaft: "Leerer Wert zum Zeichnen, wenn nichts gezeichnet wird") — Rückgabe false. In den anderen Fällen wird true zurückgegeben.

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung für Zeichenketteneigenschaften angibt:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| string property, otherwise return 'false'                        |
//+------------------------------------------------------------------+
bool CBufferArrow::SupportProperty(ENUM_BUFFER_PROP_STRING property)
  {
   if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE)
      return false;
   return true;
  }
//+------------------------------------------------------------------+

Wenn dies ein berechneter Puffer ist, werden keine Text-Eigenschaften unterstützt — Rückgabe false. In den anderen Fällen wird true zurückgegeben.

Die Methode zur Anzeige einer kurzen Pufferobjektbeschreibung im Journal:

//+------------------------------------------------------------------+
//| Display short buffer description in the journal                  |
//+------------------------------------------------------------------+
void CBufferArrow::PrintShort(void)
  {
   ::Print
     (
      CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_BUFFER),"(",(string)this.IndexPlot(),"): ",
      this.GetStatusDescription(true)," ",this.Symbol()," ",TimeframeDescription(this.Timeframe())
     );
  }
//+------------------------------------------------------------------+

Die Methode erzeugt die Zeichenfolge aus dem Puffer-Header, die den Index des gezeichneten Puffers (Puffer-Seriennummer im Datenfenster) angibt und den Pufferstatus (Zeichenstil), das Symbol und den Zeitrahmen beschreibt.
Zum Beispiel in der Form von:

Buffer(0): Drawing with arrows EURUSD H1

Dies ist die gesamte Pufferobjektklasse vom Typ "Zeichnen von Pfeilen".


Erstellen wir die neue abgeleitete Klasse des abstrakten Pufferobjekts CBufferLine des Zeichenstils Linie in \MQL5\Include\DoEasy\Objects\Indicators\BufferLine.mqh:

//+------------------------------------------------------------------+
//|                                                   BufferLine.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Buffer.mqh"
//+------------------------------------------------------------------+
//| Buffer of the Line drawing style                                 |
//+------------------------------------------------------------------+
class CBufferLine : public CBuffer
  {
private:

public:
//--- Constructor
                     CBufferLine(const uint index_plot,const uint index_base_array) :
                        CBuffer(BUFFER_STATUS_LINE,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Line") {}
//--- Supported integer properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_INTEGER property);
//--- Supported real properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_DOUBLE property);
//--- Supported string properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_STRING property);
//--- Display a short buffer description in the journal
   virtual void      PrintShort(void);
  };
//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_INTEGER property)
  {
   if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || 
      (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT)
     ) return false;
   return true; 
  }
//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_DOUBLE property)
  {
   if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE)
      return false;
   return true;
  }
//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| string property, otherwise return 'false'                        |
//+------------------------------------------------------------------+
bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_STRING property)
  {
   if(this.TypeBuffer()==BUFFER_TYPE_CALCULATE)
      return false;
   return true;
  }
//+------------------------------------------------------------------+
//| Display short buffer description in the journal                  |
//+------------------------------------------------------------------+
void CBufferLine::PrintShort(void)
  {
   ::Print
     (
      CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_BUFFER),"(",(string)this.IndexPlot(),"): ",
      this.GetStatusDescription(true)," ",this.Symbol()," ",TimeframeDescription(this.Timeframe())
     );
  }
//+------------------------------------------------------------------+

Im Vergleich zur Klasse der Deal-Puffer werden im Klassenkonstruktor Zeilenstatus und Zeilengrafischer Reihenname in der Initialisierungsliste an den Basispuffer-Objektkonstruktor übergeben. Die übrigen Parameter bleiben die gleichen wie beim Pfeilpufferobjekt:

CBufferLine(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_LINE,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Line") {}

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung von ganzzahligen Eigenschaften anzeigt, wurde ebenfalls geändert:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CBufferLine::SupportProperty(ENUM_BUFFER_PROP_INTEGER property)
  {
   if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || 
      (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT)
     ) return false;
   return true; 
  }
//+------------------------------------------------------------------+

Wenn dies die Eigenschaften "Pfeilcode" oder "vertikaler Pfeilabstand" hat oder ein berechneter Puffer ist, der nicht die Eigenschaft "Puffertyp" oder "nächster gezeichneter Pufferindex" hat, wird er nicht unterstützt und false wird zurückgegeben. In anderen Fällen wird true zurückgegeben.


Erstellen Sie die neue, abgeleitete Klasse des abstrakten Pufferobjekts CBufferSection im Teile des Zeichenstils in \MQL5\Include\DoEasy\Objects\Indicators\BufferSection.mqh.
Nur Konstruktoren neuer Klassen und Methoden zur Unterstützung ganzzahliger Eigenschaften werden weiter besprochen, da alles andere mit den beiden beschriebenen Klassen identisch ist.

Im Klassenkonstruktor werden der Sektionsstatus und Sektionsgrafischer Reihenname in der Initialisierungsliste an den Basispufferobjektkonstruktor übergeben.

CBufferSection(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_SECTION,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Section") {}

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung von ganzzahligen Eigenschaften angibt:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+ 
bool CBufferSection::SupportProperty(ENUM_BUFFER_PROP_INTEGER property)
  {
   if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || 
      (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT)
     ) return false;
   return true; 
  }
//+------------------------------------------------------------------+

Wenn dies die Eigenschaften "Pfeilcode" oder "vertikaler Pfeilabstand" hat oder ein berechneter Puffer ist, der nicht die Eigenschaft "Puffertyp" oder "nächster gezeichneter Pufferindex" hat, wird er nicht unterstützt und false wird zurückgegeben. In anderen Fällen wird true zurückgegeben.


Erstellen wir die neue abgeleitete Klasse des abstrakten Pufferobjekts CBufferHistogram des Zeichenstils "Histogramm von der Nulllinie" in \MQL5\Include\DoEasy\Objects\Indicators\BufferHistogram.mqh.

Im Klassenkonstruktor werden der Status des "Histogramms auf der Nulllinie" und der Histogrammgrafikreihenname in der Initialisierungsliste an den Basispufferobjektkonstruktor übergeben, während die Linienbreite des Histogramms standardmäßig gleich 2 ist.

CBufferHistogram(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_HISTOGRAM,BUFFER_TYPE_DATA,index_plot,index_base_array,1,2,"Histogram") {}

Die übrigen Methoden sind identisch mit der Objektklasse Sektionspuffer.


Erstellen wir die neue, abgeleitete Klasse des abstrakten Pufferobjekts CBufferHistogram2 des Zeichenstils "Histogramm von zwei Indikatorpuffern" in \MQL5\Include\DoEasy\Objects\Indicators\BufferHistogram2.mqh.

Im Klassenkonstruktor werden der Status des "Histogramms von zwei Indikatorpuffern", den graphischen Reihennamen "Histogramm2 0;Histogramm2 1" und zwei Konstruktionspuffer in der Initialisierungsliste an den Basispuffer-Objektkonstruktor übergeben. Die Linienbreite des Histogramms ist standardmäßig gleich 8.

CBufferHistogram2(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_HISTOGRAM2,BUFFER_TYPE_DATA,index_plot,index_base_array,2,8,"Histogram2 0;Histogram2 1") {}

Warum ist die Linienbreite des Histogramms gleich 8?
In MQL5, d.h. bei den auf zwei Puffern basierenden Histogrammindikatoren, ist dies die maximale Histogrammspaltenbreite in Abhängigkeit von der horizontalen Diagrammskala:


Mit dem Skalenmaximum des Charts (5) hat die Histogramm-Spaltenbreite die maximale Größe. Wenn Sie eine kleinere Größe benötigen, setzen Sie den neuen Breitenwert mit der Methode SetWidth() nach der Erstellung des Puffers.

Warum hat die grafische Reihe "Histogramm2 0;Histogramm2 1" einen solchen Namen?
Bei Indikatoren, die für ihren Aufbau mehrere Puffer verwenden, wird der Name jedes Puffers in der grafischen Reihenbezeichnung angegeben. Wenn Sie für jeden Puffer einen eindeutigen Namen festlegen müssen, trennen Sie diese bei der Angabe des grafischen Reihennamens durch Semikolon (;).
Hier wird der Name "Histogramm2 0" für den ersten Puffer festgelegt (Null gibt den ersten Pufferindex an), während der zweite Puffer "Histogramm2 1" genannt wird (Eins gibt den zweiten Pufferindex an).
In DataWindow sieht dies wie folgt aus:


Falls erforderlich, können neue Puffernamen mit der Methode SetLabel() nach der Erstellung des Puffers gesetzt werden.

Die übrigen Methoden sind identisch mit der Objektklasse Sektionspuffer.


Erstellen wir die neue, abgeleitete Klasse des abstrakten Pufferobjekts CBufferZigZag im Zeichenstils Zickzack in \MQL5\Include\DoEasy\Objects\Indicators\BufferZigZag.mqh.

Im Klassenkonstruktor werden in der Initialisierungsliste der Status von Zigzag, der Name der graphischen Reihe "ZigZag 0;ZigZag 1" und zwei Konstruktionspuffer an den Basispufferobjektkonstruktor übergeben. Die Linienbreite von Zickzack ist standardmäßig gleich 1.

CBufferZigZag(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_ZIGZAG,BUFFER_TYPE_DATA,index_plot,index_base_array,2,1,"ZigZag 0;ZigZag 1") {}

Die übrigen Methoden sind identisch mit der Objektklasse Sektionspuffer.


Erstellen wir die neue abgeleitete Klasse des abstrakten Pufferobjekts CBufferFilling des Zeichenstils "Farbfüllung zwischen zwei Ebenen" in \MQL5\Include\DoEasy\Objects\Indicators\BufferFilling.mqh.

Im Klassenkonstruktor werden der Status "Farbfüllung zwischen zwei Ebenen" , der graphische Reihenname "Filling 0;Filling 1" und zwei Konstruktionspuffer in der Initialisierungsliste an den Basispuffer-Objektkonstruktor übergeben. Die Linienbreite ist standardmäßig gleich 1 (in diesem Zeichenstil gibt es keine Linien, daher ist diese Eigenschaft irrelevant).

CBufferFilling(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_FILLING,BUFFER_TYPE_DATA,index_plot,index_base_array,2,1,"Filling 0;Filling 1") {}

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung von Integer-Eigenschaften anzeigt:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+ 
bool CBufferFilling::SupportProperty(ENUM_BUFFER_PROP_INTEGER property)
  {
   if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || property==BUFFER_PROP_LINE_STYLE || 
       property==BUFFER_PROP_LINE_WIDTH || property==BUFFER_PROP_INDEX_COLOR ||
      (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT)
     ) return false;
   return true; 
  }
//+------------------------------------------------------------------+

Wenn dies "Pfeilcode", "vertikaler Pfeilabstand", "Linientyp", die Eigenschaft "Lineienbreite", der Farbpufferindex oder ein berechneter Puffer ist, der nicht der "Puffertyp" oder die Eigenschaft "nächster gezeichneter Pufferindex" ist, wird er nicht unterstützt und false zurückgegeben. In anderen Fällen wird true zurückgegeben.

Die übrigen Methoden sind identisch mit der Objektklasse Sektionspuffer.


Erstellen Sie die neue abgeleitete Klasse des abstrakten Pufferobjekts CBufferBars des Zeichenstils "Anzeige als Balken" in \MQL5\Include\DoEasy\Objects\Indicators\BufferBars.mqh.

Im Klassenkonstruktor werden der Status der "Darstellung als Balken", die Reihennamen "Bar Open;Bar High;Bar Low;Bar Close" und vier Konstruktionspuffer in der Initialisierungsliste an den Basispufferobjektkonstruktor übergeben. Die Balkenbreite ist standardmäßig gleich 2.

CBufferBars(const uint index_plot,const uint index_base_array) :
   CBuffer(BUFFER_STATUS_BARS,BUFFER_TYPE_DATA,index_plot,index_base_array,4,2,"Bar Open;Bar High;Bar Low;Bar Close") {}

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung von Integer-Eigenschaften anzeigt:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+ 
bool CBufferBars::SupportProperty(ENUM_BUFFER_PROP_INTEGER property)
  {
   if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) || property==BUFFER_PROP_LINE_STYLE ||
      (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT)
     ) return false;
   return true; 
  }
//+------------------------------------------------------------------+

Wenn dies die Eigenschaft "Pfeilcode", "vertikale Pfeilabstand" oder "Linienstil" oder ein berechneter Puffer ist, der nicht die Eigenschaft "Puffertyp" oder "nächster gezeichneter Pufferindex" ist, wird er nicht unterstützt und false wird zurückgegeben. In anderen Fällen wird true zurückgegeben.

Die übrigen Methoden sind identisch mit der Objektklasse Sektionspuffer.


Erstellen Sie die neue, abgeleitete Klasse des abstrakten Pufferobjekts CBufferCandles des Zeichenstils "Anzeigen als Kerzen" in \MQL5\Include\DoEasy\Objects\Indicators\BufferCandles.mqh.

Im Klassenkonstruktor werden der Status ""Anzeigen als Kerzen", die graphischen Namen "Candle Open;Candle High;Candle Low;Candle Close" und vier Konstruktionspuffer in der Initialisierungsliste an den Basispuffer-Objektkonstruktor übergeben. Die Kerzenbreite ist standardmäßig gleich 1 (der Parameter hat keinen Einfluss auf die reale Zeichnungsbreite, da die Kerzenbreite immer gleich der Kerzenbreite des Diagramms in Abhängigkeit von seinem horizontalen Maßstab ist).

CBufferCandles(const uint index_plot,const uint index_base_array) : 
   CBuffer(BUFFER_STATUS_CANDLES,BUFFER_TYPE_DATA,index_plot,index_base_array,4,1,"Candle Open;Candle High;Candle Low;Candle Close") {}

Die Methode, die das Flag zurückgibt, das die Pufferunterstützung von Integer-Eigenschaften anzeigt:

//+------------------------------------------------------------------+
//| Return 'true' if a buffer supports a passed                      |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+ 
bool CBufferCandles::SupportProperty(ENUM_BUFFER_PROP_INTEGER property)
  {
   if((property==BUFFER_PROP_ARROW_CODE || property==BUFFER_PROP_ARROW_SHIFT) ||  
       property==BUFFER_PROP_LINE_STYLE || property==BUFFER_PROP_LINE_WIDTH   ||
      (this.TypeBuffer()==BUFFER_TYPE_CALCULATE && property!=BUFFER_PROP_TYPE && property!=BUFFER_PROP_INDEX_NEXT)
     ) return false;
   return true; 
  }
//+------------------------------------------------------------------+

Wenn es sich um die Eigenschaft "Pfeilcode", "vertikale Pfeilabstand", "Linienstil" oder "Linienbreite" oder um einen berechneten Puffer handelt, der nicht die Eigenschaft "Puffertyp" oder "nächster gezeichneter Pufferindex" ist, wird er nicht unterstützt und false wird zurückgegeben. In anderen Fällen wird true zurückgegeben.

Die übrigen Methoden sind identisch mit der Objektklasse Sektionspuffer.

Alle Pufferobjektklassen des abgeleiteten, abstrakten Pufferobjekts wurden erstellt.
Die vollständige Liste der Klassen finden Sie in den unten angehängten Dateien.

Anstatt Schaltflächen zur Verwaltung der Anzeige von Pufferlinien auf dem Diagramm einzuführen, sollten wir stattdessen die erforderlichen grafischen Konstruktionen in den Indikatoreinstellungen festlegen. Wir sind in der Lage, auszuwählen, welche Puffer angezeigt werden sollen, und den Indikator zu starten.

Tests

Um die notwendigen grafischen Konstruktionen auswählen zu können, fügen wir der Eingabedatei mit den Enumerationen \MQL5\Include\DoEasy\InpDatas.mqh für die Sprachen Englisch und Russisch neue Enumerationen hinzu:

//+------------------------------------------------------------------+
//|                                                     InpDatas.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
#define COMPILE_EN // Comment out the string for compilation in Russian 
//+------------------------------------------------------------------+
//| Input enumerations                                               |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| English language inputs                                          |
//+------------------------------------------------------------------+
#ifdef COMPILE_EN
//+------------------------------------------------------------------+
//| Modes of working with symbols                                    |
//+------------------------------------------------------------------+
enum ENUM_SYMBOLS_MODE
  {
   SYMBOLS_MODE_CURRENT,                              // Work only with the current Symbol
   SYMBOLS_MODE_DEFINES,                              // Work with a given list of Symbols
   SYMBOLS_MODE_MARKET_WATCH,                         // Working with Symbols from the "Market Watch" window
   SYMBOLS_MODE_ALL                                   // Work with a complete list of Symbols
  };
//+------------------------------------------------------------------+
//| Mode of working with timeframes                                  |
//+------------------------------------------------------------------+
enum ENUM_TIMEFRAMES_MODE
  {
   TIMEFRAMES_MODE_CURRENT,                           // Work only with the current timeframe
   TIMEFRAMES_MODE_LIST,                              // Work with a given list of timeframes
   TIMEFRAMES_MODE_ALL                                // Work with a complete list of timeframes
  };
//+------------------------------------------------------------------+
//| "Yes"/"No"                                                       |
//+------------------------------------------------------------------+
enum ENUM_INPUT_YES_NO
  {
   INPUT_NO  = 0,                                     // No
   INPUT_YES = 1                                      // Yes
  };
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Russian language inputs                                          |
//+------------------------------------------------------------------+
#else  
//+------------------------------------------------------------------+
//| Modes of working with symbols                                    |
//+------------------------------------------------------------------+
enum ENUM_SYMBOLS_MODE
  {
   SYMBOLS_MODE_CURRENT,                              // Работа только с текущим символом
   SYMBOLS_MODE_DEFINES,                              // Работа с заданным списком символов
   SYMBOLS_MODE_MARKET_WATCH,                         // Работа с символами из окна "Обзор рынка"
   SYMBOLS_MODE_ALL                                   // Работа с полным списком символов
  };
//+------------------------------------------------------------------+
//| Mode of working with timeframes                                  |
//+------------------------------------------------------------------+
enum ENUM_TIMEFRAMES_MODE
  {
   TIMEFRAMES_MODE_CURRENT,                           // Работа только с текущим таймфреймом
   TIMEFRAMES_MODE_LIST,                              // Работа с заданным списком таймфреймов
   TIMEFRAMES_MODE_ALL                                // Работа с полным списком таймфреймов
  };
//+------------------------------------------------------------------+
//| "Yes"/"No"                                                       |
//+------------------------------------------------------------------+
enum ENUM_INPUT_YES_NO
  {
   INPUT_NO  = 0,                                     // Нет
   INPUT_YES = 1                                      // Да
  };
//+------------------------------------------------------------------+
#endif 
//+------------------------------------------------------------------+

Dies ermöglicht die Auswahl in den Einstellungen:


Um den Test durchzuführen, verwenden wir den Indikator aus dem vorherigen Artikel und speichern ihn in \MQL5\Indikatoren\TestDoEasy\Part43\ unter dem Namen TestDoEasyPart43.mq5.

Binden wir die Dateien aller erstellten Puffer in die Indikatorendatei ein, setzen die Anzahl der benutzten Puffer auf 27, während die Anzahl der gezeichneten Puffer auf 9 gesetzt wird:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart43.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Engine.mqh>
#include <DoEasy\Objects\Indicators\BufferArrow.mqh>        // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferLine.mqh>         // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferSection.mqh>      // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferHistogram.mqh>    // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferHistogram2.mqh>   // 2 construction buffers + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferZigZag.mqh>       // 2 construction buffers + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferFilling.mqh>      // 2 construction buffers + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferBars.mqh>         // 4 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferCandles.mqh>      // 4 construction buffer + 1 color buffer
//--- In total: 18 construction buffers + 9 color buffers:       27 indicator buffers, of which 9 are drawn ones
//--- properties
#property indicator_chart_window
#property indicator_buffers 27
#property indicator_plots   9 

Im Eingabeblock entkommentieren Sie die sinput Modifikatoren für die Auswahl des Arbeitsmodus mit Symbolen (standardmäßig wird der aktuelle Modus verwendet), blenden Sie die Liste der verwendeten Symbole aus den Einstellungen aus, legen Sie den standardmäßigen Zeitrahmen für die Auswahl fest, blenden Sie die Liste der verwendeten Zeitrahmen aus den Einstellungen aus und fügen Sie die Auswahlmöglichkeit hinzu, welche Puffer in den Einstellungen in der Grafik angezeigt werden sollen:

//--- classes

//--- enums

//--- defines

//--- structures

//--- input variables
/*sinput*/ ENUM_SYMBOLS_MODE  InpModeUsedSymbols=  SYMBOLS_MODE_CURRENT;            // Mode of used symbols list
/*sinput*/   string               InpUsedSymbols    =  "EURUSD,AUDUSD,EURAUD,EURGBP,EURCAD,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY";  // List of used symbols (comma - separator)
/*sinput*/   ENUM_TIMEFRAMES_MODE InpModeUsedTFs    =  TIMEFRAMES_MODE_CURRENT;            // Mode of used timeframes list
/*sinput*/   string               InpUsedTFs        =  "M1,M5,M15,M30,H1,H4,D1,W1,MN1"; // List of used timeframes (comma - separator)
sinput   ENUM_INPUT_YES_NO    InpDrawArrow      =  INPUT_YES;  // Draw Arrow
sinput   ENUM_INPUT_YES_NO    InpDrawLine       =  INPUT_NO;   // Draw Line
sinput   ENUM_INPUT_YES_NO    InpDrawSection    =  INPUT_NO;   // Draw Section
sinput   ENUM_INPUT_YES_NO    InpDrawHistogram  =  INPUT_NO;   // Draw Histogram
sinput   ENUM_INPUT_YES_NO    InpDrawHistogram2 =  INPUT_NO;   // Draw Histogram2
sinput   ENUM_INPUT_YES_NO    InpDrawZigZag     =  INPUT_NO;   // Draw ZigZag
sinput   ENUM_INPUT_YES_NO    InpDrawFilling    =  INPUT_NO;   // Draw Filling
sinput   ENUM_INPUT_YES_NO    InpDrawBars       =  INPUT_NO;   // Draw Bars
sinput   ENUM_INPUT_YES_NO    InpDrawCandles    =  INPUT_YES;  // Draw Candles
 
sinput   bool                 InpUseSounds      =  true; // Use sounds

Anstatt die double-Arrays der Indikatorpuffer zu deklarieren, fügen wir die Deklaration eines dynamischen Arrays mit Zeigern zu CObject-Instanzen hinzu. Die Liste soll Indikatorpufferobjekte speichern, die zum Testen erstellt wurden:

//--- indicator buffers
CArrayObj      list_buffers;                    // Temporary list for storing buffer objects
//--- global variables
CEngine        engine;                          // CEngine library main object
string         prefix;                          // Prefix of graphical object names
int            min_bars;                        // The minimum number of bars for the indicator calculation
int            used_symbols_mode;               // Mode of working with symbols
string         array_used_symbols[];            // The array for passing used symbols to the library
string         array_used_periods[];            // The array for passing used timeframes to the library
//+------------------------------------------------------------------+

In OnInit() des Indikators erzeugen wir alle Pufferobjekte, fügen sie der Liste hinzu, setzen die Nicht-Standardfarben (drei) und zeigen die Daten zu jedem erzeugten Pufferobjekt im Journal an:

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Initialize DoEasy library
   OnInitDoEasy();

//--- Set indicator global variables
   prefix=engine.Name()+"_";
   //--- Get the index of the maximum used timeframe in the array,
   //--- calculate the number of bars of the current period fitting in the maximum used period
   //--- Use the obtained value if it exceeds 2, otherwise use 2
   int index=ArrayMaximum(ArrayUsedTimeframes);
   int num_bars=NumberBarsInTimeframe(ArrayUsedTimeframes[index]);
   min_bars=(index>WRONG_VALUE ? (num_bars>2 ? num_bars : 2) : 2);

//--- Check and remove remaining indicator graphical objects
   if(IsPresentObectByPrefix(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Create the button panel

//--- Check playing a standard sound using macro substitutions
   engine.PlaySoundByDescription(SND_OK);
//--- Wait for 600 milliseconds
   engine.Pause(600);
   engine.PlaySoundByDescription(SND_NEWS);

//--- indicator buffers mapping

//--- Create all buffer objects
   CBuffer *buffer0=new CBufferArrow(0,0);
   CBuffer *buffer1=new CBufferLine(1,buffer0.IndexNextBuffer());
   CBuffer *buffer2=new CBufferSection(2,buffer1.IndexNextBuffer());
   CBuffer *buffer3=new CBufferHistogram(3,buffer2.IndexNextBuffer());
   CBuffer *buffer4=new CBufferHistogram2(4,buffer3.IndexNextBuffer());
   CBuffer *buffer5=new CBufferZigZag(5,buffer4.IndexNextBuffer());
   CBuffer *buffer6=new CBufferFilling(6,buffer5.IndexNextBuffer());
   CBuffer *buffer7=new CBufferBars(7,buffer6.IndexNextBuffer());
   CBuffer *buffer8=new CBufferCandles(8,buffer7.IndexNextBuffer());
//--- Add buffers to the list of indicator buffers
   list_buffers.Add(buffer0);
   list_buffers.Add(buffer1);
   list_buffers.Add(buffer2);
   list_buffers.Add(buffer3);
   list_buffers.Add(buffer4);
   list_buffers.Add(buffer5);
   list_buffers.Add(buffer6);
   list_buffers.Add(buffer7);
   list_buffers.Add(buffer8);
//--- Create color array
   color array_colors[]={clrDodgerBlue,clrRed,clrGray};
//--- Set non-default buffer color values
   for(int i=0;i<list_buffers.Total();i++)
     {
      CBuffer *buff=list_buffers.At(i);
      buff.SetColors(array_colors);
      //--- Print data on the next buffer
      buff.Print();
     }
//--- Set the label size for the arrow buffer and the line width for ZigZag
   buffer0.SetWidth(2);
   buffer5.SetWidth(2);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

In OnCalculate()
Wenn wir historische Daten initialisieren oder ändern, initialisieren wir alle erstellten Puffer und zeigen deren Kurznamen an.

Bei einem neuen Balken oder dem aktuellen Tick schreiben wir die Kurswerte in die Puffer:
ein einziger Puffer
— Close (Schlusskurse),
zwei Puffer
— Open (Eröffnungskurse) für den ersten und Close (Schlusskurs) für den zweiten Puffer
vier
Puffer wir schreiben die entsprechenden OHLC-Preise in jeden Puffer:

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//+------------------------------------------------------------------+
//| OnCalculate code block for working with the library:             |
//+------------------------------------------------------------------+
   
//--- Pass the current symbol data from OnCalculate() to the price structure
   CopyData(rates_total,prev_calculated,time,open,high,low,close,tick_volume,volume,spread);

//--- Check for the minimum number of bars for calculation
   if(rates_total<min_bars || Point()==0) return 0;
   
//--- Handle the Calculate event in the library
//--- If the OnCalculate() method of the library returns zero, not all timeseries are ready - leave till the next tick
   if(engine.0)
      return 0;
   
//--- If working in the tester
   if(MQLInfoInteger(MQL_TESTER)) 
     {
      engine.OnTimer(rates_data);   // Working in the library timer
      EventsHandling();             // Working with library events
     }
//+------------------------------------------------------------------+
//| OnCalculate code block for working with the indicator:           |
//+------------------------------------------------------------------+
//--- Set OnCalculate arrays as timeseries
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(time,true);
   ArraySetAsSeries(tick_volume,true);
   ArraySetAsSeries(volume,true);
   ArraySetAsSeries(spread,true);

//--- Check and calculate the number of calculated bars
//--- If limit = 0, there are no new bars - calculate the current one
//--- If limit = 1, a new bar has appeared - calculate the first and the current ones
//--- limit > 1 means the first launch or changes in history - the full recalculation of all data
   int limit=rates_total-prev_calculated;
   
//--- Recalculate the entire history
   if(limit>1)
     {
      //--- In a loop by the number of buffers in the list
      for(int i=0;i<list_buffers.Total();i++)
        {
         //--- get the next buffer and display the type of its graphical construction to the journal
         //--- together with the double array assigned to the buffer (if all is correct, the size is equal to rates_total)
         CBuffer *buff=list_buffers.At(i);
         buff.PrintShort();
         buff.InitializeBuffers();
        }
      limit=rates_total-1;
     }
//--- Prepare data

//--- Calculate the indicator
   for(int i=limit; i>WRONG_VALUE && !IsStopped(); i--)
     {
      //--- In a loop by the number of buffers in the list
      for(int j=0;j<list_buffers.Total();j++)
        {
         //--- get the next buffer and
         CBuffer *buff=list_buffers.At(j);
         //--- clear its current data
         buff.ClearData(0);
         //--- If drawing is not used, move on to the next one
         if(!IsUse(buff.Status()))
            continue;
         //--- Depending on the number of buffers, fill them with price data
         //--- one buffer
         if(buff.BuffersTotal()==1)
            buff.SetBufferValue(0,i,close[i]);
         //--- two buffers - the first one is to store the bar open price, while the second one is to store the bar close price
         else if(buff.BuffersTotal()==2)
           {
            buff.SetBufferValue(0,i,open[i]);
            buff.SetBufferValue(1,i,close[i]);
           }
         //--- four buffers - each buffer is to store OHLC bar prices
         else if(buff.BuffersTotal()==4)
           {
            buff.SetBufferValue(0,i,open[i]);
            buff.SetBufferValue(1,i,high[i]);
            buff.SetBufferValue(2,i,low[i]);
            buff.SetBufferValue(3,i,close[i]);
           }
         //--- Set the buffer color depending on the candle direction
         if(open[i]<close[i])
            buff.SetBufferColorIndex(i,0);
         else if(open[i]>close[i])
            buff.SetBufferColorIndex(i,1);
         else
            buff.SetBufferColorIndex(i,2);
        }
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Verwenden wir die folgende Funktion, um festzulegen, ob das Zeichnen der Indikatorlinien aktiviert ist:

//+---------------------------------------------------------------------+
//| Return the flag indicating the appropriate drawing style is enabled |
//+---------------------------------------------------------------------+
bool IsUse(const ENUM_BUFFER_STATUS status)
  {
   switch(status)
     {
      case BUFFER_STATUS_FILLING    : return (bool)InpDrawFilling;
      case BUFFER_STATUS_LINE       : return (bool)InpDrawLine;
      case BUFFER_STATUS_HISTOGRAM  : return (bool)InpDrawHistogram;
      case BUFFER_STATUS_ARROW      : return (bool)InpDrawArrow;
      case BUFFER_STATUS_SECTION    : return (bool)InpDrawSection;
      case BUFFER_STATUS_HISTOGRAM2 : return (bool)InpDrawHistogram2;
      case BUFFER_STATUS_ZIGZAG     : return (bool)InpDrawZigZag;
      case BUFFER_STATUS_BARS       : return (bool)InpDrawBars;
      case BUFFER_STATUS_CANDLES    : return (bool)InpDrawCandles;
      default: return false;
     }
  }
//+------------------------------------------------------------------+

Die Funktion empfängt den Pufferstatus und gibt den Eingabewert zurück, der dem an die Funktion übergebenen Status entspricht.

Der vollständige Indikatorcode ist in den unten angehängten Dateien enthalten.

Kompilieren Sie den Indikator und starten Sie ihn auf dem Chart.
Während der Initialisierung zeigt das Journal alle Eigenschaften von neun erstellten Indikatorpuffern an:

Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.) 10425.23 USD, 1:100, Hedge, MetaTrader 5 demo
--- Initializing "DoEasy" library ---
Working with the current symbol only: "EURUSD"
Working with the current timeframe only: H1
EURUSD symbol timeseries: 
- Timeseries "EURUSD" H1: Requested: 1000, Actual: 0, Created: 0, On the server: 0
Library initialization time: 00:00:00.156

============= Parameter list start: Colored data buffer[0] "Drawing with arrows" ==================
Plotted buffer serial number: 0
Buffer status: Indicator buffer with graphical construction type "Drawing with arrows"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Drawing with arrows
Arrow code: 159
The vertical shift of the arrows: 0
Arrow size: 1
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 1
Base data buffer index: 0
Color buffer index: 1
Index of the array to be assigned as the next indicator buffer: 2
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Arrows
================== Parameter list end: Colored data buffer[0] "Drawing with arrows" ==================

============= Parameter list start: Colored data buffer[1] "Line" ==================
Plotted buffer serial number: 1
Buffer status: Indicator buffer with graphical construction type "Line"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Line
Line style: Solid line
Line width: 1
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 1
Base data buffer index: 2
Color buffer index: 3
Index of the array to be assigned as the next indicator buffer: 4
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Line
================== Parameter list end: Colored data buffer[1] "Line" ==================

============= Parameter list start: Colored data buffer[2] "Section" ==================
Plotted buffer serial number: 2
Buffer status: Indicator buffer with graphical construction type "Section"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Section
Line style: Solid line
Line width: 1
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 1
Base data buffer index: 4
Color buffer index: 5
Index of the array to be assigned as the next indicator buffer: 6
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Section
================== Parameter list end: Colored data buffer[2] "Section" ==================

============= Parameter list start: Colored data buffer[3] "Histogram from the zero line" ==================
Plotted buffer serial number: 3
Buffer status: Indicator buffer with graphical construction type "Histogram from the zero line"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Histogram from the zero line
Line style: Solid line
Line width: 2
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 1
Base data buffer index: 6
Color buffer index: 7
Index of the array to be assigned as the next indicator buffer: 8
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Histogram
================== Parameter list end: Colored data buffer[3] "Histogram from the zero line" ==================

============= Parameter list start: Colored data buffer[4] "Histogram on two indicator buffers" ==================
Plotted buffer serial number: 4
Buffer status: Indicator buffer with graphical construction type "Histogram on two indicator buffers"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Histogram on two indicator buffers
Line style: Solid line
Line width: 8
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 2
Base data buffer index: 8
Color buffer index: 10
Index of the array to be assigned as the next indicator buffer: 11
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Histogram2 0;Histogram2 1
================== Parameter list end: Colored data buffer[4] "Histogram on two indicator buffers" ==================

============= Parameter list start: Colored data buffer[5] "Zigzag" ==================
Plotted buffer serial number: 5
Buffer status: Indicator buffer with graphical construction type "Zigzag"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Zigzag
Line style: Solid line
Line width: 1
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 2
Base data buffer index: 11
Color buffer index: 13
Index of the array to be assigned as the next indicator buffer: 14
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: ZigZag 0;ZigZag 1
================== Parameter list end: Colored data buffer[5] "Zigzag" ==================

============= Parameter list start: Colored data buffer[6] "Color filling between two levels" ==================
Plotted buffer serial number: 6
Buffer status: Indicator buffer with graphical construction type "Color filling between two levels"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Color filling between two levels
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 2
Drawing color: clrDodgerBlue,clrRed
Number of data buffers: 2
Base data buffer index: 14
Index of the array to be assigned as the next indicator buffer: 16
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Filling 0;Filling 1
================== Parameter list end: Colored data buffer[6] "Color filling between two levels" ==================

============= Parameter list start: Colored data buffer[7] "Display as bars" ==================
Plotted buffer serial number: 7
Buffer status: Indicator buffer with graphical construction type "Display as bars"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Display as bars
Line width: 2
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 4
Base data buffer index: 16
Color buffer index: 20
Index of the array to be assigned as the next indicator buffer: 21
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Bar Open;Bar High;Bar Low;Bar Close
================== Parameter list end: Colored data buffer[7] "Display as bars" ==================

============= Parameter list start: Colored data buffer[8] "Display as candles" ==================
Plotted buffer serial number: 8
Buffer status: Indicator buffer with graphical construction type "Display as candles"
Buffer type: Colored data buffer
Buffer data period (timeframe): Current chart period (H1)
Active: Yes
Graphical construction type: Display as candles
The number of initial bars that are not drawn and values in DataWindow: 0
Display construction values in DataWindow: Yes
Indicator graphical construction shift by time axis in bars: 0
Number of colors: 3
Drawing color: clrDodgerBlue,clrRed,clrGray
Number of data buffers: 4
Base data buffer index: 21
Color buffer index: 25
Index of the array to be assigned as the next indicator buffer: 26
------
Empty value for plotting where nothing will be drawn: EMPTY_VALUE
------
Buffer symbol: EURUSD
Name of the graphical indicator series displayed in DataWindow: Candle Open;Candle High;Candle Low;Candle Close
================== Parameter list end: Colored data buffer[8] "Display as candles" ==================


Nach dem ersten Start werden bei der Initialisierung der Bibliothek und aller Indikatorpuffer die folgenden Einträge ins Journal geschrieben:

"EURUSD" H1 timeseries created successfully:
- Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6230
Buffer(0): Drawing with arrows EURUSD H1
Buffer(1): EURUSD H1 line
Buffer(2): EURUSD H1 sections
Buffer(3): Histogram from the zero line EURUSD H1
Buffer(4): Histogram on two indicator buffers EURUSD H1
Buffer(5): EURUSD H1 zigzag
Buffer(6): Color filling between two levels EURUSD H1
Buffer(7): Display as EURUSD H1 bars
Buffer(8): Display as EURUSD H1 candles

Lassen Sie uns die Berechtigungen zum Anzeigen von Indikatorlinien in den Einstellungen ändern:


Was kommt als Nächstes?

Im nächsten Artikel beginnen wir mit der Erstellung der Klasse einer Kollektion mit Indikatorpuffern. Diese Klasse bietet die größte Flexibilität und Bequemlichkeit bei der Erstellung von Indikatorpuffern und ihrer Verwendung für beliebige Symbole und Diagrammperioden bei der Entwicklung nutzerdefinierter Indikatorprogramme unter Verwendung der Bibliothek.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit den Dateien der Test-EAs angehängt, die Sie testen und herunterladen können.
Hinterlassen Sie Ihre Fragen, Kommentare und Anregungen in den Kommentaren.
Bitte bedenken Sie, dass ich hier den MQL5-Testindikator 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.
Nachdem ich die Kollektion der Indikatorpuffer erstellt und getestet habe, werde ich versuchen, einige MQL5-Funktionen in MetaTrader 4 zu implementieren.

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 Symbolperioden
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 40): Bibliotheksbasierte Indikatoren - Aktualisierung der Daten in Echtzeit
Zeitreihen in der Bibliothek DoEasy (Teil 41): Beispiel eines Multisymbol- und Mehrperiodenindikators
Zeitreihen in der Bibliothek DoEasy (Teil 42): Abstrakte Objektklasse der Indikatorpuffer