English 中文 Español Deutsch 日本語 Português
Прочие классы в библиотеке DoEasy (Часть 72): Отслеживание и фиксация параметров объектов-чартов в коллекции

Прочие классы в библиотеке DoEasy (Часть 72): Отслеживание и фиксация параметров объектов-чартов в коллекции

MetaTrader 5Примеры | 7 мая 2021, 09:41
2 842 6
Artyom Trishkin
Artyom Trishkin

Содержание


Концепция

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

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

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

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

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

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

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


Доработка классов библиотеки

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

   MSG_LIB_TEXT_SYMBOL,                               // символа: 
   MSG_LIB_TEXT_ACCOUNT,                              // аккаунта: 
   MSG_LIB_TEXT_CHART,                                // чарта: 
   MSG_LIB_TEXT_CHART_WND,                            // окна чарта: 
   MSG_LIB_TEXT_PROP_VALUE,                           // Значение свойства

...

   MSG_CHART_COLLECTION_CHART_OPENED,                 // Открыт график
   MSG_CHART_COLLECTION_CHART_CLOSED,                 // Закрыт график
   
   MSG_CHART_COLLECTION_CHART_SYMB_CHANGED,           // Изменён символ графика
   MSG_CHART_COLLECTION_CHART_TF_CHANGED,             // Изменён таймфрейм графика
   MSG_CHART_COLLECTION_CHART_SYMB_TF_CHANGED,        // Изменён символ и таймфрейм графика
  
  };
//+------------------------------------------------------------------+

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

   {"символа: ","symbol property: "},
   {"аккаунта: ","account property: "},
   {"чарта: ","chart property: "},
   {"окна чарта: ","chart window property: "},
   {"Значение свойства ","Value of the "},

...

   {"Открыт график","Open chart"},
   {"Закрыт график","Closed chart"},
   
   {"Изменён символ графика","Changed chart symbol"},
   {"Изменён таймфрейм графика","Changed chart timeframe"},
   {"Изменён символ и таймфрейм графика","Changed the symbol and timeframe of the chart"},
   
  };
//+---------------------------------------------------------------------+


В файле \MQL5\Include\DoEasy\Defines.mqh в раздел идентификаторов списков коллекций впишем новый идентификатор списка окон графика:

//--- Идентификаторы списков коллекций
#define COLLECTION_HISTORY_ID          (0x777A)                   // Идентификатор списка исторической коллекции
#define COLLECTION_MARKET_ID           (0x777B)                   // Идентификатор списка рыночной коллекции
#define COLLECTION_EVENTS_ID           (0x777C)                   // Идентификатор списка коллекции событий
#define COLLECTION_ACCOUNT_ID          (0x777D)                   // Идентификатор списка коллекции аккаунтов
#define COLLECTION_SYMBOLS_ID          (0x777E)                   // Идентификатор списка коллекции символов
#define COLLECTION_SERIES_ID           (0x777F)                   // Идентификатор списка коллекции таймсерий
#define COLLECTION_BUFFERS_ID          (0x7780)                   // Идентификатор списка коллекции индикаторных буферов
#define COLLECTION_INDICATORS_ID       (0x7781)                   // Идентификатор списка коллекции индикаторов
#define COLLECTION_INDICATORS_DATA_ID  (0x7782)                   // Идентификатор списка коллекции индикаторных данных
#define COLLECTION_TICKSERIES_ID       (0x7783)                   // Идентификатор списка коллекции тиковых серий
#define COLLECTION_MBOOKSERIES_ID      (0x7784)                   // Идентификатор списка коллекции серий стаканов цен
#define COLLECTION_MQL5_SIGNALS_ID     (0x7785)                   // Идентификатор списка коллекции mql5-сигналов
#define COLLECTION_CHARTS_ID           (0x7786)                   // Идентификатор списка коллекции чартов
#define COLLECTION_CHART_WND_ID        (0x7787)                   // Идентификатор списка окон чартов
//--- Идентификаторы типов отложенных запросов

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

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

//+------------------------------------------------------------------+
//| Данные для работы с чартами                                      |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Список возможных событий чарта                                   |
//+------------------------------------------------------------------+
enum ENUM_CHART_OBJ_EVENT
  {
   CHART_OBJ_EVENT_NO_EVENT = SIGNAL_MQL5_EVENTS_NEXT_CODE, // Нет события
   CHART_OBJ_EVENT_CHART_OPEN,                        // Событие "Открытие нового чарта"
   CHART_OBJ_EVENT_CHART_CLOSE,                       // Событие "Закрытие чарта"
   CHART_OBJ_EVENT_CHART_SYMB_CHANGE,                 // Событие "Смена символа чарта"
   CHART_OBJ_EVENT_CHART_SYMB_TF_CHANGE,              // Событие "Смена символа и таймфрейма чарта"
   CHART_OBJ_EVENT_CHART_TF_CHANGE,                   // Событие "Смена таймфрейма чарта"
   CHART_OBJ_EVENT_CHART_WND_ADD,                     // Событие "Добавление нового окна на чарт"
   CHART_OBJ_EVENT_CHART_WND_DEL,                     // Событие "Удаление окна с чарта"
   CHART_OBJ_EVENT_CHART_WND_IND_ADD,                 // Событие "Добавление нового индикатора в окно чарта"
   CHART_OBJ_EVENT_CHART_WND_IND_DEL,                 // Событие "Удаление индикатора из окна чарта"
   CHART_OBJ_EVENT_CHART_WND_IND_CHANGE,              // Событие "Изменение параметров индикатора в окне чарта"
  };
#define CHART_OBJ_EVENTS_NEXT_CODE  (CHART_OBJ_EVENT_CHART_WND_IND_CHANGE+1)  // Код следующего события после последнего кода события чарта
//+------------------------------------------------------------------+

Из перечисления целочисленных свойств уберём номер окна графика:

   CHART_PROP_WINDOW_NUM,                             // Номер окна графика
  };

это свойство принадлежит другому объекту — объекту окна графика,
а некоторые общие свойства как чарта, так и его окна, перенесём в конец списка констант перечисления:

//+------------------------------------------------------------------+
//| Целочисленные свойства чарта                                     |
//+------------------------------------------------------------------+
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_HANDLE,                          // Хэндл окна графика
   CHART_PROP_FIRST_VISIBLE_BAR,                      // Номер первого видимого бара на графике
   CHART_PROP_WIDTH_IN_BARS,                          // Ширина графика в барах
   CHART_PROP_WIDTH_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,                           // Нижняя координата открепленного графика  относительно виртуального экрана
   CHART_PROP_YDISTANCE,                              // Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   CHART_PROP_HEIGHT_IN_PIXELS,                       // Высота графика в пикселях
   CHART_PROP_WINDOW_IND_HANDLE,                      // Хэндл индикатора на графике
   CHART_PROP_WINDOW_IND_INDEX,                       // Индекс индикатора на графике
  };
#define CHART_PROP_INTEGER_TOTAL (66)                 // Общее количество целочисленных свойств
#define CHART_PROP_INTEGER_SKIP  (2)                  // Количество неиспользуемых в сортировке целочисленных свойств
//+------------------------------------------------------------------+

При этом у нас сократилось на 1 количество целочисленных свойств чарта — впишем 66 вместо 67, и укажем, что два последних свойства не должны участвовать в поиске и сортировке, и соответственно они не будут отображаться в свойствах чарта. Эти константы нужны для класса объекта-индикатора в окне чарта (он тоже выполнен в упрощённом варианте).

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

//+------------------------------------------------------------------+
//| Возможные критерии сортировки чартов                             |
//+------------------------------------------------------------------+
#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_ID = 0,                              // Сортировать по идентификатору графика
   SORT_BY_CHART_TIMEFRAME,                           // Сортировать по таймфрейму графика
   SORT_BY_CHART_SHOW,                                // Сортировать по признаку отрисовки ценового графика
   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_HANDLE,                       // Сортировать по хэндлу графика
   SORT_BY_CHART_FIRST_VISIBLE_BAR,                   // Сортировать по номеру первого видимого бара на графике
   SORT_BY_CHART_WIDTH_IN_BARS,                       // Сортировать по ширине графика в барах
   SORT_BY_CHART_WIDTH_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_YDISTANCE,                           // Сортировать по дистанции в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   SORT_BY_CHART_HEIGHT_IN_PIXELS,                    // Сортировать по высоте графика в пикселях
//--- Сортировка по вещественным свойствам
   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,                              // Сортировать по символу графика
  };
//+------------------------------------------------------------------+

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

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

//+------------------------------------------------------------------+
//| Данные для работы с окнами графиков                              |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Целочисленные свойства окна графика                              |
//+------------------------------------------------------------------+
enum ENUM_CHART_WINDOW_PROP_INTEGER
  {
   CHART_WINDOW_PROP_ID = 0,                          // Идентификатор графика
   CHART_WINDOW_PROP_WINDOW_NUM,                      // Номер окна графика
   CHART_WINDOW_PROP_YDISTANCE,                       // Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   CHART_WINDOW_PROP_HEIGHT_IN_PIXELS,                // Высота окна графика в пикселях
   //--- для CWndInd
   CHART_WINDOW_PROP_WINDOW_IND_HANDLE,               // Хэндл индикатора в окне графика
   CHART_WINDOW_PROP_WINDOW_IND_INDEX,                // Индекс индикатора в окне графика
  };
#define CHART_WINDOW_PROP_INTEGER_TOTAL (6)           // Общее количество целочисленных свойств
#define CHART_WINDOW_PROP_INTEGER_SKIP  (0)           // Количество неиспользуемых в сортировке целочисленных свойств стакана
//+------------------------------------------------------------------+
//| Вещественные свойства окна графика                               |
//+------------------------------------------------------------------+
enum ENUM_CHART_WINDOW_PROP_DOUBLE
  {
   CHART_WINDOW_PROP_PRICE_MIN = CHART_WINDOW_PROP_INTEGER_TOTAL, // Минимум графика
   CHART_WINDOW_PROP_PRICE_MAX,                       // Максимум графика
  };
#define CHART_WINDOW_PROP_DOUBLE_TOTAL  (2)           // Общее количество вещественных свойств
#define CHART_WINDOW_PROP_DOUBLE_SKIP   (0)           // Количество неиспользуемых в сортировке вещественных свойств
//+------------------------------------------------------------------+
//| Строковые свойства окна графика                                  |
//+------------------------------------------------------------------+
enum ENUM_CHART_WINDOW_PROP_STRING
  {
   CHART_WINDOW_PROP_IND_NAME = (CHART_WINDOW_PROP_INTEGER_TOTAL+CHART_WINDOW_PROP_DOUBLE_TOTAL), // Имя индикатора, запущенного в окне
   CHART_WINDOW_PROP_SYMBOL,                          // Символ графика
  };
#define CHART_WINDOW_PROP_STRING_TOTAL  (2)           // Общее количество строковых свойств
//+------------------------------------------------------------------+

И наконец, вписать перечесление возможных критериев сортировки объектов-окон графика:

//+------------------------------------------------------------------+
//| Возможные критерии сортировки окон графика                       |
//+------------------------------------------------------------------+
#define FIRST_CHART_WINDOW_DBL_PROP  (CHART_WINDOW_PROP_INTEGER_TOTAL-CHART_WINDOW_PROP_INTEGER_SKIP)
#define FIRST_CHART_WINDOW_STR_PROP  (CHART_WINDOW_PROP_INTEGER_TOTAL-CHART_WINDOW_PROP_INTEGER_SKIP+CHART_WINDOW_PROP_DOUBLE_TOTAL-CHART_WINDOW_PROP_DOUBLE_SKIP)
enum ENUM_SORT_CHART_WINDOW_MODE
  {
//--- Сортировка по целочисленным свойствам
   SORT_BY_CHART_WINDOW_ID = 0,                       // Сортировать по идентификатору графика
   SORT_BY_CHART_WINDOW_NUM,                          // Сортировать по номеру окна графика
   SORT_BY_CHART_WINDOW_YDISTANCE,                    // Сортировать по дистанции в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   SORT_BY_CHART_WINDOW_HEIGHT_IN_PIXELS,             // Сортировать по высоте окна графика в пикселях
   SORT_BY_CHART_WINDOW_IND_HANDLE,                   // Сортировать по хэндлу индикатора в окне графика
   SORT_BY_CHART_WINDOW_IND_INDEX,                    // Сортировать по индексу индикатора в окне графика
//--- Сортировка по вещественным свойствам
   SORT_BY_CHART_WINDOW_PRICE_MIN = FIRST_CHART_WINDOW_DBL_PROP,  // Сортировать по минимуму окна графика
   SORT_BY_CHART_WINDOW_PRICE_MAX,                    // Сортировать по максимуму окна графика
//--- Сортировка по строковым свойствам
   SORT_BY_CHART_WINDOW_IND_NAME = FIRST_CHART_WINDOW_STR_PROP,   // Сортировать по имени индикатора, запущенного в окне
   SORT_BY_CHART_WINDOW_SYMBOL,                       // Сортировать по символу графика
  };
//+------------------------------------------------------------------+

