English Русский 中文 Deutsch 日本語 Português
Otras clases en la biblioteca DoEasy (Parte 68): Clase de objeto de ventana de gráfico y clases de objetos de indicador en la ventana del gráfico

Otras clases en la biblioteca DoEasy (Parte 68): Clase de objeto de ventana de gráfico y clases de objetos de indicador en la ventana del gráfico

MetaTrader 5Ejemplos | 2 junio 2021, 08:21
799 0
Artyom Trishkin
Artyom Trishkin

Contenido


Concepto

En el último artículo, comenzamos a desarrollar la clase de objeto de gráfico y creamos su primera versión. El objeto describe un gráfico del terminal con todos sus parámetros. Asimismo, nos permite gestionar sus propiedades, a saber, obtener y establecer los parámetros del tamaño de la ventana y la visualización de los elementos del gráfico.

No obstante, en un gráfico podemos tener varias ventanas en las que también se colocan indicadores. Estas ventanas tienen sus propios tamaños y, por el momento, nuestro objeto gráfico podrá simplemente retornar los parámetros de la subventana indicada que se encuentre en ella, asi como controlar su altura. En una misma subventana, podemos colocar un número diferente de indicadores (como en la ventana principal del gráfico), y debemos tener esto en cuenta para que al acceder al objeto del gráfico, podamos solicitar la ventana necesaria ubicada en el gráfico, y desde el objeto de la ventana resultante, solicitar una lista con sus indicadores y obtener el identificador del deseado, pudiendo así continuar el trabajo con él.

Hoy, vamos a crear dos objetos: un objeto de indicador en la ventana del gráfico que describirá algunos parámetros del indicador para su identificación, y un objeto de ventana del gráfico que almacenará sus dimensiones y una lista con los indicadores (objetos de indicador en la ventana del gráfico) adjuntos al mismo. El objeto de gráfico que comenzamos a crear en el último artículo tendrá una lista de objetos de ventana adjunta (incluida la ventana principal del gráfico).

En el futuro, esta jerarquía facilitará sustancialmente nuestro trabajo con muchos gráficos y sus subventanas con listas de indicadores en ellos. Por desgracia, es demasiado pronto para crear la colección de clases de objetos de gráfico que anunciamos en el último artículo; necesitamos completar todas las modificaciones principales del objeto de gráfico, cosa que haremos hoy.


Clase de ventana de gráfico con objetos de indicador en la ventana

En pimer lugar, completaremos la biblioteca con todos los textos necesarios de los mensajes.
En el archivo \MQL5\Include\DoEasy\Data.mqh escribimos los índices de los nuevos mensajes:

   MSG_CHART_OBJ_CHART_WINDOW,                        // Main chart window
   MSG_CHART_OBJ_CHART_SUBWINDOW,                     // Chart subwindow
   MSG_CHART_OBJ_CHART_SUBWINDOWS_NUM,                // Subwindows
   MSG_CHART_OBJ_INDICATORS_MW_NAME_LIST,             // Indicators in the main chart window
   MSG_CHART_OBJ_INDICATORS_SW_NAME_LIST,             // Indicators in the chart window
   MSG_CHART_OBJ_INDICATOR,                           // Indicator
   MSG_CHART_OBJ_INDICATORS_TOTAL,                    // Indicators
   MSG_CHART_OBJ_WINDOW_N,                            // Window
   MSG_CHART_OBJ_INDICATORS_NONE,                     // No indicators
  
  };
//+------------------------------------------------------------------+

y los textos de los mensajes que se corresponden con los índices nuevamente añadidos:

   {"Главное окно графика","Main chart window"},
   {"Подокно графика","Chart subwindow"},
   {"Подокон","Subwindows"},
   {"Индикаторы в главном окне графика","Indicators in the main chart window"},
   {"Индикаторы в окне графика","Indicators in the chart window"},
   {"Индикатор","Indicator"},
   {"Индикаторов","Indicators total"},
   {"Окно","Window"},
   {"Отсутствуют","No indicators"},
   
  };
//+---------------------------------------------------------------------+

Al crear la enumeración de las propiedades de tipo entero del objeto de gráfico, hemos omitido a propósito tres propiedades que son propias no solo del objeto de la ventana principal, sino también de todas las subventanas del gráfico:

  • Visibilidad de las subventanas,
  • Distancia en píxeles a lo largo del eje vertical Y entre el marco superior de la subventana del indicador y el marco superior de la ventana principal del gráfico.
  • Altura del gráfico en píxeles.

Precisamente estas propiedades serán las propiedades principales del objeto de la ventana del gráfico (excepto la visibilidad de la subventana, que reconoceremos a partir del objeto de gráfico). La lista de ventanas de gráficos estará presente en cada objeto de gráfico, y cada objeto tendrá sus propios valores de estas propiedades. Al mismo tiempo, cada objeto de ventana contendrá una lista de indicadores adjuntos a esta ventana, y necesitaremos especificar las constantes adicionales en la enumeración de las propiedades de tipo entero y string del objeto de gráfico.

En el archivo \MQL5\Include\DoEasy\Defines.mqh, comentamos las propiedades que habíamos definido anteriormente, pero que no habíamos comentado, a saber, las propiedades del objeto de ventana del gráfico. Luego, añadimos las nuevas para el objeto de indicador en la ventana del gráfico:

//+------------------------------------------------------------------+
//| Chart integer property                                           |
//+------------------------------------------------------------------+
enum ENUM_CHART_PROP_INTEGER
  {
   CHART_PROP_ID = 0,                                 // Chart ID
   CHART_PROP_TIMEFRAME,                              // Chart timeframe
   CHART_PROP_SHOW,                                   // Price chart drawing
   CHART_PROP_IS_OBJECT,                              // Chart object (OBJ_CHART) identification attribute
   CHART_PROP_BRING_TO_TOP,                           // Show chart above all others
   CHART_PROP_CONTEXT_MENU,                           // Enable/disable access to the context menu using the right click 
   CHART_PROP_CROSSHAIR_TOOL,                         // Enable/disable access to the Crosshair tool using the middle click
   CHART_PROP_MOUSE_SCROLL,                           // Scroll the chart horizontally using the left mouse button
   CHART_PROP_EVENT_MOUSE_WHEEL,                      // Send messages about mouse wheel events (CHARTEVENT_MOUSE_WHEEL) to all MQL5 programs on a chart
   CHART_PROP_EVENT_MOUSE_MOVE,                       // Send messages about mouse button click and movement events (CHARTEVENT_MOUSE_MOVE) to all MQL5 programs on a chart
   CHART_PROP_EVENT_OBJECT_CREATE,                    // Send messages about the graphical object creation event (CHARTEVENT_OBJECT_CREATE) to all MQL5 programs on a chart
   CHART_PROP_EVENT_OBJECT_DELETE,                    // Send messages about the graphical object destruction event (CHARTEVENT_OBJECT_DELETE) to all MQL5 programs on a chart
   CHART_PROP_MODE,                                   // Type of the chart (candlesticks, bars or line (ENUM_CHART_MODE))
   CHART_PROP_FOREGROUND,                             // Price chart in the foreground
   CHART_PROP_SHIFT,                                  // Mode of shift of the price chart from the right border
   CHART_PROP_AUTOSCROLL,                             // The mode of automatic shift to the right border of the chart
   CHART_PROP_KEYBOARD_CONTROL,                       // Allow managing the chart using a keyboard
   CHART_PROP_QUICK_NAVIGATION,                       // Allow the chart to intercept Space and Enter key strokes to activate the quick navigation bar
   CHART_PROP_SCALE,                                  // Scale
   CHART_PROP_SCALEFIX,                               // Fixed scale mode
   CHART_PROP_SCALEFIX_11,                            // 1:1 scale mode
   CHART_PROP_SCALE_PT_PER_BAR,                       // The mode of specifying the scale in points per bar
   CHART_PROP_SHOW_TICKER,                            // Display a symbol ticker in the upper left corner
   CHART_PROP_SHOW_OHLC,                              // Display OHLC values in the upper left corner
   CHART_PROP_SHOW_BID_LINE,                          // Display Bid value as a horizontal line on the chart
   CHART_PROP_SHOW_ASK_LINE,                          // Display Ask value as a horizontal line on a chart
   CHART_PROP_SHOW_LAST_LINE,                         // Display Last value as a horizontal line on a chart
   CHART_PROP_SHOW_PERIOD_SEP,                        // Display vertical separators between adjacent periods
   CHART_PROP_SHOW_GRID,                              // Display a grid on the chart
   CHART_PROP_SHOW_VOLUMES,                           // Display volumes on a chart
   CHART_PROP_SHOW_OBJECT_DESCR,                      // Display text descriptions of objects
   CHART_PROP_VISIBLE_BARS,                           // Number of bars on a chart that are available for display
   CHART_PROP_WINDOWS_TOTAL,                          // The total number of chart windows including indicator subwindows
   CHART_PROP_WINDOW_IS_VISIBLE,                      // Subwindow visibility
   CHART_PROP_WINDOW_HANDLE,                          // Chart window handle
   CHART_PROP_WINDOW_YDISTANCE,                       // Distance in Y axis pixels between the upper frame of the indicator subwindow and the upper frame of the chart main window
   CHART_PROP_FIRST_VISIBLE_BAR,                      // Number of the first visible bar on the chart
   CHART_PROP_WIDTH_IN_BARS,                          // Width of the chart in bars
   CHART_PROP_WIDTH_IN_PIXELS,                        // Width of the chart in pixels
   CHART_PROP_HEIGHT_IN_PIXELS,                       // Height of the chart in pixels
   CHART_PROP_COLOR_BACKGROUND,                       // Color of background of the chart
   CHART_PROP_COLOR_FOREGROUND,                       // Color of axes, scale and OHLC line
   CHART_PROP_COLOR_GRID,                             // Grid color
   CHART_PROP_COLOR_VOLUME,                           // Color of volumes and position opening levels
   CHART_PROP_COLOR_CHART_UP,                         // Color for the up bar, shadows and body borders of bull candlesticks
   CHART_PROP_COLOR_CHART_DOWN,                       // Color of down bar, its shadow and border of body of the bullish candlestick
   CHART_PROP_COLOR_CHART_LINE,                       // Color of the chart line and the Doji candlesticks
   CHART_PROP_COLOR_CANDLE_BULL,                      // Color of body of a bullish candlestick
   CHART_PROP_COLOR_CANDLE_BEAR,                      // Color of body of a bearish candlestick
   CHART_PROP_COLOR_BID,                              // Color of the Bid price line
   CHART_PROP_COLOR_ASK,                              // Color of the Ask price line
   CHART_PROP_COLOR_LAST,                             // Color of the last performed deal's price line (Last)
   CHART_PROP_COLOR_STOP_LEVEL,                       // Color of stop order levels (Stop Loss and Take Profit)
   CHART_PROP_SHOW_TRADE_LEVELS,                      // Display trade levels on the chart (levels of open positions, Stop Loss, Take Profit and pending orders)
   CHART_PROP_DRAG_TRADE_LEVELS,                      // Enable the ability to drag trading levels on a chart using mouse
   CHART_PROP_SHOW_DATE_SCALE,                        // Display the time scale on a chart
   CHART_PROP_SHOW_PRICE_SCALE,                       // Display a price scale on a chart
   CHART_PROP_SHOW_ONE_CLICK,                         // Display the quick trading panel on the chart
   CHART_PROP_IS_MAXIMIZED,                           // Chart window maximized
   CHART_PROP_IS_MINIMIZED,                           // Chart window minimized
   CHART_PROP_IS_DOCKED,                              // Chart window docked
   CHART_PROP_FLOAT_LEFT,                             // Left coordinate of the undocked chart window relative to the virtual screen
   CHART_PROP_FLOAT_TOP,                              // Upper coordinate of the undocked chart window relative to the virtual screen
   CHART_PROP_FLOAT_RIGHT,                            // Right coordinate of the undocked chart window relative to the virtual screen
   CHART_PROP_FLOAT_BOTTOM,                           // Bottom coordinate of the undocked chart window relative to the virtual screen
   //--- CWndInd
   CHART_PROP_WINDOW_IND_HANDLE,                      // Indicator handle in the chart window
   CHART_PROP_WINDOW_IND_INDEX,                       // Indicator index in the chart window
  };
#define CHART_PROP_INTEGER_TOTAL (67)                 // Total number of integer properties
#define CHART_PROP_INTEGER_SKIP  (0)                  // Number of integer DOM properties not used in sorting
//+------------------------------------------------------------------+
//| Chart real properties                                            |
//+------------------------------------------------------------------+
enum ENUM_CHART_PROP_DOUBLE
  {
   CHART_PROP_SHIFT_SIZE = CHART_PROP_INTEGER_TOTAL,  // Shift size of the zero bar from the right border in %
   CHART_PROP_FIXED_POSITION,                         // Chart fixed position from the left border in %
   CHART_PROP_FIXED_MAX,                              // Chart fixed maximum
   CHART_PROP_FIXED_MIN,                              // Chart fixed minimum
   CHART_PROP_POINTS_PER_BAR,                         // Scale in points per bar
   CHART_PROP_PRICE_MIN,                              // Chart minimum
   CHART_PROP_PRICE_MAX,                              // Chart maximum
  };
