English 中文 Español Deutsch 日本語 Português
Прочие классы в библиотеке DoEasy (Часть 68): Класс объекта-окна графика и классы объектов-индикаторов в окне графика

Прочие классы в библиотеке DoEasy (Часть 68): Класс объекта-окна графика и классы объектов-индикаторов в окне графика

MetaTrader 5Примеры | 26 марта 2021, 12:22
2 365 3
Artyom Trishkin
Artyom Trishkin

Содержание


Концепция

В прошлой статье мы начали разрабатывать класс объекта-чарта и сделали его первую версию. Объект описывает один чарт терминала со всеми его параметрами. Позволяет управлять его свойствами — получать и устанавливать параметры размеров окна и отображения элементов графика.

Но у нас на одном графике может быть несколько окон, в которых к тому же размещены индикаторы. У этих окон есть свои размеры, и наш объект-чарт пока может просто вернуть параметры указанного подокна, расположенного на нём, и управлять его высотой. В одном подокне (как и в главном окне графика) может быть размещено разное количество индикаторов, и нам нужно это учитывать, чтобы при обращении к объекту-чарту мы могли запросить требуемое окно, расположенное на чарте, а от полученного объекта-окна запросить список его индикаторов и получить хэндл нужного — чтобы далее уже работать с ним.

Сегодня мы создадим два объекта — объект индикатора в окне графика, который будет описывать некоторые параметры индикатора для его идентификации, и объект окна графика, в котором будут храниться его размеры и список индикаторов (объектов индикаторов в окне графика), прикреплённых к нему. Объект-чарт, который мы начали делать в прошлой статье, будет иметь список объектов-окон, прикреплённых к нему (включая главное окно графика).

В последующем такая иерархия нам сильно облегчит работу с множеством чартов и их подокнами со списками индикаторов в них. К сожалению, класс-коллекцию объектов-чартов, который был анонсирован в прошлой статье, пока создавать ещё рано — нам необходимо завершить все основные доработки объекта-чарта, что сегодня и сделаем.


Класс окна чарта с объектами-индикаторами в окне

В первую очередь дополним библиотеку всеми необходимыми текстами сообщений.
В файле \MQL5\Include\DoEasy\Data.mqh впишем индексы новых сообщений:

   MSG_CHART_OBJ_CHART_WINDOW,                        // Главное окно графика
   MSG_CHART_OBJ_CHART_SUBWINDOW,                     // Подокно графика
   MSG_CHART_OBJ_CHART_SUBWINDOWS_NUM,                // Подокон
   MSG_CHART_OBJ_INDICATORS_MW_NAME_LIST,             // Индикаторы в главном окне графика
   MSG_CHART_OBJ_INDICATORS_SW_NAME_LIST,             // Индикаторы в окне графика
   MSG_CHART_OBJ_INDICATOR,                           // Индикатор
   MSG_CHART_OBJ_INDICATORS_TOTAL,                    // Индикаторов
   MSG_CHART_OBJ_WINDOW_N,                            // Окно
   MSG_CHART_OBJ_INDICATORS_NONE,                     // Отсутствуют
  
  };
//+------------------------------------------------------------------+

и тексты сообщений, соответствующие вновь добавленным индексам:

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

При создании перечисления целочисленных свойств объекта-чарта мы намеренно пропустили три свойства, которые присущи не только объекту главного окна, но и всем подокнам чарта:

  • Видимость подокна,
  • Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика,
  • Высота графика в пикселях.

Именно эти свойства и будут основными свойствами объекта-окна графика (кроме видимости подокон, которую будем узнавать из объекта-чарта). Список окон графика будет присутствовать в каждом объекте-чарте, и у каждого объекта будут свои значения этих свойств. При этом, в каждом объекте-окне будет присутствовать список индикаторов, прикреплённых к этому окну, и нам потребуются указать дополнительные константы в перечисления целочисленных и строковых свойств объекта-чарта.

В файле \MQL5\Include\DoEasy\Defines.mqh раскомментируем ранее определённые, но закомментированные свойства — это свойства объекта-окна графика и впишем новые — для объекта-индикатора в окне графика:

//+------------------------------------------------------------------+
//| Целочисленные свойства чарта                                     |
//+------------------------------------------------------------------+
enum ENUM_CHART_PROP_INTEGER
  {
   CHART_PROP_ID = 0,                                 // Идентификатор графика
   CHART_PROP_TIMEFRAME,                              // Таймфрейм графика
   CHART_PROP_SHOW,                                   // Признак отрисовки ценового графика
   CHART_PROP_IS_OBJECT,                              // Признак идентификации объекта "График" (OBJ_CHART)
   CHART_PROP_BRING_TO_TOP,                           // Показ графика поверх всех других
   CHART_PROP_CONTEXT_MENU,                           // Включение/отключение доступа к контекстному меню по нажатию правой клавиши мышки. 
   CHART_PROP_CROSSHAIR_TOOL,                         // Включение/отключение доступа к инструменту "Перекрестие" по нажатию средней клавиши мышки
   CHART_PROP_MOUSE_SCROLL,                           // Прокрутка графика левой кнопкой мышки по горизонтали
   CHART_PROP_EVENT_MOUSE_WHEEL,                      // Отправка всем mql5-программам на графике сообщений о событиях колёсика мышки (CHARTEVENT_MOUSE_WHEEL)
   CHART_PROP_EVENT_MOUSE_MOVE,                       // Отправка всем mql5-программам на графике сообщений о событиях перемещения и нажатия кнопок мышки (CHARTEVENT_MOUSE_MOVE)
   CHART_PROP_EVENT_OBJECT_CREATE,                    // Отправка всем mql5-программам на графике сообщений о событии создания графического объекта (CHARTEVENT_OBJECT_CREATE)
   CHART_PROP_EVENT_OBJECT_DELETE,                    // Отправка всем mql5-программам на графике сообщений о событии уничтожения графического объекта (CHARTEVENT_OBJECT_DELETE)
   CHART_PROP_MODE,                                   // Тип графика (свечи, бары или линия (ENUM_CHART_MODE))
   CHART_PROP_FOREGROUND,                             // Ценовой график на переднем плане
   CHART_PROP_SHIFT,                                  // Режим отступа ценового графика от правого края
   CHART_PROP_AUTOSCROLL,                             // Режим автоматического перехода к правому краю графика
   CHART_PROP_KEYBOARD_CONTROL,                       // Разрешение на управление графиком с помощью клавиатуры
   CHART_PROP_QUICK_NAVIGATION,                       // Разрешение на перехват графиком нажатий клавиш Space и Enter для активации строки быстрой навигации
   CHART_PROP_SCALE,                                  // Масштаб
   CHART_PROP_SCALEFIX,                               // Режим фиксированного масштаба
   CHART_PROP_SCALEFIX_11,                            // Режим масштаба 1:1
   CHART_PROP_SCALE_PT_PER_BAR,                       // Режим указания масштаба в пунктах на бар
   CHART_PROP_SHOW_TICKER,                            // Отображение в левом верхнем углу тикера символа
   CHART_PROP_SHOW_OHLC,                              // Отображение в левом верхнем углу значений OHLC
   CHART_PROP_SHOW_BID_LINE,                          // Отображение значения Bid горизонтальной линией на графике
   CHART_PROP_SHOW_ASK_LINE,                          // Отображение значения Ask горизонтальной линией на графике
   CHART_PROP_SHOW_LAST_LINE,                         // Отображение значения Last горизонтальной линией на графике
   CHART_PROP_SHOW_PERIOD_SEP,                        // Отображение вертикальных разделителей между соседними периодами
   CHART_PROP_SHOW_GRID,                              // Отображение сетки на графике
   CHART_PROP_SHOW_VOLUMES,                           // Отображение объемов на графике
   CHART_PROP_SHOW_OBJECT_DESCR,                      // Отображение текстовых описаний объектов
   CHART_PROP_VISIBLE_BARS,                           // Количество баров на графике, доступных для отображения
   CHART_PROP_WINDOWS_TOTAL,                          // Общее количество окон графика, включая подокна индикаторов
   CHART_PROP_WINDOW_IS_VISIBLE,                      // Видимость подокна
   CHART_PROP_WINDOW_HANDLE,                          // Хэндл окна графика
   CHART_PROP_WINDOW_YDISTANCE,                       // Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   CHART_PROP_FIRST_VISIBLE_BAR,                      // Номер первого видимого бара на графике
   CHART_PROP_WIDTH_IN_BARS,                          // Ширина графика в барах
   CHART_PROP_WIDTH_IN_PIXELS,                        // Ширина графика в пикселях
   CHART_PROP_HEIGHT_IN_PIXELS,                       // Высота графика в пикселях
   CHART_PROP_COLOR_BACKGROUND,                       // Цвет фона графика
   CHART_PROP_COLOR_FOREGROUND,                       // Цвет осей, шкалы и строки OHLC
   CHART_PROP_COLOR_GRID,                             // Цвет сетки
   CHART_PROP_COLOR_VOLUME,                           // Цвет объемов и уровней открытия позиций
   CHART_PROP_COLOR_CHART_UP,                         // Цвет бара вверх, тени и окантовки тела бычьей свечи
   CHART_PROP_COLOR_CHART_DOWN,                       // Цвет бара вниз, тени и окантовки тела медвежьей свечи
   CHART_PROP_COLOR_CHART_LINE,                       // Цвет линии графика и японских свечей "Доджи"
   CHART_PROP_COLOR_CANDLE_BULL,                      // Цвет тела бычьей свечи
   CHART_PROP_COLOR_CANDLE_BEAR,                      // Цвет тела медвежьей свечи
   CHART_PROP_COLOR_BID,                              // Цвет линии Bid-цены
   CHART_PROP_COLOR_ASK,                              // Цвет линии Ask-цены
   CHART_PROP_COLOR_LAST,                             // Цвет линии цены последней совершенной сделки (Last)
   CHART_PROP_COLOR_STOP_LEVEL,                       // Цвет уровней стоп-ордеров (Stop Loss и Take Profit)
   CHART_PROP_SHOW_TRADE_LEVELS,                      // Отображение на графике торговых уровней (уровни открытых позиций, Stop Loss, Take Profit и отложенных ордеров)
   CHART_PROP_DRAG_TRADE_LEVELS,                      // Разрешение на перетаскивание торговых уровней на графике с помощью мышки
   CHART_PROP_SHOW_DATE_SCALE,                        // Отображение на графике шкалы времени
   CHART_PROP_SHOW_PRICE_SCALE,                       // Отображение на графике ценовой шкалы
   CHART_PROP_SHOW_ONE_CLICK,                         // Отображение на графике панели быстрой торговли
   CHART_PROP_IS_MAXIMIZED,                           // Окно графика развернуто
   CHART_PROP_IS_MINIMIZED,                           // Окно графика свернуто
   CHART_PROP_IS_DOCKED,                              // Окно графика закреплено
   CHART_PROP_FLOAT_LEFT,                             // Левая координата открепленного графика относительно виртуального экрана
   CHART_PROP_FLOAT_TOP,                              // Верхняя координата открепленного графика относительно виртуального экрана
   CHART_PROP_FLOAT_RIGHT,                            // Правая координата открепленного графика  относительно виртуального экрана
   CHART_PROP_FLOAT_BOTTOM,                           // Нижняя координата открепленного графика  относительно виртуального экрана
   //--- CWndInd
   CHART_PROP_WINDOW_IND_HANDLE,                      // Хэндл индикатора в окне графика
   CHART_PROP_WINDOW_IND_INDEX,                       // Индекс индикатора в окне графика
  };
