preview
DoEasy. Сервисные функции (Часть 1): Ценовые паттерны

DoEasy. Сервисные функции (Часть 1): Ценовые паттерны

MetaTrader 5Примеры | 1 марта 2024, 16:34
825 1
Artyom Trishkin
Artyom Trishkin

Содержание


Концепция

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

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

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

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

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


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

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

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

#define COLLECTION_ID_LIST_END         (COLLECTION_GRAPH_OBJ_ID)  // Конец списка идентификаторов коллекций

//--- Идентификаторы типов отложенных запросов


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

   OBJECT_DE_TYPE_SERIES_BAR,                                     // Тип объекта "Бар"
   OBJECT_DE_TYPE_SERIES_PERIOD,                                  // Тип объекта "Таймсерия периода"
   OBJECT_DE_TYPE_SERIES_SYMBOL,                                  // Тип объекта "Таймсерии символа"
   
   OBJECT_DE_TYPE_SERIES_PATTERN,                                 // Тип объекта "Паттерн"
   OBJECT_DE_TYPE_SERIES_PATTERN_CONTROL,                         // Тип объекта "Управление паттерном"
   OBJECT_DE_TYPE_SERIES_PATTERNS_CONTROLLERS,                    // Тип объекта "Управление паттернами"
  • Объект Паттерн — это сам объект какого-либо паттерна;
  • Объект Управления паттерном — это объект, внутри которого будет организован функционал поиска и создания паттернов одного типа внутри одной таймсерии. Для каждого паттерна создаётся свой объект управления;
  • Объект Управления паттернами — это объект, хранящий в себе список всех объектов управления паттернами различных типов и предоставляющий к ним доступ. Объект определяется внутри класса таймсерии.

Так как паттерны ищутся по каким-либо параметрам баров таймсерии, либо сочетаниям этих параметров у разных близлежащих баров, то к свойствам бара добавим параметры пропорции свечи — отношения тела свечи к её размеру, верхней и нижней теней к размеру свечи и увеличим общее количество целочисленных параметров с 10 до 13:

//+------------------------------------------------------------------+
//| Вещественные свойства бара                                       |
//+------------------------------------------------------------------+
enum ENUM_BAR_PROP_DOUBLE
  {
//--- данные бара
   BAR_PROP_OPEN = BAR_PROP_INTEGER_TOTAL,                  // Цена открытия бара
   BAR_PROP_HIGH,                                           // Наивысшая цена за период бара
   BAR_PROP_LOW,                                            // Наименьшая цена за период бара
   BAR_PROP_CLOSE,                                          // Цена закрытия бара
//--- данные свечи
   BAR_PROP_CANDLE_SIZE,                                    // Размер свечи
   BAR_PROP_CANDLE_SIZE_BODY,                               // Размер тела свечи
   BAR_PROP_CANDLE_BODY_TOP,                                // Верх тела свечи
   BAR_PROP_CANDLE_BODY_BOTTOM,                             // Низ тела свечи
   BAR_PROP_CANDLE_SIZE_SHADOW_UP,                          // Размер верхней тени свечи
   BAR_PROP_CANDLE_SIZE_SHADOW_DOWN,                        // Размер нижней тени свечи
//--- пропорции свечи
   BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,                      // Процентное отношение тела свечи к полному размеру свечи
   BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,              // Процентное отношение размера верхней тени к размеру свечи
   BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,              // Процентное отношение размера нижней тени к размеру свечи
  }; 
#define BAR_PROP_DOUBLE_TOTAL  (13)                         // Общее количество вещественных свойств бара
#define BAR_PROP_DOUBLE_SKIP   (0)                          // Количество неиспользуемых в сортировке свойств бара

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

Напишем перечисления типов и свойств паттернов:

//+------------------------------------------------------------------+
//| Статус абстрактного паттерна                                     |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_STATUS
  {
   PATTERN_STATUS_JC,                                       // Японские свечи
   PATTERN_STATUS_PA,                                       // Формации Price Action
  };

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

Паттерны одинакового типа могут быть на покупку, на продажу и двунаправленными. Напишем перечисление типов паттернов по направлению:

//+------------------------------------------------------------------+
//| Тип паттерна по направлению (на покупку/продажу)                 |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_DIRECTION
  {
   PATTERN_DIRECTION_BULLISH,                               // Паттерн на покупку
   PATTERN_DIRECTION_BEARISH,                               // Паттерн на продажу
   PATTERN_DIRECTION_BOTH,                                  // Двунаправленный паттерн
  };


Напишем перечисление с типами паттернов:

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

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

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

//+------------------------------------------------------------------+
//| Целочисленные свойства паттерна                                  |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_PROP_INTEGER
  {
   PATTERN_PROP_CODE = 0,                                   // Уникальный код паттерна (время + тип + статус + направление + таймфрейм + символ)
   PATTERN_PROP_CTRL_OBJ_ID,                                // Идентификатор объекта управления паттерном
   PATTERN_PROP_ID,                                         // Идентификатор паттерна
   PATTERN_PROP_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 (9)                      // Общее количество целочисленных свойств паттерна
#define PATTERN_PROP_INTEGER_SKIP  (0)                      // Количество неиспользуемых в сортировке свойств паттерна
//+------------------------------------------------------------------+
//| Вещественные свойства паттерна                                   |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_PROP_DOUBLE
  {
//--- данные бара
   PATTERN_PROP_BAR_PRICE_OPEN = PATTERN_PROP_INTEGER_TOTAL,// Цена Open определяющего бара паттерна
   PATTERN_PROP_BAR_PRICE_HIGH,                             // Цена High определяющего бара паттерна
   PATTERN_PROP_BAR_PRICE_LOW,                              // Цена Low определяющего бара паттерна
   PATTERN_PROP_BAR_PRICE_CLOSE,                            // Цена Close определяющего бара паттерна
   PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE,                  // Отношение тела свечи к полному размеру свечи в %
   PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,          // Отношение размера верхней тени к размеру свечи в %
   PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,          // Отношение размера нижней тени к размеру свечи в %
   PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,           // Установленный критерий отношения тела свечи к полному размеру свечи в %
   PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,  // Установленный критерий отношения размера наибольшей тени к размеру свечи в %
   PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION, // Установленный критерий отношения размера наименьшей тени к размеру свечи в %
  }; 
#define PATTERN_PROP_DOUBLE_TOTAL   (10)                    // Общее количество вещественных свойств паттерна
#define PATTERN_PROP_DOUBLE_SKIP    (0)                     // Количество неиспользуемых в сортировке свойств паттерна
//+------------------------------------------------------------------+
//| Строковые свойства паттерна                                      |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_PROP_STRING
  {
   PATTERN_PROP_SYMBOL = (PATTERN_PROP_INTEGER_TOTAL+PATTERN_PROP_DOUBLE_TOTAL),  // Символ паттерна
   PATTERN_PROP_NAME,                                       // Наименование паттерна
  };
#define PATTERN_PROP_STRING_TOTAL   (2)                     // Общее количество строковых свойств паттерна

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

Тепернь напишем перечисление с возможными критериями сортировки для поиска, сортировки и фильтрации паттернов в их общем списке:

//+------------------------------------------------------------------+
//| Возможные критерии сортировки паттернов                          |
//+------------------------------------------------------------------+
#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_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_SERIES_EVENT
  {
   SERIES_EVENTS_NO_EVENT = SYMBOL_EVENTS_NEXT_CODE,        // Нет события
   SERIES_EVENTS_NEW_BAR,                                   // Событие "Новый бар"
   SERIES_EVENTS_MISSING_BARS,                              // Событие "Пропущены бары"
   SERIES_EVENTS_PATTERN,                                   // Событие "Паттерн"
  };
#define SERIES_EVENTS_NEXT_CODE  (SERIES_EVENTS_PATTERN+1)  // Код следующего события после события "Паттерн"

Код следующего события поменяем с "Пропущенные бары+1" на "Паттерн+1" — чтобы последующие коды событий начинались с правильного значения.


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

   MSG_LIB_TEXT_BAR_TYPE_CANDLE_ZERO_BODY,            // Свеча с нулевым телом
   MSG_LIB_TEXT_BAR_TEXT_FIRS_SET_AMOUNT_DATA,        // Сначала нужно установить требуемое количество данных при помощи SetRequiredUsedData()
   
   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,// Процентное отношение размера нижней тени к размеру свечи
  
//--- CTimeSeries

...

   MSG_LIB_TEXT_TS_TEXT_ATTEMPT,                      // Попытка:
   MSG_LIB_TEXT_TS_TEXT_WAIT_FOR_SYNC,                // Ожидание синхронизации данных ...

//--- CPattern
   MSG_LIB_TEXT_PATTERN_CODE,                         // Код
   MSG_LIB_TEXT_PATTERN_TIME,                         // Время определяющего бара
   MSG_LIB_TEXT_PATTERN_ID,                           // Идентификатор паттерна
   MSG_LIB_TEXT_PATTERN_CTRL_OBJ_ID,                  // Идентификатор объекта управления паттерном
   MSG_LIB_TEXT_PATTERN_CANDLES,                      // Количество свечей, составляющих паттерн
   MSG_LIB_TEXT_PATTERN_DIRECTION,                    // Направление паттерна
   
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_OPEN,               // Цена Open определяющего бара паттерна
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_HIGH,               // Цена High определяющего бара паттерна
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_LOW,                // Цена Low определяющего бара паттерна
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_CLOSE,              // Цена Close определяющего бара паттерна
   
   MSG_LIB_TEXT_PATTERN_RATIO_BODY_TO_CANDLE_SIZE,          // Отношение тела свечи к полному размеру свечи в %
   MSG_LIB_TEXT_PATTERN_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,  // Отношение размера верхней тени к размеру свечи в %
   MSG_LIB_TEXT_PATTERN_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,  // Отношение размера нижней тени к размеру свечи в %
   MSG_LIB_TEXT_PATTERN_RATIO_BODY_TO_CANDLE_SIZE_CRIT,           // Установленный критерий отношения тела свечи к полному размеру свечи в %
   MSG_LIB_TEXT_PATTERN_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRIT,  // Установленный критерий отношения размера наибольшей тени к размеру свечи в %
   MSG_LIB_TEXT_PATTERN_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRIT, // Установленный критерий отношения размера наименьшей тени к размеру свечи в %
   
   MSG_LIB_TEXT_PATTERN_NAME,                         // Наименование

   MSG_LIB_TEXT_PATTERN_STATUS_JC,                    // Свечной паттерн
   MSG_LIB_TEXT_PATTERN_STATUS_PA,                    // Формация Price Action
   MSG_LIB_TEXT_PATTERN_BULLISH,                      // Бычий паттерн
   MSG_LIB_TEXT_PATTERN_BEARISH,                      // Медвежий паттерн
   MSG_LIB_TEXT_PATTERN_BOTH,                         // Двунаправленный паттерн
   
   //--- Японские свечи
   MSG_LIB_TEXT_PATTERN_TYPE_HARAMI,                  // Харами
   MSG_LIB_TEXT_PATTERN_TYPE_HARAMI_CROSS,            // Крест харами
   MSG_LIB_TEXT_PATTERN_TYPE_TWEEZER,                 // Пинцет
   MSG_LIB_TEXT_PATTERN_TYPE_PIERCING_LINE,           // Просвет в облаках
   MSG_LIB_TEXT_PATTERN_TYPE_DARK_CLOUD_COVER,        // Завеса из темных облаков
   MSG_LIB_TEXT_PATTERN_TYPE_THREE_WHITE_SOLDIERS,    // Три белых солдата
   MSG_LIB_TEXT_PATTERN_TYPE_THREE_BLACK_CROWS,       // Три черные вороны
   MSG_LIB_TEXT_PATTERN_TYPE_SHOOTING_STAR,           // Падающая звезда
   MSG_LIB_TEXT_PATTERN_TYPE_HAMMER,                  // Молот
   MSG_LIB_TEXT_PATTERN_TYPE_INVERTED_HAMMER,         // Перевёрнутый молот
   MSG_LIB_TEXT_PATTERN_TYPE_HANGING_MAN,             // Повешенный
   MSG_LIB_TEXT_PATTERN_TYPE_DOJI,                    // Доджи
   MSG_LIB_TEXT_PATTERN_TYPE_DRAGONFLY_DOJI,          // Доджи стрекоза
   MSG_LIB_TEXT_PATTERN_TYPE_GRAVESTONE_DOJI,         // Доджи надгробие
   MSG_LIB_TEXT_PATTERN_TYPE_MORNING_STAR,            // Утренняя звезда
   MSG_LIB_TEXT_PATTERN_TYPE_MORNING_DOJI_STAR,       // Утренняя доджи-звезда
   MSG_LIB_TEXT_PATTERN_TYPE_EVENING_STAR,            // Вечерняя звезда
   MSG_LIB_TEXT_PATTERN_TYPE_EVENING_DOJI_STAR,       // Вечерняя доджи-звезда
   MSG_LIB_TEXT_PATTERN_TYPE_THREE_STARS,             // Три звезды
   MSG_LIB_TEXT_PATTERN_TYPE_ABANDONED_BABY,          // Брошенное дитя
   //--- Price Action
   MSG_LIB_TEXT_PATTERN_TYPE_PIVOT_POINT_REVERSAL,    // Pivot Point Reversal
   MSG_LIB_TEXT_PATTERN_TYPE_OUTSIDE_BAR,             // Внешний бар (Поглощение)
   MSG_LIB_TEXT_PATTERN_TYPE_INSIDE_BAR,              // Внутренний бар
   MSG_LIB_TEXT_PATTERN_TYPE_PIN_BAR,                 // Пин бар
   MSG_LIB_TEXT_PATTERN_TYPE_RAILS,                   // Рельсы

//--- CBuffer

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

   {"Свеча с нулевым телом","Candle with zero body"},
   {"Сначала нужно установить требуемое количество данных при помощи SetRequiredUsedData()","First you need to set the required amount of data using SetRequiredUsedData()"},
   
   {"Отношение тела свечи к полному размеру свечи","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"},
   
//--- CTimeSeries

...

   {"Попытка: ","Attempt: "},
   {"Ожидание синхронизации данных ...","Waiting for data synchronization ..."},
   
//--- CPattern
   {"Код","Code"},
   {"Время определяющего бара","Time of the defining bar"},
   {"Идентификатор паттерна","Pattern ID"},
   {"Идентификатор объекта управления паттерном","Pattern Control object ID"},
   {"Количество свечей, составляющих паттерн","Number of candles in the pattern"},
   {"Направление паттерна","Pattern direction"},
   
   {"Цена Open определяющего бара паттерна","Open price of the defining bar"},
   {"Цена High определяющего бара паттерна","High price of the defining bar"},
   {"Цена Low определяющего бара паттерна","Low price of the defining bar"},
   {"Цена Close определяющего бара паттерна","Close price of the defining bar"},
   
   {"Отношение тела свечи к полному размеру свечи в %","Ratio of candle body to full candle size in %"},
   {"Отношение размера верхней тени к размеру свечи в %","Ratio of the size of the upper shadow to the size of the candle in %"},
   {"Отношение размера нижней тени к размеру свечи в %","Ratio of the size of the lower shadow to the size of the candle in %"},
   {"Установленный критерий отношения тела свечи к полному размеру свечи в %","Criterion for the Ratio of candle body to full candle size in %"},
   {"Установленный критерий отношения размера наибольшей тени к размеру свечи в %","Criterion for the Ratio of the size of the larger shadow to the size of the candle in %"},
   {"Установленный критерий отношения размера наименьшей тени к размеру свечи в %","Criterion for the Ratio of the size of the smaller shadow to the size of the candle in %"},
   
   {"Наименование","Name"},

   //--- Статус паттерна
   {"Свечной паттерн","Candlestick pattern"},
   {"Формация Price Action","Price Action Formation"},
   {"Бычий паттерн","Bullish pattern"},
   {"Медвежий паттерн","Bearish pattern"},
   {"Двунаправленный паттерн","Bidirectional pattern"},

   //--- Свечные паттерны
   {"Харами","Harami"},
   {"Крест харами","Harami Cross"},
   {"Пинцет","Tweezer"},
   {"Просвет в облаках","Piercing pattern"},
   {"Завеса из темных облаков","Dark Cloud Cover"},
   {"Три белых солдата","Three White Soldiers"},
   {"Три черные вороны","Three Black Crows"},
   {"Падающая звезда","Shooting Star"},
   {"Молот","Hammer"},
   {"Перевёрнутый молот","Inverted Hammer"},
   {"Повешенный","Hanging Man"},
   {"Доджи","Doji"},
   {"Доджи стрекоза","Dragonfly doji"},
   {"Доджи надгробие","Gravestone Doji"},
   {"Утренняя звезда","Morning Star"},
   {"Утренняя доджи-звезда","Morning Doji Star"},
   {"Вечерняя звезда","Evening Star"},
   {"Вечерняя доджи-звезда","Evening Doji Star"},
   {"Три звезды","Three stars"},
   {"Брошенное дитя","Abandoned baby"},
   //--- Формации Price Action
   {"PPR разворотная точка","Pivot Point Reversal"},
   {"Внешний бар","Outside Bar"},
   {"Внутренний бар","Inside Bar"},
   {"Пин бар","Pin Bar"},
   {"Рельсы","Rails"},

//--- CBuffer


В файле класса объекта "Бар" \MQL5\Include\DoEasy\Objects\Series\Bar.mqh в приватной секции напишем методы, рассчитывающие и возвращающие пропорции свечи:

//+------------------------------------------------------------------+
//| Класс "Бар"                                                      |
//+------------------------------------------------------------------+
class CBar : public CBaseObj
  {
private:
   MqlDateTime       m_dt_struct;                                 // Структура даты
   int               m_digits;                                    // Значение Digits символа
   string            m_period_description;                        // Строковое описание таймфрейма
   long              m_long_prop[BAR_PROP_INTEGER_TOTAL];         // Целочисленные свойства
   double            m_double_prop[BAR_PROP_DOUBLE_TOTAL];        // Вещественные свойства
   string            m_string_prop[BAR_PROP_STRING_TOTAL];        // Строковые свойства

//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство бара
   int               IndexProp(ENUM_BAR_PROP_DOUBLE property)     const { return(int)property-BAR_PROP_INTEGER_TOTAL;                        }
   int               IndexProp(ENUM_BAR_PROP_STRING property)     const { return(int)property-BAR_PROP_INTEGER_TOTAL-BAR_PROP_DOUBLE_TOTAL;  }

//--- Возвращает тип бара (бычий/медвежий/нулевой)
   ENUM_BAR_BODY_TYPE BodyType(void)                              const;
//--- Рассчитывает и возвращает размер (1) свечи, (2) тела свечи,
//--- (3) верхней, (4) нижней тени свечи,
//--- (5) верх, (6) низ тела свечи
   double            CandleSize(void)                             const { return(this.High()-this.Low());                                    }
   double            BodySize(void)                               const { return(this.BodyHigh()-this.BodyLow());                            }
   double            ShadowUpSize(void)                           const { return(this.High()-this.BodyHigh());                               }
   double            ShadowDownSize(void)                         const { return(this.BodyLow()-this.Low());                                 }
   double            BodyHigh(void)                               const { return ::fmax(this.Close(),this.Open());                           }
   double            BodyLow(void)                                const { return ::fmin(this.Close(),this.Open());                           }
   
//--- Рассчитывает и возвращает процентное отношение размера (1) тела свечи, (2) верхней, (3) нижней тени к полному размеру свечи
   double            CandleRatioBodyToCandleSize(void)            const { return(this.CandleSize()>0 ? this.BodySize()*100.0/this.CandleSize()      : 100.0);  }
   double            CandleRatioUpperShadowToCandleSize(void)     const { return(this.CandleSize()>0 ? this.ShadowUpSize()*100.0/this.CandleSize()  : 100.0);  }
   double            CandleRatioLowerShadowToCandleSize(void)     const { return(this.CandleSize()>0 ? this.ShadowDownSize()*100.0/this.CandleSize(): 100.0);  }
   
//--- Возвращает (1) год, (2) месяц, к которому относится бар, (3) день недели,
//--- (4) порядковый номер в году, (5) день, (6) час, (7) минуту бара,
   int               TimeYear(void)                               const { return this.m_dt_struct.year;                                      }
   int               TimeMonth(void)                              const { return this.m_dt_struct.mon;                                       }
   int               TimeDayOfWeek(void)                          const { return this.m_dt_struct.day_of_week;                               }
   int               TimeDayOfYear(void)                          const { return this.m_dt_struct.day_of_year;                               }
   int               TimeDay(void)                                const { return this.m_dt_struct.day;                                       }
   int               TimeHour(void)                               const { return this.m_dt_struct.hour;                                      }
   int               TimeMinute(void)                             const { return this.m_dt_struct.min;                                       }

public:


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

//+------------------------------------------------------------------+ 
//| Методы упрощённого доступа к свойствам объекта-бара              |
//+------------------------------------------------------------------+
//--- Возвращает (1) тип, (2) период, (3) спред, (4) тиковый, (5) биржевой объём,
//--- (6) время начала периода бара, (7) год, (8) месяц, к которому относится бар
//--- (9) номер недели от начала года, (10) номер недели от начала месяца
//--- (11) день, (12) час, (13) минута
   ENUM_BAR_BODY_TYPE TypeBody(void)                                    const { return (ENUM_BAR_BODY_TYPE)this.GetProperty(BAR_PROP_TYPE);  }
   ENUM_TIMEFRAMES   Timeframe(void)                                    const { return (ENUM_TIMEFRAMES)this.GetProperty(BAR_PROP_PERIOD);   }
   int               Spread(void)                                       const { return (int)this.GetProperty(BAR_PROP_SPREAD);               }
   long              VolumeTick(void)                                   const { return this.GetProperty(BAR_PROP_VOLUME_TICK);               }
   long              VolumeReal(void)                                   const { return this.GetProperty(BAR_PROP_VOLUME_REAL);               }
   datetime          Time(void)                                         const { return (datetime)this.GetProperty(BAR_PROP_TIME);            }
   long              Year(void)                                         const { return this.GetProperty(BAR_PROP_TIME_YEAR);                 }
   long              Month(void)                                        const { return this.GetProperty(BAR_PROP_TIME_MONTH);                }
   long              DayOfWeek(void)                                    const { return this.GetProperty(BAR_PROP_TIME_DAY_OF_WEEK);          }
   long              DayOfYear(void)                                    const { return this.GetProperty(BAR_PROP_TIME_DAY_OF_YEAR);          }
   long              Day(void)                                          const { return this.GetProperty(BAR_PROP_TIME_DAY);                  }
   long              Hour(void)                                         const { return this.GetProperty(BAR_PROP_TIME_HOUR);                 }
   long              Minute(void)                                       const { return this.GetProperty(BAR_PROP_TIME_MINUTE);               }

//--- Возвращает цену (1) Open, (2) High, (3) Low, (4) Close бара,
//--- размер (5) свечи, (6) тела, (7) верх, (8) низ свечи,
//--- размер (9) верхней, (10) нижней тени свечи
   double            Open(void)                                         const { return this.GetProperty(BAR_PROP_OPEN);                      }
   double            High(void)                                         const { return this.GetProperty(BAR_PROP_HIGH);                      }
   double            Low(void)                                          const { return this.GetProperty(BAR_PROP_LOW);                       }
   double            Close(void)                                        const { return this.GetProperty(BAR_PROP_CLOSE);                     }
   double            Size(void)                                         const { return this.GetProperty(BAR_PROP_CANDLE_SIZE);               }
   double            SizeBody(void)                                     const { return this.GetProperty(BAR_PROP_CANDLE_SIZE_BODY);          }
   double            TopBody(void)                                      const { return this.GetProperty(BAR_PROP_CANDLE_BODY_TOP);           }
   double            BottomBody(void)                                   const { return this.GetProperty(BAR_PROP_CANDLE_BODY_BOTTOM);        }
   double            SizeShadowUp(void)                                 const { return this.GetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_UP);     }
   double            SizeShadowDown(void)                               const { return this.GetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_DOWN);   }
   
