English Русский Deutsch 日本語 Português
preview
Búferes de color en indicadores de periodo y símbolo múltiple

Búferes de color en indicadores de periodo y símbolo múltiple

MetaTrader 5Ejemplos | 21 mayo 2024, 14:46
86 0
Artyom Trishkin
Artyom Trishkin

Contenido


Introducción

Continuamos con el desarrollo de indicadores de símbolo y periodo múltiple, iniciado en el último artículo.

El búfer del indicador monocolor es un array double normal, que se rellena con datos al calcular el indicador. Podemos obtener los datos de este array y mostrarlos en el gráfico utilizando la función CopyBuffer(), siempre que el array receptor sea un array double asignado como búfer del indicador dibujado(SetIndexBuffer()). Al copiar datos del búfer de la parte de cálculo del indicador al búfer de la parte de dibujado del indicador, los datos se mostrarán en el gráfico en un color establecido para el búfer-array de la parte de dibujado del indicador. Con los búferes de color, sin embargo, el caso es un poco diferente. El búfer de color tiene otro array además del array de datos, el array de índices de color.

Con una línea de color dibujada con el indicador, podemos establecer no más de 64 colores diferentes para su visualización. Podemos establecer los colores para la línea dibujada utilizando la directiva del compilador indicator_colorN, por ejemplo.

#property indicator_color1  clrGreen,clrRed

o la función PlotIndexSetInteger(), por ejemplo.

PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,2);
PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrGreen);
PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrRed);

En ambos casos, aquí estableceremos dos colores de dibujado para la primera línea dibujada del indicador: verde y rojo. El índice de color verde es 0, mientras que el índice de color rojo es 1. Estos índices de color se almacenan en un array especial de índices de color en el búfer de color del indicador. Para cada barra de la serie temporal calculada por el indicador, podemos establecer un color de representación diferente: simplemente estableceremos un índice de color diferente para cada barra. En este caso, será 0 o 1. La línea indicadora se dibujará con el color asignado por este índice.

En los ejemplos anteriores, el primer método parece más conciso, Y esto es cierto, pero para poder cambiar dinámicamente el color de la línea del indicador, deberemos utilizar el segundo método: la asignación de un número de colores y el posterior cambio de estos de manera dinámica por cualquier otro según la situación que muestre el indicador.

Deberemos asignar un array de índices de color a cada búfer de color, y el array de índices de color tendrá necesariamente un índice una unidad mayor que el índice del array que se está dibujando. Para los estilos de dibujo que requieren más de un array, el índice del array de color será siempre una unidad mayor que el índice del último array asignado para dibujar la línea.


Principios básicos

Sobre la base de lo anterior, entenderemos que

  1. El búfer del indicador dibujado puede usar uno o más arrays para el dibujado, dependiendo del estilo del mismo.
  2. Para cualquier array de color, se utilizará otro array adicional: el array de índice de color del búfer a dibujar, cuyo índice será una unidad mayor que el índice del último array asignado al búfer dibujado.

Para una mejor comprensión, crearemos un nuevo indicador en el que especificaremos varios búferes a dibujar, tanto simples como de color, utilizando varios arrays para su construcción:


Como resultado, obtendremos este modelo de indicador:

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 17                     // 17 arrays for indicator calculations in total
#property indicator_plots   6                      // Out of 17  arrays, 6 graphic series are plotting buffers
//--- plot Label1
#property indicator_label1  "Label1"
#property indicator_type1   DRAW_LINE              // Plot buffer with index 0 is a simple line, requires one array to plot
#property indicator_color1  clrRed                 // Color line: Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Label2
#property indicator_label2  "Label2"
#property indicator_type2   DRAW_FILLING           // Plot buffer with index 1 is a colored area drawn between two indicator lines, requires two arrays to plot
#property indicator_color2  clrRed,clrDeepSkyBlue  // Area color: wither Red or DeepSkyBlue depending on which line is higher
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot Label3
#property indicator_label3  "Label3"
#property indicator_type3   DRAW_CANDLES           // Plot buffer with index 2, display as single-color candlesticks, requires 4 arrays of OHLC data to plot
#property indicator_color3  clrDarkSalmon          // Color: DarkSalmon
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- plot Label4
#property indicator_label4  "Label4"
#property indicator_type4   DRAW_COLOR_LINE        // Plot buffer with index 3, color line, requires two arrays to plot: data array + color index array
#property indicator_color4  clrRed,clrRoyalBlue    // Two colors: Red and RoyalBlue. Can have up to 64 colors
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- plot Label5
#property indicator_label5  "Label5"
#property indicator_type5   DRAW_COLOR_HISTOGRAM2  // Plot buffer with index 4, color histogram between two lines, requires three arrays: 2 data arrays + color index array
#property indicator_color5  clrRed,clrForestGreen,clrBurlyWood // Three colors: Red, ForestGreen and BurlyWood. Can have up to 64 colors
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1
//--- plot Label6
#property indicator_label6  "Label6"               // Plot buffer with index 5, color histogram between two lines, requires 5 arrays: 4 OHLC data arrays + color index array
#property indicator_type6   DRAW_COLOR_CANDLES     // Three colors: Red, Blue and Gray. Can have up to 64 colors
#property indicator_color6  clrRed,clrBlue,clrGray
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1
//--- input variables
input uchar    InpHidePlotIndex  =  0;             // Hide Plot Index
//--- indicator buffers
double         Label1Buffer[];                     // Plot buffer with index 0
double         Label2Buffer1[];                    // Plot buffer with index 1, array 1
double         Label2Buffer2[];                    // Plot buffer with index 1, array 2
double         Label3Buffer1[];                    // Plot buffer with index 2, array 1
double         Label3Buffer2[];                    // Plot buffer with index 2, array 2
double         Label3Buffer3[];                    // Plot buffer with index 2, array 3
double         Label3Buffer4[];                    // Plot buffer with index 2, array 4
double         Label4Buffer[];                     // Plot buffer with index 3
double         Label4Colors[];                     // Color index array for plot buffer with index 3
double         Label5Buffer1[];                    // Plot buffer with index 4, array 1
double         Label5Buffer2[];                    // Plot buffer with index 4, array 2
double         Label5Colors[];                     // Color index array for plot buffer with index 4
double         Label6Buffer1[];                    // Plot buffer with index 5, array 1
double         Label6Buffer2[];                    // Plot buffer with index 5, array 2
double         Label6Buffer3[];                    // Plot buffer with index 5, array 3
double         Label6Buffer4[];                    // Plot buffer with index 5, array 4
double         Label6Colors[];                     // Color index array for plot buffer with index 5

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//--- Plot buffer 0. One array to plot
   SetIndexBuffer(0,Label1Buffer,INDICATOR_DATA);        // Data buffer
   
//--- Plot buffer 1. Two arrays for construction
   SetIndexBuffer(1,Label2Buffer1,INDICATOR_DATA);       // Line 1 data buffer
   SetIndexBuffer(2,Label2Buffer2,INDICATOR_DATA);       // Line 2 data buffer
   
//--- Plot buffer 2. Four arrays for construction
   SetIndexBuffer(3,Label3Buffer1,INDICATOR_DATA);       // Data buffer for line 1 Open
   SetIndexBuffer(4,Label3Buffer2,INDICATOR_DATA);       // Data buffer for line 2 High
   SetIndexBuffer(5,Label3Buffer3,INDICATOR_DATA);       // Data buffer for line 3 Low
   SetIndexBuffer(6,Label3Buffer4,INDICATOR_DATA);       // Data buffer for line 4 Close
   
//--- Plot buffer 3. Two arrays for construction
   SetIndexBuffer(7,Label4Buffer,INDICATOR_DATA);        // Data buffer
   SetIndexBuffer(8,Label4Colors,INDICATOR_COLOR_INDEX); // Buffer of color indexes
   
//--- Plot buffer 4. Three arrays for construction
   SetIndexBuffer(9,Label5Buffer1,INDICATOR_DATA);       // Data buffer for line 1
   SetIndexBuffer(10,Label5Buffer2,INDICATOR_DATA);      // Data buffer for line 2
   SetIndexBuffer(11,Label5Colors,INDICATOR_COLOR_INDEX);// Buffer of color indexes
   
//--- Plot buffer 5. Five arrays for construction
   SetIndexBuffer(12,Label6Buffer1,INDICATOR_DATA);      // Data buffer for line 1 Open
   SetIndexBuffer(13,Label6Buffer2,INDICATOR_DATA);      // Data buffer for line 2 High
   SetIndexBuffer(14,Label6Buffer3,INDICATOR_DATA);      // Data buffer for line 3 Low
   SetIndexBuffer(15,Label6Buffer4,INDICATOR_DATA);      // Data buffer for line 4 Close
   SetIndexBuffer(16,Label6Colors,INDICATOR_COLOR_INDEX);// Buffer of color indexes
  }
//+------------------------------------------------------------------+
//| 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[])
  {

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Aquí ya se escribirán los comentarios para entender qué arrays se asignan a qué series de gráficos. Si no cambiamos los nombres por defecto de las series gráficas al crear un indicador, el wizard creará nombres bastante lógicos y comprensibles para los búferes de indicador, donde "LabelX" será el nombre del búfer que se dibujará con el número X, y "Buffer" será el número del array (uno o varios) para dibujar una serie gráfica.

Por ejemplo,

  • Label5Buffer1 es el primer array del quinto búfer a dibujar (su índice es en realidad 4, ya que la cuenta empieza desde cero) para construir el histograma de color dibujado entre las dos líneas,
  • Label5Buffer2 es el segundo array del quinto búfer que se dibujará para crear el histograma de color dibujado entre las dos líneas,
  • Label5Colors es un array de índices del color del quinto búfer que se dibuja para construir un histograma de color dibujado entre dos líneas.

En el ejemplo anterior, el índice de la serie gráfica (el búfer que se va a dibujar) es 4, aunque se le asignan arrays con índices 9, 10 y 11. Es decir, para asignar cualquier propiedad a esta serie gráfica, deberemos establecerla no según los índices de los arrays asignados para dibujar la serie gráfica, sino según el índice del búfer a dibujar, y en este ejemplo tendremos seis de ellos - de 0 a 5.

Para tener una visión clara de la asignación de propiedades a las series gráficas, podemos añadir una variable de entrada donde indicaremos el índice del búfer a dibujar, que no se deberá representar en la ventana de datos, y asignar al búfer a dibujar el valor false:

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 17                     // 17 arrays for indicator calculations in total
#property indicator_plots   6                      // Out of 17  arrays, 6 graphic series are plotting buffers
//--- plot Label1
#property indicator_label1  "Label1"
#property indicator_type1   DRAW_LINE              // Plot buffer with index 0 is a simple line, requires one array to plot
#property indicator_color1  clrRed                 // Color line: Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Label2
#property indicator_label2  "Label2"
#property indicator_type2   DRAW_FILLING           // Plot buffer with index 1 is a colored area drawn between two indicator lines, requires two arrays to plot
#property indicator_color2  clrRed,clrDeepSkyBlue  // Area color: wither Red or DeepSkyBlue depending on which line is higher
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot Label3
#property indicator_label3  "Label3"
#property indicator_type3   DRAW_CANDLES           // Plot buffer with index 2, display as single-color candlesticks, requires 4 arrays of OHLC data to plot
#property indicator_color3  clrDarkSalmon          // Color: DarkSalmon
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- plot Label4
#property indicator_label4  "Label4"
#property indicator_type4   DRAW_COLOR_LINE        // Plot buffer with index 3, color line, requires two arrays to plot: data array + color index array
#property indicator_color4  clrRed,clrRoyalBlue    // Two colors: Red and RoyalBlue. Can have up to 64 colors
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- plot Label5
#property indicator_label5  "Label5"
#property indicator_type5   DRAW_COLOR_HISTOGRAM2  // Plot buffer with index 4, color histogram between two lines, requires three arrays: 2 data arrays + color index array
#property indicator_color5  clrRed,clrForestGreen,clrBurlyWood // Three colors: Red, ForestGreen and BurlyWood. Can have up to 64 colors
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1
//--- plot Label6
#property indicator_label6  "Label6"               // Plot buffer with index 5, color histogram between two lines, requires 5 arrays: 4 OHLC data arrays + color index array
#property indicator_type6   DRAW_COLOR_CANDLES     // Three colors: Red, Blue and Gray. Can have up to 64 colors
#property indicator_color6  clrRed,clrBlue,clrGray
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1
//--- input variables
input uchar    InpHidePlotIndex  =  0;             // Hide Plot Index
//--- indicator buffers
double         Label1Buffer[];                     // Plot buffer with index 0
double         Label2Buffer1[];                    // Plot buffer with index 1, array 1
double         Label2Buffer2[];                    // Plot buffer with index 1, array 2
double         Label3Buffer1[];                    // Plot buffer with index 2, array 1
double         Label3Buffer2[];                    // Plot buffer with index 2, array 2
double         Label3Buffer3[];                    // Plot buffer with index 2, array 3
double         Label3Buffer4[];                    // Plot buffer with index 2, array 4
double         Label4Buffer[];                     // Plot buffer with index 3
double         Label4Colors[];                     // Color index array for plot buffer with index 3
double         Label5Buffer1[];                    // Plot buffer with index 4, array 1
double         Label5Buffer2[];                    // Plot buffer with index 4, array 2
double         Label5Colors[];                     // Color index array for plot buffer with index 4
double         Label6Buffer1[];                    // Plot buffer with index 5, array 1
double         Label6Buffer2[];                    // Plot buffer with index 5, array 2
double         Label6Buffer3[];                    // Plot buffer with index 5, array 3
double         Label6Buffer4[];                    // Plot buffer with index 5, array 4
double         Label6Colors[];                     // Color index array for plot buffer with index 5
//--- global variables
int   hide_index=(InpHidePlotIndex>5 ? 5 : InpHidePlotIndex);
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//--- Plot buffer 0. One array to plot
   SetIndexBuffer(0,Label1Buffer,INDICATOR_DATA);        // Data buffer
   
//--- Plot buffer 1. Two arrays for construction
   SetIndexBuffer(1,Label2Buffer1,INDICATOR_DATA);       // Line 1 data buffer
   SetIndexBuffer(2,Label2Buffer2,INDICATOR_DATA);       // Line 2 data buffer
   
//--- Plot buffer 2. Four arrays for construction
   SetIndexBuffer(3,Label3Buffer1,INDICATOR_DATA);       // Data buffer for line 1 Open
   SetIndexBuffer(4,Label3Buffer2,INDICATOR_DATA);       // Data buffer for line 2 High
   SetIndexBuffer(5,Label3Buffer3,INDICATOR_DATA);       // Data buffer for line 3 Low
   SetIndexBuffer(6,Label3Buffer4,INDICATOR_DATA);       // Data buffer for line 4 Close
   
//--- Plot buffer 3. Two arrays for construction
   SetIndexBuffer(7,Label4Buffer,INDICATOR_DATA);        // Data buffer
   SetIndexBuffer(8,Label4Colors,INDICATOR_COLOR_INDEX); // Buffer of color indexes
   
//--- Plot buffer 4. Three arrays for construction
   SetIndexBuffer(9,Label5Buffer1,INDICATOR_DATA);       // Data buffer for line 1
   SetIndexBuffer(10,Label5Buffer2,INDICATOR_DATA);      // Data buffer for line 2
   SetIndexBuffer(11,Label5Colors,INDICATOR_COLOR_INDEX);// Buffer of color indexes
   
//--- Plot buffer 5. Five arrays for construction
   SetIndexBuffer(12,Label6Buffer1,INDICATOR_DATA);      // Data buffer for line 1 Open
   SetIndexBuffer(13,Label6Buffer2,INDICATOR_DATA);      // Data buffer for line 2 High
   SetIndexBuffer(14,Label6Buffer3,INDICATOR_DATA);      // Data buffer for line 3 Low
   SetIndexBuffer(15,Label6Buffer4,INDICATOR_DATA);      // Data buffer for line 4 Close
   SetIndexBuffer(16,Label6Colors,INDICATOR_COLOR_INDEX);// Buffer of color indexes

//--- Hode  the specified plot buffer in the data window
   PlotIndexSetInteger(0,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(1,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(2,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(3,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(4,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(5,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(hide_index,PLOT_SHOW_DATA,false);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+


Si configuramos en los ajustes el búfer 0, que se corresponde con una serie de gráficos llamada Label1, este búfer no se mostrará en la ventana de datos


Puede ver que la lista de datos comienza con un búfer llamado Label2.

Si introducimos 5 en la configuración del indicador, el búfer dibujado llamado Label6 se ocultará de la ventana de datos:


En consecuencia, no importa cuántos arrays se asignen en el indicador para construir series gráficas, deberemos tener en cuenta los siguientes hechos:

  • para cambiar las propiedades de las series gráficas, deberemos recurrir según el índice del búfer necesario a dibujar, no según el índice de los arrays asignados para construir estas series,
  • Se necesitarán de uno a cinco arrays asignados como búferes de indicador para construir búferes con diferentes estilos de dibujado,
  • todos los arrays que pertenezcan al mismo búfer a dibujar deberán seguirse unos a otros en estricta secuencia. No deberán mezclarse con otros arrays asignados para construir otras series gráficas,
  • el array de índices de color será el último de la lista de arrays asignados al búfer que se va a dibujar.

Basándonos en todo lo anterior, notaremos que es necesario perfeccionar la estructura de los búferes de indicador de símbolo y periodo múltiple. Ahora se declararán cinco arrays en la estructura: cuatro arrays para almacenar los datos del búfer y un quinto array para almacenar los índices de color. Los distintos estilos de trazado de líneas indicadoras implicarán el uso de uno a cinco arrays de tipo double. Todos estos arrays se declararán en la estructura del búfer, y solo se utilizarán los necesarios para un indicador concreto. Como consecuencia, al acceder a los datos del búfer, deberemos especificar el número (índice) del array necesario junto con el índice de este búfer. Dado que no resulta muy cómodo especificar el índice del búfer requerido y el índice del array necesario todo el tiempo (la mayoría de las construcciones de indicadores en los indicadores estándar se implementan sobre un búfer de un solo array), deberemos especificar cero como segundo índice. Sin embargo, más adelante, después de crear y probar todos los indicadores como su multiversión, añadiremos métodos a las clases de cada indicador para obtener los datos necesarios del búfer y el array requeridos. Eso vendrá después. Por ahora, vamos a ocuparnos de la estructura de los búferes de indicador.


Mejoramos las clases

Para no llevar la cuenta de cuántos arrays requiere el búfer de indicador dibujado para su construcción, organizaremos la obtención de los datos de la serie gráfica de tal forma que nos dirijamos solo según el índice del búfer a dibujar y según el índice del array requerido. Es decir, si el búfer 0 se dibuja sobre dos arrays de datos y un array de índices de color, entonces para solicitar los datos del primer array bastará con especificar el índice del búfer a dibujar y el índice del array requerido, por ejemplo 0 y 0. Si necesitamos los datos del segundo array, especificaremos 0 y 1. Para solicitar datos del búfer de color implementaremos los métodos correspondientes: especificaremos solo el índice del búfer a dibujar (0).

Así no necesitaremos recordar los índices de los arrays asignados a los búferes de indicador, la clase los memorizará y devolverá los datos según el índice de la serie gráfica y el array requerido. De esta manera, probablemente será un poco más fácil recuperar los datos, usando solo la consulta según los índices de los búferes que se dibujan. Un poco más tarde crearemos para cada clase de cada indicador estándar los métodos que devuelvan los datos del array requerido, esto hará que sea aún más fácil obtener los datos de los búferes de multi-indicadores y trazar sus líneas en el gráfico.

Todos los cambios se realizarán en el archivo de biblioteca \MQL5\Include\IndMSTF\IndMSTF\IndMSTF.mqh.

En el archivo de la biblioteca, rediseñaremos la estructura del búfer de indicador. Algunas funciones se trasladarán a una sección privada, ya que no será necesario acceder a ellas desde el exterior. Antes solo inicializábamos y redimensionábamos un array, ahora habrá cinco. Por lo tanto, las funciones de inicialización y redimensionamiento procesarán ahora cinco arrays. El número necesario de arrays se seleccionará según el estilo de dibujado establecido para el búfer, ya que es el estilo el que determinará el número necesario de arrays para dibujar una serie gráfica. El estilo de dibujado se establecerá en la estructura del búfer al crear el indicador. También en la estructura del búfer escribiremos el índice del array del indicador fuente, para así saber exactamente desde qué búfer de indicador fuente se copian los datos.

//--- struct
struct SBuffer                // Structure of the indicator buffer
  {
private:
   double            init_value;                            // Initializing value
   uchar             init_color_idx;                        // Initializing value of the color index
   int               shift;                                 // Horizontal shift of the buffer
   uint              source;                                // Buffer number of the source indicator
   bool              colored;                               // Flag of the color buffer
   ENUM_DRAW_TYPE    draw_type;                             // Buffer drawing style
//--- Changes the size of all arrays
   bool              ResizeArrays(const int new_size)
                       {
                        bool res=true;
                        switch(draw_type)
                          {
                           //--- One buffer
                           case DRAW_LINE             :
                           case DRAW_HISTOGRAM        :
                           case DRAW_ARROW            :
                           case DRAW_SECTION          :
                              return ArrayResize(array0,new_size)==new_size;
                           //--- Two buffers
                           case DRAW_HISTOGRAM2       :
                           case DRAW_ZIGZAG           :
                           case DRAW_FILLING          :
                              res  =(ArrayResize(array0,new_size)==new_size);
                              res &=(ArrayResize(array1,new_size)==new_size);
                              return res;
                           //--- Four buffers
                           case DRAW_BARS             :
                           case DRAW_CANDLES          :
                              res  =(ArrayResize(array0,new_size)==new_size);
                              res &=(ArrayResize(array1,new_size)==new_size);
                              res &=(ArrayResize(array2,new_size)==new_size);
                              res &=(ArrayResize(array3,new_size)==new_size);
                              return res;
                           //--- One buffer + color buffer
                           case DRAW_COLOR_LINE       :
                           case DRAW_COLOR_HISTOGRAM  :
                           case DRAW_COLOR_ARROW      :
                           case DRAW_COLOR_SECTION    :
                              res  =(ArrayResize(array0,new_size)==new_size);
                              res &=(ArrayResize(color_indexes,new_size)==new_size);
                              return res;
                           //--- Two buffers + color buffer
                           case DRAW_COLOR_HISTOGRAM2 :
                           case DRAW_COLOR_ZIGZAG     :
                              res  =(ArrayResize(array0,new_size)==new_size);
                              res &=(ArrayResize(array1,new_size)==new_size);
                              res &=(ArrayResize(color_indexes,new_size)==new_size);
                              return res;
                           //--- Four buffers + color buffer
                           case DRAW_COLOR_BARS       :
                           case DRAW_COLOR_CANDLES    :
                              res  =(ArrayResize(array0,new_size)==new_size);
                              res &=(ArrayResize(array1,new_size)==new_size);
                              res &=(ArrayResize(array2,new_size)==new_size);
                              res &=(ArrayResize(array3,new_size)==new_size);
                              res &=(ArrayResize(color_indexes,new_size)==new_size);
                              return res;
                           //---DRAW_NONE
                           default:
                             break;
                          }
                        return false;
                       }
//--- Initializes all arrays
   int               InitArrays(void)
                       {
                        bool res=0;
                        switch(draw_type)
                          {
                           //--- One buffer
                           case DRAW_LINE             :
                           case DRAW_HISTOGRAM        :
                           case DRAW_ARROW            :
                           case DRAW_SECTION          :
                              return ArrayInitialize(array0,init_value);
                           //--- Two buffers
                           case DRAW_HISTOGRAM2       :
                           case DRAW_ZIGZAG           :
                           case DRAW_FILLING          :
                              res+=ArrayInitialize(array0,init_value);
                              res+=ArrayInitialize(array1,init_value);
                              return res/2;
                           //--- Four buffers
                           case DRAW_BARS             :
                           case DRAW_CANDLES          :
                              res+=ArrayInitialize(array0,init_value);
                              res+=ArrayInitialize(array1,init_value);
                              res+=ArrayInitialize(array2,init_value);
                              res+=ArrayInitialize(array3,init_value);
                              return res/4;
                           //--- One buffer + color buffer
                           case DRAW_COLOR_LINE       :
                           case DRAW_COLOR_HISTOGRAM  :
                           case DRAW_COLOR_ARROW      :
                           case DRAW_COLOR_SECTION    :
                              res+=ArrayInitialize(array0,init_value);
                              res+=ArrayInitialize(color_indexes,init_color_idx);
                              return res/2;
                           //--- Two buffers + color buffer
                           case DRAW_COLOR_HISTOGRAM2 :
                           case DRAW_COLOR_ZIGZAG     :
                              res+=ArrayInitialize(array0,init_value);
                              res+=ArrayInitialize(array1,init_value);
                              res+=ArrayInitialize(color_indexes,init_color_idx);
                              return res/3;
                           //--- Four buffers + color buffer
                           case DRAW_COLOR_BARS       :
                           case DRAW_COLOR_CANDLES    :
                              res+=ArrayInitialize(array0,init_value);
                              res+=ArrayInitialize(array1,init_value);
                              res+=ArrayInitialize(array2,init_value);
                              res+=ArrayInitialize(array3,init_value);
                              res+=ArrayInitialize(color_indexes,init_color_idx);
                              return res/5;
                           //---DRAW_NONE
                           default:
                             break;
                          }
                        return false;
                       }
public:
   double            array0[];                              // Indicator's buffer-array0
   double            array1[];                              // Indicator's buffer-array1 (2nd array for calculation)
   double            array2[];                              // Indicator's buffer-array2 (3rd array for calculation)
   double            array3[];                              // Indicator's buffer-array3 (4th array for calculation)
   double            color_indexes[];                       // Buffer array of indicator color indexes
   color             clrs[];                                // Array of colors assigned to the buffer
   string            descript;                              // Buffer description
//--- Returns the color buffer flag
   bool              IsColoredBuffer(void)                        { return colored;                }
//--- (1) Sets, (2) returns the buffer drawing style, (3) the number of the corresponding buffer of the source indicator
   void              SetBufferDrawType(const ENUM_DRAW_TYPE type,const uint buff_source)
                       {
                        draw_type=type;
                        source=buff_source;
                        switch(draw_type)
                          {
                           case DRAW_COLOR_LINE       :
                           case DRAW_COLOR_SECTION    :
                           case DRAW_COLOR_HISTOGRAM  :
                           case DRAW_COLOR_HISTOGRAM2 :
                           case DRAW_COLOR_ARROW      :
                           case DRAW_COLOR_ZIGZAG     :
                           case DRAW_COLOR_BARS       :
                           case DRAW_COLOR_CANDLES    :  colored=true;  break;
                           default                    :  colored=false; break;
                          }
                       }
   ENUM_DRAW_TYPE    DrawType(void)                               { return draw_type;              }
   uint              BufferFrom(void)                             { return source;                 }
//--- (1) Sets, (2) returns the initializing value
   void              SetInitValue(const double value)             { init_value=value;              }
   double            InitValue(void)                              { return init_value;             }
//--- (1) Sets, (2) returns the initializing value of the color index
   void              SetInitColorIdx(const uchar idx)             { init_color_idx=idx;            }
   uchar             InitColorIdx(void)                           { return init_color_idx;         }
//--- (1) Sets, (2) returns the buffer offset
   void              SetShift(const int value)                    { shift=value;                   }
   int               Shift(void)                                  { return shift;                  }
//--- (1) Returns the size of the buffer array, (2) changes the size of the buffer array,
//--- (3) initializes the array with the set "empty" value
   uint              BufferSize(void)                             { return array0.Size();          }
   bool              BuffResize(const int new_size)               { return ResizeArrays(new_size); }
   int               InitBuffer(void)                             { return InitArrays();           }
//--- (1) Returns the size of the color index buffer array,
   uint              BufferColorIdxSize(void)                     { return color_indexes.Size();   }
   //--- (1) Sets, (2) returns the color value by index
   void              SetColorToIdx(const uchar idx,const color clr)
                       {
                        if(idx>(int)clrs.Size()-1)
                          {
                           ResetLastError();
                           if(ArrayResize(clrs,idx+1)!=idx+1)
                             {
                              PrintFormat("%s: ArrayResize 'clrs' failed. Error %lu",__FUNCTION__,GetLastError());
                              return;
                             }
                          }
                        clrs[idx]=clr;
                       }
   color             ColorByIdx(const uchar idx){ return(idx<clrs.Size() ? clrs[idx] : clrNONE);   }
  };

Antes, los arrays se copiaban en el método de cálculo del indicador Calculate(). Ahora, como habrá que copiar más de un array, hemos creado nuevos métodos que retornarán el resultado del copiado de todos los arrays utilizados para el cálculo. En la clase multi-indicador, declararemos los nuevos métodos y añadiremos el índice del array requerido a los métodos de obtención de datos.

//+------------------------------------------------------------------+
//| Base class of the multi-symbol multi-period indicator            |
//+------------------------------------------------------------------+
class CIndMSTF : public CObject
  {
private:
   ENUM_PROGRAM_TYPE m_program;           // Program type
   ENUM_INDICATOR    m_type;              // Indicator type
   ENUM_TIMEFRAMES   m_timeframe;         // Chart timeframe
   string            m_symbol;            // Chart symbol
   int               m_handle;            // Indicator handle
   int               m_id;                // Identifier
   bool              m_success;           // Successful calculation flag
   ENUM_ERR_TYPE     m_type_err;          // Calculation error type
   string            m_description;       // Custom description of the indicator
   string            m_name;              // Indicator name
   string            m_parameters;        // Description of indicator parameters

protected:
   ENUM_IND_CATEGORY m_category;          // Indicator category
   MqlParam          m_param[];           // Array of indicator parameters
   string            m_title;             // Title (indicator name + description of parameters)
   SBuffer           m_buffers[];         // Indicator buffers
   int               m_digits;            // Digits in indicator values
   int               m_limit;             // Number of bars required to calculate the indicator on the current tick
   int               m_rates_total;       // Number of available bars for indicator calculation
   int               m_prev_calculated;   // Number of calculated bars on the previous indicator call
   
//--- (1) Sets indicator name, (2) description of parameters
   void              SetName(const string name)                      { this.m_name=name;           }
   void              SetParameters(const string str)                 { this.m_parameters=str;      }
   
//--- Resizes the (1) specified, (2) all indicator buffers
   bool              BufferResize(const uint buffer_num,const int new_buff_size);
   bool              BuffersResize(const int new_buff_size);
//--- Initializes the (1) specified, (2) all indicator buffers
   bool              BufferInitialize(const uint buffer_num,const int new_buff_size);
   bool              BuffersInitialize(const int new_buff_size);
   
//--- Returns the flag indicating equality of the structure of one parameter of two objects
   bool              IsEqualParameters(const MqlParam &this_param,const MqlParam &compared_param) const
                       {
                        if(this_param.type==compared_param.type                     && 
                           this_param.integer_value==compared_param.integer_value   && 
                           this_param.string_value==compared_param.string_value     && 
                           ::NormalizeDouble(this_param.double_value-compared_param.double_value,8)==0
                          ) return true;
                        return false;
                       }
//--- Return the result of comparison on one parameter of two objects
   int               CompareParams(const MqlParam &this_param,const MqlParam &compared_param)
                       {
                        if(this.IsEqualParameters(this_param,compared_param))
                           return 0;
                        else if(this_param.type>compared_param.type                 || 
                           this_param.integer_value>compared_param.integer_value    || 
                           this_param.string_value>compared_param.string_value      || 
                           this_param.double_value>compared_param.double_value
                          ) return 1;
                        else if(this_param.type<compared_param.type                 || 
                           this_param.integer_value<compared_param.integer_value    || 
                           this_param.string_value<compared_param.string_value      || 
                           this_param.double_value<compared_param.double_value
                          ) return -1;
                        else
                           return -1;
                       }
//--- Copies data of the specified array of the specified buffer
   bool              CopyArray(const uint buff_num,const uint array_num,const int to_copy,double &array[]);
//--- Copies data of all arrays of the specified buffer
   bool              CopyArrays(const uint buff_num,const int to_copy);
   
public:
//--- Creates the calculation part of the indicator, returns the handle
   int               CreateIndicator(void);
//--- (1) Calculates the indicator, fills the passed (2) plot buffer array, (3) buffer array of color indexes (taking into account the symbol-period of the chart) with data from the buffer of the calculation part of the indicator of this class
   bool              Calculate(void);
   bool              DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &buffer[]);
   bool              DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[]);

//--- (1) Sets (2) returns the initializing value for the specified buffer
   void              SetBufferInitValue(const uint buffer_num,const double value);
   double            BufferInitValue(const uint buffer_num) const;
//--- (1) Sets (2) returns the initializing value of the color index for the specified buffer
   void              SetBufferInitColorIndex(const uint buffer_num,const uchar index);
   uchar             BufferInitColorIndex(const uint buffer_num) const;
//--- (1) Sets, (2) returns the color value by index for the specified buffer
   void              SetBufferColorToIndex(const uint buffer_num,const uchar color_idx,const color clr);
   color             BufferColorByIndex(const uint buffer_num,const uchar color_idx);
   //--- Returns the color buffer flag
   bool              IsColoredBuffer(const uint buffer_num) const;

//--- (1) Sets (2) returns the offset value for the specified buffer
   void              SetBufferShift(const uint buffer_num,const int value);
   double            BufferShift(const uint buffer_num) const;

   //--- (1) Sets, (2) returns the drawing style of the specified buffer, (3) the number of the corresponding buffer of the source indicator
   void              SetBufferDrawType(const uint buffer_num,const ENUM_DRAW_TYPE type,const uint buff_source);
   ENUM_DRAW_TYPE    BufferDrawType(const uint buffer_num);
   uint              BufferFrom(const uint buffer_num);

//--- Returns data of the specified buffer and array (1) as is, (2) relative to the specified symbol/timeframe,
//--- data of the specified color buffer (3) as is, (4) relative to the specified symbol/timeframe,
//--- (5) amount of data in the specified buffer, (6) number of colors set for the buffer, (7) the state of the indicator line as it is in the calculation part buffer,
//--- (8) state of the indicator line for the chart symbol/period, description of the line state (9) as is in the buffer (10) for the specific chart symbol/period
   double            GetData(const uint buffer_num,const uint array_num,const int index)  const;
   double            GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int index) const;
   double            GetColorData(const uint buffer_num,const int index)      const;
   double            GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const;
   uint              DataTotal(const uint buffer_num,const uint array_num)    const;
   uint              ColorsTotal(const uint buffer_num)                       const;
   ENUM_LINE_STATE   BufferLineState(const uint buffer_num,const uint array_num,const int index)   const;
   ENUM_LINE_STATE   BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const uint array_num,const int index) const;
   ENUM_LINE_STATE   BufferLineStateRelative(const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE);
   ENUM_LINE_STATE   BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE);

//--- Returns (1) success flag, (2) calculation error type
   bool              IsSuccess(void)                           const { return this.m_success;               }
   ENUM_ERR_TYPE     TypeError(void)                           const { return this.m_type_err;              }
   
//--- Sets (1) identifier, (2) Digits, (3) custom description, (4) description of the specified buffer
   void              SetID(const int id)                             { this.m_id=id;                        }
   void              SetDigits(const uint digits)                    { this.m_digits=(int)digits;           }
   void              SetDescription(const string descr)              { this.m_description=descr;            }
   void              SetBufferDescription(const uint buffer_num,const string descr);

//--- Sets the indexing of buffer arrays of the calculation part not as in the timeseries
   void              SetAsSeriesOff(void);
//--- Returns flag of whether the buffer is set as series, (2) historical data for symbol/period is synchronized
   bool              IsSeries(const uint buffer_num,const uint array_num) const;
   bool              IsSynchronized(void) const
                       {
                        return (bool)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_SYNCHRONIZED);
                       }
   
//--- Returns (1) timeframe, (2) symbol, (3) name, (4) list of parameters, (5) handle, (6) Digits
//--- number of (7) buffers, (8) bars, (9) identifier, (10) description, (11) title, (12) category,
//--- (13) number of parameters, (14) program type, description of (15) category, (16) indicator buffer
   ENUM_TIMEFRAMES   Timeframe(void)                           const { return this.m_timeframe;             }
   string            Symbol(void)                              const { return this.m_symbol;                }
   string            Name(void)                                const { return this.m_name;                  }
   string            Parameters(void)                          const { return this.m_parameters;            }
   int               Handle(void)                              const { return this.m_handle;                }
   int               Digits(void)                              const { return this.m_digits;                }
   uint              BuffersTotal(void)                        const { return this.m_buffers.Size();        }
   uint              RatesTotal(void)                          const { return this.m_rates_total;           }
   int               ID(void)                                  const { return this.m_id;                    }
   string            Description(void)                         const { return this.m_description;           }
   string            Title(void)                               const { return this.m_title;                 }
   ENUM_IND_CATEGORY Category(void)                            const { return this.m_category;              }
   uint              ParamsTotal(void)                         const { return this.m_param.Size();          }
   ENUM_PROGRAM_TYPE Program(void)                             const { return this.m_program;               }
   string            CategoryDescription(void);
   string            BufferDescription(const uint buffer_num);

//--- Returns (1) structure of parameters by index from array, (2) flag of indicator program, (3) timeframe description
   MqlParam          GetMqlParam(const int index)              const { return this.m_param[index];          }
   bool              IsIndicator()                 const { return(this.Program()==PROGRAM_INDICATOR);       }
   string            TimeframeDescription(void)    const
                       {
                        return ::StringSubstr(::EnumToString(this.m_timeframe),7);
                       }
//--- Returns amount of calculated data
   int               Calculated(void)                          const { return ::BarsCalculated(this.m_handle); }
   
//--- Virtual method returning the type of object (indicator)
   virtual int       Type(void)                                const { return this.m_type;                  }
//--- Virtual method for comparing two objects
   virtual int       Compare(const CObject *node,const int mode=0) const
                       {
                        const CIndMSTF *compared=node;
                        switch(mode)
                          {
                           case COMPARE_MODE_ID          : return(this.ID()>compared.ID()                   ? 1 : this.ID()<compared.ID()                   ? -1 : 0);
                           case COMPARE_MODE_HANDLE      : return(this.Handle()>compared.Handle()           ? 1 : this.Handle()<compared.Handle()           ? -1 : 0);
                           case COMPARE_MODE_CATEGORY    : return(this.Category()>compared.Category()       ? 1 : this.Category()<compared.Category()       ? -1 : 0);
                           case COMPARE_MODE_SYMBOL      : return(this.Symbol()>compared.Symbol()           ? 1 : this.Symbol()<compared.Symbol()           ? -1 : 0);
                           case COMPARE_MODE_TIMEFRAME   : return(this.Timeframe()>compared.Timeframe()     ? 1 : this.Timeframe()<compared.Timeframe()     ? -1 : 0);
                           case COMPARE_MODE_DESCRIPTION : return(this.Description()>compared.Description() ? 1 : this.Description()<compared.Description() ? -1 : 0);
                           //--- Equality of all object parameters
                           default                       : return(this.IsEqualIndicators(compared) ? 0 : -1);
                          }
                       }
//--- Returns the flag of equality of parameters of two indicator objects
   bool              IsEqualIndicators(const CIndMSTF *compared) const
                       {
                        if(this.Type()!=compared.Type() || this.ParamsTotal()!=compared.ParamsTotal())
                           return false;
                        bool res=true;
                        int total=(int)this.ParamsTotal();
                        for(int i=0;i<total;i++)
                           res &=this.IsEqualParameters(this.m_param[i],compared.GetMqlParam(i));
                        res &=(this.Timeframe()==compared.Timeframe());
                        res &=(this.Symbol()==compared.Symbol());
                        return res;
                       }
//--- Timer
   void OnTimer(void);
   
//--- Constructor/destructor
                     CIndMSTF(){}
                     CIndMSTF(const ENUM_INDICATOR type,const uint buffers,const string symbol,const ENUM_TIMEFRAMES timeframe);
                    ~CIndMSTF();
  };

En el destructor de la clase liberaremos la memoria de todas los arrays de los búferes de indicador:

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CIndMSTF::~CIndMSTF()
  {
//--- Delete timer
   ::EventKillTimer();
//--- Release handle of the indicator
   ::ResetLastError();
   if(this.m_handle!=INVALID_HANDLE && !::IndicatorRelease(this.m_handle))
      ::PrintFormat("%s: %s, handle %ld IndicatorRelease failed. Error %ld",__FUNCTION__,this.Title(),m_handle,::GetLastError());
//--- Free up the memory of buffer arrays
   for(int i=0;i<(int)this.BuffersTotal();i++)
     {
      ::ArrayFree(this.m_buffers[i].array0);
      ::ArrayFree(this.m_buffers[i].array1);
      ::ArrayFree(this.m_buffers[i].array2);
      ::ArrayFree(this.m_buffers[i].array3);
      ::ArrayFree(this.m_buffers[i].color_indexes);
     }
  }

Aplicación de nuevos métodos declarados:

//+------------------------------------------------------------------+
//| Set the initializing value of the color index                    |
//| for the specified buffer                                         |
//+------------------------------------------------------------------+
void CIndMSTF::SetBufferInitColorIndex(const uint buffer_num,const uchar index)
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and exit
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return;
     }
