preview
DoEasy. Сервисные функции (Часть 2): Паттерн "Внутренний бар"

DoEasy. Сервисные функции (Часть 2): Паттерн "Внутренний бар"

MetaTrader 5Примеры | 26 марта 2024, 17:05
608 4
Artyom Trishkin
Artyom Trishkin

Содержание


Концепция

Продолжаем разрабатывать паттерны, образуемые на данных таймсерий. В первой статье цикла по паттернам мы создали инструментарий для поиска и отображения различных паттернов, и создали функционал для поиска паттерна "Pin Bar" из формаций Price Action. В данной статье продолжим разрабатывать и дорабатывать функционал для поиска различных паттернов на графиках цены и создадим поиск паттернов Price Action "Внутренний Бар" (Inside Bar).

Если паттерн "Пин Бар" — это однобаровая формация и ищется по пропорциям одного бара, то "Внутренний Бар" — это двухбаровая формация, состоящая из двух баров — материнский бар (бар слева) и определяющий бар (бар справа):


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

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


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

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

В файле \MQL5\Include\DoEasy\Defines.mqh добавим в список типов объектов библиотеки объект с типом "рисунок":

//+------------------------------------------------------------------+
//| Список типов объектов библиотеки                                 |
//+------------------------------------------------------------------+
enum ENUM_OBJECT_DE_TYPE
  {
//--- Графика
   OBJECT_DE_TYPE_GBASE =  COLLECTION_ID_LIST_END+1,              // Тип объекта "Базовый объект всех графических объектов библиотеки"
   OBJECT_DE_TYPE_GELEMENT,                                       // Тип объекта "Графический элемент"
   OBJECT_DE_TYPE_GFORM,                                          // Тип объекта "Форма"
   OBJECT_DE_TYPE_GFORM_CONTROL,                                  // Тип объекта "Форма управления опорными точками графического объекта"
   OBJECT_DE_TYPE_GSHADOW,                                        // Тип объекта "Тень"
   OBJECT_DE_TYPE_GGLARE,                                         // Тип объекта "Блик"
   OBJECT_DE_TYPE_GBITMAP,                                        // Тип объекта "Рисунок"
   //--- WinForms
   OBJECT_DE_TYPE_GWF_BASE,                                       // Тип объекта "WinForms Base" (базовый абстрактный WinForms-объект)
   OBJECT_DE_TYPE_GWF_CONTAINER,                                  // Тип объекта "WinForms контейнер"
   OBJECT_DE_TYPE_GWF_COMMON,                                     // Тип объекта "WinForms станартный элемент управления"
   OBJECT_DE_TYPE_GWF_HELPER,                                     // Тип объекта "WinForms вспомогательный элемент управления"
//--- Анимация
//--- ...
//---...
 

Объекты с типом OBJ_BITMAP позволяют прикрепить к нему bmp-ресурс и рисовать на нём различные примитивы. Привязан такой объект ко времени бара и цене. Будем их использовать для обрисовки баров паттернов рамкой.

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

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

В целочисленные свойства объекта-бара добавим ещё одно свойство и увеличим количество целочисленных свойств объекта-бара с 13 до 14:

//+------------------------------------------------------------------+
//| Целочисленные свойства бара                                      |
//+------------------------------------------------------------------+
enum ENUM_BAR_PROP_INTEGER
  {
   BAR_PROP_TIME = 0,                                       // Время начала периода бара
   BAR_PROP_TYPE,                                           // Тип бара (из перечисления ENUM_BAR_BODY_TYPE)
   BAR_PROP_PERIOD,                                         // Период бара (таймфрейм)
   BAR_PROP_SPREAD,                                         // Спред бара
   BAR_PROP_VOLUME_TICK,                                    // Тиковый объём бара
   BAR_PROP_VOLUME_REAL,                                    // Биржевой объём бара
   BAR_PROP_TIME_DAY_OF_YEAR,                               // Порядковый номер дня бара в году
   BAR_PROP_TIME_YEAR,                                      // Год, к которому относится бар
   BAR_PROP_TIME_MONTH,                                     // Месяц, к которому относится бар
   BAR_PROP_TIME_DAY_OF_WEEK,                               // День недели бара
   BAR_PROP_TIME_DAY,                                       // День месяца бара (число)
   BAR_PROP_TIME_HOUR,                                      // Час бара
   BAR_PROP_TIME_MINUTE,                                    // Минута бара
   BAR_PROP_PATTERNS_TYPE,                                  // Типы паттернов на баре (флаги паттернов из перечисления ENUM_PATTERN_TYPE)
  }; 
#define BAR_PROP_INTEGER_TOTAL (14)                         // Общее количество целочисленных свойств бара

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

В список возможных критериев сортировки объектов-баров впишем сортировку по типу паттернов на баре:

//+------------------------------------------------------------------+
//| Возможные критерии сортировки баров                              |
//+------------------------------------------------------------------+
#define FIRST_BAR_DBL_PROP          (BAR_PROP_INTEGER_TOTAL-BAR_PROP_INTEGER_SKIP)
#define FIRST_BAR_STR_PROP          (BAR_PROP_INTEGER_TOTAL-BAR_PROP_INTEGER_SKIP+BAR_PROP_DOUBLE_TOTAL-BAR_PROP_DOUBLE_SKIP)
enum ENUM_SORT_BAR_MODE
  {
//--- Сортировка по целочисленным свойствам
   SORT_BY_BAR_TIME = 0,                                    // Сортировать по времени начала периода бара
   SORT_BY_BAR_TYPE,                                        // Сортировать по типу бара (из перечисления ENUM_BAR_BODY_TYPE)
   SORT_BY_BAR_PERIOD,                                      // Сортировать по периоду бара (таймфрейму)
   SORT_BY_BAR_SPREAD,                                      // Сортировать по спреду бара
   SORT_BY_BAR_VOLUME_TICK,                                 // Сортировать по тиковому объёму бара
   SORT_BY_BAR_VOLUME_REAL,                                 // Сортировать по биржевому объёму бара
   SORT_BY_BAR_TIME_DAY_OF_YEAR,                            // Сортировать по порядковому номеру дня бара в году
   SORT_BY_BAR_TIME_YEAR,                                   // Сортировать по году, к которому относится бар
   SORT_BY_BAR_TIME_MONTH,                                  // Сортировать по месяцу, к которому относится бар
   SORT_BY_BAR_TIME_DAY_OF_WEEK,                            // Сортировать по дню недели бара
   SORT_BY_BAR_TIME_DAY,                                    // Сортировать по дню бара
   SORT_BY_BAR_TIME_HOUR,                                   // Сортировать по часу бара
   SORT_BY_BAR_TIME_MINUTE,                                 // Сортировать по минуте бара
   SORT_BY_BAR_PATTERN_TYPE,                                // Сортировать по типам паттернов на баре (флаги паттернов из перечисления ENUM_PATTERN_TYPE)
//--- Сортировка по вещественным свойствам
   SORT_BY_BAR_OPEN = FIRST_BAR_DBL_PROP,                   // Сортировать по цене открытия бара
   SORT_BY_BAR_HIGH,                                        // Сортировать по наивысшей цене за период бара
   SORT_BY_BAR_LOW,                                         // Сортировать по наименьшей цене за период бара
   SORT_BY_BAR_CLOSE,                                       // Сортировать по цене закрытия бара
   SORT_BY_BAR_CANDLE_SIZE,                                 // Сортировать по размеру свечи
   SORT_BY_BAR_CANDLE_SIZE_BODY,                            // Сортировать по размеру тела свечи
   SORT_BY_BAR_CANDLE_BODY_TOP,                             // Сортировать по верху тела свечи
   SORT_BY_BAR_CANDLE_BODY_BOTTOM,                          // Сортировать по низу тела свечи
   SORT_BY_BAR_CANDLE_SIZE_SHADOW_UP,                       // Сортировать по размеру верхней тени свечи
   SORT_BY_BAR_CANDLE_SIZE_SHADOW_DOWN,                     // Сортировать по размеру нижней тени свечи
//--- Сортировка по строковым свойствам
   SORT_BY_BAR_SYMBOL = FIRST_BAR_STR_PROP,                 // Сортировать по символу бара
  };


Ранее в перечислении типов паттернов для паттерна "Харами" было указано значение 0. Это не совсем правильно. Ведь лучше, если ноль будет указывать на отсутствие паттернов на баре.
Исправим ситуацию и добавим макроподстановку, указывающую общее количество паттернов, доступных для поиска в библиотеке:

//+------------------------------------------------------------------+
//| Тип паттерна                                                     |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_TYPE
  {
//--- Свечные формации
   PATTERN_TYPE_NONE                =  0x0,                 // Отсутствует
   PATTERN_TYPE_HARAMI              =  0x1,                 // Харами
   PATTERN_TYPE_HARAMI_CROSS        =  0x2,                 // Крест харами
   PATTERN_TYPE_TWEEZER             =  0x4,                 // Пинцет
   PATTERN_TYPE_PIERCING_LINE       =  0x8,                 // Просвет в облаках
   PATTERN_TYPE_DARK_CLOUD_COVER    =  0x10,                // Завеса из темных облаков
   PATTERN_TYPE_THREE_WHITE_SOLDIERS=  0x20,                // Три белых солдата
   PATTERN_TYPE_THREE_BLACK_CROWS   =  0x40,                // Три черные вороны
   PATTERN_TYPE_SHOOTING_STAR       =  0x80,                // Падающая звезда
   PATTERN_TYPE_HAMMER              =  0x100,               // Молот
   PATTERN_TYPE_INVERTED_HAMMER     =  0x200,               // Перевёрнутый молот
   PATTERN_TYPE_HANGING_MAN         =  0x400,               // Повешенный
   PATTERN_TYPE_DOJI                =  0x800,               // Доджи
   PATTERN_TYPE_DRAGONFLY_DOJI      =  0x1000,              // Доджи стрекоза
   PATTERN_TYPE_GRAVESTONE_DOJI     =  0x2000,              // Доджи надгробие
   PATTERN_TYPE_MORNING_STAR        =  0x4000,              // Утренняя звезда
   PATTERN_TYPE_MORNING_DOJI_STAR   =  0x8000,              // Утренняя доджи-звезда
   PATTERN_TYPE_EVENING_STAR        =  0x10000,             // Вечерняя звезда
   PATTERN_TYPE_EVENING_DOJI_STAR   =  0x20000,             // Вечерняя доджи-звезда
   PATTERN_TYPE_THREE_STARS         =  0x40000,             // Три звезды
   PATTERN_TYPE_ABANDONED_BABY      =  0x80000,             // Брошенное дитя
//--- Price Action
   PATTERN_TYPE_PIVOT_POINT_REVERSAL=  0x100000,            // Price Action разворотный паттерн
   PATTERN_TYPE_OUTSIDE_BAR         =  0x200000,            // Price Action Внешний бар (Поглощение)
   PATTERN_TYPE_INSIDE_BAR          =  0x400000,            // Price Action Внутренний бар
   PATTERN_TYPE_PIN_BAR             =  0x800000,            // Price Action Пин бар
   PATTERN_TYPE_RAILS               =  0x1000000,           // Price Action Рельсы
  };
#define PATTERNS_TOTAL              (26)                    // Общее количество паттернов (вместе с отсутствующим)


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

//+------------------------------------------------------------------+
//| Целочисленные свойства паттерна                                  |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_PROP_INTEGER
  {
   PATTERN_PROP_CODE = 0,                                   // Уникальный код паттерна (время + тип + статус + направление + таймфрейм + символ)
   PATTERN_PROP_CTRL_OBJ_ID,                                // Идентификатор объекта управления паттерном
   PATTERN_PROP_ID,                                         // Идентификатор паттерна
   PATTERN_PROP_TIME,                                       // Время определяющего бара паттерна
   PATTERN_PROP_MOTHERBAR_TIME,                             // Время материнского бара паттерна
   PATTERN_PROP_STATUS,                                     // Статус паттерна (из перечисления ENUM_PATTERN_STATUS)
   PATTERN_PROP_TYPE,                                       // Тип паттерна (из перечисления ENUM_PATTERN_TYPE)
   PATTERN_PROP_DIRECTION,                                  // Тип паттерна по направлению (из перечисления ENUM_PATTERN_TYPE_DIRECTION)
   PATTERN_PROP_PERIOD,                                     // Период паттерна (таймфрейм)
   PATTERN_PROP_CANDLES,                                    // Количество свечей, составляющих паттерн
  }; 
#define PATTERN_PROP_INTEGER_TOTAL (10)                     // Общее количество целочисленных свойств паттерна


В список возможных критериев сортировки паттернов добавим сортировку по новому свойству:

//+------------------------------------------------------------------+
//| Возможные критерии сортировки паттернов                          |
//+------------------------------------------------------------------+
#define FIRST_PATTERN_DBL_PROP      (PATTERN_PROP_INTEGER_TOTAL-PATTERN_PROP_INTEGER_SKIP)
#define FIRST_PATTERN_STR_PROP      (PATTERN_PROP_INTEGER_TOTAL-PATTERN_PROP_INTEGER_SKIP+PATTERN_PROP_DOUBLE_TOTAL-PATTERN_PROP_DOUBLE_SKIP)
enum ENUM_SORT_PATTERN_MODE
  {
//--- Сортировка по целочисленным свойствам
   SORT_BY_PATTERN_CODE = 0,                                // Сортировать по уникальному коду паттерна (время + тип + статус + направление + таймфрейм)
   SORT_BY_PATTERN_CTRL_OBJ_ID,                             // Сортировать по идентификатору объекта управления паттерном
   SORT_BY_PATTERN_ID,                                      // Сортировать по идентификатору паттерна
   SORT_BY_PATTERN_TIME,                                    // Сортировать по времени определяющего бара паттерна
   SORT_BY_PATTERN_MOTHERBAR_TIME,                          // Сортировать по времени материнского бара паттерна
   SORT_BY_PATTERN_STATUS,                                  // Сортировать по статусу паттерна (из перечисления ENUM_PATTERN_STATUS)
   SORT_BY_PATTERN_TYPE,                                    // Сортировать по типу паттерна (из перечисления ENUM_PATTERN_TYPE)
   SORT_BY_PATTERN_DIRECTION,                               // Сортировать по типу паттерна по направлению (из перечисления ENUM_PATTERN_TYPE_DIRECTION)
   SORT_BY_PATTERN_PERIOD,                                  // Сортировать по периоду паттерна (таймфрейм)
   SORT_BY_PATTERN_CANDLES,                                 // Сортировать по количеству свечей, составляющих паттерн
   
//--- Сортировка по вещественным свойствам
   SORT_BY_PATTERN_BAR_PRICE_OPEN = FIRST_PATTERN_DBL_PROP, // Сортировать по цене Open определяющего бара паттерна
   SORT_BY_PATTERN_BAR_PRICE_HIGH,                          // Сортировать по цене High определяющего бара паттерна
   SORT_BY_PATTERN_BAR_PRICE_LOW,                           // Сортировать по цене Low определяющего бара паттерна
   SORT_BY_PATTERN_BAR_PRICE_CLOSE,                         // Сортировать по цене Close определяющего бара паттерна
   SORT_BY_PATTERN_RATIO_BODY_TO_CANDLE_SIZE,               // Сортировать по отношению тела свечи к полному размеру свечи в %
   SORT_BY_PATTERN_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,       // Сортировать по отношению размера верхней тени к размеру свечи в %
   SORT_BY_PATTERN_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,       // Сортировать по отношению размера нижней тени к размеру свечи в %
   SORT_BY_PATTERN_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,           // Сортировать по установленному критерию отношения тела свечи к полному размеру свечи в %
   SORT_BY_PATTERN_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,  // Сортировать по установленному критерию отношения размера наибольшей тени к размеру свечи в %
   SORT_BY_PATTERN_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION, // Сортировать по установленному критерию отношения размера наименьшей тени к размеру свечи в %
   
//--- Сортировка по строковым свойствам
   SORT_BY_PATTERN_SYMBOL = FIRST_BAR_STR_PROP,             // Сортировать по символу паттерна
   SORT_BY_PATTERN_NAME,                                    // Сортировать по наименованию паттерна
  };


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

//+------------------------------------------------------------------+
//| Список типов графических элементов                               |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_STANDARD,                       // Стандартный графический объект
   GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED,              // Расширенный стандартный графический объект
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                     // Объект тени
   GRAPH_ELEMENT_TYPE_ELEMENT,                        // Элемент
   GRAPH_ELEMENT_TYPE_BITMAP,                         // Рисунок
   GRAPH_ELEMENT_TYPE_FORM,                           // Форма
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Окно
   //--- WinForms
   GRAPH_ELEMENT_TYPE_WF_UNDERLAY,                    // Подложка объекта-панели
   GRAPH_ELEMENT_TYPE_WF_BASE,                        // Windows Forms Base
   //--- Ниже нужно вписывать типы объектов "контейнер"
   GRAPH_ELEMENT_TYPE_WF_CONTAINER,                   // Windows Forms базовый объект-контейнер
   GRAPH_ELEMENT_TYPE_WF_PANEL,                       // Windows Forms Panel
   GRAPH_ELEMENT_TYPE_WF_GROUPBOX,                    // Windows Forms GroupBox
   GRAPH_ELEMENT_TYPE_WF_TAB_CONTROL,                 // Windows Forms TabControl
   GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER,             // Windows Forms SplitContainer
   //--- Ниже нужно вписывать типы объектов "стандартный элемент управления"
   GRAPH_ELEMENT_TYPE_WF_COMMON_BASE,                 // Windows Forms базовый стандартный элемент управления
   GRAPH_ELEMENT_TYPE_WF_LABEL,                       // Windows Forms Label
   GRAPH_ELEMENT_TYPE_WF_BUTTON,                      // Windows Forms Button
   GRAPH_ELEMENT_TYPE_WF_CHECKBOX,                    // Windows Forms CheckBox
   GRAPH_ELEMENT_TYPE_WF_RADIOBUTTON,                 // Windows Forms RadioButton
   GRAPH_ELEMENT_TYPE_WF_ELEMENTS_LIST_BOX,           // Базовый объект-список Windows Forms элементов
   GRAPH_ELEMENT_TYPE_WF_LIST_BOX,                    // Windows Forms ListBox
   GRAPH_ELEMENT_TYPE_WF_CHECKED_LIST_BOX,            // Windows Forms CheckedListBox
   GRAPH_ELEMENT_TYPE_WF_BUTTON_LIST_BOX,             // Windows Forms ButtonListBox
   GRAPH_ELEMENT_TYPE_WF_TOOLTIP,                     // Windows Forms ToolTip
   GRAPH_ELEMENT_TYPE_WF_PROGRESS_BAR,                // Windows Forms ProgressBar
   //--- Вспомогательные элементы WinForms-объектов
   GRAPH_ELEMENT_TYPE_WF_LIST_BOX_ITEM,               // Windows Forms ListBoxItem
   GRAPH_ELEMENT_TYPE_WF_TAB_HEADER,                  // Windows Forms TabHeader
   GRAPH_ELEMENT_TYPE_WF_TAB_FIELD,                   // Windows Forms TabField
   GRAPH_ELEMENT_TYPE_WF_SPLIT_CONTAINER_PANEL,       // Windows Forms SplitContainerPanel
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON,                // Windows Forms ArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_UP,             // Windows Forms UpArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_DOWN,           // Windows Forms DownArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_LEFT,           // Windows Forms LeftArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTON_RIGHT,          // Windows Forms RightArrowButton
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_UD_BOX,        // Windows Forms UpDownArrowButtonsBox
   GRAPH_ELEMENT_TYPE_WF_ARROW_BUTTONS_LR_BOX,        // Windows Forms LeftRightArrowButtonsBox
   GRAPH_ELEMENT_TYPE_WF_SPLITTER,                    // Windows Forms Splitter
   GRAPH_ELEMENT_TYPE_WF_HINT_BASE,                   // Windows Forms HintBase
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_LEFT,              // Windows Forms HintMoveLeft
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_RIGHT,             // Windows Forms HintMoveRight
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_UP,                // Windows Forms HintMoveUp
   GRAPH_ELEMENT_TYPE_WF_HINT_MOVE_DOWN,              // Windows Forms HintMoveDown
   GRAPH_ELEMENT_TYPE_WF_BAR_PROGRESS_BAR,            // Windows Forms BarProgressBar
   GRAPH_ELEMENT_TYPE_WF_GLARE_OBJ,                   // Объект блика
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_THUMB,            // Windows Forms ScrollBarThumb
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR,                  // Windows Forms ScrollBar
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_HORISONTAL,       // Windows Forms ScrollBarHorisontal
   GRAPH_ELEMENT_TYPE_WF_SCROLL_BAR_VERTICAL,         // Windows Forms ScrollBarVertical
  };
Это новый для библиотеки тип графических объектов, привязываемый к координатам цена/время, и позволяющий рисовать на нём так же, как на элементах GUI библиотеки. По этой причине он и был добавлен в этот список — его возможно будем использовать и для иных нужд библиотеки, кроме обрисовки баров паттернов на графике цены.


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