#define CHART_PROP_DOUBLE_TOTAL  (7)                  // Total number of real properties
#define CHART_PROP_DOUBLE_SKIP   (0)                  // Number of real properties not used in sorting
//+------------------------------------------------------------------+
//| Chart string properties                                          |
//+------------------------------------------------------------------+
enum ENUM_CHART_PROP_STRING
  {
   CHART_PROP_COMMENT = (CHART_PROP_INTEGER_TOTAL+CHART_PROP_DOUBLE_TOTAL), // Chart comment text
   CHART_PROP_EXPERT_NAME,                            // Name of an EA launched on the chart
   CHART_PROP_SCRIPT_NAME,                            // Name of a script launched on the chart
   CHART_PROP_INDICATOR_NAME,                         // Name of an indicator launched on the chart
   CHART_PROP_SYMBOL,                                 // Chart symbol
  };
#define CHART_PROP_STRING_TOTAL  (5)                  // Total number of string properties
//+------------------------------------------------------------------+

Por consiguiente, modificaremos los valores del número de propiedades a cuyas listas hemos añadido las nuevas constantes: hemos aumentado el número de propiedades de tipo entero de 62 a 67, y el número de propiedades de tipo string de 4 a 5.

Añadimos a la enumeración de posibles criterios de clasificación de los objetos de gráfico nuevos criterios que se correspondan con las propiedades nuevamente añadidas:

//+------------------------------------------------------------------+
//| Possible chart sorting criteria                                  |
//+------------------------------------------------------------------+
#define FIRST_CHART_DBL_PROP  (CHART_PROP_INTEGER_TOTAL-CHART_PROP_INTEGER_SKIP)
#define FIRST_CHART_STR_PROP  (CHART_PROP_INTEGER_TOTAL-CHART_PROP_INTEGER_SKIP+CHART_PROP_DOUBLE_TOTAL-CHART_PROP_DOUBLE_SKIP)
enum ENUM_SORT_CHART_MODE
  {
//--- Sort by integer properties
   SORT_BY_CHART_SHOW = 0,                            // Sort by the price chart drawing attribute
   SORT_BY_CHART_IS_OBJECT,                           // Sort by chart object (OBJ_CHART) identification attribute
   SORT_BY_CHART_BRING_TO_TOP,                        // Sort by the flag of displaying a chart above all others
   SORT_BY_CHART_CONTEXT_MENU,                        // Sort by the flag of enabling/disabling access to the context menu using the right click
   SORT_BY_CHART_CROSSHAIR_TOO,                       // Sort by the flag of enabling/disabling access to the Crosshair tool using the middle click
   SORT_BY_CHART_MOUSE_SCROLL,                        // Sort by the flag of scrolling the chart horizontally using the left mouse button
   SORT_BY_CHART_EVENT_MOUSE_WHEEL,                   // Sort by the flag of sending messages about mouse wheel events to all MQL5 programs on a chart
   SORT_BY_CHART_EVENT_MOUSE_MOVE,                    // Sort by the flag of sending messages about mouse button click and movement events to all MQL5 programs on a chart
   SORT_BY_CHART_EVENT_OBJECT_CREATE,                 // Sort by the flag of sending messages about the graphical object creation event to all MQL5 programs on a chart
   SORT_BY_CHART_EVENT_OBJECT_DELETE,                 // Sort by the flag of sending messages about the graphical object destruction event to all MQL5 programs on a chart
   SORT_BY_CHART_MODE,                                // Sort by chart type
   SORT_BY_CHART_FOREGROUND,                          // Sort by the "Price chart in the foreground" flag
   SORT_BY_CHART_SHIFT,                               // Sort by the "Mode of shift of the price chart from the right border" flag
   SORT_BY_CHART_AUTOSCROLL,                          // Sort by the "The mode of automatic shift to the right border of the chart" flag
   SORT_BY_CHART_KEYBOARD_CONTROL,                    // Sort by the flag allowing the chart management using a keyboard
   SORT_BY_CHART_QUICK_NAVIGATION,                    // Sort by the flag allowing the chart to intercept Space and Enter key strokes to activate the quick navigation bar
   SORT_BY_CHART_SCALE,                               // Sort by scale
   SORT_BY_CHART_SCALEFIX,                            // Sort by the fixed scale flag
   SORT_BY_CHART_SCALEFIX_11,                         // Sort by the 1:1 scale flag
   SORT_BY_CHART_SCALE_PT_PER_BAR,                    // Sort by the flag of specifying the scale in points per bar
   SORT_BY_CHART_SHOW_TICKER,                         // Sort by the flag displaying a symbol ticker in the upper left corner
   SORT_BY_CHART_SHOW_OHLC,                           // Sort by the flag displaying OHLC values in the upper left corner
   SORT_BY_CHART_SHOW_BID_LINE,                       // Sort by the flag displaying Bid value as a horizontal line on the chart
   SORT_BY_CHART_SHOW_ASK_LINE,                       // Sort by the flag displaying Ask value as a horizontal line on the chart
   SORT_BY_CHART_SHOW_LAST_LINE,                      // Sort by the flag displaying Last value as a horizontal line on the chart
   SORT_BY_CHART_SHOW_PERIOD_SEP,                     // Sort by the flag displaying vertical separators between adjacent periods
   SORT_BY_CHART_SHOW_GRID,                           // Sort by the flag of displaying a grid on the chart
   SORT_BY_CHART_SHOW_VOLUMES,                        // Sort by the mode of displaying volumes on a chart
   SORT_BY_CHART_SHOW_OBJECT_DESCR,                   // Sort by the flag of displaying object text descriptions
   SORT_BY_CHART_VISIBLE_BARS,                        // Sort by the number of bars on a chart that are available for display
   SORT_BY_CHART_WINDOWS_TOTAL,                       // Sort by the total number of chart windows including indicator subwindows
   SORT_BY_CHART_WINDOW_IS_VISIBLE,                   // Sort by the subwindow visibility flag
   SORT_BY_CHART_WINDOW_HANDLE,                       // Sort by the chart handle
   SORT_BY_CHART_WINDOW_YDISTANCE,                    // Sort by the distance in Y axis pixels between the upper frame of the indicator subwindow and the upper frame of the chart main window
   SORT_BY_CHART_FIRST_VISIBLE_BAR,                   // Sort by the number of the first visible bar on the chart
   SORT_BY_CHART_WIDTH_IN_BARS,                       // Sort by the width of the chart in bars
   SORT_BY_CHART_WIDTH_IN_PIXELS,                     // Sort by the width of the chart in pixels
   SORT_BY_CHART_HEIGHT_IN_PIXELS,                    // Sort by the height of the chart in pixels
   SORT_BY_CHART_COLOR_BACKGROUND,                    // Sort by the color of the chart background
   SORT_BY_CHART_COLOR_FOREGROUND,                    // Sort by color of axes, scale and OHLC line
   SORT_BY_CHART_COLOR_GRID,                          // Sort by grid color
   SORT_BY_CHART_COLOR_VOLUME,                        // Sort by the color of volumes and position opening levels
   SORT_BY_CHART_COLOR_CHART_UP,                      // Sort by the color for the up bar, shadows and body borders of bull candlesticks
   SORT_BY_CHART_COLOR_CHART_DOWN,                    // Sort by the color of down bar, its shadow and border of body of the bullish candlestick
   SORT_BY_CHART_COLOR_CHART_LINE,                    // Sort by the color of the chart line and the Doji candlesticks
   SORT_BY_CHART_COLOR_CANDLE_BULL,                   // Sort by the color of a bullish candlestick body
   SORT_BY_CHART_COLOR_CANDLE_BEAR,                   // Sort by the color of a bearish candlestick body
   SORT_BY_CHART_COLOR_BID,                           // Sort by the color of the Bid price line
   SORT_BY_CHART_COLOR_ASK,                           // Sort by the color of the Ask price line
   SORT_BY_CHART_COLOR_LAST,                          // Sort by the color of the last performed deal's price line (Last)
   SORT_BY_CHART_COLOR_STOP_LEVEL,                    // Sort by the color of stop order levels (Stop Loss and Take Profit)
   SORT_BY_CHART_SHOW_TRADE_LEVELS,                   // Sort by the flag of displaying trading levels on the chart
   SORT_BY_CHART_DRAG_TRADE_LEVELS,                   // Sort by the flag enabling the ability to drag trading levels on a chart using mouse
   SORT_BY_CHART_SHOW_DATE_SCALE,                     // Sort by the flag of displaying the time scale on the chart
   SORT_BY_CHART_SHOW_PRICE_SCALE,                    // Sort by the flag of displaying the price scale on the chart
   SORT_BY_CHART_SHOW_ONE_CLICK,                      // Sort by the flag of displaying the quick trading panel on the chart
   SORT_BY_CHART_IS_MAXIMIZED,                        // Sort by the "Chart window maximized" flag
   SORT_BY_CHART_IS_MINIMIZED,                        // Sort by the "Chart window minimized" flag
   SORT_BY_CHART_IS_DOCKED,                           // Sort by the "Chart window docked" flag
   SORT_BY_CHART_FLOAT_LEFT,                          // Sort by the left coordinate of the undocked chart window relative to the virtual screen
   SORT_BY_CHART_FLOAT_TOP,                           // Sort by the upper coordinate of the undocked chart window relative to the virtual screen
   SORT_BY_CHART_FLOAT_RIGHT,                         // Sort by the right coordinate of the undocked chart window relative to the virtual screen
   SORT_BY_CHART_FLOAT_BOTTOM,                        // Sort by the bottom coordinate of the undocked chart window relative to the virtual screen
   SORT_BY_CHART_WINDOW_IND_HANDLE,                   // Sort by the indicator handle in the chart window
   SORT_BY_CHART_WINDOW_IND_INDEX,                    // Sort by the indicator index in the chart window
//--- Sort by real properties
   SORT_BY_CHART_SHIFT_SIZE = FIRST_CHART_DBL_PROP,   // Sort by the shift size of the zero bar from the right border in %
   SORT_BY_CHART_FIXED_POSITION,                      // Sort by the chart fixed position from the left border in %
   SORT_BY_CHART_FIXED_MAX,                           // Sort by the fixed chart maximum
   SORT_BY_CHART_FIXED_MIN,                           // Sort by the fixed chart minimum
   SORT_BY_CHART_POINTS_PER_BAR,                      // Sort by the scale value in points per bar
   SORT_BY_CHART_PRICE_MIN,                           // Sort by the chart minimum
   SORT_BY_CHART_PRICE_MAX,                           // Sort by the chart maximum
//--- Sort by string properties
   SORT_BY_CHART_COMMENT = FIRST_CHART_STR_PROP,      // Sort by a comment text on the chart
   SORT_BY_CHART_EXPERT_NAME,                         // Sort by a name of an EA launched on the chart
   SORT_BY_CHART_SCRIPT_NAME,                         // Sort by a name of a script launched on the chart
   SORT_BY_CHART_INDICATOR_NAME,                      // Sort by a name of an indicator launched on the chart
   SORT_BY_CHART_SYMBOL,                              // Sort by chart symbol
  };
//+------------------------------------------------------------------+

En la primera versión del objeto de gráfico, la lista de criterios era incorrecta porque las propiedades comentadas de tipo entero del gráfico se añadieron a los criterios de clasificación, y no había clasificación según el nombre del símbolo. Hemos solucionado esto en el presente artículo.

Ahora, necesitamos crear dos clases: la clase del objeto de indicador en la ventana del gráfico y la clase del objeto de ventana de gráfico. Vamos a añadirlos en un solo archivo.

En la carpeta de la biblioteca \MQL5\Include\DoEasy\Objects\Chart\, creamos el nuevo archivo ChartWnd.mqh de las clases CWndInd (indicador en la ventana del gráfico) y CChartWnd (ventana del gráfico).

La clase CWndInd debe heredarse de la clase básica de la biblioteca estándar CObject, y la clase CChartWnd, del objeto básico de todos los objetos de la biblioteca CBaseObj.

Podemos adjuntar muchos indicadores diferentes a la ventana del gráfico. Por consiguiente, el objeto de la ventana del gráfico debe conocer su existencia para que siempre podamos obtener el identificador del indicador necesario desde la ventana del gráfico y luego trabajar con él. Para identificar los indicadores, no se necesitan muchos parámetros distintos; bastará con conocer el identificador del indicador, su nombre breve y el índice de la ventana del gráfico a la que se adjunta el indicador. Por ello, la clase de objeto de indicador en la ventana del gráfico será la más sencilla posible y se heredará del objeto básico de la biblioteca estándar, solo para que podamos añadir todos estos objetos a la lista de punteros a los objetos CArrayObj incluidos en las ventanas de los gráficos de los objetos.

Vamos a escribir el código de la nueva clase en el archivo ChartWnd.mqh recién creado:

//+------------------------------------------------------------------+
//|                                                     ChartWnd.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Chart window indicator object class                              |
//+------------------------------------------------------------------+
class CWndInd : public CObject
  {
private:
   long              m_chart_id;                         // Chart ID
   string            m_name;                             // Indicator short name
   int               m_index;                            // Window index on the chart
   int               m_handle;                           // Indicator handle
public:
//--- Return itself
   CWndInd          *GetObject(void)                     { return &this;         }
//--- Return (1) indicator name, (2) window index and (3) indicator handle
   string            Name(void)                    const { return this.m_name;   }
   int               Index(void)                   const { return this.m_index;  }
   int               Handle(void)                  const { return this.m_handle; }
   
//--- Display the description of object properties in the journal (dash=true - hyphen before the description, false - description only)
   void              Print(const bool dash=false)        { ::Print((dash ? "- " : "")+this.Header());                      }
//--- Return the object short name
   string            Header(void)                  const { return CMessage::Text(MSG_CHART_OBJ_INDICATOR)+" "+this.Name(); }
   
//--- Compare CWndInd objects with each other by the specified property
   virtual int       Compare(const CObject *node,const int mode=0) const;

//--- Constructors
                     CWndInd(void);
                     CWndInd(const int handle,const string name,const int index) : m_handle(handle),m_name(name),m_index(index) {}
  };