//--- Set a new initializing color index value for the specified buffer
   this.m_buffers[buffer_num].SetInitColorIdx(index);
  }
//+------------------------------------------------------------------+
//| Return the initializing value of the color index                 |
//| for the specified buffer                                         |
//+------------------------------------------------------------------+
uchar CIndMSTF::BufferInitColorIndex(const uint buffer_num) const
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      //--- If the indicator has buffers, return the initializing value of the color index of the very first one, otherwise 0
      return uchar(this.BuffersTotal()>0 ? this.m_buffers[0].InitColorIdx() : 0);
     }
//--- Return the initializing value of the color index of the requested buffer
   return this.m_buffers[buffer_num].InitColorIdx();
  }
//+------------------------------------------------------------------+
//| Set the color value by index for the specified buffer            |
//+------------------------------------------------------------------+
void CIndMSTF::SetBufferColorToIndex(const uint buffer_num,const uchar color_idx,const color clr)
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and exit
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return;
     }
//--- Set a new color value by index for the specified buffer
   this.m_buffers[buffer_num].SetColorToIdx(color_idx,clr);
  }
//+------------------------------------------------------------------+
//| Return the color value by index for the specified buffer         |
//+------------------------------------------------------------------+
color CIndMSTF::BufferColorByIndex(const uint buffer_num,const uchar color_idx)
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      //--- If the indicator has buffers, return the initializing value of the color index of the very first one, otherwise 0
      return clrNONE;
     }
//--- Return the color value by index for the requested buffer
   return this.m_buffers[buffer_num].ColorByIdx(color_idx);
  }
//+------------------------------------------------------------------+
//| Return the color buffer flag                                     |
//+------------------------------------------------------------------+
bool CIndMSTF::IsColoredBuffer(const uint buffer_num) const
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      //--- Return false
      return false;
     }
//--- Return the color flag for the specified buffer
   return this.m_buffers[buffer_num].IsColoredBuffer();
  }

//+------------------------------------------------------------------+
//| Set the drawing style for the specified buffer                   |
//+------------------------------------------------------------------+
void CIndMSTF::SetBufferDrawType(const uint buffer_num,const ENUM_DRAW_TYPE type,const uint buff_source)
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and exit
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return;
     }
//--- Set the drawing style for the buffer
   this.m_buffers[buffer_num].SetBufferDrawType(type,buff_source);
  }
//+------------------------------------------------------------------+
//| Return the drawing style for the specified buffer                |
//+------------------------------------------------------------------+
ENUM_DRAW_TYPE CIndMSTF::BufferDrawType(const uint buffer_num)
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      //--- If the indicator has buffers, return the shift value of the very first one, otherwise 0
      return(this.BuffersTotal()>0 ? this.m_buffers[0].DrawType() : DRAW_NONE);
     }
//--- Return the drawing style of the requested buffer
   return this.m_buffers[buffer_num].DrawType();
  }
//+------------------------------------------------------------------+
//| Return number of corresponding buffer of the source indicator    |
//+------------------------------------------------------------------+
uint CIndMSTF::BufferFrom(const uint buffer_num)
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      //--- If the indicator has buffers, return the shift value of the very first one, otherwise 0
      return(this.BuffersTotal()>0 ? this.m_buffers[0].Shift() : 0);
     }
//--- Return the number of the corresponding buffer of the source indicator for the requested buffer
   return this.m_buffers[buffer_num].BufferFrom();
  }
//+------------------------------------------------------------------+
//| Copy data of the specified array of the specified buffer         |
//+------------------------------------------------------------------+
bool CIndMSTF::CopyArray(const uint buff_num,const uint array_num,const int to_copy,double &array[])
  {
   ::ResetLastError();
//--- Copy either the last two bars to 'array' or all available historical data from indicator's calculation part array to buffer array of indicator object
   int copied=0;
   if(to_copy==2)
     {
      switch(array_num)
        {
         case 0   :  case 1 : case 2 :
         case 3   :  copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(),  -this.m_buffers[buff_num].Shift(),to_copy,array);   break;
         case 4   :  copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom()+1,-this.m_buffers[buff_num].Shift(),to_copy,array);   break;
         default  :  break;
        }
     }
   else
     {
      switch(array_num)
        {
         case 0   :  copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(),  -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array0);          break;
         case 1   :  copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(),  -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array1);          break;
         case 2   :  copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(),  -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array2);          break;
         case 3   :  copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom(),  -this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].array3);          break;
         case 4   :  copied=::CopyBuffer(this.m_handle,this.m_buffers[buff_num].BufferFrom()+1,-this.m_buffers[buff_num].Shift(),to_copy,this.m_buffers[buff_num].color_indexes);   break;
         default  :  break;
        }
     }
//--- If copied successfully
   if(copied>0)
      return true;
//--- If not all data is copied
//--- If CopyBuffer returned -1, this means the start of historical data downloading
//--- print a message about this to the log
   if(copied==WRONG_VALUE)
      ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription());
//--- In any other case, not all data has been copied yet
//--- print a message about this to the log
   else
      ::PrintFormat("%s::%s: Not all data was copied. Data available: %lu, total copied: %ld",__FUNCTION__,this.Title(),this.m_rates_total,copied);
   return false;
  }
//+------------------------------------------------------------------+
//| Copy data of all arrays of the specified buffer                  |
//+------------------------------------------------------------------+
bool CIndMSTF::CopyArrays(const uint buff_num,const int to_copy)
  {
   bool res=true;
   double array[2];
   if(to_copy==2)
     {
      switch(this.BufferDrawType(buff_num))
        {
         //--- One buffer
         case DRAW_LINE             :
         case DRAW_HISTOGRAM        :
         case DRAW_ARROW            :
         case DRAW_SECTION          :
            res=this.CopyArray(buff_num,0,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1];
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0];
              }
            return res;
         //--- Two buffers
         case DRAW_HISTOGRAM2       :
         case DRAW_ZIGZAG           :
         case DRAW_FILLING          :
            res=this.CopyArray(buff_num,0,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1];
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,1,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1];
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0];
              }
            return res;
         //--- Four buffers
         case DRAW_BARS             :
         case DRAW_CANDLES          :
            res=this.CopyArray(buff_num,0,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1];
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,1,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1];
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,2,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-1]=array[1];
               this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,3,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-1]=array[1];
               this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-2]=array[0];
              }
            return res;
         //--- One buffer + color buffer
         case DRAW_COLOR_LINE       :
         case DRAW_COLOR_HISTOGRAM  :
         case DRAW_COLOR_ARROW      :
         case DRAW_COLOR_SECTION    :
            res=this.CopyArray(buff_num,0,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1];
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,4,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-1]=array[1];
               this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-2]=array[0];
              }
            return res;
         //--- Two buffers + color buffer
         case DRAW_COLOR_HISTOGRAM2 :
         case DRAW_COLOR_ZIGZAG     :
            res=this.CopyArray(buff_num,0,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1];
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,1,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1];
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,4,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-1]=array[1];
               this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-2]=array[0];
              }
            return res;
         //--- Four buffers + color buffer
         case DRAW_COLOR_BARS       :
         case DRAW_COLOR_CANDLES    :
            res=this.CopyArray(buff_num,0,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-1]=array[1];
               this.m_buffers[buff_num].array0[this.DataTotal(buff_num,0)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,1,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-1]=array[1];
               this.m_buffers[buff_num].array1[this.DataTotal(buff_num,1)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,2,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-1]=array[1];
               this.m_buffers[buff_num].array2[this.DataTotal(buff_num,2)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,3,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-1]=array[1];
               this.m_buffers[buff_num].array3[this.DataTotal(buff_num,3)-2]=array[0];
              }
            res &=this.CopyArray(buff_num,4,to_copy,array);
            if(res)
              {
               this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-1]=array[1];
               this.m_buffers[buff_num].color_indexes[this.DataTotal(buff_num,4)-2]=array[0];
              }
            return res;
         //---DRAW_NONE
         default:
           break;
        }
     }
   else
     {
      switch(this.BufferDrawType(buff_num))
        {
         //--- One buffer
         case DRAW_LINE             :
         case DRAW_HISTOGRAM        :
         case DRAW_ARROW            :
         case DRAW_SECTION          :
            return this.CopyArray(buff_num,0,to_copy,array);
         //--- Two buffers
         case DRAW_HISTOGRAM2       :
         case DRAW_ZIGZAG           :
         case DRAW_FILLING          :
            res  =this.CopyArray(buff_num,0,to_copy,array);
            res &=this.CopyArray(buff_num,1,to_copy,array);
            return res;
         //--- Four buffers
         case DRAW_BARS             :
         case DRAW_CANDLES          :
            res  =this.CopyArray(buff_num,0,to_copy,array);
            res &=this.CopyArray(buff_num,1,to_copy,array);
            res &=this.CopyArray(buff_num,2,to_copy,array);
            res &=this.CopyArray(buff_num,3,to_copy,array);
            return res;
         //--- One buffer + color buffer
         case DRAW_COLOR_LINE       :
         case DRAW_COLOR_HISTOGRAM  :
         case DRAW_COLOR_ARROW      :
         case DRAW_COLOR_SECTION    :
            res  =this.CopyArray(buff_num,0,to_copy,array);
            res &=this.CopyArray(buff_num,4,to_copy,array);
            return res;
         //--- Two buffers + color buffer
         case DRAW_COLOR_HISTOGRAM2 :
         case DRAW_COLOR_ZIGZAG     :
            res  =this.CopyArray(buff_num,0,to_copy,array);
            res &=this.CopyArray(buff_num,1,to_copy,array);
            res &=this.CopyArray(buff_num,4,to_copy,array);
            return res;
         //--- Four buffers + color buffer
         case DRAW_COLOR_BARS       :
         case DRAW_COLOR_CANDLES    :
            res  =this.CopyArray(buff_num,0,to_copy,array);
            res &=this.CopyArray(buff_num,1,to_copy,array);
            res &=this.CopyArray(buff_num,2,to_copy,array);
            res &=this.CopyArray(buff_num,3,to_copy,array);
            res &=this.CopyArray(buff_num,4,to_copy,array);
            return res;
         //---DRAW_NONE
         default:
           break;
        }
     }
   return false;
  }

Ahora, en el método de cálculo del indicador, en lugar de copiar arrays, se llamará al método que copiado de todos los arrays de los búferes de indicador, y se retornará un error tras el intento de copiar todos los arrays:

//+------------------------------------------------------------------+
//| Fill object buffers with data from the calculation part buffer   |
//+------------------------------------------------------------------+
bool CIndMSTF::Calculate(void)
  {
//--- Set the success flag to true, and the error type to no error
   this.m_success=true;
   this.m_type_err=ERR_TYPE_NO_ERROR;
//--- If the data is not yet synchronized with the trade server,
   if(!this.IsSynchronized())
     {
      //--- Log a message about non-synchronized data,
      ::PrintFormat("%s::%s: Waiting for data to sync...",__FUNCTION__,this.Title());
      //--- set the error type, add 'false' to the error flag and return 'false'
      this.m_type_err=ERR_TYPE_NO_SYNC;
      this.m_success=false;
      return false;
     }
//--- If the Calculated method returned -1, this means the start of data downloading
   if(this.Calculated()==WRONG_VALUE)
     {
      //--- Log a message about the start of data downloading,
      ::PrintFormat("%s::%s: Start downloading data by %s/%s. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_symbol,this.TimeframeDescription());
      //--- set the error type, add 'false' to the error flag and return 'false'
      this.m_type_err=ERR_TYPE_NO_DATA;
      this.m_success=false;
      return false;
     }
//--- If the Calculated method returned 0, this means that the indicator has not yet been calculated
   if(this.Calculated()==0)
     {
      //--- Log a message about waiting for the indicator to be calculated,
      ::PrintFormat("%s::%s: Waiting for a new tick and when the indicator will be calculated...",__FUNCTION__,this.Title());
      //--- set the error type, add 'false' to the error flag and return 'false'
      this.m_type_err=ERR_TYPE_NO_CALC;
      this.m_success=false;
      return false;
     }
//--- Get the number of data bars for the indicator symbol/period
   int bars=::Bars(this.m_symbol,this.m_timeframe);
//--- If the Bars function returned a zero value, which often happens on weekends, calculate the available number of bars
   if(bars==0)
     {
      //--- Get the date of the very first available bar in history for the symbol/period
      datetime firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_FIRSTDATE);
      //--- Get the date of the last (current) bar in history for the symbol/period
      datetime lastdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_LASTBAR_DATE);
      //--- Calculate the number of bars between the first and last dates of history
      int sec=::PeriodSeconds(this.m_timeframe);
      ulong date_bars=(((ulong)lastdate-(ulong)firstdate)/(sec>0 ? sec : 1))+1;
      //--- Write to the 'bars' variable the smaller value of the calculated number of bars and the maximum number of bars available in the terminal
      bars=(int)fmin(date_bars,::TerminalInfoInteger(TERMINAL_MAXBARS));
     }
//--- Write the resulting number of available bars to m_rates_total
   if(this.m_rates_total!=bars)
      this.m_rates_total=bars;