//+------------------------------------------------------------------+
//| Список индексов текстовых сообщений библиотеки                   |
//+------------------------------------------------------------------+
enum ENUM_MESSAGES_LIB
  {
   MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST,      // Начало списка параметров
   MSG_LIB_PARAMS_LIST_END,                           // Конец списка параметров
   MSG_LIB_PROP_NOT_SUPPORTED,                        // Свойство не поддерживается
   MSG_LIB_PROP_NOT_SUPPORTED_MQL4,                   // Свойство не поддерживается в MQL4
   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155,          // Свойство не поддерживается в MetaTrader5 версии ниже 2155
   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3245,          // Свойство не поддерживается в MetaTrader5 версии ниже 3245
   MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260,          // Свойство не поддерживается в MetaTrader5 версии ниже 3260
   MSG_LIB_PROP_NOT_SUPPORTED_POSITION,               // Свойство не поддерживается у позиции
   MSG_LIB_PROP_NOT_SUPPORTED_PENDING,                // Свойство не поддерживается у отложенного ордера
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET,                 // Свойство не поддерживается у маркет-ордера
   MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST,            // Свойство не поддерживается у исторического маркет-ордера
   MSG_LIB_PROP_NOT_SET,                              // Значение не задано
   MSG_LIB_PROP_EMPTY,                                // Отсутствует
   MSG_LIB_PROP_NOT_FOUND,                            // Не найдено
   MSG_LIB_PROP_AUTO,                                 // Формируется терминалом
   MSG_LIB_PROP_AS_IN_ORDER,                          // В соответствии с режимом истечения ордера

...

   MSG_LIB_TEXT_BAR_RATIO_BODY_TO_CANDLE_SIZE,        // Отношение тела свечи к полному размеру свечи
   MSG_LIB_TEXT_BAR_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,// Отношение размера верхней тени к размеру свечи
   MSG_LIB_TEXT_BAR_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,// Отношение размера нижней тени к размеру свечи
   MSG_LIB_TEXT_BAR_PATTERNS_TYPE,                    // Типы паттернов на баре
  
//--- CTimeSeries

...

//--- CPattern
   MSG_LIB_TEXT_PATTERN_CODE,                         // Код
   MSG_LIB_TEXT_PATTERN_TIME,                         // Время определяющего бара
   MSG_LIB_TEXT_PATTERN_MOTHERBAR_TIME,               // Время "материнского" бара
   MSG_LIB_TEXT_PATTERN_ID,                           // Идентификатор паттерна
   MSG_LIB_TEXT_PATTERN_CTRL_OBJ_ID,                  // Идентификатор объекта управления паттерном

...

   MSG_GRAPH_ELEMENT_TYPE_STANDARD_EXTENDED,          // Расширенный стандартный графический объект
   MSG_GRAPH_ELEMENT_TYPE_ELEMENT,                    // Элемент
   MSG_GRAPH_ELEMENT_TYPE_BITMAP,                     // Рисунок
   MSG_GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                 // Объект тени
   MSG_GRAPH_ELEMENT_TYPE_FORM,                       // Форма

...

//--- Строковые свойства графических элементов
   MSG_CANV_ELEMENT_PROP_NAME_OBJ,                    // Имя объекта-графического элемента
   MSG_CANV_ELEMENT_PROP_NAME_RES,                    // Имя графического ресурса
   MSG_CANV_ELEMENT_PROP_TEXT,                        // Текст графического элемента
   MSG_CANV_ELEMENT_PROP_DESCRIPTION,                 // Описание графического элемента
   MSG_CANV_ELEMENT_PROP_TOOLTIP_TITLE,               // Заголовок подсказки элемента
   MSG_CANV_ELEMENT_PROP_TOOLTIP_TEXT,                // Текст подсказки элемента
   
//--- CGCnvBitmap
   MSG_ERR_FAILED_SET_BITMAP_OBJ_TIME,                // Не удалось установить значение времени Bitmap-объекту
   MSG_ERR_FAILED_SET_BITMAP_OBJ_PRICE,               // Не удалось установить значение цены Bitmap-объекту
  };

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

string messages_library[][TOTAL_LANG]=
  {
   {"Начало списка параметров","The beginning of the parameter list"},
   {"Конец списка параметров","End of the parameter list"},
   {"Свойство не поддерживается","Property is not support"},
   {"Свойство не поддерживается в MQL4","Property is not supported in MQL4"},
   {"Свойство не поддерживается в MetaTrader5 версии ниже 2155","The property is not supported in MetaTrader5, build lower than 2155"},
   {"Свойство не поддерживается в MetaTrader5 версии ниже 3245","The property is not supported in MetaTrader5, build lower than 3245"},
   {"Свойство не поддерживается в MetaTrader5 версии ниже 3260","The property is not supported in MetaTrader5, build lower than 3260"},
   {"Свойство не поддерживается у позиции","Property not supported for position"},
   {"Свойство не поддерживается у отложенного ордера","The property is not supported for a pending order"},
   {"Свойство не поддерживается у маркет-ордера","The property is not supported for a market-order"},
   {"Свойство не поддерживается у исторического маркет-ордера","The property is not supported for a history market-order"},
   {"Значение не задано","Value not set"},
   {"Отсутствует","Not set"},
   {"Не найдено","Not found"},
   {"Формируется терминалом","Formed by the terminal"},
   {"В соответствии с режимом истечения ордера","In accordance with the order expiration mode"},

...

   {"Отношение тела свечи к полному размеру свечи","Ratio of candle body to full candle size"},
   {"Отношение размера верхней тени к размеру свечи","Ratio of the upper shadow size to the candle size"},
   {"Отношение размера нижней тени к размеру свечи","Ratio of the lower shadow size to the candle size"},
   {"Типы паттернов на баре","Types of patterns on the bar"},
   
//--- CTimeSeries

...

//--- CPattern
   {"Код","Code"},
   {"Время определяющего бара","Time of the defining bar"},
   {"Время \"материнского\" бара","Time open of the mother bar"},
   {"Идентификатор паттерна","Pattern ID"},
   {"Идентификатор объекта управления паттерном","Pattern Control object ID"},

...

   {"Расширенный стандартный графический объект","Extended standard graphic object"},
   {"Элемент","Element"},
   {"Рисунок","Bitmap"},
   {"Объект тени","Shadow object"},
   {"Форма","Form"},

...

//--- Строковые свойства графических элементов
   {"Имя объекта-графического элемента","The name of the graphic element object"},
   {"Имя графического ресурса","Image resource name"},
   {"Текст графического элемента","Text of the graphic element"},
   {"Описание графического элемента","Description of the graphic element"},
   {"Заголовок подсказки элемента","Element tooltip header"},
   {"Текст подсказки элемента","Element tooltip title"},
   
//--- CGCnvBitmap
   {"Не удалось установить значение времени Bitmap-объекту","Failed to set time value to Bitmap object"},
   {"Не удалось установить значение цены Bitmap-объекту","Failed to set price value to Bitmap object"},
  };


Часто приходится проверять корректность переданных в функции и методы значений символа и периода графика. Чтобы не писать в таких местах один и тот же повторяющийся код, в файле \MQL5\Include\DoEasy\Services\DELib.mqh напишем функции, возвращающие корректные наименование символа и значение периода графика:

//+------------------------------------------------------------------+
//| Сервисные функции                                                |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Корректирует и возвращает наименование символа                   |
//+------------------------------------------------------------------+
string CorrectSymbol(const string symbol) 
  {
   return(symbol==NULL || symbol=="" ? ::Symbol() : symbol);
  }
//+------------------------------------------------------------------+
//| Корректирует и возвращает наименование таймфрейма                |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES CorrectTimeframe(const ENUM_TIMEFRAMES timeframe)
  {
   return(timeframe==PERIOD_CURRENT ? ::Period() : timeframe);
  }

Если переданы значения NULL или пустая строка в качестве наименования символа, или 0 или PERIOD_CURRENT в качестве значения периода графика, функции вернут текущий символ или таймфрейм. В любом другом случае — переданные в функции значения. Таким образом, мы этими функциями постепенно заменим в библиотеке все коды, где выполняются аналогичные проверки на корректность передаваемых в методы значений.

Добавим сюда же функции, возвращающие описания паттернов:

//+------------------------------------------------------------------+
//| Возвращает описание типа паттерна                                |
//+------------------------------------------------------------------+
string PatternTypeDescription(const ENUM_PATTERN_TYPE type)
  {
   switch(type)
     {
      case PATTERN_TYPE_HARAMI               :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HARAMI);
      case PATTERN_TYPE_HARAMI_CROSS         :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HARAMI_CROSS);
      case PATTERN_TYPE_TWEEZER              :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_TWEEZER);
      case PATTERN_TYPE_PIERCING_LINE        :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_PIERCING_LINE);
      case PATTERN_TYPE_DARK_CLOUD_COVER     :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_DARK_CLOUD_COVER);
      case PATTERN_TYPE_THREE_WHITE_SOLDIERS :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_THREE_WHITE_SOLDIERS);
      case PATTERN_TYPE_THREE_BLACK_CROWS    :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_THREE_BLACK_CROWS);
      case PATTERN_TYPE_SHOOTING_STAR        :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_SHOOTING_STAR);
      case PATTERN_TYPE_HAMMER               :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HAMMER);
      case PATTERN_TYPE_INVERTED_HAMMER      :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_INVERTED_HAMMER);
      case PATTERN_TYPE_HANGING_MAN          :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_HANGING_MAN);
      case PATTERN_TYPE_DOJI                 :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_DOJI);
      case PATTERN_TYPE_DRAGONFLY_DOJI       :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_DRAGONFLY_DOJI);
      case PATTERN_TYPE_GRAVESTONE_DOJI      :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_GRAVESTONE_DOJI);
      case PATTERN_TYPE_MORNING_STAR         :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_MORNING_STAR);
      case PATTERN_TYPE_MORNING_DOJI_STAR    :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_MORNING_DOJI_STAR);
      case PATTERN_TYPE_EVENING_STAR         :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_EVENING_STAR);
      case PATTERN_TYPE_EVENING_DOJI_STAR    :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_EVENING_DOJI_STAR);
      case PATTERN_TYPE_THREE_STARS          :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_THREE_STARS);
      case PATTERN_TYPE_ABANDONED_BABY       :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_ABANDONED_BABY);
      case PATTERN_TYPE_PIVOT_POINT_REVERSAL :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_PIVOT_POINT_REVERSAL);
      case PATTERN_TYPE_OUTSIDE_BAR          :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_OUTSIDE_BAR);
      case PATTERN_TYPE_INSIDE_BAR           :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_INSIDE_BAR);
      case PATTERN_TYPE_PIN_BAR              :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_PIN_BAR);
      case PATTERN_TYPE_RAILS                :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_RAILS);
      default                                :  return CMessage::Text(MSG_LIB_TEXT_FRAME_STYLE_NONE);
     }
  }

В зависимости от переданного в функцию типа паттерна, возвращается соответствующее текстовое описание.


Функция, возвращающая количество и список паттернов в ulong-переменной:

//+------------------------------------------------------------------+
//| Возвращает количество и список паттернов в ulong-переменной      |
//+------------------------------------------------------------------+
int ListPatternsInVar(const ulong var,ulong &array[])
  {
   int size=0;
   ulong x=1;
//--- В цикле от значения 1 до количества паттернов PATTERNS_TOTAL-1
   for(int i=1;i<PATTERNS_TOTAL;i++)
     {
      //--- по значению индекса цикла задаём значение проверяемого флага паттерна из перечисления ENUM_PATTERN_TYPE
      x=(i>1 ? x*2 : 1);
      ENUM_PATTERN_TYPE type=(ENUM_PATTERN_TYPE)x;
      //--- Если в переданном в функцию значении присутствует флаг паттерна со значением x
      bool res=(var & type)==type;
      if(res)
        {
         //--- увеличиваем размер массива паттернов
         size++;
         ArrayResize(array,size,PATTERNS_TOTAL-1);
         //--- записываем тип паттерна в массив
         array[size-1]=type;
        }
     }
//--- Возвращаем количество типов паттернов, хранящихся в переменной
   return size;
  }

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


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

//+------------------------------------------------------------------+
//| Выводит в журнал описание типов паттернов в ulong-переменной     |
//+------------------------------------------------------------------+
void PatternsInVarDescriptionPrint(const ulong var,const bool dash=false)
  {
   ulong array[];
//--- Получаем количество паттернов в переданном в функцию значении
   int total=ListPatternsInVar(var,array);
//--- В цикле по массиву паттернов получаем описание очередного паттерна и выводим его на печать
   for(int i=0;i<total;i++)
      Print((dash ? " - " : ""),PatternTypeDescription((ENUM_PATTERN_TYPE)array[i]));
  }

Логика метода полностью расписана в комментариях к коду.


Функция, возвращающая описание типов паттернов в ulong-переменной:

//+------------------------------------------------------------------+
//| Возвращает описание типов паттернов в ulong-переменной           |
//+------------------------------------------------------------------+
string PatternsInVarDescription(const ulong var,const bool dash=false)
  {
   ulong array[];
//--- Получаем количество паттернов в переданном в функцию значении
   int total=ListPatternsInVar(var,array);
   string txt="";
//--- В цикле по массиву паттернов получаем описание очередного паттерна и добавляем его в текстовую переменную
   for(int i=0;i<total;i++)
      txt+=((dash ? " - " : "")+PatternTypeDescription((ENUM_PATTERN_TYPE)array[i]))+(i<total-1 ? "\n" : "");
//--- Возвращаем полученный текст
   return txt;
  }

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


Класс объекта графического элемента в файле \MQL5\Include\DoEasy\Objects\Graph\GCnvElement.mqh служит основой для создания более сложных элементов GUI, но есть некоторые переменные в этом классе, доступ к которым закрыт из производных классов. Перенесём эти переменные и методы из приватной секции в защищённую:

//+------------------------------------------------------------------+
//| Класс объекта графического элемента                              |
//+------------------------------------------------------------------+
class CGCnvElement : public CGBaseObj
  {
protected:
   CGCnvElement     *m_element_main;                           // Указатель на первоначальный родительский элемент в составе всех групп связанных объектов
   CGCnvElement     *m_element_base;                           // Указатель на родительский элемент в составе связанных объектов текущей группы
   CCanvas           m_canvas;                                 // Объект класса CCanvas
   CPause            m_pause;                                  // Объект класса "Пауза"
   bool              m_shadow;                                 // Наличие тени
   color             m_chart_color_bg;                         // Цвет фона графика
   uint              m_duplicate_res[];                        // Массив для хранения копии данных ресурса
   color             m_array_colors_bg[];                      // Массив цветов фона элемента
   color             m_array_colors_bg_dwn[];                  // Массив цветов фона элемента при нажатии мышки на элемент управления
   color             m_array_colors_bg_ovr[];                  // Массив цветов фона элемента при наведении мышки на элемент управления
   bool              m_gradient_v;                             // Флаг вертикальной градиентной заливки
   bool              m_gradient_c;                             // Флаг циклической градиентной заливки
   int               m_init_relative_x;                        // Первоначальная относительная координата X
   int               m_init_relative_y;                        // Первоначальная относительная координата Y
   color             m_array_colors_bg_init[];                 // Массив цветов фона элемента (первоначальный цвет)
   int               m_shift_coord_x;                          // Смещение координаты X относительно базового объекта
   int               m_shift_coord_y;                          // Смещение координаты Y относительно базового объекта

//--- Создаёт (1) структуру объекта, (2) объект из структуры

...

   long              m_long_prop[CANV_ELEMENT_PROP_INTEGER_TOTAL];   // Целочисленные свойства
   double            m_double_prop[CANV_ELEMENT_PROP_DOUBLE_TOTAL];  // Вещественные свойства
   string            m_string_prop[CANV_ELEMENT_PROP_STRING_TOTAL];  // Строковые свойства

   ENUM_FRAME_ANCHOR m_text_anchor;                            // Текущее выравнивание текста
   int               m_text_x;                                 // Последняя координата X текста
   int               m_text_y;                                 // Последняя координата Y текста

protected:   
//--- Инициализирует значения свойств
   void              Initialize(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                const int element_id,const int element_num,
                                const int x,const int y,const int w,const int h,
                                const string descript,const bool movable,const bool activity);
                                
private:   
//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство ордера


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

//+------------------------------------------------------------------+
//| Методы работы с текстом                                          |
//+------------------------------------------------------------------+
//--- Устанавливает последнюю координату (1) X, (2) Y текста
   void              SetTextLastX(const int x)                    { this.m_text_x=x;                                                   }
   void              SetTextLastY(const int y)                    { this.m_text_y=y;                                                   }
//--- Возвращает (1) тип выравнивания (способ привязки), последнюю координату (2) X, (3) Y текста

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

До сего времени мы использовали для построения графических элементов управления объекты на основе OBJ_BITMAP_LABEL — объекта "Графическая метка":


Положение точки привязки относительно метки можно выбрать из перечисления ENUM_ANCHOR_POINT. Координаты точки привязки задаются в пикселях.

Также можно выбрать угол привязки графической метки из перечисления ENUM_BASE_CORNER.

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

Но если нам необходимо иметь привязку такого объекта к координатам цена/время, и при этом использовать точно такие же возможности рисования внутри объекта как на холсте, то здесь на помощь придёт графический объект OBJ_BITMAP — Объект "Рисунок":


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

Методы класса CCanvas позволяют создать объект-рисунок. Поэтому нам нужно просто создать на основе класса графического элемента класс объекта-рисунка. С минимальными доработками.


Класс графического элемента "Рисунок"

В папке библиотеки \MQL5\Include\DoEasy\Objects\Graph\ создадим новый файл GCnvBitmap.mqh класса CGCnvBitmap.
Класс должен быть унаследован от класса графического элемента, файл которого должен быть подключен к файлу создаваемого класса:

//+------------------------------------------------------------------+
//|                                                   GCnvBitmap.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "GCnvElement.mqh"
//+------------------------------------------------------------------+
//| Класс объекта графического элемента                              |
//+------------------------------------------------------------------+
class CGCnvBitmap : public CGCnvElement
  {
  }


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

//+------------------------------------------------------------------+
//| Класс объекта графического элемента                              |
//+------------------------------------------------------------------+
class CGCnvBitmap : public CGCnvElement
  {
private:
   datetime          m_time;              // Координата времени
   double            m_price;             // Координата цены
protected:
//--- Защищённый конструктор
                     CGCnvBitmap(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                 CGCnvElement *main_obj,CGCnvElement *base_obj,
                                 const long     chart_id,
                                 const int      wnd_num,
                                 const string   descript,
                                 const datetime time,
                                 const double   price,
                                 const int      w,
                                 const int      h);
public:
//--- Создаёт Bitmap
   virtual bool      Create(const long chart_id, 
                            const int wnd_num,
                            const int x,
                            const int y,
                            const int w,
                            const int h,
                            const bool redraw=false);

//--- Параметрический конструктор
                     CGCnvBitmap(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                                 CGCnvElement  *main_obj,CGCnvElement *base_obj,
                                 const int      element_id,
                                 const int      element_num,
                                 const long     chart_id,
                                 const int      wnd_num,
                                 const string   descript,
                                 const datetime time,
                                 const double   price,
                                 const int      w,
                                 const int      h,
                                 const color    colour,
                                 const uchar    opacity,
                                 const bool     movable=false,
                                 const bool     activity=true,
                                 const bool     redraw=false);
//--- Конструктор по умолчанию
                     CGCnvBitmap()
                        {
                         this.m_shadow=false;
                         this.m_chart_color_bg=(color)::ChartGetInteger(::ChartID(),CHART_COLOR_BACKGROUND);
                         this.m_type=OBJECT_DE_TYPE_GBITMAP;
                         this.m_element_main=NULL;
                         this.m_element_base=NULL;
                         this.m_shift_coord_x=0;
                         this.m_shift_coord_y=0;
                        }
//--- Деструктор
                    ~CGCnvBitmap()
                        { this.m_canvas.Destroy();             }
     
//+------------------------------------------------------------------+
//| Методы упрощённого доступа к свойствам объекта                   |
//+------------------------------------------------------------------+
//--- Устанавливает координату (1) времени, (2) цены, (3) обе
   bool              SetTime(const datetime time);
   bool              SetPrice(const double price);
   bool              SetTimePrice(const datetime time,const double price);
   
//--- Возвращает координату (1) времени, (2) цены
   datetime          Time(void)  const { return this.m_time;   }
   double            Price(void) const { return this.m_price;  }

  };


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

//+------------------------------------------------------------------+
//| Параметрический конструктор                                      |
//+------------------------------------------------------------------+
CGCnvBitmap::CGCnvBitmap(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                         CGCnvElement *main_obj,CGCnvElement *base_obj,
                         const int      element_id,
                         const int      element_num,
                         const long     chart_id,
                         const int      wnd_num,
                         const string   descript,
                         const datetime time,
                         const double   price,
                         const int      w,
                         const int      h,
                         const color    colour,
                         const uchar    opacity,
                         const bool     movable=false,
                         const bool     activity=true,
                         const bool     redraw=false)
  {
   this.SetTypeElement(element_type);
   this.m_type=OBJECT_DE_TYPE_GBITMAP; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.SetTextAnchor(0);
   this.SetTextLastX(0);
   this.SetTextLastY(0);
   this.SetBackgroundColor(colour,true);
   this.SetOpacity(opacity);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,0,0,w,h,redraw))
     {
      this.Initialize(element_type,element_id,element_num,0,0,w,h,descript,movable,activity);
      this.SetVisibleFlag(false,false);
      this.SetTimePrice(time,price);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
//+------------------------------------------------------------------+
//| Защищённый конструктор                                           |
//+------------------------------------------------------------------+
CGCnvBitmap::CGCnvBitmap(const ENUM_GRAPH_ELEMENT_TYPE element_type,
                         CGCnvElement *main_obj,CGCnvElement *base_obj,
                         const long     chart_id,
                         const int      wnd_num,
                         const string   descript,
                         const datetime time,
                         const double   price,
                         const int      w,
                         const int      h)
  {
   this.m_type=OBJECT_DE_TYPE_GBITMAP; 
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.m_type_element=element_type;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.SetTextAnchor(0);
   this.SetTextLastX(0);
   this.SetTextLastY(0);
   this.SetBackgroundColor(CLR_CANV_NULL,true);
   this.SetOpacity(0);
   this.m_shift_coord_x=0;
   this.m_shift_coord_y=0;
   this.m_shadow=false;
   if(::ArrayResize(this.m_array_colors_bg,1)==1)
      this.m_array_colors_bg[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,1)==1)
      this.m_array_colors_bg_dwn[0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,1)==1)
      this.m_array_colors_bg_ovr[0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,0,0,w,h,false))
     {
      this.Initialize(element_type,0,0,0,0,w,h,descript,false,false);
      this.SetVisibleFlag(false,false);
      this.SetTimePrice(time,price);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }

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


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

//+------------------------------------------------------------------+
//| Создаёт графический объект-рисунок                               |
//+------------------------------------------------------------------+
bool CGCnvBitmap::Create(const long chart_id,     // Идентификатор графика
                         const int wnd_num,       // Подокно графика
                         const int x,             // Координата X
                         const int y,             // Координата Y
                         const int w,             // Ширина
                         const int h,             // Высота
                         const bool redraw=false) // Флаг необходимости перерисовки
                         
  {
   ::ResetLastError();
   if(this.m_canvas.CreateBitmap((chart_id==NULL ? ::ChartID() : chart_id),wnd_num,this.m_name,x,y,w,h,COLOR_FORMAT_ARGB_NORMALIZE))
     {
      this.Erase(CLR_CANV_NULL);
      this.m_canvas.Update(redraw);
      this.m_shift_y=(int)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_WINDOW_YDISTANCE,wnd_num);
      return true;
     }
   int err=::GetLastError();
   int code=(err==0 ? (w<1 ? MSG_CANV_ELEMENT_ERR_FAILED_SET_WIDTH : h<1 ? MSG_CANV_ELEMENT_ERR_FAILED_SET_HEIGHT : ERR_OBJECT_ERROR) : err);
   string subj=(w<1 ? "Width="+(string)w+". " : h<1 ? "Height="+(string)h+". " : "");
   CMessage::ToLog(DFUN_ERR_LINE+subj,code,true);
   return false;
  }

Здесь, в отличии от такого же метода родительского класса, для создания графического объекта используется метод CreateBitmap() класса CCanvas вместо метода CreateBitmapLabel(). И это единственное отличие этого метода от метода родительского класса.