#define CHART_PROP_INTEGER_TOTAL (67)                 // Общее количество целочисленных свойств
#define CHART_PROP_INTEGER_SKIP  (0)                  // Количество неиспользуемых в сортировке целочисленных свойств стакана
//+------------------------------------------------------------------+
//| Вещественные свойства чарта                                      |
//+------------------------------------------------------------------+
enum ENUM_CHART_PROP_DOUBLE
  {
   CHART_PROP_SHIFT_SIZE = CHART_PROP_INTEGER_TOTAL,  // Размер отступа нулевого бара от правого края в процентах
   CHART_PROP_FIXED_POSITION,                         // Положение фиксированной позиции графика от левого края в процентах
   CHART_PROP_FIXED_MAX,                              // Фиксированный максимум графика
   CHART_PROP_FIXED_MIN,                              // Фиксированный минимум графика
   CHART_PROP_POINTS_PER_BAR,                         // Значение масштаба в пунктах на бар
   CHART_PROP_PRICE_MIN,                              // Минимум графика
   CHART_PROP_PRICE_MAX,                              // Максимум графика
  };
#define CHART_PROP_DOUBLE_TOTAL  (7)                  // Общее количество вещественных свойств
#define CHART_PROP_DOUBLE_SKIP   (0)                  // Количество неиспользуемых в сортировке вещественных свойств
//+------------------------------------------------------------------+
//| Строковые свойства чарта                                         |
//+------------------------------------------------------------------+
enum ENUM_CHART_PROP_STRING
  {
   CHART_PROP_COMMENT = (CHART_PROP_INTEGER_TOTAL+CHART_PROP_DOUBLE_TOTAL), // Текст комментария на графике
   CHART_PROP_EXPERT_NAME,                            // Имя эксперта, запущенного на графике
   CHART_PROP_SCRIPT_NAME,                            // Имя скрипта, запущенного на графике
   CHART_PROP_INDICATOR_NAME,                         // Имя индикатора, запущенного на графике
   CHART_PROP_SYMBOL,                                 // Символ графика
  };
#define CHART_PROP_STRING_TOTAL  (5)                  // Общее количество строковых свойств
//+------------------------------------------------------------------+

Соответственно, изменим значения количества свойств, в перечислении которых добавили новые константы — количество целочисленных свойств увеличено с 62 до 67, а количество строковых — с 4 до 5.

В перечисление возможных критериев сортировки объектов-чартов впишем новые критерии, соответствующие вновь добавленным свойствам:

//+------------------------------------------------------------------+
//| Возможные критерии сортировки чартов                             |
//+------------------------------------------------------------------+
#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_CHART_SHOW = 0,                            // Сортировать по признаку отрисовки ценового графика
   SORT_BY_CHART_IS_OBJECT,                           // Сортировать по признаку идентификации объекта "График" (OBJ_CHART)
   SORT_BY_CHART_BRING_TO_TOP,                        // Сортировать по флагу показа графика поверх всех других
   SORT_BY_CHART_CONTEXT_MENU,                        // Сортировать по флагу включения/отключения доступа к контекстному меню по нажатию правой клавиши мышки
   SORT_BY_CHART_CROSSHAIR_TOO,                       // Сортировать по флагу включения/отключения доступа к инструменту "Перекрестие" по нажатию средней клавиши мышки
   SORT_BY_CHART_MOUSE_SCROLL,                        // Сортировать по флагу прокрутки графика левой кнопкой мышки по горизонтали
   SORT_BY_CHART_EVENT_MOUSE_WHEEL,                   // Сортировать по флагу отправки всем mql5-программам на графике сообщений о событиях колёсика мышки
   SORT_BY_CHART_EVENT_MOUSE_MOVE,                    // Сортировать по флагу отправки всем mql5-программам на графике сообщений о событиях перемещения и нажатия кнопок мышки
   SORT_BY_CHART_EVENT_OBJECT_CREATE,                 // Сортировать по флагу отправки всем mql5-программам на графике сообщений о событии создания графического объекта
   SORT_BY_CHART_EVENT_OBJECT_DELETE,                 // Сортировать по флагу отправки всем mql5-программам на графике сообщений о событии уничтожения графического объекта
   SORT_BY_CHART_MODE,                                // Сортировать по типу графика
   SORT_BY_CHART_FOREGROUND,                          // Сортировать по флагу "Ценовой график на переднем плане"
   SORT_BY_CHART_SHIFT,                               // Сортировать по флагу "Режим отступа ценового графика от правого края"
   SORT_BY_CHART_AUTOSCROLL,                          // Сортировать по флагу "Режим автоматического перехода к правому краю графика"
   SORT_BY_CHART_KEYBOARD_CONTROL,                    // Сортировать по флагу разрешения на управление графиком с помощью клавиатуры
   SORT_BY_CHART_QUICK_NAVIGATION,                    // Сортировать по флагу разрешения на перехват графиком нажатий клавиш Space и Enter для активации строки быстрой навигации
   SORT_BY_CHART_SCALE,                               // Сортировать по масштабу
   SORT_BY_CHART_SCALEFIX,                            // Сортировать по флагу фиксированного масштаба
   SORT_BY_CHART_SCALEFIX_11,                         // Сортировать по флагу масштаба 1:1
   SORT_BY_CHART_SCALE_PT_PER_BAR,                    // Сортировать по флагу указания масштаба в пунктах на бар
   SORT_BY_CHART_SHOW_TICKER,                         // Сортировать по флагу отображения в левом верхнем углу тикера символа
   SORT_BY_CHART_SHOW_OHLC,                           // Сортировать по флагу отображения в левом верхнем углу значений OHLC
   SORT_BY_CHART_SHOW_BID_LINE,                       // Сортировать по флагу отображения значения Bid горизонтальной линией на графике
   SORT_BY_CHART_SHOW_ASK_LINE,                       // Сортировать по флагу отображения значения Ask горизонтальной линией на графике
   SORT_BY_CHART_SHOW_LAST_LINE,                      // Сортировать по флагу отображения значения Last горизонтальной линией на графике
   SORT_BY_CHART_SHOW_PERIOD_SEP,                     // Сортировать по флагу отображения вертикальных разделителей между соседними периодами
   SORT_BY_CHART_SHOW_GRID,                           // Сортировать по флагу отображения сетки на графике
   SORT_BY_CHART_SHOW_VOLUMES,                        // Сортировать по режиму отображения объемов на графике
   SORT_BY_CHART_SHOW_OBJECT_DESCR,                   // Сортировать по флагу отображения текстовых описаний объектов
   SORT_BY_CHART_VISIBLE_BARS,                        // Сортировать по количеству баров на графике, доступных для отображения
   SORT_BY_CHART_WINDOWS_TOTAL,                       // Сортировать по общему количеству окон графика, включая подокна индикаторов
   SORT_BY_CHART_WINDOW_IS_VISIBLE,                   // Сортировать по флагу видимости подокон
   SORT_BY_CHART_WINDOW_HANDLE,                       // Сортировать по хэндлу графика
   SORT_BY_CHART_WINDOW_YDISTANCE,                    // Сортировать по дистанции в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   SORT_BY_CHART_FIRST_VISIBLE_BAR,                   // Сортировать по номеру первого видимого бара на графике
   SORT_BY_CHART_WIDTH_IN_BARS,                       // Сортировать по ширине графика в барах
   SORT_BY_CHART_WIDTH_IN_PIXELS,                     // Сортировать по ширине графика в пикселях
   SORT_BY_CHART_HEIGHT_IN_PIXELS,                    // Сортировать по высоте графика в пикселях
   SORT_BY_CHART_COLOR_BACKGROUND,                    // Сортировать по цвету фона графика
   SORT_BY_CHART_COLOR_FOREGROUND,                    // Сортировать по цвету осей, шкалы и строки OHLC
   SORT_BY_CHART_COLOR_GRID,                          // Сортировать по цвету сетки
   SORT_BY_CHART_COLOR_VOLUME,                        // Сортировать по цвету объемов и уровней открытия позиций
   SORT_BY_CHART_COLOR_CHART_UP,                      // Сортировать по цвету бара вверх, тени и окантовки тела бычьей свечи
   SORT_BY_CHART_COLOR_CHART_DOWN,                    // Сортировать по цвету бара вниз, тени и окантовки тела медвежьей свечи
   SORT_BY_CHART_COLOR_CHART_LINE,                    // Сортировать по цвету линии графика и японских свечей "Доджи"
   SORT_BY_CHART_COLOR_CANDLE_BULL,                   // Сортировать по цвету тела бычьей свечи
   SORT_BY_CHART_COLOR_CANDLE_BEAR,                   // Сортировать по цвету тела медвежьей свечи
   SORT_BY_CHART_COLOR_BID,                           // Сортировать по цвету линии Bid-цены
   SORT_BY_CHART_COLOR_ASK,                           // Сортировать по цвету линии Ask-цены
   SORT_BY_CHART_COLOR_LAST,                          // Сортировать по цвету линии цены последней совершенной сделки (Last)
   SORT_BY_CHART_COLOR_STOP_LEVEL,                    // Сортировать по цвету уровней стоп-ордеров (Stop Loss и Take Profit)
   SORT_BY_CHART_SHOW_TRADE_LEVELS,                   // Сортировать по флагу отображения на графике торговых уровней
   SORT_BY_CHART_DRAG_TRADE_LEVELS,                   // Сортировать по флагу разрешения на перетаскивание торговых уровней на графике с помощью мышки
   SORT_BY_CHART_SHOW_DATE_SCALE,                     // Сортировать по флагу отображения на графике шкалы времени
   SORT_BY_CHART_SHOW_PRICE_SCALE,                    // Сортировать по флагу отображения на графике ценовой шкалы
   SORT_BY_CHART_SHOW_ONE_CLICK,                      // Сортировать по флагу отображения на графике панели быстрой торговли
   SORT_BY_CHART_IS_MAXIMIZED,                        // Сортировать по флагу "Окно графика развернуто"
   SORT_BY_CHART_IS_MINIMIZED,                        // Сортировать по флагу "Окно графика свернуто"
   SORT_BY_CHART_IS_DOCKED,                           // Сортировать по флагу "Окно графика закреплено"
   SORT_BY_CHART_FLOAT_LEFT,                          // Сортировать по левой координате открепленного графика относительно виртуального экрана
   SORT_BY_CHART_FLOAT_TOP,                           // Сортировать по верхней координате открепленного графика относительно виртуального экрана
   SORT_BY_CHART_FLOAT_RIGHT,                         // Сортировать по правой координате открепленного графика  относительно виртуального экрана
   SORT_BY_CHART_FLOAT_BOTTOM,                        // Сортировать по нижней координате открепленного графика  относительно виртуального экрана
   SORT_BY_CHART_WINDOW_IND_HANDLE,                   // Сортировать по хэндлу индикатора в окне графика
   SORT_BY_CHART_WINDOW_IND_INDEX,                    // Сортировать по индексу индикатора в окне графика