//--- If the number of available bars is received, and it is 2 or less,
   if(this.m_rates_total>=0 && this.m_rates_total<3)
     {
      //--- Log a message about the number of available bars being too small
      ::PrintFormat("%s::%s: Not enough data for calculation: %ld bars. Waiting for the next tick...",__FUNCTION__,this.Title(),this.m_rates_total);
      //--- set the error type, add 'false' to the error flag and return 'false'
      this.m_type_err=ERR_TYPE_NO_DATA;
      this.m_success=false;
      return false;
     }

//--- Calculate the number of bars required to calculate the indicator
//--- Either the entire available history, or 1 when a new bar opens, or 0 on the current tick
   this.m_limit=this.m_rates_total-this.m_prev_calculated;
   this.m_prev_calculated=this.Calculated();

//--- Declare an array of size 2 to receive data into it from the indicator's calculation part buffer
//--- We always get two bars: previous and current
   double array[2];
//--- Get the number of indicator buffers
   int total=(int)this.BuffersTotal();
//--- If the calculated m_limit is greater than 1, it means either the first launch or changes in historical data
//--- In this case, a complete recalculation of the indicator is necessary
   if(this.m_limit>1)
     {
      //--- In a loop over the number of indicator buffers
      for(int i=0;i<total;i++)
        {
         //--- resize the indicator buffer array and initialize it to the "empty" value set for this buffer
         this.BufferInitialize(i,this.m_rates_total);
         //--- Determine the amount of data to copy
         int to_copy=(this.m_prev_calculated>this.m_rates_total ? this.m_rates_total : this.m_prev_calculated);
         
         //--- If not all arrays were successfully copied, write false to m_success
         if(!this.CopyArrays(i,to_copy))
            this.m_success &=false;
        }
      //--- If there are errors after the error, return false
      if(!this.m_success)
        {
         this.m_type_err=ERR_TYPE_NO_DATA;
         return false;
        }
      //--- Everything is successful - return true
      this.m_type_err=ERR_TYPE_NO_ERROR;
      this.m_success=true;
      return true;
     }
//--- If calculated m_limit is less than or equal to 1, this means either opening of a new bar (m_limit==1) or current tick (m_limit==0)
//--- In this case, it is necessary to calculate two bars - the first and the current
   if(this.m_limit<=1)
     {
      //--- In a loop over the number of indicator buffers
      for(int i=0;i<total;i++)
        {
         //--- If this is the opening of a new bar and resizing the indicator buffer failed,
         if(this.m_limit==1 && !this.BufferResize(i,this.m_rates_total))
           {
            //--- add 'false' to the m_success variable and return 'false'
            //--- Here, an error message will be printed to log from the BufferResize method
            this.m_success=false;
            return false;
           }
         //--- If failed to copy two bars from the indicator's calculation part buffer,
         ::ResetLastError();
         if(!this.CopyArrays(i,2))
           {
            //--- report this via the log, add 'false' to the m_success variable and return 'false'
            ::PrintFormat("%s::%s: CopyBuffer(%lu) failed. Error %lu",__FUNCTION__,this.Title(),i,::GetLastError());
            this.m_success &=false;
           }
        }
      //--- If there are errors after the error, return false
      if(!this.m_success)
        {
         this.m_type_err=ERR_TYPE_NO_DATA;
         return false;
        }    
      //--- Success
      this.m_type_err=ERR_TYPE_NO_ERROR;
      this.m_success=true;
      return true;
     }
//--- Undefined 'limit' option - return 'false'
   return false;
  }

Para copiar los datos del búfer de color de la parte de cálculo del indicador al búfer de la parte de dibujado, se utilizará un método similar al método de copiado del búfer monocolor:

//+------------------------------------------------------------------+
//| Fill the plot array and the color index array                    |
//|  passed to the method with data from the class buffer            |
//+------------------------------------------------------------------+
bool CIndMSTF::DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[])
  {
//--- Set the success flag
   this.m_success=true;
//--- Get the indexing direction of the buffer array passed to the method and,
//--- if non-timeseries indexing, set timeseries indexing
   bool as_series_plot=::ArrayGetAsSeries(plot_buffer);
   if(!as_series_plot)
      ::ArraySetAsSeries(plot_buffer,true);
   bool as_series_color=::ArrayGetAsSeries(color_buffer);
   if(!as_series_color)
      ::ArraySetAsSeries(color_buffer,true);
//--- Set the symbol name and timeframe value passed to the method
   string symbol=(symbol_to=="" || symbol_to==NULL ? ::Symbol() : symbol_to);
   ENUM_TIMEFRAMES timeframe=(timeframe_to==PERIOD_CURRENT ? ::Period() : timeframe_to);
   datetime array[2];
//--- If this is the first launch or history changes, initialize the buffer array passed to the method
   if(limit>1 && this.m_limit>1)
     {
      ::PrintFormat("%s::%s First start, or historical data has been changed. Initialize Buffer(%lu)",__FUNCTION__,this.Title(),buffer_num);
      ::ArrayInitialize(plot_buffer,this.BufferInitValue(buffer_num));
      ::ArrayInitialize(color_buffer,this.BufferInitColorIndex(buffer_num));
     }
//--- Set the value of the loop counter (no more than the maximum number of bars in the terminal on the chart)
   int count=(limit<=1 ? 2 : ::fmin(::TerminalInfoInteger(TERMINAL_MAXBARS),limit));
//--- In a loop from the zero bar to the value of the loop counter
   for(int i=0;i<count;i++)
     {
      //--- If the chart timeframe matches the class object timeframe, fill the buffer directly from the class object array
      if(timeframe==::Period() && this.m_timeframe==::Period())
        {
         plot_buffer[i]=this.GetData(buffer_num,array_num,i);
         color_buffer[i]=this.GetColorData(buffer_num,i);
        }
      //--- Otherwise, if the chart timeframe is not equal to the timeframe of the class object
      else
        {
         //--- Find out which time of this class the bar of the current chart timeframe, corresponding to the loop index, belongs to
         ::ResetLastError();
         if(::CopyTime(symbol,timeframe,i,2,array)!=2)
           {
            //--- If there is no data in the terminal, move on
            if(::GetLastError()==4401)
               continue;
            //--- Error in obtaining existing data - return false
            this.m_success &=false;
            return false;
           }
         //--- Using time of bar of current chart timeframe, find corresponding index of bar of class object's chart period
         ::ResetLastError();
         int bar=::iBarShift(this.m_symbol,this.m_timeframe,array[0]);
         if(bar==WRONG_VALUE)
           {
            this.m_success &=false;
            continue;
           }
         //--- If this is historical data (not the first or zero bar) -
         //--- in the indicator buffer at the loop index, write the value obtained from the calculation part buffer
         if(i>1)
           {
            plot_buffer[i]=this.GetData(buffer_num,array_num,bar);
            color_buffer[i]=this.GetColorData(buffer_num,bar);
           }
         //--- If this is the current (zero) or previous (first) bar
         else
           {
            //--- Get the time of bars 0 and 1 by symbol/timeframe of the class object
            if(::CopyTime(this.m_symbol,this.m_timeframe,0,2,array)!=2)
              {
               this.m_success &=false;
               return false;
              }
            //--- Using time, get indexes of current and previous bars on the chart whose symbol/period was passed to method
            int bar0=::iBarShift(symbol,timeframe,array[1]);
            int bar1=::iBarShift(symbol,timeframe,array[0]);
            if(bar0==WRONG_VALUE || bar1==WRONG_VALUE)
              {
               this.m_success &=false;
               return false;
              }
            //--- If the chart timeframe is lower than the timeframe of the class object,
            if(timeframe<this.m_timeframe)
              {
               //--- in a loop from bar with smaller time to current chart bar, fill the buffer with data from the last 2 cells of the indicator buffer array
               for(int j=bar1;j>=0;j--)
                 {
                  plot_buffer[j]=this.GetData(buffer_num,array_num,(j>bar0 ? 1 : 0));
                  color_buffer[j]=this.GetColorData(buffer_num,(j>bar0 ? 1 : 0));
                 }
              }
            //--- If the chart timeframe is higher than the timeframe of the class object,
            else
              {
               //--- Get the time of the current and previous bars by symbol/timeframe of the current chart
               if(::CopyTime(symbol,timeframe,0,2,array)!=2)
                 {
                  this.m_success &=false;
                  return false;
                 }
               //--- Using time, get indexes of bars in indicator's calculation part buffer, corresponding to time of current and previous bars on the chart
               int bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[1]);
               int bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]);
               //--- Write into indicator buffer, at indexes 1 and 0, values from corresponding indexes of calculation part buffer
               plot_buffer[1]=this.GetData(buffer_num,array_num,bar1);
               plot_buffer[0]=this.GetData(buffer_num,array_num,bar0);
               color_buffer[1]=this.GetColorData(buffer_num,bar1);
               color_buffer[0]=this.GetColorData(buffer_num,bar0);
              } 
           }
        }
     }
//--- Set initial indexing of the buffer array passed to the method
   ::ArraySetAsSeries(plot_buffer,as_series_plot);
   ::ArraySetAsSeries(color_buffer,as_series_color);
//--- Successful
   return true;
  }

Aquí todo es exactamente igual que en el método de copiado de datos del búfer monocolor, solo que el método obtendrá adicionalmente un array de índices de color de la parte de dibujado, en la que deberemos copiar los datos del array correspondiente de la parte de cálculo del indicador. Pues bien, el copiado se realizará para los arrays: para el array de datos y para el array de colores.

Todos los métodos que devuelven propiedades o datos de un búfer dado especificarán ahora también el índice del array requerido.

//+------------------------------------------------------------------+
//| Fills the passed plot array with data from the class buffer      |
//+------------------------------------------------------------------+
bool CIndMSTF::DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int limit,double &buffer[])
  {
//--- Set the success flag
   this.m_success=true;
//--- Get the indexing direction of the buffer array passed to the method and,
//--- if non-timeseries indexing, set timeseries indexing
   bool as_series=::ArrayGetAsSeries(buffer);
   if(!as_series)
      ::ArraySetAsSeries(buffer,true);
//--- Set the symbol name and timeframe value passed to the method
   string symbol=(symbol_to=="" || symbol_to==NULL ? ::Symbol() : symbol_to);
   ENUM_TIMEFRAMES timeframe=(timeframe_to==PERIOD_CURRENT ? ::Period() : timeframe_to);
   datetime array[2];
//--- If this is the first launch or history changes, initialize the buffer array passed to the method
   if(limit>1 && this.m_limit>1)
     {
      ::PrintFormat("%s::%s First start, or historical data has been changed. Initialize Buffer(%lu)",__FUNCTION__,this.Title(),buffer_num);
      ::ArrayInitialize(buffer,this.BufferInitValue(buffer_num));
     }
//--- Set the value of the loop counter (no more than the maximum number of bars in the terminal on the chart)
   int count=(limit<=1 ? 2 : ::fmin(::TerminalInfoInteger(TERMINAL_MAXBARS),limit));
//--- In a loop from the zero bar to the value of the loop counter
   for(int i=0;i<count;i++)
     {
      //--- If the chart timeframe matches the class object timeframe, fill the buffer directly from the class object array
      if(timeframe==::Period() && this.m_timeframe==::Period())
         buffer[i]=this.GetData(buffer_num,array_num,i);
      //--- Otherwise, if the chart timeframe is not equal to the timeframe of the class object
      else
        {
         //--- Find out which time of this class the bar of the current chart timeframe, corresponding to the loop index, belongs to
         ::ResetLastError();
         if(::CopyTime(symbol,timeframe,i,2,array)!=2)
           {
            //--- If there is no data in the terminal, move on
            if(::GetLastError()==4401)
               continue;
            //--- Error in obtaining existing data - return false
            this.m_success &=false;
            return false;
           }
         //--- Using time of bar of current chart timeframe, find corresponding index of bar of class object's chart period
         ::ResetLastError();
         int bar=::iBarShift(this.m_symbol,this.m_timeframe,array[0]);
         if(bar==WRONG_VALUE)
           {
            this.m_success &=false;
            continue;
           }
         //--- If this is historical data (not the first or zero bar) -
         //--- in the indicator buffer at the loop index, write the value obtained from the calculation part buffer
         if(i>1)
            buffer[i]=this.GetData(buffer_num,array_num,bar);
         //--- If this is the current (zero) or previous (first) bar
         else
           {
            //--- Get the time of bars 0 and 1 by symbol/timeframe of the class object
            if(::CopyTime(this.m_symbol,this.m_timeframe,0,2,array)!=2)
              {
               this.m_success &=false;
               return false;
              }
            //--- Using time, get indexes of current and previous bars on the chart whose symbol/period was passed to method
            int bar0=::iBarShift(symbol,timeframe,array[1]);
            int bar1=::iBarShift(symbol,timeframe,array[0]);
            if(bar0==WRONG_VALUE || bar1==WRONG_VALUE)
              {
               this.m_success &=false;
               return false;
              }
            //--- If the chart timeframe is lower than the timeframe of the class object,
            if(timeframe<this.m_timeframe)
              {
               //--- in a loop from bar with smaller time to current chart bar, fill the buffer with data from the last 2 cells of the indicator buffer array
               for(int j=bar1;j>=0;j--)
                  buffer[j]=this.GetData(buffer_num,array_num,(j>bar0 ? 1 : 0));
              }
            //--- If the chart timeframe is higher than the timeframe of the class object,
            else
              {
               //--- Get the time of the current and previous bars by symbol/timeframe of the current chart
               if(::CopyTime(symbol,timeframe,0,2,array)!=2)
                 {
                  this.m_success &=false;
                  return false;
                 }
               //--- Using time, get indexes of bars in indicator's calculation part buffer, corresponding to time of current and previous bars on the chart
               int bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[1]);
               int bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]);
               //--- Write into indicator buffer, at indexes 1 and 0, values from corresponding indexes of calculation part buffer
               buffer[1]=this.GetData(buffer_num,array_num,bar1);
               buffer[0]=this.GetData(buffer_num,array_num,bar0);
              } 
           }
        }
     }
//--- Set initial indexing of the buffer array passed to the method
   ::ArraySetAsSeries(buffer,as_series);
//--- Successful
   return true;
  }

//+------------------------------------------------------------------+
//| Return the data of the specified buffer as is                    |
//+------------------------------------------------------------------+
double CIndMSTF::GetData(const uint buffer_num,const uint array_num,const int index) const
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      //--- If the indicator has buffers, return "empty" value of the first one, otherwise EMPTY_VALUE
      return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE);
     }
//--- If an incorrect index is specified, return the "empty" value of the specified buffer
   if(index<0 || index>(int)this.DataTotal(buffer_num,array_num)-1)
      return this.BufferInitValue(buffer_num);
//--- Calculate the real index in the buffer array and return the value at this index
   int n=int(this.DataTotal(buffer_num,array_num)-1-index);
   switch(array_num)
     {
      case 0 : return this.m_buffers[buffer_num].array0[n];
      case 1 : return this.m_buffers[buffer_num].array1[n];
      case 2 : return this.m_buffers[buffer_num].array2[n];
      case 3 : return this.m_buffers[buffer_num].array3[n];
      case 4 : return this.m_buffers[buffer_num].color_indexes[n];
      default: break;
     }
   return EMPTY_VALUE;
  }
//+-------------------------------------------------------------------+
//| Returns data from specified buffer for specified symbol/timeframe |
//+-------------------------------------------------------------------+
double CIndMSTF::GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const uint array_num,const int index) const
  {
//--- If current symbol/period of the chart is specified
   if(timeframe_to==::Period() && this.m_timeframe==::Period() && symbol_to==::Symbol() && this.m_symbol==::Symbol())
      return this.GetData(buffer_num,array_num,index);
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to log
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      //--- If the indicator has buffers, return "empty" value of the first one, otherwise EMPTY_VALUE
      return(this.BuffersTotal()>0 ? this.BufferInitValue(0) : EMPTY_VALUE);
     }
//--- Find out which time of this class the current chart timeframe's bar, corresponding to the loop index, belongs to
   datetime array[];
   if(::CopyTime(symbol_to,timeframe_to,index,1,array)!=1)
      return this.BufferInitValue(buffer_num);
//--- Using time of bar of current chart timeframe, find corresponding bar index of bar this class chart period
   int bar=iBarShift(this.m_symbol,this.m_timeframe,array[0]);
//--- If the bar is not found, return the "empty" value set for the buffer
   if(bar==WRONG_VALUE)
      return this.BufferInitValue(buffer_num);
//--- Return value from the indicator object buffer at the found index
   return this.GetData(buffer_num,array_num,bar);
  }

//+------------------------------------------------------------------+
//| Return the state of the indicator line as is                     |
//+------------------------------------------------------------------+
ENUM_LINE_STATE CIndMSTF::BufferLineState(const uint buffer_num,const uint array_num,const int index) const
  {
//--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
   const double value0=this.GetData(buffer_num,array_num,index);
   const double value1=this.GetData(buffer_num,array_num,index+1);
   const double value2=this.GetData(buffer_num,array_num,index+2);
//--- If at least one of the values could not be obtained, return an undefined value 
   if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
      return LINE_STATE_NONE;
//--- Line upward reversal (value2>value1 && value0>value1)
   if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0)
      return LINE_STATE_TURN_UP;
//--- Line upward direction (value2<=value1 && value0>value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0)
      return LINE_STATE_UP;
//--- Line upward stop (value2<=value1 && value0==value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0)
      return LINE_STATE_STOP_UP;
//--- Line downward reversal (value2<value1 && value0<value1)
   if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0)
      return LINE_STATE_TURN_DOWN;
//--- Line downward direction (value2>=value1 && value0<value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0)
      return LINE_STATE_DOWN;
//--- Line downward stop (value2>=value1 && value0==value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0)
      return LINE_STATE_STOP_DOWN;
//--- Undefined state
   return LINE_STATE_NONE;
  }
//+------------------------------------------------------------------+
//| Return indicator line state for the specific symbol/period       |
//+------------------------------------------------------------------+
ENUM_LINE_STATE CIndMSTF::BufferLineState(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const uint buffer_num,const uint array_num,const int index) const
  {
//--- Determine the chart symbol/period passed to the method
   string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from);
   ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from);
//--- If we get data from symbol/period equal to current chart, return state from the buffer "as is"
   if(symbol==::Symbol() && symbol==this.m_symbol && timeframe==::Period() && timeframe==this.m_timeframe)
      return this.BufferLineState(buffer_num,array_num,index);
//--- Declare variables to search for the required bars on the current chart
   datetime array[1];
   int      bar0=WRONG_VALUE;
   int      bar1=WRONG_VALUE;
   int      bar2=WRONG_VALUE;

//--- Get the time of the first bar on the chart
   ::ResetLastError();
   if(::CopyTime(symbol,timeframe,index,1,array)!=1)
     {
      ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index,::GetLastError());
      return LINE_STATE_NONE;
     }
//--- Get index of the first bar in indicator object buffer based on bar opening time on the chart
   bar0=::iBarShift(this.m_symbol,this.m_timeframe,array[0]);
   if(bar0==WRONG_VALUE)
     {
      ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError());
      return LINE_STATE_NONE;
     }
//--- Get the time of the second bar on the chart
   ::ResetLastError();
   if(::CopyTime(symbol,timeframe,index+1,1,array)!=1)
     {
      ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+1,::GetLastError());
      return LINE_STATE_NONE;
     }
//--- Get index of the second bar in indicator object buffer based on bar opening time on the chart
   bar1=::iBarShift(this.m_symbol,this.m_timeframe,array[0]);
   if(bar1==WRONG_VALUE)
     {
      ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError());
      return LINE_STATE_NONE;
     }
//--- Get the time of the third bar on the chart
   ::ResetLastError();
   if(::CopyTime(symbol,timeframe,index+2,1,array)!=1)
     {
      ::PrintFormat("%s: CopyTime for %s/%s, bar %ld failed. Error %lu",__FUNCTION__,symbol,::StringSubstr(::EnumToString(timeframe),7),index+2,::GetLastError());
      return LINE_STATE_NONE;
     }
//--- Get index of the third bar in indicator object buffer based on bar opening time on the chart
   bar2=::iBarShift(this.m_symbol,this.m_timeframe,array[0]);
   if(bar2==WRONG_VALUE)
     {
      ::PrintFormat("%s: iBarShift for %s/%s, time %s failed. Error %lu",__FUNCTION__,this.m_symbol,this.TimeframeDescription(),string(array[0]),::GetLastError());
      return LINE_STATE_NONE;
     }
     
//--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index
   const double value0=this.GetData(buffer_num,array_num,bar0);
   const double value1=this.GetData(buffer_num,array_num,bar1);
   const double value2=this.GetData(buffer_num,array_num,bar2);
//--- If at least one of the values could not be obtained, return an undefined value 
   if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE)
      return LINE_STATE_NONE;
//--- Line upward reversal (value2>value1 && value0>value1)
   if(::NormalizeDouble(value2-value1,this.m_digits)>0 && ::NormalizeDouble(value0-value1,this.m_digits)>0)
      return LINE_STATE_TURN_UP;
//--- Line upward direction (value2<=value1 && value0>value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)>0)
      return LINE_STATE_UP;
//--- Line upward stop (value2<=value1 && value0==value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)<=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0)
      return LINE_STATE_STOP_UP;
//--- Line downward reversal (value2<value1 && value0<value1)
   if(::NormalizeDouble(value2-value1,this.m_digits)<0 && ::NormalizeDouble(value0-value1,this.m_digits)<0)
      return LINE_STATE_TURN_DOWN;
//--- Line downward direction (value2>=value1 && value0<value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)<0)
      return LINE_STATE_DOWN;
//--- Line downward stop (value2>=value1 && value0==value1)
   else if(::NormalizeDouble(value2-value1,this.m_digits)>=0 && ::NormalizeDouble(value0-value1,this.m_digits)==0)
      return LINE_STATE_STOP_DOWN;
//--- Undefined state
   return LINE_STATE_NONE;
  }
//+------------------------------------------------------------------+
//| Return the state of the line relative to the specified level     |
//+------------------------------------------------------------------+
ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE)
  {
//--- Get the values of the indicator line with the shift (0,1) relative to the passed index
   const double value0=this.GetData(buffer_num,array_num,index);
   const double value1=this.GetData(buffer_num,array_num,index+1);
//--- If at least one of the values could not be obtained, return an undefined value 
   if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
      return LINE_STATE_NONE;
//--- Define the second level to compare
   double level=(level1==EMPTY_VALUE ? level0 : level1);
//--- The line is below the level (value1<level && value0<level0)
   if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0)
      return LINE_STATE_BELOW;
//--- The line is above the level (value1>level && value0>level0)
   if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0)
      return LINE_STATE_ABOVE;
//--- The line crossed the level upwards (value1<=level && value0>level0)
   if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0)
      return LINE_STATE_CROSS_UP;
//--- The line crossed the level downwards (value1>=level && value0<level0)
   if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0)
      return LINE_STATE_CROSS_DOWN;
//--- The line touched the level from below (value1<level0 && value0==level0)
   if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0)
      return LINE_STATE_TOUCH_BELOW;
//--- The line touched the level from above (value1>level0 && value0==level0)
   if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0)
      return LINE_STATE_TOUCH_BELOW;
//--- Line is equal to the level value (value1==level0 && value0==level0)
   if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0)
      return LINE_STATE_EQUALS;
//--- Undefined state
   return LINE_STATE_NONE;
  }
//+------------------------------------------------------------------+
//| Return the state of the line relative to the specified level     |
//| on the specified chart symbol/period                             |
//+------------------------------------------------------------------+
ENUM_LINE_STATE CIndMSTF::BufferLineStateRelative(const string symbol_from,const ENUM_TIMEFRAMES timeframes_from,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE)
  {
//--- Determine the chart symbol/period passed to the method
   string symbol=(symbol_from=="" || symbol_from==NULL ? ::Symbol() : symbol_from);
   ENUM_TIMEFRAMES timeframe=(timeframes_from==PERIOD_CURRENT ? ::Period() : timeframes_from);
//--- Get the values of the indicator line with the shift (0,1) relative to the passed index
   const double value0=this.GetDataTo(symbol,timeframe,buffer_num,array_num,index);
   const double value1=this.GetDataTo(symbol,timeframe,buffer_num,array_num,index+1);
//--- If at least one of the values could not be obtained, return an undefined value 
   if(value0==EMPTY_VALUE || value1==EMPTY_VALUE)
      return LINE_STATE_NONE;
//--- Define the second level to compare
   double level=(level1==EMPTY_VALUE ? level0 : level1);
//--- The line is below the level (value1<level && value0<level0)
   if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)<0)
      return LINE_STATE_BELOW;
//--- The line is above the level (value1>level && value0>level0)
   if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)>0)
      return LINE_STATE_ABOVE;
//--- The line crossed the level upwards (value1<=level && value0>level0)
   if(::NormalizeDouble(value1-level,this.m_digits)<=0 && ::NormalizeDouble(value0-level0,this.m_digits)>0)
      return LINE_STATE_CROSS_UP;
//--- The line crossed the level downwards (value1>=level && value0<level0)
   if(::NormalizeDouble(value1-level,this.m_digits)>=0 && ::NormalizeDouble(value0-level0,this.m_digits)<0)
      return LINE_STATE_CROSS_DOWN;
//--- The line touched the level from below (value1<level0 && value0==level0)
   if(::NormalizeDouble(value1-level,this.m_digits)<0 && ::NormalizeDouble(value0-level0,this.m_digits)==0)
      return LINE_STATE_TOUCH_BELOW;
//--- The line touched the level from above (value1>level0 && value0==level0)
   if(::NormalizeDouble(value1-level,this.m_digits)>0 && ::NormalizeDouble(value0-level0,this.m_digits)==0)
      return LINE_STATE_TOUCH_BELOW;
//--- Line is equal to the level value (value1==level0 && value0==level0)
   if(::NormalizeDouble(value1-level,this.m_digits)==0 && ::NormalizeDouble(value0-level0,this.m_digits)==0)
      return LINE_STATE_EQUALS;
//--- Undefined state
   return LINE_STATE_NONE;
  }

Métodos que retornan los datos del búfer de color a partir de un array de índices de color:

//+------------------------------------------------------------------+
//| Return data of the specified buffer of color indexes as is       |
//+------------------------------------------------------------------+
double CIndMSTF::GetColorData(const uint buffer_num,const int index) const
  {
//--- Validate the buffer number passed to method and, if number is incorrect, print a message to log and return 0
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return 0;
     }
//--- If this is not a color buffer, report this to the log and return 0
   if(!this.IsColoredBuffer(buffer_num))
     {
      ::PrintFormat("%s: Buffer %lu is not a color buffer",__FUNCTION__,buffer_num);
      return 0;
     }
//--- If an incorrect index is specified, return "empty" value of the specified color buffer
   if(index<0 || index>(int)this.DataTotal(buffer_num,4)-1)
      return this.BufferInitColorIndex(buffer_num);
//--- Calculate the real index in the color buffer array and return the value at this index
   int n=int(this.DataTotal(buffer_num,4)-1-index);
   return this.m_buffers[buffer_num].color_indexes[n];
  }