Возвращаясь к идентификатору списка объектов-окон графиков, вспомним, что нам необходимо доработать базовый расширенный объект CBaseObjExt, класс которого написан в файле класса базового объекта \MQL5\Include\DoEasy\Objects\BaseObj.mqh.

Всё, что нам в нём нужно сделать, — это дописать в его методе EventDescription() обработку двух новых списков, к которым принадлежат объекты, которые будут наследниками этого класса — объект-чарт и объект-окно чарта:

//+------------------------------------------------------------------+
//| Возвращает описание события объекта                              |
//+------------------------------------------------------------------+
string CBaseObjExt::EventDescription(const int property,
                                  const ENUM_BASE_EVENT_REASON reason,
                                  const int source,
                                  const string value,
                                  const string property_descr,
                                  const int digits)
  {
//--- В зависимости от ID коллекции создаём описание типа объекта
   string type=
     (
      this.Type()==COLLECTION_SYMBOLS_ID     ? CMessage::Text(MSG_LIB_TEXT_SYMBOL)     :
      this.Type()==COLLECTION_ACCOUNT_ID     ?  CMessage::Text(MSG_LIB_TEXT_ACCOUNT)   :
      this.Type()==COLLECTION_CHARTS_ID      ?  CMessage::Text(MSG_LIB_TEXT_CHART)     :
      this.Type()==COLLECTION_CHART_WND_ID   ?  CMessage::Text(MSG_LIB_TEXT_CHART_WND) :
      ""
     );
//--- В зависимости от типа свойства создаём описание величины изменения свойства
   string level=
     (
      property<this.m_long_prop_total ? 
      ::DoubleToString(this.GetControlledLongValueLEVEL(property),digits) :
      ::DoubleToString(this.GetControlledDoubleValueLEVEL(property),digits)
     );
//--- В зависимости от причины события создаём текст описания события
   string res=
     (
      reason==BASE_EVENT_REASON_INC       ?  CMessage::Text(MSG_LIB_TEXT_PROP_VALUE)+type+property_descr+CMessage::Text(MSG_LIB_TEXT_INC_BY)+value    :
      reason==BASE_EVENT_REASON_DEC       ?  CMessage::Text(MSG_LIB_TEXT_PROP_VALUE)+type+property_descr+CMessage::Text(MSG_LIB_TEXT_DEC_BY)+value    :
      reason==BASE_EVENT_REASON_MORE_THEN ?  CMessage::Text(MSG_LIB_TEXT_PROP_VALUE)+type+property_descr+CMessage::Text(MSG_LIB_TEXT_MORE_THEN)+level :
      reason==BASE_EVENT_REASON_LESS_THEN ?  CMessage::Text(MSG_LIB_TEXT_PROP_VALUE)+type+property_descr+CMessage::Text(MSG_LIB_TEXT_LESS_THEN)+level :
      reason==BASE_EVENT_REASON_EQUALS    ?  CMessage::Text(MSG_LIB_TEXT_PROP_VALUE)+type+property_descr+CMessage::Text(MSG_LIB_TEXT_EQUAL)+level     :
      CMessage::Text(MSG_LIB_TEXT_BASE_OBJ_UNKNOWN_EVENT)+type
     );
//--- Возвращаем наименование объекта+созданный текст описания события
   return this.m_name+": "+res;
  }
//+------------------------------------------------------------------+

О работе данного класса можно почитать в статье 37.

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

Откроем файл \MQL5\Include\DoEasy\Objects\Chart\ChartWnd.mqh и внесём в него необходимые исправления. В этом же файле находится вспомогательный класс объекта-индикатора в окне. Так как мы изменили некоторые свойства этих объектов, то в метод Compare() класса CWndInd впишем константы новых перечислений:

//+------------------------------------------------------------------+
//| Сравнивает объекты CWndInd между собой по указанному свойству    |
//+------------------------------------------------------------------+
int CWndInd::Compare(const CObject *node,const int mode=0) const
  {
   const CWndInd *obj_compared=node;
   if(mode==CHART_WINDOW_PROP_WINDOW_IND_HANDLE) return(this.Handle()>obj_compared.Handle() ? 1 : this.Handle()<obj_compared.Handle() ? -1 : 0);
   else if(mode==CHART_WINDOW_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);
  }
//+------------------------------------------------------------------+

Ранее это были уже удалённые константы из другого перечисления CHART_PROP_WINDOW_IND_HANDLE и CHART_PROP_WINDOW_IND_INDEX.

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

//+------------------------------------------------------------------+
//| Класс объекта-окна графика                                       |
//+------------------------------------------------------------------+
class CChartWnd : public CBaseObjExt
  {
private:
   CArrayObj         m_list_ind;                                        // Список индикаторов
   CArrayObj        *m_list_ind_del;                                    // Указатель на список удалённых из окна индикаторов
   CArrayObj        *m_list_ind_param;                                  // Указатель на список изменённых индикаторов
   long              m_long_prop[CHART_WINDOW_PROP_INTEGER_TOTAL];      // Целочисленные свойства
   double            m_double_prop[CHART_WINDOW_PROP_DOUBLE_TOTAL];     // Вещественные свойства
   string            m_string_prop[CHART_WINDOW_PROP_STRING_TOTAL];     // Строковые свойства
   int               m_digits;                                          // Digits() символа
   int               m_wnd_coord_x;                                     // Координата X для времени на графике в окне
   int               m_wnd_coord_y;                                     // Координата Y для цены на графике в окне
//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство
   int               IndexProp(ENUM_CHART_WINDOW_PROP_DOUBLE property)  const { return(int)property-CHART_WINDOW_PROP_INTEGER_TOTAL;                                 }
   int               IndexProp(ENUM_CHART_WINDOW_PROP_STRING property)  const { return(int)property-CHART_WINDOW_PROP_INTEGER_TOTAL-CHART_WINDOW_PROP_DOUBLE_TOTAL;  }

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

public:
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство объекта
   void              SetProperty(ENUM_CHART_WINDOW_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                      }
   void              SetProperty(ENUM_CHART_WINDOW_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;    }
   void              SetProperty(ENUM_CHART_WINDOW_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;    }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство объекта
   long              GetProperty(ENUM_CHART_WINDOW_PROP_INTEGER property)        const { return this.m_long_prop[property];                     }
   double            GetProperty(ENUM_CHART_WINDOW_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];   }
   string            GetProperty(ENUM_CHART_WINDOW_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];   }
//--- Возвращает себя
   CChartWnd        *GetObject(void)                                                   { return &this;   }

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

//--- Возвращает себя
   CChartWnd        *GetObject(void)                                                   { return &this;   }

//--- Возвращает флаг поддержания объектом данного свойства
   virtual bool      SupportProperty(ENUM_CHART_WINDOW_PROP_INTEGER property)          { return true;    }
   virtual bool      SupportProperty(ENUM_CHART_WINDOW_PROP_DOUBLE property)           { return true;    }
   virtual bool      SupportProperty(ENUM_CHART_WINDOW_PROP_STRING property)           { return true;    }

//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства
   string            GetPropertyDescription(ENUM_CHART_WINDOW_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_CHART_WINDOW_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_CHART_WINDOW_PROP_STRING property);

Все вхождения строки "this.m_window_num" заменим на строку "this.WindowNum()" (без кавычек естественно) — так как мы удалили переменную m_window_num, и теперь номер окна у нас расположен в свойствах объекта, то мы и будем возвращать значение этого свойства при помощи метода WindowNum().

Метод WindowNum() ранее возвращал значение переменной m_window_num:

   int               WindowNum(void) const { return this.m_window_num; }

Теперь этот метод будет возвращать свойство объекта:

   int               WindowNum(void) const { return (int)this.GetProperty(CHART_WINDOW_PROP_WINDOW_NUM); }

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

//--- Возвращает (1) номер подокна, (2) количество индикаторов, прикреплённых к окну, (3) наименование символа графика, (4) максимальную, (5) минимальную цену
   int               WindowNum(void)                              const { return (int)this.GetProperty(CHART_WINDOW_PROP_WINDOW_NUM);     }
   int               IndicatorsTotal(void)                        const { return this.m_list_ind.Total();                                 }
   string            Symbol(void)                                 const { return this.GetProperty(CHART_WINDOW_PROP_SYMBOL);              }
   double            PriceMax(void)                               const { return this.GetProperty(CHART_WINDOW_PROP_PRICE_MAX);           }
   double            PriceMin(void)                               const { return this.GetProperty(CHART_WINDOW_PROP_PRICE_MIN);           }
//--- Устанавливает (1) номер подокна, (2) символ графика
   void              SetWindowNum(const int num)                        { this.SetProperty(CHART_WINDOW_PROP_WINDOW_NUM,num);             }
   void              SetSymbol(const string symbol)                     { this.SetProperty(CHART_WINDOW_PROP_SYMBOL,symbol);              }

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

Можно в принципе и не делать этих методов — класс CBaseObjExt уже предоставляет возможность установки контрольных величин и отслеживаемых свойств, но так как класс универсальный, то его методы достаточно абстрактны, и необходимо помнить имена констант, требующихся нам для контроля свойств. А это неудобно. Поэтому мы в такие классы, которые работают на основе класса расширенного объекта CBaseObjExt, добавляем такие методы — они явно указывают, что именно мы ими устанавливаем объекту.

Итак, в самом конце листинга тела класса напишем два блока кода для установки отслеживаемых свойств для дистанции в пикселях между рамками окон и для высоты окна графика в пикселях:

//+------------------------------------------------------------------+
//| Получение и установка параметров отслеживаемых изменений свойств |
//+------------------------------------------------------------------+
//--- Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня дистанции в пикселях по вертикальной оси Y графика между рамками окон
//--- получение (4) величины изменения дистанции в пикселях по вертикальной оси Y графика между рамками окон,
//--- получение флага изменения дистанции в пикселях по вертикальной оси Y графика между рамками окон больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlWindowYDistanceInc(const long value)        { this.SetControlledValueINC(CHART_WINDOW_PROP_YDISTANCE,(long)::fabs(value));         }
   void              SetControlWindowYDistanceDec(const long value)        { this.SetControlledValueDEC(CHART_WINDOW_PROP_YDISTANCE,(long)::fabs(value));         }
   void              SetControlWindowYDistanceLevel(const long value)      { this.SetControlledValueLEVEL(CHART_WINDOW_PROP_YDISTANCE,(long)::fabs(value));       }
   long              GetValueChangedWindowYDistance(void)            const { return this.GetPropLongChangedValue(CHART_WINDOW_PROP_YDISTANCE);                    }
   bool              IsIncreasedWindowYDistance(void)                const { return (bool)this.GetPropLongFlagINC(CHART_WINDOW_PROP_YDISTANCE);                   }
   bool              IsDecreasedWindowYDistance(void)                const { return (bool)this.GetPropLongFlagDEC(CHART_WINDOW_PROP_YDISTANCE);                   }
   
//--- Высота окна графика в пикселях
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня высоты графика в пикселях
//--- получение (4) величины изменения высоты графика в пикселях,
//--- получение флага изменения высоты графика в пикселях больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlHeightInPixelsInc(const long value)         { this.SetControlledValueINC(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS,(long)::fabs(value));   }
   void              SetControlHeightInPixelsDec(const long value)         { this.SetControlledValueDEC(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS,(long)::fabs(value));   }
   void              SetControlHeightInPixelsLevel(const long value)       { this.SetControlledValueLEVEL(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS,(long)::fabs(value)); }
   long              GetValueChangedHeightInPixels(void)             const { return this.GetPropLongChangedValue(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS);              }
   bool              IsIncreasedHeightInPixels(void)                 const { return (bool)this.GetPropLongFlagINC(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS);             }
   bool              IsDecreasedHeightInPixels(void)                 const { return (bool)this.GetPropLongFlagDEC(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS);             }
   
  };
//+------------------------------------------------------------------+

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

Параметрический конструктор класса претерпел изменения:

//+------------------------------------------------------------------+
//| Параметрический конструктор                                      |
//+------------------------------------------------------------------+
CChartWnd::CChartWnd(const long chart_id,const int wnd_num,const string symbol,CArrayObj *list_ind_del,CArrayObj *list_ind_param) : m_wnd_coord_x(0),m_wnd_coord_y(0)
  {
   this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS);
   this.m_list_ind_del=list_ind_del;
   this.m_list_ind_param=list_ind_param;
   CBaseObj::SetChartID(chart_id);
   this.m_type=COLLECTION_CHART_WND_ID;
   
//--- Инициализация массивов данных базового объекта
   this.SetControlDataArraySizeLong(CHART_WINDOW_PROP_INTEGER_TOTAL);
   this.SetControlDataArraySizeDouble(CHART_WINDOW_PROP_DOUBLE_TOTAL);
   this.ResetChangesParams();
   this.ResetControlsParams();
   