//--- Сортировка по вещественным свойствам
   SORT_BY_CHART_SHIFT_SIZE = FIRST_CHART_DBL_PROP,   // Сортировать по размеру отступа нулевого бара от правого края в процентах
   SORT_BY_CHART_FIXED_POSITION,                      // Сортировать по положению фиксированной позиции графика от левого края в процентах
   SORT_BY_CHART_FIXED_MAX,                           // Сортировать по фиксированному максимуму графика
   SORT_BY_CHART_FIXED_MIN,                           // Сортировать по фиксированному минимуму графика
   SORT_BY_CHART_POINTS_PER_BAR,                      // Сортировать по значению масштаба в пунктах на бар
   SORT_BY_CHART_PRICE_MIN,                           // Сортировать по минимуму графика
   SORT_BY_CHART_PRICE_MAX,                           // Сортировать по максимуму графика
//--- Сортировка по строковым свойствам
   SORT_BY_CHART_COMMENT = FIRST_CHART_STR_PROP,      // Сортировать по тексту комментария на графике
   SORT_BY_CHART_EXPERT_NAME,                         // Сортировать по имени эксперта, запущенного на графике
   SORT_BY_CHART_SCRIPT_NAME,                         // Сортировать по имени скрипта, запущенного на графике
   SORT_BY_CHART_INDICATOR_NAME,                      // Сортировать по имени индикатора, запущенного на графике
   SORT_BY_CHART_SYMBOL,                              // Сортировать по символу графика
  };
//+------------------------------------------------------------------+

В первой версии объекта-чарта этот список критериев был некорректен — были вписаны в критерии сортировки закомментированные целочисленные свойства чарта и отсутствовала сортировка по наименованию символа. Сегодня мы это исправили.

Сейчас нам нужно создать два класса — класс объекта-индикатора в окне графика и класс объекта-окна графика. Впишем их сразу в один файл.

В папке библиотеки \MQL5\Include\DoEasy\Objects\Chart\ создадим новый файл  ChartWnd.mqh классов CWndInd (индикатор в окне графика) и CChartWnd (окно графика).

Класс CWndInd должен быть унаследован от базового класса стандартной библиотеки CObject, а класс CChartWnd — от базового объекта всех объектов библиотеки CBaseObj.

К окну графика может быть прикреплено множество различных индикаторов. Соответственно, объект окна графика должен знать об их существовании — чтобы мы всегда могли получить хэндл нужного индикатора из окна графика и далее работать с ним. Для идентификации индикаторов нам не нужно множество различных параметров — достаточно знать хэндл индикатора, его короткое наименование и индекс окна графика, к которому прикреплён индикатор. Поэтому класс объекта-индикатора в окне графика будет простейшим, и унаследован он будет от базового объекта стандартной библиотеки — просто для того, чтобы мы могли все эти объекты добавить в список указателей на объекты CArrayObj, находящийся в составе объекта-окна графика.

Напишем во вновь созданном файле ChartWnd.mqh код нового класса:

//+------------------------------------------------------------------+
//|                                                     ChartWnd.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Класс объекта-индикатора окна графика                            |
//+------------------------------------------------------------------+
class CWndInd : public CObject
  {
private:
   long              m_chart_id;                         // Идентификатор графика
   string            m_name;                             // Короткое имя индикатора
   int               m_index;                            // Индекс окна на графике
   int               m_handle;                           // Хэндл индикатора
public:
//--- Возвращает себя
   CWndInd          *GetObject(void)                     { return &this;         }
//--- Возвращает (1) имя индикатора, (2) индекс окна, (3) хэндл индикатора
   string            Name(void)                    const { return this.m_name;   }
   int               Index(void)                   const { return this.m_index;  }
   int               Handle(void)                  const { return this.m_handle; }
   
//--- Выводит в журнал описание свойств объекта (dash=true - дефис перед описанием, false - только описание)
   void              Print(const bool dash=false)        { ::Print((dash ? "- " : "")+this.Header());                      }
//--- Возвращает краткое наименование объекта
   string            Header(void)                  const { return CMessage::Text(MSG_CHART_OBJ_INDICATOR)+" "+this.Name(); }
   
//--- Сравнивает объекты CWndInd между собой по указанному свойству
   virtual int       Compare(const CObject *node,const int mode=0) const;

//--- Конструкторы
                     CWndInd(void);
                     CWndInd(const int handle,const string name,const int index) : m_handle(handle),m_name(name),m_index(index) {}
  };
//+------------------------------------------------------------------+
//| Сравнивает объекты CWndInd между собой по указанному свойству    |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

Это весь класс объекта-индикатора в окне графика.
В приватной секции расположены переменные-члены класса для хранения:

  • идентификатор графика, на котором расположено окно с этим индикатором,
  • короткое имя индикатора (в окнах графиков индикаторы идентифицируются терминалом по их коротким наименованиям),
  • индекс окна графика, в котором расположен индикатор (0 индекс — главное окно чарта, индекс 1 и далее — подокна графика),
  • хэндл этого индикатора.

Этих данных нам будет достаточно для того, чтобы хранить в объекте-окна чарта список всех индикаторов, прикреплённых к окну. А сам список будет содержать в себе вот именно эти объекты, по которым мы сможем найти нужный индикатор и вернуть его хэндл для дальнейшей с ним работы.

Публичные методы, возвращающие значения вышеперечисленных переменных, в пояснениях не нуждаются. Рассмотрим остальные некоторые методы класса.

Метод, возвращающий краткое наименование объекта-индикатора:

//--- Возвращает краткое наименование объекта
   string            Header(void)                  const { return CMessage::Text(MSG_CHART_OBJ_INDICATOR)+" "+this.Name(); }

Просто возвращается заголовок "Индикатор " + короткое имя индикатора.

Метод, выводящий в журнал описание свойств объекта-индикатора:

//--- Выводит в журнал описание свойств объекта (dash=true - дефис перед описанием, false - только описание)
   void              Print(const bool dash=false)        { ::Print((dash ? "- " : "")+this.Header());                      }

Так как индикаторов в окне графика может быть несколько, то выводиться они будут списком под заголовком. Поэтому для более красивого вывода списка в журнал мы будем использовать дефис перед именем индикатора, необходимость вывода которого будем указывать входным параметром метода.

У нас есть два конструктора: один — по умолчанию, а второй параметрический. Конструктор по умолчанию может пригодиться для создания "пустого" объекта-индикатора в окне, а параметрический конструктор будем использовать как основной конструктор класса при создании списка индикаторов в классе объекта-окна графика.

В параметрический конструктор передаются хэндл индикатора, его короткое наименование и индекс подокна, в котором находится этот индикатор.

//--- Конструкторы
                     CWndInd(void);
                     CWndInd(const int handle,const string name,const int index) : m_handle(handle),m_name(name),m_index(index) {}

Все переданные в метод значения параметров сразу же присваиваются переменным класса в его списке инициализации.

Метод, для сравнения объектов-индикаторов окна графика между собой по указанному свойству:

//+------------------------------------------------------------------+
//| Сравнивает объекты CWndInd между собой по указанному свойству    |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

Для данного объекта у нас нет своих собственных перечислений его свойств — все его свойства присутствуют в перечислениях свойств объекта-чарта. Поэтому в метод могут передаваться любые из свойств объекта-чарта, но сравнение по переданным свойствам будет произведено только если в параметре mode передано свойство "хэндл индикатора" или "индекс окна графика". В любых других случаях сравнение будет проводиться по короткому имени индикатора.

Метод сравнения стандартен для всех объектов библиотеки: если значение параметра текущего объекта больше значения сравниваемого, то возвращается 1, если значение параметра текущего объекта меньше значения сравниваемого — возвращается -1, иначе возвращается 0.

Приступим к созданию класса объекта-окна графика.

В этом же файле, в котором написали класс объекта-индикатора в окне графика (ChartWnd.mqh), продолжим писать код и впишем класс объекта-окна графика. Класс должен быть унаследован от базового объекта всех объектов библиотеки CBaseObj:

//+------------------------------------------------------------------+
//| Класс объекта-окна графика                                       |
//+------------------------------------------------------------------+
class CChartWnd : public CBaseObj
  {
  }

В приватной секции класса будут находиться список указателей на объекты-индикаторы в этом окне, номер этого подокна, описываемого объектом, и вспомогательные методы для оранизации работы класса:

//+------------------------------------------------------------------+
//| Класс объекта-окна графика                                       |
//+------------------------------------------------------------------+
class CChartWnd : public CBaseObj
  {
private:
   CArrayObj         m_list_ind;                                        // Список индикаторов
   int               m_window_num;                                      // Номер подокна
//--- Возвращает флаг наличия индикатора из списка в окне
   bool              IsPresentInWindow(const CWndInd *ind);
//--- Удаляет из списка уже отсутствующие в окне индикаторы
   void              IndicatorsDelete(void);
//--- Добавляет в список новые индикаторы
   void              IndicatorsAdd(void);
//--- Устанавливает номер подокна
   void              SetWindowNum(const int num)                        { this.m_window_num=num;   }
public:

В публичной секции класса расположены стандартные для объектов библиотеки методы (за исключением методов для установки значений свойств — по причине, что для этого объекта нет своих списков-перечислений свойств, и мы будем только возвращать требуемые значения, описываемые некоторыми свойствами объекта-чарта, которые принадлежат окну графика), и эти методы мы уже не раз рассматривали в предыдущих статьях.
Также в классе присутствуют методы для установки и возврата значений свойств окна и для работы с классом. Их устройство мы рассмотрим ниже.

//+------------------------------------------------------------------+
//| Класс объекта-окна графика                                       |
//+------------------------------------------------------------------+
class CChartWnd : public CBaseObj
  {
private:
   CArrayObj         m_list_ind;                                        // Список индикаторов
   int               m_window_num;                                      // Номер подокна
//--- Возвращает флаг наличия индикатора из списка в окне
   bool              IsPresentInWindow(const CWndInd *ind);
//--- Удаляет из списка уже отсутствующие в окне индикаторы
   void              IndicatorsDelete(void);
//--- Добавляет в список новые индикаторы
   void              IndicatorsAdd(void);
//--- Устанавливает номер подокна
   void              SetWindowNum(const int num)                        { this.m_window_num=num;   }
public:
//--- Возвращает себя
   CChartWnd        *GetObject(void)                                    { return &this;            }

//--- Возвращает флаг поддержания объектом данного свойства
   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); }

//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства
   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);  }

//--- Выводит в журнал описание свойств объекта (full_prop=true - все свойства, false - только поддерживаемые)
   void              Print(const bool full_prop=false);
//--- Выводит в журнал краткое описание объекта
   virtual void      PrintShort(const bool dash=false);
//--- Возвращает краткое наименование объекта
   virtual string    Header(void);
   
//--- Сравнивает объекты CChartWnd между собой по указанному свойству (для сортировки списка по свойству объекта-mql5-сигнала)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CChartWnd между собой по всем свойствам (для поиска равных объектов-mql5-сигналов)
   bool              IsEqual(CChartWnd* compared_obj) const;
   
//--- Конструкторы
                     CChartWnd(void);
                     CChartWnd(const long chart_id,const int wnd_num);

//--- Возвращает дистанцию в пикселях между границами окон
   int               YDistance(void)                              const { return (int)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.m_window_num);}
//--- (1) Возвращает, (2) устанавливает высоту окна в пикселях
   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);
//--- Возвращает (1) номер подокна, (2) количество индикаторов, прикреплённых к окну
   int               WindowNum(void)                              const { return this.m_window_num;}
   int               IndicatorsTotal(void)                        const { return this.m_list_ind.Total();   }
   
//--- Возвращает (1) список индикаторов, (2) объект-индикатор окна из списка п индексу
   CArrayObj        *GetIndicatorsList(void)                            { return &this.m_list_ind;          }
   CWndInd          *GetIndicator(const int index)                      { return this.m_list_ind.At(index); }
   
//--- Выводит в журнал описание индикаторов, прикреплённых к окну графика
   void              PrintIndicators(const bool dash=false);
//--- Выводит в журнал описание параметров окна
   void              PrintParameters(const bool dash=false);
   
//--- Создаёт список прикреплённых к окну индикаторов
   void              IndicatorsListCreate(void);
//--- Обновляет данные по прикреплённым индикаторам
   void              Refresh(void);
   
  };
//+------------------------------------------------------------------+

Метод, возвращающий дистанцию в пикселях между границами окон:

//--- Возвращает дистанцию в пикселях между границами окон
   int YDistance(void) const { return (int)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.m_window_num);}

Так как свойство графика CHART_WINDOW_YDISTANCE предназначено только для чтения, то метода, устанавливающего это значение, здесь нет. Метод просто возвращает значение этого свойства для именно этого подокна графика.

Метод, возвращающий высоту окна в пикселях:

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

Работает идентично вышерассмотренному, и возвращает значение этого свойства для номера окна, указанного в переменной m_window_num.

Метод, устанавливающий высоту окна в пикселях (в теле класса объявлен, а реализован за пределами тела класса):

//+------------------------------------------------------------------+
//| Устанавливает высоту окна в пикселях                             |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Метод устроен аналогично методам, устанавливающим значения свойств объекта-чарта, рассмотренных нами в прошлой статье. В метод передаётся требуемое для установки значение, затем пытаемся его установить окну при помощи функции ChartSetInteger(), и если событие изменения графика не было поставлено в очередь, то сообщаем об этом и возвращаем false. Если событие успешно поставлено в очередь, то возвращаем true, предварительно перерисовав чарт при установленном флаге redraw. Принудительная перерисовка чарта необходима для того, чтобы не ждать любого события чарта (приход котировки, изменение размеров, клик мышкой и т.д.) для отображения изменений, а сразу же перерисовать график и увидеть результат.

Метод, сравнивающий объекты окна графика между собой по указанному свойству:

//+------------------------------------------------------------------+
//| Сравнивает объекты CChartWnd между собой по указанному свойству  |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Здесь точно так же, как и в методе сравнения в классе индикатора окна графика, рассмотренного нами выше, мы сравниваем только некоторые свойства, прописанные в перечислениях свойств объекта-чарта:

  • Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика,
  • Высота графика в пикселях,
  • В любых других случаях возвращаем -1

Метод, сравнивающий объекты окна графика между собой по всем свойствам:

//+------------------------------------------------------------------+
//| Сравнивает объекты CChartWnd между собой по всем свойствам       |
//+------------------------------------------------------------------+
bool CChartWnd::IsEqual(CChartWnd *compared_obj) const
  {
   return(this.YDistance()!=compared_obj.YDistance() || this.HeightInPixels()!=compared_obj.HeightInPixels() ? false : true);
  }
//+------------------------------------------------------------------+

Здесь: если хоть одно из двух свойств сравниваемых объектов возвращает неравенство, то возвращаем false — объекты не равны между собой. Иначе возвращаем true — объекты идентичны.

Метод, возвращающий описание целочисленного свойства:

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства объекта              |
//+------------------------------------------------------------------+
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()
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

В зависимости от того, какое из двух целочисленных свойств объекта-окна графика передано в метод, создаётся и возвращается строка с его описанием.

Метод, выводящий в журнал свойства объекта:

//+------------------------------------------------------------------+
//| Выводит в журнал свойства объекта                                |
//+------------------------------------------------------------------+
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");
  }
//+------------------------------------------------------------------+

В трёх циклах по всем свойствам объекта-чарта получаем очередное свойство и выводим в журнал его описание. Так как у объекта-окна графика нет собственных списков-перечислений его свойств, то нам необходимо вывести на печать только те свойства объекта-чарта, которые присущи объекту-окну графика — целочисленные и строковые. Вещественные же свойства у этого объекта отсутствуют и их выводить не нужно. Мы могли бы сделать иначе — просто задать жёсткие рамки начала и конца каждого цикла... Но это не очень верное решение с точки зрения последующих доработок свойств объекта-чарта — нам придётся возвращаться к этому объекту и править значения начала и конца каждого цикла. Поэтому мы просто цикл по вещественным свойствам сделаем пустым (может быть временно — пока не понядобятся вещественные свойства объекту-окну графика при возможных последующих доработках). Таким образом, при любых изменениях количества свойств начало и конец каждого цикла всегда будут верными.

Метод, возвращающий краткое наименование объекта-окна графика:

//+------------------------------------------------------------------+
//| Возвращает краткое наименование объекта                          |
//+------------------------------------------------------------------+
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));
  }
//+------------------------------------------------------------------+

В методе проверяется номер этого подокна, и если это главное окно графика (его номер 0), то возвращается строка "Главное окно графика", если же это подокно главного графика, то возвращается  Номер подокна + строка "Подокно графика"

Метод, выводящий в журнал краткое описание объекта-окна графика:

//+------------------------------------------------------------------+
//| Выводит в журнал краткое описание объекта                        |
//+------------------------------------------------------------------+
void CChartWnd::PrintShort(const bool dash=false)
  {
   ::Print((dash ? "- " : ""),this.Header()," ID: ",(string)this.GetChartID(),", ",CMessage::Text(MSG_CHART_OBJ_INDICATORS_TOTAL),": ",this.IndicatorsTotal());
  }
//+------------------------------------------------------------------+

Здесь мы создаём строку из краткого наименования объекта, идентификатора графика и количества индикаторов, прикреплённых к этому окну. Если в метод передан флаг необходимости вывода дефиса перед описанием объекта (dash), то перед созданной строкой выводится дефис.

Метод, выводящий в журнал описание всех индикаторов, прикреплённых к данному окну:

//+------------------------------------------------------------------+
//| Выводит в журнал описание индикаторов, прикреплённых к окну      |
//+------------------------------------------------------------------+
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);
     }
  }
//+------------------------------------------------------------------+

Сначала создаём и выводим в журнал заголовок в зависимости от того, какое это окно.
Если это главное окно графика, то текст заголовка будет "Индикаторы в главном окне графика",
иначе — текст заголовка будет "Индикаторы в окне графика" + Номер данного окна.
Затем смотрим на количество индикаторов, прикреплённых к этому окну, и если их нет, то выводим строку "Отсутствуют",
иначе — в цикле по списку всех индикаторов получаем очередной объект-индикатор в окне графика и распечатываем его данные.