//+------------------------------------------------------------------+
//| Return data of the specified color index buffer                  |
//| for the specified symbol/timeframe                               |
//+------------------------------------------------------------------+
double CIndMSTF::GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const uint buffer_num,const int index) const
  {
//--- If current symbol/period of the chart is specified
   if(timeframe_to==::Period() && this.m_timeframe==::Period() && symbol_to==::Symbol() && this.m_symbol==::Symbol())
      return this.GetColorData(buffer_num,index);
//--- Validate the buffer number passed to method and, if number is incorrect, print a message to log and return 0
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return 0;
     }
//--- If this is not a color buffer, report this to the log and return 0
   if(!this.IsColoredBuffer(buffer_num))
     {
      ::PrintFormat("%s: Buffer %lu is not a color buffer",__FUNCTION__,buffer_num);
      return 0;
     }
//--- Find out which time of this class the current chart timeframe's bar, corresponding to the loop index, belongs to
   datetime array[];
   if(::CopyTime(symbol_to,timeframe_to,index,1,array)!=1)
      return this.BufferInitColorIndex(buffer_num);
//--- Using time of bar of current chart timeframe, find corresponding bar index of bar this class chart period
   int bar=iBarShift(this.m_symbol,this.m_timeframe,array[0]);
//--- If the bar is not found, return "empty" value set for the color buffer
   if(bar==WRONG_VALUE)
      return this.BufferInitColorIndex(buffer_num);
//--- Return a value from the color buffer of the indicator object at the found index
   return this.GetColorData(buffer_num,bar);
//--- Calculate the real index in the color buffer array and return the value at this index
   int n=int(this.DataTotal(buffer_num,4)-1-bar);
   return this.m_buffers[buffer_num].color_indexes[n];
  }

Los métodos que acceden a cualquier dato del búfer ahora lo harán especificando el array del búfer requerido:

//+------------------------------------------------------------------+
//| Disable timeseries indexing of buffer arrays                     |
//+------------------------------------------------------------------+
void CIndMSTF::SetAsSeriesOff(void)
  {
//--- In a loop through all indicator buffers, disable the array as timeseries flag
   for(int i=0;i<(int)this.BuffersTotal();i++)
     {
      ::ArraySetAsSeries(this.m_buffers[i].array0,false);
      ::ArraySetAsSeries(this.m_buffers[i].array1,false);
      ::ArraySetAsSeries(this.m_buffers[i].array2,false);
      ::ArraySetAsSeries(this.m_buffers[i].array3,false);
      ::ArraySetAsSeries(this.m_buffers[i].color_indexes,false);
     }
  }
//+------------------------------------------------------------------+
//| Returns the timeseries flag of the given buffer                  |
//+------------------------------------------------------------------+
bool CIndMSTF::IsSeries(const uint buffer_num,const uint array_num) const
  {
//--- Validate the buffer number passed to the method and, if the number is incorrect, print a message to the log and return 'false'
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return false;
     }
//--- Return the timeseries flag of the array of the specified buffer
   switch(array_num)
     {
      case 0 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array0);
      case 1 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array1);
      case 2 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array2);
      case 3 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].array3);
      case 4 : return (bool)::ArrayGetAsSeries(this.m_buffers[buffer_num].color_indexes);
      default: break;
     }
   return false;
  }
//+------------------------------------------------------------------+
//| Returns the amount of data in the specified buffer               |
//+------------------------------------------------------------------+
uint CIndMSTF::DataTotal(const uint buffer_num,const uint array_num) const
  {
//--- Validate the buffer number passed to method and, if number is incorrect, print a message to log and return zero
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return 0;
     }
//--- Return the array size of the specified buffer
   switch(array_num)
     {
      case 0 : return this.m_buffers[buffer_num].array0.Size();
      case 1 : return this.m_buffers[buffer_num].array1.Size();
      case 2 : return this.m_buffers[buffer_num].array2.Size();
      case 3 : return this.m_buffers[buffer_num].array3.Size();
      case 4 : return this.m_buffers[buffer_num].color_indexes.Size();
      default: break;
     }
   return 0;
  }

Método que retorna el número de colores establecidos en el búfer:

//+------------------------------------------------------------------+
//| Return the number of colors set for the buffer                   |
//+------------------------------------------------------------------+
uint CIndMSTF::ColorsTotal(const uint buffer_num) const
  {
//--- Validate the buffer number passed to method and, if number is incorrect, print a message to log and return zero
   if(buffer_num>this.BuffersTotal()-1)
     {
      string buff_limit=(this.BuffersTotal()==1 ? "0" : "0 - "+string(this.BuffersTotal()-1));
      ::PrintFormat("%s: Invalid buffer number passed (%lu). Value must be %s",__FUNCTION__,buffer_num,buff_limit);
      return 0;
     }
//--- Return the size of the color array of the specified buffer
   return this.m_buffers[buffer_num].clrs.Size();
  }


También se han finalizado las clases de indicadores técnicos estándar. Ahora el constructor de la clase especificará los estilos de dibujado de cada búfer de indicador y el índice del array fuente sobre el que se construye el búfer de la clase de indicador:

//+------------------------------------------------------------------+
//| Accelerator Oscillator indicator class                           |
//+------------------------------------------------------------------+
class CIndAC : public CIndMSTF
  {
public:
//--- Constructor
   CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AC,1,symbol,timeframe)
     {
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=(current ? "" : StringFormat("(%s)",symbol_period));
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("AC");
      this.SetDescription("Accelerator Oscillator");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_WILLIAMS;
      this.m_digits=::Digits()+2;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Set drawing style for buffer 0 and number of the calculation part data buffer
      this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0);
      //--- Set two default colors for the color buffer 0
      this.SetBufferColorToIndex(0,0,clrGreen);
      this.SetBufferColorToIndex(0,1,clrRed);
      //--- Set the default initializing color index
      this.SetBufferInitColorIndex(0,0);
     }
  };

En el caso de los búferes de color, también se establecerán los colores de línea por defecto como en el indicador estándar correspondiente y el índice del color con el que se inicializará inicialmente el búfer.

Listado de clases de otros indicadores estándar (algunas clases de indicador aún no están finalizadas):

//+------------------------------------------------------------------+
//| Accumulation/Distribution indicator class                        |
//+------------------------------------------------------------------+
class CIndAD : public CIndMSTF
  {
public:
//--- Constructor
   CIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe,
          const ENUM_APPLIED_VOLUME applied_volume // used volume
         ) : CIndMSTF(IND_AD,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=applied_volume;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=(current ? "" : StringFormat("(%s)",symbol_period));
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("A/D");
      this.SetDescription("Accumulation/Distribution");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_VOLUME;
      this.m_digits=0;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLightSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Average Directional Movement Index indicator class               |
//+------------------------------------------------------------------+
class CIndADX : public CIndMSTF
  {
public:
//--- Constructor
   CIndADX(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int adx_period                    // averaging period
          ) : CIndMSTF(IND_ADX,3,symbol,timeframe)
     {
      // Buffer indexes: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("ADX");
      this.SetDescription("Average Directional Movement Index");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=2;
      //--- write descriptions of MAIN_LINE, PLUSDI_LINE and MINUSDI_LINE line buffers
      this.SetBufferDescription(MAIN_LINE,this.m_title);
      this.SetBufferDescription(PLUSDI_LINE,"+DI");
      this.SetBufferDescription(MINUSDI_LINE,"-DI");
      
      //--- Set drawing style for buffers 0, 1, 2 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,PLUSDI_LINE);
      this.SetBufferDrawType(2,DRAW_LINE,MINUSDI_LINE);
      
      //--- Set default colors for buffers 0, 1 and 2
      this.SetBufferColorToIndex(MAIN_LINE,0,clrLightSeaGreen);
      this.SetBufferColorToIndex(PLUSDI_LINE,0,clrYellowGreen);
      this.SetBufferColorToIndex(MINUSDI_LINE,0,clrWheat);
     }
  };
//+------------------------------------------------------------------+
//| Average Directional Movement Index Wilder indicator class        |
//+------------------------------------------------------------------+
class CIndADXW : public CIndMSTF
  {
public:
//--- Constructor
   CIndADXW(const string symbol,const ENUM_TIMEFRAMES timeframe,
            const int adx_period                      // averaging period
           ) : CIndMSTF(IND_ADXW,3,symbol,timeframe)
     {
      // Buffer indexes: 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(adx_period<1 ? 14 : adx_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),adx_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("ADX Wilder");
      this.SetDescription("Average Directional Movement Index Wilder");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=2;
      //--- write descriptions of MAIN_LINE, PLUSDI_LINE and MINUSDI_LINE line buffers
      this.SetBufferDescription(MAIN_LINE,this.m_title);
      this.SetBufferDescription(PLUSDI_LINE,"+DI");
      this.SetBufferDescription(MINUSDI_LINE,"-DI");
      
      //--- Set drawing style for buffers 0, 1, 2 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,PLUSDI_LINE);
      this.SetBufferDrawType(2,DRAW_LINE,MINUSDI_LINE);
      
      //--- Set default colors for buffers 0, 1 and 2
      this.SetBufferColorToIndex(MAIN_LINE,0,clrLightSeaGreen);
      this.SetBufferColorToIndex(PLUSDI_LINE,0,clrYellowGreen);
      this.SetBufferColorToIndex(MINUSDI_LINE,0,clrWheat);
     }
  };
//+------------------------------------------------------------------+
//| Alligator indicator class                                        |
//+------------------------------------------------------------------+
class CIndAlligator : public CIndMSTF
  {
public:
//--- Constructor
   CIndAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe,
                 const int jaw_period,                   // period for calculating jaws
                 const int jaw_shift,                    // horizontal shift of jaws
                 const int teeth_period,                 // period for calculating teeth
                 const int teeth_shift,                  // horizontal shift of teeth
                 const int lips_period,                  // period for calculating lips
                 const int lips_shift,                   // horizontal shift of lips
                 const ENUM_MA_METHOD ma_method,         // smoothing type
                 const ENUM_APPLIED_PRICE applied_price  // price type or handle
                ) : CIndMSTF(IND_ALLIGATOR,3,symbol,timeframe)
     {
      // Buffer indexes: 0 - GATORJAW_LINE, 1 - GATORTEETH_LINE, 2 - GATORLIPS_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,8)==8)
        {
         ::ZeroMemory(this.m_param);
         //--- period for jaw line calculation
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period);
         //--- horizontal shift of the jaw line
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=jaw_shift;
         //--- period for teeth line calculation
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period);
         //--- horizontal shift of teeth line
         this.m_param[3].type=TYPE_INT;
         this.m_param[3].integer_value=teeth_shift;
         //--- period for lip line calculation
         this.m_param[4].type=TYPE_UINT;
         this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period);
         //--- horizontal shift of lips line
         this.m_param[5].type=TYPE_INT;
         this.m_param[5].integer_value=lips_shift;
         //--- smoothing type
         this.m_param[6].type=TYPE_UINT;
         this.m_param[6].integer_value=ma_method;
         //--- price type or handle
         this.m_param[7].type=TYPE_UINT;
         this.m_param[7].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period);
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("Alligator");
      this.SetDescription("Alligator");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_WILLIAMS;
      //--- Write descriptions of GATORJAW_LINE, GATORTEETH_LINE and GATORLIPS_LINE line buffers
      this.SetBufferDescription(GATORJAW_LINE,::StringFormat("Jaws(%s%lu)", (current ? "" : symbol_period+":"),jaw_period));
      this.SetBufferDescription(GATORTEETH_LINE,::StringFormat("Teeth(%s%lu)",(current ? "" : symbol_period+":"),teeth_period));
      this.SetBufferDescription(GATORLIPS_LINE,::StringFormat("Lips(%s%lu)", (current ? "" : symbol_period+":"),lips_period));
      //--- Write offsets to buffers GATORJAW_LINE, GATORTEETH_LINE and GATORLIPS_LINE
      this.SetBufferShift(GATORJAW_LINE,jaw_shift);
      this.SetBufferShift(GATORTEETH_LINE,teeth_shift);
      this.SetBufferShift(GATORLIPS_LINE,lips_shift);
      
      //--- Set drawing style for buffers 0, 1, 2 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_LINE,GATORJAW_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,GATORTEETH_LINE);
      this.SetBufferDrawType(2,DRAW_LINE,GATORLIPS_LINE);
      
      //--- Set default colors for buffers 0, 1 and 2
      this.SetBufferColorToIndex(GATORJAW_LINE,0,clrBlue);
      this.SetBufferColorToIndex(GATORTEETH_LINE,0,clrRed);
      this.SetBufferColorToIndex(GATORLIPS_LINE,0,clrLime);
     }
  };
//+------------------------------------------------------------------+
//| Adaptive Moving Average indicator class                          |
//+------------------------------------------------------------------+
class CIndAMA : public CIndMSTF
  {
public:
//--- Constructor
   CIndAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int ama_period,                   // AMA period
           const int fast_ma_period,               // fast MA period
           const int slow_ma_period,               // slow MA period
           const int ama_shift,                    // horizontal shift of the indicator
           const ENUM_APPLIED_PRICE applied_price  // price type or handle
          ) : CIndMSTF(IND_AMA,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,5)==5)
        {
         ::ZeroMemory(this.m_param);
         //--- AMA period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ama_period<1 ? 9 : ama_period);
         //--- fast MA period
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=(fast_ma_period<1 ? 2 : fast_ma_period);
         //--- slow MA period
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=(slow_ma_period<1 ? 30 : slow_ma_period);
         //--- horizontal shift of the indicator
         this.m_param[3].type=TYPE_INT;
         this.m_param[3].integer_value=ama_shift;
         //--- price type or handle
         this.m_param[4].type=TYPE_UINT;
         this.m_param[4].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),ama_period,fast_ma_period,slow_ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("AMA");
      this.SetDescription("Adaptive Moving Average");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Write shift to buffer 0
      this.SetBufferShift(0,ama_shift);
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Awesome Oscillator indicator class                               |
//+------------------------------------------------------------------+
class CIndAO : public CIndMSTF
  {
public:
//--- Constructor
   CIndAO(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_AO,1,symbol,timeframe)
     {
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=(current ? "" : StringFormat("(%s)",symbol_period));
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("AO");
      this.SetDescription("Awesome Oscillator");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_WILLIAMS;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0);
      
      //--- Set two default colors for the color buffer 0
      this.SetBufferColorToIndex(0,0,clrGreen);
      this.SetBufferColorToIndex(0,1,clrRed);
      //--- Set the default initializing color index
      this.SetBufferInitColorIndex(0,0);
     }
  };
//+------------------------------------------------------------------+
//| Average True Range indicator class                               |
//+------------------------------------------------------------------+
class CIndATR : public CIndMSTF
  {
public:
//--- Constructor
   CIndATR(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int ma_period                     // averaging period
          ) : CIndMSTF(IND_ATR,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("ATR");
      this.SetDescription("Average True Range");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLightSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Bears Power indicator class                                      |
//+------------------------------------------------------------------+
class CIndBears : public CIndMSTF
  {
public:
//--- Constructor
   CIndBears(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int ma_period                      // averaging period
            ) : CIndMSTF(IND_BEARS,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Bears");
      this.SetDescription("Bears Power");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_HISTOGRAM,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrSilver);
     }
  };
//+------------------------------------------------------------------+
//| Bulls Power indicator class                                      |
//+------------------------------------------------------------------+
class CIndBulls : public CIndMSTF
  {
public:
//--- Constructor
   CIndBulls(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int ma_period                      // averaging period
            ) : CIndMSTF(IND_BULLS,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Bulls");
      this.SetDescription("Bulls Power");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_HISTOGRAM,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrSilver);
     }
  };
//+------------------------------------------------------------------+
//| Bollinger Bands® indicator class                                 |
//+------------------------------------------------------------------+
class CIndBands : public CIndMSTF
  {
public:
//--- Constructor
   CIndBands(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int bands_period,                  // central line calculation period
             const int bands_shift,                   // horizontal shift of the indicator
             const double deviation,                  // number of standard deviations
             const ENUM_APPLIED_PRICE applied_price   // price type or handle
            ) : CIndMSTF(IND_BANDS,3,symbol,timeframe)
     {
      // Buffer indexes: 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,4)==4)
        {
         ::ZeroMemory(this.m_param);
         //--- central line calculation period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(bands_period<1 ? 20 : bands_period);
         //--- horizontal shift of the indicator
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=bands_shift;
         //--- number of standard deviations
         this.m_param[2].type=TYPE_DOUBLE;
         this.m_param[2].double_value=deviation;
         //--- price type or handle
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),bands_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Bands");
      this.SetDescription("Bollinger Bands");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Description of line buffers BASE_LINE, UPPER_BAND and LOWER_BAND
      this.SetBufferDescription(BASE_LINE,this.m_title+" Middle");
      this.SetBufferDescription(UPPER_BAND,this.m_title+" Upper");
      this.SetBufferDescription(LOWER_BAND,this.m_title+" Lower");
      //--- Write offsets to the BASE_LINE, UPPER_BAND and LOWER_BAND buffers
      this.SetBufferShift(BASE_LINE,bands_shift);
      this.SetBufferShift(UPPER_BAND,bands_shift);
      this.SetBufferShift(LOWER_BAND,bands_shift);
      
      //--- Set drawing style for buffers 0, 1, 2 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_LINE,BASE_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,UPPER_BAND);
      this.SetBufferDrawType(2,DRAW_LINE,LOWER_BAND);
      
      //--- Set default colors for buffers 0, 1 and 2
      this.SetBufferColorToIndex(BASE_LINE,0,clrMediumSeaGreen);
      this.SetBufferColorToIndex(UPPER_BAND,0,clrMediumSeaGreen);
      this.SetBufferColorToIndex(LOWER_BAND,0,clrMediumSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Commodity Channel Index indicator class                          |
//+------------------------------------------------------------------+
class CIndCCI : public CIndMSTF
  {
public:
//--- Constructor
   CIndCCI(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int ma_period,                    // averaging period
           const ENUM_APPLIED_PRICE applied_price  // price type or handle
          ) : CIndMSTF(IND_CCI,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,2)==2)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period);
         //--- price type or handle
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("CCI");
      this.SetDescription("Commodity Channel Index");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=2;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLightSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Chaikin Oscillator indicator class                               |
//+------------------------------------------------------------------+
class CIndCHO : public CIndMSTF
  {
public:
//--- Constructor
   CIndCHO(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int fast_ma_period,                  // fast period
           const int slow_ma_period,                  // slow period
           const ENUM_MA_METHOD ma_method,            // smoothing type
           const ENUM_APPLIED_VOLUME applied_volume   // used volume
          ) : CIndMSTF(IND_CHAIKIN,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,4)==4)
        {
         ::ZeroMemory(this.m_param);
         //--- fast period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(fast_ma_period<1 ? 3 : fast_ma_period);
         //--- slow period
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=(slow_ma_period<1 ? 10 : slow_ma_period);
         //--- smoothing type
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=ma_method;
         //--- used volume
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_volume;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),slow_ma_period,fast_ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("CHO");
      this.SetDescription("Chaikin Oscillator");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=0;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLightSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Double Exponential Moving Average indicator class                |
//+------------------------------------------------------------------+
class CIndDEMA : public CIndMSTF
  {
public:
//--- Constructor
   CIndDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
            const int ma_period,                      // averaging period
            const int ma_shift,                       // horizontal indicator shift
            const ENUM_APPLIED_PRICE applied_price    // price type or handle
          ) : CIndMSTF(IND_DEMA,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,3)==3)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period);
         //--- horizontal shift of the indicator
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=ma_shift;
         //--- price type or handle
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("DEMA");
      this.SetDescription("Double Exponential Moving Average");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Write shift to buffer 0
      this.SetBufferShift(0,ma_shift);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| DeMarker indicator class                                         |
//+------------------------------------------------------------------+
class CIndDeM : public CIndMSTF
  {
public:
//--- Constructor
   CIndDeM(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int ma_period                     // averaging period
          ) : CIndMSTF(IND_DEMARKER,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("DeM");
      this.SetDescription("DeMarker");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=3;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLightSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Envelopes indicator class                                        |
//+------------------------------------------------------------------+
class CIndEnvelopes : public CIndMSTF
  {
public:
//--- Constructor
   CIndEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe,
                 const int ma_period,                    // middle line calculation period
                 const int ma_shift,                     // horizontal shift of the indicator
                 const ENUM_MA_METHOD ma_method,         // smoothing type
                 const ENUM_APPLIED_PRICE applied_price, // price type or handle
                 const double deviation                  // deviation of envelope borders from the middle line
          ) : CIndMSTF(IND_ENVELOPES,2,symbol,timeframe)
     {
      // Buffer indexes: 0 - UPPER_LINE, 1 - LOWER_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,5)==5)
        {
         ::ZeroMemory(this.m_param);
         //--- central line calculation period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period);
         //--- horizontal shift of the indicator
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=ma_shift;
         //--- smoothing type
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=ma_method;
         //--- price type or handle
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_price;
         //--- deviation of envelope borders from the muddle line
         this.m_param[4].type=TYPE_DOUBLE;
         this.m_param[4].double_value=deviation;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Envelopes");
      this.SetDescription("Envelopes");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Description of UPPER_LINE and LOWER_LINE line buffers
      this.SetBufferDescription(UPPER_LINE,this.m_title+" Upper");
      this.SetBufferDescription(LOWER_LINE,this.m_title+" Lower");
      //--- Write shift to buffers
      this.SetBufferShift(0,ma_shift);
      this.SetBufferShift(1,ma_shift);
      
      //--- Set drawing style for buffers 0 and 1 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_LINE,UPPER_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,LOWER_LINE);
      
      //--- Set default colors for buffers 0 and 1
      this.SetBufferColorToIndex(UPPER_LINE,0,clrBlue);
      this.SetBufferColorToIndex(LOWER_LINE,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Force Index indicator class                                      |
//+------------------------------------------------------------------+
class CIndForce : public CIndMSTF
  {
public:
//--- Constructor
   CIndForce(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int                 ma_period,     // averaging period
             const ENUM_MA_METHOD      ma_method,     // smoothing type
             const ENUM_APPLIED_VOLUME applied_volume // volume type for calculation
            ) : CIndMSTF(IND_FORCE,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,3)==3)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 13 : ma_period);
         //--- smoothing type
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=ma_method;
         //--- volume type for calculation
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=applied_volume;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Force");
      this.SetDescription("Force Index");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLightSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Fractals indicator class                                         |
//+------------------------------------------------------------------+
class CIndFractals : public CIndMSTF
  {
public:
//--- Constructor
   CIndFractals(const string symbol,const ENUM_TIMEFRAMES timeframe) : CIndMSTF(IND_FRACTALS,2,symbol,timeframe)
     {
      // Buffer indexes: 0 - UPPER_LINE, 1 - LOWER_LINE
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=(current ? "" : StringFormat("(%s)",symbol_period));
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("Fractals");
      this.SetDescription("Fractals");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_WILLIAMS;
      //--- Description of UPPER_LINE and LOWER_LINE line buffers
      this.SetBufferDescription(UPPER_LINE,this.m_title+" Up");
      this.SetBufferDescription(LOWER_LINE,this.m_title+" Down");
      
      //--- Set drawing style for buffers 0 and 1 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_ARROW,UPPER_LINE);
      this.SetBufferDrawType(1,DRAW_ARROW,LOWER_LINE);
      
      //--- Set default colors for buffers 0 and 1
      this.SetBufferColorToIndex(UPPER_LINE,0,clrGray);
      this.SetBufferColorToIndex(LOWER_LINE,0,clrGray);
     }
  };
//+------------------------------------------------------------------+
//| Fractal Adaptive Moving Average indicator class                  |
//+------------------------------------------------------------------+
class CIndFrAMA : public CIndMSTF
  {
public:
//--- Constructor
   CIndFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int ma_period,                     // averaging period
             const int ma_shift,                      // horizontal shift of the indicator
             const ENUM_APPLIED_PRICE applied_price   // price type or handle
            ) : CIndMSTF(IND_FRAMA,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,3)==3)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period);
         //--- horizontal shift of the indicator
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=ma_shift;
         //--- price type or handle
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("FRAMA");
      this.SetDescription("Fractal Adaptive Moving Average");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Write shift to buffer 0
      this.SetBufferShift(0,ma_shift);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrBlue);
     }
  };
//+------------------------------------------------------------------+
//| Gator Oscillator indicator class                                 |
//+------------------------------------------------------------------+
class CIndGator : public CIndMSTF
  {
public:
//--- Constructor
   CIndGator(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int jaw_period,                    // period for jaw line calculation
             const int jaw_shift,                     // horizontal shift of jaw line
             const int teeth_period,                  // period for calculating teeth line
             const int teeth_shift,                   // horizontal shift of teeth line
             const int lips_period,                   // period for calculating lip line
             const int lips_shift,                    // horizontal shift of lip line
             const ENUM_MA_METHOD ma_method,          // smoothing type
             const ENUM_APPLIED_PRICE applied_price   // price type or handle
            ) : CIndMSTF(IND_GATOR,2,symbol,timeframe)
     {
      // Buffer indexes: 0 - UPPER_HISTOGRAM, 1 - color buffer of the upper histogram, 2 - LOWER_HISTOGRAM, 3 - color buffer of the lower histogram
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,8)==8)
        {
         ::ZeroMemory(this.m_param);
         //--- period for jaw line calculation
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(jaw_period<1 ? 13 : jaw_period);
         //--- horizontal shift of the jaw line
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=jaw_shift;
         //--- period for teeth line calculation
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=(teeth_period<1 ? 8 : teeth_period);
         //--- horizontal shift of teeth line
         this.m_param[3].type=TYPE_INT;
         this.m_param[3].integer_value=teeth_shift;
         //--- period for lip line calculation
         this.m_param[4].type=TYPE_UINT;
         this.m_param[4].integer_value=(lips_period<1 ? 5 : lips_period);
         //--- horizontal shift of lips line
         this.m_param[5].type=TYPE_INT;
         this.m_param[5].integer_value=lips_shift;
         //--- smoothing type
         this.m_param[6].type=TYPE_UINT;
         this.m_param[6].integer_value=ma_method;
         //--- price type or handle
         this.m_param[7].type=TYPE_UINT;
         this.m_param[7].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),jaw_period,teeth_period,lips_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Gator");
      this.SetDescription("Gator Oscillator");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_WILLIAMS;
      this.m_digits=::Digits()+1;
      
      //--- Description of line buffers UPPER_HISTOGRAM, upper histogram color buffer, LOWER_HISTOGRAM and lower histogram color buffer
      this.SetBufferDescription(0,this.m_title+" Up");
      this.SetBufferDescription(1,this.m_title+" Down");
      //--- Write offsets to buffers UPPER_HISTOGRAM, 1, LOWER_HISTOGRAM and 2
      this.SetBufferShift(0,teeth_shift);
      this.SetBufferShift(1,lips_shift);
      
      //--- Set drawing style for buffers 0 and 1 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,UPPER_HISTOGRAM);
      this.SetBufferDrawType(1,DRAW_COLOR_HISTOGRAM,LOWER_HISTOGRAM);

      //--- Set default colors for color buffers
      this.SetBufferColorToIndex(0,0,clrGreen);
      this.SetBufferColorToIndex(0,1,clrRed);
      this.SetBufferColorToIndex(1,0,clrGreen);
      this.SetBufferColorToIndex(1,1,clrRed);
      //--- Set the default initializing color index
      this.SetBufferInitColorIndex(0,0);
      this.SetBufferInitColorIndex(1,0);
     }
  };