//+------------------------------------------------------------------+
//| Compare CWndInd objects with each other by the specified property|
//+------------------------------------------------------------------+
int CWndInd::Compare(const CObject *node,const int mode=0) const
  {
   const CWndInd *obj_compared=node;
   if(mode==CHART_PROP_WINDOW_IND_HANDLE) return(this.Handle()>obj_compared.Handle() ? 1 : this.Handle()<obj_compared.Handle() ? -1 : 0);
   else if(mode==CHART_PROP_WINDOW_IND_INDEX) return(this.Index()>obj_compared.Index() ? 1 : this.Index()<obj_compared.Index() ? -1 : 0);
   return(this.Name()==obj_compared.Name() ? 0 : this.Name()<obj_compared.Name() ? -1 : 1);
  }
//+------------------------------------------------------------------+

Esta es la clase completa del objeto de indicador en la ventana del gráfico.
En la sección privada se ubican las variables de miembros de clase para el almacenamiento:

  • el identificador del gráfico en el que se encuentra la ventana con este indicador,
  • el nombre breve del indicador (en las ventanas de los gráficos, los indicadores son identificados por el terminal según sus nombres breves),
  • el índice de la ventana del gráfico en el que se encuentra el indicador (índice 0 - ventana principal del gráfico, índice 1 y superiores - subventanas del gráfico),
  • el manejador de este indicador.

Estos datos bastarán para guardar una lista con todos los indicadores adjuntos a la ventana en el objeto de ventana del gráfico. La lista en sí contendrá exactamente estos objetos, que nos ayudarán a encontrar el indicador necesario y retornar su identificador para seguir trabajando con él.

Los métodos públicos que retornan los valores de las variables anteriormente enumeradas no requieren una explicación especial. Vamos a analizar algunos otros métodos de clase.

Método que retorna el nombre breve de un objeto de indicador:

//--- Return the object short name
   string            Header(void)                  const { return CMessage::Text(MSG_CHART_OBJ_INDICATOR)+" "+this.Name(); }

Simplemente se retorna el encabezado "Indicador " + el nombre del indicador.

Método que muestra en el diario la descripción de las propiedades del objeto de indicador:

//--- Display the description of object properties in the journal (dash=true - hyphen before the description, false - description only)
   void              Print(const bool dash=false)        { ::Print((dash ? "- " : "")+this.Header());                      }

Como podemos tener varios indicadores en la ventana del gráfico, se mostrarán como una lista debajo del encabezado. Por consiguiente, para visualizar mejor la lista en el diario de registro, utilizaremos un guión delante del nombre del indicador. El parámetro de entrada del método indicará la necesidad de mostrar el guión.

Tenemos dos constructores: uno predeterminado y otro paramétrico. El constructor predeterminado puede resultar útil para crear un objeto de indicador "vacío" en la ventana, mientras que el constructor paramétrico se usará como constructor principal de la clase al crear una lista de indicadores en la clase del objeto de ventana del gráfico.

Al constructor paramétrico se le transmiten el identificador del indicador, su nombre breve y el índice de la subventana donde se encuentra este indicador.

//--- Constructors
                     CWndInd(void);
                     CWndInd(const int handle,const string name,const int index) : m_handle(handle),m_name(name),m_index(index) {}

Todos los valores de parámetro transmitidos ​al método se asignan inmediatamente a las variables de clase en su lista de inicialización.

Método para comparar los objetos de indicador de la ventana del gráfico entre sí según la propiedad especificada:

//+------------------------------------------------------------------+
//| Compare CWndInd objects with each other by the specified property|
//+------------------------------------------------------------------+
int CWndInd::Compare(const CObject *node,const int mode=0) const
  {
   const CWndInd *obj_compared=node;
   if(mode==CHART_PROP_WINDOW_IND_HANDLE) return(this.Handle()>obj_compared.Handle() ? 1 : this.Handle()<obj_compared.Handle() ? -1 : 0);
   else if(mode==CHART_PROP_WINDOW_IND_INDEX) return(this.Index()>obj_compared.Index() ? 1 : this.Index()<obj_compared.Index() ? -1 : 0);
   return(this.Name()==obj_compared.Name() ? 0 : this.Name()<obj_compared.Name() ? -1 : 1);
  }
//+------------------------------------------------------------------+

Para este objeto, no disponemos de nuestras propias enumeraciones de las propiedades; todas sus propiedades se encuentran en las enumeraciones de las propiedades del objeto de gráfico. Por ello, cualquiera de las propiedades del objeto de gráfico se puede transmitir al método, pero la comparación según las propiedades transmitidas se realizará solo si en el parámetro mode se transmite la propiedad "manejador del indicador" o "índice de la ventana del gráfico" En cualquier otro caso, la comparación se realizará según el nombre breve del indicador.

El método de comparación es estándar para todos los objetos de la biblioteca: si el valor del parámetro del objeto actual es superior al valor del objeto que se está comparando, retornaremos 1; si el valor del parámetro del objeto actual es inferior al valor del objeto que se está comparando, retornaremos -1; de lo contrario retornaremos 0.

Vamos a crear la clase del objeto de ventana del gráfico.

En el mismo archivo en el que hemos escrito la clase del objeto de indicador en la ventana del gráfico (ChartWnd.mqh), continuamos escribiendo el código e introducimos la clase del objeto de ventana del gráfico. La clase debe heredarse del objeto básico de todos los objetos de la biblioteca:

//+------------------------------------------------------------------+
//| Chart window object class                                        |
//+------------------------------------------------------------------+
class CChartWnd : public CBaseObj
  {
  }

En la sección privada de la clase se encontrarán la lista de punteros a los objetos de indicador en esta ventana, el número de esta subventana descrita por el objeto, y los métodos auxiliares para organizar el funcionamiento de la clase:

//+------------------------------------------------------------------+
//| Chart window object class                                        |
//+------------------------------------------------------------------+
class CChartWnd : public CBaseObj
  {
private:
   CArrayObj         m_list_ind;                                        // Indicator list
   int               m_window_num;                                      // Subwindow index
//--- Return the flag indicating the presence of an indicator from the list in the window
   bool              IsPresentInWindow(const CWndInd *ind);
//--- Remove indicators not present in the window from the list
   void              IndicatorsDelete(void);
//--- Add new indicators to the list
   void              IndicatorsAdd(void);
//--- Set a subwindow index
   void              SetWindowNum(const int num)                        { this.m_window_num=num;   }
public:

En la sección pública de la clase, se ubican los métodos estándar para los objetos de la biblioteca (salvo los métodos para establecer los valores de las propiedades, porque para este objeto no existen las listas propias de enumeración de las propiedades, y nosotros solo vamos a retornar los valores necesarios descritos por algunas propiedades del objeto de gráfico pertenecientes a la ventana del gráfico). Ya hemos analizado más de una vez estos métodos en artículos anteriores.
Asimismo, en la clase se encuentran los métodos para establecer y retornar los valores de las propiedades de la ventana y trabajar con la clase. Más abajo, podemos verlos con detalle.

//+------------------------------------------------------------------+
//| Chart window object class                                        |
//+------------------------------------------------------------------+
class CChartWnd : public CBaseObj
  {
private:
   CArrayObj         m_list_ind;                                        // Indicator list
   int               m_window_num;                                      // Subwindow index
//--- Return the flag indicating the presence of an indicator from the list in the window
   bool              IsPresentInWindow(const CWndInd *ind);
//--- Remove indicators not present in the window from the list
   void              IndicatorsDelete(void);
//--- Add new indicators to the list
   void              IndicatorsAdd(void);
//--- Set a subwindow index
   void              SetWindowNum(const int num)                        { this.m_window_num=num;   }
public:
//--- Return itself
   CChartWnd        *GetObject(void)                                    { return &this;            }

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_CHART_PROP_INTEGER property)  { return(property==CHART_PROP_WINDOW_YDISTANCE || property==CHART_PROP_HEIGHT_IN_PIXELS ? true : false); }
   virtual bool      SupportProperty(ENUM_CHART_PROP_DOUBLE property)   { return false; }
   virtual bool      SupportProperty(ENUM_CHART_PROP_STRING property)   { return (property==CHART_PROP_INDICATOR_NAME ? true : false); }

//--- Get description of (1) integer, (2) real and (3) string properties
   string            GetPropertyDescription(ENUM_CHART_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_CHART_PROP_DOUBLE property)  { return CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED);  }
   string            GetPropertyDescription(ENUM_CHART_PROP_STRING property)  { return CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED);  }

//--- Display the description of object properties in the journal (full_prop=true - all properties, false - supported ones only)
   void              Print(const bool full_prop=false);
//--- Display a short description of the object in the journal
   virtual void      PrintShort(const bool dash=false);
//--- Return the object short name
   virtual string    Header(void);
   
//--- Compare CChartWnd objects by a specified property (to sort the list by an MQL5 signal object)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CChartWnd objects by all properties (to search for equal MQL5 signal objects)
   bool              IsEqual(CChartWnd* compared_obj) const;
   
//--- Constructors
                     CChartWnd(void);
                     CChartWnd(const long chart_id,const int wnd_num);

//--- Return the distance in pixels between the window borders
   int               YDistance(void)                              const { return (int)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.m_window_num);}
//--- (1) Return and (2) set the window height in pixels
   int               HeightInPixels(void)                         const { return (int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS,this.m_window_num);}
   bool              SetHeightInPixels(const int value,const bool redraw=false);
//--- Return (1) the subwindow index and (2) the number of indicators attached to the window
   int               WindowNum(void)                              const { return this.m_window_num;}
   int               IndicatorsTotal(void)                        const { return this.m_list_ind.Total();   }
   
//--- Return (1) the indicator list and (2) the window indicator object from the list by index
   CArrayObj        *GetIndicatorsList(void)                            { return &this.m_list_ind;          }
   CWndInd          *GetIndicator(const int index)                      { return this.m_list_ind.At(index); }
   
//--- Display the description of indicators attached to the chart window in the journal
   void              PrintIndicators(const bool dash=false);
//--- Display the description of the window parameters in the journal
   void              PrintParameters(const bool dash=false);
   
//--- Create the list of indicators attached to the window
   void              IndicatorsListCreate(void);
//--- Update data on attached indicators
   void              Refresh(void);
   
  };
//+------------------------------------------------------------------+

Método que retorna la distancia en píxeles entre los bordes de las ventanas:

//--- Return the distance in pixels between the window borders
   int YDistance(void) const { return (int)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.m_window_num);}

Como la propiedad del gráfico CHART_WINDOW_YDISTANCE es solo de lectura, aquí no hay ningún método para establecer este valor. El método simplemente retorna el valor de esta propiedad para esta subventana del gráfico en concreto.

Método que retorna la altura de la ventana en píxeles:

int HeightInPixels(void) const { return (int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS,this.m_window_num);}

Funciona de forma idéntica al anteriormente analizado, y retorna el valor de esta propiedad para el número de ventana indicado en la variable m_window_num.

Método que establece la altura de la ventana en píxeles (se declara en el cuerpo de la clase, y se implementa fuera del cuerpo de la clase):

//+------------------------------------------------------------------+
//| Set the window height in pixels                                  |
//+------------------------------------------------------------------+
bool CChartWnd::SetHeightInPixels(const int value,const bool redraw=false)
  {
   ::ResetLastError();
   if(!::ChartSetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS,this.m_window_num,value))
     {
      CMessage::ToLog(DFUN,::GetLastError(),true);
      return false;
     }
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
   return true;
  }
//+------------------------------------------------------------------+

El método resulta similar a los métodos que establecen los valores de las propiedades del objeto de gráfico que analizamos en el artículo anterior. Transmitimos al método el valor necesario para la configuración. Después, intentamos configurarlo en la ventana utilizando la función ChartSetInteger(), y si el evento de cambio del gráfico no se encontraba en la cola, informamos sobre ello y retornamos false. Si el evento se ha puesto con éxito en cola, retornamos true, redibujando previamente el gráfico al activarse la bandera redraw. El redibujado forzoso del gráfico es necesario para no tener que esperar a que ningún evento del gráfico (la llegada de una cotización, el cambio de tamaño, los clics del ratón, etc.) muestre los cambios, volviendo a dibujar el gráfico de inmediato para ver el resultado.

Método que compara los objetos de la ventana del gráfico entre sí según la propiedad especificada:

//+------------------------------------------------------------------+
//| Compare CChartWnd objects with each other by a specified property|
//+------------------------------------------------------------------+
int CChartWnd::Compare(const CObject *node,const int mode=0) const
  {
   const CChartWnd *obj_compared=node;
   if(mode==CHART_PROP_WINDOW_YDISTANCE)
      return(this.YDistance()>obj_compared.YDistance() ? 1 : this.YDistance()<obj_compared.YDistance() ? -1 : 0);
   else if(mode==CHART_PROP_HEIGHT_IN_PIXELS)
      return(this.HeightInPixels()>obj_compared.HeightInPixels() ? 1 : this.HeightInPixels()<obj_compared.HeightInPixels() ? -1 : 0);
   return -1;
  }