//--- Установка свойств объекта
   this.SetProperty(CHART_WINDOW_PROP_WINDOW_NUM,wnd_num);
   this.SetProperty(CHART_WINDOW_PROP_SYMBOL,symbol);
   this.SetProperty(CHART_WINDOW_PROP_ID,chart_id);
   this.SetProperty(CHART_WINDOW_PROP_YDISTANCE,::ChartGetInteger(chart_id,CHART_WINDOW_YDISTANCE,wnd_num));
   this.SetProperty(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS,::ChartGetInteger(chart_id,CHART_HEIGHT_IN_PIXELS,wnd_num));
   this.SetProperty(CHART_WINDOW_PROP_PRICE_MIN,::ChartGetDouble(chart_id,CHART_PRICE_MIN,wnd_num));
   this.SetProperty(CHART_WINDOW_PROP_PRICE_MAX,::ChartGetDouble(chart_id,CHART_PRICE_MAX,wnd_num));
   this.m_name=this.Header();

//--- Заполнение текущих данных символа
   for(int i=0;i<CHART_WINDOW_PROP_INTEGER_TOTAL;i++)
      this.m_long_prop_event[i][3]=this.m_long_prop[i];
   for(int i=0;i<CHART_WINDOW_PROP_DOUBLE_TOTAL;i++)
      this.m_double_prop_event[i][3]=this.m_double_prop[i];
//--- Обновление данных в базовом объекте и поиск изменений
   CBaseObjExt::Refresh();
   
//--- Создание списка индикаторов
   this.IndicatorsListCreate();
  }
//+------------------------------------------------------------------+

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

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

//+------------------------------------------------------------------+
//| Сравнивает объекты CChartWnd между собой по указанному свойству  |
//+------------------------------------------------------------------+
int CChartWnd::Compare(const CObject *node,const int mode=0) const
  {
   const CChartWnd *obj_compared=node;
   if(mode==CHART_WINDOW_PROP_YDISTANCE)
      return(this.YDistance()>obj_compared.YDistance() ? 1 : this.YDistance()<obj_compared.YDistance() ? -1 : 0);
   else if(mode==CHART_WINDOW_PROP_HEIGHT_IN_PIXELS)
      return(this.HeightInPixels()>obj_compared.HeightInPixels() ? 1 : this.HeightInPixels()<obj_compared.HeightInPixels() ? -1 : 0);
   else if(mode==CHART_WINDOW_PROP_WINDOW_NUM)
      return(this.WindowNum()>obj_compared.WindowNum() ? 1 : this.WindowNum()<obj_compared.WindowNum() ? -1 : 0);
   else if(mode==CHART_WINDOW_PROP_SYMBOL)
      return(this.Symbol()==obj_compared.Symbol() ? 0 : this.Symbol()>obj_compared.Symbol() ? 1 : -1);
   return -1;
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства объекта              |
//+------------------------------------------------------------------+
string CChartWnd::GetPropertyDescription(ENUM_CHART_WINDOW_PROP_INTEGER property)
  {
   return
     (
      property==CHART_WINDOW_PROP_ID  ?  CMessage::Text(MSG_CHART_OBJ_ID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)CBaseObj::GetChartID()
         )  :
      property==CHART_WINDOW_PROP_WINDOW_NUM  ?  CMessage::Text(MSG_CHART_OBJ_WINDOW_N)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.WindowNum()
         )  :
      property==CHART_WINDOW_PROP_YDISTANCE  ?  CMessage::Text(MSG_CHART_OBJ_WINDOW_YDISTANCE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.YDistance()
         )  :
      property==CHART_WINDOW_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()
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Напишем реализацию метода, возвращающего описание вещественного свойства объекта:

//+------------------------------------------------------------------+
//| Возвращает описание вещественного свойства объекта               |
//+------------------------------------------------------------------+
string CChartWnd::GetPropertyDescription(ENUM_CHART_WINDOW_PROP_DOUBLE property)
  {
   return
     (
      property==CHART_WINDOW_PROP_PRICE_MIN  ?  CMessage::Text(MSG_CHART_OBJ_PRICE_MIN)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.PriceMin(),this.m_digits)
         )  :
      property==CHART_WINDOW_PROP_PRICE_MAX  ?  CMessage::Text(MSG_CHART_OBJ_PRICE_MAX)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.PriceMax(),this.m_digits)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Возвращает описание строкового свойства объекта                  |
//+------------------------------------------------------------------+
string CChartWnd::GetPropertyDescription(ENUM_CHART_WINDOW_PROP_STRING property)
  {
   return
     (
      property==CHART_WINDOW_PROP_SYMBOL  ?  CMessage::Text(MSG_LIB_PROP_SYMBOL)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.Symbol()
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Выводит в журнал свойства объекта                                |
//+------------------------------------------------------------------+
void CChartWnd::Print(const bool full_prop=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=CHART_WINDOW_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_WINDOW_PROP_INTEGER prop=(ENUM_CHART_WINDOW_PROP_INTEGER)i;
      if(prop==CHART_WINDOW_PROP_WINDOW_IND_HANDLE || prop==CHART_WINDOW_PROP_WINDOW_IND_INDEX) continue;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=CHART_WINDOW_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_WINDOW_PROP_DOUBLE prop=(ENUM_CHART_WINDOW_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   beg=end; end+=CHART_WINDOW_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_CHART_WINDOW_PROP_STRING prop=(ENUM_CHART_WINDOW_PROP_STRING)i;
      if(prop==CHART_WINDOW_PROP_IND_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");
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Выводит в журнал описание параметров окна                        |
//+------------------------------------------------------------------+
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,":");
   string pref=(dash ? " - " : "");
   if(this.WindowNum()>0)
      ::Print(pref,GetPropertyDescription(CHART_WINDOW_PROP_YDISTANCE));
   ::Print(pref,GetPropertyDescription(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS));
   ::Print(pref,GetPropertyDescription(CHART_WINDOW_PROP_PRICE_MAX));
   ::Print(pref,GetPropertyDescription(CHART_WINDOW_PROP_PRICE_MIN));
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Обновляет данные по прикреплённым индикаторам                    |
//+------------------------------------------------------------------+
void CChartWnd::Refresh(void)
  {
   //--- Инициализация событийных данных
   this.m_is_event=false;
   this.m_hash_sum=0;
   //--- Рассчитываем значение изменения количества индикаторов в окне "сейчас и на прошлой проверке"
   int change=::ChartIndicatorsTotal(this.m_chart_id,this.WindowNum())-this.m_list_ind.Total();
   //--- Если нет изменения количества индикаторов в окне -
   if(change==0)
     {
      //--- проверяем изменение параметров всех индикаторов и выходим
      this.IndicatorsChangeCheck();
      //--- Обновление целочисленных свойств
      this.SetProperty(CHART_WINDOW_PROP_YDISTANCE,::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,this.WindowNum()));
      this.SetProperty(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS,::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS,this.WindowNum()));
      //--- Обновление вещественных свойств
      this.SetProperty(CHART_WINDOW_PROP_PRICE_MIN,::ChartGetDouble(this.m_chart_id,CHART_PRICE_MIN,this.WindowNum()));
      this.SetProperty(CHART_WINDOW_PROP_PRICE_MAX,::ChartGetDouble(this.m_chart_id,CHART_PRICE_MAX,this.WindowNum()));
      //--- Обновление строковых свойств
      string symbol=::ChartSymbol(this.m_chart_id);
      if(symbol!=NULL)
         this.SetProperty(CHART_WINDOW_PROP_SYMBOL,symbol);
      
      //--- Заполнение текущих данных символа
      for(int i=0;i<CHART_WINDOW_PROP_INTEGER_TOTAL;i++)
         this.m_long_prop_event[i][3]=this.m_long_prop[i];
      for(int i=0;i<CHART_WINDOW_PROP_DOUBLE_TOTAL;i++)
         this.m_double_prop_event[i][3]=this.m_double_prop[i];
      
      //--- Обновление данных в базовом объекте, поиск изменений и выход
      CBaseObjExt::Refresh();
      this.CheckEvents();
      return;
     }
   //--- Если добавлены индикаторы
   if(change>0)
     {
      //--- Вызываем метод добавления новых индикаторов в список
      this.IndicatorsAdd();
      //--- В цикле по количеству добавленных в окно индикаторов
      for(int i=0;i<change;i++)
        {
         //--- получаем новый индикатор в списке по рассчитанному от конца списка индексу
         int index=this.m_list_ind.Total()-(1+i);
         //--- и если объект получить не удалось - переходим к следующему
         CWndInd *ind=this.m_list_ind.At(index);
         if(ind==NULL)
            continue;
         //--- вызываем метод отправки события на график управляющей программы
         this.SendEvent(CHART_OBJ_EVENT_CHART_WND_IND_ADD);
        }
     }
   //--- Если есть удалённые индикаторы
   if(change<0)
     {
      //--- Вызываем метод удаления лишних индикаторов из списка
      this.IndicatorsDelete();
      //--- В цикле по количеству удалённых из окна индикаторов
      for(int i=0;i<-change;i++)
        {
         //--- получаем новый удалённый индикатор в списке удалённых индикаторов по рассчитанному от конца списка индексу
         int index=this.m_list_ind_del.Total()-(1+i);
         //--- и если объект получить не удалось - переходим к следующему
         CWndInd *ind=this.m_list_ind_del.At(index);
         if(ind==NULL)
            continue;
         //--- вызываем метод отправки события на график управляющей программы
         this.SendEvent(CHART_OBJ_EVENT_CHART_WND_IND_DEL);
        }
     }
  }
//+------------------------------------------------------------------+

Здесь всё расписано в комментариях в блоке кода, и подробнее мы это рассматривали в описании доработки параметрического конструктора — практически то же самое.

На этом преобразование класса объекта окна графика в полноценный объект библиотеки завершено.

Теперь доработаем класс объекта-чарта в файле \MQL5\Include\DoEasy\Objects\Chart\ChartObj.mqh.

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

//+------------------------------------------------------------------+
//| Класс объекта-чарта                                              |
//+------------------------------------------------------------------+
class CChartObj : public CBaseObjExt
  {
private:
   CArrayObj         m_list_wnd;                                  // Список объектов окон графика
   CArrayObj        *m_list_wnd_del;                              // Указатель на список удалённых объектов окон графика
   CArrayObj        *m_list_ind_del;                              // Указатель на список удалённых из окна индикаторов
   CArrayObj        *m_list_ind_param;                            // Указатель на список изменённых индикаторов
   long              m_long_prop[CHART_PROP_INTEGER_TOTAL];       // Целочисленные свойства
   double            m_double_prop[CHART_PROP_DOUBLE_TOTAL];      // Вещественные свойства
   string            m_string_prop[CHART_PROP_STRING_TOTAL];      // Строковые свойства
   string            m_symbol_prev;                               // Прошлый символ чарта
   ENUM_TIMEFRAMES   m_timeframe_prev;                            // Прошлый таймфрейм
   int               m_digits;                                    // Digits() символа
   int               m_last_event;                                // Последнее событие
   datetime          m_wnd_time_x;                                // Время для координаты X на графике в окне
   double            m_wnd_price_y;                               // Цена для координаты Y на графике в окне

Нам необходимо будет заполнять данные чарта в методе обновления чарта, и они у нас так же заполняются и в конструкторе класса. Свойств у объекта-чарта достаточно много, поэтому чтобы не писать однотипный код в разных методах, вынесем его в отдельные методы и там, где необходимо заполнить свойства объекта данными чарта, будем вызывать эти методы. Объявим их в приватной секции класса:

//--- Методы установки значений свойств
   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              SetFirstVisibleBars(void);
   void              SetWidthInBars(void);
   void              SetWidthInPixels(void);
   void              SetMaximizedFlag(void);
   void              SetMinimizedFlag(void);
   void              SetExpertName(void);
   void              SetScriptName(void);
   
//--- Заполняет (1) целочисленные, (2) вещественные, (3) строковые свойства объекта
   bool              SetIntegerParameters(void);
   void              SetDoubleParameters(void);
   bool              SetStringParameters(void);

//--- (1) Создаёт, (2) проверяет и пересоздаёт список окон графика
   void              CreateWindowsList(void);
   void              RecreateWindowsList(const int change);
//--- Добавляет расширение файлу скриншота при его отсутствии
   string            FileNameWithExtention(const string filename);
   
public:

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

//--- Возвращает индикатор по индексу из указанного окна графика
   CWndInd          *GetIndicator(const int win_num,const int ind_index);
   
//--- Возвращает флаг поддержания объектом данного свойства
   virtual bool      SupportProperty(ENUM_CHART_PROP_INTEGER property)           { return true; }
   virtual bool      SupportProperty(ENUM_CHART_PROP_DOUBLE property)            { return true; }
   virtual bool      SupportProperty(ENUM_CHART_PROP_STRING property)            { return true; }

//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства
   string            GetPropertyDescription(ENUM_CHART_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_CHART_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_CHART_PROP_STRING property);

Ранее метод, возвращающий флаг поддержания целочисленного свойства, возвращал false в случае, если это свойство — дистанция в пикселях между рамками окон графика.

Впишем три публичных метода, необходимых для работы с событийным функционалом родительского класса:

//--- Возвращает (1) флаг события, (2) код последнего события, (3) последнее событие
   bool              IsEvent(void)                                   const { return this.m_is_event;                                      }
   int               GetLastEventsCode(void)                         const { return this.m_event_code;                                    }
   int               GetLastEvent(void)                              const { return this.m_last_event;                                    }
   
//--- Конструкторы
                     CChartObj(){;}
                     CChartObj(const long chart_id,CArrayObj *list_wnd_del,CArrayObj *list_ind_del,CArrayObj *list_ind_param);
//+------------------------------------------------------------------+ 

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

//--- (1) Возвращает, (2) Включает, (3) отключает закрепление окна графика
   bool              IsDocked(void)                                  const { return (bool)this.GetProperty(CHART_PROP_IS_DOCKED);         }
   bool              SetDockedON(const bool redraw=false)                  { return this.SetDockedFlag(DFUN,true,redraw); }
   bool              SetDockedOFF(const bool redraw=false)                 { return this.SetDockedFlag(DFUN,false,redraw); }
   
//--- (1) Возвращает, (2) Включает, (3) отключает показ графика поверх всех других
   bool              IsBringTop(void)                                      { return (bool)this.GetProperty(CHART_PROP_BRING_TO_TOP);      }
   bool              SetBringToTopON(const bool redraw=false)              { return this.SetBringToTopFlag(DFUN,true,redraw);             }
   bool              SetBringToTopOFF(const bool redraw=false)             { return this.SetBringToTopFlag(DFUN,false,redraw);            }
   
//--- (1) Возвращает, устанавливает тип графика (2) бары, (3) свечи, (4) линия 
   ENUM_CHART_MODE   Mode(void)                                      const { return (ENUM_CHART_MODE)this.GetProperty(CHART_PROP_MODE);   }
   bool              SetModeBars(const bool redraw=false)                  { return this.SetMode(DFUN,CHART_BARS,redraw);                 }
   bool              SetModeCandles(const bool redraw=false)               { return this.SetMode(DFUN,CHART_CANDLES,redraw);              }
   bool              SetModeLine(const bool redraw=false)                  { return this.SetMode(DFUN,CHART_LINE,redraw);                 }

Метод возвращает флаг CHART_BRING_TO_TOP.

Стоит отметить, что в справке это свойство указано как "только для записи" (w/o), и в примере указано, что возможно только установить нужный график активным, т.е. — не позволяет считывать его состояние, а только устанавливать. Однако на самом деле, это свойство так же и считывается, и при его помощи можно узнать, какой именно график на данный момент активен. То ли это ошибка в справке, то ли это недокументированная возможность (что крайне нежелательно), но по факту пока это работает. Если это свойство графика вдруг перестанет считываться (будет приведено в соответствии со справкой), то возникнут проблемы для возможности быстрого получения активного на данный момент графика и придётся выдумавать что-то своё.

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

//+------------------------------------------------------------------+
//| Получение и установка параметров отслеживаемых изменений свойств |
//+------------------------------------------------------------------+
//CHART_PROP_ID = 0,                                 // Идентификатор графика
   
//--- Таймфрейм графика
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня таймфрейма графика
//--- получение (4) величины изменения таймфрейма графика,
//--- получение флага изменения таймфрейма графика больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlTimeframeInc(const long value)              { this.SetControlledValueINC(CHART_PROP_TIMEFRAME,(long)::fabs(value));          }
   void              SetControlTimeframeDec(const long value)              { this.SetControlledValueDEC(CHART_PROP_TIMEFRAME,(long)::fabs(value));          }
   void              SetControlTimeframeLevel(const long value)            { this.SetControlledValueLEVEL(CHART_PROP_TIMEFRAME,(long)::fabs(value));        }
   long              GetValueChangedTimeframe(void)                  const { return this.GetPropLongChangedValue(CHART_PROP_TIMEFRAME);                     }
   bool              IsIncreasedTimeframe(void)                      const { return (bool)this.GetPropLongFlagINC(CHART_PROP_TIMEFRAME);                    }
   bool              IsDecreasedTimeframe(void)                      const { return (bool)this.GetPropLongFlagDEC(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)
   
//--- Тип графика (свечи, бары или линия (ENUM_CHART_MODE))
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня таймфрейма графика
//--- получение (4) величины изменения таймфрейма графика,
//--- получение флага изменения таймфрейма графика больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlChartModeInc(const long value)              { this.SetControlledValueINC(CHART_PROP_MODE,(long)::fabs(value));               }
   void              SetControlChartModeDec(const long value)              { this.SetControlledValueDEC(CHART_PROP_MODE,(long)::fabs(value));               }
   void              SetControlChartModeLevel(const long value)            { this.SetControlledValueLEVEL(CHART_PROP_MODE,(long)::fabs(value));             }
   long              GetValueChangedChartMode(void)                  const { return this.GetPropLongChangedValue(CHART_PROP_MODE);                          }
   bool              IsIncreasedChartMode(void)                      const { return (bool)this.GetPropLongFlagINC(CHART_PROP_MODE);                         }
   bool              IsDecreasedChartMode(void)                      const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_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_HANDLE,                          // Хэндл окна графика
   
   //CHART_PROP_WINDOW_YDISTANCE
////--- Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
////--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня дистанции в пикселях по вертикальной оси Y графика между рамками окон
////--- получение (4) величины изменения дистанции в пикселях по вертикальной оси Y графика между рамками окон,
////--- получение флага изменения дистанции в пикселях по вертикальной оси Y графика между рамками окон больше, чем на величину (5) прироста, (6) уменьшения
//   void              SetControlWindowYDistanceInc(const long value)        { this.SetControlledValueINC(CHART_PROP_WINDOW_YDISTANCE,(long)::fabs(value));   }
//   void              SetControlWindowYDistanceDec(const long value)        { this.SetControlledValueDEC(CHART_PROP_WINDOW_YDISTANCE,(long)::fabs(value));   }
//   void              SetControlWindowYDistanceLevel(const long value)      { this.SetControlledValueLEVEL(CHART_PROP_WINDOW_YDISTANCE,(long)::fabs(value)); }
//   long              GetValueChangedWindowYDistance(void)            const { return this.GetPropLongChangedValue(CHART_PROP_WINDOW_YDISTANCE);              }
//   bool              IsIncreasedWindowYDistance(void)                const { return (bool)this.GetPropLongFlagINC(CHART_PROP_WINDOW_YDISTANCE);             }
//   bool              IsDecreasedWindowYDistance(void)                const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_WINDOW_YDISTANCE);             }
   
//CHART_PROP_FIRST_VISIBLE_BAR,                      // Номер первого видимого бара на графике
   
//--- Ширина графика в барах
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня ширины графика в барах
//--- получение (4) величины изменения ширины графика в барах,
//--- получение флага изменения ширины графика в барах больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlWidthInBarsInc(const long value)            { this.SetControlledValueINC(CHART_PROP_WIDTH_IN_BARS,(long)::fabs(value));      }
   void              SetControlWidthInBarsDec(const long value)            { this.SetControlledValueDEC(CHART_PROP_WIDTH_IN_BARS,(long)::fabs(value));      }
   void              SetControlWidthInBarsLevel(const long value)          { this.SetControlledValueLEVEL(CHART_PROP_WIDTH_IN_BARS,(long)::fabs(value));    }
   long              GetValueChangedWidthInBars(void)                const { return this.GetPropLongChangedValue(CHART_PROP_WIDTH_IN_BARS);                 }
   bool              IsIncreasedWidthInBars(void)                    const { return (bool)this.GetPropLongFlagINC(CHART_PROP_WIDTH_IN_BARS);                }
   bool              IsDecreasedWidthInBars(void)                    const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_WIDTH_IN_BARS);                }
   
//--- Ширина графика в пикселях
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня ширины графика в пикселях
//--- получение (4) величины изменения ширины графика в пикселях,
//--- получение флага изменения ширины графика в пикселях больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlWidthInPixelsInc(const long value)          { this.SetControlledValueINC(CHART_PROP_WIDTH_IN_PIXELS,(long)::fabs(value));    }
   void              SetControlWidthInPixelsDec(const long value)          { this.SetControlledValueDEC(CHART_PROP_WIDTH_IN_PIXELS,(long)::fabs(value));    }
   void              SetControlWidthInPixelsLevel(const long value)        { this.SetControlledValueLEVEL(CHART_PROP_WIDTH_IN_PIXELS,(long)::fabs(value));  }
   long              GetValueChangedWidthInPixels(void)              const { return this.GetPropLongChangedValue(CHART_PROP_WIDTH_IN_PIXELS);               }
   bool              IsIncreasedWidthInPixels(void)                  const { return (bool)this.GetPropLongFlagINC(CHART_PROP_WIDTH_IN_PIXELS);              }
   bool              IsDecreasedWidthInPixels(void)                  const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_WIDTH_IN_PIXELS);              }
   