//--- Возвращает свойства процентного отношения размера (1) тела свечи, (2) верхней, (3) нижней тени к полному размеру свечи
   double            RatioBodyToCandleSize(void)                  const { return this.GetProperty(BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE);        }
   double            RatioUpperShadowToCandleSize(void)           const { return this.GetProperty(BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE);}
   double            RatioLowerShadowToCandleSize(void)           const { return this.GetProperty(BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE);}
   
//--- Возвращает символ бара
   string            Symbol(void)                                       const { return this.GetProperty(BAR_PROP_SYMBOL);                    }
//--- Возвращает индекс бара на указанном таймфрейме, в который попадает время бара
   int               Index(const ENUM_TIMEFRAMES timeframe)  const
                       { return ::iBarShift(this.Symbol(),(timeframe==PERIOD_CURRENT ? ::Period() : timeframe),this.Time());                 }  


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

//+------------------------------------------------------------------+
//| Устанавливает параметры объекта-бар                              |
//+------------------------------------------------------------------+
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_TYPE,this.BodyType());
//--- Установим тип объекта в объект класса управления графическими объектами
   this.m_graph_elm.SetTypeNode(this.m_type);
  }


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

//+------------------------------------------------------------------+
//| Возвращает описание вещественного свойства бара                  |
//+------------------------------------------------------------------+
string CBar::GetPropertyDescription(ENUM_BAR_PROP_DOUBLE property)
  {
   int dg=(this.m_digits>0 ? this.m_digits : 1);
   return
     (
      property==BAR_PROP_OPEN                ?  CMessage::Text(MSG_ORD_PRICE_OPEN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_HIGH                ?  CMessage::Text(MSG_LIB_TEXT_BAR_HIGH)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_LOW                 ?  CMessage::Text(MSG_LIB_TEXT_BAR_LOW)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_CLOSE               ?  CMessage::Text(MSG_ORD_PRICE_CLOSE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_CANDLE_SIZE         ?  CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_CANDLE_SIZE_BODY    ?  CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE_BODY)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_CANDLE_SIZE_SHADOW_UP  ?  CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE_SHADOW_UP)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_CANDLE_SIZE_SHADOW_DOWN   ?  CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE_SHADOW_DOWN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_CANDLE_BODY_TOP     ?  CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_BODY_TOP)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_CANDLE_BODY_BOTTOM  ?  CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_BODY_BOTTOM)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE  ?  CMessage::Text(MSG_LIB_TEXT_BAR_RATIO_BODY_TO_CANDLE_SIZE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)+"%"
         )  :
      property==BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE  ?  CMessage::Text(MSG_LIB_TEXT_BAR_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)+"%"
         )  :
      property==BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE  ?  CMessage::Text(MSG_LIB_TEXT_BAR_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)+"%"
         )  :
      ""
     );
  }


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

Класс абстрактного паттерна

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

//+------------------------------------------------------------------+
//|                                                      Pattern.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\..\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Класс абстрактного паттерна                                      |
//+------------------------------------------------------------------+
class CPattern : public CBaseObj
  {
  }


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

class CPattern : public CBaseObj
  {
private:
   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:


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

protected:
   CForm            *m_form;                                      // Указатель на объект-форму
   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;                      // Цвет панели двунаправленного паттерна

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;}

//--- Сравнивает объекты 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) вещественного и (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:
//--- Удаляет графический объект
   bool              DeleteGraphObj(bool redraw=false);
//--- Устанавливает цвета отображения графического объекта для (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;        }
//--- Создаёт объект инфо-панели
   bool              CreateInfoPanel(void);
//--- Создаёт внешний вид инфо-панели
   virtual void      CreateInfoPanelView(void){}
public:
//--- Устанавливает цвета графического объекта и цвет отображения паттерна
   void              SetColors(const color color_bullish,const color color_bearish,const color color_bidirect,const bool redraw=false);
//--- Устанавливает цвет фона панели (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);

//--- Рисует значёк паттерна на графике
   void              Draw(const bool redraw=false);
//--- (1) Отображает, (2) скрывает значёк паттерна на графике
   void              Show(const bool redraw=false);
   void              Hide(const bool redraw=false);
//--- (1) Отображает, (2) скрывает инфо-панель на графике
   void              ShowInfoPanel(const int x,const int y);
   void              HideInfoPanel(void);
  };


Рассмотрим реализацию объявленных методов.

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

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
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=clrGreen;
   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;
     }
//--- Устанавливаем базовые цвета информационных панелей паттерна
   this.m_color_panel_bullish=clrLightGray;
   this.m_color_panel_bearish=clrLightGray;
   this.m_color_panel_bidirect=clrLightGray;
   this.m_form=NULL;
  }


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

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


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