//+------------------------------------------------------------------+

Aquí, al igual que sucede en el método de comparación en la clase del indicador de la ventana del gráfico que hemos analizado anteriormente, comparamos solo algunas de las propiedades indicadas en las enumeraciones de las propiedades del objeto de gráfico:

  • Distancia en píxeles a lo largo del eje vertical Y entre el marco superior de la subventana del indicador y el marco superior de la ventana principal del gráfico.
  • La altura del gráfico en píxeles,
  • En cualquier otro caso, retornamos -1

Método que compara los objetos de la ventana del gráfico entre sí según todas las propiedades:

//+------------------------------------------------------------------+
//| Compare the CChartWnd objects by all properties                  |
//+------------------------------------------------------------------+
bool CChartWnd::IsEqual(CChartWnd *compared_obj) const
  {
   return(this.YDistance()!=compared_obj.YDistance() || this.HeightInPixels()!=compared_obj.HeightInPixels() ? false : true);
  }
//+------------------------------------------------------------------+

Aquí, si aunque sea una de las propiedades de los dos objetos comparados no resulta igual, retornamos false: los objetos no son idénticos. De lo contrario, retornamos true: los objetos son idénticos.

Método que retorna la descripción de la propiedad de tipo entero:

//+------------------------------------------------------------------+
//| Return description of object's integer property                  |
//+------------------------------------------------------------------+
string CChartWnd::GetPropertyDescription(ENUM_CHART_PROP_INTEGER property)
  {
   return
     (
      property==CHART_PROP_WINDOW_YDISTANCE  ?  CMessage::Text(MSG_CHART_OBJ_WINDOW_YDISTANCE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.YDistance()
         )  :
      property==CHART_PROP_HEIGHT_IN_PIXELS  ?  CMessage::Text(MSG_CHART_OBJ_HEIGHT_IN_PIXELS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.HeightInPixels()
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Dependiendo de cuál de las dos propiedades enteras del objeto de ventana del gráfico sea transmitida al método, se crea y se retorna una línea con su descripción.

Método que muestra en el diario la propiedad del objeto:

//+------------------------------------------------------------------+
//| Display object properties in the journal                         |
//+------------------------------------------------------------------+
void CChartWnd::Print(const bool full_prop=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=CHART_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_INTEGER prop=(ENUM_CHART_PROP_INTEGER)i;
      if(prop!=CHART_PROP_WINDOW_YDISTANCE && prop!=CHART_PROP_HEIGHT_IN_PIXELS) continue;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=CHART_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      //ENUM_CHART_PROP_DOUBLE prop=(ENUM_CHART_PROP_DOUBLE)i;
      //if(!full_prop && !this.SupportProperty(prop)) continue;
      //::Print(this.GetPropertyDescription(prop));
     }
   beg=end; end+=CHART_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_STRING prop=(ENUM_CHART_PROP_STRING)i;
      if(prop==CHART_PROP_INDICATOR_NAME)
        {
         this.PrintIndicators();
         continue;
        }
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n");
  }
//+------------------------------------------------------------------+

En tres ciclos para todas las propiedades del objeto gráfico, obtenemos la siguiente propiedad y mostramos su descripción en el diario. Como el objeto de la ventana del gráfico no dispone de sus propias listas de enumeración para sus propiedades, necesitaremos imprimir solo aquellas propiedades del objeto de gráfico que sean inherentes al objeto de la ventana del gráfico, es decir, las de tipo entero y string. Este objeto no tiene propiedades de tipo real, por lo que no necesitamos mostrarlas. Podríamos haberlo hecho de forma distinta, estableciendo simplemente un marco rígido para el comienzo y el final de cada ciclo... Pero esta no es una decisión muy correcta desde el punto de vista de las modificaciones posteriores de las propiedades del objeto de gráfico; tendremos que regresar a este objeto y editar los valores del principio y el final de cada ciclo. Por consiguiente, simplemente dejaremos vacío el ciclo de propiedades reales (tal vez de forma temporal, hasta que las propiedades reales del objeto de la ventana del gráfico sean necesarias para posibles modificaciones posteriores). Por lo tanto, para realizar cualquier cambio en el número de propiedades, el comienzo y el final de cada ciclo siempre deberán ser correctos.

Método que retorna el nombre breve del objeto de ventana del gráfico:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CChartWnd::Header(void)
  {
   return(this.m_window_num==0 ? CMessage::Text(MSG_CHART_OBJ_CHART_WINDOW) : (string)this.WindowNum()+" "+CMessage::Text(MSG_CHART_OBJ_CHART_SUBWINDOW));
  }
//+------------------------------------------------------------------+

El método verifica el índice de la subventana, y si se trata de la ventana principal del gráfico (índice 0), se retornará la línea "ventana principal del gráfico"; si se trata de una subventana del gráfico principal, se retornará el número de subventana + la línea "subventana del gráfico".

Método que muestra en el diario la descripción breve de un objeto de ventana del gráfico:

//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CChartWnd::PrintShort(const bool dash=false)
  {
   ::Print((dash ? "- " : ""),this.Header()," ID: ",(string)this.GetChartID(),", ",CMessage::Text(MSG_CHART_OBJ_INDICATORS_TOTAL),": ",this.IndicatorsTotal());
  }
//+------------------------------------------------------------------+

Aquí, creamos una línea con el nombre breve del objeto, el identificador del gráfico y el número de indicadores fijados a esta ventana. Si transmitimos al método la bandera que indica la necesidad de mostrar un guión antes de la descripción del objeto (dash), se mostrará un guión antes de la línea creada.

Método que muestra en el diario la descripción de todos los indicadores fijados a esta ventana:

//+------------------------------------------------------------------+
//| Display the description of indicators attached to the window     |
//+------------------------------------------------------------------+
void CChartWnd::PrintIndicators(const bool dash=false)
  {
   string header=
     (
      this.WindowNum()==0 ? CMessage::Text(MSG_CHART_OBJ_INDICATORS_MW_NAME_LIST) : 
      CMessage::Text(MSG_CHART_OBJ_INDICATORS_SW_NAME_LIST)+" "+(string)this.WindowNum()
     );
   ::Print(header,":");
   int total=this.IndicatorsTotal();
   if(total==0)
      ::Print("- ",CMessage::Text(MSG_CHART_OBJ_INDICATORS_NONE));
   else for(int i=0;i<total;i++)
     {
      CWndInd *ind=this.m_list_ind.At(i);
      if(ind==NULL)
         continue;
      ind.Print(dash);
     }
  }
//+------------------------------------------------------------------+

Primero, creamos y mostramos en el diario el encabezado, dependiendo de qué ventana se trate.
Si se trata de la ventana principal del gráfico, el texto del encabezado será "indicadores en la ventana principal del gráfico",
De lo contrario, el texto del encabezado será "indicadores en la ventana del gráfico" + número de esta ventana.
Luego, miramos el número de indicadores fijados a esta ventana , y si no hay, mostramos la línea "no hay" .
De lo contrario, obtendremos en un ciclo por la lista de todos los indicadores el siguiente objeto de indicador en la ventana del gráfico y lo imprimiremos.

Método que muestra en el diario la descripción de los parámetros de la ventana:

//+------------------------------------------------------------------+
//| Display the description of the window parameters in the journal  |
//+------------------------------------------------------------------+
void CChartWnd::PrintParameters(const bool dash=false)
  {
   string header=
     (
      this.WindowNum()==0 ? CMessage::Text(MSG_CHART_OBJ_CHART_WINDOW) : 
      CMessage::Text(MSG_CHART_OBJ_CHART_SUBWINDOW)+" "+(string)this.WindowNum()
     );
   ::Print((dash ? " " : ""),header,":");
   if(this.WindowNum()>0)
      ::Print((dash ? " - " : ""),GetPropertyDescription(CHART_PROP_WINDOW_YDISTANCE));
   ::Print((dash ? " - " : ""),GetPropertyDescription(CHART_PROP_HEIGHT_IN_PIXELS));
  }
//+------------------------------------------------------------------+

Primero, creamos y mostramos en el diario el encabezado, dependiendo de qué ventana se trate.
si se trata de la ventana principal del gráfico, el texto del encabezado será "ventana principal del gráfico",
de lo contrario, el texto del encabezado será "subventana del gráfico" + el número de esta ventana.
Luego, si se trata de una subventana del gráfico (su número es mayor que cero), mostraremos el valor de la distancia en píxeles a lo largo del eje vertical Y entre el marco superior de la subventana del indicador y el marco superior de la ventana principal del gráfico (para la ventana principal, este valor es siempre 0, por lo que no lo mostraremos), y después mostraremos en el diario la segunda propiedad del objeto: la altura del gráfico en píxeles.

Método que crea la lista de indicadores fijados a la ventana:

//+------------------------------------------------------------------+
//| Create the list of indicators attached to the window             |
//+------------------------------------------------------------------+
void CChartWnd::IndicatorsListCreate(void)
  {
   //--- Clear the list of indicators
   this.m_list_ind.Clear();
   //--- Get the total number of indicators in the window
   int total=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num);
   //--- In the loop by the number of indicators,
   for(int i=0;i<total;i++)
     {
      //--- obtain and save the short indicator name,
      string name=::ChartIndicatorName(this.m_chart_id,this.m_window_num,i);
      //--- get and save the indicator handle by its short name
      int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name);
      //--- Free the indicator handle
      ::IndicatorRelease(handle);
      //--- Create the new indicator object in the chart window
      CWndInd *ind=new CWndInd(handle,name,i);
      if(ind==NULL)
         continue;
      //--- set the sorted list flag to the list
      this.m_list_ind.Sort();
      //--- If failed to add the object to the list, remove it
      if(!this.m_list_ind.Add(ind))
         delete ind;
     }
  }
//+------------------------------------------------------------------+

El método se comenta con detalle en el código. Notemos que, al obtener la lista de indicadores en la ventana, obtenemos el manejador del indicador según su nombre breve usando ChartIndicatorGet(), lo cual nos impone algunas "responsabilidades". El terminal realiza un seguimiento del uso de cada indicador, y con cada nueva obtención del manejador, aumentará el contador interno de uso de este indicador. Si no liberamos en nuestro programa el manejador del indicador que ya no necesitamos, nos resultará imposible captar el manejador "perdido" más tarde. Por consiguiente, inmediatamente después de obtener todos los datos del indicador necesario, liberamos el manejador, disminuyendo así el contador interno del uso del indicador.

Método que añade los nuevos indicadores a la lista:

//+------------------------------------------------------------------+
//| Add new indicators to the list                                   |
//+------------------------------------------------------------------+
void CChartWnd::IndicatorsAdd(void)
  {
   //--- Get the total number of indicators in the window
   int total=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num);
   //--- In the loop by the number of indicators,
   for(int i=0;i<total;i++)
     {
      //--- obtain and save the short indicator name,
      string name=::ChartIndicatorName(this.m_chart_id,this.m_window_num,i);
      //--- get and save the indicator handle by its short name
      int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name);
      //--- Release the indicator handle
      ::IndicatorRelease(handle);
      //--- Create the new indicator object in the chart window
      CWndInd *ind=new CWndInd(handle,name,i);
      if(ind==NULL)
         continue;
      //--- set the sorted list flag to the list
      this.m_list_ind.Sort();
      //--- If the object is already in the list or an attempt to add it to the list failed, remove it
      if(this.m_list_ind.Search(ind)>WRONG_VALUE || !this.m_list_ind.Add(ind))
         delete ind;
     }
  }
//+------------------------------------------------------------------+

La lógica del método es idéntica a la analizada anteriormente. También se comenta en el código. La única diferencia es que la lista no se borra inicialmente en el método. Al añadir un indicador a la lista, se comprueba en primer lugar la presencia de dicho indicador en la lista, y si ya está presente, el objeto de este indicador será eliminado.

Para poder sincronizar nuestra lista de indicadores en la ventana con su número real (después de todo, podemos añadir los indicadores a la ventana y eliminarlos de la ventana del gráfico), debemos comparar su número en la ventana con el número en la lista. Implementaremos esto en los siguientes artículos. No obstante, vamos a crear aquí el método que retorna la presencia de un indicador de la lista en la ventana del terminal:

//+----------------------------------------------------------------------------------------+
//| Return the flag indicating the presence of an indicator from the list in the window    |
//+----------------------------------------------------------------------------------------+
bool CChartWnd::IsPresentInWindow(const CWndInd *ind)
  {
   int total=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num);
   for(int i=0;i<total;i++)
     {
      string name=::ChartIndicatorName(this.m_chart_id,this.m_window_num,i);
      int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name);
      ::IndicatorRelease(handle);
      if(ind.Name()==name && ind.Handle()==handle)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

Transmitmos al método el puntero al objeto de indicador en la ventana del gráfico cuya presencia real debemos comprobar. A continuación, en un ciclo por el número total de indicadores en la ventana del gráfico obtenemos el nombre del siguiente indicador, obtenemos su manejador y lo liberamos de inmediato. Si el nombre breve y el manejador del indicador actual coinciden con el nombre y el manejador del objeto que estamos comprobando, retornaremos true: este indicador aún se encuentra en la ventana del gráfico. Al finalizar el ciclo, retornamos false: no se han encontrado coincidencias, lo cual significa que no existe tal indicador en la ventana del gráfico.