//--- Высота графика в пикселях
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня высоты графика в пикселях
//--- получение (4) величины изменения высоты графика в пикселях,
//--- получение флага изменения высоты графика в пикселях больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlHeightInPixelsInc(const long value)         { this.SetControlledValueINC(CHART_PROP_HEIGHT_IN_PIXELS,(long)::fabs(value));   }
   void              SetControlHeightInPixelsDec(const long value)         { this.SetControlledValueDEC(CHART_PROP_HEIGHT_IN_PIXELS,(long)::fabs(value));   }
   void              SetControlHeightInPixelsLevel(const long value)       { this.SetControlledValueLEVEL(CHART_PROP_HEIGHT_IN_PIXELS,(long)::fabs(value)); }
   long              GetValueChangedHeightInPixels(void)             const { return this.GetPropLongChangedValue(CHART_PROP_HEIGHT_IN_PIXELS);              }
   bool              IsIncreasedHeightInPixels(void)                 const { return (bool)this.GetPropLongFlagINC(CHART_PROP_HEIGHT_IN_PIXELS);             }
   bool              IsDecreasedHeightInPixels(void)                 const { return (bool)this.GetPropLongFlagDEC(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,                              // Окно графика закреплено

//--- Левая координата открепленного графика относительно виртуального экрана
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня левой координаты открепленного графика относительно виртуального экрана
//--- получение (4) величины изменения левой координаты открепленного графика относительно виртуального экрана,
//--- получение флага изменения левой координаты открепленного графика относительно виртуального экрана больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlFloatLeftInc(const long value)              { this.SetControlledValueINC(CHART_PROP_FLOAT_LEFT,(long)::fabs(value));         }
   void              SetControlFloatLeftDec(const long value)              { this.SetControlledValueDEC(CHART_PROP_FLOAT_LEFT,(long)::fabs(value));         }
   void              SetControlFloatLeftLevel(const long value)            { this.SetControlledValueLEVEL(CHART_PROP_FLOAT_LEFT,(long)::fabs(value));       }
   long              GetValueChangedFloatLeft(void)                  const { return this.GetPropLongChangedValue(CHART_PROP_FLOAT_LEFT);                    }
   bool              IsIncreasedFloatLeft(void)                      const { return (bool)this.GetPropLongFlagINC(CHART_PROP_FLOAT_LEFT);                   }
   bool              IsDecreasedFloatLeft(void)                      const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_FLOAT_LEFT);                   }
   
//--- Верхняя координата открепленного графика относительно виртуального экрана
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня верхней координаты открепленного графика относительно виртуального экрана
//--- получение (4) величины изменения верхней координаты открепленного графика относительно виртуального экрана,
//--- получение флага изменения верхней координаты открепленного графика относительно виртуального экрана больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlFloatTopInc(const long value)               { this.SetControlledValueINC(CHART_PROP_FLOAT_TOP,(long)::fabs(value));          }
   void              SetControlFloatTopDec(const long value)               { this.SetControlledValueDEC(CHART_PROP_FLOAT_TOP,(long)::fabs(value));          }
   void              SetControlFloatTopLevel(const long value)             { this.SetControlledValueLEVEL(CHART_PROP_FLOAT_TOP,(long)::fabs(value));        }
   long              GetValueChangedFloatTop(void)                   const { return this.GetPropLongChangedValue(CHART_PROP_FLOAT_TOP);                     }
   bool              IsIncreasedFloatTop(void)                       const { return (bool)this.GetPropLongFlagINC(CHART_PROP_FLOAT_TOP);                    }
   bool              IsDecreasedFloatTop(void)                       const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_FLOAT_TOP);                    }
   
//--- Правая координата открепленного графика  относительно виртуального экрана
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня правой координаты открепленного графика относительно виртуального экрана
//--- получение (4) величины изменения правой координаты открепленного графика относительно виртуального экрана,
//--- получение флага изменения правой координаты открепленного графика относительно виртуального экрана больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlFloatRightInc(const long value)             { this.SetControlledValueINC(CHART_PROP_FLOAT_RIGHT,(long)::fabs(value));        }
   void              SetControlFloatRightDec(const long value)             { this.SetControlledValueDEC(CHART_PROP_FLOAT_RIGHT,(long)::fabs(value));        }
   void              SetControlFloatRightLevel(const long value)           { this.SetControlledValueLEVEL(CHART_PROP_FLOAT_RIGHT,(long)::fabs(value));      }
   long              GetValueChangedFloatRight(void)                 const { return this.GetPropLongChangedValue(CHART_PROP_FLOAT_RIGHT);                   }
   bool              IsIncreasedFloatRight(void)                     const { return (bool)this.GetPropLongFlagINC(CHART_PROP_FLOAT_RIGHT);                  }
   bool              IsDecreasedFloatRight(void)                     const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_FLOAT_RIGHT);                  }
   