Метод, выводящий в журнал описание параметров окна:

//+------------------------------------------------------------------+
//| Выводит в журнал описание параметров окна                        |
//+------------------------------------------------------------------+
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));
  }
//+------------------------------------------------------------------+

Сначала создаём и выводим в журнал заголовок в зависимости от того, какое это окно.
Если это главное окно графика, то текст заголовка будет "Главное окно графика",
иначе — текст заголовка будет "Подокно графика" + Номер данного окна.
Затем, если это подокно графика (его номер больше нуля), то выводим в журнал значение дистанции в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика (для главного окна это значение всегда 0, и мы его не вывоим), а следом выводим в журнал второе свойство объекта — высоту графика в пикселях.

Метод, создающий список прикреплённых к окну индикаторов:

//+------------------------------------------------------------------+
//| Создаёт список прикреплённых к окну индикаторов                  |
//+------------------------------------------------------------------+
void CChartWnd::IndicatorsListCreate(void)
  {
   //--- Очищаем список индикаторов
   this.m_list_ind.Clear();
   //--- Получаем общее количество индикаторов в окне
   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);
      //--- Создаём новый объект-индикатора в окне графика
      CWndInd *ind=new CWndInd(handle,name,i);
      if(ind==NULL)
         continue;
      //--- устанавливаем списку флаг сортированного списка
      this.m_list_ind.Sort();
      //--- Если объект добавить в список не удалось - удаляем его
      if(!this.m_list_ind.Add(ind))
         delete ind;
     }
  }
//+------------------------------------------------------------------+

Метод подробно прокомментирован в коде. Отмечу, что при получении списка индикаторов в окне мы получаем хэндл индикатора по его короткому имени при помощи ChartIndicatorGet(), что накладывает на нас некоторые "обязанности". Терминал ведёт подсчёт использования каждого индикатора, и с каждым новым получением его хэндла увеличивает внутренний счётчик использования данного индикатора. Если мы в своей программе не позаботимся сами об освобождении уже ненужного нам хэндла индикатора, то потом отловить "потерявшийся" хэндл будет невозможно. Поэтому здесь мы сразу же после получения всех нужных данных об индикаторе, освобождаем хэндл, тем самым уменьшая внутренний счётчик использования этого индикатора.

Метод, добавляющий в список новые индикаторы:

//+------------------------------------------------------------------+
//| Добавляет в список новые индикаторы                              |
//+------------------------------------------------------------------+
void CChartWnd::IndicatorsAdd(void)
  {
   //--- Получаем общее количество индикаторов в окне
   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);
      //--- Создаём новый объект-индикатора в окне графика
      CWndInd *ind=new CWndInd(handle,name,i);
      if(ind==NULL)
         continue;
      //--- устанавливаем списку флаг сортированного списка
      this.m_list_ind.Sort();
      //--- Если объект уже есть в списке, или добавить его в список не удалось - удаляем его
      if(this.m_list_ind.Search(ind)>WRONG_VALUE || !this.m_list_ind.Add(ind))
         delete ind;
     }
  }
//+------------------------------------------------------------------+

Логика метода идентична вышерассмотренному, так же прокомментирована в коде. Разницей является лишь то, что в данном методе список изначально не очищается, а при добавлении индикатора в список сначала проверяется наличие такого индикатора в списке и, если он уже есть, то объект этого индикатора удаляется.

Чтобы мы могли в последующем синхронизировать наш список индикаторов в окне с их реальным количеством (ведь индикаторы могут добавляться в окно и сниматься с окна графика), нам необходимо сравнивать их количество в окне с количеством в списке. Это будем делать в последующих статьях, но
метод, возвращающий наличие индикатора из списка в окне терминала мы сделаем:

//+------------------------------------------------------------------+
//| Возвращает флаг наличия индикатора из списка в окне              |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

В метод передаётся указатель на объект-индикатор в окне графика, реальное наличие которого необходимо проверить. Затем в цикле по общему количеству индикаторов в окне графика получаем имя очередного индикатора, получаем его хэндл и сразу же его освобождаем. Если короткое имя и хэндл текущего индикатора совпадают с именем и хэндлом проверяемого объекта, то возвращаем true — этот индикатор ещё есть в окне графика. По окончании цикла возвращаем false — не было найдено совпадений, а значит, и нет такого индикатора в окне графика.

Если же у нас были найдены в списке индикаторы, отсутствующие на графике, то их необходимо удалить из списка.
Метод, удаляющий из списка уже отсутствующие в окне индикаторы:

//+------------------------------------------------------------------+
//| Удаляет из списка уже отсутствующие в окне индикаторы            |
//+------------------------------------------------------------------+
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);
     }
  }
//+------------------------------------------------------------------+

Здесь: в цикле по списку объектов-индикаторов получаем очередной объект-индикатор по индексу цикла и проверяем его наличие в реальном окне графика. Если он там отсутствует, то указатель на него удаляем из нашего списка при помощи метода Delete().

В последующем, когда будем делать класс-коллекцию чартов, нам необходимо будет отслеживать состояние индикаторов в подокнах всех объектов-чартов, и в случае найденных расхождений реального количества индикаторов в подокнах чартов с их описаниями в списках объектов-окон графика, нам нужно будет удалить лишние индикаторы из списка и добавить новые при их наличии.

Для этого создадим метод, обновляющий данные по прикреплённым к окнам графиков индикаторам:

//+------------------------------------------------------------------+
//| Обновляет данные по прикреплённым индикаторам                    |
//+------------------------------------------------------------------+
void CChartWnd::Refresh(void)
  {
   this.IndicatorsDelete();
   this.IndicatorsAdd();
  }
//+------------------------------------------------------------------+

Здесь мы сначала ищем и удаляем из списка отсутствующие на реальном графике в его окне индикаторы, которые ещё есть в списке, а затем ищем и добавляем новые индикаторы, которые есть в окне, но ещё отсутствуют в списке при помощи вышерассмотренных методов.

Напоследок рассмотрим параметрический конструктор класса:

//+------------------------------------------------------------------+
//| Параметрический конструктор                                      |
//+------------------------------------------------------------------+
CChartWnd::CChartWnd(const long chart_id,const int wnd_num) : m_window_num(wnd_num)
  {
   CBaseObj::SetChartID(chart_id);
   this.IndicatorsListCreate();
  }
//+------------------------------------------------------------------+

Здесь мы первым делом устанавливаем значение идентификатора графика в родительском объекте CBaseObj, а затем создаём список индикаторов, прикреплённых к этому окну графика. Номер подокна графика устанавливаем в списке инициализации конструктора.

На этом создание классов объекта-индикатора в окне графика и объекта-окна графика завершено.
Полный листинг обоих классов, расположенных в одном файле, можно посмотреть в прикреплённых к статье файлах.

Так как теперь у нас появился объект, описывающий окно графика и его подокна, соответственно, то нам необходимо доработать класс объекта-чарта  CChartObj, находящийся в файле \MQL5\Include\DoEasy\Objects\Chart\ChartObj.mqh. Теперь он будет иметь список всех подокон, расположенных на его главном окне, и для получения данных о свойствах окна нам нужно будет обратиться по указателю на нужный объект-окна графика, созданный нами выше. А из полученного объекта-окна мы в свою очередь сможем получить список всех индикаторов прикреплённых к нему, а от них получить хэндл нужного индикатора для работы с ним.

В первую очередь подключим к файлу объекта-чарта файл объектов окна и индикаторов в окне и объявим объект-список, в котором будем хранить указатели на все окна объекта-чарта:

//+------------------------------------------------------------------+
//|                                                     ChartObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\..\Objects\BaseObj.mqh"
#include "ChartWnd.mqh"
//+------------------------------------------------------------------+
//| Класс объекта-чарта                                              |
//+------------------------------------------------------------------+
class CChartObj : public CBaseObj
  {
private:
   CArrayObj         m_list_wnd;                                  // Список объектов окон графика
   long              m_long_prop[CHART_PROP_INTEGER_TOTAL];       // Целочисленные свойства
   double            m_double_prop[CHART_PROP_DOUBLE_TOTAL];      // Вещественные свойства
   string            m_string_prop[CHART_PROP_STRING_TOTAL];      // Строковые свойства
   int               m_digits;                                    // Digits() символа

В приватной секции класса в списке методов установки значений свойств добавим метод, устанавливающий значение видимости окна графика:

//--- Методы установки значений свойств
   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:

Так как свойство "Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика" для главного окна не имеет смысла (там всегда 0), то изменим в методе, возвращающем флаг поддержания объектом целочисленного свойства, возврат значения в случае, если это свойство CHART_PROP_WINDOW_YDISTANCE:

//--- Возвращает флаг поддержания объектом данного свойства
   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; }

Если переданное в метод свойство не равно CHART_PROP_WINDOW_YDISTANCE, то возвращаем true, иначе возвращаем false.

В список методов для упрощённого доступа к свойствам объекта добавим метод, возвращающий видимость окна:

//--- Возвращает общее количество окон графика, включая подокна индикаторов
   int               WindowsTotal(void)                              const { return (int)this.GetProperty(CHART_PROP_WINDOWS_TOTAL);      }

//--- Возвращает видимость окна
   bool              Visible(void)                                   const { return (bool)this.GetProperty(CHART_PROP_WINDOW_IS_VISIBLE); }

//--- Возвращает хэндл окна графика
   int               Handle(void)                                    const { return (int)this.GetProperty(CHART_PROP_WINDOW_HANDLE);      } 

Здесь метод будет возвращать это свойство только главного окна чарта.

Методы, возвращающие дистанцию в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика, возвращающий и устанавливающий высоту указанного графика в пикселях, претерпели изменения. Теперь для установки и возврата этих свойств нам нужно будет найти объект нужного окна, и уже в его свойства вписать или получить эти значения. Реализацию методов рассмотрим чуть позже.

//--- Возвращает имя скрипта, запущенного на графике
   string            ScriptName(void)                                const { return this.GetProperty(CHART_PROP_SCRIPT_NAME);             }