Si la lista presenta indicadores que no están presentes en el gráfico, deberemos eliminarlos de la lista.
Método que elimina de la lista los indicadores ya existentes en la ventana:

//+------------------------------------------------------------------+
//| Remove indicators not present in the window from the list        |
//+------------------------------------------------------------------+
void CChartWnd::IndicatorsDelete(void)
  {
   int total=this.m_list_ind.Total();
   for(int i=total-1;i>WRONG_VALUE;i--)
     {
      CWndInd *ind=this.m_list_ind.At(i);
      if(!this.IsPresentInWindow(ind))
         this.m_list_ind.Delete(i);
     }
  }
//+------------------------------------------------------------------+

Aquí, en un ciclo por la lista de objetos de indicador, obtenemos el siguiente objeto de indicador según el índice del ciclo y comprobamos su presencia en la ventana real del gráfico. Si está ausente, eliminaremos el puntero al mismo de la lista usando el método Delete().

Más adelante, al implementar la clase de colección de gráficos, deberemos monitorear el estado del indicador en las subventanas de todos los objetos del gráfico. Si existen desajustes entre el número real de indicadores en las subventanas de los gráficos y sus descripciones en las listas de los objetos de ventana del gráfico, deberemos eliminar los indicadores innecesarios de la lista y añadir nuevos si estos estuvieran disponibles.

Para ello, crearemos un método que combinará los datos de los indicadores fijados a las ventanas de los gráficos:

//+------------------------------------------------------------------+
//| Update data on attached indicators                               |
//+------------------------------------------------------------------+
void CChartWnd::Refresh(void)
  {
   this.IndicatorsDelete();
   this.IndicatorsAdd();
  }
//+------------------------------------------------------------------+

Aquí, primero buscamos y eliminamos de la lista los indicadores ausentes en la ventana del gráfico real que aún existan en la lista, y después buscamos y añadimos los nuevos indicadores que estén en la ventana, pero que todavía no se encuentren en la lista con la ayuda de los métodos analizados anteriormente.

Por último, vamos a analizar el constructor paramétrico de la clase:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CChartWnd::CChartWnd(const long chart_id,const int wnd_num) : m_window_num(wnd_num)
  {
   CBaseObj::SetChartID(chart_id);
   this.IndicatorsListCreate();
  }
//+------------------------------------------------------------------+

Aquí, en primer lugar, establecemos el valor del identificador del gráfico en el objeto padre CBaseObj, y después creamos la lista de indicadores adjuntos a esta ventana del gráfico. Establecemos el número de subventana del gráfico en la lista de inicialización del constructor.

Con esto, podemos dar por finalizada la creación de la clase de objeto de indicador en la ventana del gráfico y la clase de objeto de ventana del gráfico.
Podrá ver el listado completo de ambas clases en un único archivo ubicado en los archivos adjuntos al artículo.

Como ahora tenemos un objeto que describe la ventana del gráfico y sus subventanas, respectivamente, es hora de mejorar la clase del objeto de gráfico CCHARTOBJ CChartObj, que se encuentar en el archivo \MQL5\Include\DoEasy\Objects\Chart\ChartObj.mqh. Ahora, tendremos una lista con todas las subventanas ubicadas en su ventana principal. Para obtener las propiedades de la ventana, deberemos utilizar el puntero al objeto de ventana del gráfico necesario, creado anteriormente. Partiendo del objeto de ventana obtenido, podremos obtener la lista de todos los indicadores fijados a él, y ya de esos indicadores, podremos recibir el manejador del indicador necesario para trabajar con él.

En primer lugar, añadimos al archivo del objeto de gráfico el archivo de los objetos de la ventana y de los indicadores en la ventana y declaramos el objeto de lista en el que guardaremos los punteros a todas las ventanas del objeto de gráfico:

//+------------------------------------------------------------------+
//|                                                     ChartObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Objects\BaseObj.mqh"
#include "ChartWnd.mqh"
//+------------------------------------------------------------------+
//| Chart object class                                               |
//+------------------------------------------------------------------+
class CChartObj : public CBaseObj
  {
private:
   CArrayObj         m_list_wnd;                                  // List of chart window objects
   long              m_long_prop[CHART_PROP_INTEGER_TOTAL];       // Integer properties
   double            m_double_prop[CHART_PROP_DOUBLE_TOTAL];      // Real properties
   string            m_string_prop[CHART_PROP_STRING_TOTAL];      // String properties
   int               m_digits;                                    // Symbol's Digits()

En la seccón privada de la clase, en la lista de los métodos para establecer los valores de las propiedades, añadimos el método que establece el valor de visibilidad de la ventana del gráfico:

//--- The methods of setting property values
   bool              SetMode(const string source,const ENUM_CHART_MODE mode,const bool redraw=false);
   bool              SetScale(const string source,const int scale,const bool redraw=false);
   bool              SetModeVolume(const string source,const ENUM_CHART_VOLUME_MODE mode,const bool redraw=false);
   void              SetVisibleBars(void);
   void              SetWindowsTotal(void);
   void              SetVisible(void);
   void              SetFirstVisibleBars(void);
   void              SetWidthInBars(void);
   void              SetWidthInPixels(void);
   void              SetMaximizedFlag(void);
   void              SetMinimizedFlag(void);
   void              SetExpertName(void);
   void              SetScriptName(void);

public:

Como la "distancia en píxeles a lo largo del eje vertical Y entre el marco superior de la subventana del indicador y el marco superior de la ventana principal del gráfico" no tiene sentido para la ventana principal (siempre está en 0), entonces, en el método que retorna la bandera de soporte por parte del objeto de una propiedad de tipo entero, cambiaremos el retorno del valor en caso de que sea la propiedad CHART_PROP_WINDOW_YDISTANCE:

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_CHART_PROP_INTEGER property)           { return (property!=CHART_PROP_WINDOW_YDISTANCE ? true : false); }
   virtual bool      SupportProperty(ENUM_CHART_PROP_DOUBLE property)            { return true; }
   virtual bool      SupportProperty(ENUM_CHART_PROP_STRING property)            { return true; }

Si la propiedad transmitida al método no es igual a CHART_PROP_WINDOW_YDISTANCE, retornaremos true, de lo contrario, retornaremos false.

En la lista de métodos para el acceso simplificado a las propiedades del objeto, añadimos el método que retorna la visibilidad de la ventana:

//--- Return the total number of chart windows including indicator subwindows
   int               WindowsTotal(void)                              const { return (int)this.GetProperty(CHART_PROP_WINDOWS_TOTAL);      }

//--- Return the window visibility
   bool              Visible(void)                                   const { return (bool)this.GetProperty(CHART_PROP_WINDOW_IS_VISIBLE); }

//--- Return the chart window handle
   int               Handle(void)                                    const { return (int)this.GetProperty(CHART_PROP_WINDOW_HANDLE);      } 

Aquí, el método retornará esta propiedad solo para la ventana principal del gráfico.

Los métodos que retornan la distancia en píxeles a lo largo del eje vertical Y entre el marco superior de la subventana del indicador y el marco superior de la ventana principal del gráfico, así como el método que retorna y configura la altura de un gráfico específico en píxeles han sufrido cambios. Ahora, para configurar y retornar estas propiedades, deberemos encontrar el objeto de la ventana necesaria, y ya en sus propiedades añadir u obtener estos valores. Analizaremos la implementación de los métodos un poco más tarde.

//--- Return the name of a script launched on the chart
   string            ScriptName(void)                                const { return this.GetProperty(CHART_PROP_SCRIPT_NAME);             }

//--- Return the distance in Y axis pixels between the upper frame of the indicator subwindow and the upper frame of the chart main window
   int               WindowYDistance(const int sub_window)           const;
   
//--- (1) Return and (2) set the height of the specified chart in pixels
   int               WindowHeightInPixels(const int sub_window)      const;
   bool              SetWindowHeightInPixels(const int height,const int sub_window,const bool redraw=false);
   
//--- Return the specified subwindow visibility

En la parte inferior del cuerpo de la clase, declaramos los métodos adicionales para obtener el objeto de ventana necesario y mostrar en el diario las propiedades de todas las subventanas del gráfico y los datos de todos los indicadores fijados a la ventana del gráfico especificada:

//--- Emulate a tick (chart updates - similar to the terminal Refresh command)
   void              EmulateTick(void)                                     { ::ChartSetSymbolPeriod(this.ID(),this.Symbol(),this.Timeframe());}

//--- Return the chart window specified by index
   CChartWnd        *GetWindowByIndex(const int index)               const { return this.m_list_wnd.At(index); }
//--- Return the window object by its subwindow index
   CChartWnd        *GetWindowByNum(const int win_num)               const;
   
//--- Display data of all indicators of all chart windows in the journal
   void              PrintWndIndicators(void);
//--- Display the properties of all chart windows in the journal
   void              PrintWndParameters(void);

  };
//+------------------------------------------------------------------+