//--- Нижняя координата открепленного графика  относительно виртуального экрана
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня нижней координаты открепленного графика относительно виртуального экрана
//--- получение (4) величины изменения нижней координаты открепленного графика относительно виртуального экрана,
//--- получение флага изменения нижней координаты открепленного графика относительно виртуального экрана больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlFloatBottomInc(const long value)            { this.SetControlledValueINC(CHART_PROP_FLOAT_BOTTOM,(long)::fabs(value));       }
   void              SetControlFloatBottomDec(const long value)            { this.SetControlledValueDEC(CHART_PROP_FLOAT_BOTTOM,(long)::fabs(value));       }
   void              SetControlFloatBottomLevel(const long value)          { this.SetControlledValueLEVEL(CHART_PROP_FLOAT_BOTTOM,(long)::fabs(value));     }
   long              GetValueChangedFloatBottom(void)                const { return this.GetPropLongChangedValue(CHART_PROP_FLOAT_BOTTOM);                  }
   bool              IsIncreasedFloatBottom(void)                    const { return (bool)this.GetPropLongFlagINC(CHART_PROP_FLOAT_BOTTOM);                 }
   bool              IsDecreasedFloatBottom(void)                    const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_FLOAT_BOTTOM);                 }
   
//--- Размер отступа нулевого бара от правого края в процентах
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня размера отступа нулевого бара от правого края в процентах
//--- получение (4) величины изменения размера отступа нулевого бара от правого края в процентах,
//--- получение флага изменения размера отступа нулевого бара от правого края в процентах больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlShiftSizeInc(const long value)              { this.SetControlledValueINC(CHART_PROP_SHIFT_SIZE,(long)::fabs(value));         }
   void              SetControlShiftSizeDec(const long value)              { this.SetControlledValueDEC(CHART_PROP_SHIFT_SIZE,(long)::fabs(value));         }
   void              SetControlShiftSizeLevel(const long value)            { this.SetControlledValueLEVEL(CHART_PROP_SHIFT_SIZE,(long)::fabs(value));       }
   double            GetValueChangedShiftSize(void)                  const { return this.GetPropDoubleChangedValue(CHART_PROP_SHIFT_SIZE);                  }
   bool              IsIncreasedShiftSize(void)                      const { return (bool)this.GetPropLongFlagINC(CHART_PROP_SHIFT_SIZE);                   }
   bool              IsDecreasedShiftSize(void)                      const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_SHIFT_SIZE);                   }
   
//--- Положение фиксированной позиции графика от левого края в процентах
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня положения фиксированной позиции графика от левого края в процентах
//--- получение (4) величины изменения положения фиксированной позиции графика от левого края в процентах,
//--- получение флага изменения положения фиксированной позиции графика от левого края в процентах больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlFixedPositionInc(const long value)          { this.SetControlledValueINC(CHART_PROP_FIXED_POSITION,(long)::fabs(value));     }
   void              SetControlFixedPositionDec(const long value)          { this.SetControlledValueDEC(CHART_PROP_FIXED_POSITION,(long)::fabs(value));     }
   void              SetControlFixedPositionLevel(const long value)        { this.SetControlledValueLEVEL(CHART_PROP_FIXED_POSITION,(long)::fabs(value));   }
   double            GetValueChangedFixedPosition(void)              const { return this.GetPropDoubleChangedValue(CHART_PROP_FIXED_POSITION);              }
   bool              IsIncreasedFixedPosition(void)                  const { return (bool)this.GetPropLongFlagINC(CHART_PROP_FIXED_POSITION);               }
   bool              IsDecreasedFixedPosition(void)                  const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_FIXED_POSITION);               }
   
//--- Фиксированный максимум графика
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня фиксированного максимума графика
//--- получение (4) величины изменения фиксированного максимума графика,
//--- получение флага изменения положения фиксированного максимума графика больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlFixedMaxInc(const long value)               { this.SetControlledValueINC(CHART_PROP_FIXED_MAX,(long)::fabs(value));          }
   void              SetControlFixedMaxDec(const long value)               { this.SetControlledValueDEC(CHART_PROP_FIXED_MAX,(long)::fabs(value));          }
   void              SetControlFixedMaxLevel(const long value)             { this.SetControlledValueLEVEL(CHART_PROP_FIXED_MAX,(long)::fabs(value));        }
   double            GetValueChangedFixedMax(void)                   const { return this.GetPropDoubleChangedValue(CHART_PROP_FIXED_MAX);                   }
   bool              IsIncreasedFixedMax(void)                       const { return (bool)this.GetPropLongFlagINC(CHART_PROP_FIXED_MAX);                    }
   bool              IsDecreasedFixedMax(void)                       const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_FIXED_MAX);                    }
   
//--- Фиксированный минимум графика
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня фиксированного минимума графика
//--- получение (4) величины изменения фиксированного минимума графика,
//--- получение флага изменения положения фиксированного минимума графика больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlFixedMinInc(const long value)               { this.SetControlledValueINC(CHART_PROP_FIXED_MIN,(long)::fabs(value));          }
   void              SetControlFixedMinDec(const long value)               { this.SetControlledValueDEC(CHART_PROP_FIXED_MIN,(long)::fabs(value));          }
   void              SetControlFixedMinLevel(const long value)             { this.SetControlledValueLEVEL(CHART_PROP_FIXED_MIN,(long)::fabs(value));        }
   double            GetValueChangedFixedMin(void)                   const { return this.GetPropDoubleChangedValue(CHART_PROP_FIXED_MIN);                   }
   bool              IsIncreasedFixedMin(void)                       const { return (bool)this.GetPropLongFlagINC(CHART_PROP_FIXED_MIN);                    }
   bool              IsDecreasedFixedMin(void)                       const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_FIXED_MIN);                    }
   
//CHART_PROP_POINTS_PER_BAR,                         // Значение масштаба в пунктах на бар

//--- Минимум графика
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня минимума графика
//--- получение (4) величины изменения минимума графика,
//--- получение флага изменения положения минимума графика больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlPriceMinInc(const long value)               { this.SetControlledValueINC(CHART_PROP_PRICE_MIN,(long)::fabs(value));          }
   void              SetControlPriceMinDec(const long value)               { this.SetControlledValueDEC(CHART_PROP_PRICE_MIN,(long)::fabs(value));          }
   void              SetControlPriceMinLevel(const long value)             { this.SetControlledValueLEVEL(CHART_PROP_PRICE_MIN,(long)::fabs(value));        }
   double            GetValueChangedPriceMin(void)                   const { return this.GetPropDoubleChangedValue(CHART_PROP_PRICE_MIN);                   }
   bool              IsIncreasedPriceMin(void)                       const { return (bool)this.GetPropLongFlagINC(CHART_PROP_PRICE_MIN);                    }
   bool              IsDecreasedPriceMin(void)                       const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_PRICE_MIN);                    }
   
//--- Максимум графика
//--- установка контролируемой величины (1) прироста, (2) уменьшения, (3) контрольного уровня максимума графика
//--- получение (4) величины изменения максимума графика,
//--- получение флага изменения положения максимума графика больше, чем на величину (5) прироста, (6) уменьшения
   void              SetControlPriceMaxInc(const long value)               { this.SetControlledValueINC(CHART_PROP_PRICE_MAX,(long)::fabs(value));          }
   void              SetControlPriceMaxDec(const long value)               { this.SetControlledValueDEC(CHART_PROP_PRICE_MAX,(long)::fabs(value));          }
   void              SetControlPriceMaxLevel(const long value)             { this.SetControlledValueLEVEL(CHART_PROP_PRICE_MAX,(long)::fabs(value));        }
   double            GetValueChangedPriceMax(void)                   const { return this.GetPropDoubleChangedValue(CHART_PROP_PRICE_MAX);                   }
   bool              IsIncreasedPriceMax(void)                       const { return (bool)this.GetPropLongFlagINC(CHART_PROP_PRICE_MAX);                    }
   bool              IsDecreasedPriceMax(void)                       const { return (bool)this.GetPropLongFlagDEC(CHART_PROP_PRICE_MAX);                    }
   
  };
//+------------------------------------------------------------------+

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

Конструктор класса был изменён таким же образом, как и в ранее обсуждаемом классе объекта-окна графика:

//+------------------------------------------------------------------+
//| Параметрический конструктор                                      |
//+------------------------------------------------------------------+
CChartObj::CChartObj(const long chart_id,CArrayObj *list_wnd_del,CArrayObj *list_ind_del,CArrayObj *list_ind_param) : m_wnd_time_x(0),m_wnd_price_y(0)
  {
   this.m_list_wnd_del=list_wnd_del;
   this.m_list_ind_del=list_ind_del;
   this.m_list_ind_param=list_ind_param;
//--- Установка идентификатора графика в базовый объект и идентификатора объекта-чарта
   CBaseObj::SetChartID(chart_id);
   this.m_type=COLLECTION_CHARTS_ID;
   
//--- Инициализация массивов данных базового объекта
   this.SetControlDataArraySizeLong(CHART_PROP_INTEGER_TOTAL);
   this.SetControlDataArraySizeDouble(CHART_PROP_DOUBLE_TOTAL);
   this.ResetChangesParams();
   this.ResetControlsParams();
   
//--- Идентификатор графика
   this.SetProperty(CHART_PROP_ID,chart_id);
//--- Установка целочисленных свойств
   this.SetIntegerParameters();
//--- Установка вещественных свойств
   this.SetDoubleParameters();
//--- Установка строковых свойств
   this.SetStringParameters();
//--- Инициализация переменных и списков
   this.m_digits=(int)::SymbolInfoInteger(this.Symbol(),SYMBOL_DIGITS);
   this.m_list_wnd_del.Sort(SORT_BY_CHART_WINDOW_NUM);
   this.CreateWindowsList();
   this.m_symbol_prev=this.Symbol();
   this.m_timeframe_prev=this.Timeframe();
   this.m_name=this.Header();
   
//--- Заполнение текущих данных чарта
   for(int i=0;i<CHART_PROP_INTEGER_TOTAL;i++)
      this.m_long_prop_event[i][3]=this.m_long_prop[i];
   for(int i=0;i<CHART_PROP_DOUBLE_TOTAL;i++)
      this.m_double_prop_event[i][3]=this.m_double_prop[i];
   
//--- Обновление данных в базовом объекте и поиск изменений
   CBaseObjExt::Refresh();
  }
//+------------------------------------------------------------------+

Здесь запись значений параметров графика в свойства объекта осуществляется тремя методами, предназначенными для этого:

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

//+------------------------------------------------------------------+
//| Заполняет целочисленные свойства объекта                         |
//+------------------------------------------------------------------+
bool CChartObj::SetIntegerParameters(void)
  {
   ENUM_TIMEFRAMES timeframe=::ChartPeriod(this.ID());
   if(timeframe==0)
      return false;
   this.SetProperty(CHART_PROP_TIMEFRAME,timeframe);                                                     // Таймфрейм графика
   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,::ChartGetInteger(this.ID(),CHART_BRING_TO_TOP));            // Показ графика поверх всех других
   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_HANDLE,::ChartGetInteger(this.ID(),CHART_WINDOW_HANDLE));          // Хэндл окна графика
   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_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_YDISTANCE,::ChartGetInteger(this.ID(),CHART_WINDOW_YDISTANCE,0));         // Дистанция в пикселях по вертикальной оси Y между верхней рамкой подокна индикатора и верхней рамкой главного окна графика
   this.SetProperty(CHART_PROP_HEIGHT_IN_PIXELS,::ChartGetInteger(this.ID(),CHART_HEIGHT_IN_PIXELS,0));  // Высота графика в пикселях
   return true;
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Заполняет вещественные свойства объекта                          |
//+------------------------------------------------------------------+
void CChartObj::SetDoubleParameters(void)
  {
   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));                   // Максимум графика
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Заполняет строковые свойства объекта                             |
//+------------------------------------------------------------------+
bool CChartObj::SetStringParameters(void)
  {
   string symbol=::ChartSymbol(this.ID());
   if(symbol==NULL)
      return false;
   this.SetProperty(CHART_PROP_SYMBOL,symbol);                                                           // Символ графика
   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));               // Имя скрипта, запущенного на графике
   return true;
  }
//+------------------------------------------------------------------+

Методы, заполняющие целочисленные и строковые свойства возвращают bool-значения по той причине, что внутри методов мы получаем период графика и символ графика по его идентификатору функциями ChartPeriod() и ChartSymbol(). Эти функции могут вернуть либо ноль, либо пустую строку. В этих случаях методы вернут false.

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

      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_YDISTANCE  ?  CMessage::Text(MSG_CHART_OBJ_WINDOW_YDISTANCE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)::ChartGetInteger(this.m_chart_id,CHART_WINDOW_YDISTANCE,0)
         )  :
      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)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS,0)
         )  :
      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)
         )  :

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

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