//--- Возвращает дистанцию в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   int               WindowYDistance(const int sub_window)           const;
   
//--- (1) Возвращает, (2) устанавливает высоту указанного графика в пикселях
   int               WindowHeightInPixels(const int sub_window)      const;
   bool              SetWindowHeightInPixels(const int height,const int sub_window,const bool redraw=false);
   
//--- Возвращает видимость указанного подокна

В самом низу тела класса объявим дополнительные методы для получения нужного объекта-окна и для вывода в журнал свойств всех подокон графика и данных всех индикаторов, прикреплённых к указанному окну графика:

//--- Эмулирует тик (обновления графика - аналогично команде Refresh в терминале)
   void              EmulateTick(void)                                     { ::ChartSetSymbolPeriod(this.ID(),this.Symbol(),this.Timeframe());}

//--- Возвращает указанное по индексу окно графика
   CChartWnd        *GetWindowByIndex(const int index)               const { return this.m_list_wnd.At(index); }
//--- Возвращает объект-окно по его номеру подокна
   CChartWnd        *GetWindowByNum(const int win_num)               const;
   
//--- Выводит в журнал данные всех индикаторов всех окон графика
   void              PrintWndIndicators(void);
//--- Выводит в журнал свойства всех окон графика
   void              PrintWndParameters(void);

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

В параметрическом конструкторе класса установим значение идентификатора графика в родительском объекте класса, укажем три свойства главного окна объекту-чарту (это можно было и не делать, так как объект главного окна теперь нахоится в списке всех окон чарта, но раз есть такие свойства у объекта, то мы их заполним корректными данными), и в самом конце метода добавим в список всех окон чарта все объекты-окна, принадлежащие данному чарту:

//+------------------------------------------------------------------+
//| Параметрический конструктор                                      |
//+------------------------------------------------------------------+
CChartObj::CChartObj(const long chart_id)
  {
//--- Установка идентификатора графика в базовый объект
   CBaseObj::SetChartID(chart_id);
//--- Установка целочисленных свойств
   this.SetProperty(CHART_PROP_ID,chart_id);                                                             // Идентификатор графика
   this.SetProperty(CHART_PROP_TIMEFRAME,::ChartPeriod(this.ID()));                                      // Таймфрейм графика
   this.SetProperty(CHART_PROP_SHOW,::ChartGetInteger(this.ID(),CHART_SHOW));                            // Признак отрисовки ценового графика
   this.SetProperty(CHART_PROP_IS_OBJECT,::ChartGetInteger(this.ID(),CHART_IS_OBJECT));                  // Признак идентификации объекта "График"
   this.SetProperty(CHART_PROP_BRING_TO_TOP,false);                                                      // Показ графика поверх всех других
   this.SetProperty(CHART_PROP_CONTEXT_MENU,::ChartGetInteger(this.ID(),CHART_CONTEXT_MENU));            // Доступ к контекстному меню по нажатию правой клавиши мышки
   this.SetProperty(CHART_PROP_CROSSHAIR_TOOL,::ChartGetInteger(this.ID(),CHART_CROSSHAIR_TOOL));        // Доступ к инструменту "Перекрестие" по нажатию средней клавиши мышки
   this.SetProperty(CHART_PROP_MOUSE_SCROLL,::ChartGetInteger(this.ID(),CHART_MOUSE_SCROLL));            // Прокрутка графика левой кнопкой мышки по горизонтали
   this.SetProperty(CHART_PROP_EVENT_MOUSE_WHEEL,::ChartGetInteger(this.ID(),CHART_EVENT_MOUSE_WHEEL));  // Отправка всем mql5-программам на графике сообщений о событиях колёсика мышки
   this.SetProperty(CHART_PROP_EVENT_MOUSE_MOVE,::ChartGetInteger(this.ID(),CHART_EVENT_MOUSE_MOVE));    // Отправка всем mql5-программам на графике сообщений о событиях перемещения и нажатия кнопок мышки
   this.SetProperty(CHART_PROP_EVENT_OBJECT_CREATE,::ChartGetInteger(this.ID(),CHART_EVENT_OBJECT_CREATE)); // Отправка всем mql5-программам на графике сообщений о событии создания графического объекта
   this.SetProperty(CHART_PROP_EVENT_OBJECT_DELETE,::ChartGetInteger(this.ID(),CHART_EVENT_OBJECT_DELETE)); // Отправка всем mql5-программам на графике сообщений о событии уничтожения графического объекта
   this.SetProperty(CHART_PROP_MODE,::ChartGetInteger(this.ID(),CHART_MODE));                            // Тип графика (свечи, бары или линия
   this.SetProperty(CHART_PROP_FOREGROUND,::ChartGetInteger(this.ID(),CHART_FOREGROUND));                // Ценовой график на переднем плане
   this.SetProperty(CHART_PROP_SHIFT,::ChartGetInteger(this.ID(),CHART_SHIFT));                          // Режим отступа ценового графика от правого края
   this.SetProperty(CHART_PROP_AUTOSCROLL,::ChartGetInteger(this.ID(),CHART_AUTOSCROLL));                // Режим автоматического перехода к правому краю графика
   this.SetProperty(CHART_PROP_KEYBOARD_CONTROL,::ChartGetInteger(this.ID(),CHART_KEYBOARD_CONTROL));    // Разрешение на управление графиком с помощью клавиатуры
   this.SetProperty(CHART_PROP_QUICK_NAVIGATION,::ChartGetInteger(this.ID(),CHART_QUICK_NAVIGATION));    // Разрешение на перехват графиком нажатий клавиш Space и Enter для активации строки быстрой навигации
   this.SetProperty(CHART_PROP_SCALE,::ChartGetInteger(this.ID(),CHART_SCALE));                          // Масштаб
   this.SetProperty(CHART_PROP_SCALEFIX,::ChartGetInteger(this.ID(),CHART_SCALEFIX));                    // Режим фиксированного масштаба
   this.SetProperty(CHART_PROP_SCALEFIX_11,::ChartGetInteger(this.ID(),CHART_SCALEFIX_11));              // Режим масштаба 1:1
   this.SetProperty(CHART_PROP_SCALE_PT_PER_BAR,::ChartGetInteger(this.ID(),CHART_SCALE_PT_PER_BAR));    // Режим указания масштаба в пунктах на бар
   this.SetProperty(CHART_PROP_SHOW_TICKER,::ChartGetInteger(this.ID(),CHART_SHOW_TICKER));              // Отображение в левом верхнем углу тикера символа
   this.SetProperty(CHART_PROP_SHOW_OHLC,::ChartGetInteger(this.ID(),CHART_SHOW_OHLC));                  // Отображение в левом верхнем углу значений OHLC
   this.SetProperty(CHART_PROP_SHOW_BID_LINE,::ChartGetInteger(this.ID(),CHART_SHOW_BID_LINE));          // Отображение значения Bid горизонтальной линией на графике
   this.SetProperty(CHART_PROP_SHOW_ASK_LINE,::ChartGetInteger(this.ID(),CHART_SHOW_ASK_LINE));          // Отображение значения Ask горизонтальной линией на графике
   this.SetProperty(CHART_PROP_SHOW_LAST_LINE,::ChartGetInteger(this.ID(),CHART_SHOW_LAST_LINE));        // Отображение значения Last горизонтальной линией на графике
   this.SetProperty(CHART_PROP_SHOW_PERIOD_SEP,::ChartGetInteger(this.ID(),CHART_SHOW_PERIOD_SEP));      // Отображение вертикальных разделителей между соседними периодами
   this.SetProperty(CHART_PROP_SHOW_GRID,::ChartGetInteger(this.ID(),CHART_SHOW_GRID));                  // Отображение сетки на графике
   this.SetProperty(CHART_PROP_SHOW_VOLUMES,::ChartGetInteger(this.ID(),CHART_SHOW_VOLUMES));            // Отображение объемов на графике
   this.SetProperty(CHART_PROP_SHOW_OBJECT_DESCR,::ChartGetInteger(this.ID(),CHART_SHOW_OBJECT_DESCR));  // Отображение текстовых описаний объектов
   this.SetProperty(CHART_PROP_VISIBLE_BARS,::ChartGetInteger(this.ID(),CHART_VISIBLE_BARS));            // Количество баров на графике, доступных для отображения
   this.SetProperty(CHART_PROP_WINDOWS_TOTAL,::ChartGetInteger(this.ID(),CHART_WINDOWS_TOTAL));          // Общее количество окон графика, включая подокна индикаторов
   this.SetProperty(CHART_PROP_WINDOW_IS_VISIBLE,::ChartGetInteger(this.ID(),CHART_WINDOW_IS_VISIBLE,0));// Видимость окна
   this.SetProperty(CHART_PROP_WINDOW_HANDLE,::ChartGetInteger(this.ID(),CHART_WINDOW_HANDLE));          // Хэндл окна графика
   this.SetProperty(CHART_PROP_WINDOW_YDISTANCE,::ChartGetInteger(this.ID(),CHART_WINDOW_YDISTANCE,0));  // Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   this.SetProperty(CHART_PROP_FIRST_VISIBLE_BAR,::ChartGetInteger(this.ID(),CHART_FIRST_VISIBLE_BAR));  // Номер первого видимого бара на графике
   this.SetProperty(CHART_PROP_WIDTH_IN_BARS,::ChartGetInteger(this.ID(),CHART_WIDTH_IN_BARS));          // Ширина графика в барах
   this.SetProperty(CHART_PROP_WIDTH_IN_PIXELS,::ChartGetInteger(this.ID(),CHART_WIDTH_IN_PIXELS));      // Ширина графика в пикселях
   this.SetProperty(CHART_PROP_HEIGHT_IN_PIXELS,::ChartGetInteger(this.ID(),CHART_HEIGHT_IN_PIXELS,0));  // Высота графика в пикселях
   this.SetProperty(CHART_PROP_COLOR_BACKGROUND,::ChartGetInteger(this.ID(),CHART_COLOR_BACKGROUND));    // Цвет фона графика
   this.SetProperty(CHART_PROP_COLOR_FOREGROUND,::ChartGetInteger(this.ID(),CHART_COLOR_FOREGROUND));    // Цвет осей, шкалы и строки OHLC
   this.SetProperty(CHART_PROP_COLOR_GRID,::ChartGetInteger(this.ID(),CHART_COLOR_GRID));                // Цвет сетки
   this.SetProperty(CHART_PROP_COLOR_VOLUME,::ChartGetInteger(this.ID(),CHART_COLOR_VOLUME));            // Цвет объемов и уровней открытия позиций
   this.SetProperty(CHART_PROP_COLOR_CHART_UP,::ChartGetInteger(this.ID(),CHART_COLOR_CHART_UP));        // Цвет бара вверх, тени и окантовки тела бычьей свечи
   this.SetProperty(CHART_PROP_COLOR_CHART_DOWN,::ChartGetInteger(this.ID(),CHART_COLOR_CHART_DOWN));    // Цвет бара вниз, тени и окантовки тела медвежьей свечи
   this.SetProperty(CHART_PROP_COLOR_CHART_LINE,::ChartGetInteger(this.ID(),CHART_COLOR_CHART_LINE));    // Цвет линии графика и японских свечей "Доджи"
   this.SetProperty(CHART_PROP_COLOR_CANDLE_BULL,::ChartGetInteger(this.ID(),CHART_COLOR_CANDLE_BULL));  // Цвет тела бычьей свечи
   this.SetProperty(CHART_PROP_COLOR_CANDLE_BEAR,::ChartGetInteger(this.ID(),CHART_COLOR_CANDLE_BEAR));  // Цвет тела медвежьей свечи
   this.SetProperty(CHART_PROP_COLOR_BID,::ChartGetInteger(this.ID(),CHART_COLOR_BID));                  // Цвет линии Bid-цены
   this.SetProperty(CHART_PROP_COLOR_ASK,::ChartGetInteger(this.ID(),CHART_COLOR_ASK));                  // Цвет линии Ask-цены
   this.SetProperty(CHART_PROP_COLOR_LAST,::ChartGetInteger(this.ID(),CHART_COLOR_LAST));                // Цвет линии цены последней совершенной сделки (Last)
   this.SetProperty(CHART_PROP_COLOR_STOP_LEVEL,::ChartGetInteger(this.ID(),CHART_COLOR_STOP_LEVEL));    // Цвет уровней стоп-ордеров (Stop Loss и Take Profit)
   this.SetProperty(CHART_PROP_SHOW_TRADE_LEVELS,::ChartGetInteger(this.ID(),CHART_SHOW_TRADE_LEVELS));  // Отображение на графике торговых уровней (уровни открытых позиций, Stop Loss, Take Profit и отложенных ордеров)
   this.SetProperty(CHART_PROP_DRAG_TRADE_LEVELS,::ChartGetInteger(this.ID(),CHART_DRAG_TRADE_LEVELS));  // Разрешение на перетаскивание торговых уровней на графике с помощью мышки
   this.SetProperty(CHART_PROP_SHOW_DATE_SCALE,::ChartGetInteger(this.ID(),CHART_SHOW_DATE_SCALE));      // Отображение на графике шкалы времени
   this.SetProperty(CHART_PROP_SHOW_PRICE_SCALE,::ChartGetInteger(this.ID(),CHART_SHOW_PRICE_SCALE));    // Отображение на графике ценовой шкалы
   this.SetProperty(CHART_PROP_SHOW_ONE_CLICK,::ChartGetInteger(this.ID(),CHART_SHOW_ONE_CLICK));        // Отображение на графике панели быстрой торговли
   this.SetProperty(CHART_PROP_IS_MAXIMIZED,::ChartGetInteger(this.ID(),CHART_IS_MAXIMIZED));            // Окно графика развернуто
   this.SetProperty(CHART_PROP_IS_MINIMIZED,::ChartGetInteger(this.ID(),CHART_IS_MINIMIZED));            // Окно графика свернуто
   this.SetProperty(CHART_PROP_IS_DOCKED,::ChartGetInteger(this.ID(),CHART_IS_DOCKED));                  // Окно графика закреплено
   this.SetProperty(CHART_PROP_FLOAT_LEFT,::ChartGetInteger(this.ID(),CHART_FLOAT_LEFT));                // Левая координата открепленного графика относительно виртуального экрана
   this.SetProperty(CHART_PROP_FLOAT_TOP,::ChartGetInteger(this.ID(),CHART_FLOAT_TOP));                  // Верхняя координата открепленного графика относительно виртуального экрана
   this.SetProperty(CHART_PROP_FLOAT_RIGHT,::ChartGetInteger(this.ID(),CHART_FLOAT_RIGHT));              // Правая координата открепленного графика  относительно виртуального экрана
   this.SetProperty(CHART_PROP_FLOAT_BOTTOM,::ChartGetInteger(this.ID(),CHART_FLOAT_BOTTOM));            // Нижняя координата открепленного графика  относительно виртуального экрана
//--- Установка вещественных свойств
   this.SetProperty(CHART_PROP_SHIFT_SIZE,::ChartGetDouble(this.ID(),CHART_SHIFT_SIZE));                 // Размер отступа нулевого бара от правого края в процентах
   this.SetProperty(CHART_PROP_FIXED_POSITION,::ChartGetDouble(this.ID(),CHART_FIXED_POSITION));         // Положение фиксированной позиции графика от левого края в процентах
   this.SetProperty(CHART_PROP_FIXED_MAX,::ChartGetDouble(this.ID(),CHART_FIXED_MAX));                   // Фиксированный максимум графика
   this.SetProperty(CHART_PROP_FIXED_MIN,::ChartGetDouble(this.ID(),CHART_FIXED_MIN));                   // Фиксированный минимум графика
   this.SetProperty(CHART_PROP_POINTS_PER_BAR,::ChartGetDouble(this.ID(),CHART_POINTS_PER_BAR));         // Значение масштаба в пунктах на бар
   this.SetProperty(CHART_PROP_PRICE_MIN,::ChartGetDouble(this.ID(),CHART_PRICE_MIN));                   // Минимум графика
   this.SetProperty(CHART_PROP_PRICE_MAX,::ChartGetDouble(this.ID(),CHART_PRICE_MAX));                   // Максимум графика
//--- Установка строковых свойств
   this.SetProperty(CHART_PROP_COMMENT,::ChartGetString(this.ID(),CHART_COMMENT));                       // Текст комментария на графике
   this.SetProperty(CHART_PROP_EXPERT_NAME,::ChartGetString(this.ID(),CHART_EXPERT_NAME));               // Имя эксперта, запущенного на графике
   this.SetProperty(CHART_PROP_SCRIPT_NAME,::ChartGetString(this.ID(),CHART_SCRIPT_NAME));               // Имя скрипта, запущенного на графике
   this.SetProperty(CHART_PROP_SYMBOL,::ChartSymbol(this.ID()));                                         // Символ графика
   
   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;
     }
  }