//+------------------------------------------------------------------+
//| Сравнивает объекты CPattern между собой по указанному свойству   |
//+------------------------------------------------------------------+
int CPattern::Compare(const CObject *node,const int mode=0) const
  {
   const CPattern *obj_compared=node;
//--- сравнение целочисленных свойств двух паттернов
   if(mode<PATTERN_PROP_INTEGER_TOTAL)
     {
      long value_compared=obj_compared.GetProperty((ENUM_PATTERN_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_PATTERN_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение вещественных свойств двух паттернов
   else if(mode<PATTERN_PROP_DOUBLE_TOTAL+PATTERN_PROP_INTEGER_TOTAL)
     {
      double value_compared=obj_compared.GetProperty((ENUM_PATTERN_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_PATTERN_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение строковых свойств двух паттернов
   else if(mode<PATTERN_PROP_DOUBLE_TOTAL+PATTERN_PROP_INTEGER_TOTAL+PATTERN_PROP_STRING_TOTAL)
     {
      string value_compared=obj_compared.GetProperty((ENUM_PATTERN_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_PATTERN_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }

Это стандартный метод библиотеки для сравнения свойств двух объектов.


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

//+------------------------------------------------------------------+
//| Сравнивает объекты CPattern между собой по всем свойствам        |
//+------------------------------------------------------------------+
bool CPattern::IsEqual(CPattern *compared_obj) const
  {
   int begin=0, end=PATTERN_PROP_INTEGER_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_PATTERN_PROP_INTEGER prop=(ENUM_PATTERN_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   begin=end; end+=PATTERN_PROP_DOUBLE_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_PATTERN_PROP_DOUBLE prop=(ENUM_PATTERN_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   begin=end; end+=PATTERN_PROP_STRING_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_PATTERN_PROP_STRING prop=(ENUM_PATTERN_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }

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


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

//+------------------------------------------------------------------+
//| Выводит в журнал свойства паттерна                               |
//+------------------------------------------------------------------+
void CPattern::Print(const bool full_prop=false,const bool dash=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int begin=0, end=PATTERN_PROP_INTEGER_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_PATTERN_PROP_INTEGER prop=(ENUM_PATTERN_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   begin=end; end+=PATTERN_PROP_DOUBLE_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_PATTERN_PROP_DOUBLE prop=(ENUM_PATTERN_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   begin=end; end+=PATTERN_PROP_STRING_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_PATTERN_PROP_STRING prop=(ENUM_PATTERN_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n");
  }
//+------------------------------------------------------------------+
//| Выводит в журнал краткое описание паттерна                       |
//+------------------------------------------------------------------+
void CPattern::PrintShort(const bool dash=false,const bool symbol=false)
  {
   ::Print(this.Header(),":\n",(dash ? " - " : ""),this.Symbol(),", ",TimeframeDescription(this.Timeframe())," ",::TimeToString(this.Time()),", ",this.DirectDescription());
  }
//+------------------------------------------------------------------+
//| Возвращает краткое наименование объекта-паттерна                 |
//+------------------------------------------------------------------+
string CPattern::Header(void)
  {
   return(this.StatusDescription()+" "+this.TypeDescription());
  }
//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства паттерна             |
//+------------------------------------------------------------------+
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|TIME_SECONDS)
         )  :
      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)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание вещественного свойства паттерна              |
//+------------------------------------------------------------------+
string CPattern::GetPropertyDescription(ENUM_PATTERN_PROP_DOUBLE property)
  {
   int dg=(this.m_digits>0 ? this.m_digits : 1);
   return
     (
      property==PATTERN_PROP_BAR_PRICE_OPEN  ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_BAR_PRICE_OPEN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==PATTERN_PROP_BAR_PRICE_HIGH  ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_BAR_PRICE_HIGH)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==PATTERN_PROP_BAR_PRICE_LOW   ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_BAR_PRICE_LOW)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==PATTERN_PROP_BAR_PRICE_CLOSE ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_BAR_PRICE_CLOSE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE         ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_RATIO_BODY_TO_CANDLE_SIZE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION           ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_RATIO_BODY_TO_CANDLE_SIZE_CRIT)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION  ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRIT)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRIT)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание строкового свойства паттерна                 |
//+------------------------------------------------------------------+
string CPattern::GetPropertyDescription(ENUM_PATTERN_PROP_STRING property)
  {
   return
     (
      property==PATTERN_PROP_SYMBOL          ?  CMessage::Text(MSG_LIB_PROP_SYMBOL)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      property==PATTERN_PROP_NAME            ?  CMessage::Text(MSG_LIB_TEXT_PATTERN_NAME)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание направления паттерна                         |
//+------------------------------------------------------------------+
string CPattern::DirectDescription(void) const
  {
   switch(this.Direction())
     {
      case PATTERN_DIRECTION_BULLISH   :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_BULLISH);
      case PATTERN_DIRECTION_BEARISH   :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_BEARISH);
      case PATTERN_DIRECTION_BOTH      :  return CMessage::Text(MSG_LIB_TEXT_PATTERN_BOTH);
      default                          :  return "Unknown";
     }
  }

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


Методы для работы с графическими объектами:

//+------------------------------------------------------------------+
//| Удаляет графический объект-метку паттерна на графике             |
//+------------------------------------------------------------------+
bool CPattern::DeleteGraphObj(bool redraw=false)
  {
   if(::ObjectFind(this.m_chart_id,this.m_name_graph_obj)<0)
      return true;
   if(::ObjectDelete(this.m_chart_id,this.m_name_graph_obj))
     {
      if(redraw)
         ::ChartRedraw(this.m_chart_id);
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+
//| Создаёт инфо-панель                                              |
//+------------------------------------------------------------------+
bool CPattern::CreateInfoPanel(void)
  {
   int x=0, y=0;
//--- Если объект панели уже создан ранее - возвращаем true
   if(this.m_form!=NULL)
      return true;
//--- Определяем цену верхнего левого угла между High и Low свечи
   double price=(this.BarPriceHigh()+this.BarPriceLow())/2;
//--- По времени бара и рассчитанной цене получаем координаты X и Y панели
   if(!::ChartTimePriceToXY(this.m_chart_id,0,this.Time(),price,x,y))
      return false;
//--- Создаём объект панели
   this.m_form=this.CreateForm(this.ID(),this.Name(),x,y,4,4);
   if(this.m_form==NULL)
      return false;
//--- Рисуем внешний вид панели
   this.CreateInfoPanelView();
   return true;
  }
//+------------------------------------------------------------------+
//| Отображает инфо-панель на графике                                |
//+------------------------------------------------------------------+
void CPattern::ShowInfoPanel(const int x,const int y)
  {
//--- Если объекта панели ещё нету - создаём его
   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();
  }
//+------------------------------------------------------------------+
//| Скрывает инфо-панель на графике                                  |
//+------------------------------------------------------------------+
void CPattern::HideInfoPanel(void)
  {
   if(this.m_form!=NULL)
      this.m_form.Hide();
  }
//+------------------------------------------------------------------+
//| Рисует значок паттерна на графике                                |
//+------------------------------------------------------------------+
void CPattern::Draw(const bool redraw=false)
  {
//--- Если графический объект ещё не создавался - создаём его
   if(::ObjectFind(this.m_chart_id,this.m_name_graph_obj)<0)
     {
      if(!this.CreateTrendLine(this.m_chart_id,this.m_name_graph_obj,0,this.Time(),this.m_price,this.Time(),this.m_price,this.m_color,5))
         return;
     }
//--- Иначе - отображаем
   else
      this.Show(redraw);
  }
//+------------------------------------------------------------------+
//| Отображает значок паттерна на графике                            |
//+------------------------------------------------------------------+
void CPattern::Show(const bool redraw=false)
  {
   ::ObjectSetInteger(this.m_chart_id,this.m_name_graph_obj,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }
//+------------------------------------------------------------------+
//| Скрывает значок паттерна на графике                              |
//+------------------------------------------------------------------+
void CPattern::Hide(const bool redraw=false)
  {
   ::ObjectSetInteger(this.m_chart_id,this.m_name_graph_obj,OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS);
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }
//+------------------------------------------------------------------+
//| Устанавливает цвета графического объекта                         |
//| и цвет отображения паттерна                                      |
//+------------------------------------------------------------------+
void CPattern::SetColors(const color color_bullish,const color color_bearish,const color color_bidirect,const bool redraw=false)
  {
   this.SetColorBullish(color_bullish);
   this.SetColorBearish(color_bearish);
   this.SetColorBiDirect(color_bidirect);
   this.m_color=(this.Direction()==PATTERN_DIRECTION_BULLISH ? this.m_color_bullish : this.Direction()==PATTERN_DIRECTION_BEARISH ? this.m_color_bearish : this.m_color_bidirect);
   ::ObjectSetInteger(this.m_chart_id,this.m_name_graph_obj,OBJPROP_COLOR,this.m_color);
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }

Методы достаточно просты и прокомментированы. Каждый из них разбирать не имеет особого смысла — все методы понятны при чтении их кода.

Объект базового абстрактного паттерна готов. На его основе будем делать все запланированные для библиотеки паттерны. И уже в них будем прописывать точные параметры и используемые/неиспользуемые свойства.

Начнём с простого, но полезного паттерна Price Action Pin Bar.


Паттерн Пин-бар

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

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

Рассмотрим класс паттерна Пин-Бар, который продолжаем писать в том же файле, где и базовый класс паттернов:

//+------------------------------------------------------------------+
//| Класс паттерна "Пин-Бар"                                         |
//+------------------------------------------------------------------+
class CPatternPinBar : public CPattern
  {
protected:
//--- Создаёт внешний вид инфо-панели
   virtual void      CreateInfoPanelView(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_PIN_BAR); }

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

Методы, возвращающие описания статуса и типа паттерна возвращают строки "Формация Price Action" и "Pin Bar" соответственно. Методы, возвращающие флаги использования свойств, здесь для всех свойств возвращают true. При добавлении новых паттернов и новых свойств бара для паттернов, будем запрещать те свойства, которые не имеют отношения к паттерну Пин Бар.

В конструкторе класса в строке инициализации в родительский класс передаём статус паттерна "Price Action", тип паттерна "Pin Bar" и остальные параметры, переданные во входных параметрах конструктора:

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
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);
  }

В теле конструктора устанавливаем наименование паттерна "Pin Bar" и количество свечей, составляющих паттерн, равное 1.


Виртуальный метод, создающий внешний вид инфо-панели, для каждого паттерна будет своим — будет отображать присущие паттерну свойства. Для паттерна Пин Бар метод будет таким:

//+------------------------------------------------------------------+
//| Создаёт внешний вид инфо-панели                                  |
//+------------------------------------------------------------------+
void CPatternPinBar::CreateInfoPanelView(void)
  {
//--- Если объект-форма не создана - уходим
   if(this.m_form==NULL)
      return;
//--- Изменяем тональность цветовой окраски для бычьих и медвежьих паттернов: бычий будет иметь синий оттенок, медвежий - красный
   color color_bullish=this.m_form.ChangeRGBComponents(this.m_form.ChangeColorLightness(this.m_color_panel_bullish,5),0,0,30);
   color color_bearish=this.m_form.ChangeRGBComponents(this.m_form.ChangeColorLightness(this.m_color_panel_bearish,5),30,0,0);
   color color_bidirect=this.m_color_bidirect;
//--- Объявляем массив для начального и конечного цветов градиентной заливки
   color clr[2]={};
//--- В зависимости от направления паттерна меняем светлоту соответствующих цветов - начальный чуть темнее, конечный - чуть светлее
   switch(this.Direction())
     {
      case PATTERN_DIRECTION_BULLISH : 
        clr[0]=this.m_form.ChangeColorLightness(color_bullish,-2.5);
        clr[1]=this.m_form.ChangeColorLightness(color_bullish,2.5);
        break;
      case PATTERN_DIRECTION_BEARISH : 
        clr[0]=this.m_form.ChangeColorLightness(color_bearish,-2.5);
        clr[1]=this.m_form.ChangeColorLightness(color_bearish,2.5);
        break;
      default:
        clr[0]=this.m_form.ChangeColorLightness(color_bidirect,-2.5);
        clr[1]=this.m_form.ChangeColorLightness(color_bidirect,2.5);
        break;
     }
   
//--- Устанавливаем цвета фона и рамки формы
   this.m_form.SetBackgroundColor(this.Direction()==PATTERN_DIRECTION_BULLISH ? color_bullish : this.Direction()==PATTERN_DIRECTION_BEARISH ? color_bearish : this.m_color_bidirect,true);
   this.m_form.SetBorderColor(clrGray,true);
//--- Создаём строки для описания паттерна, его параметров и критериев его поиска
   string name=::StringFormat("Pin Bar (%.2f/%.2f/%.2f)",this.GetProperty(PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE),this.GetProperty(PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE),this.GetProperty(PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE));
   string param=::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);
  }

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

Здесь в заголовке указаны пропорции свечи:

  • 16.22 — отношение тела свечи к размеру всей свечи, 
  • 18.92 — отношение верхней тени к размеру всей свечи, 
  • 64.86 — отношение нижней тени к размеру всей свечи.

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

  • 30.00 — тело не должно быть более 30% от размера всей свечи, 
  • 60.00 — наибольшая тень должна быть не менее 60% от размера всей свечи, 
  • 30.00 — наименьшая тень не должна быть более 30% от размера всей свечи.

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

С классами паттернов на сегодня завершили. Теперь нужно интегрировать их в библиотеку.


Чтобы мы могли сортировать паттерны, фильтровать и выбирать нужные, необходимо создать такой инструментарий. В классе CSelect в файле библиотеки \MQL5\Include\DoEasy\Services\Select.mqh допишем всё необходимое.

В первую очередь подключим к файлу класса CSelect файл классов паттернов:

//+------------------------------------------------------------------+
//|                                                       Select.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\Objects\Orders\Order.mqh"
#include "..\Objects\Events\Event.mqh"
#include "..\Objects\Accounts\Account.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "..\Objects\PendRequest\PendRequest.mqh"
#include "..\Objects\Series\\Patterns\Pattern.mqh"
#include "..\Objects\Series\SeriesDE.mqh"
#include "..\Objects\Indicators\Buffer.mqh"
#include "..\Objects\Indicators\IndicatorDE.mqh"
#include "..\Objects\Indicators\DataInd.mqh"
#include "..\Objects\Ticks\DataTick.mqh"
#include "..\Objects\Book\MarketBookOrd.mqh"
#include "..\Objects\MQLSignalBase\MQLSignal.mqh"
#include "..\Objects\Chart\ChartObj.mqh"
#include "..\Objects\Graph\GCnvElement.mqh"
#include "..\Objects\Graph\Standard\GStdGraphObj.mqh"


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

//+------------------------------------------------------------------+
//| Методы работы с барами таймсерии                                 |
//+------------------------------------------------------------------+
   //--- Возвращает список баров, у которых одно из (1) целочисленных, (2) вещественных и (3) строковых свойств удовлетворяет заданному критерию
   static CArrayObj *ByBarProperty(CArrayObj *list_source,ENUM_BAR_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByBarProperty(CArrayObj *list_source,ENUM_BAR_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByBarProperty(CArrayObj *list_source,ENUM_BAR_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode);
   //--- Возвращает индекс бара в списке с максимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства бара
   static int        FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_INTEGER property);
   static int        FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_DOUBLE property);
   static int        FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_STRING property);
   //--- Возвращает индекс бара в списке с минимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства бара
   static int        FindBarMin(CArrayObj *list_source,ENUM_BAR_PROP_INTEGER property);
   static int        FindBarMin(CArrayObj *list_source,ENUM_BAR_PROP_DOUBLE property);
   static int        FindBarMin(CArrayObj *list_source,ENUM_BAR_PROP_STRING property);
//+------------------------------------------------------------------+
//| Методы работы с паттернами таймсерии                             |
//+------------------------------------------------------------------+
   //--- Возвращает список паттернов, у которых одно из (1) целочисленных, (2) вещественных и (3) строковых свойств удовлетворяет заданному критерию
   static CArrayObj *ByPatternProperty(CArrayObj *list_source,ENUM_PATTERN_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByPatternProperty(CArrayObj *list_source,ENUM_PATTERN_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByPatternProperty(CArrayObj *list_source,ENUM_PATTERN_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode);
   //--- Возвращает индекс паттерна в списке с максимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства паттерна
   static int        FindPatternMax(CArrayObj *list_source,ENUM_PATTERN_PROP_INTEGER property);
   static int        FindPatternMax(CArrayObj *list_source,ENUM_PATTERN_PROP_DOUBLE property);
   static int        FindPatternMax(CArrayObj *list_source,ENUM_PATTERN_PROP_STRING property);
   //--- Возвращает индекс паттерна в списке с минимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства паттерна
   static int        FindPatternMin(CArrayObj *list_source,ENUM_PATTERN_PROP_INTEGER property);
   static int        FindPatternMin(CArrayObj *list_source,ENUM_PATTERN_PROP_DOUBLE property);
   static int        FindPatternMin(CArrayObj *list_source,ENUM_PATTERN_PROP_STRING property);
//+------------------------------------------------------------------+
//| Методы работы с индикаторными буферами                           |
//+------------------------------------------------------------------+


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

//+------------------------------------------------------------------+
//| Методы работы со списками паттернов таймсерии                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Возвращает список паттернов, у которых одно из целочисленных     |
//| свойств удовлетворяет заданному критерию                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByPatternProperty(CArrayObj *list_source,ENUM_PATTERN_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   int total=list_source.Total();
   for(int i=0; i<total; i++)
     {
      CPattern *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      long obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Возвращает список паттернов, у которых одно из вещественных      |
//| свойств удовлетворяет заданному критерию                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByPatternProperty(CArrayObj *list_source,ENUM_PATTERN_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CPattern *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      double obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Возвращает список паттернов, у которых одно из строковых         |
//| свойств удовлетворяет заданному критерию                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByPatternProperty(CArrayObj *list_source,ENUM_PATTERN_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CPattern *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      string obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Возвращает индекс паттерна в списке                              |
//| с максимальным значением целочисленного свойства                 |
//+------------------------------------------------------------------+
int CSelect::FindPatternMax(CArrayObj *list_source,ENUM_PATTERN_PROP_INTEGER property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CPattern *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CPattern *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      long obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Возвращает индекс паттерна в списке                              |
//| с максимальным значением вещественного свойства                  |
//+------------------------------------------------------------------+
int CSelect::FindPatternMax(CArrayObj *list_source,ENUM_PATTERN_PROP_DOUBLE property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CPattern *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CPattern *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      double obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Возвращает индекс паттерна в списке                              |
//| с максимальным значением строкового свойства                     |
//+------------------------------------------------------------------+
int CSelect::FindPatternMax(CArrayObj *list_source,ENUM_PATTERN_PROP_STRING property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CPattern *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CPattern *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      string obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Возвращает индекс паттерна в списке                              |
//| с минимальным значением целочисленного свойства                  |
//+------------------------------------------------------------------+
int CSelect::FindPatternMin(CArrayObj* list_source,ENUM_PATTERN_PROP_INTEGER property)
  {
   int index=0;
   CPattern *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CPattern *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      long obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Возвращает индекс паттерна в списке                              |
//| с минимальным значением вещественного свойства                   |
//+------------------------------------------------------------------+
int CSelect::FindPatternMin(CArrayObj* list_source,ENUM_PATTERN_PROP_DOUBLE property)
  {
   int index=0;
   CPattern *min_obj=NULL;
   int total=list_source.Total();
   if(total== 0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CPattern *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      double obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Возвращает индекс паттерна в списке                              |
//| с минимальным значением строкового свойства                      |
//+------------------------------------------------------------------+
int CSelect::FindPatternMin(CArrayObj* list_source,ENUM_PATTERN_PROP_STRING property)
  {
   int index=0;
   CPattern *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CPattern *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      string obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }

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

Единственное, что сейчас отличает рассмотренный ранее класс, — это метод сравнения значений двух объектов CompareValues(). Ранее он был таким:

//+------------------------------------------------------------------+
//| Метод сравнения двух величин                                     |
//+------------------------------------------------------------------+
template<typename T>
bool CSelect::CompareValues(T value1,T value2,ENUM_COMPARER_TYPE mode)
  {
   return
     (
      mode==EQUAL && value1==value2          ?  true  :
      mode==NO_EQUAL && value1!=value2       ?  true  :
      mode==MORE && value1>value2            ?  true  :
      mode==LESS && value1<value2            ?  true  :
      mode==EQUAL_OR_MORE && value1>=value2  ?  true  :
      mode==EQUAL_OR_LESS && value1<=value2  ?  true  :  false
     );
  }

Сейчас же конструкция if-else, применённая в старом методе, заменена на конструкцию switch:

//+------------------------------------------------------------------+
//| Метод сравнения двух величин                                     |
//+------------------------------------------------------------------+
template<typename T>
bool CSelect::CompareValues(T value1,T value2,ENUM_COMPARER_TYPE mode)
  {
   switch(mode)
     {
      case EQUAL           :  return(value1==value2   ?  true  :  false);
      case NO_EQUAL        :  return(value1!=value2   ?  true  :  false);
      case MORE            :  return(value1>value2    ?  true  :  false);
      case LESS            :  return(value1<value2    ?  true  :  false);
      case EQUAL_OR_MORE   :  return(value1>=value2   ?  true  :  false);
      case EQUAL_OR_LESS   :  return(value1<=value2   ?  true  :  false);
      default              :  return false;
     }
  }

В таком виде сравнение должно работать быстрее.


Классы управления паттернами

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

По имеющемуся порядку файлов в библиотеке, для каждого нового типа классов создаётся свой собственный файл — это упорядочивает структуру библиотеки и уменьшает объём каждого из файлов. Но в данном случае пришлось классы управления паттернами расположить в файле класса таймсерии \MQL5\Include\DoEasy\Objects\Series\SeriesDE.mqh. Всё из-за того, что слишком много в библиотеке взаимосвязей разных классов и, если разделить класс таймсерии и классы управления паттернами по разным файлам и к файлу таймсерии подключить файл классов управления паттернами, то некоторые из файлов перестают компилироваться, так как в одном месте компилятор не имеет доступа к файлу таймсерии, а в другом — к файлу классов управления паттернами. Пока я не смог всё правильно подключить сколько бы ни пытался, и сколько бы вариантов не перепробовал. В конечном итоге решил писать классы управления паттернами прямо в файле класса таймсерии, в которой и будет находиться один из классов управления паттернами.

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

Откроем файл класса таймсерии \MQL5\Include\DoEasy\Objects\Series\SeriesDE.mqh и с самого его начала начнём писать новый класс — класс управления абстрактным паттерном:

//+------------------------------------------------------------------+
//|                                                     SeriesDE.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\..\Services\Select.mqh"
#include "..\..\Services\NewBarObj.mqh"
#include "Bar.mqh"
//+------------------------------------------------------------------+
//| Класс управления абстрактным паттерном                           |
//+------------------------------------------------------------------+
class CPatternControl : public CBaseObjExt
  {
private:
   ENUM_TIMEFRAMES   m_timeframe;                                                // Период графика таймсерии паттерна
   string            m_symbol;                                                   // Символ таймсерии паттерна
   double            m_point;                                                    // Point символа
   bool              m_used;                                                     // Флаг использования паттерна
   bool              m_drawing;                                                  // Флаг отрисовки значка паттерна на графике
//--- Обрабатываемый паттерн
   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;                                              // Наименование символа графика в виде числа

//--- (1) Ищет паттерн, возвращает направление или -1, если паттерн не найден,
//--- (2) создаёт паттерн с указанным направлением,
//--- (3) создаёт и возвращает уникальный код паттерна,
//--- (4) возвращает список паттернов, управляемых этим объектом
   virtual ENUM_PATTERN_DIRECTION FindPattern(const datetime series_bar_time,const uint min_body_size) 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;                                           }

public:
//--- Возвращает себя
   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) верхней, (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;                          }

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

//--- Ищет паттерны и добавляет найденные в список всех паттернов
   virtual int       CreateAndRefreshPatternList(void);
//--- Выводит паттерны на график
   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);
  };

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

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

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

//+------------------------------------------------------------------+
//| 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);
  }

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


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

//+------------------------------------------------------------------+
//| Сравнивает объекты CPatternControl между собой                   |
//+------------------------------------------------------------------+
int CPatternControl::Compare(const CObject *node,const int mode=0) const
  {
   const CPatternControl *obj_compared=node;
   return
     (
      this.SymbolCode()    >  obj_compared.SymbolCode()  ||
      this.Timeframe()     >  obj_compared.Timeframe()   || 
      this.TypePattern()   >  obj_compared.TypePattern() || 
      this.ObjectID()      >  obj_compared.ObjectID()     ?  1 :
      
      this.SymbolCode()    <  obj_compared.SymbolCode()  ||
      this.Timeframe()     <  obj_compared.Timeframe()   || 
      this.TypePattern()   <  obj_compared.TypePattern() || 
      this.ObjectID()      <  obj_compared.ObjectID()     ? -1 :
      0
     );
  }

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


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

//+------------------------------------------------------------------+
//| CPatternControl::Ищет паттерны и добавляет                       |
//| найденные в список всех паттернов                                |
//+------------------------------------------------------------------+
int CPatternControl::CreateAndRefreshPatternList(void)
  {
//--- Если не используется - уходим
   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;
//--- Сортируем полученный список по времени открытия баров
   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(),1);
      //--- Если паттерна нет - идём к следующему бару
      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;
           }
         //--- Если стоит флаг рисования - рисуем метку паттерна на графике
         if(this.m_drawing)
            pattern.Draw();
        }
     }
//--- Сортируем список всех паттернов по времени и возвращаем общее количество паттернов в списке
   this.m_list_all_patterns.Sort(SORT_BY_PATTERN_TIME);
   return m_list_all_patterns.Total();
  }

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


Метод, выводящий метки паттернов на график:

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

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

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


Так как сегодня делаем только один паттерн — Пин-Бар, то сделаем объект управления этим паттерном. Продолжим писать код далее в том же файле:

//+------------------------------------------------------------------+
//| Класс управления паттерном "Пин бар"                             |
//+------------------------------------------------------------------+
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) 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();
                       }
  };

В конструкторе класса в списке инициализации в родительский класс передаём статус паттерна Price Action и тип паттерна Pin Bar. Также в параметрах конструктора передаются указатели на внешние списки и критерии поиска паттерна.


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

//+------------------------------------------------------------------+
//| Создаёт идентификатор объекта на основе критериев поиска паттерна|
//+------------------------------------------------------------------+
ulong CPatternControlPinBar::CreateObjectID(void)
  {
   ushort body=(ushort)this.RatioBodyToCandleSizeValue()*100;
   ushort larger=(ushort)this.RatioLargerShadowToCandleSizeValue()*100;
   ushort smaller=(ushort)this.RatioSmallerShadowToCandleSizeValue()*100;
   ulong res=0;
   this.UshortToLong(body,0,res);
   this.UshortToLong(larger,1,res);
   return this.UshortToLong(smaller,2,res);
  }

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

//+------------------------------------------------------------------+
//| Упаковывает ushort-число в переданное long-число                 |
//+------------------------------------------------------------------+
long CBaseObjExt::UshortToLong(const ushort ushort_value,const uchar to_byte,long &long_value)
  {
   if(to_byte>3)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_INDEX));
      return 0;
     }
   return(long_value |= this.UshortToByte(ushort_value,to_byte));
  }
//+------------------------------------------------------------------+
//| Преобразует ushort-значение в заданный байт long-числа           |
//+------------------------------------------------------------------+
long CBaseObjExt::UshortToByte(const ushort value,const uchar to_byte) const
  {
   return(long)value<<(16*to_byte);
  }


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

//+------------------------------------------------------------------+
//| CPatternControlPinBar::Создаёт паттерн с указанным направлением  |
//+------------------------------------------------------------------+
CPattern *CPatternControlPinBar::CreatePattern(const ENUM_PATTERN_DIRECTION direction,const uint id,CBar *bar)
  {
//--- Если передан невалидный указатель на объект-бар - возвращаем NULL
   if(bar==NULL)
      return NULL;
//--- Заполняем структуру MqlRates данными бара
   MqlRates rates={0};
   rates.time=bar.Time();
   rates.open=bar.Open();
   rates.high=bar.High();
   rates.low=bar.Low();
   rates.close=bar.Close();
//--- Создаём новый паттерн Пин-Бар
   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;
  }

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


Метод, ищущий паттерн:

//+------------------------------------------------------------------+
//| CPatternControlPinBar::Ищет паттерн                              |
//+------------------------------------------------------------------+
ENUM_PATTERN_DIRECTION CPatternControlPinBar::FindPattern(const datetime series_bar_time,const uint min_body_size) const
  {
//--- Указатели на объекты
   CBar *bar=NULL;
   CPatternPinBar *pin_bar=NULL;
//--- Получаем данные одного бара по времени
   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)
      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)
      return PATTERN_DIRECTION_BEARISH;
//--- Паттернов не найдено - возвращаем -1
   return WRONG_VALUE;
  }

Логика метода прокомментирована в коде. Вкратце: Пин-Бар — это однобаровая формация Price Action, поэтому нам нужен всего один бар таймсерии. Получаем один бар по переданному в метод времени бара. Далее узнаём пропорции тела свечи относительно всего её размера. Если тело больше допустимого размера — паттерна точно нет, возвращаем -1. Если же критерий по размеру тела свечи пройден, то точно так же проверяем сначала тени свечи на допустимые размеры для бычьего паттерна, а затем, если бычьего паттерна нет, то проверяем тени свечи на размеры для медвежьего паттерна. Если паттерн найден — возвращаем его направление, если нет — возвращаем -1.


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

//+------------------------------------------------------------------+
//| Возвращает список паттернов, управляемых этим объектом           |
//+------------------------------------------------------------------+
CArrayObj *CPatternControlPinBar::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_PIN_BAR,EQUAL);
   return CSelect::ByPatternProperty(list,PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID(),EQUAL);
  }

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