//+------------------------------------------------------------------+
//| Обновляет объект-чарт и список его окон                          |
//+------------------------------------------------------------------+
void CChartObj::Refresh(void)
  {
//--- Инициализация событийных данных
   this.m_is_event=false;
   this.m_hash_sum=0;
   this.m_list_events.Clear();
   this.m_list_events.Sort();
//--- Обновление всех окон чарта
   for(int i=0;i<this.m_list_wnd.Total();i++)
     {
      //--- Получаем из списка очередной объект-окно графика
      CChartWnd *wnd=this.m_list_wnd.At(i);
      if(wnd==NULL)
         continue;
      //--- Обновляем окно и проверяем его флаг события
      //--- Если у окна нет события - идём к следующему окну
      wnd.Refresh();
      if(!wnd.IsEvent())
         continue;
      //--- Получаем список событий окна графика
      CArrayObj *list=wnd.GetListEvents();
      if(list==NULL)
         continue;
      //--- Устанавливаем флаг события чарта и получаем код последнего события
      this.m_is_event=true;
      this.m_event_code=wnd.GetEventCode();
      //--- В цикле по количеству событий окна графика
      int n=list.Total();
      for(int j=0; j<n; j++)
        {
         //--- получаем из списка событий окна графика объект базового события
         CEventBaseObj *event=list.At(j);
         if(event==NULL)
            continue;
         //--- На основании базового события создаём параметры события окна чарта
         ushort event_id=event.ID();
         this.m_last_event=event_id;
         string sparam=(string)this.GetChartID()+"_"+(string)wnd.WindowNum();
         //--- и, если окно на переднем плане и событие окна графика добавлено в список событий чарта -
         if(::ChartGetInteger(this.ID(),CHART_BRING_TO_TOP) && this.EventAdd((ushort)event.ID(),event.LParam(),event.DParam(),sparam))
           {
            //--- отправляем созданное событие окна чарта на график управляющей программы
            ::EventChartCustom(this.m_chart_id_main,(ushort)event_id,event.LParam(),event.DParam(),sparam);
           }
        }
     }
   
//--- Проверка изменений символа и периода графика чарта
   int change=(int)::ChartGetInteger(this.m_chart_id,CHART_WINDOWS_TOTAL)-this.WindowsTotal();
   if(change==0)
     {
      //--- Получаем символ и период графика по его идентификатору
      string symbol=::ChartSymbol(this.ID());
      ENUM_TIMEFRAMES timeframe=::ChartPeriod(this.ID());
      //--- Если символ и период получены
      if(symbol!=NULL && timeframe!=0)
        {
         //--- создаём флаги, указывающие на равенство/неравенство полученных символа-периода с текущими
         bool symb=symbol!=this.m_symbol_prev;
         bool tf=timeframe!=this.m_timeframe_prev;
         //--- Если что-то из них изменено - проверим что именно:
         if(symb || tf)
           {
            //--- Если изменены и символ, и таймфрейм
            if(symb && tf)
              {
               //--- Отправляем событие CHART_OBJ_EVENT_CHART_SYMB_TF_CHANGE на график управляющей программы
               this.SendEvent(CHART_OBJ_EVENT_CHART_SYMB_TF_CHANGE);
               //--- Устанавливаем объекту новый символ и период и
               this.SetSymbol(symbol);
               this.SetTimeframe(timeframe);
               //--- записываем текущие символ/период как прошлые
               this.m_symbol_prev=this.Symbol();
               this.m_timeframe_prev=this.Timeframe();
              }
            //--- Иначе, если изменён только символ графика
            else if(symb)
              {
               //--- Отправляем событие CHART_OBJ_EVENT_CHART_SYMB_CHANGE на график управляющей программы
               this.SendEvent(CHART_OBJ_EVENT_CHART_SYMB_CHANGE);
               //--- Устанавливаем объекту новый символ и записываем текущий символ как прошлый
               this.SetSymbol(symbol);
               this.m_symbol_prev=this.Symbol();
              }
            //--- Иначе, если изменён только период графика
            else if(tf)
              {
               //--- Отправляем событие CHART_OBJ_EVENT_CHART_TF_CHANGE на график управляющей программы
               this.SendEvent(CHART_OBJ_EVENT_CHART_TF_CHANGE);
               //--- Устанавливаем объекту новый таймфрейм и записываем текущий таймфрейм как прошлый
               this.SetTimeframe(timeframe);
               this.m_timeframe_prev=this.Timeframe();
              }
           }
        }
      //--- Обновление данных чарта
      if(this.SetIntegerParameters())
        {
         this.SetDoubleParameters();
         this.SetStringParameters();
        }
      //--- Заполнение текущих данных чарта
      for(int i=0;i<CHART_PROP_INTEGER_TOTAL;i++)
         this.m_long_prop_event[i][3]=this.m_long_prop[i];
      for(int i=0;i<CHART_PROP_DOUBLE_TOTAL;i++)
         this.m_double_prop_event[i][3]=this.m_double_prop[i];
      //--- Обновление данных в базовом объекте и поиск изменений
      CBaseObjExt::Refresh();
      this.CheckEvents();
     }
   else
     {
      this.RecreateWindowsList(change);
     }
  }
//+------------------------------------------------------------------+

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

В метод создания и отправки события графика на график управляющей программы допишем обработку события смены символа и/или периода графика:

//+------------------------------------------------------------------+
//| Создаёт и отправляет событие графика                             |
//| на график управляющей программы                                  |
//+------------------------------------------------------------------+
void CChartObj::SendEvent(ENUM_CHART_OBJ_EVENT event)
  {
   //--- Если добавлено окно
   if(event==CHART_OBJ_EVENT_CHART_WND_ADD)
     {
      //--- Получаем последний добавленный в список объект-окно графика
      CChartWnd *wnd=this.GetLastAddedWindow();
      if(wnd==NULL)
         return;
      //--- Отправляем событие CHART_OBJ_EVENT_CHART_WND_ADD на график управляющей программы
      //--- в lparam передаём идентификатор графика,
      //--- в dparam передаём номер окна графика,
      //--- в sparam передаём символ графика
      ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol());
     }
   //--- Если удалено окно
   else if(event==CHART_OBJ_EVENT_CHART_WND_DEL)
     {
      //--- Получаем последний объект-окно графика, добавленный в список удалённых окон
      CChartWnd *wnd=this.GetLastDeletedWindow();
      if(wnd==NULL)
         return;
      //--- Отправляем событие CHART_OBJ_EVENT_CHART_WND_DEL на график управляющей программы
      //--- в lparam передаём идентификатор графика,
      //--- в dparam передаём номер окна графика,
      //--- в sparam передаём символ графика
      ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol());
     }
   //--- Если сменён символ и таймфрейм
   else if(event==CHART_OBJ_EVENT_CHART_SYMB_TF_CHANGE)
     {
      //--- Отправляем событие CHART_OBJ_EVENT_CHART_SYMB_TF_CHANGE на график управляющей программы
      //--- в lparam передаём идентификатор графика,
      //--- в dparam передаём прошлый таймфрейм,
      //--- в sparam передаём прошлый символ графика
      ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.m_timeframe_prev,this.m_symbol_prev);
     }
   //--- Если сменён символ
   else if(event==CHART_OBJ_EVENT_CHART_SYMB_CHANGE)
     {
      //--- Отправляем событие CHART_OBJ_EVENT_CHART_SYMB_CHANGE на график управляющей программы
      //--- в lparam передаём идентификатор графика,
      //--- в dparam передаём текущий таймфрейм,
      //--- в sparam передаём прошлый символ графика
      ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.Timeframe(),this.m_symbol_prev);
     }
   //--- Если сменён таймфрейм
   else if(event==CHART_OBJ_EVENT_CHART_TF_CHANGE)
     {
      //--- Отправляем событие CHART_OBJ_EVENT_CHART_TF_CHANGE на график управляющей программы
      //--- в lparam передаём идентификатор графика,
      //--- в dparam передаём прошлый таймфрейм,
      //--- в sparam передаём текущий символ графика
      ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.m_timeframe_prev,this.Symbol());
     }
  }
//+------------------------------------------------------------------+

Здесь тоже всё подробно расписано в комментариях к коду и, надеюсь, вопросов не возникнет. В любом случае их можно задать в обсуждении статьи.

Теперь доработаем класс-коллекцию объектов-чартов в файле \MQL5\Include\DoEasy\Collections\ChartObjCollection.mqh.

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