//+------------------------------------------------------------------+
//| Ichimoku Kinko Hyo indicator class                               |
//+------------------------------------------------------------------+
class CIndIchimoku : public CIndMSTF
  {
public:
//--- Constructor
   CIndIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe,
                const int tenkan_sen,                    // period of Tenkan-sen
                const int kijun_sen,                     // period of Kijun-sen
                const int senkou_span_b                  // period of Senkou Span B
               ) : CIndMSTF(IND_ICHIMOKU,5,symbol,timeframe)
     {
      // Buffer indexes: 0 - TENKANSEN_LINE, 1 - KIJUNSEN_LINE, 2 - SENKOUSPANA_LINE, 3 - SENKOUSPANB_LINE, 4 - CHIKOUSPAN_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,3)==3)
        {
         ::ZeroMemory(this.m_param);
         //--- period of Tenkan-sen
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(tenkan_sen<1 ? 9 : tenkan_sen);
         //--- period of Kijun-sen
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=(kijun_sen<1 ? 26 : kijun_sen);
         //--- period of Senkou Span B
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=(senkou_span_b<1 ? 52 : senkou_span_b);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),tenkan_sen,kijun_sen,senkou_span_b);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Ichimoku");
      this.SetDescription("Ichimoku Kinko Hyo");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Description of line buffers TENKANSEN_LINE, KIJUNSEN_LINE, SENKOUSPANA_LINE, SENKOUSPANB_LINE and CHIKOUSPAN_LINE
      this.SetBufferDescription(TENKANSEN_LINE,::StringFormat("Tenkan-sen(%lu)",tenkan_sen));
      this.SetBufferDescription(KIJUNSEN_LINE,::StringFormat("Kijun-sen(%lu)",kijun_sen));
      this.SetBufferDescription(SENKOUSPANA_LINE,"Senkou Span A");
      this.SetBufferDescription(SENKOUSPANB_LINE,::StringFormat("Senkou Span B(%lu)",senkou_span_b));
      this.SetBufferDescription(CHIKOUSPAN_LINE,"Chikou Span");
      //--- Write shifts to buffers SENKOUSPANA_LINE, SENKOUSPANB_LINE and CHIKOUSPAN_LINE
      //this.SetBufferShift(SENKOUSPANA_LINE,kijun_sen);
      //this.SetBufferShift(SENKOUSPANB_LINE,kijun_sen);
      //this.SetBufferShift(CHIKOUSPAN_LINE,kijun_sen-senkou_span_b);
     }
  };
//+------------------------------------------------------------------+
//| Market Facilitation Index indicator class                        |
//+------------------------------------------------------------------+
class CIndBWMFI : public CIndMSTF
  {
public:
//--- Constructor
   CIndBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const ENUM_APPLIED_VOLUME applied_volume // volume type for calculation
            ) : CIndMSTF(IND_BWMFI,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         //--- volume type for calculation
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=applied_volume;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=(current ? "" : StringFormat("(%s)",symbol_period));
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("BW MFI");
      this.SetDescription("Market Facilitation Index");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_WILLIAMS;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0);
      
      //--- Set four default colors for the color buffer 0
      this.SetBufferColorToIndex(0,0,clrLime);
      this.SetBufferColorToIndex(0,1,clrSaddleBrown);
      this.SetBufferColorToIndex(0,2,clrBlue);
      this.SetBufferColorToIndex(0,3,clrPink);
      //--- Set the default initializing color index
      this.SetBufferInitColorIndex(0,0);
     }
  };
//+------------------------------------------------------------------+
//| Momentum indicator class                                         |
//+------------------------------------------------------------------+
class CIndMomentum : public CIndMSTF
  {
public:
//--- Constructor
   CIndMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe,
                const int                 mom_period,    // averaging period
                const ENUM_APPLIED_PRICE  applied_price  // price type or handle
               ) : CIndMSTF(IND_MOMENTUM,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,2)==2)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(mom_period<1 ? 14 : mom_period);
         //--- price type or handle
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),mom_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Momentum");
      this.SetDescription("Momentum");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=2;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrDodgerBlue);
     }
  };
//+------------------------------------------------------------------+
//| Money Flow Index indicator class                                 |
//+------------------------------------------------------------------+
class CIndMFI : public CIndMSTF
  {
public:
//--- Constructor
   CIndMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int                 ma_period,       // averaging period
           const ENUM_APPLIED_VOLUME applied_volume   // volume type for calculation
          ) : CIndMSTF(IND_MFI,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,2)==2)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period);
         //--- volume type for calculation
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=applied_volume;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("MFI");
      this.SetDescription("Money Flow Index");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_VOLUME;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrDodgerBlue);
     }
  };
//+------------------------------------------------------------------+
//| Moving Average indicator class                                   |
//+------------------------------------------------------------------+
class CIndMA : public CIndMSTF
  {
public:
//--- Constructor
   CIndMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
          const int                 ma_period,     // averaging period
          const int                 ma_shift,      // horizontal shift of the indicator
          const ENUM_MA_METHOD      ma_method,     // smoothing type
          const ENUM_APPLIED_PRICE  applied_price  // price type or handle
         ) : CIndMSTF(IND_MA,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,4)==4)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period);
         //--- horizontal shift of the indicator
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=ma_shift;
         //--- smoothing type
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=ma_method;
         //--- price type or handle
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("MA");
      this.SetDescription("Moving Average");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Write shift to buffer 0
      this.SetBufferShift(0,ma_shift);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Moving Average of Oscillator indicator class                     |
//+------------------------------------------------------------------+
class CIndOsMA : public CIndMSTF
  {
public:
//--- Constructor
   CIndOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
            const int                fast_ema_period, // fast MA period
            const int                slow_ema_period, // slow MA period
            const int                signal_period,   // difference averaging period
            const ENUM_APPLIED_PRICE applied_price    // price type or handle
           ) : CIndMSTF(IND_OSMA,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,4)==4)
        {
         ::ZeroMemory(this.m_param);
         //--- fast MA period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period);
         //--- slow MA period
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period);
         //--- difference averaging period
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period<2 ? 2 : signal_period);
         //--- price type or handle
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("OsMA");
      this.SetDescription("Moving Average of Oscillator");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=::Digits()+2;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_HISTOGRAM,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrSilver);
     }
  };
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence indicator class           |
//+------------------------------------------------------------------+
class CIndMACD : public CIndMSTF
  {
public:
//--- Constructor
   CIndMACD(const string symbol,const ENUM_TIMEFRAMES timeframe,
            const int                fast_ema_period, // fast MA period
            const int                slow_ema_period, // slow MA period
            const int                signal_period,   // difference averaging period
            const ENUM_APPLIED_PRICE applied_price    // price type or handle
           ) : CIndMSTF(IND_MACD,2,symbol,timeframe)
     {
      // Buffer indexes: 0 - MAIN_LINE, 1 - SIGNAL_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,4)==4)
        {
         ::ZeroMemory(this.m_param);
         //--- fast MA period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(fast_ema_period<1 ? 12 : fast_ema_period);
         //--- slow MA period
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=(slow_ema_period<1 ? 26 : slow_ema_period);
         //--- difference averaging period
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=(signal_period<1 ? 9 : signal_period);
         //--- price type or handle
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),fast_ema_period,slow_ema_period,signal_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("MACD");
      this.SetDescription("Moving Averages Convergence/Divergence");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=::Digits()+1;
      //--- Description of MAIN_LINE and SIGNAL_LINE line buffers
      this.SetBufferDescription(MAIN_LINE,this.m_title);
      this.SetBufferDescription(SIGNAL_LINE,"Signal");
      
      //--- Set drawing style for buffers 0 and 1 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_HISTOGRAM,MAIN_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,SIGNAL_LINE);
      
      //--- Set default colors for buffers 0 and 1
      this.SetBufferColorToIndex(MAIN_LINE,0,clrSilver);
      this.SetBufferColorToIndex(SIGNAL_LINE,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| On Balance Volume indicator class                                |
//+------------------------------------------------------------------+
class CIndOBV : public CIndMSTF
  {
public:
//--- Constructor
   CIndOBV(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const ENUM_APPLIED_VOLUME applied_volume   // volume type for calculation
          ) : CIndMSTF(IND_OBV,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         //--- volume type for calculation
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=applied_volume;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=(current ? "" : StringFormat("(%s)",symbol_period));
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("OBV");
      this.SetDescription("On Balance Volume");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_VOLUME;
      this.m_digits=0;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLightSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Parabolic Stop and Reverse system indicator class                |
//+------------------------------------------------------------------+
class CIndSAR : public CIndMSTF
  {
public:
//--- Constructor
   CIndSAR(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const double step,                      // price change step — acceleration factor
           const double maximum                    // maximum step
          ) : CIndMSTF(IND_SAR,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,2)==2)
        {
         ::ZeroMemory(this.m_param);
         //--- price change step — acceleration factor
         this.m_param[0].type=TYPE_DOUBLE;
         this.m_param[0].double_value=step;
         //--- maximum step
         this.m_param[1].type=TYPE_DOUBLE;
         this.m_param[1].double_value=maximum;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%.2f,%.2f)",symbol_period,(current ? "" : ":"),step,maximum);
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("SAR");
      this.SetDescription("Parabolic SAR");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_ARROW,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrLime);
     }
  };
//+------------------------------------------------------------------+
//| Relative Strength Index indicator class                          |
//+------------------------------------------------------------------+
class CIndRSI : public CIndMSTF
  {
public:
//--- Constructor
   CIndRSI(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int                ma_period,     // averaging period
           const ENUM_APPLIED_PRICE applied_price  // price type or handle
          ) : CIndMSTF(IND_RSI,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,2)==2)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period);
         //--- price type or handle
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("RSI");
      this.SetDescription("Relative Strength Index");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=2;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrDodgerBlue);
     }
  };
//+------------------------------------------------------------------+
//| Relative Vigor Index indicator class                             |
//+------------------------------------------------------------------+
class CIndRVI : public CIndMSTF
  {
public:
//--- Constructor
   CIndRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int ma_period                     // averaging period
          ) : CIndMSTF(IND_RVI,2,symbol,timeframe)
     {
      // Buffer indexes: 0 - MAIN_LINE, 1 - SIGNAL_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 10 : ma_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("RVI");
      this.SetDescription("Relative Vigor Index");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=3;
      //--- Description of MAIN_LINE and SIGNAL_LINE line buffers
      this.SetBufferDescription(MAIN_LINE,this.m_title);
      this.SetBufferDescription(SIGNAL_LINE,"Signal");
      
      //--- Set drawing style for buffers 0 and 1 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,SIGNAL_LINE);
      
      //--- Set default colors for buffers 0 and 1
      this.SetBufferColorToIndex(MAIN_LINE,0,clrGreen);
      this.SetBufferColorToIndex(SIGNAL_LINE,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Standard Deviation indicator class                               |
//+------------------------------------------------------------------+
class CIndStdDev : public CIndMSTF
  {
public:
//--- Constructor
   CIndStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe,
              const int                ma_period,        // averaging period
              const int                ma_shift,         // horizontal shift of the indicator
              const ENUM_MA_METHOD     ma_method,        // smoothing type
              const ENUM_APPLIED_PRICE applied_price     // price type or handle
             ) : CIndMSTF(IND_STDDEV,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,4)==4)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 20 : ma_period<2 ? 2 : ma_period);
         //--- horizontal shift of the indicator
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=ma_shift;
         //--- smoothing type
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=ma_method;
         //--- price type or handle
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("StdDev");
      this.SetDescription("Standard Deviation");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Write shift to buffer 0
      this.SetBufferShift(0,ma_shift);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrMediumSeaGreen);
     }
  };
//+------------------------------------------------------------------+
//| Stochastic Oscillator indicator class                            |
//+------------------------------------------------------------------+
class CIndStoch : public CIndMSTF
  {
public:
//--- Constructor
   CIndStoch(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int              Kperiod,          // K-period (number of bars for calculations)
             const int              Dperiod,          // D-period (primary smoothing period)
             const int              slowing,          // final smoothing
             const ENUM_MA_METHOD   ma_method,        // smoothing type
             const ENUM_STO_PRICE   price_field       // Stochastic calculation method
            ) : CIndMSTF(IND_STOCHASTIC,2,symbol,timeframe)
     {
      // Buffer indexes: 0 - MAIN_LINE, 1 - SIGNAL_LINE
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,5)==5)
        {
         ::ZeroMemory(this.m_param);
         //--- K period (number of bars for calculation)
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(Kperiod<1 ? 5 : Kperiod);
         //--- D period (primary smoothing period)
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=(Dperiod<1 ? 3 : Dperiod);
         //--- final smoothing
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=(slowing<1 ? 3 : slowing);
         //--- smoothing type
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=ma_method;
         //--- stochastic calculation method
         this.m_param[4].type=TYPE_UINT;
         this.m_param[4].integer_value=price_field;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu,%lu)",symbol_period,(current ? "" : ":"),Kperiod,Dperiod,slowing);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Stoch");
      this.SetDescription("Stochastic Oscillator");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=2;
      //--- Description of MAIN_LINE and SIGNAL_LINE line buffers
      this.SetBufferDescription(MAIN_LINE,this.m_title);
      this.SetBufferDescription(SIGNAL_LINE,"Signal");
      
      //--- Set drawing style for buffers 0 and 1 and the numbers of calculation part data buffers
      this.SetBufferDrawType(0,DRAW_LINE,MAIN_LINE);
      this.SetBufferDrawType(1,DRAW_LINE,SIGNAL_LINE);
      
      //--- Set default colors for buffers 0 and 1
      this.SetBufferColorToIndex(MAIN_LINE,0,clrLightSeaGreen);
      this.SetBufferColorToIndex(SIGNAL_LINE,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Triple Exponential Moving Average indicator class                |
//+------------------------------------------------------------------+
class CIndTEMA : public CIndMSTF
  {
public:
//--- Constructor
   CIndTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
            const int                  ma_period,     // averaging period
            const int                  ma_shift,      // horizontal shift of the indicator
            const ENUM_APPLIED_PRICE   applied_price  // price type or handle
           ) : CIndMSTF(IND_TEMA,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,3)==3)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period);
         //--- horizontal shift of the indicator
         this.m_param[1].type=TYPE_INT;
         this.m_param[1].integer_value=ma_shift;
         //--- price type or handle
         this.m_param[2].type=TYPE_UINT;
         this.m_param[2].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("TEMA");
      this.SetDescription("Triple Exponential Moving Average");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Write shift to buffer 0
      this.SetBufferShift(0,ma_shift);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Triple Exponential Moving Averages Oscillator indicator class    |
//+------------------------------------------------------------------+
class CIndTriX : public CIndMSTF
  {
public:
//--- Constructor
   CIndTriX(const string symbol,const ENUM_TIMEFRAMES timeframe,
            const int                ma_period,       // averaging period
            const ENUM_APPLIED_PRICE applied_price    // price type or handle
           ) : CIndMSTF(IND_TRIX,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,2)==2)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(ma_period<1 ? 14 : ma_period<2 ? 2 : ma_period);
         //--- price type or handle
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),ma_period);
      //--- Write description of parameters, indicator name, its description, title and category
      this.SetParameters(param);
      this.SetName("TRIX");
      this.SetDescription("Triple Exponential Average");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Larry Williams' Percent Range indicator class                    |
//+------------------------------------------------------------------+
class CIndWPR : public CIndMSTF
  {
public:
//--- Constructor
   CIndWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,
           const int calc_period                   // averaging period
          ) : CIndMSTF(IND_WPR,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         //--- averaging period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(calc_period<1 ? 14 : calc_period);
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu)",symbol_period,(current ? "" : ":"),calc_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("%R");
      this.SetDescription("Williams' Percent Range");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_OSCILLATOR;
      this.m_digits=2;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrAqua);
     }
  };
//+------------------------------------------------------------------+
//| Variable Index Dynamic Average indicator class                   |
//+------------------------------------------------------------------+
class CIndVIDyA : public CIndMSTF
  {
public:
//--- Constructor
   CIndVIDyA(const string symbol,const ENUM_TIMEFRAMES timeframe,
             const int                 cmo_period,    // the Chande Momentum period
             const int                 ema_period,    // period of the smoothing factor
             const int                 ma_shift,      // horizontal shift of the indicator
             const ENUM_APPLIED_PRICE  applied_price  // price type or handle
            ) : CIndMSTF(IND_VIDYA,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,4)==4)
        {
         ::ZeroMemory(this.m_param);
         //--- Chande Momentum period
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=(cmo_period<1 ? 9 : cmo_period);
         //--- smoothing factor period
         this.m_param[1].type=TYPE_UINT;
         this.m_param[1].integer_value=(ema_period<1 ? 12 : ema_period);
         //--- horizontal shift of the indicator
         this.m_param[2].type=TYPE_INT;
         this.m_param[2].integer_value=ma_shift;
         //--- price type or handle
         this.m_param[3].type=TYPE_UINT;
         this.m_param[3].integer_value=applied_price;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=StringFormat("(%s%s%lu,%lu)",symbol_period,(current ? "" : ":"),cmo_period,ema_period);
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("VIDYA");
      this.SetDescription("Variable Index Dynamic Average");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_TREND;
      this.m_digits=::Digits()+1;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      //--- Write shift to buffer 0
      this.SetBufferShift(0,ma_shift);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_LINE,0);
      //--- Set the default color for buffer 0
      this.SetBufferColorToIndex(0,0,clrRed);
     }
  };
//+------------------------------------------------------------------+
//| Volumes indicator class                                          |
//+------------------------------------------------------------------+
class CIndVolumes : public CIndMSTF
  {
public:
//--- Constructor
   CIndVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,
               const ENUM_APPLIED_VOLUME applied_volume  // volume type
              ) : CIndMSTF(IND_VOLUMES,1,symbol,timeframe)
     {
      //--- Set the size of the parameter array and fill it
      ::ResetLastError();
      if(::ArrayResize(this.m_param,1)==1)
        {
         ::ZeroMemory(this.m_param);
         //--- volume type
         this.m_param[0].type=TYPE_UINT;
         this.m_param[0].integer_value=applied_volume;
        }
      else
         ::PrintFormat("%s: ArrayResize failed. Error %ld",__FUNCTION__,::GetLastError());
      //--- Create description of parameters
      //--- If non-current chart symbol or period, their descriptions are added to parameters
      bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
      string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
      string param=(current ? "" : StringFormat("(%s)",symbol_period));
      //--- Write description of parameters, indicator name, its description, title, category and Digits
      this.SetParameters(param);
      this.SetName("Volumes");
      this.SetDescription("Volumes");
      this.m_title=this.Name()+this.Parameters();
      this.m_category=IND_CATEGORY_VOLUME;
      this.m_digits=0;
      //--- Write description of line buffers
      this.SetBufferDescription(0,this.m_title);
      
      //--- Set drawing style for buffer 0 and the data buffer number of the calculation part
      this.SetBufferDrawType(0,DRAW_COLOR_HISTOGRAM,0);
      
      //--- Set two default colors for the color buffer 0
      this.SetBufferColorToIndex(0,0,clrGreen);
      this.SetBufferColorToIndex(0,1,clrRed);
      //--- Set the default initializing color index
      this.SetBufferInitColorIndex(0,0);
     }
  };
//+------------------------------------------------------------------+
//| Custom indicator class                                           |
//+------------------------------------------------------------------+
class CIndCustom : public CIndMSTF
  {
public:
//--- Constructor
   CIndCustom(const string symbol,const ENUM_TIMEFRAMES timeframe,
              const string path,                      // path to the indicator (for example, "Examples\\MACD.ex5")
              const string name,                      // name of the custom indicator
              const uint   buffers,                   // number of indicator buffers
              const MqlParam &param[]                 // array of custom indicator parameters
             ) : CIndMSTF(IND_CUSTOM,buffers,symbol,timeframe)
     {
      //--- If an empty array of parameters is passed, print this to log
      int total=(int)param.Size();
      if(total==0)
         ::PrintFormat("%s Error. Passed an empty array",__FUNCTION__);
      //--- If the array is not empty and its size is increased by 1 (the first string parameter must contain the indicator name)
      ResetLastError();
      if(total>0 && ::ArrayResize(this.m_param,total+1)==total+1)
        {
         //--- Reset data in the array and enter name (path to file and name of .ex5 file)
         ::ZeroMemory(this.m_param);
         //--- name of the custom indicator
         this.m_param[0].type=TYPE_STRING;
         this.m_param[0].string_value=path;
         //--- fill the array of indicator parameters
         for(int i=0;i<total;i++)
           {
            this.m_param[i+1].type=param[i].type;
            this.m_param[i+1].double_value=param[i].double_value;
            this.m_param[i+1].integer_value=param[i].integer_value;
            this.m_param[i+1].string_value=param[i].string_value;
           }
         //--- Create description of parameters
         //--- If non-current chart symbol or period, their descriptions are added to parameters
         bool current=(this.Symbol()==::Symbol() && this.Timeframe()==::Period());
         string symbol_period=(current ? "" : ::StringFormat("%s,%s",this.Symbol(),this.TimeframeDescription()));
         string param=(current ? "" : StringFormat("(%s)",symbol_period));
         //--- Write description of parameters, indicator name, its description, title and category
         this.SetParameters(param);
         this.SetName(name);
         this.SetDescription(name);
         this.m_title=this.Name()+this.Parameters();
         this.m_category=IND_CATEGORY_CUSTOM;
         //--- Write a description of the first line buffer
         this.SetBufferDescription(0,this.m_title);
        }
     }
  };

Usando el estilo de dibujado establecido para el búfer, podremos determinar si se trata de un búfer de color o no, y en consecuencia utilizar esos u otros métodos para dibujar el búfer. Especificando el índice del búfer de la parte de cálculo y escribiéndolo en el búfer de la clase de indicador, permitiremos determinar fácilmente de qué búfer de la parte de cálculo hay que copiar los datos. Además, si se trata de un búfer de color, recordando que el búfer de color siempre viene después del búfer de datos de la parte de cálculo, podremos saber exactamente de qué búfer obtener los datos de color de la línea: simplemente deberemos añadir uno al índice del búfer de la parte de cálculo para obtener el índice de color deseado. Y todos estos datos ya están escritos en el búfer de la clase de indicador, lo cual resulta bastante cómodo.

En la clase de colección de indicadores, también hay que introducir mejoras en los métodos y añadir otros nuevos.

//+------------------------------------------------------------------+
//| Indicator collection class                                       |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
class CMSTFIndicators
  {
private:
   CArrayObj         m_list;
//--- Creates an indicator for the passed object
   bool              CreateIndicator(CIndMSTF *ind_obj);
//--- Adds the specified indicator to the collection
   int               AddNewIndicator(CIndMSTF *ind_obj,const string source);

public:
//--- Returns (1) indicator object by handle, (2) number of indicators in the collection
   CIndMSTF         *GetIndicatorObj(const int ind_handle,const string source) const;
   uint              IndicatorsTotal(void)                  const { return this.m_list.Total(); }

//--- Populates buffers of (1) the indicator by handle, (2) all indicators in the collection
   bool              Calculate(const int ind_handle);
   bool              Calculate(void);
//--- Sets (1) the specified, (2) default description, (3) color of the indicator buffer line
   void              SetPlotLabel(const uint plot_index,const string descript);
   void              SetPlotLabelFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num);
   void              SetPlotColorsFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num);
//--- Sets the shift to the specified plotting buffer
   void              SetPlotShift(const uint plot_index,const int shift);
//--- (1) Sets (2) returns the initializing value of the given buffer specified by the indicator handle
   void              SetBufferInitValue(const int ind_handle,const uint buffer_num,const double value);
   double            BufferInitValue(const int ind_handle,const uint buffer_num) const;

//--- (1) Sets (2) returns the initializing value of the color index for the specified buffer
   void              SetBufferInitColorIndex(const int ind_handle,const uint buffer_num,const uchar index);
   uchar             BufferInitColorIndex(const int ind_handle,const uint buffer_num) const;
//--- (1) Sets, (2) returns the color value by index for the specified buffer
   void              SetBufferColorToIndex(const int ind_handle,const uint buffer_num,const uchar color_idx,const color clr);
   color             BufferColorByIndex(const int ind_handle,const uint buffer_num,const uchar color_idx) const;
   //--- Returns the color buffer flag
   bool              IsColoredBuffer(const int ind_handle,const uint buffer_num) const;

//--- Returns indicator data by handle from the specified buffer at index (1) as is, (2) for the specified symbol/timeframe
   double            GetData(const int ind_handle,const uint buffer_num,const uint array_num,const uint index);
   double            GetDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const uint index);
//--- Returns indicator color index data by handle from the specified buffer at index (1) as is, (2) for the specified symbol/timeframe
   double            GetColorData(const int ind_handle,const uint buffer_num,const uint index);
   double            GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index);

//--- (1) Copies data of the specified calculation part buffer of the indicator by handle into the indicator buffer, taking into account chart symbol/period,
//--- (2) Copies the data of the specified color buffer of the indicator calculation part by handle into the color buffer of the indicator, taking into account the chart symbol/period,
//--- (2) returns the amount of data in the specified buffer of the indicator by handle
   bool              DataToBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const int limit,double &buffer[]);
   bool              DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[]);
   uint              DataTotal(const int ind_handle,const uint buffer_num) const;

   //--- Returns (1) buffer description, (2) state of the line data of given buffer of indicator specified by handle on the specified bar
   //--- (3) indicator line state for the specific chart symbol/period, (4) indicator line state relation to the specified level,
   //--- (5)  state of relation of indicator line with specified level for certain chart symbol/period, (6) indicator category description
   string            BufferDescription(const int ind_handle,const uint buffer_num);
   ENUM_LINE_STATE   BufferLineState(const int ind_handle,const uint buffer_num,const uint array_num,const int index);
   ENUM_LINE_STATE   BufferLineState(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const uint buffer_num,const uint array_num,const int index);
   ENUM_LINE_STATE   BufferLineStateRelative(const int ind_handle,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE);
   ENUM_LINE_STATE   BufferLineStateRelative(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ind_handle,const int buffer_num,const uint array_num,const int index,const double level0,const double level1=EMPTY_VALUE);
   string            CategoryDescription(const int ind_handle);
   
//--- Sets (1) identifier, (2) Digits, (3) user description, (4) buffer description
   void              SetID(const int ind_handle,const int id);
   void              SetDigits(const int ind_handle,const int digits);
   void              SetDescription(const int ind_handle,const string descr);
   void              SetBufferDescription(const int ind_handle,const uint buffer_num,const string descr);

//--- Returns flag of whether the buffer is set as series, (2) historical data for symbol/period is synchronized
   bool              IsSeries(const int ind_handle,const uint buffer_num,const uint array_num) const;
   bool              IsSynchronized(const int ind_handle) const;
   
//--- ...
//--- ...
//--- ...