Если на каком-то этапе список получить не удалось, то в результате будет возвращён NULL.

Объект управления паттерном Пин-Бар готов. В последующих статьях будем постепенно добавлять новые паттерны и новые объекту управления ими.


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

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

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

//+------------------------------------------------------------------+
//| Класс управления паттернами                                      |
//+------------------------------------------------------------------+
class CPatternsControl : public CBaseObjExt
  {
private:
   CArrayObj         m_list_controls;                                   // Список контроллеров управления паттернами
   CArrayObj        *m_list_series;                                     // Указатель на список таймсерии
   CArrayObj        *m_list_all_patterns;                               // Указатель на список всех паттернов
//--- Данные таймсерии
   ENUM_TIMEFRAMES   m_timeframe;                                       // Таймфрейм таймсерии
   string            m_symbol;                                          // Символ таймсерии
   
public:
//--- Возвращает (1) таймфрейм, (2) символ таймсерии, (3) себя
   ENUM_TIMEFRAMES   Timeframe(void)                                       const { return this.m_timeframe; }
   string            Symbol(void)                                          const { return this.m_symbol;    }
   CPatternsControl *GetObject(void)                                             { return &this;            }
   
protected:


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

//--- Возвращает объект управления паттерном Пин бар
   CPatternControl  *GetObjControlPatternPinBar(const double ratio_body=30,            // Процентное отношение тела свечи к полному размеру свечи
                                                const double ratio_larger_shadow=60,   // Процентное отношение размера большей тени к размеру свечи
                                                const double ratio_smaller_shadow=30)  // Процентное отношение размера меньшей тени к размеру свечи
                       {
                        //--- В цикле по списку объектов управления
                        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 || obj.TypePattern()!=PATTERN_TYPE_PIN_BAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           if(ratio_body==obj.RatioBodyToCandleSizeValue() && ratio_larger_shadow==obj.RatioLargerShadowToCandleSizeValue() && ratio_smaller_shadow==obj.RatioSmallerShadowToCandleSizeValue())
                              return obj;
                          }
                        //--- Не нашли - возвращаем NULL
                        return NULL;
                       }


Остальные методы созданы в виде заготовок. Рассмотрим полный список этих методов:

protected:
//--- Возвращает объект управления паттерном Харами
   CPatternControl  *GetObjControlPatternHarami(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 || obj.TypePattern()!=PATTERN_TYPE_HARAMI)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Крест харами
   CPatternControl  *GetObjControlPatternHaramiCross(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 || obj.TypePattern()!=PATTERN_TYPE_HARAMI_CROSS)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Пинцет
   CPatternControl  *GetObjControlPatternTweezer(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 || obj.TypePattern()!=PATTERN_TYPE_TWEEZER)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Просвет в облаках
   CPatternControl  *GetObjControlPatternPiercingLine(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 || obj.TypePattern()!=PATTERN_TYPE_PIERCING_LINE)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Завеса из темных облаков
   CPatternControl  *GetObjControlPatternDarkCloudCover(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 || obj.TypePattern()!=PATTERN_TYPE_DARK_CLOUD_COVER)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Три белых солдата
   CPatternControl  *GetObjControlPatternThreeWhiteSoldiers(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 || obj.TypePattern()!=PATTERN_TYPE_THREE_WHITE_SOLDIERS)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Три черные вороны
   CPatternControl  *GetObjControlPatternThreeBlackCrows(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 || obj.TypePattern()!=PATTERN_TYPE_THREE_BLACK_CROWS)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Падающая звезда
   CPatternControl  *GetObjControlPatternShootingStar(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 || obj.TypePattern()!=PATTERN_TYPE_SHOOTING_STAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Молот
   CPatternControl  *GetObjControlPatternHammer(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 || obj.TypePattern()!=PATTERN_TYPE_HAMMER)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Перевёрнутый молот
   CPatternControl  *GetObjControlPatternInvertedHammer(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 || obj.TypePattern()!=PATTERN_TYPE_INVERTED_HAMMER)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Повешенный
   CPatternControl  *GetObjControlPatternHangingMan(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 || obj.TypePattern()!=PATTERN_TYPE_HANGING_MAN)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Доджи
   CPatternControl  *GetObjControlPatternDoji(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 || obj.TypePattern()!=PATTERN_TYPE_DOJI)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Доджи стрекоза
   CPatternControl  *GetObjControlPatternDragonflyDoji(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 || obj.TypePattern()!=PATTERN_TYPE_DRAGONFLY_DOJI)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Доджи надгробие
   CPatternControl  *GetObjControlPatternGravestoneDoji(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 || obj.TypePattern()!=PATTERN_TYPE_GRAVESTONE_DOJI)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Утренняя звезда
   CPatternControl  *GetObjControlPatternMorningStar(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 || obj.TypePattern()!=PATTERN_TYPE_MORNING_STAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Утренняя доджи-звезда
   CPatternControl  *GetObjControlPatternMorningDojiStar(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 || obj.TypePattern()!=PATTERN_TYPE_MORNING_DOJI_STAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Вечерняя звезда
   CPatternControl  *GetObjControlPatternEveningStar(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 || obj.TypePattern()!=PATTERN_TYPE_EVENING_STAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Вечерняя доджи-звезда
   CPatternControl  *GetObjControlPatternEveningDojiStar(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 || obj.TypePattern()!=PATTERN_TYPE_EVENING_DOJI_STAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Три звезды
   CPatternControl  *GetObjControlPatternThreeStars(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 || obj.TypePattern()!=PATTERN_TYPE_THREE_STARS)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Брошенное дитя
   CPatternControl  *GetObjControlPatternAbandonedBaby(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 || obj.TypePattern()!=PATTERN_TYPE_ABANDONED_BABY)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }

//--- Price Action
//--- Возвращает объект управления паттерном Pivot Point Reversal
   CPatternControl  *GetObjControlPatternPivotPointReversal(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 || obj.TypePattern()!=PATTERN_TYPE_PIVOT_POINT_REVERSAL)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Внешний бар (Поглощение)
   CPatternControl  *GetObjControlPatternOutsideBar(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 || obj.TypePattern()!=PATTERN_TYPE_OUTSIDE_BAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Внутренний бар
   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 || obj.TypePattern()!=PATTERN_TYPE_INSIDE_BAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Пин бар
   CPatternControl  *GetObjControlPatternPinBar(const double ratio_body=30,            // Процентное отношение тела свечи к полному размеру свечи
                                                const double ratio_larger_shadow=60,   // Процентное отношение размера большей тени к размеру свечи
                                                const double ratio_smaller_shadow=30)  // Процентное отношение размера меньшей тени к размеру свечи
                       {
                        //--- В цикле по списку объектов управления
                        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 || obj.TypePattern()!=PATTERN_TYPE_PIN_BAR)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           if(ratio_body==obj.RatioBodyToCandleSizeValue() && ratio_larger_shadow==obj.RatioLargerShadowToCandleSizeValue() && ratio_smaller_shadow==obj.RatioSmallerShadowToCandleSizeValue())
                              return obj;
                          }
                        //--- Не нашли - возвращаем NULL
                        return NULL;
                       }
//--- Возвращает объект управления паттерном Рельсы
   CPatternControl  *GetObjControlPatternRails(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 || obj.TypePattern()!=PATTERN_TYPE_RAILS)
                              continue;
                           //--- Проверка условий поиска и возврат результата
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }

public:

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


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

//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternPinBar(const bool flag,                       // Флаг использования 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.SetUsed(flag);
                        //--- Если объекта нет, а флаг передан как true
                        else if(flag)
                          {
                           //--- Создаём новый объект управления паттернами Пин-Бар с указанными параметрами
                           obj=new CPatternControlPinBar(this.Symbol(),this.Timeframe(),this.m_list_series,this.m_list_all_patterns,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                           if(obj==NULL)
                              return;
                           //--- Добавляем указатель на созданный объект в список
                           if(!this.m_list_controls.Add(obj))
                             {
                              delete obj;
                              return;
                             }
                           //--- Устанавливаем флаг использования и параметры паттерна в объект управления
                           obj.SetUsed(flag);
                           obj.SetRatioBodyToCandleSizeValue(ratio_body);
                           obj.SetRatioLargerShadowToCandleSizeValue(ratio_larger_shadow);
                           obj.SetRatioSmallerShadowToCandleSizeValue(ratio_smaller_shadow);
                           obj.CreateAndRefreshPatternList();
                          }
                       }


Остальные методы написаны лишь как заготовки — их будем дополнять по мере создания новых паттернов:

public:
//+------------------------------------------------------------------+
//| Методы установки флага использования паттерна                    |
//+------------------------------------------------------------------+
//--- Устанавливает флаг использования паттерна Харами и создаёт объект управления если его ещё нет
   void              SetUsedPatternHarami(const bool flag)
                       {
                        
                       }
//--- Устанавливает флаг использования паттерна Крест харами и создаёт объект управления если его ещё нет
   void              SetUsedPatternHaramiCross(const bool flag)
                       {
                        
                       }
//--- Устанавливает флаг использования паттерна Пинцет и создаёт объект управления если его ещё нет
   void              SetUsedPatternTweezer(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Просвет в облаках и создаёт объект управления если его ещё нет
   void              SetUsedPatternPiercingLine(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Завеса из темных облаков и создаёт объект управления если его ещё нет
   void              SetUsedPatternDarkCloudCover(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Три белых солдата и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeWhiteSoldiers(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Три черные вороны и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeBlackCrows(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Падающая звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternShootingStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Молот и создаёт объект управления если его ещё нет
   void              SetUsedPatternHammer(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Перевёрнутый молот и создаёт объект управления если его ещё нет
   void              SetUsedPatternInvertedHammer(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Повешенный и создаёт объект управления если его ещё нет
   void              SetUsedPatternHangingMan(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Доджи и создаёт объект управления если его ещё нет
   void              SetUsedPatternDoji(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Доджи стрекоза и создаёт объект управления если его ещё нет
   void              SetUsedPatternDragonflyDoji(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Доджи надгробие и создаёт объект управления если его ещё нет
   void              SetUsedPatternGravestoneDoji(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Утренняя звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternMorningStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Утренняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternMorningDojiStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Вечерняя звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternEveningStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Вечерняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternEveningDojiStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Три звезды и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeStars(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Брошенное дитя и создаёт объект управления если его ещё нет
   void              SetUsedPatternAbandonedBaby(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Pivot Point Reversal и создаёт объект управления если его ещё нет
//--- Price Action
   void              SetUsedPatternPivotPointReversal(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Внешний бар (Поглощение) и создаёт объект управления если его ещё нет
   void              SetUsedPatternOutsideBar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternInsideBar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternPinBar(const bool flag,                       // Флаг использования 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.SetUsed(flag);
                        //--- Если объекта нет, а флаг передан как true
                        else if(flag)
                          {
                           //--- Создаём новый объект управления паттернами Пин-Бар с указанными параметрами
                           obj=new CPatternControlPinBar(this.Symbol(),this.Timeframe(),this.m_list_series,this.m_list_all_patterns,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                           if(obj==NULL)
                              return;
                           //--- Добавляем указатель на созданный объект в список
                           if(!this.m_list_controls.Add(obj))
                             {
                              delete obj;
                              return;
                             }
                           //--- Устанавливаем флаг использования и параметры паттерна в объект управления
                           obj.SetUsed(flag);
                           obj.SetRatioBodyToCandleSizeValue(ratio_body);
                           obj.SetRatioLargerShadowToCandleSizeValue(ratio_larger_shadow);
                           obj.SetRatioSmallerShadowToCandleSizeValue(ratio_smaller_shadow);
                           obj.CreateAndRefreshPatternList();
                          }
                       }
//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void              SetUsedPatternRails(const bool flag)
                       {
                       
                       }


Методы возврата флага использования паттерна. Здесь тоже готов лишь метод возврата флага использования паттерна Пин-Бар:

//--- Возвращает флаг использования паттерна Пин бар
   bool              IsUsedPatternPinBar(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.IsUsed() : false);
                       }


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

//+------------------------------------------------------------------+
//| Методы возврата флага использования паттерна                     |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг использования паттерна Харами
   bool              IsUsedPatternHarami(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHarami();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Крест харами
   bool              IsUsedPatternHaramiCross(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHaramiCross();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Пинцет
   bool              IsUsedPatternTweezer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternTweezer();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Просвет в облаках
   bool              IsUsedPatternPiercingLine(void)
                       {
                        CPatternControl *obj=GetObjControlPatternPiercingLine();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Завеса из темных облаков
   bool              IsUsedPatternDarkCloudCover(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDarkCloudCover();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Три белых солдата
   bool              IsUsedPatternThreeWhiteSoldiers(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeWhiteSoldiers();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Три черные вороны
   bool              IsUsedPatternThreeBlackCrows(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeBlackCrows();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Падающая звезда
   bool              IsUsedPatternShootingStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternShootingStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Молот
   bool              IsUsedPatternHammer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHammer();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Перевёрнутый молот
   bool              IsUsedPatternInvertedHammer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternInvertedHammer();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Повешенный
   bool              IsUsedPatternHangingMan(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHangingMan();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Доджи
   bool              IsUsedPatternDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDoji();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Доджи стрекоза
   bool              IsUsedPatternDragonflyDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDragonflyDoji();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Доджи надгробие
   bool              IsUsedPatternGravestoneDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternGravestoneDoji();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Утренняя звезда
   bool              IsUsedPatternMorningStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Утренняя доджи-звезда
   bool              IsUsedPatternMorningDojiStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningDojiStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Вечерняя звезда
   bool              IsUsedPatternEveningStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Вечерняя доджи-звезда
   bool              IsUsedPatternEveningDojiStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningDojiStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Три звезды
   bool              IsUsedPatternThreeStars(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeStars();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Брошенное дитя
   bool              IsUsedPatternAbandonedBaby(void)
                       {
                        CPatternControl *obj=GetObjControlPatternAbandonedBaby();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Price Action
//--- Возвращает флаг использования паттерна Pivot Point Reversal
   bool              IsUsedPatternPivotPointReversal(void)
                       {
                        CPatternControl *obj=GetObjControlPatternPivotPointReversal();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Внешний бар (Поглощение)
   bool              IsUsedPatternOutsideBar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternOutsideBar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Внутренний бар
   bool              IsUsedPatternInsideBar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternInsideBar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Пин бар
   bool              IsUsedPatternPinBar(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.IsUsed() : false);
                       }
//--- Возвращает флаг использования паттерна Рельсы
   bool              IsUsedPatternRails(void)
                       {
                        CPatternControl *obj=GetObjControlPatternRails();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }


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

//+------------------------------------------------------------------+
//| Методы обновления данных паттернов                               |
//+------------------------------------------------------------------+
//--- Ищет и обновляет все активные паттерны
   void              RefreshAll(void)
                       {
                        //--- В цикле по списку объектов управления паттернами
                        int total=this.m_list_controls.Total();
                        for(int i=0;i<total;i++)
                          {
                           //--- получаем очередной объект управления
                           CPatternControl *ctrl=this.m_list_controls.At(i);
                           if(ctrl==NULL)
                              continue;
                           //--- Если объект получен - ищем и создаём новый паттерн
                           ctrl.CreateAndRefreshPatternList();
                          }
                        //--- По окончании цикла выводим значки паттернов на график
                        this.DrawPatternPinBar();
                       }


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

//+------------------------------------------------------------------+
//| Методы рисования паттернов на графике                            |
//+------------------------------------------------------------------+
//--- Ставит метки паттернов Харами на графике
   void              DrawPatternHarami(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHarami();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Крест харами на графике
   void              DrawPatternHaramiCross(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHaramiCross();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Пинцет на графике
   void              DrawPatternTweezer(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternTweezer();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Просвет в облаках на графике
   void              DrawPatternPiercingLine(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternPiercingLine();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Завеса из темных облаков на графике
   void              DrawPatternDarkCloudCover(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternDarkCloudCover();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Три белых солдата на графике
   void              DrawPatternThreeWhiteSoldiers(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeWhiteSoldiers();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Три черные вороны на графике
   void              DrawPatternThreeBlackCrows(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeBlackCrows();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Падающая звезда на графике
   void              DrawPatternShootingStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternShootingStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Молот на графике
   void              DrawPatternHammer(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHammer();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Перевёрнутый молот на графике
   void              DrawPatternInvertedHammer(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternInvertedHammer();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Повешенный на графике
   void              DrawPatternHangingMan(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHangingMan();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Доджи на графике
   void              DrawPatternDoji(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternDoji();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Доджи стрекоза на графике
   void              DrawPatternDragonflyDoji(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternDragonflyDoji();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Доджи надгробие на графике
   void              DrawPatternGravestoneDoji(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternGravestoneDoji();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Утренняя звезда на графике
   void              DrawPatternMorningStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Утренняя доджи-звезда на графике
   void              DrawPatternMorningDojiStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningDojiStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Вечерняя звезда на графике
   void              DrawPatternEveningStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Вечерняя доджи-звезда на графике
   void              DrawPatternEveningDojiStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningDojiStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Три звезды на графике
   void              DrawPatternThreeStars(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeStars();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Брошенное дитя на графике
   void              DrawPatternAbandonedBaby(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternAbandonedBaby();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Pivot Point Reversal на графике
//--- Price Action
   void              DrawPatternPivotPointReversal(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternPivotPointReversal();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Внешний бар (Поглощение) на графике
   void              DrawPatternOutsideBar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternOutsideBar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Внутренний бар на графике
   void              DrawPatternInsideBar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternInsideBar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Пин бар на графике
   void              DrawPatternPinBar(const double ratio_body=30,            // Процентное отношение тела свечи к полному размеру свечи
                                       const double ratio_larger_shadow=60,   // Процентное отношение размера большей тени к размеру свечи
                                       const double ratio_smaller_shadow=30,  // Процентное отношение размера меньшей тени к размеру свечи
                                       const bool redraw=false)               // Флаг перерисовки графика
                       {
                        //--- Получаем объект управления паттерном с указанными параметрами
                        CPatternControl *obj=GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        if(obj==NULL)
                           return;
                        //--- Рисуем метки паттернов на графике
                        obj.DrawPatterns(redraw);
                       }
//--- Ставит метки паттернов Рельсы на графике
   void              DrawPatternRails(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternRails();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
                       
//--- Конструктор
                     CPatternsControl(const string symbol,const ENUM_TIMEFRAMES timeframe,CArrayObj *list_timeseries,CArrayObj *list_all_patterns);
  };


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

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CPatternsControl::CPatternsControl(const string symbol,const ENUM_TIMEFRAMES timeframe,CArrayObj *list_timeseries,CArrayObj *list_all_patterns)
  {
   this.m_type=OBJECT_DE_TYPE_SERIES_PATTERNS_CONTROLLERS;
   this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol);
   this.m_timeframe=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe);
   this.m_list_series=list_timeseries;
   this.m_list_all_patterns=list_all_patterns;
  }

Классы управления паттернами готовы.


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

В этом же файле \MQL5\Include\DoEasy\Objects\Series\SeriesDE.mqh внесём правки в класс таймсерии.

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

//+------------------------------------------------------------------+
//| Класс "Таймсерия"                                                |
//+------------------------------------------------------------------+
class CSeriesDE : public CBaseObj
  {
private:
   ENUM_TIMEFRAMES   m_timeframe;                                       // Таймфрейм
   string            m_symbol;                                          // Символ
   string            m_period_description;                              // Строковое описание таймфрейма
   datetime          m_firstdate;                                       // Самая первая дата по символу-периоду на данный момент
   datetime          m_lastbar_date;                                    // Время открытия последнего бара по символу-периоду
   uint              m_amount;                                          // Количество используемых данных таймсерии
   uint              m_required;                                        // Требуемое количество используемых данных таймсерии
   uint              m_bars;                                            // Количество баров в истории по символу и таймфрейму
   bool              m_sync;                                            // Флаг синхронизированности данных
   CArrayObj         m_list_series;                                     // Список-таймсерия
   CNewBarObj        m_new_bar_obj;                                     // Объект "Новый бар"
   CPatternsControl *m_patterns_control;                                // Указатель на объект управления паттернами
//--- Устанавливает самую первую дату по символу-периоду на данный момент и новое время открытия последнего бара по символу-периоду
   void              SetServerDate(void)
                       {
                        this.m_firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_FIRSTDATE);
                        this.m_lastbar_date=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_LASTBAR_DATE);
                       }
protected:
   CArrayObj        *m_list_all_patterns;                               // Указатель на список всех паттернов всех таймсерий всех символов
public:
//--- Возвращает (1) себя, (2) список-таймсерию, (3) объект "Новый бар" таймсерии, (4) объект управления паттернами
   CSeriesDE        *GetObject(void)                                    { return &this;                  }
   CArrayObj        *GetList(void)                                      { return &m_list_series;         }
   CNewBarObj       *GetNewBarObj(void)                                 { return &this.m_new_bar_obj;    }
   CPatternsControl *GetPatternsCtrlObj(void)                           { return this.m_patterns_control;}


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

//--- Конструкторы
                     CSeriesDE(CArrayObj *list);
                     CSeriesDE(CArrayObj *list,const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0);
                    ~CSeriesDE(void);
//+------------------------------------------------------------------+
//| Работа с паттернами                                              |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы установки флага использования паттерна и обновления данных|
//+------------------------------------------------------------------+
//--- Устанавливает флаг использования паттерна Харами и создаёт объект управления если его ещё нет
   void              SetUsedPatternHarami(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Крест харами и создаёт объект управления если его ещё нет
   void              SetUsedPatternHaramiCross(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Пинцет и создаёт объект управления если его ещё нет
   void              SetUsedPatternTweezer(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Просвет в облаках и создаёт объект управления если его ещё нет
   void              SetUsedPatternPiercingLine(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Завеса из темных облаков и создаёт объект управления если его ещё нет
   void              SetUsedPatternDarkCloudCover(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Три белых солдата и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeWhiteSoldiers(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Три черные вороны и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeBlackCrows(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Падающая звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternShootingStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Молот и создаёт объект управления если его ещё нет
   void              SetUsedPatternHammer(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Перевёрнутый молот и создаёт объект управления если его ещё нет
   void              SetUsedPatternInvertedHammer(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Повешенный и создаёт объект управления если его ещё нет
   void              SetUsedPatternHangingMan(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Доджи и создаёт объект управления если его ещё нет
   void              SetUsedPatternDoji(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Доджи стрекоза и создаёт объект управления если его ещё нет
   void              SetUsedPatternDragonflyDoji(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Доджи надгробие и создаёт объект управления если его ещё нет
   void              SetUsedPatternGravestoneDoji(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Утренняя звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternMorningStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Утренняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternMorningDojiStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Вечерняя звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternEveningStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Вечерняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternEveningDojiStar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Три звезды и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeStars(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Брошенное дитя и создаёт объект управления если его ещё нет
   void              SetUsedPatternAbandonedBaby(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Pivot Point Reversal и создаёт объект управления если его ещё нет
//--- Price Action
   void              SetUsedPatternPivotPointReversal(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Внешний бар (Поглощение) и создаёт объект управления если его ещё нет
   void              SetUsedPatternOutsideBar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternInsideBar(const bool flag)
                       {
                       
                       }
//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternPinBar(const bool flag,                       // Флаг использования 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.SetUsedPatternPinBar(flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                       }
//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void              SetUsedPatternRails(const bool flag)
                       {
                       
                       }
//+------------------------------------------------------------------+
//| Методы возврата флага использования паттерна                     |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг использования паттерна Харами
   bool              IsUsedPatternHarami(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHarami() : false);
                       }
//--- Возвращает флаг использования паттерна Крест харами
   bool              IsUsedPatternHaramiCross(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHaramiCross() : false);
                       }
//--- Возвращает флаг использования паттерна Пинцет
   bool              IsUsedPatternTweezer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternTweezer() : false);
                       }
//--- Возвращает флаг использования паттерна Просвет в облаках
   bool              IsUsedPatternPiercingLine(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternPiercingLine() : false);
                       }
//--- Возвращает флаг использования паттерна Завеса из темных облаков
   bool              IsUsedPatternDarkCloudCover(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternDarkCloudCover() : false);
                       }
//--- Возвращает флаг использования паттерна Три белых солдата
   bool              IsUsedPatternThreeWhiteSoldiers(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternThreeWhiteSoldiers() : false);
                       }
//--- Возвращает флаг использования паттерна Три черные вороны
   bool              IsUsedPatternThreeBlackCrows(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternThreeBlackCrows() : false);
                       }
//--- Возвращает флаг использования паттерна Падающая звезда
   bool              IsUsedPatternShootingStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternShootingStar() : false);
                       }
//--- Возвращает флаг использования паттерна Молот
   bool              IsUsedPatternHammer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHammer() : false);
                       }
//--- Возвращает флаг использования паттерна Перевёрнутый молот
   bool              IsUsedPatternInvertedHammer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternInvertedHammer() : false);
                       }
//--- Возвращает флаг использования паттерна Повешенный
   bool              IsUsedPatternHangingMan(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHangingMan() : false);
                       }
//--- Возвращает флаг использования паттерна Доджи
   bool              IsUsedPatternDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternDoji() : false);
                       }
//--- Возвращает флаг использования паттерна Доджи стрекоза
   bool              IsUsedPatternDragonflyDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternDragonflyDoji() : false);
                       }
//--- Возвращает флаг использования паттерна Доджи надгробие
   bool              IsUsedPatternGravestoneDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternGravestoneDoji() : false);
                       }
//--- Возвращает флаг использования паттерна Утренняя звезда
   bool              IsUsedPatternMorningStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternMorningStar() : false);
                       }
//--- Возвращает флаг использования паттерна Утренняя доджи-звезда
   bool              IsUsedPatternMorningDojiStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternMorningDojiStar() : false);
                       }
//--- Возвращает флаг использования паттерна Вечерняя звезда
   bool              IsUsedPatternEveningStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternEveningStar() : false);
                       }
//--- Возвращает флаг использования паттерна Вечерняя доджи-звезда
   bool              IsUsedPatternEveningDojiStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternEveningDojiStar() : false);
                       }
//--- Возвращает флаг использования паттерна Три звезды
   bool              IsUsedPatternThreeStars(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternThreeStars() : false);
                       }
//--- Возвращает флаг использования паттерна Брошенное дитя
   bool              IsUsedPatternAbandonedBaby(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternAbandonedBaby() : false);
                       }
//--- Price Action
//--- Возвращает флаг использования паттерна Pivot Point Reversal
   bool              IsUsedPatternPivotPointReversal(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternPivotPointReversal() : false);
                       }
//--- Возвращает флаг использования паттерна Внешний бар (Поглощение)
   bool              IsUsedPatternOutsideBar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternOutsideBar() : false);
                       }
//--- Возвращает флаг использования паттерна Внутренний бар
   bool              IsUsedPatternInsideBar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternInsideBar() : false);
                       }
//--- Возвращает флаг использования паттерна Пин бар
   bool              IsUsedPatternPinBar(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.IsUsedPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
                       }
//--- Возвращает флаг использования паттерна Рельсы
   bool              IsUsedPatternRails(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternRails() : false);
                       }
                       
//+------------------------------------------------------------------+
//| Методы рисования паттернов на графике                            |
//+------------------------------------------------------------------+
//--- Ставит метки паттернов Харами на графике
   void              DrawPatternHarami(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHarami(redraw);
                       }
//--- Ставит метки паттернов Крест харами на графике
   void              DrawPatternHaramiCross(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHaramiCross(redraw);
                       }
//--- Ставит метки паттернов Пинцет на графике
   void              DrawPatternTweezer(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternTweezer(redraw);
                       }
//--- Ставит метки паттернов Просвет в облаках на графике
   void              DrawPatternPiercingLine(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternPiercingLine(redraw);
                       }
//--- Ставит метки паттернов Завеса из темных облаков на графике
   void              DrawPatternDarkCloudCover(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternDarkCloudCover(redraw);
                       }
//--- Ставит метки паттернов Три белых солдата на графике
   void              DrawPatternThreeWhiteSoldiers(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternThreeWhiteSoldiers(redraw);
                       }
//--- Ставит метки паттернов Три черные вороны на графике
   void              DrawPatternThreeBlackCrows(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternThreeBlackCrows(redraw);
                       }
//--- Ставит метки паттернов Падающая звезда на графике
   void              DrawPatternShootingStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternShootingStar(redraw);
                       }
//--- Ставит метки паттернов Молот на графике
   void              DrawPatternHammer(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHammer(redraw);
                       }
//--- Ставит метки паттернов Перевёрнутый молот на графике
   void              DrawPatternInvertedHammer(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternInvertedHammer(redraw);
                       }
//--- Ставит метки паттернов Повешенный на графике
   void              DrawPatternHangingMan(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHangingMan(redraw);
                       }
//--- Ставит метки паттернов Доджи на графике
   void              DrawPatternDoji(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternDoji(redraw);
                       }
//--- Ставит метки паттернов Доджи стрекоза на графике
   void              DrawPatternDragonflyDoji(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternDragonflyDoji(redraw);
                       }
//--- Ставит метки паттернов Доджи надгробие на графике
   void              DrawPatternGravestoneDoji(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternGravestoneDoji(redraw);
                       }
//--- Ставит метки паттернов Утренняя звезда на графике
   void              DrawPatternMorningStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternMorningStar(redraw);
                       }
//--- Ставит метки паттернов Утренняя доджи-звезда на графике
   void              DrawPatternMorningDojiStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternMorningDojiStar(redraw);
                       }
//--- Ставит метки паттернов Вечерняя звезда на графике
   void              DrawPatternEveningStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternEveningStar(redraw);
                       }
//--- Ставит метки паттернов Вечерняя доджи-звезда на графике
   void              DrawPatternEveningDojiStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternEveningDojiStar(redraw);
                       }
//--- Ставит метки паттернов Три звезды на графике
   void              DrawPatternThreeStars(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternThreeStars(redraw);
                       }
//--- Ставит метки паттернов Брошенное дитя на графике
   void              DrawPatternAbandonedBaby(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternAbandonedBaby(redraw);
                       }
//--- Ставит метки паттернов Pivot Point Reversal на графике
//--- Price Action
   void              DrawPatternPivotPointReversal(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternPivotPointReversal(redraw);
                       }
//--- Ставит метки паттернов Внешний бар (Поглощение) на графике
   void              DrawPatternOutsideBar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternOutsideBar(redraw);
                       }
//--- Ставит метки паттернов Внутренний бар на графике
   void              DrawPatternInsideBar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternInsideBar(redraw);
                       }
//--- Ставит метки паттернов Пин бар на графике
   void              DrawPatternPinBar(const double ratio_body=30,            // Процентное отношение тела свечи к полному размеру свечи
                                       const double ratio_larger_shadow=60,   // Процентное отношение размера большей тени к размеру свечи
                                       const double ratio_smaller_shadow=30,  // Процентное отношение размера меньшей тени к размеру свечи
                                       const bool redraw=false)               // Флаг перерисовки графика
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
                       }
//--- Ставит метки паттернов Рельсы на графике
   void              DrawPatternRails(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternRails(redraw);
                       }
  };


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

//+------------------------------------------------------------------+
//| Конструктор 1 (таймсерия текущего символа и периода)             |
//+------------------------------------------------------------------+
CSeriesDE::CSeriesDE(CArrayObj *list) : m_bars(0),m_amount(0),m_required(0),m_sync(false)
  {
   this.m_type=OBJECT_DE_TYPE_SERIES_PERIOD; 
   this.m_list_series.Clear();
   this.m_list_series.Sort(SORT_BY_BAR_TIME);
   this.SetSymbolPeriod(NULL,(ENUM_TIMEFRAMES)::Period());
   this.m_period_description=TimeframeDescription(this.m_timeframe);
   this.m_list_all_patterns=list;
   this.m_patterns_control=new CPatternsControl(this.m_symbol,this.m_timeframe,this.GetList(),this.m_list_all_patterns);
  }
//+------------------------------------------------------------------+
//| Конструктор 2 (таймсерия указанных символа и периода)            |
//+------------------------------------------------------------------+
CSeriesDE::CSeriesDE(CArrayObj *list,const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0) : m_bars(0), m_amount(0),m_required(0),m_sync(false)
  {
   this.m_type=OBJECT_DE_TYPE_SERIES_PERIOD; 
   this.m_list_series.Clear();
   this.m_list_series.Sort(SORT_BY_BAR_TIME);
   this.SetSymbolPeriod(symbol,timeframe);
   this.m_sync=this.SetRequiredUsedData(required,0);
   this.m_period_description=TimeframeDescription(this.m_timeframe);
   this.m_list_all_patterns=list;
   this.m_patterns_control=new CPatternsControl(this.m_symbol,this.m_timeframe,this.GetList(),this.m_list_all_patterns);
  }


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

//+------------------------------------------------------------------+
//| Деструктор                                                       |
//+------------------------------------------------------------------+
CSeriesDE::~CSeriesDE(void)
  {
   if(this.m_patterns_control!=NULL)
      delete this.m_patterns_control;
  }


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

//+------------------------------------------------------------------+
//| Обновляет список и данные тайм-серии                             |
//+------------------------------------------------------------------+
void CSeriesDE::Refresh(SDataCalculate &data_calculate)
  {
//--- Если таймсерия не используется - выходим
   if(!this.m_available)
      return;
   MqlRates rates[1];
//--- Устанавливаем флаг сортировки списка баров по времени
   this.m_list_series.Sort(SORT_BY_BAR_TIME);
//--- Если есть новый бар на символе и периоде
   if(this.IsNewBarManual(data_calculate.rates.time))
     {
      //--- создаём новый объект-бар и добавляем его в конец списка
      CBar *new_bar=new CBar(this.m_symbol,this.m_timeframe,this.m_new_bar_obj.TimeNewBar(),DFUN_ERR_LINE);
      if(new_bar==NULL)
         return;
      if(!this.m_list_series.InsertSort(new_bar))
        {
         delete new_bar;
         return;
        }
      //--- Записываем самую первую дату по символу-периоду на данный момент и новое время открытия последнего бара по символу-периоду 
      this.SetServerDate();
      //--- если размер таймсерии стал больше запрашиваемого количества баров - удаляем самый ранний бар
      if(this.m_list_series.Total()>(int)this.m_required)
         this.m_list_series.Delete(0);
   
      //--- Обновляем данные всех паттернов таймсерии
      if(this.m_patterns_control==NULL)
         return;
      this.m_patterns_control.RefreshAll();
      
      //--- сохраняем новое время бара как прошлое для последующей проверки на новый бар
      this.SaveNewBarTime(data_calculate.rates.time);
     }
     
//--- Получаем индекс бара с максимальным временем (нулевой бар) и объект-бар из списка по полученному индексу
   int index=CSelect::FindBarMax(this.GetList(),BAR_PROP_TIME);
   CBar *bar=this.m_list_series.At(index);
   if(bar==NULL)
      return;
//--- если работа в индикаторе, и таймсерия принадлежит текущему символу и таймфрейму,
//--- копируем в структуру цен бара переданные в метод извне параметры цен
   int copied=1;
   if(this.m_program==PROGRAM_INDICATOR && this.m_symbol==::Symbol() && this.m_timeframe==(ENUM_TIMEFRAMES)::Period())
     {
      rates[0].time=data_calculate.rates.time;
      rates[0].open=data_calculate.rates.open;
      rates[0].high=data_calculate.rates.high;
      rates[0].low=data_calculate.rates.low;
      rates[0].close=data_calculate.rates.close;
      rates[0].tick_volume=data_calculate.rates.tick_volume;
      rates[0].real_volume=data_calculate.rates.real_volume;
      rates[0].spread=data_calculate.rates.spread;
     }
//--- иначе - получаем данные в структуру цен бара из окружения
   else
      copied=::CopyRates(this.m_symbol,this.m_timeframe,0,1,rates);
//--- Если цены получены - устанавливаем объекту-бару новые свойства из структуры цен
   if(copied==1)
      bar.SetProperties(rates[0]);
  }


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

//+------------------------------------------------------------------+
//| Класс "Таймсерии символа"                                        |
//+------------------------------------------------------------------+
class CTimeSeriesDE : public CBaseObjExt
  {
private:
   string            m_symbol;                                             // Символ таймсерий
   CNewTickObj       m_new_tick;                                           // Объект "Новый тик"
   CArrayObj         m_list_series;                                        // Список таймсерий по таймфреймам
   datetime          m_server_firstdate;                                   // Самая первая дата в истории по символу на сервере
   datetime          m_terminal_firstdate;                                 // Самая первая дата в истории по символу в клиентском терминале
//--- Возвращает (1) индекс таймфрейма в списке, (2) таймфрейм по индексу списка
   int               IndexTimeframe(const ENUM_TIMEFRAMES timeframe);
   ENUM_TIMEFRAMES   TimeframeByIndex(const uchar index)             const { return TimeframeByEnumIndex(uchar(index+1));                       }
//--- Устанавливает самую первую дату в истории по символу на сервере и в клиентском терминале
   void              SetTerminalServerDate(void)
                       {
                        this.m_server_firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,::Period(),SERIES_SERVER_FIRSTDATE);
                        this.m_terminal_firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,::Period(),SERIES_TERMINAL_FIRSTDATE);
                       }
protected:
   CArrayObj        *m_list_all_patterns;                                  // Указатель на список всех паттернов всех таймсерий всех символов

public:
//--- Возвращает (1) себя, полный список (2) таймсерий, (3) паттернов, (4) указанный объект-таймсерию, (5) объект-таймсерию по индексу
   CTimeSeriesDE    *GetObject(void)                                       { return &this;                                                      }
   CArrayObj        *GetListSeries(void)                                   { return &this.m_list_series;                                        }
   CArrayObj        *GetListPatterns(void)                                 { return this.m_list_all_patterns;                                   }
   CSeriesDE        *GetSeries(const ENUM_TIMEFRAMES timeframe)            { return this.m_list_series.At(this.IndexTimeframe(timeframe));      }
   CSeriesDE        *GetSeriesByIndex(const uchar index)                   { return this.m_list_series.At(index);                               }


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

//--- Конструкторы
                     CTimeSeriesDE(CArrayObj *list_all_patterns)
                       {
                        this.m_type=OBJECT_DE_TYPE_SERIES_SYMBOL;
                        this.m_list_all_patterns=list_all_patterns;
                       }
                     CTimeSeriesDE(CArrayObj *list_all_patterns,const string symbol);
                     
//+------------------------------------------------------------------+
//| Методы установки флага использования паттерна                    |
//+------------------------------------------------------------------+
//--- Устанавливает флаг использования паттерна Харами и создаёт объект управления если его ещё нет
   void              SetUsedPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Крест харами и создаёт объект управления если его ещё нет
   void              SetUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Пинцет и создаёт объект управления если его ещё нет
   void              SetUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Просвет в облаках и создаёт объект управления если его ещё нет
   void              SetUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Завеса из темных облаков и создаёт объект управления если его ещё нет
   void              SetUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Три белых солдата и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Три черные вороны и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Падающая звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Молот и создаёт объект управления если его ещё нет
   void              SetUsedPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Перевёрнутый молот и создаёт объект управления если его ещё нет
   void              SetUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Повешенный и создаёт объект управления если его ещё нет
   void              SetUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Доджи и создаёт объект управления если его ещё нет
   void              SetUsedPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Доджи стрекоза и создаёт объект управления если его ещё нет
   void              SetUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Доджи надгробие и создаёт объект управления если его ещё нет
   void              SetUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Утренняя звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Утренняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Вечерняя звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Вечерняя доджи-звезда и создаёт объект управления если его ещё нет
   void              SetUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Три звезды и создаёт объект управления если его ещё нет
   void              SetUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Брошенное дитя и создаёт объект управления если его ещё нет
   void              SetUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Pivot Point Reversal и создаёт объект управления если его ещё нет
//--- Price Action
   void              SetUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Внешний бар (Поглощение) и создаёт объект управления если его ещё нет
   void              SetUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void              SetUsedPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                          const bool flag,                       // Флаг использования Price Action Пин бар
                                          const double ratio_body=30,            // Процентное отношение тела свечи к полному размеру свечи
                                          const double ratio_larger_shadow=60,   // Процентное отношение размера большей тени к размеру свечи
                                          const double ratio_smaller_shadow=30); // Процентное отношение размера меньшей тени к размеру свечи
//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void              SetUsedPatternRails(const ENUM_TIMEFRAMES timeframe,const bool flag);
   
//+------------------------------------------------------------------+
//| Методы возврата флага использования паттерна                     |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг использования паттерна Харами
   bool              IsUsedPatternHarami(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Крест харами
   bool              IsUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пинцет
   bool              IsUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Просвет в облаках
   bool              IsUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Завеса из темных облаков
   bool              IsUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три белых солдата
   bool              IsUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три черные вороны
   bool              IsUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Падающая звезда
   bool              IsUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Молот
   bool              IsUsedPatternHammer(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Перевёрнутый молот
   bool              IsUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Повешенный
   bool              IsUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи
   bool              IsUsedPatternDoji(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи стрекоза
   bool              IsUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи надгробие
   bool              IsUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя звезда
   bool              IsUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя доджи-звезда
   bool              IsUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя звезда
   bool              IsUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя доджи-звезда
   bool              IsUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три звезды
   bool              IsUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Брошенное дитя
   bool              IsUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe);
//--- Price Action
//--- Возвращает флаг использования паттерна Pivot Point Reversal
   bool              IsUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внешний бар (Поглощение)
   bool              IsUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внутренний бар
   bool              IsUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пин бар
   bool              IsUsedPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                         const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                         const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                         const double ratio_smaller_shadow=30);  // Процентное отношение размера меньшей тени к размеру свечи
//--- Возвращает флаг использования паттерна Рельсы
   bool              IsUsedPatternRails(const ENUM_TIMEFRAMES timeframe);
   
//+------------------------------------------------------------------+
//| Методы рисования паттернов на графике                            |
//+------------------------------------------------------------------+
//--- Рисует метки паттернов Харами на графике
   void              DrawPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Крест харами на графике
   void              DrawPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Пинцет на графике
   void              DrawPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Просвет в облаках на графике
   void              DrawPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Завеса из темных облаков на графике
   void              DrawPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Три белых солдата на графике
   void              DrawPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Три черные вороны на графике
   void              DrawPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Падающая звезда на графике
   void              DrawPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Молот на графике
   void              DrawPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Перевёрнутый молот на графике
   void              DrawPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Повешенный на графике
   void              DrawPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Доджи на графике
   void              DrawPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Доджи стрекоза на графике
   void              DrawPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Доджи надгробие на графике
   void              DrawPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Утренняя звезда на графике
   void              DrawPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Утренняя доджи-звезда на графике
   void              DrawPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Вечерняя звезда на графике
   void              DrawPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Вечерняя доджи-звезда на графике
   void              DrawPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Три звезды на графике
   void              DrawPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Брошенное дитя на графике
   void              DrawPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Pivot Point Reversal на графике
//--- Price Action
   void              DrawPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Внешний бар (Поглощение) на графике
   void              DrawPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Внутренний бар на графике
   void              DrawPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Пин бар на графике
   void              DrawPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                       const double ratio_body=30,            // Процентное отношение тела свечи к полному размеру свечи
                                       const double ratio_larger_shadow=60,   // Процентное отношение размера большей тени к размеру свечи
                                       const double ratio_smaller_shadow=30,  // Процентное отношение размера меньшей тени к размеру свечи
                                       const bool redraw=false);              // Флаг перерисовки графика
//--- Рисует метки паттернов Рельсы на графике
   void              DrawPatternRails(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);

  };

Здесь только в методах для работы с паттерном Пин-Бар написаны входные параметры. В остальных методах будем их вписывать по мере создания классов новых паттернов.


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

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CTimeSeriesDE::CTimeSeriesDE(CArrayObj *list_all_patterns,const string symbol) : m_symbol(symbol)
  {
   this.m_type=OBJECT_DE_TYPE_SERIES_SYMBOL; 
   this.m_list_series.Clear();
   this.m_list_series.Sort();
   this.SetTerminalServerDate();
   this.m_new_tick.SetSymbol(this.m_symbol);
   this.m_new_tick.Refresh();
   this.m_list_all_patterns=list_all_patterns;
  }


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

//+------------------------------------------------------------------+
//| Возвращает индекс таймфрейма в списке                            |
//+------------------------------------------------------------------+
int CTimeSeriesDE::IndexTimeframe(const ENUM_TIMEFRAMES timeframe)
  {
   CArrayObj *list=NULL;
   const CSeriesDE *obj=new CSeriesDE(list,this.m_symbol,(timeframe==PERIOD_CURRENT ? (ENUM_TIMEFRAMES)::Period() : timeframe));
   if(obj==NULL)
      return WRONG_VALUE;
   this.m_list_series.Sort();
   int index=this.m_list_series.Search(obj);
   delete obj;
   return index;
  }


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

//+------------------------------------------------------------------+
//| Добавляет в список указанную список-таймсерию                    |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::AddSeries(const ENUM_TIMEFRAMES timeframe,const uint required=0)
  {
   bool res=false;
   CSeriesDE *series=new CSeriesDE(this.m_list_all_patterns,this.m_symbol,timeframe,required);
   if(series==NULL)
      return res;
   this.m_list_series.Sort();
   if(this.m_list_series.Search(series)==WRONG_VALUE)
      res=this.m_list_series.Add(series);
   series.SetAvailable(true);
   if(!res)
      delete series;
   return res;
  }


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

//+------------------------------------------------------------------+
//| Работа с паттернами таймсерий                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы установки флага использования паттерна                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Харами                 |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHarami(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Крест харами           |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHaramiCross(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Пинцет                 |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternTweezer(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Просвет в облаках      |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternPiercingLine(flag);
  }
//+------------------------------------------------------------------+
//|Устанавливает флаг использования паттерна Завеса из темных облаков|
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternDarkCloudCover(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Три белых солдата      |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternThreeWhiteSoldiers(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Три черные вороны      |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternThreeBlackCrows(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Падающая звезда        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternShootingStar(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Молот                  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHammer(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Перевёрнутый молот     |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternInvertedHammer(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Повешенный             |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHangingMan(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Доджи                  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternDoji(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Доджи стрекоза         |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternDragonflyDoji(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Доджи надгробие        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternGravestoneDoji(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Утренняя звезда        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternMorningStar(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Утренняя доджи-звезда  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternMorningDojiStar(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Вечерняя звезда        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternEveningStar(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Вечерняя доджи-звезда  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternEveningDojiStar(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Три звезды             |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternThreeStars(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Брошенное дитя         |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternAbandonedBaby(flag);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Pivot Point Reversal   |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternPivotPointReversal(flag);
  }
//+------------------------------------------------------------------+
//|Устанавливает флаг использования паттерна Внешний бар (Поглощение)|
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternOutsideBar(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Внутренний бар         |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
                     CSeriesDE *series=this.GetSeries(timeframe);
                     if(series!=NULL)
                        series.SetUsedPatternInsideBar(flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Пин бар                |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                         const bool flag,                        // Флаг использования 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.SetUsedPatternPinBar(flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Рельсы                 |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternRails(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternRails(flag);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы возврата флага использования паттерна                     |
//+------------------------------------------------------------------+
//--- Свечные формации
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Харами                    |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHarami(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHarami() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Крест харами              |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHaramiCross() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Пинцет                    |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternTweezer() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Просвет в облаках         |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternPiercingLine() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Завеса из темных облаков  |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternDarkCloudCover() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Три белых солдата         |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternThreeWhiteSoldiers() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Три черные вороны         |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternThreeBlackCrows() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Падающая звезда           |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternShootingStar() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Молот                     |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHammer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHammer() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Перевёрнутый молот        |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternInvertedHammer() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Повешенный                |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHangingMan() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Доджи                     |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternDoji() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Доджи стрекоза            |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternDragonflyDoji() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Доджи надгробие           |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternGravestoneDoji() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Утренняя звезда           |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternMorningStar() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Утренняя доджи-звезда     |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternMorningDojiStar() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Вечерняя звезда           |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternEveningStar() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Вечерняя доджи-звезда     |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternEveningDojiStar() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Три звезды                |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternThreeStars() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Брошенное дитя            |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternAbandonedBaby() : false);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Pivot Point Reversal      |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternPivotPointReversal() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Внешний бар (Поглощение)  |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternOutsideBar() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Внутренний бар            |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternInsideBar() : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Пин бар                   |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternPinBar(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.IsUsedPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Рельсы                    |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternRails(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternRails() : false);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы рисования паттернов на графике                            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Рисует метки паттернов Харами на графике                         |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHarami(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Крест харами на графике                   |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHaramiCross(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Пинцет на графике                         |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternTweezer(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Просвет в облаках на графике              |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternPiercingLine(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Завеса из темных облаков на графике       |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternDarkCloudCover(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Три белых солдата на графике              |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternThreeWhiteSoldiers(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Три черные вороны на графике              |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternThreeBlackCrows(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Падающая звезда на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternShootingStar(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Молот на графике                          |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHammer(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Перевёрнутый молот на графике             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternInvertedHammer(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Повешенный на графике                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHangingMan(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Доджи на графике                          |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternDoji(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Доджи стрекоза на графике                 |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternDragonflyDoji(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Доджи надгробие на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternGravestoneDoji(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Утренняя звезда на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternMorningStar(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Утренняя доджи-звезда на графике          |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternMorningDojiStar(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Вечерняя звезда на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternEveningStar(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Вечерняя доджи-звезда на графике          |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternEveningDojiStar(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Три звезды на графике                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternThreeStars(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Брошенное дитя на графике                 |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternAbandonedBaby(redraw);
  }
//--- Price Action
//+------------------------------------------------------------------+
//|  Рисует метки паттернов Pivot Point Reversal на графике          |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternPivotPointReversal(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Внешний бар (Поглощение) на графике       |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternOutsideBar(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Внутренний бар на графике                 |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternInsideBar(redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Пин бар на графике                        |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                      const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                      const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                      const double ratio_smaller_shadow=30,   // Процентное отношение размера меньшей тени к размеру свечи
                                      const bool redraw=false)                // Флаг перерисовки графика
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Рельсы на графике                         |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternRails(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternRails(redraw);
  }

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


Теперь аналогичные доработки нужно сделать в классе-коллекции таймсерий в файле \MQL5\Include\DoEasy\Collections\TimeSeriesCollection.mqh.

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

//+------------------------------------------------------------------+
//| Коллекция таймсерий символов                                     |
//+------------------------------------------------------------------+
class CTimeSeriesCollection : public CBaseObjExt
  {
private:
   CListObj                m_list;                    // Список используемых таймсерий символов
   CListObj                m_list_all_patterns;       // Список всех паттернов всех используемых таймсерий символов

//--- Возвращает индекс таймсерии по имени символа
   int                     IndexTimeSeries(const string symbol);
public:
//--- Возвращает (1) себя, (2) список таймсерий, (3) список паттернов
   CTimeSeriesCollection  *GetObject(void)            { return &this;                     }
   CArrayObj              *GetList(void)              { return &this.m_list;              }
   CArrayObj              *GetListAllPatterns(void)   { return &this.m_list_all_patterns; }

//--- Возвращает (1) объект таймсерий указанного символа, (2) объект-таймсерию указанного символа/периода
   CTimeSeriesDE          *GetTimeseries(const string symbol);
   CSeriesDE              *GetSeries(const string symbol,const ENUM_TIMEFRAMES timeframe);


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

//--- Копирует в массив указанное double-свойство указанной таймсерии указанного символа
//--- Независимо от направления индексации массива, копирование производится как в массив-таймсерию
   bool                    CopyToBufferAsSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                const ENUM_BAR_PROP_DOUBLE property,
                                                double &array[],
                                                const double empty=EMPTY_VALUE);
                                                
//+------------------------------------------------------------------+
//| Работа с паттернами таймсерий                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы установки флага использования паттерна                    |
//+------------------------------------------------------------------+
//--- Устанавливает флаг использования паттерна Харами и создаёт объект управления если его ещё нет
   void                    SetUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Крест харами и создаёт объект управления если его ещё нет
   void                    SetUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Пинцет и создаёт объект управления если его ещё нет
   void                    SetUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Просвет в облаках и создаёт объект управления если его ещё нет
   void                    SetUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Завеса из темных облаков и создаёт объект управления если его ещё нет
   void                    SetUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Три белых солдата и создаёт объект управления если его ещё нет
   void                    SetUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Три черные вороны и создаёт объект управления если его ещё нет
   void                    SetUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Падающая звезда и создаёт объект управления если его ещё нет
   void                    SetUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Молот и создаёт объект управления если его ещё нет
   void                    SetUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Перевёрнутый молот и создаёт объект управления если его ещё нет
   void                    SetUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Повешенный и создаёт объект управления если его ещё нет
   void                    SetUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Доджи и создаёт объект управления если его ещё нет
   void                    SetUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Доджи стрекоза и создаёт объект управления если его ещё нет
   void                    SetUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Доджи надгробие и создаёт объект управления если его ещё нет
   void                    SetUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Утренняя звезда и создаёт объект управления если его ещё нет
   void                    SetUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Утренняя доджи-звезда и создаёт объект управления если его ещё нет
   void                    SetUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Вечерняя звезда и создаёт объект управления если его ещё нет
   void                    SetUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Вечерняя доджи-звезда и создаёт объект управления если его ещё нет
   void                    SetUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Три звезды и создаёт объект управления если его ещё нет
   void                    SetUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Брошенное дитя и создаёт объект управления если его ещё нет
   void                    SetUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Price Action
//--- Устанавливает флаг использования паттерна Pivot Point Reversal и создаёт объект управления если его ещё нет
   void                    SetUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Внешний бар (Поглощение) и создаёт объект управления если его ещё нет
   void                    SetUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void                    SetUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void                    SetUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                const bool flag,                        // Флаг использования Price Action Пин бар
                                                const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                                const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                                const double ratio_smaller_shadow=30);  // Процентное отношение размера меньшей тени к размеру свечи
//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void                    SetUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы возврата флага использования паттерна                     |
//+------------------------------------------------------------------+
//--- Свечные формации
//--- Возвращает флаг использования паттерна Харами
   bool                    IsUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Крест харами
   bool                    IsUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пинцет
   bool                    IsUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Просвет в облаках
   bool                    IsUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Завеса из темных облаков
   bool                    IsUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три белых солдата
   bool                    IsUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три черные вороны
   bool                    IsUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Падающая звезда
   bool                    IsUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Молот
   bool                    IsUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Перевёрнутый молот
   bool                    IsUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Повешенный
   bool                    IsUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи
   bool                    IsUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи стрекоза
   bool                    IsUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Доджи надгробие
   bool                    IsUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя звезда
   bool                    IsUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Утренняя доджи-звезда
   bool                    IsUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя звезда
   bool                    IsUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Вечерняя доджи-звезда
   bool                    IsUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Три звезды
   bool                    IsUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Брошенное дитя
   bool                    IsUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Price Action
//--- Возвращает флаг использования паттерна Pivot Point Reversal
   bool                    IsUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внешний бар (Поглощение)
   bool                    IsUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Внутренний бар
   bool                    IsUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Возвращает флаг использования паттерна Пин бар
   bool                    IsUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                               const double ratio_body=30,           // Процентное отношение тела свечи к полному размеру свечи
                                               const double ratio_larger_shadow=60,  // Процентное отношение размера большей тени к размеру свечи
                                               const double ratio_smaller_shadow=30);// Процентное отношение размера меньшей тени к размеру свечи
//--- Возвращает флаг использования паттерна Рельсы
   bool                    IsUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы рисования паттернов на графике                            |
//+------------------------------------------------------------------+
//--- Рисует метки паттернов Харами на графике
   void                    DrawPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Крест харами на графике
   void                    DrawPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Пинцет на графике
   void                    DrawPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Просвет в облаках на графике
   void                    DrawPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Завеса из темных облаков на графике
   void                    DrawPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Три белых солдата на графике
   void                    DrawPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Три черные вороны на графике
   void                    DrawPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Падающая звезда на графике
   void                    DrawPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Молот на графике
   void                    DrawPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Перевёрнутый молот на графике
   void                    DrawPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Повешенный на графике
   void                    DrawPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Доджи на графике
   void                    DrawPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Доджи стрекоза на графике
   void                    DrawPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Доджи надгробие на графике
   void                    DrawPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Утренняя звезда на графике
   void                    DrawPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Утренняя доджи-звезда на графике
   void                    DrawPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Вечерняя звезда на графике
   void                    DrawPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Вечерняя доджи-звезда на графике
   void                    DrawPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Три звезды на графике
   void                    DrawPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Брошенное дитя на графике
   void                    DrawPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Price Action
//--- Рисует метки паттернов Pivot Point Reversal на графике
   void                    DrawPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Внешний бар (Поглощение) на графике
   void                    DrawPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Внутренний бар на графике
   void                    DrawPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Рисует метки паттернов Пин бар на графике
   void                    DrawPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                             const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                             const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                             const double ratio_smaller_shadow=30,   // Процентное отношение размера меньшей тени к размеру свечи
                                             const bool redraw=false);               // Флаг перерисовки графика
//--- Рисует метки паттернов Рельсы на графике
   void                    DrawPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
                                                
//--- Конструктор
                           CTimeSeriesCollection();
  };


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

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CTimeSeriesCollection::CTimeSeriesCollection()
  {
   this.m_type=COLLECTION_SERIES_ID;
   this.m_list.Clear();
   this.m_list.Sort();
   this.m_list.Type(COLLECTION_SERIES_ID);
   this.m_list_all_patterns.Clear();
   this.m_list_all_patterns.Sort();
   this.m_list_all_patterns.Type(COLLECTION_SERIES_PATTERNS_ID);
  }


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

//+------------------------------------------------------------------+
//| Возвращает индекс таймсерии по имени символа                     |
//+------------------------------------------------------------------+
int CTimeSeriesCollection::IndexTimeSeries(const string symbol)
  {
   CArrayObj *list=NULL;
   const CTimeSeriesDE *obj=new CTimeSeriesDE(list,symbol==NULL || symbol=="" ? ::Symbol() : symbol);
   if(obj==NULL)
      return WRONG_VALUE;
   this.m_list.Sort();
   int index=this.m_list.Search(obj);
   delete obj;
   return index;
  }


В методе, создающем список-коллекцию таймсерий символов, передадим указатель на список всех паттернов в конструктор создаваемой таймсерии:

//+------------------------------------------------------------------+
//| Создаёт список-коллекцию таймсерий символов                      |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::CreateCollection(const CArrayObj *list_symbols)
  {
//--- Если передан пустой список объектов-символов - выходим
   if(list_symbols==NULL)
      return false;
//--- Получаем количество объектов-символов в переданном списке
   int total=list_symbols.Total();
//--- Очищаем список-коллекцию таймсерий
   this.m_list.Clear();
//--- В цикле по всем объектам-символам
   for(int i=0;i<total;i++)
     {
      //--- получаем очередной объект-символ
      CSymbol *symbol_obj=list_symbols.At(i);
      //--- если объект-символ получить не удалось - переходим к следующему в списке
      if(symbol_obj==NULL)
         continue;
      //--- Создаём новый объект-таймсерию с именем текущего символа
      CTimeSeriesDE *timeseries=new CTimeSeriesDE(this.GetListAllPatterns(),symbol_obj.Name());
      //--- Если объект-таймсерию создать не удалось - переходим к следующему символу в списке
      if(timeseries==NULL)
         continue;
      //--- Списку-коллекции таймсерий устанавливаем флаг сортированного списка
      this.m_list.Sort();
      //--- Если объект с таким именем символа уже есть в списке-коллекции таймсерий - удаляем объект-таймсерию
      if(this.m_list.Search(timeseries)>WRONG_VALUE)
         delete timeseries;
      //--- иначе - если объект-таймсерию не удалось добавить в список-коллекцию - удаляем объект-таймсерию
      else 
         if(!this.m_list.Add(timeseries))
            delete timeseries;
     }
//--- Возвращаем флаг того, что созданный список-коллекция имеет размер больше нуля
   return this.m_list.Total()>0;
  }


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

//+------------------------------------------------------------------+
//| Работа с паттернами таймсерий                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы установки флага использования паттерна                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Харами                 |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternHarami(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Крест харами           |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternHaramiCross(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Пинцет                 |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternTweezer(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Просвет в облаках      |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternPiercingLine(timeframe,flag);
  }
//+------------------------------------------------------------------+
//|Устанавливает флаг использования паттерна Завеса из темных облаков|
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternDarkCloudCover(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Три белых солдата      |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternThreeWhiteSoldiers(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Три черные вороны      |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternThreeBlackCrows(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Падающая звезда        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternShootingStar(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Молот                  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternHammer(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Перевёрнутый молот     |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternInvertedHammer(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Повешенный             |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternHangingMan(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Доджи                  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternDoji(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Доджи стрекоза         |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternDragonflyDoji(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Доджи надгробие        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternGravestoneDoji(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Утренняя звезда        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternMorningStar(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Утренняя доджи-звезда  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternMorningDojiStar(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Вечерняя звезда        |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternEveningStar(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Вечерняя доджи-звезда  |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternEveningDojiStar(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Три звезды             |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternThreeStars(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Брошенное дитя         |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternAbandonedBaby(timeframe,flag);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Pivot Point Reversal   |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternPivotPointReversal(timeframe,flag);
  }
//+------------------------------------------------------------------+
//|Устанавливает флаг использования паттерна Внешний бар (Поглощение)|
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternOutsideBar(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Внутренний бар         |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternInsideBar(timeframe,flag);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Пин бар                |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                 const bool flag,                        // Флаг использования 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.SetUsedPatternPinBar(timeframe,flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
  }
//+------------------------------------------------------------------+
//| Устанавливает флаг использования паттерна Рельсы                 |
//| и создаёт объект управления если его ещё нет                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternRails(timeframe,flag);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы возврата флага использования паттерна                     |
//+------------------------------------------------------------------+
//--- Свечные формации
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Харами                    |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHarami(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Крест харами              |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHaramiCross(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Пинцет                    |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternTweezer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Просвет в облаках         |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternPiercingLine(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Завеса из темных облаков  |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternDarkCloudCover(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Три белых солдата         |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternThreeWhiteSoldiers(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Три черные вороны         |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternThreeBlackCrows(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Падающая звезда           |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternShootingStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Молот                     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHammer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Перевёрнутый молот        |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternInvertedHammer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Повешенный                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHangingMan(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Доджи                     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Доджи стрекоза            |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternDragonflyDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Доджи надгробие           |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternGravestoneDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Утренняя звезда           |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternMorningStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Утренняя доджи-звезда     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternMorningDojiStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Вечерняя звезда           |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternEveningStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Вечерняя доджи-звезда     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternEveningDojiStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Три звезды                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternThreeStars(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Брошенное дитя            |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternAbandonedBaby(timeframe) : false);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Pivot Point Reversal      |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternPivotPointReversal(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Внешний бар (Поглощение)  |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternOutsideBar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Внутренний бар            |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternInsideBar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Пин бар                   |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternPinBar(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.IsUsedPatternPinBar(timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг использования паттерна Рельсы                    |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternRails(timeframe) : false);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Методы рисования паттернов на графике                            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Рисует метки паттернов Харами на графике                         |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternHarami(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Крест харами на графике                   |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternHaramiCross(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Пинцет на графике                         |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternTweezer(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Просвет в облаках на графике              |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternPiercingLine(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Завеса из темных облаков на графике       |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternDarkCloudCover(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Три белых солдата на графике              |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternThreeWhiteSoldiers(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Три черные вороны на графике              |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternThreeBlackCrows(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Падающая звезда на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternShootingStar(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Молот на графике                          |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternHammer(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Перевёрнутый молот на графике             |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternInvertedHammer(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Повешенный на графике                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternHangingMan(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Доджи на графике                          |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternDoji(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Доджи стрекоза на графике                 |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternDragonflyDoji(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Доджи надгробие на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternGravestoneDoji(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Утренняя звезда на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternMorningStar(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Утренняя доджи-звезда на графике          |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternMorningDojiStar(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Вечерняя звезда на графике                |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternEveningStar(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Вечерняя доджи-звезда на графике          |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternEveningDojiStar(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Три звезды на графике                     |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternThreeStars(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Брошенное дитя на графике                 |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternAbandonedBaby(timeframe,redraw);
  }
//--- Price Action
//+------------------------------------------------------------------+
//|  Рисует метки паттернов Pivot Point Reversal на графике          |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternPivotPointReversal(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Внешний бар (Поглощение) на графике       |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternOutsideBar(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Внутренний бар на графике                 |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternInsideBar(timeframe,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Пин бар на графике                        |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                              const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                              const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                              const double ratio_smaller_shadow=30,   // Процентное отношение размера меньшей тени к размеру свечи
                                              const bool redraw=false)                // Флаг перерисовки графика
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternPinBar(timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
  }
//+------------------------------------------------------------------+
//| Рисует метки паттернов Рельсы на графике                         |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternRails(timeframe,redraw);
  }

Логика всех методов простая — получаем указатель на таймсерию, и используем её методы для работы с паттернами, созданные выше. Полностью готовы методы только для работы с паттерном Пин-Бар. Остальные доработаем по мере создания новых паттернов.


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

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

//--- Копирует в массив указанное double-свойство указанной таймсерии указанного символа
//--- Независимо от направления индексации массива, копирование производится как в массив-таймсерию
   bool                 SeriesCopyToBufferAsSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_BAR_PROP_DOUBLE property,
                                                   double &array[],const double empty=EMPTY_VALUE)
                          { return this.m_time_series.CopyToBufferAsSeries(symbol,timeframe,property,array,empty);}

//--- Возвращает полный список паттернов
   CArrayObj           *GetListAllPatterns(void)
                          { return this.m_time_series.GetListAllPatterns();   }
//--- Возвращает список паттернов по указанным символу и таймфрейму
   CArrayObj           *GetListPatterns(const string symbol,const ENUM_TIMEFRAMES timeframe)
                          {
                           CArrayObj *list=CSelect::ByPatternProperty(this.GetListAllPatterns(),PATTERN_PROP_SYMBOL,symbol,EQUAL);
                           return CSelect::ByPatternProperty(list,PATTERN_PROP_PERIOD,timeframe,EQUAL);
                          }
//--- Возвращает список указанных паттернов по указанным символу и таймфрейму
   CArrayObj           *GetListPatterns(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_PATTERN_TYPE type)
                          {
                           CArrayObj *list=this.GetListPatterns(symbol,timeframe);
                           return CSelect::ByPatternProperty(list,PATTERN_PROP_TYPE,type,EQUAL);
                          }
//--- Возвращает список паттернов по указанным времени открытия бара на символе и таймфрейме
   CArrayObj           *GetListPatterns(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime time)
                          {
                           CArrayObj *list=this.GetListPatterns(symbol,timeframe);
                           return CSelect::ByPatternProperty(list,PATTERN_PROP_TIME,time,EQUAL);
                          }
//--- Возвращает список указанных паттернов по указанным времени открытия бара на символе и таймфрейме
   CArrayObj           *GetListPatterns(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime time,const ENUM_PATTERN_TYPE type)
                          {
                           CArrayObj *list=this.GetListPatterns(symbol,timeframe,time);
                           return CSelect::ByPatternProperty(list,PATTERN_PROP_TYPE,type,EQUAL);
                          }
//--- Возвращает указатель на указанный паттерн по времени открытия бара на графике указанного символа и периода
   CPattern            *GetPattern(const string symbol,const ENUM_TIMEFRAMES timeframe,const datetime time,const ENUM_PATTERN_TYPE type)
                          {
                           CArrayObj *list=this.GetListPatterns(symbol,timeframe,time,type);
                           return(list!=NULL ? list.At(0) : NULL);
                          }

//--- Устанавливает флаг использования паттерна Харами и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHarami(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Крест харами и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHaramiCross(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Пинцет и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternTweezer(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Просвет в облаках и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternPiercingLine(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Завеса из темных облаков и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternDarkCloudCover(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Три белых солдата и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternThreeWhiteSoldiers(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Три черные вороны и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternThreeBlackCrows(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Падающая звезда и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternShootingStar(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Молот и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHammer(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Перевёрнутый молот и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternInvertedHammer(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Повешенный и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHangingMan(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Доджи и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternDoji(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Доджи стрекоза и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternDragonflyDoji(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Доджи надгробие и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternGravestoneDoji(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Утренняя звезда и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternMorningStar(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Утренняя доджи-звезда и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternMorningDojiStar(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Вечерняя звезда и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternEveningStar(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Вечерняя доджи-звезда и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternEveningDojiStar(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Три звезды и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternThreeStars(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Брошенное дитя и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternAbandonedBaby(symbol,timeframe,flag);
                          }
//--- Price Action
//--- Устанавливает флаг использования паттерна Pivot Point Reversal и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternPivotPointReversal(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Внешний бар (Поглощение) и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternOutsideBar(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Внутренний бар и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternInsideBar(symbol,timeframe,flag);
                          }
//--- Устанавливает флаг использования паттерна Пин бар и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                   const bool flag,                        // Флаг использования Price Action Пин бар
                                                   const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                                   const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                                   const double ratio_smaller_shadow=30)   // Процентное отношение размера меньшей тени к размеру свечи
                          {
                           this.m_time_series.SetUsedPatternPinBar(symbol,timeframe,flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                          }
//--- Устанавливает флаг использования паттерна Рельсы и создаёт объект управления если его ещё нет
   void                 SeriesSetUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternRails(symbol,timeframe,flag);
                          }

//--- Рисует метки паттернов Харами на графике
   void                 SeriesDrawPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHarami(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Крест харами на графике
   void                 SeriesDrawPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHaramiCross(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Пинцет на графике
   void                 SeriesDrawPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternTweezer(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Просвет в облаках на графике
   void                 SeriesDrawPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternPiercingLine(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Завеса из темных облаков на графике
   void                 SeriesDrawPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternDarkCloudCover(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Три белых солдата на графике
   void                 SeriesDrawPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternThreeWhiteSoldiers(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Три черные вороны на графике
   void                 SeriesDrawPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternThreeBlackCrows(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Падающая звезда на графике
   void                 SeriesDrawPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternShootingStar(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Молот на графике
   void                 SeriesDrawPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHammer(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Перевёрнутый молот на графике
   void                 SeriesDrawPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternInvertedHammer(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Повешенный на графике
   void                 SeriesDrawPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHangingMan(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Доджи на графике
   void                 SeriesDrawPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternDoji(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Доджи стрекоза на графике
   void                 SeriesDrawPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternDragonflyDoji(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Доджи надгробие на графике
   void                 SeriesDrawPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternGravestoneDoji(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Утренняя звезда на графике
   void                 SeriesDrawPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternMorningStar(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Утренняя доджи-звезда на графике
   void                 SeriesDrawPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternMorningDojiStar(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Вечерняя звезда на графике
   void                 SeriesDrawPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternEveningStar(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Вечерняя доджи-звезда на графике
   void                 SeriesDrawPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternEveningDojiStar(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Три звезды на графике
   void                 SeriesDrawPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternThreeStars(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Брошенное дитя на графике
   void                 SeriesDrawPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternAbandonedBaby(symbol,timeframe,redraw);
                          }
//--- Price Action
//--- Рисует метки паттернов Pivot Point Reversal на графике
   void                 SeriesDrawPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternPivotPointReversal(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Внешний бар (Поглощение) на графике
   void                 SeriesDrawPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternOutsideBar(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Внутренний бар на графике
   void                 SeriesDrawPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternInsideBar(symbol,timeframe,redraw);
                          }
//--- Рисует метки паттернов Пин бар на графике
   void                 SeriesDrawPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                const double ratio_body=30,             // Процентное отношение тела свечи к полному размеру свечи
                                                const double ratio_larger_shadow=60,    // Процентное отношение размера большей тени к размеру свечи
                                                const double ratio_smaller_shadow=30,   // Процентное отношение размера меньшей тени к размеру свечи
                                                const bool redraw=false)                // Флаг перерисовки графика
                          {
                           this.m_time_series.DrawPatternPinBar(symbol,timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
                           if(redraw)
                              ::ChartRedraw();
                          }
   //--- Рисует метки паттернов Рельсы на графике
   void                 SeriesDrawPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternRails(symbol,timeframe,redraw);
                          }

//--- Скрывает значки всех паттернов
   void                 SeriesPatternHideAll(const bool redraw=false)
                          {
                           CArrayObj *list=this.GetListAllPatterns();
                           for(int i=list.Total()-1;i>=0;i--)
                             {
                              CPattern *obj=list.At(i);
                              if(obj!=NULL)
                                 obj.Hide();
                             }
                           if(redraw)
                              ::ChartRedraw();
                          }
//--- Скрывает значки всех паттернов кроме указанного
   void                 SeriesPatternHideAllExceptOne(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.Hide();
                             }
                           if(redraw)
                              ::ChartRedraw();
                          }

//--- Скрывает информационные панели всех паттернов
   void                 SeriesPatternHideAllInfoPanels(const bool redraw=false)
                          {
                           CArrayObj *list=this.GetListAllPatterns();
                           for(int i=list.Total()-1;i>=0;i--)
                             {
                              CPattern *obj=list.At(i);
                              if(obj!=NULL)
                                 obj.HideInfoPanel();
                             }
                           if(redraw)
                              ::ChartRedraw();
                          }
//--- Скрывает информационные панели всех паттернов кроме указанного
   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();
                          }

//--- Возвращает (1) коллекцию тиковых серий, (2) список тиковых серий из коллекции тиковых серий
   CTickSeriesCollection *GetTickSeriesCollection(void)                                { return &this.m_tick_series;                                  }
   CArrayObj           *GetListTickSeries(void)                                        { return this.m_tick_series.GetList();                         }

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

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

//+------------------------------------------------------------------+
//| Обработчик события NewTick                                       |
//+------------------------------------------------------------------+
void CEngine::OnTick(SDataCalculate &data_calculate,const uint required=0)
  {
//--- Если это не эксперт - уходим
   if(this.m_program_type!=PROGRAM_EXPERT)
      return;
//--- Пересоздание пустых таймсерий и обновление таймсерий текущего символа
   this.SeriesSync(data_calculate,required);
   this.SeriesRefresh(NULL,data_calculate);
//--- Здесь пока закомментировано потому, что TickSeriesRefresh вызывает зависания - нужно смотреть что там сломалось
   //this.TickSeriesRefresh(NULL);
//--- end
  }

На сегодня это всё. Протестируем что у нас вышло.


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

Для тестирования возьмём советник из статьи "Прочие классы в библиотеке DoEasy (Часть 72): Отслеживание и фиксация параметров объектов-чартов в коллекции"
и сохраним его в новой папке \MQL5\Experts\TestDoEasy\Part134\ под новым именем TestDoEasyPart134.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   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


В обработчике OnInit() подготовим список паттернов для работы с ним:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Вызов данной функции выводит в журнал список констант перечисления, 
//--- заданного в файле DELib.mqh в строках 22 и 25, для проверки корректности констант
   //EnumNumbersTest();

//--- Установка глобальных переменных советника
   prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";
   testing=engine.IsTester();
   for(int i=0;i<TOTAL_BUTT;i++)
     {
      butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i);
      butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i);
     }
   lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0));
   magic_number=InpMagic;
   stoploss=InpStopLoss;
   takeprofit=InpTakeProfit;
   distance_pending=InpDistance;
   distance_stoplimit=InpDistanceSL;
   slippage=InpSlippage;
   trailing_stop=InpTrailingStop*Point();
   trailing_step=InpTrailingStep*Point();
   trailing_start=InpTrailingStart;
   stoploss_to_modify=InpStopLossModify;
   takeprofit_to_modify=InpTakeProfitModify;
   distance_pending_request=(InpDistancePReq<5 ? 5 : InpDistancePReq);
   bars_delay_pending_request=(InpBarsDelayPReq<1 ? 1 : InpBarsDelayPReq);
   g_point=SymbolInfoDouble(NULL,SYMBOL_POINT);
   g_digits=(int)SymbolInfoInteger(NULL,SYMBOL_DIGITS);
//--- Инициализация случайных номеров групп
   group1=0;
   group2=0;
   srand(GetTickCount());
   
//--- Инициализация библиотеки DoEasy
   OnInitDoEasy();
   
//--- Проверка и удаление неудалённых графических объектов советника
   if(IsPresentObectByPrefix(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Создание панели кнопок
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      return INIT_FAILED;
//--- Установка состояния кнопки активизации трейлингов
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);
//--- Сброс состояний кнопок активизации работы отложенными запросами
   for(int i=0;i<14;i++)
     {
      ButtonState(butt_data[i].name+"_PRICE",false);
      ButtonState(butt_data[i].name+"_TIME",false);
     }

//--- Проверка воспроизведения стандартного звука по макроподстановке и пользовательского звука по описанию
   engine.PlaySoundByDescription(SND_OK);
//--- Ждём 600 миллисекунд
   engine.Pause(600);
   engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","The sound of a falling coin 2"));

//--- Проверка расчёта координат курсора в окнах графика.
//--- Установим текущему графику разрешение на отслеживание событий перемещения мыши
   if(engine.ChartGetMainChart()!=NULL)
      engine.ChartGetMainChart().SetEventMouseMoveON();

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


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

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Если работа в тестере - выход
   if(MQLInfoInteger(MQL_TESTER))
      return;
//--- Обработка событий мыши
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Обработка нажатий кнопок в панели
      if(StringFind(sparam,"BUTT_")>0)
         PressButtonEvents(sparam);
     }
//--- Обработка событий библиотеки DoEasy
   if(id>CHARTEVENT_CUSTOM-1)
     {
      OnDoEasyEvent(id,lparam,dparam,sparam);
     }
//--- Изменение графика
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- При любом изменении графика скроем все информационные панели
      engine.SeriesPatternHideAllInfoPanels();
      return;
     }
//--- Проверка 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);
         //--- Получим паттерн с бара графика, для которого было найдено время открытия
         CPattern *pinbar=engine.GetPattern(Symbol(),Period(),bar_time,PATTERN_TYPE_PIN_BAR);
         //--- Если на этом баре есть паттерн Пин-Бар
         if(pinbar!=NULL)
           {
            //--- Если курсор находится в пределах размера свечи
            if(price>=pinbar.BarPriceLow() && price<=pinbar.BarPriceHigh())
              {
               //--- Распечатаем в журнале короткое описание паттерна
               pinbar.PrintShort(true);
               //--- Получим координаты графика, на которых нужно показать информационную панель
               int x=0;
               int y=0;
               if(ChartTimePriceToXY(pinbar.GetChartID(),0,bar_time,price,x,y))
                 {
                  //--- Скрываем все панели, кроме принадлежащей текущему паттерну под курсором
                  engine.SeriesPatternHideAllInfoPanelsExceptOne(pinbar.Code());
                  //--- Отображаем информационную панель на графике
                  pinbar.ShowInfoPanel(x,y);
                 }
              }
           }
        }
     }
  }

Это будет работать так: на графике будут отображены метки найденных паттернов. Если навести курсор на бар с меткой (в пределах его High и Low), то отобразится информационная панель с небольшим описанием паттерна. При наведении курсора мышки на другой бар с паттерном, панель первого паттерна будет скрыта и отображена панель того, на который переместили курсор. Любая отображённая на графике панель будет видима до тех пор, пока не будет как-либо изменён график, например, сдвинут вправо или влево. На данный момент для теста это самое простое решение. Далее, скорее всего сделаем автоматическое скрытие панелей по времени.

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

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


Что дальше

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

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

К содержанию

Прикрепленные файлы |
MQL5.zip (4704.17 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
Renat Akhtyamov
Renat Akhtyamov | 1 мар. 2024 в 19:38

Мдаааа. Не слабо!  

Ждем тест

Разработка системы репликации (Часть 29): Проект советника — класс C_Mouse (III) Разработка системы репликации (Часть 29): Проект советника — класс C_Mouse (III)
После улучшения класса C_Mouse, мы можем сосредоточиться на создании класса, призванного создать совершенно новую основу для обучения. Как уже упоминалось в начале статьи, мы не будем использовать наследование или полиморфизм для создания этого нового класса. Вместо этого мы изменим, а точнее, добавим новые объекты в ценовую линию. Именно этим мы и займемся в данный момент, а в следующей статье мы рассмотрим, как изменить исследования. Но мы сделаем всё это, не меняя код класса C_Mouse. Признаюсь, на практике было бы легче достичь этого с помощью наследования или полиморфизма. однако существуют и другие методы достижения такого же результата.
Нейросети — это просто (Часть 79): Агрегирование запросов в контексте состояния (FAQ) Нейросети — это просто (Часть 79): Агрегирование запросов в контексте состояния (FAQ)
В предыдущей статье мы познакомились с одним из методом обнаружение объектов на изображении. Однако, обработка статического изображения несколько отличается от работы с динамическими временными рядами, к которым относится и динамика анализируемых нами цен. В данной статье я хочу предложить Вам познакомиться с методом обнаружения объектов на видео, что несколько ближе к решаемой нами задаче.
Возможности Мастера MQL5, которые вам нужно знать (Часть 07): Дендрограммы Возможности Мастера MQL5, которые вам нужно знать (Часть 07): Дендрограммы
Классификация данных для анализа и прогнозирования — очень разнообразная область машинного обучения с большим количеством подходов и методов. В этой статье рассматривается один из таких подходов, а именно агломеративная иерархическая классификация (Agglomerative Hierarchical Classification).
Интеграция ML-моделей с тестером стратегий (Заключение): Реализация регрессионной модели для прогнозирования цен Интеграция ML-моделей с тестером стратегий (Заключение): Реализация регрессионной модели для прогнозирования цен
В данной статье описывается реализация регрессионной модели на основе дерева решений для прогнозирования цен финансовых активов. Мы уже провели подготовку данных, обучение и оценку модели, а также ее корректировку и оптимизацию. Однако важно отметить, что данная модель является лишь исследованием и не должна использоваться при реальной торговле.