//+------------------------------------------------------------------+
//| Коллекция объектов-mql5-сигналов                                 |
//+------------------------------------------------------------------+
class CChartObjCollection : public CBaseObjExt
  {
private:
   CListObj                m_list;                                   // Список объектов-чартов
   CListObj                m_list_del;                               // Список удалённых объектов-чартов
   CArrayObj               m_list_wnd_del;                           // Список удалённых объектов окон графика
   CArrayObj               m_list_ind_del;                           // Список удалённых из окна индикаторов
   CArrayObj               m_list_ind_param;                         // Список изменённых индикаторов
   int                     m_charts_total_prev;                      // Прошлое количество чартов в терминале
   int                     m_last_event;                             // Последнее событие
   //--- Возвращает количество чартов в терминале
   int                     ChartsTotal(void) const;
   //--- Возвращает флаг существования (1) объекта-чарта, (2) чарта
   bool                    IsPresentChartObj(const long chart_id);
   bool                    IsPresentChart(const long chart_id);
   //--- Создаёт новый объект-чарт и добавляет его в список
   bool                    CreateNewChartObj(const long chart_id,const string source);
   //--- Находит отсутствующий объект-чарт, создаёт его и добавляет в список-коллекцию
   bool                    FindAndCreateMissingChartObj(void);
   //--- Находит и удаляет из списка объект-чарт, отсутствующий в терминале
   void                    FindAndDeleteExcessChartObj(void);
public:

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

//--- Возвращает (1) флаг события, (2) событие одного из чартов, (3) последнее событие
   bool                    IsEvent(void)                             const { return this.m_is_event;                                   }
   int                     GetLastEventsCode(void)                   const { return this.m_event_code;                                 }
   int                     GetLastEvent(void)                        const { return this.m_last_event;                                 }
   
//--- Конструктор
                           CChartObjCollection();

//--- Возвращает список объектов-чартов по (1) символу, (2) таймфрейму
   CArrayObj              *GetChartsList(const string symbol)              { return this.GetList(CHART_PROP_SYMBOL,symbol,EQUAL);      }
   CArrayObj              *GetChartsList(const ENUM_TIMEFRAMES timeframe)  { return this.GetList(CHART_PROP_TIMEFRAME,timeframe,EQUAL);}
//--- Возвращает указатель на объект-чарт (1) по идентификатору, (2) по индексу в списке
   CChartObj              *GetChart(const long id);
   CChartObj              *GetChart(const int index)                       { return this.m_list.At(index);                             }
//--- Возвращает (1) последний добавленный чарт, (2) последний удалённый чарт
   CChartObj              *GetLastAddedChart(void)                         { return this.m_list.At(this.m_list.Total()-1);             }
   CChartObj              *GetLastDeletedChart(void)                       { return this.m_list_del.At(this.m_list_del.Total()-1);     }
   
//--- Возвращает (1) последнее добавленное окно на чарт по идентификатору чарта, (2) последнее удалённое окно чарта
   CChartWnd              *GetLastAddedChartWindow(const long chart_id); 
   CChartWnd              *GetLastDeletedChartWindow(void)                 { return this.m_list_wnd_del.At(this.m_list_wnd_del.Total()-1);}
//--- Возвращает указанный по индексу объект-окно указанного по идентификатору чарта
   CChartWnd              *GetChartWindow(const long chart_id,const int wnd_num);

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

//+------------------------------------------------------------------+
//| Обновляет список-коллекцию объектов-чартов                       |
//+------------------------------------------------------------------+
void CChartObjCollection::Refresh(void)
  {
//--- Инициализация событийных данных
   this.m_is_event=false;
   this.m_hash_sum=0;
   this.m_list_events.Clear();
   this.m_list_events.Sort();
   //--- В цикле по количеству объектов-чартов в списке-коллекции
   for(int i=0;i<this.m_list.Total();i++)
     {
      //--- получаем очередной объект-чарт и
      CChartObj *chart=this.m_list.At(i);
      if(chart==NULL)
         continue;
      //--- обновляем его
      chart.Refresh();
      //--- Если нет события чарта - идём к следующему
      if(!chart.IsEvent())
         continue;
      //--- Получаем список событий выбранного чарта
      CArrayObj *list=chart.GetListEvents();
      if(list==NULL)
         continue;
      //--- Устанавливаем флаг события в коллекции чартов и получаем код последнего события
      this.m_is_event=true;
      this.m_event_code=chart.GetEventCode();
      //--- В цикле по списку событий чарта
      int n=list.Total();
      for(int j=0; j<n; j++)
        {
         //--- получаем из списка событий чарта объект базового события
         CEventBaseObj *event=list.At(j);
         if(event==NULL)
            continue;
         //--- На основании базового события создаём параметры события чарта
         ushort event_id=event.ID();
         this.m_last_event=event_id;
         string sparam=(string)this.GetChartID();
         //--- и, если событие графика добавлено в список событий чарта -
         if(this.EventAdd((ushort)event.ID(),event.LParam(),event.DParam(),sparam))
           {
            //--- отправляем созданное событие чарта на график управляющей программы
            ::EventChartCustom(this.m_chart_id_main,(ushort)event_id,event.LParam(),event.DParam(),sparam);
           }
        }
     }
   
   //--- Получаем количество открытых графиков в терминале и
   int charts_total=this.ChartsTotal();
   //--- рассчитываем разницу между количеством открытых графиков в терминале
   //--- и объектов-чартов в списке-коллекции, эти значения выводим в комментарии на графике
   int change=charts_total-this.m_list.Total();
   //--- Если нет изменений - уходим
   if(change==0)
      return;
   //--- Если добавлен график в терминале
   if(change>0)
     {
      //--- Находим недостающий объект-чарт, создаём и добавляем его в список-коллекцию
      this.FindAndCreateMissingChartObj();
      //--- Получаем текущий график и возвращаемся к нему т.к.
      //--- добавление нового графика переключает фокус на него
      CChartObj *chart=this.GetChart(GetMainChartID());
      if(chart!=NULL)
         chart.SetBringToTopON(true);
      for(int i=0;i<change;i++)
        {
         chart=m_list.At(m_list.Total()-(1+i));
         if(chart==NULL)
            continue;
         this.SendEvent(CHART_OBJ_EVENT_CHART_OPEN);
        }
     }
   //--- Если удалён график в терминале
   else if(change<0)
     {
      //--- Находим лишний объект-чарт в списке-коллекции и удаляем его из списка
      this.FindAndDeleteExcessChartObj();
      for(int i=0;i<-change;i++)
        {
         CChartObj *chart=this.m_list_del.At(this.m_list_del.Total()-(1+i));
         if(chart==NULL)
            continue;
         this.SendEvent(CHART_OBJ_EVENT_CHART_CLOSE);
        }
     }
  }
//+------------------------------------------------------------------+

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

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

//+------------------------------------------------------------------+
//| Возвращает указанный по индексу объект-окно                      |
//| указанного по идентификатору чарта                               |
//+------------------------------------------------------------------+
CChartWnd* CChartObjCollection::GetChartWindow(const long chart_id,const int wnd_num)
  {
   CChartObj *chart=this.GetChart(chart_id);
   if(chart==NULL)
      return NULL;
   return chart.GetWindowByNum(wnd_num);
  }
//+------------------------------------------------------------------+

Здесь: получаем объект-чарт по его идентификатору и возвращаем окно, принадлежащее полученному чарту по указанному номеру окна.
Если любой из объектов не был получен, метод вернёт NULL.

Теперь этот же метод добавим в главный класс библиотеки CEngine в файле\MQL5\Include\DoEasy\Engine.mqh:

//--- Возвращает объект (1) последнего добавленного окна указанного чарта, (2) последнего удалённого окна чарта
   CChartWnd           *ChartGetLastAddedChartWindow(const long chart_id)              { return this.m_charts.GetLastAddedChartWindow(chart_id);}
   CChartWnd           *ChartGetLastDeletedChartWindow(void)                           { return this.m_charts.GetLastDeletedChartWindow();   }
//--- Возвращает указанный по индексу объект-окно указанного по идентификатору чарта
   CChartWnd           *ChartGetChartWindow(const long chart_id,const int wnd_num)     { return this.m_charts.GetChartWindow(chart_id,wnd_num);}

Метод просто возвращает результат вызова метода GetChartWindow() класса-коллекции объектов-чартов, рассмотренный нами выше.

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


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

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

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

В функции советника OnInitDoEasy(), в самом её конце, впишем блок кода, в котором будем устанавливать требуемые для отслеживания свойства окон графиков (полный код функции приводить не буду, так как он достаточно объёмен):

//--- Установка контрольных значений для текущего аккаунта
   CAccount* account=engine.GetAccountCurrent();
   if(account!=NULL)
     {
      //--- Установка контроля увеличения значения прибыли на 10
      account.SetControlledValueINC(ACCOUNT_PROP_PROFIT,10.0);
      //--- Установка контроля увеличения значения средств на 15
      account.SetControlledValueINC(ACCOUNT_PROP_EQUITY,15.0);
      //--- Установка контрольного уровня прибыли на 20
      account.SetControlledValueLEVEL(ACCOUNT_PROP_PROFIT,20.0);
     }
      
//--- Установка контрольных значений для чартов
   //--- Получаем список всех чартов коллекции
   CArrayObj *list_charts=engine.GetListCharts();
   if(list_charts!=NULL && list_charts.Total()>0)
     {
      //--- В цикле по списку устанавливаем нужные значения для отслеживаемых свойств чартов
      //--- По умолчанию всем свойствам установлены значения LONG_MAX, что означает "Не отслеживать данное свойство" 
      //--- Включить или выключить (задать величину меньше LONG_MAX или наоборот - установить значение LONG_MAX) можно в любое время в любом месте программы
      for(int i=0;i<list_charts.Total();i++)
        {
         CChartObj* chart=list_charts.At(i);
         if(chart==NULL)
            continue;
         //--- Установка контрольных значений для окон выбранного чарта
         int total_wnd=chart.WindowsTotal();
         for(int j=0;j<total_wnd;j++)
           {
            CChartWnd *wnd=engine.ChartGetChartWindow(chart.ID(),j);
            if(wnd==NULL)
               continue;
            //--- Установка контроля увеличения высоты окна графика на 20 пикселей
            wnd.SetControlHeightInPixelsInc(20);
            //--- Установка контроля уменьшения высоты окна графика на 20 пикселей
            wnd.SetControlHeightInPixelsDec(20);
            //--- Установка контрольного уровня высоты окна графика в 50 пикселей
            wnd.SetControlledValueLEVEL(CHART_WINDOW_PROP_HEIGHT_IN_PIXELS,50);
           }
        }
     }

//--- Получим конец отсчёта времени инициализации библиотеки и выведем его в журнал
   ulong end=GetTickCount();
   Print(TextByLanguage("Время инициализации библиотеки: ","Library initialization time: "),TimeMSCtoString(end-begin,TIME_MINUTES|TIME_SECONDS));
  }
//+------------------------------------------------------------------+

Здесь мы установили такие параметры, при которых:

  • Если высота окна увеличена более чем на 20 пикселей, то будет сгенерировано соответствующее событие,
  • Если высота окна уменьшена более чем на 20 пикселей, то будет сгенерировано соответствующее событие,
  • Если высота окна стала больше, меньше или равна 50 пикселям, то будет сгенерировано соответствующее событие.

В функцию советника OnDoEasyEvent() впишем обработку всех новых событий библиотеки (приведён только полный блок кода обработки всех событий коллекции-чартов, в том числе и новых):

//--- Обработка событий таймсерий
   else if(idx>SERIES_EVENTS_NO_EVENT && idx<SERIES_EVENTS_NEXT_CODE)
     {
      //--- Событие "Новый бар"
      if(idx==SERIES_EVENTS_NEW_BAR)
        {
         Print(TextByLanguage("Новый бар на ","New Bar on "),sparam," ",TimeframeDescription((ENUM_TIMEFRAMES)dparam),": ",TimeToString(lparam));
        }
     }
     