//--- Timer
   void OnTimer(void)
     {
      //--- In a loop through all indicators form the collection
      int total=this.m_list.Total();
      for(int i=0;i<total;i++)
        {
         //--- get a pointer to the next indicator object
         //--- and call its timer
         CIndMSTF *obj=this.m_list.At(i);
         if(obj!=NULL)
            obj.OnTimer();
        }
     }
//--- Constructor/destructor
                     CMSTFIndicators(void){ this.m_list.Clear(); }
                    ~CMSTFIndicators(void){;}
  };

En todos los métodos que requieren la especificación del índice de array ya se han realizado estas mejoras:

//+------------------------------------------------------------------+
//| Returns data of the indicator at the handle                      |
//| from the specified buffers by index as is                        |
//+------------------------------------------------------------------+
double CMSTFIndicators::GetData(const int ind_handle,const uint buffer_num,const uint array_num,const uint index)
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return EMPTY_VALUE;
     }
//--- Return data from the specified indicator buffer at the index passed to the method
   return obj.GetData(buffer_num,array_num,index);
  }

Implementación de nuevos métodos declarados:

//+------------------------------------------------------------------+
//| Return color index data of the indicator by handle               |
//| from the specified buffers by index as is                        |
//+------------------------------------------------------------------+
double CMSTFIndicators::GetColorData(const int ind_handle,const uint buffer_num,const uint index)
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return EMPTY_VALUE;
     }
//--- Return color index data from the specified indicator buffer at the index passed to the method
   return obj.GetColorData(buffer_num,index);
  }
//+------------------------------------------------------------------+
//| Return color index data of the indicator by handle               |
//| from the specified buffer at index for this symbol/timeframe     |
//+------------------------------------------------------------------+
double CMSTFIndicators::GetColorDataTo(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint index)
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return EMPTY_VALUE;
     }
//--- Return color index data from the specified indicator buffer at the index passed to the method
   return obj.GetColorDataTo(symbol_to,timeframe_to,buffer_num,index);
  }

//+------------------------------------------------------------------+
//| Fill the passed color buffer of the indicator with data          |
//+------------------------------------------------------------------+
bool CMSTFIndicators::DataToColorBuffer(const string symbol_to,const ENUM_TIMEFRAMES timeframe_to,const int ind_handle,const uint buffer_num,const uint array_num,const int limit,double &plot_buffer[],double &color_buffer[])
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return false;
     }
//--- Fill the color array-buffer passed to the method from the specified color buffer of the indicator
   return obj.DataToColorBuffer(symbol_to,timeframe_to,buffer_num,array_num,limit,plot_buffer,color_buffer);
  }

//+------------------------------------------------------------------+
//| Set the line color for the indicator buffer                      |
//+------------------------------------------------------------------+
void CMSTFIndicators::SetPlotColorsFromBuffer(const uint plot_index,const int ind_handle,const uint buffer_num)
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return;
     }
//--- Set colors from the specified indicator color buffer for the specified plot buffer
   uint colors=obj.ColorsTotal(buffer_num);
   if(colors==0)
      return;
   ::PlotIndexSetInteger(plot_index,PLOT_COLOR_INDEXES,colors);
   for(int i=0;i<(int)colors;i++)
      ::PlotIndexSetInteger(plot_index,PLOT_LINE_COLOR,i,obj.BufferColorByIndex(buffer_num,(uchar)i));
  }

//+------------------------------------------------------------------+
//| Set the initializing value of the color index                    |
//| for the specified buffer of indicator specified by handle        |
//+------------------------------------------------------------------+
void CMSTFIndicators::SetBufferInitColorIndex(const int ind_handle,const uint buffer_num,const uchar index)
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return;
     }
//--- Set the initializing color index value for the specified buffer
   obj.SetBufferInitColorIndex(buffer_num,index);
  }
//+------------------------------------------------------------------+
//| Return the initializing value of the color index                 |
//| for the specified buffer of indicator specified by handle        |
//+------------------------------------------------------------------+
uchar CMSTFIndicators::BufferInitColorIndex(const int ind_handle,const uint buffer_num) const
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return WRONG_VALUE;
     }
//--- Return the initializing value of the color index set for the specified buffer
   return obj.BufferInitColorIndex(buffer_num);
  }
//+------------------------------------------------------------------+
//| Set the color value by index for the specified buffer            |
//| of the indicator specified by handle                             |
//+------------------------------------------------------------------+
void CMSTFIndicators::SetBufferColorToIndex(const int ind_handle,const uint buffer_num,const uchar color_idx,const color clr)
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return;
     }
//--- Set the color value for the specified buffer by index
   obj.SetBufferColorToIndex(buffer_num,color_idx,clr);
  }
//+------------------------------------------------------------------+
//| Return the color value by index for the specified buffer         |
//| of the indicator specified by handle                             |
//+------------------------------------------------------------------+
color CMSTFIndicators::BufferColorByIndex(const int ind_handle,const uint buffer_num,const uchar color_idx) const
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return WRONG_VALUE;
     }
//--- Return the color value, set for the specified buffer, by index
   return obj.BufferColorByIndex(buffer_num,color_idx);
  }
//+------------------------------------------------------------------+
//| Return the color flag for the specified buffer                   |
//| of the indicator specified by handle                             |
//+------------------------------------------------------------------+
bool CMSTFIndicators::IsColoredBuffer(const int ind_handle,const uint buffer_num) const
  {
//--- Get a pointer to the indicator object using the handle passed to the method
   CIndMSTF *obj=this.GetIndicatorObj(ind_handle,__FUNCTION__);
   if(obj==NULL)
     {
      ::PrintFormat("%s: Failed to get indicator object",__FUNCTION__);
      return false;
     }
//--- Return value of the color flag set for the specified buffer
   return obj.IsColoredBuffer(buffer_num);
  }

Hemos introducido mejoras en los métodos de adición de objetos de indicador a la colección para establecer inmediatamente para el indicador creado Digits e inicializar el "valor vacío" del búfer de datos y el búfer de color:

//+------------------------------------------------------------------+
//| Add the Accelerator Oscillator indicator to the collection       |
//+------------------------------------------------------------------+
int CMSTFIndicators::AddNewAC(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
//--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE
   CIndAC *ind_obj=new CIndAC(symbol,timeframe);
   if(ind_obj==NULL)
     {
      ::PrintFormat("%s: Error. Failed to create AC indicator object",__FUNCTION__);
      return INVALID_HANDLE;
     }
//--- Get the result of adding the created indicator object to the collection list
   int handle=this.AddNewIndicator(ind_obj,__FUNCTION__);
//--- If the indicator is successfully created and added to the collection, set the parameters for its display
   if(handle!=INVALID_HANDLE && ::CheckPointer(ind_obj)!=POINTER_INVALID)
     {
      ::IndicatorSetInteger(INDICATOR_DIGITS,ind_obj.Digits());
      ind_obj.SetBufferInitValue(0,EMPTY_VALUE);
      ind_obj.SetBufferInitColorIndex(0,0);
     }
//--- Return the handle of the created indicator or INVALID_HANDLE
   return handle;
  }

En caso necesario, también se establecerá el número de niveles de indicador y sus valores:

//+------------------------------------------------------------------+
//| Add the Commodity Channel Index indicator to the collection      |
//+------------------------------------------------------------------+
int CMSTFIndicators::AddNewCCI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                               const int ma_period=14,
                               const ENUM_APPLIED_PRICE applied_price=PRICE_TYPICAL)
  {
//--- Create a new indicator object. If there is an error, add a journal message and return INVALID_HANDLE
   CIndCCI *ind_obj=new CIndCCI(symbol,timeframe,ma_period,applied_price);
   if(ind_obj==NULL)
     {
      ::PrintFormat("%s: Error. Failed to create CCI indicator object",__FUNCTION__);
      return INVALID_HANDLE;
     }
//--- Get the result of adding the created indicator object to the collection list
   int handle=this.AddNewIndicator(ind_obj,__FUNCTION__);
//--- If the indicator is successfully created and added to the collection, set the parameters for its display
   if(handle!=INVALID_HANDLE && ::CheckPointer(ind_obj)!=POINTER_INVALID)
     {
      ::IndicatorSetInteger(INDICATOR_LEVELS,2);
      ::IndicatorSetDouble(INDICATOR_LEVELVALUE,0,-100.0);
      ::IndicatorSetDouble(INDICATOR_LEVELVALUE,1, 100.0);
      ::IndicatorSetInteger(INDICATOR_DIGITS,ind_obj.Digits());
      ind_obj.SetBufferInitValue(0,EMPTY_VALUE);
     }
//--- Return the handle of the created indicator or INVALID_HANDLE
   return handle;
  }

Todos los métodos similares ya han sido perfeccionados y pueden verse en los archivos adjuntos al artículo. Los métodos anteriores simplemente retornaban el resultado de la creación y adición de un objeto de indicador a la lista de colección, el manejador del indicador creado, o INVALID_HANDLE en caso de fallo. Ahora, si el objeto indicador se ha creado correctamente y el puntero al objeto en la lista es válido, se establecerán Digits y los niveles para el indicador en el gráfico y se establecerán "valores vacíos" para sus búferes en el objeto de indicador creado.

Hemos realizado todas las mejoras de la biblioteca de indicadores de símbolo y periodo múltiple. Podrá ver las correcciones completas en el archivo IndMSTF.mqh adjunto a este artículo.


Simulación

En los indicadores de prueba utilizaremos la clase de panel informativo Dashboard.mqh, creada solo para probar indicadores múltiples.

El archivo de clase de panel se adjunta al artículo y deberá encontrarse en la ruta \MQL5\Include\Dashboard\Dashboard\Dashboard.mqh.

En el artículo anterior, ya creamos un indicador de prueba que dibuja en el gráfico una media móvil de símbolo y periodo múltiple seleccionada en la lista. Ahora, basándonos en este archivo, haremos algunos otros indicadores estándar de símbolo y periodo múltiple, incluyendo aquellos con búferes de color. El indicador de prueba está organizado de manera que en un mismo gráfico se dibujen la línea de datos del indicador del símbolo actual y el periodo del gráfico, y que en el mismo gráfico se dibuje una segunda línea, pero con los datos del símbolo y el periodo del mismo indicador seleccionado en la configuración. La línea del marco temporal más antiguo se dibujará más gruesa.

Algunos indicadores no se ven correctamente al mostrar los datos de diferentes marco temporales en una ventana, por ejemplo, algunos indicadores de volumen que muestran el volumen de un periodo gráfico seleccionado. En el marco temporal mayor el volumen de ticks será definitivamente mayor que en el menor, mientras que la línea del marco temporal menor será casi recta con respecto a la línea del mayor. Por tanto, dichos indicadores mostrarán solo una línea, desde el símbolo seleccionado y su periodo de configuración.

Indicador de acumulación/distribución:

//+------------------------------------------------------------------+
//|                                      TestMSTFAccDistribution.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- enums

//--- plot MSTF A/D
#property indicator_label1  "MSTF A/D"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input ENUM_APPLIED_VOLUME  InpVolume      =  VOLUME_TICK;      /* Applied Volume             */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferAD[];
//--- global variables
int handle_ad;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferAD,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferAD,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_ad=indicators.AddNewAD(InpSymbol,InpTimeframe,InpVolume);

//--- If failed to create indicator handles, return initialization error
   if(handle_ad==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_ad,0);
      
//--- Dashboard
//--- Create the panel
   int width=220;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ad,0,0,limit,BufferAD))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_ad), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_ad,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ad)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ad,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_ad), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ad,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ad)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ad,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Accelerator Oscillator:

//+------------------------------------------------------------------+
//|                                TestMSTFAcceleratorOscillator.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   2
//--- enums

//--- plot AC1
#property indicator_label1  "AC1"
#property indicator_type1   DRAW_COLOR_HISTOGRAM
#property indicator_color1  clrGreen,clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot AC2
#property indicator_label2  "AC2"
#property indicator_type2   DRAW_COLOR_HISTOGRAM
#property indicator_color2  clrGreen,clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferAC1[];
double         BufferClrAC1[];
double         BufferAC2[];
double         BufferClrAC2[];
//--- global variables
int handle_ac1;
int handle_ac2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign arrays BufferAC1 and BufferAC2 to plot buffers 0 and 2, respectively,
//--- and color arrays BufferClrAC1 and BufferClrAC2 to buffers 1 and 3
   SetIndexBuffer(0,BufferAC1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferClrAC1,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,BufferAC2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferClrAC2,INDICATOR_COLOR_INDEX);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferAC1,InpAsSeries);
   ArraySetAsSeries(BufferClrAC1,InpAsSeries);
   ArraySetAsSeries(BufferAC2,InpAsSeries);
   ArraySetAsSeries(BufferClrAC2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_ac1=indicators.AddNewAC(NULL,PERIOD_CURRENT);
   handle_ac2=indicators.AddNewAC(InpSymbol,InpTimeframe);

//--- If failed to create indicator handles, return initialization error
   if(handle_ac1==INVALID_HANDLE || handle_ac2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_ac1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_ac2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_ac1,0,0,limit,BufferAC1,BufferClrAC1))
      return 0;
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_ac2,0,0,limit,BufferAC2,BufferClrAC2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_ac1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_ac1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ac1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ac1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_ac2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ac2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ac2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ac2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ac2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_ac1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_ac1);
   string ma2=indicators.Name(handle_ac2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Alligator:

//+------------------------------------------------------------------+
//|                                        TestMSTFAlligator.mq5.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   6
//--- enums

//--- plot Jaws1
#property indicator_label1  "Jaws1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_width1  1

//--- plot Teeth1
#property indicator_label2  "Teeth1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrOrangeRed
#property indicator_width2  1

//--- plot Lips1
#property indicator_label3  "Lips1"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrLime
#property indicator_width3  1

//--- plot Jaws2
#property indicator_label4  "Jaws2"
#property indicator_type4  DRAW_LINE
#property indicator_color4  clrBlue
#property indicator_width4  1

//--- plot Teeth2
#property indicator_label5  "Teeth"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrRed
#property indicator_width5  1

//--- plot Lips2
#property indicator_label6  "Lips"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrLimeGreen
#property indicator_width6  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* MA Symbol                  */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* MA Timeframe               */ 
input int                  InpJawsPeriod  =  13;               /* Jaws Period                */ 
input int                  InpJawsShift   =  8;                /* Jaws Shift                 */ 
input int                  InpTeethPeriod =  8;                /* Teeth Period               */ 
input int                  InpTeethShift  =  5;                /* Teeth Shift                */ 
input int                  InpLipsPeriod  =  5;                /* Lips Period                */ 
input int                  InpLipsShift   =  3;                /* Lips Shift                 */ 
input ENUM_MA_METHOD       InpMethod      =  MODE_SMMA;        /* Method                     */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_MEDIAN;     /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferJaws1[];
double         BufferTeeth1[];
double         BufferLips1[];
double         BufferJaws2[];
double         BufferTeeth2[];
double         BufferLips2[];
//--- global variables
int handle_alligator1;
int handle_alligator2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign arrays BufferBandsUp1, BufferBandsDn1 and BufferBandsMd1 to plot buffers 0, 1 and 2, respectively
   SetIndexBuffer(0,BufferJaws1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferTeeth1,INDICATOR_DATA);
   SetIndexBuffer(2,BufferLips1,INDICATOR_DATA);
//--- Set arrays BufferBandsUp2, BufferBandsDn2 and BufferBandsMd2 to buffers 3, 4 and 5, respectively
   SetIndexBuffer(3,BufferJaws2,INDICATOR_DATA);
   SetIndexBuffer(4,BufferTeeth2,INDICATOR_DATA);
   SetIndexBuffer(5,BufferLips2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(4,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(5,PLOT_LINE_WIDTH,w2);
//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferJaws1,InpAsSeries);
   ArraySetAsSeries(BufferTeeth1,InpAsSeries);
   ArraySetAsSeries(BufferLips1,InpAsSeries);
   ArraySetAsSeries(BufferJaws2,InpAsSeries);
   ArraySetAsSeries(BufferTeeth2,InpAsSeries);
   ArraySetAsSeries(BufferLips2,InpAsSeries);
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_alligator1=indicators.AddNewAlligator(NULL,PERIOD_CURRENT,InpJawsPeriod,InpJawsShift,InpTeethPeriod,InpTeethShift,InpLipsPeriod,InpLipsShift,InpMethod,InpPrice);
   handle_alligator2=indicators.AddNewAlligator(InpSymbol,InpTimeframe,InpJawsPeriod,InpJawsShift,InpTeethPeriod,InpTeethShift,InpLipsPeriod,InpLipsShift,InpMethod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_alligator1==INVALID_HANDLE || handle_alligator2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_alligator1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_alligator1,1);
   indicators.SetPlotLabelFromBuffer(2,handle_alligator1,2);
   indicators.SetPlotLabelFromBuffer(3,handle_alligator2,0);
   indicators.SetPlotLabelFromBuffer(4,handle_alligator2,1);
   indicators.SetPlotLabelFromBuffer(5,handle_alligator2,2);
//--- Set shifts for indicator lines
   indicators.SetPlotShift(0,InpJawsShift);
   indicators.SetPlotShift(1,InpTeethShift);
   indicators.SetPlotShift(2,InpLipsShift);
   indicators.SetPlotShift(3,InpJawsShift);
   indicators.SetPlotShift(4,InpTeethShift);
   indicators.SetPlotShift(5,InpLipsShift);

//--- Dashboard
//--- Create the panel
   int width=321;
   panel=new CDashboard(1,20,20,width,264);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator1,0,0,limit,BufferJaws1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator1,1,0,limit,BufferTeeth1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator1,2,0,limit,BufferLips1))
      return 0;
   
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator2,0,0,limit,BufferJaws2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator2,1,0,limit,BufferTeeth2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_alligator2,2,0,limit,BufferLips2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_alligator1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_alligator1,0,0,index+InpJawsShift);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_alligator1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,150);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_alligator1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,150);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_alligator2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_alligator2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_alligator2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,150);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_alligator2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,150);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_alligator2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_alligator1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_alligator1);
   string ma2=indicators.Name(handle_alligator2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,150);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Average Directional Movement Index:

//+------------------------------------------------------------------+
//|                      TestMSTFAverageDirectionalMovementIndex.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   6
//--- enums

//--- plot ADX1
#property indicator_label1  "ADX1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot +DI1
#property indicator_label2  "+DI1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGreen
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- plot -DI1
#property indicator_label3  "-DI1"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

//--- plot ADX2
#property indicator_label4  "ADX2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrBlue
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

//--- plot +DI2
#property indicator_label5  "+DI2"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrGreen
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1

//--- plot -DI2
#property indicator_label6  "-DI2"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrRed
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferADX1[];
double         BufferDIPlus1[];
double         BufferDIMinus1[];
double         BufferADX2[];
double         BufferDIPlus2[];
double         BufferDIMinus2[];
//--- global variables
int handle_adx1;
int handle_adx2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferADX1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferDIPlus1,INDICATOR_DATA);
   SetIndexBuffer(2,BufferDIMinus1,INDICATOR_DATA);
   SetIndexBuffer(3,BufferADX2,INDICATOR_DATA);
   SetIndexBuffer(4,BufferDIPlus2,INDICATOR_DATA);
   SetIndexBuffer(5,BufferDIMinus2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(4,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(5,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferADX1,InpAsSeries);
   ArraySetAsSeries(BufferDIPlus1,InpAsSeries);
   ArraySetAsSeries(BufferDIMinus1,InpAsSeries);
   ArraySetAsSeries(BufferADX2,InpAsSeries);
   ArraySetAsSeries(BufferDIPlus2,InpAsSeries);
   ArraySetAsSeries(BufferDIMinus2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_adx1=indicators.AddNewADX(NULL,PERIOD_CURRENT,InpPeriod);
   handle_adx2=indicators.AddNewADX(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_adx1==INVALID_HANDLE || handle_adx2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_adx1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_adx1,1);
   indicators.SetPlotLabelFromBuffer(2,handle_adx1,2);
   indicators.SetPlotLabelFromBuffer(3,handle_adx2,0);
   indicators.SetPlotLabelFromBuffer(4,handle_adx2,1);
   indicators.SetPlotLabelFromBuffer(5,handle_adx2,2);
      
//--- Dashboard
//--- Create the panel
   int width=301;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx1,0,0,limit,BufferADX1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx1,1,0,limit,BufferDIPlus1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx1,2,0,limit,BufferDIMinus1))
      return 0;
      
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx2,0,0,limit,BufferADX2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx2,1,0,limit,BufferDIPlus2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adx2,2,0,limit,BufferDIMinus2))
      return 0;
      
//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_adx1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_adx1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_adx1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adx1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_adx2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adx2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_adx2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adx2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adx2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_adx1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_adx1);
   string ma2=indicators.Name(handle_adx2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Índice Average Directional Movement Index Wilder:

//+------------------------------------------------------------------+
//|                TestMSTFAverageDirectionalMovementIndexWilder.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   6
//--- enums

//--- plot ADXW1
#property indicator_label1  "ADXW1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot +DI1
#property indicator_label2  "+DI1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGreen
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- plot -DI1
#property indicator_label3  "-DI1"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

//--- plot ADXW2
#property indicator_label4  "ADXW2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrBlue
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

//--- plot +DI2
#property indicator_label5  "+DI2"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrGreen
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1

//--- plot -DI2
#property indicator_label6  "-DI2"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrRed
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferADXW1[];
double         BufferDIPlus1[];
double         BufferDIMinus1[];
double         BufferADXW2[];
double         BufferDIPlus2[];
double         BufferDIMinus2[];
//--- global variables
int handle_adxw1;
int handle_adxw2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferADXW1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferDIPlus1,INDICATOR_DATA);
   SetIndexBuffer(2,BufferDIMinus1,INDICATOR_DATA);
   SetIndexBuffer(3,BufferADXW2,INDICATOR_DATA);
   SetIndexBuffer(4,BufferDIPlus2,INDICATOR_DATA);
   SetIndexBuffer(5,BufferDIMinus2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(4,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(5,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferADXW1,InpAsSeries);
   ArraySetAsSeries(BufferDIPlus1,InpAsSeries);
   ArraySetAsSeries(BufferDIMinus1,InpAsSeries);
   ArraySetAsSeries(BufferADXW2,InpAsSeries);
   ArraySetAsSeries(BufferDIPlus2,InpAsSeries);
   ArraySetAsSeries(BufferDIMinus2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_adxw1=indicators.AddNewADX(NULL,PERIOD_CURRENT,InpPeriod);
   handle_adxw2=indicators.AddNewADX(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_adxw1==INVALID_HANDLE || handle_adxw2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_adxw1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_adxw1,1);
   indicators.SetPlotLabelFromBuffer(2,handle_adxw1,2);
   indicators.SetPlotLabelFromBuffer(3,handle_adxw2,0);
   indicators.SetPlotLabelFromBuffer(4,handle_adxw2,1);
   indicators.SetPlotLabelFromBuffer(5,handle_adxw2,2);
      
//--- Dashboard
//--- Create the panel
   int width=301;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw1,0,0,limit,BufferADXW1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw1,1,0,limit,BufferDIPlus1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw1,2,0,limit,BufferDIMinus1))
      return 0;
      
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw2,0,0,limit,BufferADXW2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw2,1,0,limit,BufferDIPlus2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_adxw2,2,0,limit,BufferDIMinus2))
      return 0;
      