Методы для установки координат цены и времени объекту-рисунку:

//+------------------------------------------------------------------+
//| Устанавливает координату времени                                 |
//+------------------------------------------------------------------+
bool CGCnvBitmap::SetTime(const datetime time)
  {
   string name=this.NameObj();
   if(name==NULL || name=="")
      return false;
   ::ResetLastError();
   if(!::ObjectSetInteger(this.ChartID(),name,OBJPROP_TIME,time))
     {
      ::PrintFormat("%s%s. %s %s",DFUN,CMessage::Text(MSG_ERR_FAILED_SET_BITMAP_OBJ_TIME),CMessage::Text(MSG_LIB_SYS_ERROR),::GetLastError());
      return false;
     }
   this.m_time=time;
   return true;
  }
//+------------------------------------------------------------------+
//| Устанавливает координату цены                                    |
//+------------------------------------------------------------------+
bool CGCnvBitmap::SetPrice(const double price)
  {
   string name=this.NameObj();
   if(name==NULL || name=="")
      return false;
   ::ResetLastError();
   if(!::ObjectSetDouble(this.ChartID(),name,OBJPROP_PRICE,price))
     {
      ::PrintFormat("%s%s. %s %s",DFUN,CMessage::Text(MSG_ERR_FAILED_SET_BITMAP_OBJ_PRICE),CMessage::Text(MSG_LIB_SYS_ERROR),::GetLastError());
      return false;
     }
   this.m_price=price;
   return true;
  }
//+------------------------------------------------------------------+
//| Устанавливает обе координаты                                     |
//+------------------------------------------------------------------+
bool CGCnvBitmap::SetTimePrice(const datetime time,const double price)
  {
   if(!this.SetTime(time))
      return false;
   return this.SetPrice(price);
  }
//+------------------------------------------------------------------+
Вкратце: если в графический объект не удалось установить свойство, выводим об этом сообщение в журнал и возвращаем false.
При успешной установке свойства объекту, в переменную класса записывается новое значение и возвращается true.


В классе управления графическими элементами в файле \MQL5\Include\DoEasy\Objects\Graph\GraphElmControl.mqh объявим метод для создания объекта-рисунка:

//+------------------------------------------------------------------+
//| Класс управления графическими элементами                         |
//+------------------------------------------------------------------+
class CGraphElmControl : public CObject
  {
private:
   int               m_type;                          // Тип объекта
   int               m_type_node;                     // Тип объекта, для которого строится графика
//--- Устанавливает общие параметры для стандартных графических объектов
   void              SetCommonParamsStdGraphObj(const long chart_id,const string name);
public:
//--- Возвращает себя
   CGraphElmControl *GetObject(void)                  { return &this;               }
//--- Устанавливает тип объекта, для которого строится графика
   void              SetTypeNode(const int type_node) { this.m_type_node=type_node; }
   
//--- Создаёт объект-форму
   CForm            *CreateForm(const int form_id,const long chart_id,const int wnd,const string name,const int x,const int y,const int w,const int h);
   CForm            *CreateForm(const int form_id,const int wnd,const string name,const int x,const int y,const int w,const int h);
   CForm            *CreateForm(const int form_id,const string name,const int x,const int y,const int w,const int h);

//--- Создаёт объект Bitmap
   CGCnvBitmap      *CreateBitmap(const int obj_id,const long chart_id,const int wnd,const string name,const datetime time,const double price,const int w,const int h,const color clr);
   
//--- Создаёт стандартный графический объект-трендовую линию


За пределами тела класса напишем его реализацию:

//+------------------------------------------------------------------+
//| Создаёт объект Bitmap                                            |
//+------------------------------------------------------------------+
CGCnvBitmap *CGraphElmControl::CreateBitmap(const int obj_id,const long chart_id,const int wnd,const string name,const datetime time,const double price,const int w,const int h,const color clr)
  {
   CGCnvBitmap *obj=new CGCnvBitmap(GRAPH_ELEMENT_TYPE_BITMAP,NULL,NULL,obj_id,0,chart_id,wnd,name,time,price,w,h,clr,200);
   return obj;
  }

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


Теперь в классе базового объекта библиотеки CBaseObj в файле \MQL5\Include\DoEasy\Objects\BaseObj.mqh напишем методы для создания объекта-рисунка:

//+------------------------------------------------------------------+
//| Методы работы с графическими элементами                          |
//+------------------------------------------------------------------+
//--- Создаёт объект-форму на указанном графике в указанном подокне
   CForm            *CreateForm(const int form_id,const long chart_id,const int wnd,const string name,const int x,const int y,const int w,const int h)
                       { return this.m_graph_elm.CreateForm(form_id,chart_id,wnd,name,x,y,w,h);                }
//--- Создаёт объект-форму на текущем графике в указанном подокне
   CForm            *CreateForm(const int form_id,const int wnd,const string name,const int x,const int y,const int w,const int h)
                       { return this.m_graph_elm.CreateForm(form_id,wnd,name,x,y,w,h);                         }
//--- Создаёт объект-форму на текущем графике в главном окне
   CForm            *CreateForm(const int form_id,const string name,const int x,const int y,const int w,const int h)
                       { return this.m_graph_elm.CreateForm(form_id,name,x,y,w,h);                             }
   
//--- Создаёт объект-рисунок на указанном графике в указанном подокне
   CGCnvBitmap      *CreateBitmap(const int obj_id,const long chart_id,const int wnd,const string name,const datetime time,const double price,const int w,const int h,const color clr)
                       { return this.m_graph_elm.CreateBitmap(obj_id,chart_id,wnd,name,time,price,w,h,clr);   }
//--- Создаёт объект-рисунок на текущем графике в указанном подокне
   CGCnvBitmap      *CreateBitmap(const int obj_id,const int wnd,const string name,const datetime time,const double price,const int w,const int h,const color clr)
                       { return this.m_graph_elm.CreateBitmap(obj_id,::ChartID(),wnd,name,time,price,w,h,clr);}
//--- Создаёт объект-рисунок на текущем графике в главном окне
   CGCnvBitmap      *CreateBitmap(const int obj_id,const string name,const datetime time,const double price,const int w,const int h,const color clr)
                       { return this.m_graph_elm.CreateBitmap(obj_id,::ChartID(),0,name,time,price,w,h,clr);  }
   
//--- Создаёт стандартный графический объект-трендовую линию на указанном графике в указанном подокне

Три метода для создания объекта-рисунка (1) на указанном графике в указанном подокне, (2) на текущем графике в указанном подокне, (3) на текущем графике в главном окне. Методы просто возвращают результат вызова метода создания объекта-рисунка класса CGraphElmControl с указанными параметрами, которые написали выше.

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

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

К файлу класса объекта формы \MQL5\Include\DoEasy\Objects\Graph\Form.mqh вместо файла графического элемента подключим файл класса объекта-рисунка:

//+------------------------------------------------------------------+
//|                                                         Form.mqh |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "GCnvBitmap.mqh"
#include "ShadowObj.mqh"
#include "Animations\Animations.mqh"
#include "..\..\Services\MouseState.mqh"
//+------------------------------------------------------------------+
//| Класс объекта "форма"                                            |
//+------------------------------------------------------------------+
class CForm : public CGCnvElement
  {

Теперь в объекте-форме будут доступны и объект-элемент, и объект-рисунок. Соответственно, и в остальных файлах, где нужен объект-элемент, будут доступны оба эти объекта.


В объект-бар будем вписывать паттерны, которые были найденные на нём.
Для этого в файле класса объекта-бара \MQL5\Include\DoEasy\Objects\Series\Bar.mqh в публичной секции напишем метод, добавляющий к свойству бара тип нового паттерна:

//--- Возвращает себя
   CBar             *GetObject(void)                                    { return &this;}
//--- Устанавливает (1) символ, таймфрейм и время бара, (2) параметры объекта-бар
   void              SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime time);
   void              SetProperties(const MqlRates &rates);
//--- Добавляет тип паттерна на баре
   void              AddPattern(const ENUM_PATTERN_TYPE pattern_type)   { this.m_long_prop[BAR_PROP_PATTERNS_TYPE] |=pattern_type;           }

//--- Сравнивает объекты CBar между собой по всем возможным свойствам (для сортировки списков по указанному свойству объекта-бара)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CBar между собой по всем свойствам (для поиска равных объектов-баров)
   bool              IsEqual(CBar* compared_bar) const;
//--- Конструкторы
                     CBar(){ this.m_type=OBJECT_DE_TYPE_SERIES_BAR; }
                     CBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime time,const string source);
                     CBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const MqlRates &rates);

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


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

//+------------------------------------------------------------------+
//| Описания свойств объекта-бара                                    |
//+------------------------------------------------------------------+
//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства бара
   string            GetPropertyDescription(ENUM_BAR_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_BAR_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_BAR_PROP_STRING property);

//--- Возвращает описание типа бара
   string            BodyTypeDescription(void)  const;
//--- Выводит в журнал описание свойств объекта (full_prop=true - все свойства, false - только поддерживаемые - реализуется в наследниках класса)
   virtual void      Print(const bool full_prop=false,const bool dash=false);
//--- Выводит в журнал краткое описание объекта
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);
//--- Возвращает (1) краткое наименование, описание (2) параметров объекта-бара, (3) список паттернов в переданном массиве
   virtual string    Header(void);
   string            ParameterDescription(void);
   int               GetPatternsList(ulong &array[]);
//--- Выводит в журнал список паттернов на баре
   void              PatternTypeDescriptionPrint(const bool dash=false);
//---
  };


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

//+------------------------------------------------------------------+
//| Устанавливает параметры объекта-бар                              |
//+------------------------------------------------------------------+
void CBar::SetProperties(const MqlRates &rates)
  {
   this.SetProperty(BAR_PROP_SPREAD,rates.spread);
   this.SetProperty(BAR_PROP_VOLUME_TICK,rates.tick_volume);
   this.SetProperty(BAR_PROP_VOLUME_REAL,rates.real_volume);
   this.SetProperty(BAR_PROP_TIME,rates.time);
   this.SetProperty(BAR_PROP_TIME_YEAR,this.TimeYear());
   this.SetProperty(BAR_PROP_TIME_MONTH,this.TimeMonth());
   this.SetProperty(BAR_PROP_TIME_DAY_OF_YEAR,this.TimeDayOfYear());
   this.SetProperty(BAR_PROP_TIME_DAY_OF_WEEK,this.TimeDayOfWeek());
   this.SetProperty(BAR_PROP_TIME_DAY,this.TimeDay());
   this.SetProperty(BAR_PROP_TIME_HOUR,this.TimeHour());
   this.SetProperty(BAR_PROP_TIME_MINUTE,this.TimeMinute());
//---
   this.SetProperty(BAR_PROP_OPEN,rates.open);
   this.SetProperty(BAR_PROP_HIGH,rates.high);
   this.SetProperty(BAR_PROP_LOW,rates.low);
   this.SetProperty(BAR_PROP_CLOSE,rates.close);
   this.SetProperty(BAR_PROP_CANDLE_SIZE,this.CandleSize());
   this.SetProperty(BAR_PROP_CANDLE_SIZE_BODY,this.BodySize());
   this.SetProperty(BAR_PROP_CANDLE_BODY_TOP,this.BodyHigh());
   this.SetProperty(BAR_PROP_CANDLE_BODY_BOTTOM,this.BodyLow());
   this.SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_UP,this.ShadowUpSize());
   this.SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_DOWN,this.ShadowDownSize());
//---
   this.SetProperty(BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,this.CandleRatioBodyToCandleSize());
   this.SetProperty(BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.CandleRatioUpperShadowToCandleSize());
   this.SetProperty(BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.CandleRatioLowerShadowToCandleSize());
   this.SetProperty(BAR_PROP_PATTERNS_TYPE,0);
   this.SetProperty(BAR_PROP_TYPE,this.BodyType());
//--- Установим тип объекта в объект класса управления графическими объектами
   this.m_graph_elm.SetTypeNode(this.m_type);
  }


За пределами тела класса напишем метод, возвращающий список паттернов в переданном массиве:

//+------------------------------------------------------------------+
//| Возвращает список паттернов в переданном массиве                 |
//+------------------------------------------------------------------+
int CBar::GetPatternsList(ulong &array[])
  {
   return ListPatternsInVar(this.GetProperty(BAR_PROP_PATTERNS_TYPE),array);
  }

В метод передаётся массив и возвращается результат выполнения ранее написанной сегодня функции ListPatternsInVar(). При этом список всех паттернов на баре помещается в массив, переданный по ссылке в метод.


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

//+------------------------------------------------------------------+
//| Выводит в журнал описание паттернов на баре                      |
//+------------------------------------------------------------------+
void CBar::PatternTypeDescriptionPrint(const bool dash=false)
  {
   ulong patt=this.GetProperty(BAR_PROP_PATTERNS_TYPE);
   ::Print(CMessage::Text(MSG_LIB_TEXT_BAR_PATTERNS_TYPE),": ",(patt>0 ? "" : CMessage::Text(MSG_LIB_PROP_EMPTY)));
   if(patt>0)
      ::Print(PatternsInVarDescription(patt,dash));
  }

Ранее мы написали функцию PatternsInVarDescription(), возвращающую строку, содержащую описания всех паттернов, флаги которых содержатся в переменной. Здесь мы отправляем в эту функцию значение переменной, хранящей свойство бара BAR_PROP_PATTERNS_TYPE, и распечатываем в журнал полученную из функции строку.


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

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства бара                 |
//+------------------------------------------------------------------+
string CBar::GetPropertyDescription(ENUM_BAR_PROP_INTEGER property)
  {
   return
     (
      property==BAR_PROP_TIME                ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==BAR_PROP_TYPE                ?  CMessage::Text(MSG_ORD_TYPE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.BodyTypeDescription()
         )  :
      property==BAR_PROP_PERIOD              ?  CMessage::Text(MSG_LIB_TEXT_BAR_PERIOD)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.m_period_description
         )  :
      property==BAR_PROP_SPREAD              ?  CMessage::Text(MSG_LIB_TEXT_BAR_SPREAD)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==BAR_PROP_VOLUME_TICK         ?  CMessage::Text(MSG_LIB_TEXT_BAR_VOLUME_TICK)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==BAR_PROP_VOLUME_REAL         ?  CMessage::Text(MSG_LIB_TEXT_BAR_VOLUME_REAL)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==BAR_PROP_TIME_YEAR           ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME_YEAR)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.Year()
         )  :
      property==BAR_PROP_TIME_MONTH          ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME_MONTH)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+MonthDescription((int)this.Month())
         )  :
      property==BAR_PROP_TIME_DAY_OF_YEAR    ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY_OF_YEAR)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::IntegerToString(this.DayOfYear(),3,'0')
         )  :
      property==BAR_PROP_TIME_DAY_OF_WEEK    ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY_OF_WEEK)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+DayOfWeekDescription((ENUM_DAY_OF_WEEK)this.DayOfWeek())
         )  :
      property==BAR_PROP_TIME_DAY            ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::IntegerToString(this.Day(),2,'0')
         )  :
      property==BAR_PROP_TIME_HOUR           ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME_HOUR)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::IntegerToString(this.Hour(),2,'0')
         )  :
      property==BAR_PROP_TIME_MINUTE         ?  CMessage::Text(MSG_LIB_TEXT_BAR_TIME_MINUTE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::IntegerToString(this.Minute(),2,'0')
         )  :
      property==BAR_PROP_PATTERNS_TYPE       ?  CMessage::Text(MSG_LIB_TEXT_BAR_PATTERNS_TYPE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property)==0 ? CMessage::Text(MSG_LIB_PROP_NOT_FOUND) : "\n"+PatternsInVarDescription(this.GetProperty(property),true))
         )  :
      ""
     );
  }


Внесём доработки в файл \MQL5\Include\DoEasy\Objects\Series\Patterns\Pattern.mqh.

Так как в объект-паттерн будем размещать указатель на объект-бар, на котором был найден паттерн, то нужно к файлу класса объекта-паттерна подключить файл класса объекта-бара. У паттерна есть образующий и "материнский" бары. Для образующего бара будем использовать указатель на объект-бар (это бар, на котором найден паттерн), а для "материнского" бара создадим MqlRates-структуру, в которой будут храниться данные этого бара. Таким образом мы будем всегда иметь все данные о тех барах, которые "охватывает" паттерн. К слову, если паттерн однобаровый, то материнский и образующий бары — это один и тот же единственный бар. "Обрисовывать" паттерн будем при помощи объекта-рисунка, класс которого сегодня создали. Указатель на объект этого класса объявим в защищённой секции класса абстрактного объекта-паттерна. Чтобы можно было рассчитать необходимый размер рисунка, охватывающего бары паттерна, нам нужно знать размеры и параметры графика. Объявим переменные для хранения параметров графика, требуемых для расчёта размера объекта-рисунка.

//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\..\BaseObj.mqh"
#include "..\Bar.mqh"
//+------------------------------------------------------------------+
//| Класс абстрактного паттерна                                      |
//+------------------------------------------------------------------+
class CPattern : public CBaseObj
  {
private:
   CBar             *m_bar_pattern;                               // Указатель на бар, на котором образован паттерн
   MqlRates          m_mother_bar_prop;                           // Параметры "материнского" бара
   long              m_long_prop[PATTERN_PROP_INTEGER_TOTAL];     // Целочисленные свойства
   double            m_double_prop[PATTERN_PROP_DOUBLE_TOTAL];    // Вещественные свойства
   string            m_string_prop[PATTERN_PROP_STRING_TOTAL];    // Строковые свойства
   
//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство паттерна
   int               IndexProp(ENUM_PATTERN_PROP_DOUBLE property) const { return(int)property-PATTERN_PROP_INTEGER_TOTAL;                          }
   int               IndexProp(ENUM_PATTERN_PROP_STRING property) const { return(int)property-PATTERN_PROP_INTEGER_TOTAL-PATTERN_PROP_DOUBLE_TOTAL;}

protected:
   CForm            *m_form;                                      // Указатель на объект-форму
   CGCnvBitmap      *m_bitmap;                                    // Указатель на объект-рисунок
   int               m_digits;                                    // Значение Digits символа
   ulong             m_symbol_code;                               // Символ в виде числа (сумма кодов символов наименования)
   string            m_name_graph_obj;                            // Имя графического объекта, отображающего паттерн
   double            m_price;                                     // Уровень цены, на который устанавливается графический объект
   color             m_color_bullish;                             // Цвет графического объекта, устанавливаемый значку бычьего паттерна
   color             m_color_bearish;                             // Цвет графического объекта, устанавливаемый значку медвежьего паттерна
   color             m_color_bidirect;                            // Цвет графического объекта, устанавливаемый значку двунаправленного паттерна
   color             m_color;                                     // Цвет графического объекта
   color             m_color_panel_bullish;                       // Цвет панели бычьего паттерна
   color             m_color_panel_bearish;                       // Цвет панели медвежьего паттерна
   color             m_color_panel_bidirect;                      // Цвет панели двунаправленного паттерна
   int               m_bars_formation;                            // Количество баров формации (вложенный паттерн)
   bool              m_draw_dots;                                 // Рисовать на графике точками
   int               m_chart_scale;                               // Масштаб графика
   int               m_chart_height_px;                           // Высота графика в пикселях
   double            m_chart_price_max;                           // Максимум графика
   double            m_chart_price_min;                           // Минимум графика
   
public:


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

public:
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство паттерна
   void              SetProperty(ENUM_PATTERN_PROP_INTEGER property,long value) { this.m_long_prop[property]=value;                    }
   void              SetProperty(ENUM_PATTERN_PROP_DOUBLE property,double value){ this.m_double_prop[this.IndexProp(property)]=value;  }
   void              SetProperty(ENUM_PATTERN_PROP_STRING property,string value){ this.m_string_prop[this.IndexProp(property)]=value;  }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство паттерна
   long              GetProperty(ENUM_PATTERN_PROP_INTEGER property) const { return this.m_long_prop[property];                        }
   double            GetProperty(ENUM_PATTERN_PROP_DOUBLE property)  const { return this.m_double_prop[this.IndexProp(property)];      }
   string            GetProperty(ENUM_PATTERN_PROP_STRING property)  const { return this.m_string_prop[this.IndexProp(property)];      }

//--- Возвращает флаг поддержания паттерном указанного свойства
   virtual bool      SupportProperty(ENUM_PATTERN_PROP_INTEGER property)   { return true;       }
   virtual bool      SupportProperty(ENUM_PATTERN_PROP_DOUBLE property)    { return true;       }
   virtual bool      SupportProperty(ENUM_PATTERN_PROP_STRING property)    { return true;       }
//--- Возвращает себя
   CPattern         *GetObject(void)                                       { return &this;      }
   CForm            *GetForm(void)                                         { return this.m_form;}
   
//--- Сравнивает объекты CPattern между собой по всем возможным свойствам (для сортировки списков по указанному свойству объекта-паттерна)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CPattern между собой по всем свойствам (для поиска равных объектов-паттернов)
   bool              IsEqual(CPattern* compared_obj) const;
//--- Конструкторы
                     CPattern(){ this.m_type=OBJECT_DE_TYPE_SERIES_PATTERN; }
protected:
//--- Защищённый параметрический конструктор
                     CPattern(const ENUM_PATTERN_STATUS status,
                              const ENUM_PATTERN_TYPE type,
                              const uint id,
                              const ENUM_PATTERN_DIRECTION direction,
                              const string symbol,
                              const ENUM_TIMEFRAMES timeframe,MqlRates &rates);
public:                     
//--- Деструктор
                    ~CPattern(void);
                    
//+------------------------------------------------------------------+ 
//| Методы упрощённого доступа к свойствам объекта-паттерна          |
//+------------------------------------------------------------------+
//--- Возвращает (1) тип, (2) направление, (3) период, (4) статус,
//--- (5) код, (6) время определяющшего бара паттерна,
//--- (7) количество свечей, образующих паттерн
   ENUM_PATTERN_TYPE TypePattern(void)                               const { return (ENUM_PATTERN_TYPE)this.GetProperty(PATTERN_PROP_TYPE);           }
   ENUM_PATTERN_DIRECTION Direction(void)                            const { return (ENUM_PATTERN_DIRECTION)this.GetProperty(PATTERN_PROP_DIRECTION); }
   ENUM_TIMEFRAMES   Timeframe(void)                                 const { return (ENUM_TIMEFRAMES)this.GetProperty(PATTERN_PROP_PERIOD);           }
   ENUM_PATTERN_STATUS Status(void)                                  const { return (ENUM_PATTERN_STATUS)this.GetProperty(PATTERN_PROP_STATUS);       }
   ulong             Code(void)                                      const { return this.GetProperty(PATTERN_PROP_CODE);                              }
   uint              ID(void)                                        const { return (uint)this.GetProperty(PATTERN_PROP_ID);                          }
   ulong             ControlObjectID(void)                           const { return this.GetProperty(PATTERN_PROP_CTRL_OBJ_ID);                       }
   datetime          Time(void)                                      const { return (datetime)this.GetProperty(PATTERN_PROP_TIME);                    }
   uint              Candles(void)                                   const { return (uint)this.GetProperty(PATTERN_PROP_CANDLES);                     }
//--- Возвращает цены определяющего бара паттерна
   double            BarPriceOpen(void)                              const { return this.GetProperty(PATTERN_PROP_BAR_PRICE_OPEN);                    }
   double            BarPriceHigh(void)                              const { return this.GetProperty(PATTERN_PROP_BAR_PRICE_HIGH);                    }
   double            BarPriceLow(void)                               const { return this.GetProperty(PATTERN_PROP_BAR_PRICE_LOW);                     }
   double            BarPriceClose(void)                             const { return this.GetProperty(PATTERN_PROP_BAR_PRICE_CLOSE);                   }
//--- Возвращает (1) символ, (2) наименование паттерна
   string            Symbol(void)                                    const { return this.GetProperty(PATTERN_PROP_SYMBOL);                            }
   string            Name(void)                                      const { return this.GetProperty(PATTERN_PROP_NAME);                              }
   
//--- Устанавливает указатель на (1) бар паттерна, (2) данные "материнского" бара
   void              SetPatternBar(CBar *bar)                              { this.m_bar_pattern=bar;                                                  }
   void              SetMotherBarData(MqlRates &data);
//--- Устанавливает (1) OHLC "материнского" бара, (2) количество баров во вложенных формациях
   void              SetMotherBarOpen(const double open)                   { this.m_mother_bar_prop.open=open;                                        }
   void              SetMotherBarHigh(const double high)                   { this.m_mother_bar_prop.high=high;                                        }
   void              SetMotherBarLow(const double low)                     { this.m_mother_bar_prop.low=low;                                          }
   void              SetMotherBarClose(const double close)                 { this.m_mother_bar_prop.close=close;                                      }
   void              SetBarsInNestedFormations(const int bars)             { this.m_bars_formation=bars;                                              }
   
//--- Возвращает указатель на (1) бар паттерна, (2) время, (3 - 6) OHLC "материнского" бара, (7) количество баров во вложенных формациях
   CBar             *PatternBar(void)                                const { return this.m_bar_pattern;                                               }
   datetime          MotherBarTime(void)                             const { return (datetime)this.GetProperty(PATTERN_PROP_MOTHERBAR_TIME);          }
   double            MotherBarOpen(void)                             const { return this.m_mother_bar_prop.open;                                      }
   double            MotherBarHigh(void)                             const { return this.m_mother_bar_prop.high;                                      }
   double            MotherBarLow(void)                              const { return this.m_mother_bar_prop.low;                                       }
   double            MotherBarClose(void)                            const { return this.m_mother_bar_prop.close;                                     }
   int               BarsInNestedFormations(void)                    const { return this.m_bars_formation;                                            }
   
//+------------------------------------------------------------------+
//| Описания свойств объекта-паттерна                                |
//+------------------------------------------------------------------+
//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства паттерна
   string            GetPropertyDescription(ENUM_PATTERN_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_PATTERN_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_PATTERN_PROP_STRING property);

//--- Возвращает описание (1) статуса, (2) типа, (3) направления паттерна
   virtual string    StatusDescription(void) const { return NULL; }
   virtual string    TypeDescription(void)   const { return NULL; }
   string            DirectDescription(void) const;
//--- Выводит в журнал описание свойств объекта (full_prop=true - все свойства, false - только поддерживаемые - реализуется в наследниках класса)
   virtual void      Print(const bool full_prop=false,const bool dash=false);
//--- Выводит в журнал краткое описание объекта
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);
//--- Возвращает краткое наименование объекта-паттерна
   virtual string    Header(void);
