Прочие классы в библиотеке DoEasy (Часть 72): Отслеживание и фиксация параметров объектов-чартов в коллекции
Содержание
Концепция
Эта статья будет последней в описании классов объектов-чартов и их коллекции. У нас уже хранятся в коллекции чартов все открытые графики в клиентском терминале, их подокна и индикаторы в них. Если свойства какого-либо графика меняются, то некоторые события мы уже обрабатываем и отсылаем пользовательское событие о произошедшем изменении чарта, его окна или индикатора в окне чарта на график управляющей программы. Но мы можем изменить свойства объекта-чарта или его окна, и нам необходимо новые значения изменённых свойств вписать в параметры изменённого объекта.
К счастью, у нас уже давно создан объект, наделяющий всех своих наследников событийным функционалом (расширенный базовый объект всех объектов библиотеки). И наши классы объектов-чартов и окон графиков уже являются его наследниками. Нам необходимо будет лишь добавить стандартную для этого объекта обработку изменений свойств своего объекта-наследника, и этот класс автоматически будет обновлять все свойства своего наследника и при изменении указанных свойств будет создавать список событий, произошедших с его объектом-наследником.
Для того чтобы создавались и отправлялись на график управляющей программы события, происходящие в объекте, для него необходимо будет указать все отслеживаемые свойства, которые мы хотим контролировать в своей программе. Расширенный базовый объект позволяет задать величину изменения указанного свойства или превышение указанного порогового значения для отслеживаемого свойства. Либо комбинацию изменений отслеживаемых свойств.
Любые внесённые изменения в свойства объекта будут автоматически записываться в его параметры, и если установлены разрешения на отслеживание каких-либо свойств объекта, то эти свойства будут "сигналить" о зафиксированных изменениях, которые мы хотим отслеживать.
Практически все объекты библиотеки имеют одинаковую структуру своего построения — набор свойств (целочисленных, вещественных и строковых), критерии сортировки объектов, соответствующие исключительно свойствам каждого отдельного объекта, и некоторые методы для поиска и сортировки таких объектов в списках, где они хранятся, методы описания свойств объекта и класс, позволяющий осуществлять поиск в списке объектов по указанному свойству и возвращающий индекс объекта в списке с максимальным или минимальным значением требуемого свойства.
Все эти длинные описания свойств объектов, прилагающиеся к самому объекту и неотрывно связанные с ним, немного усложняют создание самого объекта, но многократно упрощают дальнейшую с ним работу. Вот и с классом объекта-окна графика получилось так, что мы его сделали изначально неполноценным (как все основные объекты библиотеки), а упростили задачу — для того чтобы не писать все его свойства отдельно, а разместить их в свойствах объекта-чарта, к которому это окно принадлежит.
Теперь же, при создании автоматического обновления свойств объектов-чартов и их подокон, мы столкнёмся с большим усложнением при сохранении предыдущего состояния свойств объекта-окна графика при помощи методов его родительского класса. Поэтому решено было объект-окно графика сделать полноценным объектом библиотеки, что сильно упростит создание его автоматического обновления с поиском отслеживаемых событий (всё это уже давно нами сделано при создании родительского класса — расширенного объекта всех объектов библиотеки).
Доработка классов библиотеки
В файл \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): События коллекции объектов-чартов
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Артем, дочитал ваши статьи до 34.
В ней вы закончили отложенные запросы, на видео в конце видно что вы открываете ордер и делаете отложенный запрос на установку ТП СЛ, после чего ставиться тп сл но сл удаляется через секунду.
Погонял потыкал панель, не удается одновременно использовать отложенный запрос как в пунктах так и по времени, при срабатывании или стоп удаляется или тейк.
Скачал советника с 72 статьи, проверил, та же проблема, первым срабатывает то что нажал на панели последним.
Артем, дочитал ваши статьи до 34.
В ней вы закончили отложенные запросы, на видео в конце видно что вы открываете ордер и делаете отложенный запрос на установку ТП СЛ, после чего ставиться тп сл но сл удаляется через секунду.
Погонял потыкал панель, не удается одновременно использовать отложенный запрос как в пунктах так и по времени, при срабатывании или стоп удаляется или тейк.
Скачал советника с 72 статьи, проверил, та же проблема, первым срабатывает то что нажал на панели последним.
Спасибо. Будет время, нужно будет поглядеть. Скорее всего, навскидку, при срабатывании одного отложенного запроса, и остальные удаляются. Погляжу как время будет. В любом случае, библиотека ещё на стадии доработки, и такие баги имеют право на существование. Главное, чтобы была обратная связь от заинтересованных, и тогда всё поправимо.
Спасибо. Будет время, нужно будет поглядеть. Скорее всего, навскидку, при срабатывании одного отложенного запроса, и остальные удаляются. Погляжу как время будет. В любом случае, библиотека ещё на стадии доработки, и такие баги имеют право на существование. Главное, чтобы была обратная связь от заинтересованных, и тогда всё поправимо.
Я заинтересован )) Читать и разбираться еще думаю пару недель только в статьях что бы, хотя бы, образно понимать как все устроено и как этим пользоваться... и не представляю сколько на практике еще )
Я очень долго ждал когда появятся грамотные статьи и главное полноценная ООП библиотека с работой по московской бирже. Прошлый год вылетел из жизни и не заходил особо на ресурс, а тут зашел и ужаснулся от тонны топового материала.
Спасибо за проделанную работу, честно сказать восхищен от того как могут работать мозги у людей в этом плане
Я заинтересован )) Читать и разбираться еще думаю пару недель только в статьях что бы, хотя бы, образно понимать как все устроено и как этим пользоваться... и не представляю сколько на практике еще )
Я очень долго ждал когда появятся грамотные статьи и главное полноценная ООП библиотека с работой по московской бирже. Прошлый год вылетел из жизни и не заходил особо на ресурс, а тут зашел и ужаснулся от тонны топового материала.
Спасибо за проделанную работу, честно сказать восхищен от того как могут работать мозги у людей в этом плане
Спасибо за оценку. На самом деле - это просто рутина.
Насчёт Московской биржи - тут нужно всё тщательно тестировать и выявлять баги. Равно как и на форекс.
Спасибо за оценку. На самом деле - это просто рутина.
Насчёт Московской биржи - тут нужно всё тщательно тестировать и выявлять баги. Равно как и на форекс.
Дочитаю до этого места, посмотрю что тут сделано уже, у меня просто все стратегии стаканные, мне нужны его объемы, скопления и т.д. если библиотека позволяет полноценно работать со стаканом, его индексами - ценами - объемами, то пересоберу робота своего на вашей библиотеке и по тестирую ее уже.
там может и недочеты какие выявятся.
Главное не бросайте, контент шикарный.