//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_adxw1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_adxw1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_adxw1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adxw1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_adxw2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adxw2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_adxw2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_adxw2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_adxw2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_adxw1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_adxw1);
   string ma2=indicators.Name(handle_adxw2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Average True Range:

//+------------------------------------------------------------------+
//|                                     TestMSTFAverageTrueRange.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot ATR1
#property indicator_label1  "ATR1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot ATR2
#property indicator_label2  "ATR2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferATR1[];
double         BufferATR2[];
//--- global variables
int handle_atr1;
int handle_atr2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferATR1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferATR2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferATR1,InpAsSeries);
   ArraySetAsSeries(BufferATR2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_atr1=indicators.AddNewATR(NULL,PERIOD_CURRENT,InpPeriod);
   handle_atr2=indicators.AddNewATR(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_atr1==INVALID_HANDLE || handle_atr2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_atr1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_atr2,0);
      
//--- Dashboard
//--- Create the panel
   int width=237;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_atr1,0,0,limit,BufferATR1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_atr2,0,0,limit,BufferATR2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_atr1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_atr1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_atr1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_atr1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_atr2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_atr2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_atr2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_atr2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_atr2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_atr1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_atr1);
   string ma2=indicators.Name(handle_atr2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:


A veces, puede cambiar el marco temporal del gráfico para que el indicador se dibuje más rápidamente.


Indicador Awesome Oscillator:

//+------------------------------------------------------------------+
//|                                    TestMSTFAwesomeOscillator.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   2
//--- enums

//--- plot AC1
#property indicator_label1  "AO1"
#property indicator_type1   DRAW_COLOR_HISTOGRAM
#property indicator_color1  clrGreen,clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot AC2
#property indicator_label2  "AO2"
#property indicator_type2   DRAW_COLOR_HISTOGRAM
#property indicator_color2  clrGreen,clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferAO1[];
double         BufferClrAO1[];
double         BufferAO2[];
double         BufferClrAO2[];
//--- global variables
int handle_ao1;
int handle_ao2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign arrays BufferAO1 and BufferAO2 to plot buffers 0 and 2, respectively,
//--- and color arrays BufferClrAO1 and BufferClrAO2 to buffers 1 and 3
   SetIndexBuffer(0,BufferAO1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferClrAO1,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,BufferAO2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferClrAO2,INDICATOR_COLOR_INDEX);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferAO1,InpAsSeries);
   ArraySetAsSeries(BufferClrAO1,InpAsSeries);
   ArraySetAsSeries(BufferAO2,InpAsSeries);
   ArraySetAsSeries(BufferClrAO2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_ao1=indicators.AddNewAO(NULL,PERIOD_CURRENT);
   handle_ao2=indicators.AddNewAO(InpSymbol,InpTimeframe);

//--- If failed to create indicator handles, return initialization error
   if(handle_ao1==INVALID_HANDLE || handle_ao2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_ao1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_ao2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_ao1,0,0,limit,BufferAO1,BufferClrAO1))
      return 0;
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_ao2,0,0,limit,BufferAO2,BufferClrAO2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_ao1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_ao1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ao1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ao1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_ao2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ao2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ao2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ao2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ao2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_ao1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_ao1);
   string ma2=indicators.Name(handle_ao2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Bears Power:

//+------------------------------------------------------------------+
//|                                           TestMSTFBearsPower.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot Bears1
#property indicator_label1  "Bears1"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrGray
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Bears2
#property indicator_label2  "Bears2"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  13;               /* Period                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferBears1[];
double         BufferBears2[];
//--- global variables
int handle_bears1;
int handle_bears2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferBears1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferBears2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferBears1,InpAsSeries);
   ArraySetAsSeries(BufferBears2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_bears1=indicators.AddNewBearsPower(NULL,PERIOD_CURRENT,InpPeriod);
   handle_bears2=indicators.AddNewBearsPower(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_bears1==INVALID_HANDLE || handle_bears2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_bears1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_bears2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bears1,0,0,limit,BufferBears1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bears2,0,0,limit,BufferBears2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_bears1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_bears1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_bears1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bears1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_bears2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bears2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_bears2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bears2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bears2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_bears1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_bears1);
   string ma2=indicators.Name(handle_bears2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Bollinger Bands:

//+------------------------------------------------------------------+
//|                                   TestMSTFBollingerBands.mq5.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   6
//--- enums

//--- plot BandsUpper1
#property indicator_label1  "BandsUpper1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrGreen
#property indicator_width1  1

//--- plot BandsLower1
#property indicator_label2  "BandsLower1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGreen
#property indicator_width2  1

//--- plot BandsMiddle1
#property indicator_label3  "BandsMiddle1"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGreen
#property indicator_width3  1

//--- plot BandsUpper2
#property indicator_label4  "BandsUpper2"
#property indicator_type4  DRAW_LINE
#property indicator_color4  clrDodgerBlue
#property indicator_width4  1

//--- plot BandsLower2
#property indicator_label5  "BandsLower2"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrDodgerBlue
#property indicator_width5  1

//--- plot BandsMiddle2
#property indicator_label6  "BandsMiddle2"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrDodgerBlue
#property indicator_width6  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* MA Symbol                  */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* MA Timeframe               */ 
input int                  InpPeriod      =  20;               /* Period                     */ 
input int                  InpShift       =  0;                /* MA Shift                   */ 
input double               InpDeviation   =  2.0;              /* Deviation                  */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferBandsUp1[];
double         BufferBandsDn1[];
double         BufferBandsMd1[];
double         BufferBandsUp2[];
double         BufferBandsDn2[];
double         BufferBandsMd2[];
//--- global variables
int handle_bands1;
int handle_bands2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign arrays BufferBandsUp1, BufferBandsDn1 and BufferBandsMd1 to plot buffers 0, 1 and 2, respectively
   SetIndexBuffer(0,BufferBandsUp1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferBandsDn1,INDICATOR_DATA);
   SetIndexBuffer(2,BufferBandsMd1,INDICATOR_DATA);
//--- Set arrays BufferBandsUp2, BufferBandsDn2 and BufferBandsMd2 to buffers 3, 4 and 5, respectively
   SetIndexBuffer(3,BufferBandsUp2,INDICATOR_DATA);
   SetIndexBuffer(4,BufferBandsDn2,INDICATOR_DATA);
   SetIndexBuffer(5,BufferBandsMd2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(4,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(5,PLOT_LINE_WIDTH,w2);
//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferBandsUp1,InpAsSeries);
   ArraySetAsSeries(BufferBandsDn1,InpAsSeries);
   ArraySetAsSeries(BufferBandsMd1,InpAsSeries);
   ArraySetAsSeries(BufferBandsUp2,InpAsSeries);
   ArraySetAsSeries(BufferBandsDn2,InpAsSeries);
   ArraySetAsSeries(BufferBandsMd2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_bands1=indicators.AddNewBands(NULL,PERIOD_CURRENT,InpPeriod,InpShift,InpDeviation,InpPrice);
   handle_bands2=indicators.AddNewBands(InpSymbol,InpTimeframe,InpPeriod,InpShift,InpDeviation,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_bands1==INVALID_HANDLE || handle_bands2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_bands1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_bands1,1);
   indicators.SetPlotLabelFromBuffer(2,handle_bands1,2);
   indicators.SetPlotLabelFromBuffer(3,handle_bands2,0);
   indicators.SetPlotLabelFromBuffer(4,handle_bands2,1);
   indicators.SetPlotLabelFromBuffer(5,handle_bands2,2);
//--- Set shifts for indicator lines
   indicators.SetPlotShift(0,InpShift);
   indicators.SetPlotShift(1,InpShift);
   indicators.SetPlotShift(2,InpShift);
   indicators.SetPlotShift(3,InpShift);
   indicators.SetPlotShift(4,InpShift);
   indicators.SetPlotShift(5,InpShift);

//--- Dashboard
//--- Create the panel
   int width=301;
   panel=new CDashboard(1,20,20,width,264);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bands1,0,0,limit,BufferBandsUp1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bands1,1,0,limit,BufferBandsDn1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bands1,2,0,limit,BufferBandsMd1))
      return 0;
   
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bands2,0,0,limit,BufferBandsUp2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bands2,1,0,limit,BufferBandsDn2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bands2,2,0,limit,BufferBandsMd2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_bands1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_bands1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_bands1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,150);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bands1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,150);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_bands2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bands2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_bands2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,150);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bands2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,150);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bands2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_bands1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_bands1);
   string ma2=indicators.Name(handle_bands2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,150);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Bulls Power:

//+------------------------------------------------------------------+
//|                                           TestMSTFBullsPower.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot Bulls1
#property indicator_label1  "Bulls1"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrGray
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Bulls2
#property indicator_label2  "Bulls2"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  13;               /* Period                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferBulls1[];
double         BufferBulls2[];
//--- global variables
int handle_bulls1;
int handle_bulls2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferBulls1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferBulls2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferBulls1,InpAsSeries);
   ArraySetAsSeries(BufferBulls2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_bulls1=indicators.AddNewBullsPower(NULL,PERIOD_CURRENT,InpPeriod);
   handle_bulls2=indicators.AddNewBullsPower(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_bulls1==INVALID_HANDLE || handle_bulls2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_bulls1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_bulls2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bulls1,0,0,limit,BufferBulls1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_bulls2,0,0,limit,BufferBulls2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_bulls1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_bulls1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_bulls1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bulls1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_bulls2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bulls2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_bulls2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bulls2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bulls2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_bulls1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_bulls1);
   string ma2=indicators.Name(handle_bulls2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:


También en este caso hemos tenido que cambiar los periodos del gráfico para dibujarlo.


Indicador Chaikin Oscillator:

//+------------------------------------------------------------------+
//|                                    TestMSTFChaikinOscillator.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot CHO1
#property indicator_label1  "CHO1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot CHO2
#property indicator_label2  "CHO2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpFastMAPeriod=  3;                /* Fast MA Period             */ 
input int                  InpSlowMAPeriod=  10;               /* Slow MA Period             */ 
input ENUM_MA_METHOD       InpMethod      =  MODE_EMA;         /* Method                     */ 
input ENUM_APPLIED_VOLUME  InpVolume      =  VOLUME_TICK;      /* Applied Volume             */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferCHO1[];
double         BufferCHO2[];
//--- global variables
int handle_cho1;
int handle_cho2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferCHO1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferCHO2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferCHO1,InpAsSeries);
   ArraySetAsSeries(BufferCHO2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_cho1=indicators.AddNewChaikin(NULL,PERIOD_CURRENT,InpFastMAPeriod,InpSlowMAPeriod,InpMethod,InpVolume);
   handle_cho2=indicators.AddNewChaikin(InpSymbol,InpTimeframe,InpFastMAPeriod,InpSlowMAPeriod,InpMethod,InpVolume);

//--- If failed to create indicator handles, return initialization error
   if(handle_cho1==INVALID_HANDLE || handle_cho2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_cho1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_cho2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_cho1,0,0,limit,BufferCHO1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_cho2,0,0,limit,BufferCHO2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_cho1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_cho1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_cho1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_cho1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_cho2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_cho2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_cho2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_cho2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_cho2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_cho1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_cho1);
   string ma2=indicators.Name(handle_cho2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Commodity Channel Index:

//+------------------------------------------------------------------+
//|                                TestMSTFCommodityChannelIndex.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot CCI1
#property indicator_label1  "CCI1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot CCI2
#property indicator_label2  "CCI2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_TYPICAL;    /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferCCI1[];
double         BufferCCI2[];
//--- global variables
int handle_cci1;
int handle_cci2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferCCI1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferCCI2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferCCI1,InpAsSeries);
   ArraySetAsSeries(BufferCCI2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_cci1=indicators.AddNewCCI(NULL,PERIOD_CURRENT,InpPeriod,InpPrice);
   handle_cci2=indicators.AddNewCCI(InpSymbol,InpTimeframe,InpPeriod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_cci1==INVALID_HANDLE || handle_cci2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_cci1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_cci2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_cci1,0,0,limit,BufferCCI1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_cci2,0,0,limit,BufferCCI2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_cci1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_cci1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_cci1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_cci1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_cci2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_cci2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_cci2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_cci2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_cci2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_cci1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_cci1);
   string ma2=indicators.Name(handle_cci2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador DeMarker:

//+------------------------------------------------------------------+
//|                                             TestMSTFDeMarker.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot DeM1
#property indicator_label1  "DeM1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot DeM2
#property indicator_label2  "DeM2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferDeM1[];
double         BufferDeM2[];
//--- global variables
int handle_dem1;
int handle_dem2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferDeM1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferDeM2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferDeM1,InpAsSeries);
   ArraySetAsSeries(BufferDeM2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_dem1=indicators.AddNewDeMarker(NULL,PERIOD_CURRENT,InpPeriod);
   handle_dem2=indicators.AddNewDeMarker(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_dem1==INVALID_HANDLE || handle_dem2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_dem1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_dem2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_dem1,0,0,limit,BufferDeM1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_dem2,0,0,limit,BufferDeM2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_dem1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_dem1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_dem1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_dem1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_dem2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_dem2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_dem2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_dem2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_dem2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_dem1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_dem1);
   string ma2=indicators.Name(handle_dem2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Envelopes:

//+------------------------------------------------------------------+
//|                                        TestMSTFEnvelopes.mq5.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   4
//--- enums

//--- plot EnvelopesUp1
#property indicator_label1  "EnvelopesUp1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_width1  1

//--- plot EnvelopesDown1
#property indicator_label2  "EnvelopesDown1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_width2  1

//--- plot EnvelopesUp2
#property indicator_label3  "EnvelopesUp2"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrDodgerBlue
#property indicator_width3  1

//--- plot EnvelopesDown2
#property indicator_label4  "EnvelopesDown2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrRed
#property indicator_width4  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* MA Symbol                  */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* MA Timeframe               */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input ENUM_MA_METHOD       InpMethod      =  MODE_SMA;         /* MA Method                  */ 
input int                  InpShift       =  0;                /* MA Shift                   */ 
input double               InpDeviation   =  0.1;              /* Deviation                  */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferEnvelopesUp1[];
double         BufferEnvelopesDn1[];
double         BufferEnvelopesUp2[];
double         BufferEnvelopesDn2[];
//--- global variables
int handle_envelopes1;
int handle_envelopes2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferEnvelopesUp1 and BufferEnvelopesDn1 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferEnvelopesUp1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferEnvelopesDn1,INDICATOR_DATA);
//--- Assign the BufferEnvelopesUp2 and BufferEnvelopesDn2 arrays to the plot buffers 2 and 3, respectively
   SetIndexBuffer(2,BufferEnvelopesUp2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferEnvelopesDn2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferEnvelopesUp1,InpAsSeries);
   ArraySetAsSeries(BufferEnvelopesDn1,InpAsSeries);
   ArraySetAsSeries(BufferEnvelopesUp2,InpAsSeries);
   ArraySetAsSeries(BufferEnvelopesDn2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_envelopes1=indicators.AddNewEnvelopes(NULL,PERIOD_CURRENT,InpPeriod,InpShift,InpMethod,InpPrice,InpDeviation);
   handle_envelopes2=indicators.AddNewEnvelopes(InpSymbol,InpTimeframe,InpPeriod,InpShift,InpMethod,InpPrice,InpDeviation);

//--- If failed to create indicator handles, return initialization error
   if(handle_envelopes1==INVALID_HANDLE || handle_envelopes2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_envelopes1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_envelopes1,1);
   indicators.SetPlotLabelFromBuffer(2,handle_envelopes2,0);
   indicators.SetPlotLabelFromBuffer(3,handle_envelopes2,1);
//--- Set shifts for indicator lines
   indicators.SetPlotShift(0,InpShift);
   indicators.SetPlotShift(1,InpShift);
   indicators.SetPlotShift(2,InpShift);
   indicators.SetPlotShift(3,InpShift);

//--- Dashboard
//--- Create the panel
   int width=301;
   panel=new CDashboard(1,20,20,width,264);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_envelopes1,0,0,limit,BufferEnvelopesUp1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_envelopes1,1,0,limit,BufferEnvelopesDn1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_envelopes2,0,0,limit,BufferEnvelopesUp2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_envelopes2,1,0,limit,BufferEnvelopesDn2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_envelopes1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_envelopes1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_envelopes1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,150);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_envelopes1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,150);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_envelopes2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_envelopes2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_envelopes2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,150);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_envelopes2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,150);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_envelopes2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_envelopes1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_envelopes1);
   string ma2=indicators.Name(handle_envelopes2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,150);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Force Index:

//+------------------------------------------------------------------+
//|                                           TestMSTFForceIndex.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot Force1
#property indicator_label1  "Force1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Force2
#property indicator_label2  "Force2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  13;               /* Period                     */ 
input ENUM_MA_METHOD       InpMethod      =  MODE_SMA;         /* Method                     */ 
input ENUM_APPLIED_VOLUME  InpVolume      =  VOLUME_TICK;      /* Applied Volume             */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferForce1[];
double         BufferForce2[];
//--- global variables
int handle_force1;
int handle_force2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferForce1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferForce2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferForce1,InpAsSeries);
   ArraySetAsSeries(BufferForce2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_force1=indicators.AddNewForce(NULL,PERIOD_CURRENT,InpPeriod,InpMethod,InpVolume);
   handle_force2=indicators.AddNewForce(InpSymbol,InpTimeframe,InpPeriod,InpMethod,InpVolume);

//--- If failed to create indicator handles, return initialization error
   if(handle_force1==INVALID_HANDLE || handle_force2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_force1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_force2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_force1,0,0,limit,BufferForce1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_force2,0,0,limit,BufferForce2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_force1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_force1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_force1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_force1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_force2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_force2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_force2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_force2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_force2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_force1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_force1);
   string ma2=indicators.Name(handle_force2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador MACD:

//+------------------------------------------------------------------+
//|                                                 TestMSTFMACD.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   4
//--- enums

//--- plot MACD1
#property indicator_label1  "MACD1"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Signal1
#property indicator_label2  "Signal1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_DOT
#property indicator_width2  1

//--- plot MACD2
#property indicator_label3  "MACD2"
#property indicator_type3   DRAW_HISTOGRAM
#property indicator_color3  clrPaleGreen
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

//--- plot Signal2
#property indicator_label4  "Signal2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrOrange
#property indicator_style4  STYLE_DOT
#property indicator_width4  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpFastPeriod  =  12;               /* Fast EMA Period            */ 
input int                  InpSlowPeriod  =  26;               /* Slow EMA Period            */ 
input int                  InpSignal      =  9;                /* MACD SMA                   */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferMACD1[];
double         BufferSig1[];
double         BufferMACD2[];
double         BufferSig2[];
//--- global variables
int macd1;
int macd2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferMACD1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferSig1,INDICATOR_DATA);
   SetIndexBuffer(2,BufferMACD2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferSig2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferMACD1,InpAsSeries);
   ArraySetAsSeries(BufferSig1,InpAsSeries);
   ArraySetAsSeries(BufferMACD2,InpAsSeries);
   ArraySetAsSeries(BufferSig2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   macd1=indicators.AddNewMACD(NULL,PERIOD_CURRENT,InpFastPeriod,InpSlowPeriod,InpSignal,InpPrice);
   macd2=indicators.AddNewMACD(InpSymbol,InpTimeframe,InpFastPeriod,InpSlowPeriod,InpSignal,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(macd1==INVALID_HANDLE || macd2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,macd1,0);
   indicators.SetPlotLabelFromBuffer(1,macd1,1);
   indicators.SetPlotLabelFromBuffer(2,macd2,0);
   indicators.SetPlotLabelFromBuffer(3,macd2,1);
      
//--- Dashboard
//--- Create the panel
   int width=301;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,macd1,0,0,limit,BufferMACD1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,macd1,1,0,limit,BufferSig1))
      return 0;
      
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,macd2,0,0,limit,BufferMACD2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,macd2,1,0,limit,BufferSig2))
      return 0;
      
//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(macd1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(macd1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(macd1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,macd1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(macd2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,macd2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(macd2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,macd2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,macd2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,macd1,0,0,index,value2,value21);
   string ma1=indicators.Name(macd1);
   string ma2=indicators.Name(macd2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador MA of Oscillator:

//+------------------------------------------------------------------+
//|                                       TestMSTFMAofOscillator.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot OsMA1
#property indicator_label1  "OsMA1"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot OsMA2
#property indicator_label2  "OsMA2"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpFastPeriod  =  12;               /* Fast MA Period             */ 
input int                  InpSlowPeriod  =  26;               /* Fast MA Period             */ 
input int                  InpSignalPeriod=  9;                /* Signal Period              */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferOsMA1[];
double         BufferOsMA2[];
//--- global variables
int handle_osma1;
int handle_osma2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferOsMA1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferOsMA2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferOsMA1,InpAsSeries);
   ArraySetAsSeries(BufferOsMA2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_osma1=indicators.AddNewOsMA(NULL,PERIOD_CURRENT,InpFastPeriod,InpSlowPeriod,InpSignalPeriod,InpPrice);
   handle_osma2=indicators.AddNewOsMA(InpSymbol,InpTimeframe,InpFastPeriod,InpSlowPeriod,InpSignalPeriod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_osma1==INVALID_HANDLE || handle_osma2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_osma1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_osma2,0);
      
//--- Dashboard
//--- Create the panel
   int width=301;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_osma1,0,0,limit,BufferOsMA1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_osma2,0,0,limit,BufferOsMA2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_osma1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_osma1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_osma1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_osma1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_osma2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_osma2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_osma2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_osma2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_osma2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_osma1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_osma1);
   string ma2=indicators.Name(handle_osma2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Market Facilitation Index:

//+------------------------------------------------------------------+
//|                              TestMSTFMarketFacilitationIndex.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   2
//--- enums

//--- plot AC1
#property indicator_label1  "BWMFI1"
#property indicator_type1   DRAW_COLOR_HISTOGRAM
//#property indicator_color1  clrLime,clrSaddleBrown,clrBlue,clrPink // analog in line 98
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot AC2
#property indicator_label2  "BWMFI2"
#property indicator_type2   DRAW_COLOR_HISTOGRAM
//#property indicator_color2  clrLime,clrSaddleBrown,clrBlue,clrPink // analog in line 99
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input ENUM_APPLIED_VOLUME  InpVolume      =  VOLUME_TICK;      /* Applied Volume             */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferBWMFI1[];
double         BufferClrBWMFI1[];
double         BufferBWMFI2[];
double         BufferClrBWMFI2[];
//--- global variables
int handle_bwmfi1;
int handle_bwmfi2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign arrays BufferBWMFI1 and BufferBWMFI2 to plot buffers 0 and 2, respectively,
//--- and color arrays BufferClrBWMFI1 and BufferClrBWMFI2 to buffers 1 and 3
   SetIndexBuffer(0,BufferBWMFI1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferClrBWMFI1,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,BufferBWMFI2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferClrBWMFI2,INDICATOR_COLOR_INDEX);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferBWMFI1,InpAsSeries);
   ArraySetAsSeries(BufferClrBWMFI1,InpAsSeries);
   ArraySetAsSeries(BufferBWMFI2,InpAsSeries);
   ArraySetAsSeries(BufferClrBWMFI2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_bwmfi1=indicators.AddNewBWMFI(NULL,PERIOD_CURRENT,InpVolume);
   handle_bwmfi2=indicators.AddNewBWMFI(InpSymbol,InpTimeframe,InpVolume);

//--- If failed to create indicator handles, return initialization error
   if(handle_bwmfi1==INVALID_HANDLE || handle_bwmfi2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set indicator line descriptions from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_bwmfi1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_bwmfi2,0);
//--- Set colors for indicator lines from the buffer color set of calculation part of created indicators
   indicators.SetPlotColorsFromBuffer(0,handle_bwmfi1,0);
   indicators.SetPlotColorsFromBuffer(1,handle_bwmfi2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_bwmfi1,0,0,limit,BufferBWMFI1,BufferClrBWMFI1))
      return 0;
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_bwmfi2,0,0,limit,BufferBWMFI2,BufferClrBWMFI2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_bwmfi1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_bwmfi1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_bwmfi1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bwmfi1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_bwmfi2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bwmfi2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_bwmfi2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_bwmfi2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_bwmfi2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_bwmfi1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_bwmfi1);
   string ma2=indicators.Name(handle_bwmfi2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Momentum:

//+------------------------------------------------------------------+
//|                                             TestMSTFMomentum.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot Momentum1
#property indicator_label1  "Momentum1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Momentum2
#property indicator_label2  "Momentum2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferMomentum1[];
double         BufferMomentum2[];
//--- global variables
int handle_mom1;
int handle_mom2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferMomentum1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferMomentum2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferMomentum1,InpAsSeries);
   ArraySetAsSeries(BufferMomentum2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_mom1=indicators.AddNewMomentum(NULL,PERIOD_CURRENT,InpPeriod,InpPrice);
   handle_mom2=indicators.AddNewMomentum(InpSymbol,InpTimeframe,InpPeriod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_mom1==INVALID_HANDLE || handle_mom2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_mom1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_mom2,0);
      
//--- Dashboard
//--- Create the panel
   int width=317;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_mom1,0,0,limit,BufferMomentum1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_mom2,0,0,limit,BufferMomentum2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_mom1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_mom1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_mom1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_mom1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_mom2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_mom2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_mom2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_mom2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_mom2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_mom1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_mom1);
   string ma2=indicators.Name(handle_mom2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Money Flow Index:

//+------------------------------------------------------------------+
//|                                       TestMSTFMoneyFlowIndex.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot MFI1
#property indicator_label1  "MFI1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot MFI2
#property indicator_label2  "MFI2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input ENUM_APPLIED_VOLUME  InpVolume      =  VOLUME_TICK;      /* Applied Volume             */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferMFI1[];
double         BufferMFI2[];
//--- global variables
int handle_mfi1;
int handle_mfi2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferMFI1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferMFI2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferMFI1,InpAsSeries);
   ArraySetAsSeries(BufferMFI2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_mfi1=indicators.AddNewMFI(NULL,PERIOD_CURRENT,InpPeriod,InpVolume);
   handle_mfi2=indicators.AddNewMFI(InpSymbol,InpTimeframe,InpPeriod,InpVolume);

//--- If failed to create indicator handles, return initialization error
   if(handle_mfi1==INVALID_HANDLE || handle_mfi2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_mfi1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_mfi2,0);
      
//--- Dashboard
//--- Create the panel
   int width=237;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_mfi1,0,0,limit,BufferMFI1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_mfi2,0,0,limit,BufferMFI2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_mfi1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_mfi1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_mfi1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_mfi1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_mfi2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_mfi2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_mfi2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_mfi2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_mfi2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_mfi1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_mfi1);
   string ma2=indicators.Name(handle_mfi2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicadores Moving Averages:

//+------------------------------------------------------------------+
//|                                       TestMSTFMovingAverages.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums
enum ENUM_USED_MA
  {
   USED_MA_AMA    =  IND_AMA,    // Adaptive Moving Average
   USED_MA_DEMA   =  IND_DEMA,   // Double Exponential Moving Average
   USED_MA_FRAMA  =  IND_FRAMA,  // Fractal Adaptive Moving Average
   USED_MA_MA     =  IND_MA,     // Moving Average
   USED_MA_TEMA   =  IND_TEMA,   // Triple Exponential Moving Average
   USED_MA_VIDYA  =  IND_VIDYA,  // Variable Index Dynamic Average
  };
//--- plot MA1
#property indicator_label1  "MA1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot MA2
#property indicator_label2  "MA2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input ENUM_USED_MA         InpIndicator   =  USED_MA_MA;       /* Used MA        */ // Type of moving average to use
input string               InpSymbol      =  NULL;             /* MA Symbol         */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* MA Timeframe      */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price    */ 
input ENUM_MA_METHOD       InpMethod      =  MODE_SMA;         /* MA Method        */ 
input int                  InpShift       =  0;                /* MA Shift         */ 
input bool                 InpAsSeries    =  true;             /* As Series flag   */ 

//--- indicator buffers
double         BufferMA1[];
double         BufferMA2[];
//--- global variables
int handle_ma1;
int handle_ma2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferMA1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferMA2,INDICATOR_DATA);
//--- sets indicator shift
   //PlotIndexSetInteger(0,PLOT_SHIFT,InpShift);   // analog in line 116
   //PlotIndexSetInteger(1,PLOT_SHIFT,InpShift);   // analog in line 117
//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferMA1,InpAsSeries);
   ArraySetAsSeries(BufferMA2,InpAsSeries);
   
//--- For different indicators, the dashboard width will be individual (due to the number of parameters in the description)
   int width=0;
//--- According on the indicator selected in the settings, create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   switch(InpIndicator)
     {
      case USED_MA_AMA     :
         handle_ma1=indicators.AddNewAMA(NULL,PERIOD_CURRENT,9,2,30,InpShift);
         handle_ma2=indicators.AddNewAMA(InpSymbol,InpTimeframe,9,2,30,InpShift);
         width=269;
        break;
      case USED_MA_DEMA    :
         handle_ma1=indicators.AddNewDEMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice);
         handle_ma2=indicators.AddNewDEMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice);
         width=255;
        break;
      case USED_MA_FRAMA   :
         handle_ma1=indicators.AddNewFrAMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice);
         handle_ma2=indicators.AddNewFrAMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice);
         width=259;
        break;
      case USED_MA_TEMA    :
         handle_ma1=indicators.AddNewTEMA(NULL,PERIOD_CURRENT,14,InpShift,InpPrice);
         handle_ma2=indicators.AddNewTEMA(InpSymbol,InpTimeframe,14,InpShift,InpPrice);
         width=253;
        break;
      case USED_MA_VIDYA   :
         handle_ma1=indicators.AddNewVIDyA(NULL,PERIOD_CURRENT,9,12,InpShift,InpPrice);
         handle_ma2=indicators.AddNewVIDyA(InpSymbol,InpTimeframe,9,12,InpShift,InpPrice);
         width=267;
        break;
      default:
         handle_ma1=indicators.AddNewMA(NULL,PERIOD_CURRENT,10,InpShift,InpMethod,InpPrice);
         handle_ma2=indicators.AddNewMA(InpSymbol,InpTimeframe,10,InpShift,InpMethod,InpPrice);
         width=231;
        break;
     }
//--- If failed to create indicator handles, return initialization error
   if(handle_ma1==INVALID_HANDLE || handle_ma2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_ma1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_ma2,0);
//--- Set shifts for indicator lines
   indicators.SetPlotShift(0,InpShift);
   indicators.SetPlotShift(1,InpShift);
      