//+------------------------------------------------------------------+
//| Работа с графическим отображением                                |
//+------------------------------------------------------------------+
protected:
//--- Устанавливает цвета отображения графического объекта для (1) бычьего, (2) медвежьего, (3) двунаправленного паттерна
   void              SetColorBullish(const color clr)       { this.m_color_bullish=clr;         }
   void              SetColorBearish(const color clr)       { this.m_color_bearish=clr;         }
   void              SetColorBiDirect(const color clr)      { this.m_color_bidirect=clr;        }
//--- Создаёт объект (1) инфо-панели, (2) Bitmap
   bool              CreateInfoPanel(void);
   virtual bool      CreateBitmap(void);
//--- Создаёт внешний вид инфо-панели
   virtual void      CreateInfoPanelView(void){}
//--- Рассчитывает (1) ширину, (2) высоту объекта-рисунка
   int               GetBitmapWidth(void);
   int               GetBitmapHeight(void);
   
public:
//--- Удаляет графический объект
   bool              DeleteGraphObj(bool redraw=false);
//--- Устанавливает цвета графического объекта и цвет отображения паттерна
   void              SetColors(const color color_bullish,const color color_bearish,const color color_bidirect,const bool redraw=false);
//--- Устанавливает флаг рисования меток паттернов как точки
   void              SetDrawAsDots(const bool flag)         { this.m_draw_dots=flag;            }
   
//--- Устанавливает цвет фона панели (1) бычьего, (2) медвежьего, (3) двунаправленного паттерна
   void              SetColorPanelBullish(const color clr)  { this.m_color_panel_bullish=clr;   }
   void              SetColorPanelBearish(const color clr)  { this.m_color_panel_bearish=clr;   }
   void              SetColorPanelBiDirect(const color clr) { this.m_color_panel_bidirect=clr;  }
//--- Устанавливает цвет фона панели (1) бычьего, (2) медвежьего, (3) двунаправленного паттерна установкой значений RGB-компонент цвета
   void              SetColorPanelBullish(const uchar R,const uchar G,const uchar B);
   void              SetColorPanelBearish(const uchar R,const uchar G,const uchar B);
   void              SetColorPanelBiDirect(const uchar R,const uchar G,const uchar B);

//--- Рисует значок паттерна на графике
   virtual void      Draw(const bool redraw);
//--- (1) Отображает, (2) скрывает значок паттерна на графике
   void              Show(const bool redraw=false);
   void              Hide(const bool redraw=false);
//--- (1) Отображает, (2) скрывает инфо-панель на графике
   void              ShowInfoPanel(const int x,const int y,const bool redraw=true);
   void              HideInfoPanel(void);
   
//--- Изменяет (1) ширину, (2) высоту, (3) размер объекта-рисунка
   bool              BitmapSetWidth(const int width);
   bool              BitmapSetHeight(const int height);
   bool              BitmapResize(const int w,const int h);
   
//--- Устанавливает (1) масштаб графика, (2) высоту графика в пикселях, (3) максимум, (3) минимум графика
   void              SetChartScale(const int scale)            { this.m_chart_scale=scale;      }
   void              SetChartHeightInPixels(const int height)  { this.m_chart_height_px=height; }
   void              SetChartPriceMax(const double price)      { this.m_chart_price_max=price;  }
   void              SetChartPriceMin(const double price)      { this.m_chart_price_min=price;  }
//--- Возвращает (1) масштаб графика, (2) высоту графика в пикселях, (3) максимум, (3) минимум графика
   int               ChartScale(void)                    const { return this.m_chart_scale;     }
   int               ChartHeightInPixels(void)           const { return this.m_chart_height_px; }
   double            ChartPriceMax(void)                 const { return this.m_chart_price_max; }
   double            ChartPriceMin(void)                 const { return this.m_chart_price_min; }
   
  };


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

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CPattern::CPattern(const ENUM_PATTERN_STATUS status,const ENUM_PATTERN_TYPE type,const uint id,const ENUM_PATTERN_DIRECTION direction,const string symbol,const ENUM_TIMEFRAMES timeframe,MqlRates &rates)
  {
//--- Устанавливаем свойства объекта-паттерна
   this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS);
   this.m_type=OBJECT_DE_TYPE_SERIES_PATTERN; 
   this.SetProperty(PATTERN_PROP_STATUS,status);
   this.SetProperty(PATTERN_PROP_TYPE,type);
   this.SetProperty(PATTERN_PROP_ID,id);
   this.SetProperty(PATTERN_PROP_DIRECTION,direction);
   this.SetProperty(PATTERN_PROP_PERIOD,timeframe);
   this.SetProperty(PATTERN_PROP_TIME,rates.time);
   this.SetProperty(PATTERN_PROP_BAR_PRICE_OPEN,rates.open);
   this.SetProperty(PATTERN_PROP_BAR_PRICE_HIGH,rates.high);
   this.SetProperty(PATTERN_PROP_BAR_PRICE_LOW,rates.low);
   this.SetProperty(PATTERN_PROP_BAR_PRICE_CLOSE,rates.close);
   this.SetProperty(PATTERN_PROP_SYMBOL,symbol);
//--- Создаём код символа
   this.m_symbol_code=0;
   for(int i=0;i<(int)symbol.Length();i++)
      this.m_symbol_code+=symbol.GetChar(i);
//--- Код паттерна = время определяющего бара + тип + статус + направление паттерна + таймфрейм + код символа
   ulong code=(ulong)rates.time+type+status+direction+timeframe+this.m_symbol_code;
   this.SetProperty(PATTERN_PROP_CODE,code);
//--- Устанавливаем параметры графических объектов паттерна (метки на графике)
   this.m_name_graph_obj=::StringFormat("%s_p%lu",this.m_name_program,code);
   this.m_color_bullish=clrBlue;
   this.m_color_bearish=clrRed;
   this.m_color_bidirect=clrMediumSeaGreen;
   if(this.Direction()==PATTERN_DIRECTION_BULLISH)
     {
      this.m_color=this.m_color_bullish;
      this.m_price=rates.low;
     }
   else if(this.Direction()==PATTERN_DIRECTION_BEARISH)
     {
      this.m_color=this.m_color_bearish;
      this.m_price=rates.high;
     }
   else
     {
      this.m_color=this.m_color_bidirect;
      this.m_price=(rates.open+rates.close)/2;
     }
//--- Устанавливаем базовые цвета информационных панелей паттерна
   this.m_color_panel_bullish=clrLightGray;
   this.m_color_panel_bearish=clrLightGray;
   this.m_color_panel_bidirect=clrLightGray;
   this.m_form=NULL;
   this.m_bitmap=NULL;
   this.m_draw_dots=true;
   this.m_bars_formation=1;
  }


В деструкторе класса удалим объект-рисунок:

//+------------------------------------------------------------------+
//| Деструктор                                                       |
//+------------------------------------------------------------------+
CPattern::~CPattern(void)
  {
//--- Удаляем объект-форму и метку паттерна на графике
   if(this.m_form!=NULL)
      delete this.m_form;
   if(this.m_bitmap!=NULL)
      delete this.m_bitmap;
   this.DeleteGraphObj();
  }


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

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства паттерна             |
//+------------------------------------------------------------------+
string CPattern::GetPropertyDescription(ENUM_PATTERN_PROP_INTEGER property)
  {
   return
     (
      property==PATTERN_PROP_CODE            ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_CODE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==PATTERN_PROP_TIME            ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_TIME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES)
         )  :
      property==PATTERN_PROP_MOTHERBAR_TIME  ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_MOTHERBAR_TIME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES)
         )  :
      property==PATTERN_PROP_STATUS          ?  CMessage::Text(MSG_ORD_STATUS)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.StatusDescription()
         )  :
      property==PATTERN_PROP_TYPE            ?  CMessage::Text(MSG_ORD_TYPE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.TypeDescription()
         )  :
      property==PATTERN_PROP_ID              ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_ID)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==PATTERN_PROP_CTRL_OBJ_ID     ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_CTRL_OBJ_ID)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==PATTERN_PROP_DIRECTION       ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_DIRECTION)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.DirectDescription()
         )  :
      property==PATTERN_PROP_PERIOD          ?  CMessage::Text(MSG_LIB_TEXT_BAR_PERIOD)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+TimeframeDescription((ENUM_TIMEFRAMES)this.GetProperty(property))
         )  :
      property==PATTERN_PROP_CANDLES         ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_CANDLES)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }


Реализация метода, устанавливающего данные "материнского" бара:

//+------------------------------------------------------------------+
//| Устанавливает данные "материнского" бара                         |
//+------------------------------------------------------------------+
void CPattern::SetMotherBarData(MqlRates &data)
  {
   this.m_mother_bar_prop.open=data.open;
   this.m_mother_bar_prop.high=data.high;
   this.m_mother_bar_prop.low=data.low;
   this.m_mother_bar_prop.close=data.close;
   this.m_mother_bar_prop.time=data.time;
   this.SetProperty(PATTERN_PROP_MOTHERBAR_TIME,data.time);
  }

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

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

//+------------------------------------------------------------------+
//| Отображает инфо-панель на графике                                |
//+------------------------------------------------------------------+
void CPattern::ShowInfoPanel(const int x,const int y,const bool redraw=true)
  {
//--- Если объекта панели ещё нету - создаём его
   if(this.m_form==NULL)
      if(!this.CreateInfoPanel())
         return;
//--- Получаем ширину и высоту графика
   int chart_w=(int)::ChartGetInteger(this.m_chart_id,CHART_WIDTH_IN_PIXELS);
   int chart_h=(int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS);
//--- Рассчитываем координаты X и Y панели так, чтобы она не выходила за пределы графика
   int cx=(x+this.m_form.Width() >chart_w-1 ? chart_w-1-this.m_form.Width()  : x);
   int cy=(y+this.m_form.Height()>chart_h-1 ? chart_h-1-this.m_form.Height() : y);
//--- Устанавливаем панели рассчитанные координаты и отображаем панель
   if(this.m_form.SetCoordX(cx) && this.m_form.SetCoordY(cy))
      this.m_form.Show();
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }

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

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