En el constructor paramétrico de la clase, establecemos el valor del identificador del gráfico en el objeto padre de la clase, indicamos las tres propiedades de la ventana principal del objeto de gráfico (podríamos no hacer esto, ya que el objeto de la ventana principal ahora se encuentra en la lista de todas las ventanas del gráfico; pero, como el objeto tiene estas propiedades, las rellenaremos con los datos correctos), y al final del método, añadimos a la lista de todas las ventanas del gráfico todos los objetos de ventana que pertenecen a este gráfico:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CChartObj::CChartObj(const long chart_id)
  {
//--- Set chart ID to the base object
   CBaseObj::SetChartID(chart_id);
//--- Set integer properties
   this.SetProperty(CHART_PROP_ID,chart_id);                                                             // Chart ID
   this.SetProperty(CHART_PROP_TIMEFRAME,::ChartPeriod(this.ID()));                                      // Chart timeframe
   this.SetProperty(CHART_PROP_SHOW,::ChartGetInteger(this.ID(),CHART_SHOW));                            // Price chart drawing attribute
   this.SetProperty(CHART_PROP_IS_OBJECT,::ChartGetInteger(this.ID(),CHART_IS_OBJECT));                  // Chart object identification attribute
   this.SetProperty(CHART_PROP_BRING_TO_TOP,false);                                                      // Show chart above all others
   this.SetProperty(CHART_PROP_CONTEXT_MENU,::ChartGetInteger(this.ID(),CHART_CONTEXT_MENU));            // Access to the context menu using the right click
   this.SetProperty(CHART_PROP_CROSSHAIR_TOOL,::ChartGetInteger(this.ID(),CHART_CROSSHAIR_TOOL));        // Access the Crosshair tool by pressing the middle mouse button
   this.SetProperty(CHART_PROP_MOUSE_SCROLL,::ChartGetInteger(this.ID(),CHART_MOUSE_SCROLL));            // Scroll the chart horizontally using the left mouse button
   this.SetProperty(CHART_PROP_EVENT_MOUSE_WHEEL,::ChartGetInteger(this.ID(),CHART_EVENT_MOUSE_WHEEL));  // Send messages about mouse wheel events to all MQL5 programs on a chart
   this.SetProperty(CHART_PROP_EVENT_MOUSE_MOVE,::ChartGetInteger(this.ID(),CHART_EVENT_MOUSE_MOVE));    // Send messages about mouse button click and movement events to all MQL5 programs on a chart
   this.SetProperty(CHART_PROP_EVENT_OBJECT_CREATE,::ChartGetInteger(this.ID(),CHART_EVENT_OBJECT_CREATE)); // Send messages about the graphical object creation event to all MQL5 programs on a chart
   this.SetProperty(CHART_PROP_EVENT_OBJECT_DELETE,::ChartGetInteger(this.ID(),CHART_EVENT_OBJECT_DELETE)); // Send messages about the graphical object destruction event to all MQL5 programs on a chart
   this.SetProperty(CHART_PROP_MODE,::ChartGetInteger(this.ID(),CHART_MODE));                            // Type of the chart (candlesticks, bars or line)
   this.SetProperty(CHART_PROP_FOREGROUND,::ChartGetInteger(this.ID(),CHART_FOREGROUND));                // Price chart in the foreground
   this.SetProperty(CHART_PROP_SHIFT,::ChartGetInteger(this.ID(),CHART_SHIFT));                          // Mode of shift of the price chart from the right border
   this.SetProperty(CHART_PROP_AUTOSCROLL,::ChartGetInteger(this.ID(),CHART_AUTOSCROLL));                // The mode of automatic shift to the right border of the chart
   this.SetProperty(CHART_PROP_KEYBOARD_CONTROL,::ChartGetInteger(this.ID(),CHART_KEYBOARD_CONTROL));    // Allow managing the chart using a keyboard
   this.SetProperty(CHART_PROP_QUICK_NAVIGATION,::ChartGetInteger(this.ID(),CHART_QUICK_NAVIGATION));    // Allow the chart to intercept Space and Enter key strokes to activate the quick navigation bar
   this.SetProperty(CHART_PROP_SCALE,::ChartGetInteger(this.ID(),CHART_SCALE));                          // Scale
   this.SetProperty(CHART_PROP_SCALEFIX,::ChartGetInteger(this.ID(),CHART_SCALEFIX));                    // Fixed scale mode
   this.SetProperty(CHART_PROP_SCALEFIX_11,::ChartGetInteger(this.ID(),CHART_SCALEFIX_11));              // 1:1 scale mode
   this.SetProperty(CHART_PROP_SCALE_PT_PER_BAR,::ChartGetInteger(this.ID(),CHART_SCALE_PT_PER_BAR));    // Mode for specifying the scale in points per bar
   this.SetProperty(CHART_PROP_SHOW_TICKER,::ChartGetInteger(this.ID(),CHART_SHOW_TICKER));              // Display a symbol ticker in the upper left corner
   this.SetProperty(CHART_PROP_SHOW_OHLC,::ChartGetInteger(this.ID(),CHART_SHOW_OHLC));                  // Display OHLC values in the upper left corner
   this.SetProperty(CHART_PROP_SHOW_BID_LINE,::ChartGetInteger(this.ID(),CHART_SHOW_BID_LINE));          // Display Bid value as a horizontal line on the chart
   this.SetProperty(CHART_PROP_SHOW_ASK_LINE,::ChartGetInteger(this.ID(),CHART_SHOW_ASK_LINE));          // Display Ask value as a horizontal line on the chart
   this.SetProperty(CHART_PROP_SHOW_LAST_LINE,::ChartGetInteger(this.ID(),CHART_SHOW_LAST_LINE));        // Display Last value as a horizontal line on the chart
   this.SetProperty(CHART_PROP_SHOW_PERIOD_SEP,::ChartGetInteger(this.ID(),CHART_SHOW_PERIOD_SEP));      // Display vertical separators between adjacent periods
   this.SetProperty(CHART_PROP_SHOW_GRID,::ChartGetInteger(this.ID(),CHART_SHOW_GRID));                  // Display the chart grid
   this.SetProperty(CHART_PROP_SHOW_VOLUMES,::ChartGetInteger(this.ID(),CHART_SHOW_VOLUMES));            // Display volumes on the chart
   this.SetProperty(CHART_PROP_SHOW_OBJECT_DESCR,::ChartGetInteger(this.ID(),CHART_SHOW_OBJECT_DESCR));  // Display text descriptions of the objects
   this.SetProperty(CHART_PROP_VISIBLE_BARS,::ChartGetInteger(this.ID(),CHART_VISIBLE_BARS));            // Number of bars on a chart that are available for display
   this.SetProperty(CHART_PROP_WINDOWS_TOTAL,::ChartGetInteger(this.ID(),CHART_WINDOWS_TOTAL));          // The total number of chart windows including indicator subwindows
   this.SetProperty(CHART_PROP_WINDOW_IS_VISIBLE,::ChartGetInteger(this.ID(),CHART_WINDOW_IS_VISIBLE,0));// Window visibility
   this.SetProperty(CHART_PROP_WINDOW_HANDLE,::ChartGetInteger(this.ID(),CHART_WINDOW_HANDLE));          // Chart window handle
   this.SetProperty(CHART_PROP_WINDOW_YDISTANCE,::ChartGetInteger(this.ID(),CHART_WINDOW_YDISTANCE,0));  // Distance in Y axis pixels between the upper frame of the indicator subwindow and the upper frame of the chart main window
   this.SetProperty(CHART_PROP_FIRST_VISIBLE_BAR,::ChartGetInteger(this.ID(),CHART_FIRST_VISIBLE_BAR));  // Number of the first visible bar on the chart
   this.SetProperty(CHART_PROP_WIDTH_IN_BARS,::ChartGetInteger(this.ID(),CHART_WIDTH_IN_BARS));          // Chart width in bars
   this.SetProperty(CHART_PROP_WIDTH_IN_PIXELS,::ChartGetInteger(this.ID(),CHART_WIDTH_IN_PIXELS));      // Chart width in pixels
   this.SetProperty(CHART_PROP_HEIGHT_IN_PIXELS,::ChartGetInteger(this.ID(),CHART_HEIGHT_IN_PIXELS,0));  // Chart height in pixels
   this.SetProperty(CHART_PROP_COLOR_BACKGROUND,::ChartGetInteger(this.ID(),CHART_COLOR_BACKGROUND));    // Chart background color
   this.SetProperty(CHART_PROP_COLOR_FOREGROUND,::ChartGetInteger(this.ID(),CHART_COLOR_FOREGROUND));    // Color of axes, scale and OHLC line
   this.SetProperty(CHART_PROP_COLOR_GRID,::ChartGetInteger(this.ID(),CHART_COLOR_GRID));                // Grid color
   this.SetProperty(CHART_PROP_COLOR_VOLUME,::ChartGetInteger(this.ID(),CHART_COLOR_VOLUME));            // Color of volumes and position opening levels
   this.SetProperty(CHART_PROP_COLOR_CHART_UP,::ChartGetInteger(this.ID(),CHART_COLOR_CHART_UP));        // Color for the up bar, shadows and body borders of bullish candlesticks
   this.SetProperty(CHART_PROP_COLOR_CHART_DOWN,::ChartGetInteger(this.ID(),CHART_COLOR_CHART_DOWN));    // Color for the down bar, shadows and body borders of bearish candlesticks
   this.SetProperty(CHART_PROP_COLOR_CHART_LINE,::ChartGetInteger(this.ID(),CHART_COLOR_CHART_LINE));    // Color of the chart line and the Doji candlesticks
   this.SetProperty(CHART_PROP_COLOR_CANDLE_BULL,::ChartGetInteger(this.ID(),CHART_COLOR_CANDLE_BULL));  // Color of the bullish candle body
   this.SetProperty(CHART_PROP_COLOR_CANDLE_BEAR,::ChartGetInteger(this.ID(),CHART_COLOR_CANDLE_BEAR));  // Color of the bearish candle body
   this.SetProperty(CHART_PROP_COLOR_BID,::ChartGetInteger(this.ID(),CHART_COLOR_BID));                  // Bid price line color
   this.SetProperty(CHART_PROP_COLOR_ASK,::ChartGetInteger(this.ID(),CHART_COLOR_ASK));                  // Ask price line color
   this.SetProperty(CHART_PROP_COLOR_LAST,::ChartGetInteger(this.ID(),CHART_COLOR_LAST));                // Color of the last performed deal's price line (Last)
   this.SetProperty(CHART_PROP_COLOR_STOP_LEVEL,::ChartGetInteger(this.ID(),CHART_COLOR_STOP_LEVEL));    // Color of stop order levels (Stop Loss and Take Profit)
   this.SetProperty(CHART_PROP_SHOW_TRADE_LEVELS,::ChartGetInteger(this.ID(),CHART_SHOW_TRADE_LEVELS));  // Display trade levels on the chart (levels of open positions, Stop Loss, Take Profit and pending orders)
   this.SetProperty(CHART_PROP_DRAG_TRADE_LEVELS,::ChartGetInteger(this.ID(),CHART_DRAG_TRADE_LEVELS));  // Enable the ability to drag trading levels on a chart using mouse
   this.SetProperty(CHART_PROP_SHOW_DATE_SCALE,::ChartGetInteger(this.ID(),CHART_SHOW_DATE_SCALE));      // Display the time scale on the chart
   this.SetProperty(CHART_PROP_SHOW_PRICE_SCALE,::ChartGetInteger(this.ID(),CHART_SHOW_PRICE_SCALE));    // Display the price scale on the chart
   this.SetProperty(CHART_PROP_SHOW_ONE_CLICK,::ChartGetInteger(this.ID(),CHART_SHOW_ONE_CLICK));        // Display the quick trading panel on the chart
   this.SetProperty(CHART_PROP_IS_MAXIMIZED,::ChartGetInteger(this.ID(),CHART_IS_MAXIMIZED));            // Chart window maximized
   this.SetProperty(CHART_PROP_IS_MINIMIZED,::ChartGetInteger(this.ID(),CHART_IS_MINIMIZED));            // Chart window minimized
   this.SetProperty(CHART_PROP_IS_DOCKED,::ChartGetInteger(this.ID(),CHART_IS_DOCKED));                  // Chart window docked
   this.SetProperty(CHART_PROP_FLOAT_LEFT,::ChartGetInteger(this.ID(),CHART_FLOAT_LEFT));                // Left coordinate of the undocked chart window relative to the virtual screen
   this.SetProperty(CHART_PROP_FLOAT_TOP,::ChartGetInteger(this.ID(),CHART_FLOAT_TOP));                  // Upper coordinate of the undocked chart window relative to the virtual screen
   this.SetProperty(CHART_PROP_FLOAT_RIGHT,::ChartGetInteger(this.ID(),CHART_FLOAT_RIGHT));              // Right coordinate of the undocked chart window relative to the virtual screen
   this.SetProperty(CHART_PROP_FLOAT_BOTTOM,::ChartGetInteger(this.ID(),CHART_FLOAT_BOTTOM));            // Bottom coordinate of the undocked chart window relative to the virtual screen
//--- Set real properties
   this.SetProperty(CHART_PROP_SHIFT_SIZE,::ChartGetDouble(this.ID(),CHART_SHIFT_SIZE));                 // Shift size of the zero bar from the right border in %
   this.SetProperty(CHART_PROP_FIXED_POSITION,::ChartGetDouble(this.ID(),CHART_FIXED_POSITION));         // Chart fixed position from the left border in %
   this.SetProperty(CHART_PROP_FIXED_MAX,::ChartGetDouble(this.ID(),CHART_FIXED_MAX));                   // Fixed chart maximum
   this.SetProperty(CHART_PROP_FIXED_MIN,::ChartGetDouble(this.ID(),CHART_FIXED_MIN));                   // Fixed chart minimum
   this.SetProperty(CHART_PROP_POINTS_PER_BAR,::ChartGetDouble(this.ID(),CHART_POINTS_PER_BAR));         // Scale in points per bar
   this.SetProperty(CHART_PROP_PRICE_MIN,::ChartGetDouble(this.ID(),CHART_PRICE_MIN));                   // Chart minimum
   this.SetProperty(CHART_PROP_PRICE_MAX,::ChartGetDouble(this.ID(),CHART_PRICE_MAX));                   // Chart maximum
//--- Set string properties
   this.SetProperty(CHART_PROP_COMMENT,::ChartGetString(this.ID(),CHART_COMMENT));                       // Comment text on the chart
   this.SetProperty(CHART_PROP_EXPERT_NAME,::ChartGetString(this.ID(),CHART_EXPERT_NAME));               // name of an EA launched on the chart
   this.SetProperty(CHART_PROP_SCRIPT_NAME,::ChartGetString(this.ID(),CHART_SCRIPT_NAME));               // name of a script launched on the chart
   this.SetProperty(CHART_PROP_SYMBOL,::ChartSymbol(this.ID()));                                         // Chart symbol
   
   this.m_digits=(int)::SymbolInfoInteger(this.Symbol(),SYMBOL_DIGITS);
   int total=this.WindowsTotal();
   for(int i=0;i<total;i++)
     {
      CChartWnd *wnd=new CChartWnd(m_chart_id,i);
      if(wnd==NULL)
         continue;
      m_list_wnd.Sort();
      if(!m_list_wnd.Add(wnd))
         delete wnd;
     }
  }
//+------------------------------------------------------------------+

Para crear las listas de las ventanas del gráfico, obtenemos el número total de todas las ventanas del gráfico, y en un ciclo por todas las ventanas, creamos un nuevo objeto de ventana del gráfico y lo añadimos a la lista.

En el método para comparar dos objetos de gráfico que creamos en el artículo anterior, cometimos un error de lógica: cada gráfico tiene su identificador único del gráfico y su propio manejador de ventana. Por eso, la comparación de estas propiedades en dos gráficos distintos siempre retornará false. Sin embargo, el objetivo del método es comprobar si dos gráficos distintos son idénticos, mientras que la comparación de sus identificadores y manejadores siempre mostrará que no son idénticos.
Vamos a corregir el error, omitiendo estas dos propiedades al realizar la comparación:

//+------------------------------------------------------------------+
//| Compare the CChartObj objects by all properties                  |
//+------------------------------------------------------------------+
bool CChartObj::IsEqual(CChartObj *compared_obj) const
  {
   int beg=0, end=CHART_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_INTEGER prop=(ENUM_CHART_PROP_INTEGER)i;
      if(prop==CHART_PROP_ID || prop==CHART_PROP_WINDOW_HANDLE) continue;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false;
     }
   beg=end; end+=CHART_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_DOUBLE prop=(ENUM_CHART_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=CHART_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_STRING prop=(ENUM_CHART_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

En el método que retorna la descripción de una propiedad de tipo entero del objeto, añadimos el retorno de la descripción de las tres propiedades añadidas:

//+------------------------------------------------------------------+
//| Return description of object's integer property                  |
//+------------------------------------------------------------------+
string CChartObj::GetPropertyDescription(ENUM_CHART_PROP_INTEGER property)
  {
   return
     (
      property==CHART_PROP_ID     ?  CMessage::Text(MSG_CHART_OBJ_ID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_TIMEFRAME      ?  CMessage::Text(MSG_LIB_TEXT_BAR_PERIOD)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+TimeframeDescription((ENUM_TIMEFRAMES)this.GetProperty(property))
         )  :
      property==CHART_PROP_SHOW   ?  CMessage::Text(MSG_CHART_OBJ_SHOW)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_IS_OBJECT      ?  CMessage::Text(MSG_CHART_OBJ_IS_OBJECT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_BRING_TO_TOP   ?  CMessage::Text(MSG_CHART_OBJ_BRING_TO_TOP)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_CONTEXT_MENU   ?  CMessage::Text(MSG_CHART_OBJ_CONTEXT_MENU)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_CROSSHAIR_TOOL ?  CMessage::Text(MSG_CHART_OBJ_CROSSHAIR_TOOL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_MOUSE_SCROLL   ?  CMessage::Text(MSG_CHART_OBJ_MOUSE_SCROLL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_EVENT_MOUSE_WHEEL ?  CMessage::Text(MSG_CHART_OBJ_EVENT_MOUSE_WHEEL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_EVENT_MOUSE_MOVE  ?  CMessage::Text(MSG_CHART_OBJ_EVENT_MOUSE_MOVE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_EVENT_OBJECT_CREATE  ?  CMessage::Text(MSG_CHART_OBJ_EVENT_OBJECT_CREATE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_EVENT_OBJECT_DELETE  ?  CMessage::Text(MSG_CHART_OBJ_EVENT_OBJECT_DELETE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_MODE           ?  CMessage::Text(MSG_CHART_OBJ_MODE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ChartModeDescription((ENUM_CHART_MODE)this.GetProperty(property))
         )  :
      property==CHART_PROP_FOREGROUND     ?  CMessage::Text(MSG_CHART_OBJ_FOREGROUND)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHIFT        ?  CMessage::Text(MSG_CHART_OBJ_SHIFT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_AUTOSCROLL        ?  CMessage::Text(MSG_CHART_OBJ_AUTOSCROLL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_KEYBOARD_CONTROL        ?  CMessage::Text(MSG_CHART_OBJ_KEYBOARD_CONTROL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_QUICK_NAVIGATION        ?  CMessage::Text(MSG_CHART_OBJ_QUICK_NAVIGATION)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SCALE        ?  CMessage::Text(MSG_CHART_OBJ_SCALE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_SCALEFIX        ?  CMessage::Text(MSG_CHART_OBJ_SCALEFIX)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SCALEFIX_11        ?  CMessage::Text(MSG_CHART_OBJ_SCALEFIX_11)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SCALE_PT_PER_BAR  ?  CMessage::Text(MSG_CHART_OBJ_SCALE_PT_PER_BAR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_TICKER        ?  CMessage::Text(MSG_CHART_OBJ_SHOW_TICKER)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_OHLC        ?  CMessage::Text(MSG_CHART_OBJ_SHOW_OHLC)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_BID_LINE  ?  CMessage::Text(MSG_CHART_OBJ_SHOW_BID_LINE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_ASK_LINE  ?  CMessage::Text(MSG_CHART_OBJ_SHOW_ASK_LINE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_LAST_LINE ?  CMessage::Text(MSG_CHART_OBJ_SHOW_LAST_LINE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_PERIOD_SEP   ?  CMessage::Text(MSG_CHART_OBJ_SHOW_PERIOD_SEP)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_GRID        ?  CMessage::Text(MSG_CHART_OBJ_SHOW_GRID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_VOLUMES   ?  CMessage::Text(MSG_CHART_OBJ_SHOW_VOLUMES)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+ChartModeVolumeDescription((ENUM_CHART_VOLUME_MODE)this.GetProperty(property))
         )  :
      property==CHART_PROP_SHOW_OBJECT_DESCR ?  CMessage::Text(MSG_CHART_OBJ_SHOW_OBJECT_DESCR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_VISIBLE_BARS   ?  CMessage::Text(MSG_CHART_OBJ_VISIBLE_BARS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_WINDOWS_TOTAL  ?  CMessage::Text(MSG_CHART_OBJ_WINDOWS_TOTAL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_WINDOW_IS_VISIBLE  ?  CMessage::Text(MSG_CHART_OBJ_WINDOW_IS_VISIBLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_WINDOW_HANDLE  ?  CMessage::Text(MSG_CHART_OBJ_WINDOW_HANDLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_WINDOW_YDISTANCE  ?  CMessage::Text(MSG_CHART_OBJ_WINDOW_YDISTANCE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_FIRST_VISIBLE_BAR ?  CMessage::Text(MSG_CHART_OBJ_FIRST_VISIBLE_BAR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_WIDTH_IN_BARS  ?  CMessage::Text(MSG_CHART_OBJ_WIDTH_IN_BARS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_WIDTH_IN_PIXELS   ?  CMessage::Text(MSG_CHART_OBJ_WIDTH_IN_PIXELS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_HEIGHT_IN_PIXELS   ?  CMessage::Text(MSG_CHART_OBJ_HEIGHT_IN_PIXELS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_COLOR_BACKGROUND        ?  CMessage::Text(MSG_CHART_OBJ_COLOR_BACKGROUND)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_FOREGROUND  ?  CMessage::Text(MSG_CHART_OBJ_COLOR_FOREGROUND)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_GRID     ?  CMessage::Text(MSG_CHART_OBJ_COLOR_GRID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_VOLUME   ?  CMessage::Text(MSG_CHART_OBJ_COLOR_VOLUME)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_CHART_UP ?  CMessage::Text(MSG_CHART_OBJ_COLOR_CHART_UP)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_CHART_DOWN  ?  CMessage::Text(MSG_CHART_OBJ_COLOR_CHART_DOWN)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_CHART_LINE  ?  CMessage::Text(MSG_CHART_OBJ_COLOR_CHART_LINE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_CANDLE_BULL ?  CMessage::Text(MSG_CHART_OBJ_COLOR_CANDLE_BULL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_CANDLE_BEAR ?  CMessage::Text(MSG_CHART_OBJ_COLOR_CANDLE_BEAR)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_BID        ?  CMessage::Text(MSG_CHART_OBJ_COLOR_BID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_ASK        ?  CMessage::Text(MSG_CHART_OBJ_COLOR_ASK)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_LAST        ?  CMessage::Text(MSG_CHART_OBJ_COLOR_LAST)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_COLOR_STOP_LEVEL  ?  CMessage::Text(MSG_CHART_OBJ_COLOR_STOP_LEVEL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::ColorToString((color)this.GetProperty(property),true)
         )  :
      property==CHART_PROP_SHOW_TRADE_LEVELS ?  CMessage::Text(MSG_CHART_OBJ_SHOW_TRADE_LEVELS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_DRAG_TRADE_LEVELS ?  CMessage::Text(MSG_CHART_OBJ_DRAG_TRADE_LEVELS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_DATE_SCALE   ?  CMessage::Text(MSG_CHART_OBJ_SHOW_DATE_SCALE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_PRICE_SCALE  ?  CMessage::Text(MSG_CHART_OBJ_SHOW_PRICE_SCALE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_SHOW_ONE_CLICK ?  CMessage::Text(MSG_CHART_OBJ_SHOW_ONE_CLICK)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_IS_MAXIMIZED   ?  CMessage::Text(MSG_CHART_OBJ_IS_MAXIMIZED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_IS_MINIMIZED   ?  CMessage::Text(MSG_CHART_OBJ_IS_MINIMIZED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_IS_DOCKED      ?  CMessage::Text(MSG_CHART_OBJ_IS_DOCKED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      property==CHART_PROP_FLOAT_LEFT     ?  CMessage::Text(MSG_CHART_OBJ_FLOAT_LEFT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_FLOAT_TOP      ?  CMessage::Text(MSG_CHART_OBJ_FLOAT_TOP)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_FLOAT_RIGHT    ?  CMessage::Text(MSG_CHART_OBJ_FLOAT_RIGHT)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==CHART_PROP_FLOAT_BOTTOM   ?  CMessage::Text(MSG_CHART_OBJ_FLOAT_BOTTOM)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Los bloques del código añadido son idénticos a todos los demás: dependiendo de la propiedad transmitida al método, se creará y retornará una línea con la descripción de esta propiedad.

Vamos a mejorar el método que muestra en el diario todas las propiedades del objeto:

//+------------------------------------------------------------------+
//| Display object properties in the journal                         |
//+------------------------------------------------------------------+
void CChartObj::Print(const bool full_prop=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=CHART_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_INTEGER prop=(ENUM_CHART_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      if(prop==CHART_PROP_WINDOW_IND_HANDLE || prop==CHART_PROP_WINDOW_IND_INDEX) continue;
      if(prop==CHART_PROP_HEIGHT_IN_PIXELS)
        {
         this.PrintWndParameters();
         continue;
        }
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=CHART_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_DOUBLE prop=(ENUM_CHART_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=CHART_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_PROP_STRING prop=(ENUM_CHART_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      if(prop==CHART_PROP_INDICATOR_NAME)
        {
         this.PrintWndIndicators();
         continue;
        }
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n");
  }
//+------------------------------------------------------------------+

Si encontramos en el ciclo las propiedades "manejador del indicador" e "índice del indicador en la ventana", estas propiedades se omitirán: no estarán relacionadas con el objeto de gráfico.
Si encontramos la propiedad "altura del gráfico en píxeles", llamaremos al método que muestra la descripción de esta propiedad para todas las ventanas de este gráfico.
Exactamente de la misma forma, si encontramos la propiedad "nombre del indicador en la ventana", se llamará al método que muestra la descripción de todos los indicadodres fijados a todas las ventanas del gráfico. Veremos estos métodos más tarde.

El método que muestra en el diario la descripción breve del objeto también ha sido mejorado.
Ahora, muestra adicionalmente el número de subventanas de la ventana del gráfico, si las hay, o bien comunica que no hay ninguna:

//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CChartObj::PrintShort(const bool dash=false)
  {
   ::Print
     (
      (dash ? "- " : ""),this.Header()," ID: ",(string)this.ID(),", HWND: ",(string)this.Handle(),
      ", ",CMessage::Text(MSG_CHART_OBJ_CHART_SUBWINDOWS_NUM),": ",(this.WindowsTotal()>1 ? string(this.WindowsTotal()-1) : CMessage::Text(MSG_LIB_TEXT_NO))
     );
  }
//+------------------------------------------------------------------+

Método que muestra en el diario los datos de todos los indicadores de todas las ventanas del gráfico:

//+-------------------------------------------------------------------+
//| Display data of all indicators of all chart windows in the journal|
//+-------------------------------------------------------------------+
void CChartObj::PrintWndIndicators(void)
  {
   for(int i=0;i<this.WindowsTotal();i++)
     {
      CChartWnd *wnd=m_list_wnd.At(i);
      if(wnd==NULL)
         continue;
      wnd.PrintIndicators(true);
     }
  }
//+------------------------------------------------------------------+

Aquí, en un ciclo por todos los objetos de ventana del gráfico, obtenemos el siguiente objeto de ventana del gráfico e imprimimos en el diario la descripción de todos los indicadores fijados a esta ventana. Transmitimos al método true para mostrar un guión antes de la descripción del indicador.

Método que muestra en el diario las propiedades de todas las ventanas del gráfico:

//+------------------------------------------------------------------+
//| Display the properties of all chart windows in the journal       |
//+------------------------------------------------------------------+
void CChartObj::PrintWndParameters(void)
  {
   for(int i=0;i<this.WindowsTotal();i++)
     {
      CChartWnd *wnd=m_list_wnd.At(i);
      if(wnd==NULL)
         continue;
      wnd.PrintParameters(true);
     }
  }
//+------------------------------------------------------------------+

Aquí, en un ciclo por todos los objetos de ventana del gráfico, obtenemos el siguiente objeto de ventana del gráfico e imprimimos en el diario la descripción de sus parámetros.. Transmitimos al método true para mostrar un guión antes de la descripción de la ventana.

Método que retorna un objeto de ventana según su número de subventana:

//+------------------------------------------------------------------+
//| Return the window object by its subwindow index                  |
//+------------------------------------------------------------------+
CChartWnd *CChartObj::GetWindowByNum(const int win_num) const
  {
   int total=m_list_wnd.Total();
   for(int i=0;i<total;i++)
     {
      CChartWnd *wnd=m_list_wnd.At(i);
      if(wnd==NULL)
         continue;
      if(wnd.WindowNum()==win_num)
         return wnd;
     }
   return NULL;
  }
//+------------------------------------------------------------------+

Aquí, en un ciclo por el número total de objetos de ventana del gráfico, obtenemos el siguiente objeto de ventana y si su número coincide con el transmitido al método, retornamos el puntero al objeto encontrado en la lista. Al finalizar el ciclo, retornamos NULL: el objeto no ha sido encontrado.

Método que establece la propiedad "visibilidad de la subventana" para un objeto de gráfico:

//+------------------------------------------------------------------+
//| Set the "Subwindow visibility" property                          |
//+------------------------------------------------------------------+
void CChartObj::SetVisible(void)
  {
   this.SetProperty(CHART_PROP_WINDOW_IS_VISIBLE,::ChartGetInteger(this.ID(),CHART_WINDOW_IS_VISIBLE,0));
  }
//+------------------------------------------------------------------+

Aquí, solo tenemos que escribir en la propiedad indicada la propiedad read/only correspondiente de la ventana principal del gráfico.

Método que retorna la distancia en píxeles a lo largo del eje vertical Y entre el marco superior de la subventana del indicador y el marco superior de la ventana principal del gráfico:

//+-----------------------------------------------------------------------------------+
//| Return the distance in pixels by Y axis between                                   |
//| the upper frame of the indicator subwindow and the upper frame of the main window |
//+-----------------------------------------------------------------------------------+
int CChartObj::WindowYDistance(const int sub_window) const
  {
   CChartWnd *wnd=GetWindowByNum(sub_window);
   return(wnd!=NULL ? wnd.YDistance() : WRONG_VALUE);
  }
//+------------------------------------------------------------------+

Aquí, obtenemos el objeto de ventana del gráfico según su número de subventana y retornamos el valor de la propiedad del objeto obtenido.
Si el objeto no se ha obtenido, retornaremos -1
.

Método que retorna la altura del gráfico indicado en píxeles:

//+------------------------------------------------------------------+
//| Return the height of the specified chart in pixels               |
//+------------------------------------------------------------------+
int CChartObj::WindowHeightInPixels(const int sub_window) const
  {
   CChartWnd *wnd=GetWindowByNum(sub_window);
   return(wnd!=NULL ? wnd.HeightInPixels() : WRONG_VALUE);
  }
//+------------------------------------------------------------------+

Aquí, obtenemos el objeto de ventana del gráfico según su número de subventana y retornamos el valor de la propiedad del objeto obtenido.
Si el objeto no se ha obtenido, retornaremos -1

Método que establece la altura del gráfico indicado en píxeles:

//+------------------------------------------------------------------+
//| Set the height of the specified chart in pixels                  |
//+------------------------------------------------------------------+
bool CChartObj::SetWindowHeightInPixels(const int height,const int sub_window,const bool redraw=false)
  {
   CChartWnd *wnd=GetWindowByNum(sub_window);
   return(wnd!=NULL ? wnd.SetHeightInPixels(height,redraw) : false);
  }
//+------------------------------------------------------------------+

Aquí, obtenemos el objeto de ventana del gráfico según su número de subventana y retornamos el valor de la configuración de la propiedad correspondiente del objeto obtenido.
Si el objeto no se ha obtenido, retornaremos false
.

Vamos a eliminar el método antiguo que escribimos en el artículo anterior:

//+------------------------------------------------------------------+
//| Set the height of the specified chart in pixels                  |
//+------------------------------------------------------------------+
bool CChartObj::SetWindowHeightInPixels(const int height,const int sub_window,const bool redraw=false)
  {
   ::ResetLastError();
   if(!::ChartSetInteger(this.ID(),CHART_HEIGHT_IN_PIXELS,sub_window,height))
     {
      CMessage::ToLog(DFUN,::GetLastError(),true);
      return false;
     }
   if(redraw)
      ::ChartRedraw(this.ID());
   return true;
  }
//+------------------------------------------------------------------+

Con esto, hemos finalizado la mejora de la clase del objeto de gráfico.


Simulación

Para comprobar el rendimiento de los objetos creados, simplemente abriremos tres gráficos. En la ventana principal del gráfico con el asesor, añadimos un indicador de fractales + la ventana de un indicador, por ejemplo, DeMarker, en el que ubicaremos otro más, por ejemplo, AMA, calculado con los datos de DeMarker.
En el segundo gráfico, colocaremos una ventana estocástica, mientras que la tercera ventana será desacoplable (Alt + D):


En el diario, mostraremos las descripciones breves de los tres objetos del gráfico y la descripción completa del gráfico actual en el que se encuentra el asesor.

Para la prueba, tomaremos el asesor del artículo anterior y
lo guardaremos en la carpeta \MQL5\Experts\TestDoEasy\Part68\ con el nuevo nombre TestDoEasyPart68.mq5.

El asesor permanecerá prácticamente sin cambios. Todo lo que necesitamos hacer es completar el código del manejador OnTick() con esta lógica:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Handle the NewTick event in the library
   engine.OnTick(rates_data);

//--- If working in the tester
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer(rates_data);   // Working in the timer
      PressButtonsControl();        // Button pressing control
      engine.EventsHandling();      // Working with events
     }

//--- If the trailing flag is set
   if(trailing_on)
     {
      TrailingPositions();          // Trailing positions
      TrailingOrders();             // Trailing pending orders
     }
   
//--- If it is the first launch
   static bool done=false;
   if(!done)
     {
      //--- Create the list object for storing chart objects
      CArrayObj *list=new CArrayObj();
      if(list==NULL)
         return;
      //--- Declare the variables and get the first chart ID
      long currChart,prevChart=ChartFirst(); 
      int i=0; 
      //--- Create the chart object and add it to the list
      CChartObj *chart_first=new CChartObj(prevChart);
      list.Add(chart_first);
      //--- In the loop by the total number of terminal charts (not more than 100)
      while(i<CHARTS_MAX)
        { 
         //--- based on the previous one, get the new chart
         currChart=ChartNext(prevChart);
         //--- When reaching the end of the chart list, complete the loop
         if(currChart<0) break;
         //--- Create the chart object based on the current chart ID in the loop and add it to the list
         CChartObj *chart=new CChartObj(currChart);
         list.Add(chart);
         //--- remember the current chart ID for ChartNext() and increase the loop counter
         prevChart=currChart;
         i++;
        }
      Print("");
      //--- From the filled list in the loop, receive the next chart object and display its short description
      int total=list.Total();
      for(int j=0;j<total;j++)
        {
         CChartObj *chart_obj=list.At(j);
         if(chart_obj!=NULL)
            chart_obj.PrintShort();
        }
      Print("");
      //--- Display the full description of the current chart: in the loop by all objects of the created list
      for(int j=0;j<total;j++)
        {
         //--- get the next chart object and
         CChartObj *chart_obj=list.At(j);
         //--- if its symbol matches the current chart symbol, display its full description in the journal
         if(chart_obj!=NULL && chart_obj.Symbol()==Symbol())
            chart_obj.Print();
        }
      //--- Destroy the list of chart objects
      delete list;
      done=true;
     }
//---
  }
//+------------------------------------------------------------------+

Compilamos el asesor y lo iniciamos en el gráfico, creando previamente en el terminal el entorno necesario descrito al principio de este apartado.

En el diario se mostrarán las descripciones breves de los tres gráficos abiertos:

Main chart window EURUSD H4 ID: 131733844391938630, HWND: 5179646, Subwindows: 1
Main chart window AUDUSD H4 ID: 131733844391938634, HWND: 3672036, Subwindows: 1
Main chart window GBPUSD H4 ID: 131733844391938633, HWND: 3473910, Subwindows: No

y la descripción completa del actual. El resultado del funcionamiento de las clases creadas hoy se representa en el diario como líneas ordenadas de las propiedades de los objetos de ventana y los indicadores fijados a ellas:

============= The beginning of the parameter list (Main chart window EURUSD H4) =============
Chart ID: 131733844391938630
Timeframe: H4
Drawing attributes of a price chart: Yes
Object "Chart": No
Chart on top of other charts: No
Accessing the context menu by pressing the right mouse button: Yes
Accessing the "Crosshair tool" by pressing the middle mouse button: Yes
Scrolling the chart horizontally using the left mouse button: Yes
Sending messages about mouse wheel events to all mql5 programs on a chart: No
Send notifications of mouse move and mouse click events to all mql5 programs on a chart: No
Send a notification of an event of new object creation to all mql5-programs on a chart: No
Send a notification of an event of object deletion to all mql5-programs on a chart: No
Chart type: Display as Japanese candlesticks
Price chart in the foreground: No
Price chart indent from the right border: Yes
Automatic moving to the right border of the chart: Yes
Managing the chart using a keyboard: Yes
Allowed to intercept Space and Enter key presses on the chart to activate the quick navigation bar: Yes
Scale: 2
Fixed scale mode: No
Scale 1:1 mode: No
Scale to be specified in points per bar: No
Display a symbol ticker in the upper left corner: Yes
Display OHLC values in the upper left corner: Yes
Display Bid values as a horizontal line in a chart: Yes
Display Ask values as a horizontal line in a chart: Yes
Display Last values as a horizontal line in a chart: No
Display vertical separators between adjacent periods: No
Display grid in the chart: No
Display volume in the chart: Trade volumes
Display textual descriptions of objects: Yes
The number of bars on the chart that can be displayed: 137
The total number of chart windows, including indicator subwindows: 2
Visibility of subwindow: Yes
Chart window handle: 5179646
Number of the first visible bar in the chart: 136
Chart width in bars: 168
Chart width in pixels: 670
 Main chart window:
 - Chart height in pixels: 301
 Chart subwindow 1:
 - The distance between the upper frame of the indicator subwindow and the upper frame of the main chart window: 303
 - Chart height in pixels: 13
Chart background color: clrWhite
Color of axes, scales and OHLC line: clrBlack
Grid color: clrSilver
Color of volumes and position opening levels: clrGreen
Color for the up bar, shadows and body borders of bull candlesticks: clrBlack
Color for the down bar, shadows and body borders of bear candlesticks: clrBlack
Line chart color and color of "Doji" Japanese candlesticks: clrBlack
Body color of a bull candlestick: clrWhite
Body color of a bear candlestick: clrBlack
Bid price level color: clrLightSkyBlue
Ask price level color: clrCoral
Line color of the last executed deal price (Last): clrSilver
Color of stop order levels (Stop Loss and Take Profit): clrOrangeRed
Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders): Yes
Permission to drag trading levels on a chart with a mouse: Yes
Showing the time scale on a chart: Yes
Showing the price scale on a chart: Yes
Showing the "One click trading" panel on a chart: No
Chart window is maximized: Yes
Chart window is minimized: No
The chart window is docked: Yes
The left coordinate of the undocked chart window relative to the virtual screen: 0
The top coordinate of the undocked chart window relative to the virtual screen: 0
The right coordinate of the undocked chart window relative to the virtual screen: 0
The bottom coordinate of the undocked chart window relative to the virtual screen: 0
------
The size of the zero bar indent from the right border in percents: 18.93
Chart fixed position from the left border in percent value: 0.00
Fixed  chart maximum: 1.22620
Fixed  chart minimum : 1.17940
Scale in points per bar: 1.00
Chart minimum: 1.17940
Chart maximum: 1.22620
------
Text of a comment in a chart: ""
The name of the Expert Advisor running on the chart: "TestDoEasyPart68"
The name of the script running on the chart: ""
Indicators in the main chart window:
- Indicator Fractals
Indicators in the chart window 1:
- Indicator DeM(14)
- Indicator AMA(14,2,30)
Symbol: "EURUSD"
============= End of the parameter list (Main chart window EURUSD H4) =============


¿Qué es lo próximo?

En el próximo artículo, comenzaremos a desarrollar la clase de colección de objetos de gráfico.

Más abajo se adjuntan todos los archivos de la versión actual de la biblioteca y el archivo del asesor de prueba para MQL5. Puede descargarlo todo y ponerlo a prueba por sí mismo.
Querríamos señalar que no resulta recomendable usar los objetos de gráfico en desarrollos propios en su estado actual, debido a los cambios adicionales que sufrirán más adelante.
Si tiene preguntas, observaciones o sugerencias, podrá concretarlas en los comentarios al artículo.

Volver al contenido

*Artículos de esta serie:

Trabajando con los precios en la biblioteca DoEasy (Parte 62): Actualización de las series de tick en tiempo real, preparando para trabajar con la Profundidad del mercado
Trabajando con los precios en la biblioteca DoEasy (Parte 63): Profundidad del mercado, clase de orden abstracta de la Profundidad del mercado
Trabajando con los precios en la biblioteca DoEasy (Parte 64): Profundidad del mercado, clases del objeto de instantánea y del objeto de serie de instantáneas del DOM
Trabajando con los precios y Señales en la biblioteca DoEasy (Parte 65): Colección de la profundidad de mercado y clase para trabajar con las Señales MQL5.com
Otras clases en la biblioteca DoEasy (Parte 66): Clases de Colección de Señales MQL5.com
Otras clases en la biblioteca DoEasy (Parte 67): Clase de objeto de gráfico

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

Archivos adjuntos |
MQL5.zip (3945.98 KB)
Scalping combinatorio: analizando transacciones del pasado para aumentar el rendimiento de las transacciones futuras Scalping combinatorio: analizando transacciones del pasado para aumentar el rendimiento de las transacciones futuras
Ofrecemos al lector la descripción de una tecnología para aumentar la eficacia de cualquier sistema de comercio automático. El artículo expone brevemente la idea, los fundamentos básicos, las posibilidades y las desventajas del método.
Otras clases en la biblioteca DoEasy (Parte 67): Clase de objeto de gráfico Otras clases en la biblioteca DoEasy (Parte 67): Clase de objeto de gráfico
En este artículo, crearemos una clase de objeto de gráfico (de un gráfico de un instrumento comercial) y modificaremos la clase de colección de objetos de señal mql5 para que cada objeto de señal guardado en la colección actualice también todos sus parámetros al actualizarse la lista.
Otras clases en la biblioteca DoEasy (Parte 69): Clases de colección de objetos de gráfico Otras clases en la biblioteca DoEasy (Parte 69): Clases de colección de objetos de gráfico
A partir de este artículo, comenzaremos el desarrollo de una colección de clases de objetos de gráfico que almacenará una colección de lista de objetos de gráfico con sus subventanas y los indicadores en ellas, y nos permitirá trabajar con cualquier gráfico seleccionado y sus subventanas, o bien directamente con una lista de varios gráficos al mismo tiempo.
Plantilla para proyectar el MVC y posibilidades de uso Plantilla para proyectar el MVC y posibilidades de uso
En el artículo, analizaremos una plantilla de MVC bastante extendida. Asimismo, estudiaremos sus posibilidades y las ventajas y desventajas de su uso en los programas MQL. Su esencia consiste en "dividir" el código existente en tres componentes separados: Modelo (Model), Vista (View) y Controlador (Controller).