//--- Dashboard
//--- Create the panel
   panel=new CDashboard(1,20,20,width,264);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   if(mouse_bar_index>WRONG_VALUE && mouse_bar_index<rates_total)
      DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ma1,0,0,limit,BufferMA1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_ma2,0,0,limit,BufferMA2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_ma1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_ma1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_ma1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ma1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_ma2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ma2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_ma2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_ma2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_ma2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_ma1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_ma1);
   string ma2=indicators.Name(handle_ma2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador On Balance Volume:

//+------------------------------------------------------------------+
//|                                      TestMSTFOnBalanceVolume.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- enums

//--- plot OBV1
#property indicator_label1  "OBV1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input ENUM_APPLIED_VOLUME  InpVolume      =  VOLUME_TICK;      /* Applied Volume             */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferOBV[];
//--- global variables
int handle_obv;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferOBV,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferOBV,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_obv=indicators.AddNewOBV(InpSymbol,InpTimeframe,InpVolume);

//--- If failed to create indicator handles, return initialization error
   if(handle_obv==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_obv,0);
      
//--- Dashboard
//--- Create the panel
   int width=237;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_obv,0,0,limit,BufferOBV))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_obv), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_obv,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_obv)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_obv,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:


Indicador Parabolic SAR:

//+------------------------------------------------------------------+
//|                                         TestMSTFParabolicSAR.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot PSAR1
#property indicator_label1  "PSAR1"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot MA2
#property indicator_label2  "PSAR2"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* MA Symbol                     */ // 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* MA Timeframe                  */ 
input uchar                InpArrowCode1  =  158;              /* SAR Senior period Arrow Code  */ 
input uchar                InpArrowCode2  =  159;              /* SAR Junior period Arrow Code  */ 
input bool                 InpAsSeries    =  true;             /* As Series flag                */ 

//--- indicator buffers
double         BufferPSAR1[];
double         BufferPSAR2[];
//--- global variables
int handle_psar1;
int handle_psar2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferPSAR1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferPSAR2,INDICATOR_DATA);
//--- Define the symbol code from the Wingdings font to draw in PLOT_ARROW
//--- Higher period is drawn with the first arrow code, the lower one with the second
   uchar code1=InpArrowCode1;
   uchar code2=InpArrowCode2;
   if(InpTimeframe>Period())
     {
      code1=InpArrowCode1;
      code2=InpArrowCode2;
     }
   else
     {
      code1=InpArrowCode2;
      code2=InpArrowCode1;
     }
   PlotIndexSetInteger(0,PLOT_ARROW,code1);
   PlotIndexSetInteger(1,PLOT_ARROW,code2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferPSAR1,InpAsSeries);
   ArraySetAsSeries(BufferPSAR2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_psar1=indicators.AddNewSAR(NULL,PERIOD_CURRENT);
   handle_psar2=indicators.AddNewSAR(InpSymbol,InpTimeframe);

//--- If failed to create indicator handles, return initialization error
   if(handle_psar1==INVALID_HANDLE || handle_psar2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_psar1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_psar2,0);
      
//--- Dashboard
//--- Create the panel
   int width=290;
   panel=new CDashboard(1,20,20,width,264);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_psar1,0,0,limit,BufferPSAR1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_psar2,0,0,limit,BufferPSAR2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_psar1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_psar1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_psar1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_psar1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_psar2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_psar2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_psar2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_psar2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_psar2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_psar1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_psar1);
   string ma2=indicators.Name(handle_psar2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Relative Strength Index:

//+------------------------------------------------------------------+
//|                                TestMSTFRelativeStrengthIndex.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot RSI1
#property indicator_label1  "RSI1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot RSI2
#property indicator_label2  "RSI2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferRSI1[];
double         BufferRSI2[];
//--- global variables
int handle_rsi1;
int handle_rsi2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferRSI1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferRSI2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferRSI1,InpAsSeries);
   ArraySetAsSeries(BufferRSI2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_rsi1=indicators.AddNewRSI(NULL,PERIOD_CURRENT,InpPeriod,InpPrice);
   handle_rsi2=indicators.AddNewRSI(InpSymbol,InpTimeframe,InpPeriod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_rsi1==INVALID_HANDLE || handle_rsi2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_rsi1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_rsi2,0);
      
//--- Dashboard
//--- Create the panel
   int width=231;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_rsi1,0,0,limit,BufferRSI1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_rsi2,0,0,limit,BufferRSI2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_rsi1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_rsi1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_rsi1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_rsi1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_rsi2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_rsi2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_rsi2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_rsi2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_rsi2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_rsi1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_rsi1);
   string ma2=indicators.Name(handle_rsi2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Relative Vigor Index:

//+------------------------------------------------------------------+
//|                                   TestMSTFRelativeVigorIndex.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   4
//--- enums

//--- plot RVI1
#property indicator_label1  "RVI1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Signal1
#property indicator_label2  "Signal1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrOrangeRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- plot RVI2
#property indicator_label3  "RVI2"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGreen
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

//--- plot Signal2
#property indicator_label4  "Signal2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrRed
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  10;               /* MA Period                  */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferRVI1[];
double         BufferSig1[];
double         BufferRVI2[];
double         BufferSig2[];
//--- global variables
int handle_rvi1;
int handle_rvi2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferRVI1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferSig1,INDICATOR_DATA);
   SetIndexBuffer(2,BufferRVI2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferSig2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferRVI1,InpAsSeries);
   ArraySetAsSeries(BufferSig1,InpAsSeries);
   ArraySetAsSeries(BufferRVI2,InpAsSeries);
   ArraySetAsSeries(BufferSig2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_rvi1=indicators.AddNewRVI(NULL,PERIOD_CURRENT,InpPeriod);
   handle_rvi2=indicators.AddNewRVI(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_rvi1==INVALID_HANDLE || handle_rvi2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_rvi1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_rvi1,1);
   indicators.SetPlotLabelFromBuffer(2,handle_rvi2,0);
   indicators.SetPlotLabelFromBuffer(3,handle_rvi2,1);
      
//--- Dashboard
//--- Create the panel
   int width=231;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_rvi1,0,0,limit,BufferRVI1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_rvi1,1,0,limit,BufferSig1))
      return 0;
      
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_rvi2,0,0,limit,BufferRVI2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_rvi2,1,0,limit,BufferSig2))
      return 0;
      
//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_rvi1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_rvi1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_rvi1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_rvi1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_rvi2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_rvi2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_rvi2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_rvi2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_rvi2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_rvi1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_rvi1);
   string ma2=indicators.Name(handle_rvi2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Standard Deviation:

//+------------------------------------------------------------------+
//|                                         TestMSTFStdDeviation.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot StdDev1
#property indicator_label1  "StdDev1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot StdDev2
#property indicator_label2  "StdDev2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  20;               /* Period                     */ 
input int                  InpShift       =  0;                /* Horizontal Shift           */ 
input ENUM_MA_METHOD       InpMethod      =  MODE_SMA;         /* Method                     */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferStdDev1[];
double         BufferStdDev2[];
//--- global variables
int handle_stddev1;
int handle_stddev2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferStdDev1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferStdDev2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferStdDev1,InpAsSeries);
   ArraySetAsSeries(BufferStdDev2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_stddev1=indicators.AddNewStdDev(NULL,PERIOD_CURRENT,InpPeriod,InpShift,InpMethod,InpPrice);
   handle_stddev2=indicators.AddNewStdDev(InpSymbol,InpTimeframe,InpPeriod,InpShift,InpMethod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_stddev1==INVALID_HANDLE || handle_stddev2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_stddev1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_stddev2,0);
      
//--- Dashboard
//--- Create the panel
   int width=290;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_stddev1,0,0,limit,BufferStdDev1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_stddev2,0,0,limit,BufferStdDev2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_stddev1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_stddev1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_stddev1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_stddev1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_stddev2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_stddev2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_stddev2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_stddev2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_stddev2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_stddev1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_stddev1);
   string ma2=indicators.Name(handle_stddev2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Stochastic Oscillator:

//+------------------------------------------------------------------+
//|                                 TestMSTFStochasticOdcillator.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   4
//--- enums

//--- plot RVI1
#property indicator_label1  "RVI1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrSeaGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot Signal1
#property indicator_label2  "Signal1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrOrangeRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- plot RVI2
#property indicator_label3  "RVI2"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGreen
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

//--- plot Signal2
#property indicator_label4  "Signal2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrRed
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpKPeriod     =  5;                /* %K Period                  */ 
input int                  InpDPeriod     =  3;                /* %D Period                  */ 
input int                  InpSlowing     =  3;                /* Slowing                    */ 
input ENUM_STO_PRICE       InpPrice       =  STO_LOWHIGH;      /* Applied Price              */ 
input ENUM_MA_METHOD       InpMethod      =  MODE_SMA;         /* Method                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferStoch1[];
double         BufferSig1[];
double         BufferStoch2[];
double         BufferSig2[];
//--- global variables
int handle_stoch1;
int handle_stoch2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferStoch1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferSig1,INDICATOR_DATA);
   SetIndexBuffer(2,BufferStoch2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferSig2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,w2);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferStoch1,InpAsSeries);
   ArraySetAsSeries(BufferSig1,InpAsSeries);
   ArraySetAsSeries(BufferStoch2,InpAsSeries);
   ArraySetAsSeries(BufferSig2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_stoch1=indicators.AddNewStochastic(NULL,PERIOD_CURRENT,InpKPeriod,InpDPeriod,InpSlowing,InpMethod,InpPrice);
   handle_stoch2=indicators.AddNewStochastic(InpSymbol,InpTimeframe,InpKPeriod,InpDPeriod,InpSlowing,InpMethod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_stoch1==INVALID_HANDLE || handle_stoch2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_stoch1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_stoch1,1);
   indicators.SetPlotLabelFromBuffer(2,handle_stoch2,0);
   indicators.SetPlotLabelFromBuffer(3,handle_stoch2,1);
      
//--- Dashboard
//--- Create the panel
   int width=271;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_stoch1,0,0,limit,BufferStoch1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_stoch1,1,0,limit,BufferSig1))
      return 0;
      
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_stoch2,0,0,limit,BufferStoch2))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_stoch2,1,0,limit,BufferSig2))
      return 0;
      
//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_stoch1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_stoch1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_stoch1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_stoch1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,190);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_stoch2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_stoch2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_stoch2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,190);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_stoch2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,190);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_stoch2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_stoch1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_stoch1);
   string ma2=indicators.Name(handle_stoch2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,190);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Triple Exponential Average:

//+------------------------------------------------------------------+
//|                             TestMSTFTripleExponentialAverage.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot TRIX1
#property indicator_label1  "TRIX1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot TRIX2
#property indicator_label2  "TRIX2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  13;               /* Period                     */ 
input ENUM_APPLIED_PRICE   InpPrice       =  PRICE_CLOSE;      /* Applied Price              */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferTRIX1[];
double         BufferTRIX2[];
//--- global variables
int handle_trix1;
int handle_trix2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferTRIX1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferTRIX2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferTRIX1,InpAsSeries);
   ArraySetAsSeries(BufferTRIX2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_trix1=indicators.AddNewTriX(NULL,PERIOD_CURRENT,InpPeriod,InpPrice);
   handle_trix2=indicators.AddNewTriX(InpSymbol,InpTimeframe,InpPeriod,InpPrice);

//--- If failed to create indicator handles, return initialization error
   if(handle_trix1==INVALID_HANDLE || handle_trix2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_trix1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_trix2,0);
      
//--- Dashboard
//--- Create the panel
   int width=247;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_trix1,0,0,limit,BufferTRIX1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_trix2,0,0,limit,BufferTRIX2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_trix1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_trix1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_trix1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_trix1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_trix2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_trix2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_trix2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_trix2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_trix2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_trix1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_trix1);
   string ma2=indicators.Name(handle_trix2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Volumes:

//+------------------------------------------------------------------+
//|                                              TestMSTFVolumes.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_plots   2
//--- enums

//--- plot AC1
#property indicator_label1  "Volumes1"
#property indicator_type1   DRAW_COLOR_HISTOGRAM
//#property indicator_color1  clrGreen,clrRed // analog in line 98
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot AC2
#property indicator_label2  "Volumes2"
#property indicator_type2   DRAW_COLOR_HISTOGRAM
//#property indicator_color2  clrGreen,clrRed // analog in line 99
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input ENUM_APPLIED_VOLUME  InpVolume      =  VOLUME_TICK;      /* Applied Volume             */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferVolumes1[];
double         BufferClrVolumes1[];
double         BufferVolumes2[];
double         BufferClrVolumes2[];
//--- global variables
int handle_volumes1;
int handle_volumes2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign arrays BufferVolumes1 and BufferVolumes2 to plot buffers 0 and 2, respectively,
//--- and color arrays BufferClrVolumes1 and BufferClrVolumes2 to buffers 1 and 3
   SetIndexBuffer(0,BufferVolumes1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferClrVolumes1,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,BufferVolumes2,INDICATOR_DATA);
   SetIndexBuffer(3,BufferClrVolumes2,INDICATOR_COLOR_INDEX);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferVolumes1,InpAsSeries);
   ArraySetAsSeries(BufferClrVolumes1,InpAsSeries);
   ArraySetAsSeries(BufferVolumes2,InpAsSeries);
   ArraySetAsSeries(BufferClrVolumes2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_volumes1=indicators.AddNewVolumes(NULL,PERIOD_CURRENT,InpVolume);
   handle_volumes2=indicators.AddNewVolumes(InpSymbol,InpTimeframe,InpVolume);

//--- If failed to create indicator handles, return initialization error
   if(handle_volumes1==INVALID_HANDLE || handle_volumes2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set indicator line descriptions from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_volumes1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_volumes2,0);
//--- Set colors for indicator lines from the buffer color set of calculation part of created indicators
   indicators.SetPlotColorsFromBuffer(0,handle_volumes1,0);
   indicators.SetPlotColorsFromBuffer(1,handle_volumes2,0);
      
//--- Dashboard
//--- Create the panel
   int width=267;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_volumes1,0,0,limit,BufferVolumes1,BufferClrVolumes1))
      return 0;
   if(!indicators.DataToColorBuffer(NULL,PERIOD_CURRENT,handle_volumes2,0,0,limit,BufferVolumes2,BufferClrVolumes2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_volumes1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_volumes1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_volumes1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,120);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_volumes1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,120);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_volumes2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_volumes2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_volumes2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,120);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_volumes2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,120);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_volumes2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_volumes1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_volumes1);
   string ma2=indicators.Name(handle_volumes2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,120);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Indicador Williams Percent Range:

//+------------------------------------------------------------------+
//|                                 TestMSTFWilliamsPercentRange.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
//--- enums

//--- plot WPR1
#property indicator_label1  "WPR1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- plot WPR2
#property indicator_label2  "WPR2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

//--- includes
#include <IndMSTF\IndMSTF.mqh>
#include <Dashboard\Dashboard.mqh>
//--- input parameters
input string               InpSymbol      =  NULL;             /* Symbol                     */ 
input ENUM_TIMEFRAMES      InpTimeframe   =  PERIOD_CURRENT;   /* Timeframe                  */ 
input int                  InpPeriod      =  14;               /* Period                     */ 
input uchar                InpLineWidth1  =  2;                /* Senior period Line Width   */ 
input uchar                InpLineWidth2  =  1;                /* Junior period Line Width   */ 
input bool                 InpAsSeries    =  true;             /* As Series flag             */ 

//--- indicator buffers
double         BufferWPR1[];
double         BufferWPR2[];
//--- global variables
int handle_wpr1;
int handle_wpr2;
CMSTFIndicators indicators;      // An instance of the indicator collection object
//--- variables for the panel
CDashboard *panel=NULL;          // Pointer to the panel object
int         mouse_bar_index;     // Index of the bar the data is taken from
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set a timer with an interval of 1 second
   EventSetTimer(1);
//--- Assign the BufferMA1 and BufferMA2 arrays to the plot buffers 0 and 1, respectively
   SetIndexBuffer(0,BufferWPR1,INDICATOR_DATA);
   SetIndexBuffer(1,BufferWPR2,INDICATOR_DATA);
//--- Set the line width
   int w1=0,w2=0;
   if(InpTimeframe>Period())
     {
      w1=InpLineWidth2;
      w2=InpLineWidth1;
     }
   else
     {
      w1=InpLineWidth1;
      w2=InpLineWidth2;
     }
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,w1);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,w2);
//--- sets indicator shift

//--- Set the timeseries flags for the indicator buffer arrays (for testing, to see that there is no difference)
   ArraySetAsSeries(BufferWPR1,InpAsSeries);
   ArraySetAsSeries(BufferWPR2,InpAsSeries);
   
//--- Create two indicators of the same type
//--- The first one is calculated on the current chart symbol/period, the second - on those specified in the settings
   handle_wpr1=indicators.AddNewWPR(NULL,PERIOD_CURRENT,InpPeriod);
   handle_wpr2=indicators.AddNewWPR(InpSymbol,InpTimeframe,InpPeriod);

//--- If failed to create indicator handles, return initialization error
   if(handle_wpr1==INVALID_HANDLE || handle_wpr2==INVALID_HANDLE)
      return INIT_FAILED;
//--- Set descriptions for indicator lines from buffer descriptions of calculation part of created indicators
   indicators.SetPlotLabelFromBuffer(0,handle_wpr1,0);
   indicators.SetPlotLabelFromBuffer(1,handle_wpr2,0);
      
//--- Dashboard
//--- Create the panel
   int width=231;
   panel=new CDashboard(1,20,20,width,264,0);
   if(panel==NULL)
     {
      Print("Error. Failed to create panel object");
      return INIT_FAILED;
     }
//--- Set font parameters
   panel.SetFontParams("Calibri",9);
//--- Display the panel with the "Symbol, Timeframe description" header text
   panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7));

//--- Create a table with ID 0 to display bar data in it
   panel.CreateNewTable(0);
//--- Draw a table with ID 0 on the panel background
   panel.DrawGrid(0,2,20,6,2,18,width/2-2);

//--- Create a table with ID 1 to display the data of indicator 1
   panel.CreateNewTable(1);
//--- Get the Y2 table coordinate with ID 0 and
//--- set the Y1 coordinate for the table with ID 1
   int y1=panel.TableY2(0)+22;
//--- Draw a table with ID 1 on the panel background
   panel.DrawGrid(1,2,y1,2,2,18,width/2-2);

//--- Create a table with ID 2 to display the data of indicator 2
   panel.CreateNewTable(2);
//--- Get the Y2 coordinate of the table with ID 1 and
//--- set the Y1 coordinate for the table with ID 2
   int y2=panel.TableY2(1)+3;
//--- Draw a table with ID 2 on the background of the dashboard
   panel.DrawGrid(2,2,y2,3,2,18,width/2-2);
   
//--- Initialize the variable with the index of the mouse cursor bar
   mouse_bar_index=0;
//--- Display the data of the current bar on the panel
   DrawData(mouse_bar_index,TimeCurrent());

//--- Successful initialization
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Delete the timer
   EventKillTimer();
//--- If the panel object exists, delete it
   if(panel!=NULL)
      delete panel;
//--- Delete all comments
   Comment("");
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//--- Number of bars for calculation
   int limit=rates_total-prev_calculated;
//--- If limit > 1, then this is the first calculation or change in the history
   if(limit>1)
     {
      //--- specify all the available history for calculation
      limit=rates_total-1;
      /*
      // If the indicator has any buffers that display other calculations (not multi-indicators),
      // initialize them here with the "empty" value set for these buffers
      */
     }
//--- Calculate all created multi-symbol multi-period indicators
   if(!indicators.Calculate())
      return 0;

//--- Display the bar data under cursor (or current bar if cursor is outside the chart) on the dashboard
   DrawData(mouse_bar_index,time[mouse_bar_index]);

//--- From buffers of calculated indicators, output data to indicator buffers
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_wpr1,0,0,limit,BufferWPR1))
      return 0;
   if(!indicators.DataToBuffer(NULL,PERIOD_CURRENT,handle_wpr2,0,0,limit,BufferWPR2))
      return 0;

//--- return value of prev_calculated for the next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   | 
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Call the indicator collection timer
   indicators.OnTimer();
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Handling the panel
//--- Call the panel event handler
   panel.OnChartEvent(id,lparam,dparam,sparam);

//--- If the cursor moves or a click is made on the chart
   if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK)
     {
      //--- Declare the variables to record time and price coordinates in them
      datetime time=0;
      double price=0;
      int wnd=0;
      //--- If the cursor coordinates are converted to date and time
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- write the bar index where the cursor is located to a global variable
         mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         //--- Display the bar data under the cursor on the panel 
         DrawData(mouse_bar_index,time);
        }
     }

//--- If we received a custom event, display the appropriate message in the journal
   if(id>CHARTEVENT_CUSTOM)
     {
      //--- Here we can implement handling a click on the close button on the panel
      PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam);
     }
  }
//+------------------------------------------------------------------+
//| Display data from the specified timeseries index to the panel    |
//+------------------------------------------------------------------+
void DrawData(const int index,const datetime time)
  {
//--- Declare the variables to receive data in them
   MqlRates rates[1];

//--- Exit if unable to get the bar data by the specified index
   if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1)
      return;

//--- Set font parameters for bar and indicator data headers
   int  size=0;
   uint flags=0;
   uint angle=0;
   string name=panel.FontParams(size,flags,angle);
   panel.SetFontParams(name,9,FW_BOLD);
   panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6);
   panel.DrawText("Indicators data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6);
//--- Set font parameters for bar and indicator data
   panel.SetFontParams(name,9);

//--- Display the data of the specified bar in table 0 on the panel
   panel.DrawText("Date",  panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_DATE),     panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90);
   panel.DrawText("Time",  panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString(  rates[0].time,TIME_MINUTES),  panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90);
   panel.DrawText("Open",  panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()),      panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90);
   panel.DrawText("High",  panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()),      panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90);
   panel.DrawText("Low",   panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()),       panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90);
   panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()),     panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90);

//--- Output the data of indicator 1 from the specified bar into table 1
   panel.DrawText(indicators.Title(handle_wpr1), panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2);
   double value1=indicators.GetData(handle_wpr1,0,0,index);
   string value_str1=(value1!=EMPTY_VALUE ? DoubleToString(value1,indicators.Digits(handle_wpr1)) : " ");
   panel.DrawText(value_str1,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 1 line state
   panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2);
   ENUM_LINE_STATE state1=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_wpr1,0,0,index);
   panel.DrawText(BufferLineStateDescription(state1),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,110);
   
//--- Output the data of indicator 2 from the specified bar into table 2
   panel.DrawText(indicators.Title(handle_wpr2), panel.CellX(2,0,0)+2, panel.CellY(2,0,0)+2);
   double value2=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_wpr2,0,0,index);
   string value_str2=(value2!=EMPTY_VALUE ? DoubleToString(value2,indicators.Digits(handle_wpr2)) : " ");
   panel.DrawText(value_str2,panel.CellX(2,0,1)+2,panel.CellY(2,0,1)+2,clrNONE,110);
   
//--- Display a description of the indicator 2 line state
   panel.DrawText("Line state", panel.CellX(2,1,0)+2, panel.CellY(2,1,0)+2);
   ENUM_LINE_STATE state2=indicators.BufferLineState(Symbol(),PERIOD_CURRENT,handle_wpr2,0,0,index);
   panel.DrawText(BufferLineStateDescription(state2),panel.CellX(2,1,1)+2,panel.CellY(2,1,1)+2,clrNONE,110);
   
//--- Display description of relationship between indicator 1 line relative to indicator 2 line
   double value21=indicators.GetDataTo(Symbol(),PERIOD_CURRENT,handle_wpr2,0,0,index+1);
   ENUM_LINE_STATE stateR=indicators.BufferLineStateRelative(Symbol(),PERIOD_CURRENT,handle_wpr1,0,0,index,value2,value21);
   string ma1=indicators.Name(handle_wpr1);
   string ma2=indicators.Name(handle_wpr2);
   string state_relative=
     (
      stateR==LINE_STATE_ABOVE      ? StringFormat("%s1 > %s2",ma1,ma2)   :
      stateR==LINE_STATE_BELOW      ? StringFormat("%s1 < %s2",ma1,ma2)           :
      stateR==LINE_STATE_CROSS_DOWN ? "Top-down crossing"   :
      stateR==LINE_STATE_CROSS_UP   ? "Bottom-up crossing"  :
      BufferLineStateDescription(stateR)
     );
   panel.DrawText(StringFormat("%s1 vs %s2",ma1,ma2), panel.CellX(2,2,0)+2, panel.CellY(2,2,0)+2);
   panel.DrawText(state_relative, panel.CellX(2,2,1)+2, panel.CellY(2,2,1)+2,clrNONE,110);
   
//--- Redraw the chart to immediately display all changes on the panel
   ChartRedraw(ChartID());
  }
//+------------------------------------------------------------------+

Tras compilar y ejecutar el indicador en el gráfico M1 y el periodo del gráfico seleccionado para el cálculo M5, podemos ver:



Conclusión

Aún no se han creado todos los indicadores estándar, y el concepto no funciona para todos los estilos de dibujo. Más tarde implementaremos los otros estilos de dibujado y el resto de los indicadores. Lamentablemente, no siempre es posible calcular y dibujar un indicador calculado sobre un símbolo y un marco temporal no actuales. A veces hay que cambiar el marco temporal del gráfico. El indicador en sí (su parte de cálculo) ya se ha calculado para toda la historia disponible, pero CopyBuffer() retornará -1 cuando no haya error de datos. Esto no se había visto antes. Hasta ahora este problema no se ha resuelto: solo cambiar el periodo del gráfico ayuda para que CopyBuffer() pueda copiar los datos existentes y ya calculados del indicador.


Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/13824

Stop Loss y Take Profit amigables para el tráder Stop Loss y Take Profit amigables para el tráder
El stop loss y el take profit pueden tener una influencia significativa en los resultados de las transacciones. En este artículo, veremos varias formas de buscar órdenes stop óptimas.
Cuantificación en el aprendizaje automático (Parte 2): Preprocesamiento de datos, selección de tablas, entrenamiento del modelo CatBoost Cuantificación en el aprendizaje automático (Parte 2): Preprocesamiento de datos, selección de tablas, entrenamiento del modelo CatBoost
En este artículo, hablaremos de la aplicación práctica de la cuantificación en la construcción de modelos arbóreos. Asimismo, analizaremos los métodos de selección de tablas cuantificadas y el preprocesamiento de datos. El material se presentará sin fórmulas matemáticas complejas, en un lenguaje accesible.
Aprendiendo MQL5 de principiante a profesional (Parte I): Comenzamos a programar Aprendiendo MQL5 de principiante a profesional (Parte I): Comenzamos a programar
Este artículo supone la introducción a toda una serie de artículos sobre programación. Partimos del supuesto de que el lector no se ha enfrentado nunca a la programación. Así que empezaremos por lo básico. Nivel de conocimientos de programación: principiante absoluto.
Cuantificación en el aprendizaje automático (Parte 1): Teoría, ejemplo de código, análisis sintáctico de la aplicación CatBoost Cuantificación en el aprendizaje automático (Parte 1): Teoría, ejemplo de código, análisis sintáctico de la aplicación CatBoost
En este artículo, hablaremos de la aplicación teórica de la cuantificación en la construcción de modelos arbóreos. Asimismo, analizaremos los métodos de cuantificación implementados en CatBoost. El material se presentará sin fórmulas matemáticas complejas, en un lenguaje accesible.