//+------------------------------------------------------------------+
//| Отображает значок паттерна на графике                            |
//+------------------------------------------------------------------+
void CPattern::Show(const bool redraw=false)
  {
   if(this.m_draw_dots)
     {
      ::ObjectSetInteger(this.m_chart_id,this.m_name_graph_obj,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
      return;
     }
   if(this.m_bitmap!=NULL)
      this.m_bitmap.Show();
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }

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

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

//+------------------------------------------------------------------+
//| Скрывает значок паттерна на графике                              |
//+------------------------------------------------------------------+
void CPattern::Hide(const bool redraw=false)
  {
   if(this.m_draw_dots)
     {
      ::ObjectSetInteger(this.m_chart_id,this.m_name_graph_obj,OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS);
      return;
     }
   if(this.m_bitmap!=NULL)
      this.m_bitmap.Hide();
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }


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

//+------------------------------------------------------------------+
//| Рассчитывает ширину объекта-рисунка                              |
//+------------------------------------------------------------------+
int CPattern::GetBitmapWidth(void)
  {
//--- Рассчитываем ширину свечей графика в пикселях
   int px=int(1<<this.m_chart_scale);
//--- Рассчитываем количество баров, составляющих паттерн
   int num_bars=::Bars(this.Symbol(),this.Timeframe(),this.MotherBarTime(),this.Time());
   if(num_bars==0)
      num_bars=(int)this.Candles();
//--- Рассчитываем и возвращаем ширину объекта-рисунка
   return (px*num_bars*2)-px+1;
  }

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


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

//+------------------------------------------------------------------+
//| Рассчитывает высоту объекта-рисунка                              |
//+------------------------------------------------------------------+
int CPattern::GetBitmapHeight(void)
  {
//--- Рассчитаем диапазон цен графика и диапазон цен паттерна
   double chart_price_range=this.m_chart_price_max-this.m_chart_price_min;
   double patt_price_range=this.MotherBarHigh()-this.MotherBarLow();
//--- По рассчитанным диапазонам цен рассчитаем и вернём высоту объекта-рисунка
   return (int)ceil(patt_price_range*this.m_chart_height_px/chart_price_range)+8;
  }

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

В конструкторе паттерна "Пин Бар" установим количество вложенных паттернов, равное значению баров паттерна (1):

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CPatternPinBar::CPatternPinBar(const uint id,const string symbol,const ENUM_TIMEFRAMES timeframe,MqlRates &rates,const ENUM_PATTERN_DIRECTION direct) : 
   CPattern(PATTERN_STATUS_PA,PATTERN_TYPE_PIN_BAR,id,direct,symbol,timeframe,rates)
  {
   this.SetProperty(PATTERN_PROP_NAME,"Pin Bar");
   this.SetProperty(PATTERN_PROP_CANDLES,1);
   this.m_bars_formation=(int)this.GetProperty(PATTERN_PROP_CANDLES);
  }


Теперь создадим класс нового паттерна Price Action "Внутренний бар".

Класс паттерна "Внутренний бар"

В том же файле, где написаны классы абстрактного паттерна и паттерна "Пин Бар", создадим новый класс — класс паттерна "Внутренний Бар". По сути, нам необходимо лишь написать (переопределить) некоторые виртуальные методы и значения свойств паттерна. Класс должен быть унаследован от класса объекта абстрактного паттерна:

//+------------------------------------------------------------------+
//| Класс паттерна "Внутренний бар"                                  |
//+------------------------------------------------------------------+
class CPatternInsideBar : public CPattern
  {
protected:
//--- Создаёт (1) объект-рисунок, внешний вид (2) инфо-панели, (3) объекта-рисунка
   virtual bool      CreateBitmap(void);
   virtual void      CreateInfoPanelView(void);
   void              CreateBitmapView(void);
public:
//--- Возвращает флаг поддержания паттерном указанного свойства
   virtual bool      SupportProperty(ENUM_PATTERN_PROP_INTEGER property)   { return true; }
   virtual bool      SupportProperty(ENUM_PATTERN_PROP_DOUBLE property)    { return true; }
   virtual bool      SupportProperty(ENUM_PATTERN_PROP_STRING property)    { return true; }
   
//--- Возвращает описание (1) статуса, (2) типа паттерна
   virtual string    StatusDescription(void) const { return CMessage::Text(MSG_LIB_TEXT_PATTERN_STATUS_PA);       }
   virtual string    TypeDescription(void)   const { return CMessage::Text(MSG_LIB_TEXT_PATTERN_TYPE_INSIDE_BAR); }

//--- Рисует значок паттерна на графике
   virtual void      Draw(const bool redraw);

//--- Конструктор
                     CPatternInsideBar(const uint id,const string symbol,const ENUM_TIMEFRAMES timeframe,MqlRates &rates,const ENUM_PATTERN_DIRECTION direct);
  };


В конструкторе класса установим наименование паттерна, количество баров паттерна, равное двум и, соответственно, количество баров вложенных формаций, равное 2 — нет вложенных формаций:

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CPatternInsideBar::CPatternInsideBar(const uint id,const string symbol,const ENUM_TIMEFRAMES timeframe,MqlRates &rates,const ENUM_PATTERN_DIRECTION direct) : 
   CPattern(PATTERN_STATUS_PA,PATTERN_TYPE_INSIDE_BAR,id,direct,symbol,timeframe,rates)
  {
   this.SetProperty(PATTERN_PROP_NAME,"Inside Bar");
   this.SetProperty(PATTERN_PROP_CANDLES,2);
   this.m_bars_formation=(int)this.GetProperty(PATTERN_PROP_CANDLES);
  }


Виртуальный метод, создающий внешний вид инфо-панели:

//+------------------------------------------------------------------+
//| Создаёт внешний вид инфо-панели                                  |
//+------------------------------------------------------------------+
void CPatternInsideBar::CreateInfoPanelView(void)
  {
//--- Если объект-форма не создана - уходим
   if(this.m_form==NULL)
      return;
//--- Объявляем массив для начального и конечного цветов градиентной заливки
   color clr[2]={this.m_form.ChangeColorLightness(this.m_color_panel_bidirect,-5),this.m_form.ChangeColorLightness(this.m_color_panel_bidirect,15)};
   
//--- Устанавливаем цвета фона и рамки формы
   this.m_form.SetBackgroundColor(this.m_color_panel_bidirect,true);
   this.m_form.SetBorderColor(clrGray,true);
//--- Создаём строки для описания паттерна, его параметров и критериев его поиска
   string name=::StringFormat("Inside Bar (%lu bars)",int(this.Time()-this.MotherBarTime())/::PeriodSeconds(this.Timeframe())+1);
   string param=this.DirectDescription();//::StringFormat("%s (%.2f/%.2f/%.2f)",this.DirectDescription(),this.GetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION),this.GetProperty(PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION),this.GetProperty(PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION));
//--- Устанавливаем координаты панели и рассчитываем её ширину и высоту в зависимости от размеров текстов, размещаемых на панели
   int x=3;
   int y=20;
   int w=4+(::fmax(20+this.m_form.TextWidth(name),::fmax(x+this.m_form.TextWidth(param),x+this.m_form.TextWidth(::TimeToString(this.Time())))));
   int h=2+(20+this.m_form.TextHeight(this.DirectDescription())+this.m_form.TextHeight(::TimeToString(this.Time())));
//--- Устанавливаем ширину и высоту панели по рассчитанным значениям
   this.m_form.SetWidth(w);
   this.m_form.SetHeight(h);
//--- В зависимости от размеров и координат графика, рассчитываем координаты панели так, чтобы она не выходила за пределы графика
   int chart_w=(int)::ChartGetInteger(this.m_chart_id,CHART_WIDTH_IN_PIXELS);
   int chart_h=(int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS);
   int cx=(this.m_form.RightEdge() >chart_w-1 ? chart_w-1-this.m_form.Width()  : this.m_form.CoordX());
   int cy=(this.m_form.BottomEdge()>chart_h-1 ? chart_h-1-this.m_form.Height() : this.m_form.CoordY());
   this.m_form.SetCoordX(cx);
   this.m_form.SetCoordY(cy);
//--- Заливаем фон градиентным цветом
   this.m_form.Erase(clr,200,true,false);
//--- Рисуем рамку панели, иконку с (i), рисуем текст заголовка с пропорциями свечи и отделяем заголовок горизонтальной линией
   this.m_form.DrawFrameSimple(0,0,this.m_form.Width(),this.m_form.Height(),1,1,1,1,this.m_form.BorderColor(),200);
   this.m_form.DrawIconInfo(1,1,200);
   this.m_form.Text(20,3,name,clrBlack,200);
   this.m_form.DrawLine(1,18,this.m_form.Width()-1,18,clrDarkGray,250);
//--- Под горизонтальной линией вписываем описание паттерна с критериями его поиска и датой определяющего паттерн бара
   y=20;
   this.m_form.Text(x,y,param,clrBlack,200);
   y+=this.m_form.TextHeight(::TimeToString(this.Time()));
   this.m_form.Text(x,y,::TimeToString(this.Time()),clrBlack,200);
//--- Обновляем панель с перерисовкой графика
   this.m_form.Update(true);
  }

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


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

//+------------------------------------------------------------------+
//| Рисует значок паттерна на графике                                |
//+------------------------------------------------------------------+
void CPatternInsideBar::Draw(const bool redraw)
  {
//--- Если установлен флаг рисования точками - вызываем метод родительского класса и уходим
   if(this.m_draw_dots)
     {
      CPattern::Draw(redraw);
      return;
     }
//--- Если объект-рисунок ещё не создавался - создаём его
   if(this.m_bitmap==NULL)
     {
      if(!this.CreateBitmap())
         return;
     }
//--- отображаем
   this.Show(redraw);
  }

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


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

//+------------------------------------------------------------------+
//| Создаёт объект-рисунок                                           |
//+------------------------------------------------------------------+
bool CPatternInsideBar::CreateBitmap(void)
  {
//--- Если объект-рисунок уже создан ранее - возвращаем true
   if(this.m_bitmap!=NULL)
      return true;
//--- Рассчитываем координаты и размеры объекта
   datetime time=this.MotherBarTime();
   double   price=(this.MotherBarHigh()+this.MotherBarLow())/2;
   int      w=this.GetBitmapWidth();
   int      h=this.GetBitmapHeight();
//--- Создаём объект Bitmap
   this.m_bitmap=this.CreateBitmap(this.ID(),this.GetChartID(),0,this.Name(),time,price,w,h,this.m_color_bidirect);
   if(this.m_bitmap==NULL)
      return false;
//--- Устанавливаем начало координат объекта по его центру и убираем всплывающую подсказку
   ::ObjectSetInteger(this.GetChartID(),this.m_bitmap.NameObj(),OBJPROP_ANCHOR,ANCHOR_CENTER);
   ::ObjectSetString(this.GetChartID(),this.m_bitmap.NameObj(),OBJPROP_TOOLTIP,"\n");
//--- Рисуем внешний вид объекта-рисунка
   this.CreateBitmapView();
   return true;
  }


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

//+------------------------------------------------------------------+
//| Создаёт внешний вид объекта-рисунка                              |
//+------------------------------------------------------------------+
void CPatternInsideBar::CreateBitmapView(void)
  {
   this.m_bitmap.Erase(CLR_CANV_NULL,0);
   int x=this.m_bitmap.Width()/2-int(1<<this.m_chart_scale)/2;
   this.m_bitmap.DrawRectangleFill(x,0,this.m_bitmap.Width()-1,this.m_bitmap.Height()-1,this.m_color_bidirect,80);
   this.m_bitmap.DrawRectangle(x,0,this.m_bitmap.Width()-1,this.m_bitmap.Height()-1,clrGray);
   this.m_bitmap.Update(false);
  }

Здесь: заливаем холст прозрачным цветом, рассчитываем начальную координату X прямоугольника, обрисовывающего бары паттерна. Далее заливаем прямоугольную область, начиная с рассчитанной координаты X, цветом, установленным для двунаправленного паттерна и непрозрачностью 80, и обводим залитую область серым прямоугольником. По окончании рисования обновляем ресурс без перерисовки графика.


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

Класс объекта управления паттерном находится в файле \MQL5\Include\DoEasy\Objects\Series\SeriesDE.mqh. Внесём в него необходимые доработки:

//+------------------------------------------------------------------+
//| Класс управления абстрактным паттерном                           |
//+------------------------------------------------------------------+
class CPatternControl : public CBaseObjExt
  {
private:
   ENUM_TIMEFRAMES   m_timeframe;                                                // Период графика таймсерии паттерна
   string            m_symbol;                                                   // Символ таймсерии паттерна
   double            m_point;                                                    // Point символа
   bool              m_used;                                                     // Флаг использования паттерна
   bool              m_drawing;                                                  // Флаг отрисовки значка паттерна на графике
   bool              m_draw_dots;                                                // Флаг отрисовки значка паттерна на графике точками
//--- Обрабатываемый паттерн
   ENUM_PATTERN_TYPE m_type_pattern;                                             // Тип паттерна
protected:
//--- Пропорции свечи
   double            m_ratio_body_to_candle_size;                                // Процентное отношение тела свечи к полному размеру свечи
   double            m_ratio_larger_shadow_to_candle_size;                       // Процентное отношение размера большей тени к размеру свечи
   double            m_ratio_smaller_shadow_to_candle_size;                      // Процентное отношение размера меньшей тени к размеру свечи
   ulong             m_object_id;                                                // Уникальный код объекта на основе критериев поиска паттерна
//--- Списки
   CArrayObj        *m_list_series;                                              // Указатель на список таймсерии
   CArrayObj        *m_list_all_patterns;                                        // Указатель на список всех паттернов
   CPattern          m_pattern_instance;                                         // Объект-паттерн для поиска по свойству
   ulong             m_symbol_code;                                              // Наименование символа графика в виде числа
   int               m_chart_scale;                                              // Масштаб графика
   int               m_chart_height_px;                                          // Высота графика в пикселях
   double            m_chart_price_max;                                          // Максимум графика
   double            m_chart_price_min;                                          // Минимум графика

//--- (1) Ищет паттерн, возвращает направление или -1, если паттерн не найден,
//--- (2) создаёт паттерн с указанным направлением,
//--- (3) создаёт и возвращает уникальный код паттерна,
//--- (4) возвращает список паттернов, управляемых этим объектом
   virtual ENUM_PATTERN_DIRECTION FindPattern(const datetime series_bar_time,const uint min_body_size,MqlRates &mother_bar_data) const
                                    { return WRONG_VALUE;   }
   virtual CPattern *CreatePattern(const ENUM_PATTERN_DIRECTION direction,const uint id,CBar *bar){ return NULL;                       }
   virtual ulong     GetPatternCode(const ENUM_PATTERN_DIRECTION direction,const datetime time) const { return 0;                      }
   virtual CArrayObj*GetListPatterns(void)                                       { return NULL;                                        }

//--- Создаёт идентификатор объекта на основе критериев поиска паттерна
   virtual ulong     CreateObjectID(void)                                        { return 0;                                           }

//--- Записывает данные бара в структуру
   void              SetBarData(CBar *bar,MqlRates &rates) const
                       {
                        if(bar==NULL)
                           return;
                        rates.open=bar.Open();
                        rates.high=bar.High();
                        rates.low=bar.Low();
                        rates.close=bar.Close();
                        rates.time=bar.Time();
                       }

public:
//--- Возвращает (1) себя, (2) флаг использования патитерна
   CPatternControl  *GetObject(void)                                             { return &this;                                       }
//--- (1) Устанавливает, (2) возвращает флаг использования патитерна
   void              SetUsed(const bool flag)                                    { this.m_used=flag;                                   }
   bool              IsUsed(void)                                          const { return this.m_used;                                 }
//--- (1) Устанавливает, (2) возвращает флаг рисования патитерна
   void              SetDrawing(const bool flag)                                 { this.m_drawing=flag;                                }
   bool              IsDrawing(void)                                       const { return this.m_drawing;                              }
//--- (1) Устанавливает, (2) возвращает флаг рисования значков паттерна в виде точек
   void              SetDrawingAsDots(const bool flag,const bool redraw);
   bool              IsDrawingAsDots(void)                                 const { return this.m_draw_dots;                            }

//--- Устанавливает искомое процентное отношение (1) тела свечи к полному размеру свечи,
//--- размера (2) верхней, (3) нижней тени к размеру свечи
   void              SetRatioBodyToCandleSizeValue(const double value)           { this.m_ratio_body_to_candle_size=value;             }
   void              SetRatioLargerShadowToCandleSizeValue(const double value)   { this.m_ratio_larger_shadow_to_candle_size=value;    }
   void              SetRatioSmallerShadowToCandleSizeValue(const double value)  { this.m_ratio_smaller_shadow_to_candle_size=value;   }
//--- Возвращает процентное отношение (1) тела свечи к полному размеру свечи,
//--- размера (2) верхней, (3) нижней тени к размеру свечи
   double            RatioBodyToCandleSizeValue(void)                      const { return this.m_ratio_body_to_candle_size;            }
   double            RatioLargerShadowToCandleSizeValue(void)              const { return this.m_ratio_larger_shadow_to_candle_size;   }
   double            RatioSmallerShadowToCandleSizeValue(void)             const { return this.m_ratio_smaller_shadow_to_candle_size;  }

//--- Возвращает идентификатор объекта на основе критериев поиска паттерна
   virtual ulong     ObjectID(void)                                        const { return this.m_object_id;                            }

//--- Возвращает (1) тип, (2) таймфрейм, (3) символ, (4) Point символа, (5) код символа паттерна
   ENUM_PATTERN_TYPE TypePattern(void)                                     const { return this.m_type_pattern;                         }
   ENUM_TIMEFRAMES   Timeframe(void)                                       const { return this.m_timeframe;                            }
   string            Symbol(void)                                          const { return this.m_symbol;                               }
   double            Point(void)                                           const { return this.m_point;                                }
   ulong             SymbolCode(void)                                      const { return this.m_symbol_code;                          }
   
//--- Устанавливает (1) масштаб графика, (2) высоту графика в пикселях, (3) максимум, (3) минимум графика
   void              SetChartScale(const int scale)                              { this.m_chart_scale=scale;                           }
   void              SetChartHeightInPixels(const int height)                    { this.m_chart_height_px=height;                      }
   void              SetChartPriceMax(const double price)                        { this.m_chart_price_max=price;                       }
   void              SetChartPriceMin(const double price)                        { this.m_chart_price_min=price;                       }
//--- Возвращает (1) масштаб графика, (2) высоту графика в пикселях, (3) максимум, (3) минимум графика
   int               ChartScale(void)                                      const { return this.m_chart_scale;                          }
   int               ChartHeightInPixels(void)                             const { return this.m_chart_height_px;                      }
   double            ChartPriceMax(void)                                   const { return this.m_chart_price_max;                      }
   double            ChartPriceMin(void)                                   const { return this.m_chart_price_min;                      }

//--- Сравнивает объекты CPatternControl между собой по всем возможным свойствам
   virtual int       Compare(const CObject *node,const int mode=0) const;

//--- Ищет паттерны и добавляет найденные в список всех паттернов
   virtual int       CreateAndRefreshPatternList(const uint min_body_size);
//--- Выводит паттерны на график
   void              DrawPatterns(const bool redraw=false);
   
//--- Защищённый параметрический конструктор
protected:
                     CPatternControl(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_PATTERN_STATUS status,const ENUM_PATTERN_TYPE type,CArrayObj *list_series,CArrayObj *list_patterns);
  };

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


В конструкторе класса считаем данные графика и запишем их в новые переменные класса:

//+------------------------------------------------------------------+
//| CPatternControl::Защищённый параметрический конструктор          |
//+------------------------------------------------------------------+
CPatternControl::CPatternControl(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_PATTERN_STATUS status,const ENUM_PATTERN_TYPE type,CArrayObj *list_series,CArrayObj *list_patterns) :
  m_ratio_body_to_candle_size(30),m_ratio_larger_shadow_to_candle_size(60),m_ratio_smaller_shadow_to_candle_size(30),m_used(true),m_drawing(true)
  {
   this.m_type=OBJECT_DE_TYPE_SERIES_PATTERN_CONTROL;
   this.m_type_pattern=type;
   this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol);
   this.m_timeframe=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe);
   this.m_point=::SymbolInfoDouble(this.m_symbol,SYMBOL_POINT);
   this.m_object_id=0;
   this.m_list_series=list_series;
   this.m_list_all_patterns=list_patterns;
   for(int i=0;i<(int)this.m_symbol.Length();i++)
      this.m_symbol_code+=this.m_symbol.GetChar(i);
   this.m_chart_scale=(int)::ChartGetInteger(this.m_chart_id,CHART_SCALE);
   this.m_chart_height_px=(int)::ChartGetInteger(this.m_chart_id,CHART_HEIGHT_IN_PIXELS);
   this.m_chart_price_max=::ChartGetDouble(this.m_chart_id,CHART_PRICE_MAX);
   this.m_chart_price_min=::ChartGetDouble(this.m_chart_id,CHART_PRICE_MIN);
  }


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

//+------------------------------------------------------------------+
//| CPatternControl::Ищет паттерны и добавляет                       |
//| найденные в список всех паттернов                                |
//+------------------------------------------------------------------+
int CPatternControl::CreateAndRefreshPatternList(const uint min_body_size)
  {
//--- Если не используется - уходим
   if(!this.m_used)
      return 0;
//--- Сбрасываем флаг события таймсерии и очищаем список всех событий паттернов таймсерии
   this.m_is_event=false;
   this.m_list_events.Clear();
//--- Получаем дату открытия последнего (текущего) бара
   datetime time_open=0;
   if(!::SeriesInfoInteger(this.Symbol(),this.Timeframe(),SERIES_LASTBAR_DATE,time_open))
      return 0;
//--- Получаем список всех баров таймсерии кроме текущего
   CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,time_open,LESS);
   if(list==NULL || list.Total()==0)
      return 0;
//--- Структура данных "материнского" бара
   MqlRates pattern_mother_bar_data={};
//--- Сортируем полученный список по времени открытия баров
   list.Sort(SORT_BY_BAR_TIME);
//--- В цикле от самого позднего бара
   for(int i=list.Total()-1;i>=0;i--)
     {
      //--- получаем очередной объект-бар из списка
      CBar *bar=list.At(i);
      if(bar==NULL)
         continue;
      //--- ищем паттерн относительно полученного бара
      ENUM_PATTERN_DIRECTION direction=this.FindPattern(bar.Time(),min_body_size,pattern_mother_bar_data);
      //--- Если паттерна нет - идём к следующему бару
      if(direction==WRONG_VALUE)
         continue;
         
      //--- Паттерн на текущем баре цикла найден
      //--- уникальный код паттерна = время открытия свечи + тип + статус + направление паттерна + таймфрейм + символ таймсерии
      ulong code=this.GetPatternCode(direction,bar.Time());
      //--- Устанавливаем в образец код паттерна
      this.m_pattern_instance.SetProperty(PATTERN_PROP_CODE,code);
      //--- Сортируем список всех паттернов по уникальному коду паттерна
      this.m_list_all_patterns.Sort(SORT_BY_PATTERN_CODE);
      //--- ищем паттерн в списке по уникальному коду
      int index=this.m_list_all_patterns.Search(&this.m_pattern_instance);
      //--- Если в списке всех паттернов нет паттерна, равного образцу
      if(index==WRONG_VALUE)
        {
         //--- Создаём объект-паттерн
         CPattern *pattern=this.CreatePattern(direction,this.m_list_all_patterns.Total(),bar);
         if(pattern==NULL)
            continue;
         //--- Сортируем список всех паттернов по времени и вставляем паттерн в список по его времени
         this.m_list_all_patterns.Sort(SORT_BY_PATTERN_TIME);
         if(!this.m_list_all_patterns.InsertSort(pattern))
           {
            delete pattern;
            continue;
           }
         //--- Добавляем паттерн в список паттернов объекта-бара
         bar.AddPattern(pattern.TypePattern());
         //--- В объект-паттерн добавляем указатель на бар, на котором он найден, и данные материнского бара
         pattern.SetPatternBar(bar);
         pattern.SetMotherBarData(pattern_mother_bar_data);
         //--- устанавливаем в объект-паттерн данные графика
         pattern.SetChartHeightInPixels(this.m_chart_height_px);
         pattern.SetChartScale(this.m_chart_scale);
         pattern.SetChartPriceMax(this.m_chart_price_max);
         pattern.SetChartPriceMin(this.m_chart_price_min);
         //--- Если стоит флаг рисования - рисуем метку паттерна на графике
         if(this.m_drawing)
            pattern.Draw(false);
        }
     }
//--- Сортируем список всех паттернов по времени и возвращаем общее количество паттернов в списке
   this.m_list_all_patterns.Sort(SORT_BY_PATTERN_TIME);
   return m_list_all_patterns.Total();
  }

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


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

//+------------------------------------------------------------------+
//| Устанавливает флаг рисования значков паттерна в виде точек       |
//+------------------------------------------------------------------+
void CPatternControl::SetDrawingAsDots(const bool flag,const bool redraw)
  {
   this.m_draw_dots=flag;
//--- Получаем список паттернов, управляемых данным объектом управления
   CArrayObj *list=this.GetListPatterns();
   if(list==NULL || list.Total()==0)
      return;
//--- В цикле по списку паттернов
   for(int i=list.Total()-1;i>=0;i--)
     {
      //--- получаем очередной объект-паттерн
      CPattern *obj=list.At(i);
      if(obj==NULL)
         continue;
      //--- Устанавливаем значение флага и, если false - удаляем объект-точку паттерна
      obj.SetDrawAsDots(flag);
      if(!flag)
         obj.DeleteGraphObj();
      //--- Отображаем метку паттерна на графике, если флаг true
      else
         obj.Draw(false);
     }
//--- По окончании цикла, если установлен флаг, перерисовываем график
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }

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


Далее нужно доработать класс управления паттерном "Пин бар". В метод поиска паттерна добавим переменную MqlRates для записи данных о материнском баре:

//+------------------------------------------------------------------+
//| Класс управления паттерном "Пин бар"                             |
//+------------------------------------------------------------------+
class CPatternControlPinBar : public CPatternControl
  {
protected:
//--- (1) Ищет паттерн, возвращает направление (или -1),
//--- (2) создаёт паттерн с указанным направлением,
//--- (3) создаёт и возвращает уникальный код паттерна
//--- (4) возвращает список паттернов, управляемых этим объектом
   virtual ENUM_PATTERN_DIRECTION FindPattern(const datetime series_bar_time,const uint min_body_size,MqlRates &mother_bar_data) const;
   virtual CPattern *CreatePattern(const ENUM_PATTERN_DIRECTION direction,const uint id,CBar *bar);
   virtual ulong     GetPatternCode(const ENUM_PATTERN_DIRECTION direction,const datetime time) const
                       {
                        //--- уникальный код паттерна = время открытия свечи + тип + статус + направление паттерна + таймфрейм + символ таймсерии
                        return(time+PATTERN_TYPE_PIN_BAR+PATTERN_STATUS_PA+direction+this.Timeframe()+this.m_symbol_code);
                       }
   virtual CArrayObj*GetListPatterns(void);
//--- Создаёт идентификатор объекта на основе критериев поиска паттерна
   virtual ulong     CreateObjectID(void);

public:
//--- Параметрический конструктор
                     CPatternControlPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                           CArrayObj *list_series,CArrayObj *list_patterns,
                                           const double ratio_body_to_candle_size,
                                           const double ratio_larger_shadow_to_candle_size,
                                           const double ratio_smaller_shadow_to_candle_size) :
                        CPatternControl(symbol,timeframe,PATTERN_STATUS_PA,PATTERN_TYPE_PIN_BAR,list_series,list_patterns)
                       {
                        this.m_ratio_body_to_candle_size=ratio_body_to_candle_size;
                        this.m_ratio_larger_shadow_to_candle_size=ratio_larger_shadow_to_candle_size;
                        this.m_ratio_smaller_shadow_to_candle_size=ratio_smaller_shadow_to_candle_size;
                        this.m_object_id=this.CreateObjectID();
                       }
  };


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

//+------------------------------------------------------------------+
//| CPatternControlPinBar::Создаёт паттерн с указанным направлением  |
//+------------------------------------------------------------------+
CPattern *CPatternControlPinBar::CreatePattern(const ENUM_PATTERN_DIRECTION direction,const uint id,CBar *bar)
  {
//--- Если передан невалидный указатель на объект-бар - возвращаем NULL
   if(bar==NULL)
      return NULL;
//--- Заполняем структуру MqlRates данными бара
   MqlRates rates={0};
   this.SetBarData(bar,rates);
//--- Создаём новый паттерн Пин-Бар
   CPatternPinBar *obj=new CPatternPinBar(id,this.Symbol(),this.Timeframe(),rates,direction);
   if(obj==NULL)
      return NULL;
//--- устанавливаем в свойства созданного объекта-паттерна пропорции свечи, на которой найден паттерн
   obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE,bar.RatioBodyToCandleSize());
   obj.SetProperty(PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,bar.RatioLowerShadowToCandleSize());
   obj.SetProperty(PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,bar.RatioUpperShadowToCandleSize());
//--- устанавливаем в свойства созданного объекта-паттерна критерии поиска свечи, на которой найден паттерн
   obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,this.RatioBodyToCandleSizeValue());
   obj.SetProperty(PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioLargerShadowToCandleSizeValue());
   obj.SetProperty(PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioSmallerShadowToCandleSizeValue());
//--- Устанавливаем объекту-паттерну идентификатор объекта управления
   obj.SetProperty(PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID());
//--- Возвращаем указатель на созданный объект
   return obj;
  }

Ранее здесь мы вписывали данные поэлементно. Теперь эта поэлементная запись производится в методе SetBarData(), что одно и то же, но код метода короче.


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

//+------------------------------------------------------------------+
//| CPatternControlPinBar::Ищет паттерн                              |
//+------------------------------------------------------------------+
ENUM_PATTERN_DIRECTION CPatternControlPinBar::FindPattern(const datetime series_bar_time,const uint min_body_size,MqlRates &mother_bar_data) const
  {
//--- Получаем данные одного бара по времени
   CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,series_bar_time,EQUAL);
//--- Если список пустой - возвращаем -1
   if(list==NULL || list.Total()==0)
      return WRONG_VALUE;
//--- Размер тела свечи должен быть меньше, либо равен RatioBodyToCandleSizeValue() (по умолчанию 30%) размера всей свечи,
//--- при этом размер тела не должен быть меньше min_body_size
   list=CSelect::ByBarProperty(list,BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,this.RatioBodyToCandleSizeValue(),EQUAL_OR_LESS);
   list=CSelect::ByBarProperty(list,BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,min_body_size,EQUAL_OR_MORE);
//--- Если список пустой - паттернов нет, возвращаем -1
   if(list==NULL || list.Total()==0)
      return WRONG_VALUE;
      
//--- Определяем бычий паттерн
//--- Нижняя тень должна быть равна, либо больше RatioLargerShadowToCandleSizeValue() (по умолчанию 60%) размера всей свечи
   CArrayObj *list_bullish=CSelect::ByBarProperty(list,BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.RatioLargerShadowToCandleSizeValue(),EQUAL_OR_MORE);
//--- Верхняя тень должна быть меньше, либо равна RatioSmallerShadowToCandleSizeValue() (по умолчанию 30%) размера всей свечи
   list_bullish=CSelect::ByBarProperty(list_bullish,BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.RatioSmallerShadowToCandleSizeValue(),EQUAL_OR_LESS);