//--- Обработка автоматических событий чартов
//--- Обработка событий чартов и окон
   if(source==COLLECTION_CHART_WND_ID)
     {
      int pos=StringFind(sparam,"_");
      long chart_id=StringToInteger(StringSubstr(sparam,0,pos));
      int wnd_num=(int)StringToInteger(StringSubstr(sparam,pos+1));
      
      CChartObj *chart=engine.ChartGetChartObj(chart_id); 
      if(chart==NULL)                                                   
         return;
      CSymbol *symbol=engine.GetSymbolObjByName(chart.Symbol());
      if(symbol==NULL)
         return;
      CChartWnd *wnd=chart.GetWindowByNum(wnd_num);
      if(wnd==NULL)
         return;
      //--- Количество знаков после запятой в значении события - если long-событие, то 0, иначе - Digits() символа
      int digits=(idx<CHART_WINDOW_PROP_INTEGER_TOTAL ? 0 : symbol.Digits());
      //--- Текстовое описание события
      string id_descr=(idx<CHART_WINDOW_PROP_INTEGER_TOTAL ? wnd.GetPropertyDescription((ENUM_CHART_WINDOW_PROP_INTEGER)idx) : wnd.GetPropertyDescription((ENUM_CHART_WINDOW_PROP_DOUBLE)idx));
      //--- Текстовое значение величины изменения свойства
      string value=DoubleToString(dparam,digits);

      //--- Проверка причин события и просто вывод в журнал его описания
      if(reason==BASE_EVENT_REASON_INC)
        {
         Print(wnd.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_DEC)
        {
         Print(wnd.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_MORE_THEN)
        {
         Print(wnd.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_LESS_THEN)
        {
         Print(wnd.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_EQUALS)
        {
         Print(wnd.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
     }   
//--- Обработка автоматических событий графиков
   if(source==COLLECTION_CHARTS_ID)
     {
      long chart_id=StringToInteger(sparam);
      
      CChartObj *chart=engine.ChartGetChartObj(chart_id); 
      if(chart==NULL)                                                   
         return;
      Print(DFUN,"chart_id=",chart_id,", chart.Symbol()=",chart.Symbol());
      //--- Количество знаков после запятой в значении события - если long-событие, то 0, иначе - Digits() символа
      int digits=int(idx<CHART_PROP_INTEGER_TOTAL ? 0 : SymbolInfoInteger(chart.Symbol(),SYMBOL_DIGITS));
      //--- Текстовое описание события
      string id_descr=(idx<CHART_PROP_INTEGER_TOTAL ? chart.GetPropertyDescription((ENUM_CHART_PROP_INTEGER)idx) : chart.GetPropertyDescription((ENUM_CHART_PROP_DOUBLE)idx));
      //--- Текстовое значение величины изменения свойства
      string value=DoubleToString(dparam,digits);

      //--- Проверка причин события и просто вывод в журнал его описания
      if(reason==BASE_EVENT_REASON_INC)
        {
         Print(chart.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_DEC)
        {
         Print(chart.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_MORE_THEN)
        {
         Print(chart.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_LESS_THEN)
        {
         Print(chart.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
      if(reason==BASE_EVENT_REASON_EQUALS)
        {
         Print(chart.EventDescription(idx,(ENUM_BASE_EVENT_REASON)reason,source,value,id_descr,digits));
        }
     }   

//--- Обработка неавтоматических событий чартов
   else if(idx>CHART_OBJ_EVENT_NO_EVENT && idx<CHART_OBJ_EVENTS_NEXT_CODE)
     {
      //--- Событие "Открытие нового чарта"
      if(idx==CHART_OBJ_EVENT_CHART_OPEN)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,chart.ID(),chart.Timeframe(),chart.Symbol());
         CChartObj *chart=engine.ChartGetLastOpenedChart();
         if(chart!=NULL)
           {
            string symbol=sparam;
            long chart_id=lparam;
            ENUM_TIMEFRAMES timeframe=(ENUM_TIMEFRAMES)dparam;
            string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id;
            Print(DFUN,CMessage::Text(MSG_CHART_COLLECTION_CHART_OPENED),": ",header);
           }
        }
      //--- Событие "Закрытие чарта"
      if(idx==CHART_OBJ_EVENT_CHART_CLOSE)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,chart.ID(),chart.Timeframe(),chart.Symbol());
         CChartObj *chart=engine.ChartGetLastClosedChart();
         if(chart!=NULL)
           {
            string symbol=sparam;
            long   chart_id=lparam;
            ENUM_TIMEFRAMES timeframe=(ENUM_TIMEFRAMES)dparam;
            string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id;
            Print(DFUN,CMessage::Text(MSG_CHART_COLLECTION_CHART_CLOSED),": ",header);
           }
        }
      //--- Событие "Изменён символ графика"
      if(idx==CHART_OBJ_EVENT_CHART_SYMB_CHANGE)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.Timeframe(),this.m_symbol_prev);
         long chart_id=lparam;
         ENUM_TIMEFRAMES timeframe=(ENUM_TIMEFRAMES)dparam;
         string symbol_prev=sparam;
         CChartObj *chart=engine.ChartGetChartObj(chart_id);
         if(chart!=NULL)
           {
            string header=chart.Symbol()+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id;
            Print(DFUN,CMessage::Text(MSG_CHART_COLLECTION_CHART_SYMB_CHANGED),": ",header,": ",symbol_prev," >>> ",chart.Symbol());
           }
        }
      //--- Событие "Изменён таймфрейм графика"
      if(idx==CHART_OBJ_EVENT_CHART_TF_CHANGE)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.m_timeframe_prev,this.Symbol());
         long chart_id=lparam;
         ENUM_TIMEFRAMES timeframe_prev=(ENUM_TIMEFRAMES)dparam;
         string symbol=sparam;
         CChartObj *chart=engine.ChartGetChartObj(chart_id);
         if(chart!=NULL)
           {
            string header=chart.Symbol()+" "+TimeframeDescription(chart.Timeframe())+", ID "+(string)chart_id;
            Print
              (
               DFUN,CMessage::Text(MSG_CHART_COLLECTION_CHART_TF_CHANGED),": ",header,": ",
               TimeframeDescription(timeframe_prev)," >>> ",TimeframeDescription(chart.Timeframe())
              );
           }
        }
      //--- Событие "Изменён символ и таймфрейм графика"
      if(idx==CHART_OBJ_EVENT_CHART_SYMB_TF_CHANGE)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.m_timeframe_prev,this.m_symbol_prev);
         long chart_id=lparam;
         ENUM_TIMEFRAMES timeframe_prev=(ENUM_TIMEFRAMES)dparam;
         string symbol_prev=sparam;
         CChartObj *chart=engine.ChartGetChartObj(chart_id);
         if(chart!=NULL)
           {
            string header=chart.Symbol()+" "+TimeframeDescription(chart.Timeframe())+", ID "+(string)chart_id;
            Print
              (
               DFUN,CMessage::Text(MSG_CHART_COLLECTION_CHART_SYMB_TF_CHANGED),": ",header,": ",
               symbol_prev," >>> ",chart.Symbol(),", ",TimeframeDescription(timeframe_prev)," >>> ",TimeframeDescription(chart.Timeframe())
              );
           }
        }
        
      //--- Событие "Добавление нового окна на чарт"
      if(idx==CHART_OBJ_EVENT_CHART_WND_ADD)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol());
         ENUM_TIMEFRAMES timeframe=WRONG_VALUE;
         string ind_name="";
         string symbol=sparam;
         long   chart_id=lparam;
         int    win_num=(int)dparam;
         string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id+": ";
         
         CChartObj *chart=engine.ChartGetLastOpenedChart();
         if(chart!=NULL)
           {
            timeframe=chart.Timeframe();
            CChartWnd *wnd=engine.ChartGetLastAddedChartWindow(chart.ID());
            if(wnd!=NULL)
              {
               CWndInd *ind=wnd.GetLastAddedIndicator();
               if(ind!=NULL)
                  ind_name=ind.Name();
              }
           }
         Print(DFUN,header,CMessage::Text(MSG_CHART_OBJ_WINDOW_ADDED)," ",(string)win_num," ",ind_name);
        }
      //--- Событие "Удаление окна с чарта"
      if(idx==CHART_OBJ_EVENT_CHART_WND_DEL)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol());
         CChartWnd *wnd=engine.ChartGetLastDeletedChartWindow();
         ENUM_TIMEFRAMES timeframe=WRONG_VALUE;
         string symbol=sparam;
         long   chart_id=lparam;
         int    win_num=(int)dparam;
         string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id+": ";
         Print(DFUN,header,CMessage::Text(MSG_CHART_OBJ_WINDOW_REMOVED)," ",(string)win_num);
        }
      //--- Событие "Добавление нового индикатора в окно чарта"
      if(idx==CHART_OBJ_EVENT_CHART_WND_IND_ADD)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name());
         ENUM_TIMEFRAMES timeframe=WRONG_VALUE;
         string ind_name=sparam;
         string symbol=NULL;
         long   chart_id=lparam;
         int    win_num=(int)dparam;
         string header=NULL;
         
         CWndInd *ind=engine.ChartGetLastAddedIndicator(chart_id,win_num);
         if(ind!=NULL)
           {
            CChartObj *chart=engine.ChartGetChartObj(chart_id);
            if(chart!=NULL)
              {
               symbol=chart.Symbol();
               timeframe=chart.Timeframe();
               CChartWnd *wnd=chart.GetWindowByNum(win_num);
               if(wnd!=NULL)
                  header=wnd.Header();
              }
           }
         Print(DFUN,symbol," ",TimeframeDescription(timeframe),", ID ",chart_id,", ",header,": ",CMessage::Text(MSG_CHART_OBJ_INDICATOR_ADDED)," ",ind_name);
        }
      //--- Событие "Удаление индикатора из окна чарта"
      if(idx==CHART_OBJ_EVENT_CHART_WND_IND_DEL)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name());
         ENUM_TIMEFRAMES timeframe=WRONG_VALUE;
         string ind_name=sparam;
         string symbol=NULL;
         long   chart_id=lparam;
         int    win_num=(int)dparam;
         string header=NULL;
         
         CWndInd *ind=engine.ChartGetLastDeletedIndicator();
         if(ind!=NULL)
           {
            CChartObj *chart=engine.ChartGetChartObj(chart_id);
            if(chart!=NULL)
              {
               symbol=chart.Symbol();
               timeframe=chart.Timeframe();
               CChartWnd *wnd=chart.GetWindowByNum(win_num);
               if(wnd!=NULL)
                  header=wnd.Header();
              }
           }
         Print(DFUN,symbol," ",TimeframeDescription(timeframe),", ID ",chart_id,", ",header,": ",CMessage::Text(MSG_CHART_OBJ_INDICATOR_REMOVED)," ",ind_name);
        }
      //--- Событие "Изменение параметров индикатора в окне чарта"
      if(idx==CHART_OBJ_EVENT_CHART_WND_IND_CHANGE)
        {
         //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name());
         ENUM_TIMEFRAMES timeframe=WRONG_VALUE;
         string ind_name=sparam;
         string symbol=NULL;
         long   chart_id=lparam;
         int    win_num=(int)dparam;
         string header=NULL;
         
         CWndInd *ind=NULL;
         CWndInd *ind_changed=engine.ChartGetLastChangedIndicator();
         if(ind_changed!=NULL)
           {
            ind=engine.ChartGetIndicator(chart_id,win_num,ind_changed.Index());
            if(ind!=NULL)
              {
               CChartObj *chart=engine.ChartGetChartObj(chart_id);
               if(chart!=NULL)
                 {
                  symbol=chart.Symbol();
                  timeframe=chart.Timeframe();
                  CChartWnd *wnd=chart.GetWindowByNum(win_num);
                  if(wnd!=NULL)
                     header=wnd.Header();
                 }
              }
           }
         Print(DFUN,symbol," ",TimeframeDescription(timeframe),", ID ",chart_id,", ",header,": ",CMessage::Text(MSG_CHART_OBJ_INDICATOR_CHANGED)," ",ind_name," >>> ",ind.Name());
        }
     }
     
//--- Обработка торговых событий

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

Скомпилируем советник и запустим его на графике EURUSD, предварительно установив в настройках использование двух символов EURUSD и GBPUSD, и текущего таймфрейма:

Оба графика должны быть предварительно открыты. На EURUSD запустим советник, а GBPUSD должен иметь одно подокно с любым индикатором-осциллятором, и это подокно мы будем использовать для контроля событийного функционала класса-коллекции чартов.

Проверим работу событий смены таймфрейма графика:

Теперь проверим смену символа графика:

Проверим контроль изменения высоты графиков (изменяться будут два графика — подокно и окно главного графика чарта):


Как видим, здесь отработало несколько критериев: высота окна равна заданному размеру, высота окна больше/меньше заданного размера и высота окон увеличена/уменьшена больше чем на заданное количество пикселей.

Что дальше

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

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

К содержанию

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

Прочие классы в библиотеке DoEasy (Часть 67): Класс объекта-чарта
Прочие классы в библиотеке DoEasy (Часть 68): Класс объекта-окна графика и классы объектов-индикаторов в окне графика
Прочие классы в библиотеке DoEasy (Часть 69): Класс-коллекция объектов-чартов
Прочие классы в библиотеке DoEasy (Часть 70): Расширение функционала и автообновление коллекции объектов-чартов
Прочие классы в библиотеке DoEasy (Часть 71): События коллекции объектов-чартов

Прикрепленные файлы |
MQL5.zip (4016.43 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (6)
Konstantin Seredkin
Konstantin Seredkin | 26 янв. 2022 в 14:05

Артем, дочитал ваши статьи до 34.

В ней вы закончили отложенные запросы, на видео в конце видно что вы открываете ордер и делаете отложенный запрос на установку ТП СЛ, после чего ставиться тп сл но сл удаляется через секунду.

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

Скачал советника с 72 статьи, проверил, та же проблема, первым срабатывает то что нажал на панели последним.

Artyom Trishkin
Artyom Trishkin | 26 янв. 2022 в 14:29
Konstantin Seredkin #:

Артем, дочитал ваши статьи до 34.

В ней вы закончили отложенные запросы, на видео в конце видно что вы открываете ордер и делаете отложенный запрос на установку ТП СЛ, после чего ставиться тп сл но сл удаляется через секунду.

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

Скачал советника с 72 статьи, проверил, та же проблема, первым срабатывает то что нажал на панели последним.

Спасибо. Будет время, нужно будет поглядеть. Скорее всего, навскидку, при срабатывании одного отложенного запроса, и остальные удаляются. Погляжу как время будет. В любом случае, библиотека ещё на стадии доработки, и такие баги имеют право на существование. Главное, чтобы была обратная связь от заинтересованных, и тогда всё поправимо.

Konstantin Seredkin
Konstantin Seredkin | 27 янв. 2022 в 02:42
Artyom Trishkin #:

Спасибо. Будет время, нужно будет поглядеть. Скорее всего, навскидку, при срабатывании одного отложенного запроса, и остальные удаляются. Погляжу как время будет. В любом случае, библиотека ещё на стадии доработки, и такие баги имеют право на существование. Главное, чтобы была обратная связь от заинтересованных, и тогда всё поправимо.

Я заинтересован )) Читать и разбираться еще думаю пару недель только в статьях что бы, хотя бы, образно понимать как все устроено и как этим пользоваться...  и не представляю сколько на практике еще )

Я очень долго ждал когда появятся грамотные статьи и главное полноценная ООП библиотека с работой по московской бирже. Прошлый год вылетел из жизни и не заходил особо на ресурс, а тут зашел и ужаснулся от тонны топового материала.

Спасибо за проделанную работу, честно сказать восхищен от того как могут работать мозги у людей в этом плане

Artyom Trishkin
Artyom Trishkin | 27 янв. 2022 в 07:51
Konstantin Seredkin #:

Я заинтересован )) Читать и разбираться еще думаю пару недель только в статьях что бы, хотя бы, образно понимать как все устроено и как этим пользоваться...  и не представляю сколько на практике еще )

Я очень долго ждал когда появятся грамотные статьи и главное полноценная ООП библиотека с работой по московской бирже. Прошлый год вылетел из жизни и не заходил особо на ресурс, а тут зашел и ужаснулся от тонны топового материала.

Спасибо за проделанную работу, честно сказать восхищен от того как могут работать мозги у людей в этом плане

Спасибо за оценку. На самом деле - это просто рутина.

Насчёт Московской биржи - тут нужно всё тщательно тестировать и выявлять баги. Равно как и на форекс.

Konstantin Seredkin
Konstantin Seredkin | 27 янв. 2022 в 11:57
Artyom Trishkin #:

Спасибо за оценку. На самом деле - это просто рутина.

Насчёт Московской биржи - тут нужно всё тщательно тестировать и выявлять баги. Равно как и на форекс.

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

там может и недочеты какие выявятся.

Главное не бросайте, контент шикарный.

Паттерны с примерами (Часть I): Кратная вершина Паттерны с примерами (Часть I): Кратная вершина
Статья начинает цикл рассмотрения разворотных паттернов в рамках алготрейдинга. Мы начнем мысль, исследуя первое и самое интересное семейство данных паттернов, которые берут начало из паттерна "Двойная вершина" и "Двойное дно".
Советы профессионального программиста (Часть II): Организация хранения и обмена параметров между экспертом, скриптами и внешними программами Советы профессионального программиста (Часть II): Организация хранения и обмена параметров между экспертом, скриптами и внешними программами
Советы профессионального программиста о методах, приемах и вспомогательных инструментах, облегчающих программирование. Речь пойдет о параметрах, которые можно восстанавливать после перезапуска (закрытия) терминала. Все примеры — реально работающие куски кода из моего проекта Cayman.
Графика в библиотеке DoEasy (Часть 73): Объект-форма графического элемента Графика в библиотеке DoEasy (Часть 73): Объект-форма графического элемента
В статье начинаем новый большой раздел библиотеки по работе с графикой. Сегодня создадим объект состояний мышки, базовый объект всех графических элементов и класс объекта-формы графических элементов библиотеки.
Прочие классы в библиотеке DoEasy (Часть 71): События коллекции объектов-чартов Прочие классы в библиотеке DoEasy (Часть 71): События коллекции объектов-чартов
В статье создадим функционал отслеживания некоторых событий объектов-чартов — добавление и удаление графиков символов, добавление и удаление подокон на график, а также добавление/удаление/изменение индикаторов в окнах чартов.