//+------------------------------------------------------------------+

Для создания списков окон чарта, получаем общее количество всех окон графика, и в цикле по всем окнам создаём новый объект-окно чарта и добавляем его в список.

В методе сравнения двух объектов-чартов, созданного в прошлой статье, была допущена логическая ошибка: каждый чарт имеет свой уникальный идентификатор графика и хэндл окна. Поэтому сравнение по этим свойствам двух разных графиков всегда вернёт false. Нам же нужно в этом методе сравнить разные графики на их идентичность, а сравнение их идентификаторов и хэндлов всегда укажет на то, что два графика неидентичны.
Исправим ошибку, пропустив два этих свойства при сравнении:

//+------------------------------------------------------------------+
//| Сравнивает объекты CChartObj между собой по всем свойствам       |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

В методе, возвращающем описание целочисленного свойства объекта, впишем возврат описания трёх добавленных свойств:

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства объекта              |
//+------------------------------------------------------------------+
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)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Блоки добавленного кода идентичны всем остальным — в зависимости от переданного в метод свойства создаётся и возвращается строка с описанием этого свойства.

Доработаем метод, выводящий в журнал все свойства объекта:

//+------------------------------------------------------------------+
//| Выводит в журнал свойства объекта                                |
//+------------------------------------------------------------------+
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");
  }
//+------------------------------------------------------------------+

Если в цикле встречаются свойства "Хэндл индикатора" и "Идекс индикатора в окне", то эти свойства пропускаются — они не относятся к объекту-чарту.
Если же встречено свойство "Высота графика в пикселях", то вызывается метод, выводящий описание данного свойства для всех окон данного чарта.
Точно так же, если встречено свойство "Имя индикатора в окне", то вызывается метод, выводящий описание всех индикаторов, прикреплённых ко всем окнам чарта. Эти методы мы рассмотрим позже.

Метод, выводящий в журнал краткое описание объекта тоже был дополнен.
Теперь он выводит дополнительно ещё и количество подокон окна графика при их наличии, либо сообщает, что их нет:

//+------------------------------------------------------------------+
//| Выводит в журнал краткое описание объекта                        |
//+------------------------------------------------------------------+
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))
     );
  }
//+------------------------------------------------------------------+

Метод, выводящий в журнал данные всех индикаторов всех окон графика:

//+------------------------------------------------------------------+
//| Выводит в журнал данные всех индикаторов всех окон графика       |
//+------------------------------------------------------------------+
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);
     }
  }
//+------------------------------------------------------------------+

Здесь: в цикле по всем объектам-окнам чарта получаем очередной объект-окно графика и распечатываем в журнал описания всех индикаторов, прикреплённых к этому окну. В метод передаём true для того, чтобы перед описанием индикатора выводился дефис.

Метод, выводящий в журнал свойства всех окон графика:

//+------------------------------------------------------------------+
//| Выводит в журнал свойства всех окон графика                      |
//+------------------------------------------------------------------+
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);
     }
  }
//+------------------------------------------------------------------+

Здесь: в цикле по всем объектам-окнам чарта получаем очередной объект-окно графика и распечатываем в журнал описание его параметров. В метод передаём true для того, чтобы перед описанием окна выводился дефис.

Метод, возвращающий объект-окно по его номеру подокна:

//+------------------------------------------------------------------+
//| Возвращает объект-окно по его номеру подокна                     |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