//--- Если паттерн на баре найден
   if(list_bullish!=NULL && list_bullish.Total()>0)
     {
      CBar *bar=list.At(list_bullish.Total()-1);
      if(bar!=NULL)
        {
         this.SetBarData(bar,mother_bar_data);
         return PATTERN_DIRECTION_BULLISH;
        }
     }

//--- Определяем медвежий паттерн
//--- Верхняя тень должна быть равна, либо больше RatioLargerShadowToCandleSizeValue() (по умолчанию 60%) размера всей свечи
   CArrayObj *list_bearish=CSelect::ByBarProperty(list,BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.RatioLargerShadowToCandleSizeValue(),EQUAL_OR_MORE);
//--- Нижняя тень должна быть меньше, либо равна RatioSmallerShadowToCandleSizeValue() (по умолчанию 30%) размера всей свечи
   list_bearish=CSelect::ByBarProperty(list_bearish,BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.RatioSmallerShadowToCandleSizeValue(),EQUAL_OR_LESS);
//--- Если паттерн на баре найден
   if(list_bearish!=NULL && list_bearish.Total()>0)
     {
      CBar *bar=list.At(list_bearish.Total()-1);
      if(bar!=NULL)
        {
         this.SetBarData(bar,mother_bar_data);
         return PATTERN_DIRECTION_BEARISH;
        }
     }
//--- Паттернов не найдено - возвращаем -1
   return WRONG_VALUE;
  }

Так как "Пин Бар" — это однобаровая формация, то материнский бар является одновременно и определяющим баром, на котором найден паттерн.


Создадим класс управления паттерном "Внутренний Бар". Структура этого паттерна строго определена, и не имеет иных параметров, кроме того, что определяющий бар (бар справа) должен быть полностью расположен внутри материнского бара (бар слева). Иных параметров нет. Поэтому любой паттерн "Внутренний Бар" — это единственный паттерн на одной таймсерии в отличие от паттерна "Пин Бар", в котором мы можем задать параметры его поиска, и паттернов "Пин Бар" может быть несколько с разными параметрами на одной таймсерии, и для каждого такого паттерна создаётся собственный объект управления. Для паттерна "Внутренний Бар", исходя из вышесказанного, будет всегда создаваться только по одному объекту управления для каждой таймсерии.

Впишем в том же файле, после класса управления паттерном "Пин Бар" новый класс управления паттерном "Внутренний Бар":

//+------------------------------------------------------------------+
//| Класс управления паттерном "Внутренний бар"                      |
//+------------------------------------------------------------------+
class CPatternControlInsideBar : public CPatternControl
  {
private:
//--- Проверяет и возвращает факт наличия паттерна на двух соседних барах
   bool              CheckInsideBar(const CBar *bar1,const CBar *bar0) const
                       {
                        //--- Если переданы пустые объекты-бары - возвращаем false
                        if(bar0==NULL || bar1==NULL)
                           return false;
                        //--- Возвращаем факт того, что бар справа полностью находится внутри размеров бара слева
                        return(bar0.High()<bar1.High() && bar0.Low()>bar1.Low());
                       }
   bool              FindMotherBar(CArrayObj *list,MqlRates &rates) const
                       {
                        bool res=false;
                        if(list==NULL)
                           return false;
                        //--- В цикле по списку, начиная с бара слева от определяющего
                        for(int i=list.Total()-2;i>0;i--)
                          {
                           //--- Получаем указатели на два подряд идущих бара
                           CBar *bar0=list.At(i);
                           CBar *bar1=list.At(i-1);
                           if(bar0==NULL || bar1==NULL)
                              return false;
                           //--- Если полученные бары представляют паттерн
                           if(CheckInsideBar(bar1,bar0))
                             {
                              //--- записываем в переменную MqlRates данные материнского бара и записываем в res значение true
                              this.SetBarData(bar1,rates);
                              res=true;
                             }
                           //--- Если паттерна нет - прерываем цикл
                           else
                              break;
                          }
                        //--- возвращаем результат
                        return res;
                       }
protected:
//--- (1) Ищет паттерн, возвращает направление (или -1),
//--- (2) создаёт паттерн с указанным направлением,
//--- (3) создаёт и возвращает уникальный код паттерна
//--- (4) возвращает список паттернов, управляемых этим объектом
   virtual ENUM_PATTERN_DIRECTION FindPattern(const datetime series_bar_time,const uint min_body_size,MqlRates &mother_bar_data) const;
   virtual CPattern *CreatePattern(const ENUM_PATTERN_DIRECTION direction,const uint id,CBar *bar);
   virtual ulong     GetPatternCode(const ENUM_PATTERN_DIRECTION direction,const datetime time) const
                       {
                        //--- уникальный код паттерна = время открытия свечи + тип + статус + направление паттерна + таймфрейм + символ таймсерии
                        return(time+PATTERN_TYPE_INSIDE_BAR+PATTERN_STATUS_PA+PATTERN_DIRECTION_BOTH+this.Timeframe()+this.m_symbol_code);
                       }
   virtual CArrayObj*GetListPatterns(void);
//--- Создаёт идентификатор объекта на основе критериев поиска паттерна
   virtual ulong     CreateObjectID(void);

public:
//--- Параметрический конструктор
                     CPatternControlInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                              CArrayObj *list_series,CArrayObj *list_patterns) :
                        CPatternControl(symbol,timeframe,PATTERN_STATUS_PA,PATTERN_TYPE_INSIDE_BAR,list_series,list_patterns)
                       {
                        this.m_ratio_body_to_candle_size=0;
                        this.m_ratio_larger_shadow_to_candle_size=0;
                        this.m_ratio_smaller_shadow_to_candle_size=0;
                        this.m_object_id=this.CreateObjectID();
                       }
  };

Класс является практически копией класса управления паттерном "Пин Бар", который был рассмотрен в предыдущей статье по паттернам библиотеки. В конструкторе класса устанавливаем все критерии поиска паттерна в ноль, так как они здесь не используются. А идентификатор объекта всегда равен нулю потому, что это единственный объект на одной таймсерии:

//+------------------------------------------------------------------+
//| Создаёт идентификатор объекта на основе критериев поиска паттерна|
//+------------------------------------------------------------------+
ulong CPatternControlInsideBar::CreateObjectID(void)
  {
   return 0;
  }


Основными методами для поиска паттерна являются метод сравнения двух соседних баров на наличие паттерна и метод для поиска материнского бара:

//--- Проверяет и возвращает факт наличия паттерна на двух соседних барах
   bool              CheckInsideBar(const CBar *bar1,const CBar *bar0) const
                       {
                        //--- Если переданы пустые объекты-бары - возвращаем false
                        if(bar0==NULL || bar1==NULL)
                           return false;
                        //--- Возвращаем факт того, что бар справа полностью находится внутри размеров бара слева
                        return(bar0.High()<bar1.High() && bar0.Low()>bar1.Low());
                       }
   bool              FindMotherBar(CArrayObj *list,MqlRates &rates) const
                       {
                        bool res=false;
                        if(list==NULL)
                           return false;
                        //--- В цикле по списку, начиная с бара слева от определяющего
                        for(int i=list.Total()-2;i>0;i--)
                          {
                           //--- Получаем указатели на два подряд идущих бара
                           CBar *bar0=list.At(i);
                           CBar *bar1=list.At(i-1);
                           if(bar0==NULL || bar1==NULL)
                              return false;
                           //--- Если полученные бары представляют паттерн
                           if(CheckInsideBar(bar1,bar0))
                             {
                              //--- записываем в переменную MqlRates данные материнского бара и записываем в res значение true
                              this.SetBarData(bar1,rates);
                              res=true;
                             }
                           //--- Если паттерна нет - прерываем цикл
                           else
                              break;
                          }
                        //--- возвращаем результат
                        return res;
                       }

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

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


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

//+------------------------------------------------------------------+
//|CPatternControlInsideBar::Создаёт паттерн с указанным направлением|
//+------------------------------------------------------------------+
CPattern *CPatternControlInsideBar::CreatePattern(const ENUM_PATTERN_DIRECTION direction,const uint id,CBar *bar)
  {
//--- Если передан невалидный указатель на объект-бар - возвращаем NULL
   if(bar==NULL)
      return NULL;
//--- Заполняем структуру MqlRates данными бара
   MqlRates rates={0};
   this.SetBarData(bar,rates);
//--- Создаём новый паттерн Внутренний бар
   CPatternInsideBar *obj=new CPatternInsideBar(id,this.Symbol(),this.Timeframe(),rates,PATTERN_DIRECTION_BOTH);
   if(obj==NULL)
      return NULL;
//--- устанавливаем в свойства созданного объекта-паттерна пропорции свечи, на которой найден паттерн
   obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE,bar.RatioBodyToCandleSize());
   obj.SetProperty(PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,bar.RatioLowerShadowToCandleSize());
   obj.SetProperty(PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,bar.RatioUpperShadowToCandleSize());
//--- устанавливаем в свойства созданного объекта-паттерна критерии поиска свечи, на которой найден паттерн
   obj.SetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,this.RatioBodyToCandleSizeValue());
   obj.SetProperty(PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioLargerShadowToCandleSizeValue());
   obj.SetProperty(PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION,this.RatioSmallerShadowToCandleSizeValue());
//--- Устанавливаем объекту-паттерну идентификатор объекта управления
   obj.SetProperty(PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID());
//--- Возвращаем указатель на созданный объект
   return obj;
  }

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


Метод, для поиска паттерна:

//+------------------------------------------------------------------+
//| CPatternControlInsideBar::Ищет паттерн                           |
//+------------------------------------------------------------------+
ENUM_PATTERN_DIRECTION CPatternControlInsideBar::FindPattern(const datetime series_bar_time,const uint min_body_size,MqlRates &mother_bar_data) const
  {
//--- Получаем данные баров до указанного времени включительно
   CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,series_bar_time,EQUAL_OR_LESS);
//--- Если список пустой - возвращаем -1
   if(list==NULL || list.Total()==0)
      return WRONG_VALUE;
//--- Сортируем список по времени открытия баров
   list.Sort(SORT_BY_BAR_TIME);
//--- Получаем самый поздний бар из списка (определяющий бар)
   CBar *bar_patt=list.At(list.Total()-1);
   if(bar_patt==NULL)
      return WRONG_VALUE;
//--- В цикле от следующего бара (материнский)
   for(int i=list.Total()-2;i>=0;i--)
     {
      CBar *bar_prev=list.At(i);
      if(bar_prev==NULL)
         return WRONG_VALUE;
      //--- проверяем что полученные два бара являются паттерном. Если нет - возвращаем -1
      if(!this.CheckInsideBar(bar_prev,bar_patt))
         return WRONG_VALUE;
      //--- Если на прошлом шаге паттерн найден - ищем вложенные паттерны.
      //--- Самый левый бар будет материнским для всей цепочки вложенных паттернов
      //--- Если у найденного паттерна нет вложенных, то его материнским баром будет текущий бар цикла (слева от определяющего)
      if(!this.FindMotherBar(list,mother_bar_data))
         SetBarData(bar_prev,mother_bar_data);
//--- Возвращаем направление паттерна (двунаправлененый)
      return PATTERN_DIRECTION_BOTH;
     }
//--- Паттернов не найдено - возвращаем -1
   return WRONG_VALUE;
  }

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


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

//+------------------------------------------------------------------+
//| Возвращает список паттернов, управляемых этим объектом           |
//+------------------------------------------------------------------+
CArrayObj *CPatternControlInsideBar::GetListPatterns(void)
  {
   CArrayObj *list=CSelect::ByPatternProperty(this.m_list_all_patterns,PATTERN_PROP_PERIOD,this.Timeframe(),EQUAL);
   list=CSelect::ByPatternProperty(list,PATTERN_PROP_SYMBOL,this.Symbol(),EQUAL);
   list=CSelect::ByPatternProperty(list,PATTERN_PROP_TYPE,PATTERN_TYPE_INSIDE_BAR,EQUAL);
   return CSelect::ByPatternProperty(list,PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID(),EQUAL);
  }


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

//--- Возвращает объект управления паттерном Внутренний бар
   CPatternControl  *GetObjControlPatternInsideBar(void)
                       {
                        int total=this.m_list_controls.Total();
                        for(int i=0;i<total;i++)
                          {
                           CPatternControl *obj=this.m_list_controls.At(i);
                           if(obj==NULL)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           if(obj.TypePattern()==PATTERN_TYPE_INSIDE_BAR)
                              return obj;
                          }
                        return NULL;
                       }

Ранее метод возвращал NULL, так как ещё не был сделан класс возвращаемого методом объекта.


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

//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternInsideBar(const bool flag)
                       {
                        //--- Получаем указатель на объект управления паттерном Внутренний бар
                        CPatternControlInsideBar *obj=this.GetObjControlPatternInsideBar();
                        //--- Если указатель получен (объект существует) - устанавливаем флаг использования
                        if(obj!=NULL)
                           obj.SetUsed(flag);
                        //--- Если объекта нет, а флаг передан как true
                        else if(flag)
                          {
                           //--- Создаём новый объект управления паттернами Внутренний бар
                           obj=new CPatternControlInsideBar(this.Symbol(),this.Timeframe(),this.m_list_series,this.m_list_all_patterns);
                           if(obj==NULL)
                              return;
                           //--- Добавляем указатель на созданный объект в список
                           if(!this.m_list_controls.Add(obj))
                             {
                              delete obj;
                              return;
                             }
                           //--- Устанавливаем флаг использования и параметры паттерна в объект управления
                           obj.SetUsed(flag);
                           obj.SetRatioBodyToCandleSizeValue(0);
                           obj.SetRatioLargerShadowToCandleSizeValue(0);
                           obj.SetRatioSmallerShadowToCandleSizeValue(0);
                           obj.CreateAndRefreshPatternList(0);
                          }
                       }

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


Напишем методы установки флага рисования паттерна точками:

//+------------------------------------------------------------------+
//| Методы установки флага рисования паттерна точками                |
//+------------------------------------------------------------------+
//--- Устанавливает флаг рисования точками паттерна Харами
   void              SetDrawingAsDotsPatternHarami(const bool flag,const bool redraw)
                       {
                        
                       }
//--- Устанавливает флаг рисования точками паттерна Крест харами
   void              SetDrawingAsDotsPatternHaramiCross(const bool flag,const bool redraw)
                       {
                        
                       }
//--- Устанавливает флаг рисования точками паттерна Пинцет
   void              SetDrawingAsDotsPatternTweezer(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Просвет в облаках
   void              SetDrawingAsDotsPatternPiercingLine(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Завеса из темных облаков
   void              SetDrawingAsDotsPatternDarkCloudCover(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Три белых солдата
   void              SetDrawingAsDotsPatternThreeWhiteSoldiers(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Три черные вороны
   void              SetDrawingAsDotsPatternThreeBlackCrows(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Падающая звезда
   void              SetDrawingAsDotsPatternShootingStar(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Молот
   void              SetDrawingAsDotsPatternHammer(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Перевёрнутый молот
   void              SetDrawingAsDotsPatternInvertedHammer(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Повешенный
   void              SetDrawingAsDotsPatternHangingMan(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Доджи
   void              SetDrawingAsDotsPatternDoji(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Доджи стрекоза
   void              SetDrawingAsDotsPatternDragonflyDoji(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Доджи надгробие
   void              SetDrawingAsDotsPatternGravestoneDoji(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Утренняя звезда
   void              SetDrawingAsDotsPatternMorningStar(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Утренняя доджи-звезда
   void              SetDrawingAsDotsPatternMorningDojiStar(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Вечерняя звезда
   void              SetDrawingAsDotsPatternEveningStar(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Вечерняя доджи-звезда
   void              SetDrawingAsDotsPatternEveningDojiStar(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Три звезды
   void              SetDrawingAsDotsPatternThreeStars(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Брошенное дитя
   void              SetDrawingAsDotsPatternAbandonedBaby(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Pivot Point Reversal
//--- Price Action
   void              SetDrawingAsDotsPatternPivotPointReversal(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Внешний бар (Поглощение)
   void              SetDrawingAsDotsPatternOutsideBar(const bool flag,const bool redraw)
                       {
                       
                       }
//--- Устанавливает флаг рисования точками паттерна Внутренний бар
   void              SetDrawingAsDotsPatternInsideBar(const bool flag,const bool redraw)
                       {
                        //--- Получаем указатель на объект управления паттерном Внутренний бар
                        CPatternControlInsideBar *obj=this.GetObjControlPatternInsideBar();
                        //--- Если указатель получен (объект существует) - устанавливаем флаг рисования
                        if(obj!=NULL)
                           obj.SetDrawingAsDots(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Пин бар
   void              SetDrawingAsDotsPatternPinBar(const bool flag,const bool redraw,  // Флаг рисования точкой и флаг перерисовки Price Action Пин бар
                                          const double ratio_body=30,                  // Процентное отношение тела свечи к полному размеру свечи
                                          const double ratio_larger_shadow=60,         // Процентное отношение размера большей тени к размеру свечи
                                          const double ratio_smaller_shadow=30)        // Процентное отношение размера меньшей тени к размеру свечи
                       {
                        //--- Получаем указатель на объект управления паттерном Пин-Бар с указанными параметрами
                        CPatternControlPinBar *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        //--- Если указатель получен (объект существует) - устанавливаем флаг использования
                        if(obj!=NULL)
                           obj.SetDrawingAsDots(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Рельсы
   void              SetDrawingAsDotsPatternRails(const bool flag,const bool redraw)
                       {
                       
                       }

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


Напишем методы возврата флага рисования паттерна точками:

//+------------------------------------------------------------------+
//| Методы возврата флага рисования паттерна точками                 |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг рисования точками паттерна Харами
   bool              IsDrawingAsDotsPatternHarami(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHarami();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Крест харами
   bool              IsDrawingAsDotsPatternHaramiCross(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHaramiCross();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Пинцет
   bool              IsDrawingAsDotsPatternTweezer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternTweezer();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Просвет в облаках
   bool              IsDrawingAsDotsPatternPiercingLine(void)
                       {
                        CPatternControl *obj=GetObjControlPatternPiercingLine();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Завеса из темных облаков
   bool              IsDrawingAsDotsPatternDarkCloudCover(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDarkCloudCover();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Три белых солдата
   bool              IsDrawingAsDotsPatternThreeWhiteSoldiers(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeWhiteSoldiers();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Три черные вороны
   bool              IsDrawingAsDotsPatternThreeBlackCrows(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeBlackCrows();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Падающая звезда
   bool              IsDrawingAsDotsPatternShootingStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternShootingStar();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Молот
   bool              IsDrawingAsDotsPatternHammer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHammer();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Перевёрнутый молот
   bool              IsDrawingAsDotsPatternInvertedHammer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternInvertedHammer();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Повешенный
   bool              IsDrawingAsDotsPatternHangingMan(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHangingMan();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Доджи
   bool              IsDrawingAsDotsPatternDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDoji();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Доджи стрекоза
   bool              IsDrawingAsDotsPatternDragonflyDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDragonflyDoji();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Доджи надгробие
   bool              IsDrawingAsDotsPatternGravestoneDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternGravestoneDoji();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Утренняя звезда
   bool              IsDrawingAsDotsPatternMorningStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningStar();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Утренняя доджи-звезда
   bool              IsDrawingAsDotsPatternMorningDojiStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningDojiStar();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Вечерняя звезда
   bool              IsDrawingAsDotsPatternEveningStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningStar();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Вечерняя доджи-звезда
   bool              IsDrawingAsDotsPatternEveningDojiStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningDojiStar();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Три звезды
   bool              IsDrawingAsDotsPatternThreeStars(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeStars();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Брошенное дитя
   bool              IsDrawingAsDotsPatternAbandonedBaby(void)
                       {
                        CPatternControl *obj=GetObjControlPatternAbandonedBaby();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Price Action
//--- Возвращает флаг рисования точками паттерна Pivot Point Reversal
   bool              IsDrawingAsDotsPatternPivotPointReversal(void)
                       {
                        CPatternControl *obj=GetObjControlPatternPivotPointReversal();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Внешний бар (Поглощение)
   bool              IsDrawingAsDotsPatternOutsideBar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternOutsideBar();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Внутренний бар
   bool              IsDrawingAsDotsPatternInsideBar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternInsideBar();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Пин бар
   bool              IsDrawingAsDotsPatternPinBar(const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                                  const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                                  const double ratio_smaller_shadow=30)   // Процентное отношение размера меньшей тени к размеру свечи
                       {
                        //--- Получаем объект управления паттерна по его параметрам
                        CPatternControl *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        //--- Возвращаем флаг использования паттерна, либо false, если объект не найден
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Рельсы
   bool              IsDrawingAsDotsPatternRails(void)
                       {
                        CPatternControl *obj=GetObjControlPatternRails();
                        return(obj!=NULL ? obj.IsDrawingAsDots() : false);
                       }

Для метода, возвращающего флаг рисования точками паттерна Пин Бар написаны входные параметры, так как все методы для работы с этим паттерном их имеют. Остальные методы пока возвращают флаги рисования точками без каких-либо параметров. Если для какого-то паттерна нужны будут параметры, то в такие методы их потом впишем.


Теперь точно такие же методы нужно написать для класса-таймсерии, расположенном в этом же файле:

//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternInsideBar(const bool flag)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetUsedPatternInsideBar(flag);
                       }

...

//+------------------------------------------------------------------+
//| Методы установки флага рисования паттерна точками                |
//+------------------------------------------------------------------+
//--- Устанавливает флаг рисования точками паттерна Харами
   void              SetDrawingAsDotsPatternHarami(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternHarami(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Крест харами
   void              SetDrawingAsDotsPatternHaramiCross(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternHaramiCross(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Пинцет
   void              SetDrawingAsDotsPatternTweezer(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternTweezer(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Просвет в облаках
   void              SetDrawingAsDotsPatternPiercingLine(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternPiercingLine(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Завеса из темных облаков
   void              SetDrawingAsDotsPatternDarkCloudCover(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternDarkCloudCover(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Три белых солдата
   void              SetDrawingAsDotsPatternThreeWhiteSoldiers(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternThreeWhiteSoldiers(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Три черные вороны
   void              SetDrawingAsDotsPatternThreeBlackCrows(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternThreeBlackCrows(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Падающая звезда
   void              SetDrawingAsDotsPatternShootingStar(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternShootingStar(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Молот
   void              SetDrawingAsDotsPatternHammer(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternHammer(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Перевёрнутый молот
   void              SetDrawingAsDotsPatternInvertedHammer(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternInvertedHammer(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Повешенный
   void              SetDrawingAsDotsPatternHangingMan(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternHangingMan(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Доджи
   void              SetDrawingAsDotsPatternDoji(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternDoji(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Доджи стрекоза
   void              SetDrawingAsDotsPatternDragonflyDoji(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternDragonflyDoji(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Доджи надгробие
   void              SetDrawingAsDotsPatternGravestoneDoji(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternGravestoneDoji(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Утренняя звезда
   void              SetDrawingAsDotsPatternMorningStar(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternMorningStar(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Утренняя доджи-звезда
   void              SetDrawingAsDotsPatternMorningDojiStar(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternMorningDojiStar(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Вечерняя звезда
   void              SetDrawingAsDotsPatternEveningStar(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternEveningStar(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Вечерняя доджи-звезда
   void              SetDrawingAsDotsPatternEveningDojiStar(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternEveningDojiStar(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Три звезды
   void              SetDrawingAsDotsPatternThreeStars(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternThreeStars(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Брошенное дитя
   void              SetDrawingAsDotsPatternAbandonedBaby(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternAbandonedBaby(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Pivot Point Reversal
//--- Price Action
   void              SetDrawingAsDotsPatternPivotPointReversal(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternPivotPointReversal(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Внешний бар (Поглощение)
   void              SetDrawingAsDotsPatternOutsideBar(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternOutsideBar(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Внутренний бар
   void              SetDrawingAsDotsPatternInsideBar(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternInsideBar(flag,redraw);
                       }
//--- Устанавливает флаг рисования точками паттерна Пин бар
   void              SetDrawingAsDotsPatternPinBar(const bool flag,const bool redraw,     // Флаг рисования точкой и флаг перерисовки Price Action Пин бар
                                                   const double ratio_body=30,            // Процентное отношение тела свечи к полному размеру свечи
                                                   const double ratio_larger_shadow=60,   // Процентное отношение размера большей тени к размеру свечи
                                                   const double ratio_smaller_shadow=30)  // Процентное отношение размера меньшей тени к размеру свечи
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternPinBar(flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                       }
//--- Устанавливает флаг рисования точками паттерна Рельсы
   void              SetDrawingAsDotsPatternRails(const bool flag,const bool redraw)
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetDrawingAsDotsPatternRails(flag,redraw);
                       }
                       
//+------------------------------------------------------------------+
//| Методы возврата флага рисования паттерна точками                 |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг рисования точками паттерна Харами
   bool              IsDrawingAsDotsPatternHarami(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHarami() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Крест харами
   bool              IsDrawingAsDotsPatternHaramiCross(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHaramiCross() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Пинцет
   bool              IsDrawingAsDotsPatternTweezer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternTweezer() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Просвет в облаках
   bool              IsDrawingAsDotsPatternPiercingLine(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternPiercingLine() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Завеса из темных облаков
   bool              IsDrawingAsDotsPatternDarkCloudCover(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternDarkCloudCover() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Три белых солдата
   bool              IsDrawingAsDotsPatternThreeWhiteSoldiers(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternThreeWhiteSoldiers() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Три черные вороны
   bool              IsDrawingAsDotsPatternThreeBlackCrows(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternThreeBlackCrows() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Падающая звезда
   bool              IsDrawingAsDotsPatternShootingStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternShootingStar() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Молот
   bool              IsDrawingAsDotsPatternHammer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHammer() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Перевёрнутый молот
   bool              IsDrawingAsDotsPatternInvertedHammer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternInvertedHammer() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Повешенный
   bool              IsDrawingAsDotsPatternHangingMan(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternHangingMan() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Доджи
   bool              IsDrawingAsDotsPatternDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternDoji() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Доджи стрекоза
   bool              IsDrawingAsDotsPatternDragonflyDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternDragonflyDoji() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Доджи надгробие
   bool              IsDrawingAsDotsPatternGravestoneDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternGravestoneDoji() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Утренняя звезда
   bool              IsDrawingAsDotsPatternMorningStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternMorningStar() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Утренняя доджи-звезда
   bool              IsDrawingAsDotsPatternMorningDojiStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternMorningDojiStar() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Вечерняя звезда
   bool              IsDrawingAsDotsPatternEveningStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternEveningStar() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Вечерняя доджи-звезда
   bool              IsDrawingAsDotsPatternEveningDojiStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternEveningDojiStar() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Три звезды
   bool              IsDrawingAsDotsPatternThreeStars(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternThreeStars() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Брошенное дитя
   bool              IsDrawingAsDotsPatternAbandonedBaby(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternAbandonedBaby() : false);
                       }
//--- Price Action
//--- Возвращает флаг рисования точками паттерна Pivot Point Reversal
   bool              IsDrawingAsDotsPatternPivotPointReversal(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternPivotPointReversal() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Внешний бар (Поглощение)
   bool              IsDrawingAsDotsPatternOutsideBar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternOutsideBar() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Внутренний бар
   bool              IsDrawingAsDotsPatternInsideBar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternInsideBar() : false);
                       }
//--- Возвращает флаг рисования точками паттерна Пин бар
   bool              IsDrawingAsDotsPatternPinBar(const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                                  const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                                  const double ratio_smaller_shadow=30)   // Процентное отношение размера меньшей тени к размеру свечи
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
                       }
//--- Возвращает флаг рисования точками паттерна Рельсы
   bool              IsDrawingAsDotsPatternRails(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsDrawingAsDotsPatternRails() : false);
                       }


Такие же методы нужно написать в файле \MQL5\Include\DoEasy\Objects\Series\TimeSeriesDE.mqh класса таймсерии символа:

В публичной секции объявим эти методы:

//+------------------------------------------------------------------+
//| Методы установки флага рисования паттерна точками                |
//+------------------------------------------------------------------+
//--- Устанавливает флаг использования паттерна Харами и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Крест харами и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Пинцет и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Просвет в облаках и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Завеса из темных облаков и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Три белых солдата и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Три черные вороны и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Падающая звезда и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Молот и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Перевёрнутый молот и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Повешенный и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Доджи и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Доджи стрекоза и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Доджи надгробие и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Утренняя звезда и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Утренняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Вечерняя звезда и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Вечерняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Три звезды и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Брошенное дитя и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Pivot Point Reversal и создаёт объект управления если его ещё нет
//--- Price Action
   void              SetDrawingAsDotsPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Внешний бар (Поглощение) и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternPinBar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw,  // Флаг рисования точкой и флаг перерисовки Price Action Пин бар
                                          const double ratio_body=30,                  // Процентное отношение тела свечи к полному размеру свечи
                                          const double ratio_larger_shadow=60,         // Процентное отношение размера большей тени к размеру свечи
                                          const double ratio_smaller_shadow=30);       // Процентное отношение размера меньшей тени к размеру свечи
//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void              SetDrawingAsDotsPatternRails(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
                       
//+------------------------------------------------------------------+
//| Методы возврата флага рисования паттерна точками                 |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг использования паттерна Харами
   bool              IsDrawingAsDotsPatternHarami(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Крест харами
   bool              IsDrawingAsDotsPatternHaramiCross(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пинцет
   bool              IsDrawingAsDotsPatternTweezer(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Просвет в облаках
   bool              IsDrawingAsDotsPatternPiercingLine(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Завеса из темных облаков
   bool              IsDrawingAsDotsPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три белых солдата
   bool              IsDrawingAsDotsPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три черные вороны
   bool              IsDrawingAsDotsPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Падающая звезда
   bool              IsDrawingAsDotsPatternShootingStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Молот
   bool              IsDrawingAsDotsPatternHammer(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Перевёрнутый молот
   bool              IsDrawingAsDotsPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Повешенный
   bool              IsDrawingAsDotsPatternHangingMan(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи
   bool              IsDrawingAsDotsPatternDoji(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи стрекоза
   bool              IsDrawingAsDotsPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи надгробие
   bool              IsDrawingAsDotsPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя звезда
   bool              IsDrawingAsDotsPatternMorningStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя доджи-звезда
   bool              IsDrawingAsDotsPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя звезда
   bool              IsDrawingAsDotsPatternEveningStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя доджи-звезда
   bool              IsDrawingAsDotsPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три звезды
   bool              IsDrawingAsDotsPatternThreeStars(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Брошенное дитя
   bool              IsDrawingAsDotsPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe);
//--- Price Action
//--- Возвращает флаг использования паттерна Pivot Point Reversal
   bool              IsDrawingAsDotsPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внешний бар (Поглощение)
   bool              IsDrawingAsDotsPatternOutsideBar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внутренний бар
   bool              IsDrawingAsDotsPatternInsideBar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пин бар
   bool              IsDrawingAsDotsPatternPinBar(const ENUM_TIMEFRAMES timeframe,double ratio_body=30,    // Процентное отношение тела свечи к полному размеру свечи
                                         const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                         const double ratio_smaller_shadow=30);  // Процентное отношение размера меньшей тени к размеру свечи
//--- Возвращает флаг использования паттерна Рельсы
   bool              IsDrawingAsDotsPatternRails(const ENUM_TIMEFRAMES timeframe);
   
//+------------------------------------------------------------------+
//| Методы рисования паттернов на графике                            |
//+------------------------------------------------------------------+


За пределами тела класса напишем реализацию объявленных методов:

//+------------------------------------------------------------------+
//| Методы установки флага рисования паттерна точками                |
//+------------------------------------------------------------------+
//--- Устанавливает флаг рисования точками паттерна Харами
void CTimeSeriesDE::SetDrawingAsDotsPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternHarami(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Крест харами
void CTimeSeriesDE::SetDrawingAsDotsPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternHaramiCross(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Пинцет
void CTimeSeriesDE::SetDrawingAsDotsPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternTweezer(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Просвет в облаках
void CTimeSeriesDE::SetDrawingAsDotsPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternPiercingLine(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Завеса из темных облаков
void CTimeSeriesDE::SetDrawingAsDotsPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternDarkCloudCover(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Три белых солдата
void CTimeSeriesDE::SetDrawingAsDotsPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternThreeWhiteSoldiers(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Три черные вороны
void CTimeSeriesDE::SetDrawingAsDotsPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternThreeBlackCrows(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Падающая звезда
void CTimeSeriesDE::SetDrawingAsDotsPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternShootingStar(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Молот
void CTimeSeriesDE::SetDrawingAsDotsPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternHammer(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Перевёрнутый молот
void CTimeSeriesDE::SetDrawingAsDotsPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternInvertedHammer(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Повешенный
void CTimeSeriesDE::SetDrawingAsDotsPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternHangingMan(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Доджи
void CTimeSeriesDE::SetDrawingAsDotsPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternDoji(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Доджи стрекоза
void CTimeSeriesDE::SetDrawingAsDotsPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternDragonflyDoji(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Доджи надгробие
void CTimeSeriesDE::SetDrawingAsDotsPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternGravestoneDoji(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Утренняя звезда
void CTimeSeriesDE::SetDrawingAsDotsPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternMorningStar(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Утренняя доджи-звезда
void CTimeSeriesDE::SetDrawingAsDotsPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternMorningDojiStar(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Вечерняя звезда
void CTimeSeriesDE::SetDrawingAsDotsPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternEveningStar(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Вечерняя доджи-звезда
void CTimeSeriesDE::SetDrawingAsDotsPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternEveningDojiStar(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Три звезды
void CTimeSeriesDE::SetDrawingAsDotsPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternThreeStars(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Брошенное дитя
void CTimeSeriesDE::SetDrawingAsDotsPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternAbandonedBaby(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Pivot Point Reversal
//--- Price Action
void CTimeSeriesDE::SetDrawingAsDotsPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternPivotPointReversal(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Внешний бар (Поглощение)
void CTimeSeriesDE::SetDrawingAsDotsPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternOutsideBar(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Внутренний бар
void CTimeSeriesDE::SetDrawingAsDotsPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternInsideBar(flag,redraw);
  }
//--- Устанавливает флаг рисования точками паттерна Пин бар
void CTimeSeriesDE::SetDrawingAsDotsPatternPinBar(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw,  // Флаг рисования точкой и флаг перерисовки Price Action Пин бар
                                                  const double ratio_body=30,                  // Процентное отношение тела свечи к полному размеру свечи
                                                  const double ratio_larger_shadow=60,         // Процентное отношение размера большей тени к размеру свечи
                                                  const double ratio_smaller_shadow=30)        // Процентное отношение размера меньшей тени к размеру свечи
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternPinBar(flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
  }
//--- Устанавливает флаг рисования точками паттерна Рельсы
void CTimeSeriesDE::SetDrawingAsDotsPatternRails(const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetDrawingAsDotsPatternRails(flag,redraw);
  }
  
//+------------------------------------------------------------------+
//| Методы возврата флага рисования паттерна точками                 |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг рисования точками паттерна Харами
bool CTimeSeriesDE::IsDrawingAsDotsPatternHarami(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternHarami() : false);
  }
//--- Возвращает флаг рисования точками паттерна Крест харами
bool CTimeSeriesDE::IsDrawingAsDotsPatternHaramiCross(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternHaramiCross() : false);
  }
//--- Возвращает флаг рисования точками паттерна Пинцет
bool CTimeSeriesDE::IsDrawingAsDotsPatternTweezer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternTweezer() : false);
  }
//--- Возвращает флаг рисования точками паттерна Просвет в облаках
bool CTimeSeriesDE::IsDrawingAsDotsPatternPiercingLine(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternPiercingLine() : false);
  }
//--- Возвращает флаг рисования точками паттерна Завеса из темных облаков
bool CTimeSeriesDE::IsDrawingAsDotsPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternDarkCloudCover() : false);
  }
//--- Возвращает флаг рисования точками паттерна Три белых солдата
bool CTimeSeriesDE::IsDrawingAsDotsPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternThreeWhiteSoldiers() : false);
  }
//--- Возвращает флаг рисования точками паттерна Три черные вороны
bool CTimeSeriesDE::IsDrawingAsDotsPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternThreeBlackCrows() : false);
  }
//--- Возвращает флаг рисования точками паттерна Падающая звезда
bool CTimeSeriesDE::IsDrawingAsDotsPatternShootingStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternShootingStar() : false);
  }
//--- Возвращает флаг рисования точками паттерна Молот
bool CTimeSeriesDE::IsDrawingAsDotsPatternHammer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternHammer() : false);
  }
//--- Возвращает флаг рисования точками паттерна Перевёрнутый молот
bool CTimeSeriesDE::IsDrawingAsDotsPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternInvertedHammer() : false);
  }
//--- Возвращает флаг рисования точками паттерна Повешенный
bool CTimeSeriesDE::IsDrawingAsDotsPatternHangingMan(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternHangingMan() : false);
  }
//--- Возвращает флаг рисования точками паттерна Доджи
bool CTimeSeriesDE::IsDrawingAsDotsPatternDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternDoji() : false);
  }
//--- Возвращает флаг рисования точками паттерна Доджи стрекоза
bool CTimeSeriesDE::IsDrawingAsDotsPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternDragonflyDoji() : false);
  }
//--- Возвращает флаг рисования точками паттерна Доджи надгробие
bool CTimeSeriesDE::IsDrawingAsDotsPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternGravestoneDoji() : false);
  }
//--- Возвращает флаг рисования точками паттерна Утренняя звезда
bool CTimeSeriesDE::IsDrawingAsDotsPatternMorningStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternMorningStar() : false);
  }
//--- Возвращает флаг рисования точками паттерна Утренняя доджи-звезда
bool CTimeSeriesDE::IsDrawingAsDotsPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternMorningDojiStar() : false);
  }
//--- Возвращает флаг рисования точками паттерна Вечерняя звезда
bool CTimeSeriesDE::IsDrawingAsDotsPatternEveningStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternEveningStar() : false);
  }
//--- Возвращает флаг рисования точками паттерна Вечерняя доджи-звезда
bool CTimeSeriesDE::IsDrawingAsDotsPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternEveningDojiStar() : false);
  }
//--- Возвращает флаг рисования точками паттерна Три звезды
bool CTimeSeriesDE::IsDrawingAsDotsPatternThreeStars(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternThreeStars() : false);
  }
//--- Возвращает флаг рисования точками паттерна Брошенное дитя
bool CTimeSeriesDE::IsDrawingAsDotsPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternAbandonedBaby() : false);
  }
//--- Price Action
//--- Возвращает флаг рисования точками паттерна Pivot Point Reversal
bool CTimeSeriesDE::IsDrawingAsDotsPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternPivotPointReversal() : false);
  }
//--- Возвращает флаг рисования точками паттерна Внешний бар (Поглощение)
bool CTimeSeriesDE::IsDrawingAsDotsPatternOutsideBar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternOutsideBar() : false);
  }
//--- Возвращает флаг рисования точками паттерна Внутренний бар
bool CTimeSeriesDE::IsDrawingAsDotsPatternInsideBar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternInsideBar() : false);
  }
//--- Возвращает флаг рисования точками паттерна Пин бар
bool CTimeSeriesDE::IsDrawingAsDotsPatternPinBar(const ENUM_TIMEFRAMES timeframe,const double ratio_body=30,   // Процентное отношение тела свечи к полному размеру свечи
                                                 const double ratio_larger_shadow=60,                          // Процентное отношение размера большей тени к размеру свечи
                                                 const double ratio_smaller_shadow=30)                         // Процентное отношение размера меньшей тени к размеру свечи
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
  }
//--- Возвращает флаг рисования точками паттерна Рельсы
bool CTimeSeriesDE::IsDrawingAsDotsPatternRails(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsDrawingAsDotsPatternRails() : false);
  }


В последующих статьях сделаем отслеживание параметров графика для переустановки свойств графика в объектах таймсерий, используемых для отрисовки значков паттернов. Все свойства всех открытых в терминале графиков содержатся в коллекции чартов библиотеки. Чтобы мы имели доступ к данным этой коллекции из коллекции таймсерий всех символов, нужно указатель на коллекцию чартов передать в коллекцию таймсерий.
Для этого к файлу коллекции таймсерий символов \MQL5\Include\DoEasy\Collections\TimeSeriesCollection.mqh подключим файл коллекции чартов и в приватной секции объявим указатель на коллекцию чартов:

//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Objects\Series\TimeSeriesDE.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "ChartObjCollection.mqh"
//+------------------------------------------------------------------+
//| Коллекция таймсерий символов                                     |
//+------------------------------------------------------------------+
class CTimeSeriesCollection : public CBaseObjExt
  {
private:
   CListObj                m_list;                    // Список используемых таймсерий символов
   CListObj                m_list_all_patterns;       // Список всех паттернов всех используемых таймсерий символов
   CChartObjCollection    *m_charts;                  // Указатель на коллекцию чартов
   
//--- Возвращает индекс таймсерии по имени символа
   int                     IndexTimeSeries(const string symbol);
public:


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

//+------------------------------------------------------------------+
//| Методы установки флага рисования паттерна точками                |
//+------------------------------------------------------------------+
//--- Устанавливает флаг использования паттерна Харами и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Крест харами и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Пинцет и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Просвет в облаках и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Завеса из темных облаков и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Три белых солдата и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Три черные вороны и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Падающая звезда и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Молот и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Перевёрнутый молот и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Повешенный и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Доджи и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Доджи стрекоза и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Доджи надгробие и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Утренняя звезда и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Утренняя доджи-звезда и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Вечерняя звезда и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Вечерняя доджи-звезда и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Три звезды и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Брошенное дитя и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Pivot Point Reversal и создаёт объект управления если его ещё нет
//--- Price Action
   void                    SetDrawingAsDotsPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Внешний бар (Поглощение) и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw, // Флаг рисования точкой и флаг перерисовки Price Action Пин бар
                                                         const double ratio_body=30,                                                            // Процентное отношение тела свечи к полному размеру свечи
                                                         const double ratio_larger_shadow=60,                                                   // Процентное отношение размера большей тени к размеру свечи
                                                         const double ratio_smaller_shadow=30);                                                 // Процентное отношение размера меньшей тени к размеру свечи
//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void                    SetDrawingAsDotsPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw);
                       
//+------------------------------------------------------------------+
//| Методы возврата флага рисования паттерна точками                 |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг использования паттерна Харами
   bool                    IsDrawingAsDotsPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Крест харами
   bool                    IsDrawingAsDotsPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пинцет
   bool                    IsDrawingAsDotsPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Просвет в облаках
   bool                    IsDrawingAsDotsPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Завеса из темных облаков
   bool                    IsDrawingAsDotsPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три белых солдата
   bool                    IsDrawingAsDotsPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три черные вороны
   bool                    IsDrawingAsDotsPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Падающая звезда
   bool                    IsDrawingAsDotsPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Молот
   bool                    IsDrawingAsDotsPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Перевёрнутый молот
   bool                    IsDrawingAsDotsPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Повешенный
   bool                    IsDrawingAsDotsPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи
   bool                    IsDrawingAsDotsPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи стрекоза
   bool                    IsDrawingAsDotsPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи надгробие
   bool                    IsDrawingAsDotsPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя звезда
   bool                    IsDrawingAsDotsPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя доджи-звезда
   bool                    IsDrawingAsDotsPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя звезда
   bool                    IsDrawingAsDotsPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя доджи-звезда
   bool                    IsDrawingAsDotsPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три звезды
   bool                    IsDrawingAsDotsPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Брошенное дитя
   bool                    IsDrawingAsDotsPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Price Action
//--- Возвращает флаг использования паттерна Pivot Point Reversal
   bool                    IsDrawingAsDotsPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внешний бар (Поглощение)
   bool                    IsDrawingAsDotsPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внутренний бар
   bool                    IsDrawingAsDotsPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пин бар
   bool                    IsDrawingAsDotsPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,double ratio_body=30,   // Процентное отношение тела свечи к полному размеру свечи
                                                        const double ratio_larger_shadow=60,                                        // Процентное отношение размера большей тени к размеру свечи
                                                        const double ratio_smaller_shadow=30);                                      // Процентное отношение размера меньшей тени к размеру свечи
//--- Возвращает флаг использования паттерна Рельсы
   bool                    IsDrawingAsDotsPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe);


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

//--- Рисует метки паттернов Рельсы на графике
   void                    DrawPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
                                                
//--- Инициализация
   void                    OnInit(CChartObjCollection *charts) { this.m_charts=charts; }
   
//--- Конструктор
                           CTimeSeriesCollection(void);
  };


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

//+------------------------------------------------------------------+
//| Методы установки флага рисования паттерна точками                |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Харами             |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternHarami(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Крест харами       |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternHaramiCross(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Пинцет             |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternTweezer(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Просвет в облаках  |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternPiercingLine(timeframe,flag,redraw);
  }
//+----------------------------------------------------------------------+
//|Устанавливает флаг рисования точками паттерна Завеса из темных облаков|
//+----------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternDarkCloudCover(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Три белых солдата  |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternThreeWhiteSoldiers(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Три черные вороны  |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternThreeBlackCrows(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Падающая звезда    |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternShootingStar(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Молот              |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternHammer(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Перевёрнутый молот |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternInvertedHammer(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Повешенный         |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternHangingMan(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Доджи              |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternDoji(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Доджи стрекоза     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternDragonflyDoji(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Доджи надгробие    |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternGravestoneDoji(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Утренняя звезда    |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternMorningStar(timeframe,flag,redraw);
  }
//+-------------------------------------------------------------------+
//|Устанавливает флаг рисования точками паттерна Утренняя доджи-звезда|
//+-------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternMorningDojiStar(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Вечерняя звезда    |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternEveningStar(timeframe,flag,redraw);
  }
//+-------------------------------------------------------------------+
//|Устанавливает флаг рисования точками паттерна Вечерняя доджи-звезда|
//+-------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternEveningDojiStar(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Три звезды         |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternThreeStars(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Брошенное дитя     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternAbandonedBaby(timeframe,flag,redraw);
  }
//--- Price Action
//+------------------------------------------------------------------+
//|Устанавливает флаг рисования точками паттерна Pivot Point Reversal|
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternPivotPointReversal(timeframe,flag,redraw);
  }
//+----------------------------------------------------------------------+
//|Устанавливает флаг рисования точками паттерна Внешний бар (Поглощение)|
//+----------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternOutsideBar(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Внутренний бар     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternInsideBar(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Пин бар            |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                          const bool flag,const bool redraw,                   // Флаг рисования точкой и флаг перерисовки Price Action Пин бар
                                                          const double ratio_body=30,                          // Процентное отношение тела свечи к полному размеру свечи
                                                          const double ratio_larger_shadow=60,                 // Процентное отношение размера большей тени к размеру свечи
                                                          const double ratio_smaller_shadow=30)                // Процентное отношение размера меньшей тени к размеру свечи
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternPinBar(timeframe,flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг рисования точками паттерна Рельсы             |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetDrawingAsDotsPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetDrawingAsDotsPatternRails(timeframe,flag,redraw);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы возврата флага рисования паттерна точками                 |
//+------------------------------------------------------------------+
//--- Свечные формации
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Харами                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHarami(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Крест харами          |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHaramiCross(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Пинцет                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternTweezer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Просвет в облаках     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternPiercingLine(timeframe) : false);
  }
//+-------------------------------------------------------------------+
//|Возвращает флаг рисования точками паттерна Завеса из темных облаков|
//+-------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternDarkCloudCover(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Три белых солдата     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternThreeWhiteSoldiers(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Три черные вороны     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternThreeBlackCrows(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Падающая звезда       |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternShootingStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Молот                 |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHammer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Перевёрнутый молот    |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternInvertedHammer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Повешенный            |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternHangingMan(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Доджи                 |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Доджи стрекоза        |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternDragonflyDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Доджи надгробие       |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternGravestoneDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Утренняя звезда       |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternMorningStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Утренняя доджи-звезда |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternMorningDojiStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Вечерняя звезда       |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternEveningStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Вечерняя доджи-звезда |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternEveningDojiStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Три звезды            |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternThreeStars(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Брошенное дитя        |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternAbandonedBaby(timeframe) : false);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Pivot Point Reversal  |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternPivotPointReversal(timeframe) : false);
  }
//+-------------------------------------------------------------------+
//|Возвращает флаг рисования точками паттерна Внешний бар (Поглощение)|
//+-------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternOutsideBar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Внутренний бар        |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternInsideBar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Пин бар               |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                         const double ratio_body=30,                        // Процентное отношение тела свечи к полному размеру свечи
                                                         const double ratio_larger_shadow=60,               // Процентное отношение размера большей тени к размеру свечи
                                                         const double ratio_smaller_shadow=30)              // Процентное отношение размера меньшей тени к размеру свечи
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternPinBar(timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг рисования точками паттерна Рельсы                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsDrawingAsDotsPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsDrawingAsDotsPatternRails(timeframe) : false);
  }

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

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

Во всех методах работы с паттернами заменим такие или аналогичные строки входных параметров

CArrayObj *list=this.GetListPatterns(symbol,timeframe);

на такие:

CArrayObj *list=this.GetListPatterns(CorrectSymbol(symbol),CorrectTimeframe(timeframe));

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


В разделе методов для работы с паттернами напишем новые методы для работы с флагом рисования паттернов в виде точки:

//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternRails(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag);
                          }

//--- Устанавливает флаг рисования точками паттерна Харами
   void                 SeriesSetDrawingAsDotsPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternHarami(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Крест харами
   void                 SeriesSetDrawingAsDotsPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternHaramiCross(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Пинцет
   void                 SeriesSetDrawingAsDotsPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternTweezer(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Просвет в облаках
   void                 SeriesSetDrawingAsDotsPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternPiercingLine(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Завеса из темных облаков
   void                 SeriesSetDrawingAsDotsPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternDarkCloudCover(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Три белых солдата
   void                 SeriesSetDrawingAsDotsPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternThreeWhiteSoldiers(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Три черные вороны
   void                 SeriesSetDrawingAsDotsPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternThreeBlackCrows(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Падающая звезда
   void                 SeriesSetDrawingAsDotsPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternShootingStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Молот
   void                 SeriesSetDrawingAsDotsPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternHammer(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Перевёрнутый молот
   void                 SeriesSetDrawingAsDotsPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternInvertedHammer(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Повешенный
   void                 SeriesSetDrawingAsDotsPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternHangingMan(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Доджи
   void                 SeriesSetDrawingAsDotsPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternDoji(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Доджи стрекоза
   void                 SeriesSetDrawingAsDotsPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternDragonflyDoji(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Доджи надгробие
   void                 SeriesSetDrawingAsDotsPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternGravestoneDoji(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Утренняя звезда
   void                 SeriesSetDrawingAsDotsPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternMorningStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Утренняя доджи-звезда
   void                 SeriesSetDrawingAsDotsPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternMorningDojiStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Вечерняя звезда
   void                 SeriesSetDrawingAsDotsPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternEveningStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Вечерняя доджи-звезда
   void                 SeriesSetDrawingAsDotsPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternEveningDojiStar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Три звезды
   void                 SeriesSetDrawingAsDotsPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternThreeStars(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Брошенное дитя
   void                 SeriesSetDrawingAsDotsPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternAbandonedBaby(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Pivot Point Reversal
//--- Price Action
   void                 SeriesSetDrawingAsDotsPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternPivotPointReversal(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Внешний бар (Поглощение)
   void                 SeriesSetDrawingAsDotsPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternOutsideBar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Внутренний бар
   void                 SeriesSetDrawingAsDotsPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternInsideBar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }
//--- Устанавливает флаг рисования точками паттерна Пин бар
   void                 SeriesSetDrawingAsDotsPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                            const bool flag,const bool redraw=false,  // Флаг рисования точкой и флаг перерисовки Price Action Пин бар
                                                            const double ratio_body=30,               // Процентное отношение тела свечи к полному размеру свечи
                                                            const double ratio_larger_shadow=60,      // Процентное отношение размера большей тени к размеру свечи
                                                            const double ratio_smaller_shadow=30)     // Процентное отношение размера меньшей тени к размеру свечи
                          {
                           this.m_time_series.SetDrawingAsDotsPatternPinBar(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                          }
//--- Устанавливает флаг рисования точками паттерна Рельсы
   void                 SeriesSetDrawingAsDotsPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag,const bool redraw=false)
                          {
                           this.m_time_series.SetDrawingAsDotsPatternRails(CorrectSymbol(symbol),CorrectTimeframe(timeframe),flag,redraw);
                          }

//--- Рисует метки паттернов Харами на графике
   void                 SeriesDrawPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHarami(CorrectSymbol(symbol),CorrectTimeframe(timeframe),redraw);
                          }

Методы вызывают написанные выше соответствующие методы класса-коллекции таймсерий.


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

//--- Скрывает информационные панели всех паттернов кроме указанного
   void                 SeriesPatternHideAllInfoPanelsExceptOne(const ulong pattern_code,const bool redraw=false)
                          {
                           CArrayObj *list=CSelect::ByPatternProperty(this.GetListAllPatterns(),PATTERN_PROP_CODE,pattern_code,NO_EQUAL);
                           if(list==NULL)
                              return;
                           for(int i=list.Total()-1;i>=0;i--)
                             {
                              CPattern *obj=list.At(i);
                              if(obj!=NULL)
                                 obj.HideInfoPanel();
                             }
                           if(redraw)
                              ::ChartRedraw();
                          }
//--- Скрывает информационные панели всех паттернов кроме находящихся на указанном времени бара
   void                 SeriesPatternHideAllInfoPanelsExceptBarTime(const datetime bar_time,const bool redraw=false)
                          {
                           CArrayObj *list=CSelect::ByPatternProperty(this.GetListAllPatterns(),PATTERN_PROP_TIME,bar_time,NO_EQUAL);
                           if(list==NULL)
                              return;
                           for(int i=list.Total()-1;i>=0;i--)
                             {
                              CPattern *obj=list.At(i);
                              if(obj!=NULL)
                                 obj.HideInfoPanel();
                             }
                           if(redraw)
                              ::ChartRedraw();
                          }

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


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

//--- Воспроизводит звук по его описанию
   bool                 PlaySoundByDescription(const string sound_description);

//--- Передаёт в торговый класс и класс-коллекцию индикаторных буферов указатели на все необходимые коллекции
   void                 CollectionOnInit(void)
                          {
                           this.m_trading.OnInit(this.GetAccountCurrent(),this.m_symbols.GetObject(),this.m_market.GetObject(),this.m_history.GetObject(),this.m_events.GetObject());
                           this.m_buffers.OnInit(this.m_time_series.GetObject(),this.m_indicators.GetObject());
                           this.m_time_series.OnInit(this.GetChartObjCollection());
                          }
//--- Устанавливает множитель спреда торговым объектам символов в коллекции символов
   void                 SetSpreadMultiplier(const uint value=1,const string symbol=NULL)  { this.m_trading.SetSpreadMultiplier(value,symbol);   }


В обработчике событий библиотеки DoEasy создадим заготовку для обработки событий коллекции чартов:

//--- Обработка событий окна обзор рынка
   else if(idx>MARKET_WATCH_EVENT_NO_EVENT && idx<SYMBOL_EVENTS_NEXT_CODE)
     {
      //--- Событие окна "Обзор рынка"
      string descr=this.GetMWEventDescription((ENUM_MW_EVENT)idx);
      string name=(idx==MARKET_WATCH_EVENT_SYMBOL_SORT ? "" : ": "+sparam);
      Print(TimeMSCtoString(lparam)," ",descr,name);
     }

//--- Обработка событий чартов
   else if(idx>CHART_OBJ_EVENT_NO_EVENT && idx<CHART_OBJ_EVENTS_NEXT_CODE)
     {
      
     }
     
//--- Обработка событий таймсерий
   else if(idx>SERIES_EVENTS_NO_EVENT && idx<SERIES_EVENTS_NEXT_CODE)
     {

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

Теперь всё готово для тестирования того, что у нас получилось.



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

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

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

//--- input variables
input    ushort            InpMagic             =  123;  // Magic number
input    double            InpLots              =  0.1;  // Lots
input    uint              InpStopLoss          =  150;  // StopLoss in points
input    uint              InpTakeProfit        =  150;  // TakeProfit in points
input    uint              InpDistance          =  50;   // Pending orders distance (points)
input    uint              InpDistanceSL        =  50;   // StopLimit orders distance (points)
input    uint              InpDistancePReq      =  50;   // Distance for Pending Request's activate (points)
input    uint              InpBarsDelayPReq     =  5;    // Bars delay for Pending Request's activate (current timeframe)
input    uint              InpSlippage          =  5;    // Slippage in points
input    uint              InpSpreadMultiplier  =  1;    // Spread multiplier for adjusting stop-orders by StopLevel
input    uchar             InpTotalAttempts     =  5;    // Number of trading attempts
sinput   double            InpWithdrawal        =  10;   // Withdrawal funds (in tester)

sinput   uint              InpButtShiftX        =  0;    // Buttons X shift 
sinput   uint              InpButtShiftY        =  10;   // Buttons Y shift 

input    uint              InpTrailingStop      =  50;   // Trailing Stop (points)
input    uint              InpTrailingStep      =  20;   // Trailing Step (points)
input    uint              InpTrailingStart     =  0;    // Trailing Start (points)
input    uint              InpStopLossModify    =  20;   // StopLoss for modification (points)
input    uint              InpTakeProfitModify  =  60;   // TakeProfit for modification (points)

sinput   ENUM_SYMBOLS_MODE InpModeUsedSymbols   =  SYMBOLS_MODE_CURRENT;            // Mode of used symbols list
sinput   string            InpUsedSymbols       =  "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY";  // List of used symbols (comma - separator)
sinput   ENUM_TIMEFRAMES_MODE InpModeUsedTFs    =  TIMEFRAMES_MODE_CURRENT;         // Mode of used timeframes list
sinput   string            InpUsedTFs           =  "M1,M5,M15,M30,H1,H4,D1,W1,MN1"; // List of used timeframes (comma - separator)

sinput   double            InpPinBarRatioBody   =  30.0;                            // Pin Bar Ratio Body to Candle size
sinput   double            InpPinBarRatioLarger =  60.0;                            // Pin Bar Ratio Larger shadow to Candle size
sinput   double            InpPinBarRatioSmaller=  30.0;                            // Pin Bar Ratio Smaller shadow to Candle size
sinput   bool              InpDrawPatternsAsDots=  true;                            // Draw Patterns as dots

sinput   ENUM_INPUT_YES_NO InpUseBook           =  INPUT_NO;                        // Use Depth of Market
sinput   ENUM_INPUT_YES_NO InpUseMqlSignals     =  INPUT_NO;                        // Use signal service
sinput   ENUM_INPUT_YES_NO InpUseCharts         =  INPUT_NO;                        // Use Charts control
sinput   ENUM_INPUT_YES_NO InpUseSounds         =  INPUT_YES;                       // Use sounds

//--- global variables

При значении true, все найденные паттерны будут рисоваться точками на графике. При значении false паттерны "Внутренний Бар" будут рисоваться объектами Bitmap — бары паттернов будут обводиться цветными прямоугольниками.


В обработчике OnInit() советника настроим поиск и отображение паттернов:

//--- Очистим список всех паттернов
   engine.GetListAllPatterns().Clear();
//--- Установим флаг использования паттерна Пин-Бар с параметрами, заданными в настройках
   engine.SeriesSetUsedPatternPinBar(NULL,PERIOD_CURRENT,true,InpPinBarRatioBody,InpPinBarRatioLarger,InpPinBarRatioSmaller);
//--- Установим флаг использования паттерна Внутренний бар
   engine.SeriesSetUsedPatternInsideBar(NULL,PERIOD_CURRENT,true);
//--- Установим из входных параметров флаг рисования паттернов Внутренний бар в виде точек
   engine.SeriesSetDrawingAsDotsPatternInsideBar(NULL,PERIOD_CURRENT,InpDrawPatternsAsDots);
   
//--- Выведем на график значки паттерна Пин-Бар с указанными в настройках параметрами
   engine.SeriesDrawPatternPinBar(NULL,PERIOD_CURRENT,InpPinBarRatioBody,InpPinBarRatioLarger,InpPinBarRatioSmaller);
//--- Выведем на график значки паттерна Внутренний бар
   engine.SeriesDrawPatternInsideBar(NULL,PERIOD_CURRENT,true);
//---
   return(INIT_SUCCEEDED);
  }


В обработчике OnChartEvent() советника напишем такой блок кода для отображения информационных панелей паттернов:

//--- Проверка ChartXYToTimePrice()
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Получим объект-чарт текущего (главного) графика программы
      CChartObj *chart=engine.ChartGetMainChart();
      if(chart==NULL)
         return;
      //--- Получим номер подокна, в котором находится курсор
      int wnd_num=chart.XYToTimePrice(lparam,dparam);
      if(wnd_num==WRONG_VALUE)
         return;
      //--- Получим рассчитанные время и цену расположения курсора
      datetime time=chart.TimeFromXY();
      double price=chart.PriceFromXY();
      //--- Получим объект-окно чарта, в котором расположен курсор, по номеру подокна
      CChartWnd *wnd=chart.GetWindowByNum(wnd_num);
      if(wnd==NULL)
         return;
      //--- Если координаты X и Y рассчитаны по времени и цене (делаем обратное предыдущему преобразование),
      if(wnd.TimePriceToXY(time,price))
        {
         //--- то выведем в комментарии рассчитанные по X и Y курсора время, цену и номер окна,
         //--- а также преобразованные обратно из времени и цены координаты X и Y курсора
         //Comment
         //  (
         //   DFUN,"time: ",TimeToString(time),", price: ",DoubleToString(price,Digits()),
         //   ", win num: ",(string)wnd_num,": x: ",(string)wnd.XFromTimePrice(),
         //   ", y: ",(string)wnd.YFromTimePrice()," (",(string)wnd.YFromTimePriceRelative(),")"
         //  );
         
         //--- По времени курсора получим время открытия бара на графике
         datetime bar_time=GetStartTimeOfBarFast(PERIOD_CURRENT,time);
         //--- Получим указатель на бар, время открытия которого получили
         CBar *bar=engine.SeriesGetBar(Symbol(),PERIOD_CURRENT,bar_time);
         if(bar!=NULL && price>=bar.Low() && price<=bar.High())
           {
            //--- Из объекта-бара получим в массив array список паттернов, найденных на нём
            ulong array[]={};
            int total=bar.GetPatternsList(array);
            //--- Если паттерны найдены на баре
            if(total>0)
              {
               //--- выведем в журнал описания всех найденных на баре паттернов
               bar.PatternTypeDescriptionPrint(true);
               //--- В цикле по количеству найденных на баре паттернов
               for(int i=0;i<(int)array.Size();i++)
                 {
                  //--- получаем из массива array тип очередного паттерна и получаем на него указатель
                  ENUM_PATTERN_TYPE type=(ENUM_PATTERN_TYPE)array[i];
                  CPattern *pattern=engine.GetPattern(Symbol(),PERIOD_CURRENT,bar_time,type);
                  
                  //--- Распечатаем в журнале короткое описание паттерна
                  if(pattern==NULL)
                     continue;
                  pattern.PrintShort(true);
                  //pattern.Print(false,true);
                  //--- Получим координаты графика, на которых нужно показать информационную панель
                  int x=wnd.XFromTimePrice();
                  int y=wnd.YFromTimePrice();
                  //--- Скрываем все панели, кроме принадлежащих паттернам, найденных на баре под курсором
                  engine.SeriesPatternHideAllInfoPanelsExceptBarTime(bar_time);
                  //--- рассчитываем координату Y информационной панели от индекса цикла
                  static int shift=0;
                  int cy=y+shift*i;
                  //--- Отображаем информационную панель на графике
                  pattern.ShowInfoPanel(x,cy);
                  CForm *form=pattern.GetForm();
                  //--- Если указатель на  панель получен - рассчитываем размер смещения координаты Y (высота панели + 1)
                  if(form!=NULL)
                     shift=form.Height()+1;
                 }
              }
           }
        }
     }

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

Скомпилируем советник и запустим его на графике:


Как видим всё работает, как и было заявлено. Рисование паттернов в виде рисунков имеет некоторые задержки. С этим разберёмся.

Примерно в центре экрана видим вложенный паттерн. При наведении курсора и появлении информационной панели отображается общее количество баров, входящих в цепочку паттернов.

В правой стороне экрана на одном баре образовано два паттерна — Пин Бар и Внутренний Бар, и информационные панели обоих паттернов выводятся одна над другой.


Что дальше

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

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


К содержанию

Прикрепленные файлы |
MQL5.zip (9005.57 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (4)
Alexey Viktorov
Alexey Viktorov | 26 мар. 2024 в 17:19

Поздравляю Артём с новой интересной статьёй. Продолжай в том-же духе.

Artyom Trishkin
Artyom Trishkin | 26 мар. 2024 в 17:43
Alexey Viktorov #:

Поздравляю Артём с новой интересной статьёй. Продолжай в том-же духе.

Спасибо, Алексей

Николай
Николай | 12 апр. 2024 в 14:26

Классное чтиво, правда осилил не все буквы)

Во время теста не удалось открыть не одного ордера, но паттерны отображаются.

Жду продолжение

Artyom Trishkin
Artyom Trishkin | 12 апр. 2024 в 15:44
Николай #:

Классное чтиво, правда осилил не все буквы)

Во время теста не удалось открыть не одного ордера, но паттерны отображаются.

Жду продолжение

Должен торговать кнопками. Не может не торговать. Как пробовали? 
Разрабатываем мультивалютный советник (Часть 6): Автоматизируем подбор группы экземпляров Разрабатываем мультивалютный советник (Часть 6): Автоматизируем подбор группы экземпляров
После оптимизации торговой стратегии мы получаем наборы параметров, на основе которых можно создать несколько экземпляров торговых стратегий, объединённых в одном советнике. Раньше мы делали это вручную, а теперь попробуем автоматизировать этот процесс
Роль качества генератора случайных чисел в эффективности алгоритмов оптимизации Роль качества генератора случайных чисел в эффективности алгоритмов оптимизации
В этой статье мы рассмотрим генератор случайных чисел Mersenne Twister и сравним со стандартным в MQL5. Узнаем влияние качества случайных чисел генераторов на результаты алгоритмов оптимизации.
Введение в MQL5 (Часть 1): Руководство по алготрейдингу для начинающих Введение в MQL5 (Часть 1): Руководство по алготрейдингу для начинающих
Данная статья представляет собой руководство по программированию на MQL5 для начинающих. Она открывает дверь в увлекательный мир алготрейдинга. Здесь вы познакомитесь с основами MQL5, языка программирования торговых стратегий в MetaTrader 5, который и станет проводником в мир автоматической торговли. Эта статья — от понимания основ до первых шагов в программировании — призвана раскрыть потенциал алготрейдинга для всех читателей, даже для тех, у кого совершенно нет опыта программирования. Надеюсь, вам понравится это путешествие в мир трейдинга с MQL5.
Риск-менеджер для ручной торговли Риск-менеджер для ручной торговли
В данной статье мы подробно раскроем написание класса риск-менеджера для ручной торговли с нуля. Также данный класс может быть использован как базовый класс для наследования трейдерам, которые торгуют алгоритмически.