Здесь: в цикле по общему количеству объектов-окон чарта получаем очередной объект-окно и если его номер совпадает с переданным в метод, возвращаем указатель на найденный в списке объект. По завершении цикла возвращаем NULL — объект не найден.

Метод, устанавливающий свойство объекту-чарту "Видимость подокна":

//+------------------------------------------------------------------+
//| Устанавливает свойство "Видимость подокна"                       |
//+------------------------------------------------------------------+
void CChartObj::SetVisible(void)
  {
   this.SetProperty(CHART_PROP_WINDOW_IS_VISIBLE,::ChartGetInteger(this.ID(),CHART_WINDOW_IS_VISIBLE,0));
  }
//+------------------------------------------------------------------+

Здесь просто в указанное свойство записываем соответствующее read/only-свойство главного окна чарта.

Метод, возвращающий дистанцию в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна:

//+------------------------------------------------------------------+
//| Возвращает дистанцию в пикселях по вертикальной оси Y между      |
//| верхней рамкой подокна индикатора и верхней рамкой главного окна |
//+------------------------------------------------------------------+
int CChartObj::WindowYDistance(const int sub_window) const
  {
   CChartWnd *wnd=GetWindowByNum(sub_window);
   return(wnd!=NULL ? wnd.YDistance() : WRONG_VALUE);
  }
//+------------------------------------------------------------------+

Здесь: получаем объект-окно графика по его номеру подокна и возвращаем значение свойства из полученного объекта.
Если объект не получен — возвращаем -1
.

Метод, возвращающий высоту указанного графика в пикселях:

//+------------------------------------------------------------------+
//| Возвращает высоту указанного графика в пикселях                  |
//+------------------------------------------------------------------+
int CChartObj::WindowHeightInPixels(const int sub_window) const
  {
   CChartWnd *wnd=GetWindowByNum(sub_window);
   return(wnd!=NULL ? wnd.HeightInPixels() : WRONG_VALUE);
  }
//+------------------------------------------------------------------+

Здесь: получаем объект-окно графика по его номеру подокна и возвращаем значение свойства из полученного объекта.
Если объект не получен — возвращаем -1
.

Метод, устанавливающий высоту указанного графика в пикселях:

//+------------------------------------------------------------------+
//| Устанавливает высоту указанного графика в пикселях               |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

Здесь: получаем объект-окно графика по его номеру подокна и возвращаем результат установки соответствующего свойства для полученного объекта.
Если объект не получен — возвращаем false
.

Старый метод, написанный нами в прошлой статье, удалим:

//+------------------------------------------------------------------+
//| Устанавливает высоту указанного графика в пикселях               |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+

На этом доработка класса объекта-чарта завершена.


Тестирование

Для проверки работоспособности созданных объектов просто откроем три любых графика. На чарт с советником в его главное окно добавим индикатор фракталов + добавим окно индикатора, например, DeMarker, в который разместим ещё один, например, AMA, рассчитываемый на данных DeMarker.
На втором графике расположим окно стохастика, а третье окно сделаем откреплённым (Alt+D):


В журнал выведем краткие описания всех трёх объектов-чартов и полное описание текущего чарта, на котором расположен советник.

Для тестирования возмём советник из прошлой статьи и
сохраним его в новой папке \MQL5\Experts\TestDoEasy\Part68\ под новым именем TestDoEasyPart68.mq5.

Советник останется практически без изменений. Всё, что нам потребуется — это дополнить код обработчика OnTick() такой логикой:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Обработка события NewTick в библиотеке
   engine.OnTick(rates_data);

//--- Если работа в тестере
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer(rates_data);   // Работа в таймере
      PressButtonsControl();        // Контроль нажатия кнопок
      engine.EventsHandling();      // Работа с событиями
     }

//--- Если установлен флаг трейлинга
   if(trailing_on)
     {
      TrailingPositions();          // Трейлинг позиций
      TrailingOrders();             // Трейлинг отложенных ордеров
     }
   
//--- Если первый запуск
   static bool done=false;
   if(!done)
     {
      //--- Создадим объект-список для хранения объектов-чартов
      CArrayObj *list=new CArrayObj();
      if(list==NULL)
         return;
      //--- Объявим переменные и получим идентификатор первого графика
      long currChart,prevChart=ChartFirst(); 
      int i=0; 
      //--- Создадим объект-чарт и добавим его в список
      CChartObj *chart_first=new CChartObj(prevChart);
      list.Add(chart_first);
      //--- В цикле по общему количеству графиков терминала (не более 100)
      while(i<CHARTS_MAX)
        { 
         //--- на основании предыдущего получим новый график
         currChart=ChartNext(prevChart);
         //--- Если достигли конца списка графиков - завершаем цикл
         if(currChart<0) break;
         //--- Создаём объект-чарт на основании идентификатора текущего графика в цикле и добавим его в список
         CChartObj *chart=new CChartObj(currChart);
         list.Add(chart);
         //--- запомним идентификатор текущего графика для ChartNext() и увеличим счётчик цикла
         prevChart=currChart;
         i++;
        }
      Print("");
      //--- Из заполненного списка в цикле получим очередной объект-чарт и выведем его краткое описание
      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("");
      //--- Выведем полное описание текущего графика: в цикле по всем объектам созданного списка
      for(int j=0;j<total;j++)
        {
         //--- получим очередной объект-чарт и
         CChartObj *chart_obj=list.At(j);
         //--- если его символ совпадает с символом текущего графика - выведем в журнал его полное описание
         if(chart_obj!=NULL && chart_obj.Symbol()==Symbol())
            chart_obj.Print();
        }
      //--- Уничтожим список объектов-чартов
      delete list;
      done=true;
     }
//---
  }
//+------------------------------------------------------------------+

Скомпилируем советник и запустим его на графике, предварительно создав требуемое окружение в терминале, описанное в самом начале этого раздела.

В журнал будут выведены краткие описания всех трёх открытых графиков:

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

и полное описание текущего. Результат работы созданных сегодня классов отображается в журнале упорядоченными строками свойств объектов-окон и индикаторов, прикреплённых к ним:

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


Что дальше

В следующей статье начнём разработку класса-коллекции объектов-чартов.

Ниже прикреплены все файлы текущей версии библиотеки и файл тестового советника для MQL5. Их можно скачать и протестировать всё самостоятельно.
Хочу отметить, что использовать объекты-чарты в своих разработках в текущем их состоянии не рекомендуется ввиду дальнейших их изменений.
При возникновении вопросов, замечаний и пожеланий, вы можете озвучить их в комментариях к статье.

К содержанию

*Статьи этой серии:

Работа с ценами в библиотеке DoEasy (Часть 62): Реалтайм-обновление тиковых серий, подготовка к работе со стаканом цен
Работа с ценами в библиотеке DoEasy (Часть 63): Стакан цен, класс абстрактной заявки стакана цен
Работа с ценами в библиотеке DoEasy (Часть 64): Стакан цен, классы объекта-снимка и объекта-серии снимков стакана цен
Работа с ценами и Сигналами в библиотеке DoEasy (Часть 65): Коллекция стаканов и класс для работы с Сигналами MQL5.com
Прочие классы в библиотеке DoEasy (Часть 66): Класс-коллекция Сигналов MQL5.com
Прочие классы в библиотеке DoEasy (Часть 67): Класс объекта-чарта

Прикрепленные файлы |
MQL5.zip (3988.52 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (3)
BillionerClub
BillionerClub | 26 мар. 2021 в 13:21

Довольно похвально, что библиотека, развивается, вашими, невероятными усилиями, в одиночку.

Есть довольно большая область в области интеграции Python. Могу посоветовать исходные коды закрытой фирмы Quantopian, для творчества. В них можно многое найти не изобретая велосипеда. Конечно если вы хотите и дальше развивать этот высокоуровневый проект на Mql5.

Artyom Trishkin
Artyom Trishkin | 26 мар. 2021 в 13:36
BillionerClub:

Довольно похвально, что библиотека, развивается, вашими, невероятными усилиями, в одиночку.

Есть довольно большая область в области интеграции Python. Могу посоветовать исходные коды закрытой фирмы Quantopian, для творчества. В них можно многое найти не изобретая велосипеда. Конечно если вы хотите и дальше развивать этот высокоуровневый проект на Mql5.

Спасибо. С питоном не буду связывать библиотеку.

BillionerClub
BillionerClub | 26 мар. 2021 в 15:53
Artyom Trishkin:

Спасибо. С питоном не буду связывать библиотеку.

Можно написать такое же на языке mql ))  только конечно зачем?  только если для хайпа и рекламы МТ5

Иметь джентельменский набор квантов в МТ5 серьезная заявка на весь Мир
Комбинационный скальпинг: сделки из прошлого или повышение результативности будущих сделок Комбинационный скальпинг: сделки из прошлого или повышение результативности будущих сделок
На рассмотрение предлагается описание технологии повышения результативности любой автоматизированной торговой системы. В статье кратко раскрывается идея, базовые основы, возможности и недостатки метода.
Шаблон проектирования MVC и возможность его использования Шаблон проектирования MVC и возможность его использования
В статье рассматривается распространенный шаблон MVC, возможность, плюсы и минусы его применения в программах на MQL. Его суть в том, чтобы "разделить" имеющийся код на три отдельных компонента: Модель (Model), Представление (View) и Контроллер (Controller).
Прочие классы в библиотеке DoEasy (Часть 69): Класс-коллекция объектов-чартов Прочие классы в библиотеке DoEasy (Часть 69): Класс-коллекция объектов-чартов
С этой статьи начнём разработку класса-коллекции объектов-чартов, который будет хранить в себе список-коллекцию объектов-чартов с их подокнами и индикаторами в них, и даст возможность работы с любыми выбранными чартами и их подокнами, или сразу со списком из нескольких чартов одновременно.
Нейросети — это просто (Часть 13): Пакетная нормализация (Batch Normalization) Нейросети — это просто (Часть 13): Пакетная нормализация (Batch Normalization)
В предыдущей статье мы начали рассматривать методы повышения качества обучения нейронной сети. В данной статье предлагаю продолжить эту тему и рассмотреть такой поход, как пакетная нормализация данных.