English Русский Deutsch
preview
DoEasy. Funções de serviço (Parte 1): Padrões de preços

DoEasy. Funções de serviço (Parte 1): Padrões de preços

MetaTrader 5Exemplos | 8 agosto 2024, 17:38
16 0
Artyom Trishkin
Artyom Trishkin

Conteúdo


Conceito

A biblioteca DoEasy está sendo desenvolvida como uma ferramenta que nos permite obter de forma conveniente vários dados do nosso ambiente de negociação. Na biblioteca, podemos classificar quaisquer listas de dados obtendo acesso apenas a determinados dados com certos parâmetros. Tudo isso nos permite adicionar alguma funcionalidade padrão à biblioteca, o que facilitará para o usuário criá-la - estará pronta para uso diretamente da biblioteca.

A criação de vários tipos de funcionalidades padrão é planejada com antecedência e essa funcionalidade será gradualmente adicionada à biblioteca. No artigo atual, adicionaremos à biblioteca ferramentas para buscar e exibir padrões de preço que podem ser encontrados em dados de séries temporais. As classes de séries temporais fornecem a capacidade de acessar rapidamente quaisquer dados de qualquer série temporal. Usando esses dados, podemos encontrar facilmente qualquer padrão descrito por qualquer autor ou desenvolvido de forma independente.

Qualquer padrão tem um certo conjunto de parâmetros que é comum a qualquer tipo de padrão. Todos os dados desse tipo serão concentrados na classe de objetos do padrão abstrato base. Com base na classe, criaremos classes herdadas distribuídas por tipo de padrão. Qualquer padrão encontrado será associado a uma barra de série temporal para que, usando a barra encontrada, seja possível referir-se ao padrão que foi descoberto nessa barra. Qualquer padrão inclui uma barra base, a partir da qual uma formação é procurada, resultando em um padrão. Portanto, diferentes padrões podem estar presentes em uma barra. Consequentemente, a barra de série temporal armazenará uma lista de padrões, para os quais ela serve como base.

Para cada padrão, forneceremos a capacidade de exibi-lo graficamente em um gráfico. Para não sobrecarregar o gráfico com ícones de padrão, faremos com que seja possível exibir esses ícones de acordo com instruções do programa. Cada padrão pode ter configurações diferentes para sua busca. Teremos a oportunidade de criar padrões do mesmo tipo, mas diferentes em seu conjunto de parâmetros - estes serão dois ou mais padrões diferentes do mesmo tipo. Essa abordagem permitirá buscar um padrão específico, indicando seus vários parâmetros. Todas as listas de todos os padrões encontrados serão salvas no programa para acesso rápido de acordo com os parâmetros especificados. Isso permitirá encontrar todos os padrões do mesmo tipo com o primeiro tipo de parâmetros e, em seguida, encontrar o mesmo padrão, mas com parâmetros diferentes, e depois comparar o que foi encontrado. Acho que será conveniente não definir rigidamente as proporções necessárias das proporções da barra, mas fazer isso de forma mais flexível - dando a oportunidade de "brincar com os parâmetros".

Todos os padrões encontrados em qualquer símbolo e período de gráfico serão armazenados em uma lista de padrões para que possamos usar a lista comum para buscar quaisquer propriedades comuns de diferentes padrões em diferentes dados de preços sem antes transferi-los de listas diferentes para uma só.


Melhorando classes de biblioteca

Em \MQL5\Include\DoEasyDefines.mqh, adicione uma substituição de macro com o ID da lista de padrões:

//--- Collection list IDs
#define COLLECTION_HISTORY_ID          (0x777A)                   // Historical collection list ID
#define COLLECTION_MARKET_ID           (0x777B)                   // Market collection list ID
#define COLLECTION_EVENTS_ID           (0x777C)                   // Event collection list ID
#define COLLECTION_ACCOUNT_ID          (0x777D)                   // Account collection list ID
#define COLLECTION_SYMBOLS_ID          (0x777E)                   // Symbol collection list ID
#define COLLECTION_SERIES_ID           (0x777F)                   // Timeseries collection list ID
#define COLLECTION_SERIES_PATTERNS_ID  (0x7780)                   // Timeseries pattern list ID
#define COLLECTION_BUFFERS_ID          (0x7781)                   // Indicator buffer collection list ID
#define COLLECTION_INDICATORS_ID       (0x7782)                   // Indicator collection list ID
#define COLLECTION_INDICATORS_DATA_ID  (0x7783)                   // Indicator data collection list ID
#define COLLECTION_TICKSERIES_ID       (0x7784)                   // Tick series collection list ID
#define COLLECTION_MBOOKSERIES_ID      (0x7785)                   // DOM series collection list ID
#define COLLECTION_MQL5_SIGNALS_ID     (0x7786)                   // MQL5 signals collection list ID
#define COLLECTION_CHARTS_ID           (0x7787)                   // Chart collection list ID
#define COLLECTION_CHART_WND_ID        (0x7788)                   // Chart window list ID
#define COLLECTION_GRAPH_OBJ_ID        (0x7789)                   // Graphical object collection list ID

#define COLLECTION_ID_LIST_END         (COLLECTION_GRAPH_OBJ_ID)  // End of collection ID list

//--- Pending request type IDs


Na lista de tipos de objeto, adicione novos tipos de objeto para classes de padrão criadas hoje:

   OBJECT_DE_TYPE_SERIES_BAR,                                     // "Bar" object type
   OBJECT_DE_TYPE_SERIES_PERIOD,                                  // "Period timeseries" object type
   OBJECT_DE_TYPE_SERIES_SYMBOL,                                  // "Symbol timeseries" object type
   
   OBJECT_DE_TYPE_SERIES_PATTERN,                                 // "Pattern" object type
   OBJECT_DE_TYPE_SERIES_PATTERN_CONTROL,                         // "Pattern management" object type
   OBJECT_DE_TYPE_SERIES_PATTERNS_CONTROLLERS,                    // "Patterns management" object type

  • O objeto Padrão é o próprio objeto de um padrão;
  • O objeto Gerenciamento de Padrões é um objeto que possui a funcionalidade de buscar e criar padrões do mesmo tipo dentro de uma série temporal. Um objeto de controle é criado para cada padrão;
  • O objeto Gerenciamento de Padrões é um objeto que armazena uma lista de todos os objetos para gerenciar padrões de vários tipos e fornece acesso a eles. O objeto é definido dentro da classe da série temporal.

Como os padrões são buscados usando quaisquer parâmetros das barras da série temporal, ou combinações desses parâmetros para diferentes barras próximas, adicione parâmetros de proporção de vela às propriedades da barra (proporção do corpo da vela em relação ao seu tamanho, sombras superior e inferior em relação ao tamanho da vela e aumente o número total de parâmetros inteiros de 10 para 13:

//+------------------------------------------------------------------+
//| Real bar properties                                              |
//+------------------------------------------------------------------+
enum ENUM_BAR_PROP_DOUBLE
  {
//--- bar data
   BAR_PROP_OPEN = BAR_PROP_INTEGER_TOTAL,                  // Bar open price
   BAR_PROP_HIGH,                                           // Highest price for the bar period
   BAR_PROP_LOW,                                            // Lowest price for the bar period
   BAR_PROP_CLOSE,                                          // Bar close price
//--- candle data
   BAR_PROP_CANDLE_SIZE,                                    // Candle size
   BAR_PROP_CANDLE_SIZE_BODY,                               // Candle body size
   BAR_PROP_CANDLE_BODY_TOP,                                // Candle body top
   BAR_PROP_CANDLE_BODY_BOTTOM,                             // Candle body bottom
   BAR_PROP_CANDLE_SIZE_SHADOW_UP,                          // Candle upper wick size
   BAR_PROP_CANDLE_SIZE_SHADOW_DOWN,                        // Candle lower wick size
//--- candle proportions
   BAR_PROP_RATIO_BODY_TO_CANDLE_SIZE,                      // Percentage ratio of the candle body to the full size of the candle
   BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,              // Percentage ratio of the upper shadow size to the candle size
   BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,              // Percentage ratio of the lower shadow size to the candle size
  }; 
#define BAR_PROP_DOUBLE_TOTAL  (13)                         // Total number of real bar properties
#define BAR_PROP_DOUBLE_SKIP   (0)                          // Number of bar properties not used in sorting

Usando essas proporções, podemos sempre descrever a aparência geral de qualquer vela, e, usando-as, você também pode buscar as velas corretas com as proporções corretas.

Vamos escrever enumerações de tipos e propriedades de padrões:

//+------------------------------------------------------------------+
//| Abstract pattern status                                          |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_STATUS
  {
   PATTERN_STATUS_JC,                                       // Candles
   PATTERN_STATUS_PA,                                       // Price Action formations
  };

No momento, a biblioteca terá dois grupos de diferentes padrões - formações de velas e formações de Price Action. Um padrão pertencente a um grupo ou outro será considerado o estado do padrão. A listagem acima descreve esses estados.

Padrões do mesmo tipo podem ser de compra, venda ou bidirecionais. Vamos escrever uma lista de tipos de padrões por direção:

//+------------------------------------------------------------------+
//| Pattern type by direction (buy/sell)                             |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_DIRECTION
  {
   PATTERN_DIRECTION_BULLISH,                               // Buy pattern
   PATTERN_DIRECTION_BEARISH,                               // Sell pattern
   PATTERN_DIRECTION_BOTH,                                  // Bidirectional pattern
  };


Vamos escrever uma enumeração com tipos de padrões:

//+------------------------------------------------------------------+
//| Pattern type                                                     |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_TYPE
  {
//--- Candle formations
   PATTERN_TYPE_HARAMI              =  0x0,                 // Harami
   PATTERN_TYPE_HARAMI_CROSS        =  0x1,                 // Harami Cross
   PATTERN_TYPE_TWEEZER             =  0x2,                 // Tweezer
   PATTERN_TYPE_PIERCING_LINE       =  0x4,                 // Piercing Line
   PATTERN_TYPE_DARK_CLOUD_COVER    =  0x8,                 // Dark Cloud Cover
   PATTERN_TYPE_THREE_WHITE_SOLDIERS=  0x10,                // Three White Soldiers
   PATTERN_TYPE_THREE_BLACK_CROWS   =  0x20,                // Three Black Crows
   PATTERN_TYPE_SHOOTING_STAR       =  0x40,                // Shooting Star
   PATTERN_TYPE_HAMMER              =  0x80,                // Hammer
   PATTERN_TYPE_INVERTED_HAMMER     =  0x100,               // Inverted Hammer
   PATTERN_TYPE_HANGING_MAN         =  0x200,               // Hanging Man
   PATTERN_TYPE_DOJI                =  0x400,               // Doji
   PATTERN_TYPE_DRAGONFLY_DOJI      =  0x800,               // Dragonfly Doji
   PATTERN_TYPE_GRAVESTONE_DOJI     =  0x1000,              // Gravestone Doji
   PATTERN_TYPE_MORNING_STAR        =  0x2000,              // Morning Star
   PATTERN_TYPE_MORNING_DOJI_STAR   =  0x4000,              // Morning Doji Star
   PATTERN_TYPE_EVENING_STAR        =  0x8000,              // Evening Star
   PATTERN_TYPE_EVENING_DOJI_STAR   =  0x10000,             // Evening Doji Star
   PATTERN_TYPE_THREE_STARS         =  0x20000,             // Three Stars
   PATTERN_TYPE_ABANDONED_BABY      =  0x40000,             // Abandoned Baby
//--- Price Action
   PATTERN_TYPE_PIVOT_POINT_REVERSAL=  0x80000,             // Price Action Reversal Pattern
   PATTERN_TYPE_OUTSIDE_BAR         =  0x100000,            // Price Action Outside Bar
   PATTERN_TYPE_INSIDE_BAR          =  0x200000,            // Price Action Inside Bar
   PATTERN_TYPE_PIN_BAR             =  0x400000,            // Price Action Pin Bar
   PATTERN_TYPE_RAILS               =  0x800000,            // Price Action Rails
  };

Esta lista contém padrões, cuja busca será gradualmente adicionada à biblioteca. Os valores das constantes são feitos na forma de flags de bits. Isso nos permitirá armazenar em uma variável diferentes tipos de padrões que são encontrados em uma barra, que são a base para cada padrão.

Cada padrão tem certas propriedades inerentes a esse padrão. Mas também existem propriedades comuns a todos os padrões. Vamos escrever uma lista de propriedades inteiras, reais e de string dos padrões:

//+------------------------------------------------------------------+
//| Pattern integer properties                                       |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_PROP_INTEGER
  {
   PATTERN_PROP_CODE = 0,                                   // Unique pattern code (time + type + status + direction + timeframe + symbol)
   PATTERN_PROP_CTRL_OBJ_ID,                                // Pattern control object ID
   PATTERN_PROP_ID,                                         // Pattern ID
   PATTERN_PROP_TIME,                                       // Pattern defining bar time
   PATTERN_PROP_STATUS,                                     // Pattern status (from the ENUM_PATTERN_STATUS enumeration)
   PATTERN_PROP_TYPE,                                       // Pattern type (from the ENUM_PATTERN_TYPE enumeration)
   PATTERN_PROP_DIRECTION,                                  // Pattern type by direction (from the ENUM_PATTERN_TYPE_DIRECTION enumeration)
   PATTERN_PROP_PERIOD,                                     // Pattern period (timeframe)
   PATTERN_PROP_CANDLES,                                    // Number of candles that make up the pattern
  }; 
#define PATTERN_PROP_INTEGER_TOTAL (9)                      // Total number of integer pattern properties
#define PATTERN_PROP_INTEGER_SKIP  (0)                      // Number of pattern properties not used in sorting
//+------------------------------------------------------------------+
//| Pattern real properties                                          |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_PROP_DOUBLE
  {
//--- bar data
   PATTERN_PROP_BAR_PRICE_OPEN = PATTERN_PROP_INTEGER_TOTAL,// Pattern defining bar Open price
   PATTERN_PROP_BAR_PRICE_HIGH,                             // Pattern defining bar High price
   PATTERN_PROP_BAR_PRICE_LOW,                              // Pattern defining bar Low price
   PATTERN_PROP_BAR_PRICE_CLOSE,                            // Pattern defining bar Close price
   PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE,                  // Percentage ratio of the candle body to the full size of the candle
   PATTERN_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,          // Percentage ratio of the upper shadow size to the candle size
   PATTERN_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,          // Percentage ratio of the lower shadow size to the candle size
   PATTERN_PROP_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,           // Defined criterion of the ratio of the candle body to the full candle size in %
   PATTERN_PROP_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,  // Defined criterion of the ratio of the maximum shadow to the candle size in %
   PATTERN_PROP_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION, // Defined criterion of the ratio of the minimum shadow to the candle size in %
  }; 
#define PATTERN_PROP_DOUBLE_TOTAL   (10)                    // Total number of real pattern properties
#define PATTERN_PROP_DOUBLE_SKIP    (0)                     // Number of pattern properties not used in sorting
//+------------------------------------------------------------------+
//| Pattern string properties                                        |
//+------------------------------------------------------------------+
enum ENUM_PATTERN_PROP_STRING
  {
   PATTERN_PROP_SYMBOL = (PATTERN_PROP_INTEGER_TOTAL+PATTERN_PROP_DOUBLE_TOTAL),  // Pattern symbol
   PATTERN_PROP_NAME,                                       // Pattern name
  };
#define PATTERN_PROP_STRING_TOTAL   (2)                     // Total number of pattern string properties

Adicionaremos as propriedades, inerentes a todos os padrões, a essas listas de propriedades. Então, em métodos herdados dos padrões base que retornam uma flag para o uso de uma determinada propriedade, indicaremos quais propriedades dessas listas não pertencem a esse padrão específico.

Agora vamos escrever uma enumeração com possíveis critérios de ordenação para busca, ordenação e filtragem de padrões em sua lista geral:

//+------------------------------------------------------------------+
//| Possible pattern sorting criteria                                |
//+------------------------------------------------------------------+
#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 integer properties
   SORT_BY_PATTERN_CODE = 0,                                // Sort by unique pattern code (time + type + status + direction + timeframe)
   SORT_BY_PATTERN_CTRL_OBJ_ID,                             // Sort by pattern control object ID
   SORT_BY_PATTERN_ID,                                      // Sort by pattern ID
   SORT_BY_PATTERN_TIME,                                    // Sort by pattern defining bar time
   SORT_BY_PATTERN_STATUS,                                  // Sort by pattern status (from the ENUM_PATTERN_STATUS enumeration)
   SORT_BY_PATTERN_TYPE,                                    // Sort by pattern type (from the ENUM_PATTERN_TYPE enumeration)
   SORT_BY_PATTERN_DIRECTION,                               // Sort by pattern type based on direction (from the ENUM_PATTERN_TYPE_DIRECTION enumeration)
   SORT_BY_PATTERN_PERIOD,                                  // Sort by pattern period (timeframe)
   SORT_BY_PATTERN_CANDLES,                                 // Sort by the number of candles that make up the pattern
   
//--- Sort by real properties
   SORT_BY_PATTERN_BAR_PRICE_OPEN = FIRST_PATTERN_DBL_PROP, // Sort by pattern defining bar Open price
   SORT_BY_PATTERN_BAR_PRICE_HIGH,                          // Sort by pattern defining bar High price
   SORT_BY_PATTERN_BAR_PRICE_LOW,                           // Sort by pattern defining bar Low price
   SORT_BY_PATTERN_BAR_PRICE_CLOSE,                         // Sort by pattern defining bar Close price
   SORT_BY_PATTERN_RATIO_BODY_TO_CANDLE_SIZE,               // Sort by percentage ratio of the candle body to the full size of the candle
   SORT_BY_PATTERN_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,       // Sort by percentage ratio of the upper shadow size to the candle size
   SORT_BY_PATTERN_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,       // Sort by percentage ratio of the lower shadow size to the candle size
   SORT_BY_PATTERN_RATIO_BODY_TO_CANDLE_SIZE_CRITERION,           // Sort by defined criterion of the ratio of the candle body to the full candle size in %
   SORT_BY_PATTERN_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRITERION,  // Sort by  defined criterion of the ratio of the maximum shadow to the candle size in %
   SORT_BY_PATTERN_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRITERION, // Sort by  defined criterion of the ratio of the minimum shadow to the candle size in %
   
//--- Sort by string properties
   SORT_BY_PATTERN_SYMBOL = FIRST_BAR_STR_PROP,             // Sort by a pattern symbol
   SORT_BY_PATTERN_NAME,                                    // Sort by pattern name
  };

Usando essas propriedades, poderemos buscar padrões na lista.

Quando um padrão é encontrado na barra base mais próxima da atual, precisaremos enviar uma mensagem para a biblioteca para que ela possa processá-la e enviar a mensagem para o programa de controle. Já temos os métodos para enviar e tratar mensagens sobre eventos de séries temporais. Mas esses métodos exigem a adição de eventos para encontrar um novo padrão.

Adicione um código de mensagem sobre encontrar um novo padrão à lista de possíveis eventos de séries temporais:

//+------------------------------------------------------------------+
//| List of possible timeseries events                               |
//+------------------------------------------------------------------+
enum ENUM_SERIES_EVENT
  {
   SERIES_EVENTS_NO_EVENT = SYMBOL_EVENTS_NEXT_CODE,        // no event
   SERIES_EVENTS_NEW_BAR,                                   // "New bar" event
   SERIES_EVENTS_MISSING_BARS,                              // "Bars skipped" event
   SERIES_EVENTS_PATTERN,                                   // "Pattern" event
  };
#define SERIES_EVENTS_NEXT_CODE  (SERIES_EVENTS_PATTERN+1)  // Code of the next event after the "Pattern" event

Mude o código do próximo evento de "Skipped bars+1" para "Pattern+1", para que os códigos de eventos subsequentes comecem com o valor correto.


Em \MQL5\Include\DoEasyData.mqh, escreva índices das novas mensagens da biblioteca:

   MSG_LIB_TEXT_BAR_TYPE_CANDLE_ZERO_BODY,            // Candle with a zero body
   MSG_LIB_TEXT_BAR_TEXT_FIRS_SET_AMOUNT_DATA,        // First, we need to set the required amount of data using SetRequiredUsedData()
   
   MSG_LIB_TEXT_BAR_RATIO_BODY_TO_CANDLE_SIZE,        // Percentage ratio of the candle body to the full size of the candle
   MSG_LIB_TEXT_BAR_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,// Percentage ratio of the upper shadow size to the candle size
   MSG_LIB_TEXT_BAR_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,// Percentage ratio of the lower shadow size to the candle size
  
//--- CTimeSeries

...

   MSG_LIB_TEXT_TS_TEXT_ATTEMPT,                      // Attempt:
   MSG_LIB_TEXT_TS_TEXT_WAIT_FOR_SYNC,                // Waiting for data synchronization ...

//--- CPattern
   MSG_LIB_TEXT_PATTERN_CODE,                         // Code
   MSG_LIB_TEXT_PATTERN_TIME,                         // Defining bar time
   MSG_LIB_TEXT_PATTERN_ID,                           // Pattern ID
   MSG_LIB_TEXT_PATTERN_CTRL_OBJ_ID,                  // Pattern control object ID
   MSG_LIB_TEXT_PATTERN_CANDLES,                      // Number of candles that make up the pattern
   MSG_LIB_TEXT_PATTERN_DIRECTION,                    // Pattern direction
   
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_OPEN,               // Pattern defining bar Open price
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_HIGH,               // Pattern defining bar High price
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_LOW,                // Pattern defining bar Low price
   MSG_LIB_TEXT_PATTERN_BAR_PRICE_CLOSE,              // Pattern defining bar Close price
   
   MSG_LIB_TEXT_PATTERN_RATIO_BODY_TO_CANDLE_SIZE,          // Percentage ratio of the candle body to the full size of the candle
   MSG_LIB_TEXT_PATTERN_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,  // Percentage ratio of the upper shadow size to the candle size
   MSG_LIB_TEXT_PATTERN_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,  // Percentage ratio of the lower shadow size to the candle size
   MSG_LIB_TEXT_PATTERN_RATIO_BODY_TO_CANDLE_SIZE_CRIT,           // Defined criterion of the ratio of the candle body to the full candle size in %
   MSG_LIB_TEXT_PATTERN_RATIO_LARGER_SHADOW_TO_CANDLE_SIZE_CRIT,  // Defined criterion of the ratio of the maximum shadow to the candle size in %
   MSG_LIB_TEXT_PATTERN_RATIO_SMALLER_SHADOW_TO_CANDLE_SIZE_CRIT, // Defined criterion of the ratio of the minimum shadow to the candle size in %
   
   MSG_LIB_TEXT_PATTERN_NAME,                         // Name

   MSG_LIB_TEXT_PATTERN_STATUS_JC,                    // Candle pattern
   MSG_LIB_TEXT_PATTERN_STATUS_PA,                    // Price Action formation
   MSG_LIB_TEXT_PATTERN_BULLISH,                      // Bullish pattern
   MSG_LIB_TEXT_PATTERN_BEARISH,                      // Bearish pattern
   MSG_LIB_TEXT_PATTERN_BOTH,                         // Bidirectional pattern
   
   //--- Candles
   MSG_LIB_TEXT_PATTERN_TYPE_HARAMI,                  // Harami
   MSG_LIB_TEXT_PATTERN_TYPE_HARAMI_CROSS,            // Harami Cross
   MSG_LIB_TEXT_PATTERN_TYPE_TWEEZER,                 // Tweezer
   MSG_LIB_TEXT_PATTERN_TYPE_PIERCING_LINE,           // Piercing Line
   MSG_LIB_TEXT_PATTERN_TYPE_DARK_CLOUD_COVER,        // Dark Cloud Cover
   MSG_LIB_TEXT_PATTERN_TYPE_THREE_WHITE_SOLDIERS,    // Three White Soldiers
   MSG_LIB_TEXT_PATTERN_TYPE_THREE_BLACK_CROWS,       // Three Black Crows
   MSG_LIB_TEXT_PATTERN_TYPE_SHOOTING_STAR,           // Shooting Star
   MSG_LIB_TEXT_PATTERN_TYPE_HAMMER,                  // Hammer
   MSG_LIB_TEXT_PATTERN_TYPE_INVERTED_HAMMER,         // Inverted Hammer
   MSG_LIB_TEXT_PATTERN_TYPE_HANGING_MAN,             // Hanging Man
   MSG_LIB_TEXT_PATTERN_TYPE_DOJI,                    // Doji
   MSG_LIB_TEXT_PATTERN_TYPE_DRAGONFLY_DOJI,          // Dragonfly Doji
   MSG_LIB_TEXT_PATTERN_TYPE_GRAVESTONE_DOJI,         // Gravestone Doji
   MSG_LIB_TEXT_PATTERN_TYPE_MORNING_STAR,            // Morning Star
   MSG_LIB_TEXT_PATTERN_TYPE_MORNING_DOJI_STAR,       // Morning Doji Star
   MSG_LIB_TEXT_PATTERN_TYPE_EVENING_STAR,            // Evening Star
<100/100/72% >
   MSG_LIB_TEXT_PATTERN_TYPE_EVENING_DOJI_STAR,       // Evening Doji Star
   MSG_LIB_TEXT_PATTERN_TYPE_THREE_STARS,             // Three Stars
   MSG_LIB_TEXT_PATTERN_TYPE_ABANDONED_BABY,          // Abandoned Baby
   //--- Price Action
   MSG_LIB_TEXT_PATTERN_TYPE_PIVOT_POINT_REVERSAL,    // Pivot Point Reversal
   MSG_LIB_TEXT_PATTERN_TYPE_OUTSIDE_BAR,             // Outside Bar
   MSG_LIB_TEXT_PATTERN_TYPE_INSIDE_BAR,              // Inside Bar
   MSG_LIB_TEXT_PATTERN_TYPE_PIN_BAR,                 // Pin Bar
   MSG_LIB_TEXT_PATTERN_TYPE_RAILS,                   // Rails

//--- CBuffer

e mensagens correspondentes aos índices recém-adicionados:

   {"Свеча с нулевым телом","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"},

   //--- Pattern status
   {"Свечной паттерн","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


Na seção privada do arquivo de classe de objeto Bar \MQL5\Include\DoEasy\Objects\SeriesBar.mqh, escreva os métodos que calculam e retornam as proporções das velas:

//+------------------------------------------------------------------+
//| Bar class                                                        |
//+------------------------------------------------------------------+
class CBar : public CBaseObj
  {
private:
   MqlDateTime       m_dt_struct;                                 // Date structure
   int               m_digits;                                    // Symbol's digits value
   string            m_period_description;                        // Timeframe string description
   long              m_long_prop[BAR_PROP_INTEGER_TOTAL];         // Integer properties
   double            m_double_prop[BAR_PROP_DOUBLE_TOTAL];        // Real properties
   string            m_string_prop[BAR_PROP_STRING_TOTAL];        // String properties

//--- Return the index of the array the bar's (1) double and (2) string properties are located at
   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;  }

//--- Return the bar type (bullish/bearish/zero)
   ENUM_BAR_BODY_TYPE BodyType(void)                              const;
//--- Calculate and return the size of (1) candle, (2) candle body,
//--- (3) upper, (4) lower candle wick,
//--- (5) candle body top and (6) bottom
   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());                           }
   
//--- Calculate and return the percentage ratio of the (1) candle body, (2) upper and (3) lower shadow size to the full candle size
   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);  }
   
//--- Return the (1) year and (2) month the bar belongs to, (3) week day,
//--- (4) bar serial number in a year, (5) day, (6) hour, (7) minute,
   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:


Na seção pública, nomeadamente no acesso simplificado às propriedades do bar, escreva os métodos que retornam as novas propriedades do bar para as proporções das velas:

//+------------------------------------------------------------------+ 
//| Methods of simplified access to bar object properties            |
//+------------------------------------------------------------------+
//--- Return the (1) type, (2) period, (3) spread, (4) tick, (5) exchange volume,
//--- (6) bar period start time, (7) year, (8) month the bar belongs to
//--- (9) week number since the year start, (10) week number since the month start
//--- (11) day, (12) hour, (13) minute
   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);               }

//--- Return bar's (1) Open, (2) High, (3) Low, (4) Close price,
//--- size of the (5) candle, (6) body, (7) candle top, (8) bottom,
//--- size of the (9) candle upper, (10) lower wick
   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);   }
   
//--- Return the properties of the percentage ratio of the (1) candle body, (2) upper and (3) lower shadow size to the candle full size
   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);}
   
//--- Return bar symbol
   string            Symbol(void)                                       const { return this.GetProperty(BAR_PROP_SYMBOL);                    }
//--- Return bar index on the specified timeframe the bar time falls into
   int               Index(const ENUM_TIMEFRAMES timeframe)  const
                       { return ::iBarShift(this.Symbol(),(timeframe==PERIOD_CURRENT ? ::Period() : timeframe),this.Time());                 }  


No método que define os parâmetros do objeto bar, adicione a escrita das proporções das velas calculadas nas propriedades do objeto bar:

//+------------------------------------------------------------------+
//| Set bar object parameters                                        |
//+------------------------------------------------------------------+
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());
//--- Set the object type to the object of the graphical object management class
   this.m_graph_elm.SetTypeNode(this.m_type);
  }


No método que retorna uma descrição de uma propriedade real de um bar, implemente a devolução das descrições das novas propriedades do bar:

//+------------------------------------------------------------------+
//| Return the description of the bar's real property                |
//+------------------------------------------------------------------+
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)+"%"
         )  :
      ""
     );
  }


Isso conclui a melhoria das classes. Agora podemos começar a criar um objeto de padrão básico.

Classe de padrão abstrato

Em \MQL5\Include\DoEasy\Objects\SeriesPatterns, crie o novo arquivo Pattern.mqh. A classe deve ser herdada do objeto de biblioteca subjacente, cujo arquivo precisa ser conectado ao arquivo da classe criada:

//+------------------------------------------------------------------+
//|                                                      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    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Abstract pattern class                                           |
//+------------------------------------------------------------------+
class CPattern : public CBaseObj
  {
  }


A seção privada declara arrays padrão de propriedades para objetos de biblioteca e métodos que retornam o índice real da propriedade no array correspondente:

class CPattern : public CBaseObj
  {
private:
   long              m_long_prop[PATTERN_PROP_INTEGER_TOTAL];     // Integer properties
   double            m_double_prop[PATTERN_PROP_DOUBLE_TOTAL];    // Real properties
   string            m_string_prop[PATTERN_PROP_STRING_TOTAL];    // String properties
   
//--- Return the index of the array the pattern (1) double and (2) string properties are located at
   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:


Na seção protegida da classe, são declaradas as variáveis membro da classe necessárias para seu funcionamento:

protected:
   CForm            *m_form;                                      // Pointer to form object
   int               m_digits;                                    // Symbol's digits value
   ulong             m_symbol_code;                               // Symbol as a number (sum of name symbol codes)
   string            m_name_graph_obj;                            // Name of the graphical object displaying the pattern
   double            m_price;                                     // Price level the graphical object is placed at
   color             m_color_bullish;                             // Color of a graphical object set to the bullish pattern icon
   color             m_color_bearish;                             // Color of a graphical object set to the bearish pattern icon
   color             m_color_bidirect;                            // Color of a graphical object set to the bidirectional pattern icon
   color             m_color;                                     // Graphical object color
   color             m_color_panel_bullish;                       // Bullish pattern panel color
   color             m_color_panel_bearish;                       // Bearish pattern panel color
   color             m_color_panel_bidirect;                      // Bidirectional pattern panel color

public:

Um objeto de formulário é necessário para criar um painel de informações que aparecerá ao passar o mouse sobre o gráfico onde o padrão é formado. O código digital do símbolo é necessário para converter o nome do símbolo em um número que será adicionado ao ID do padrão. O ID do padrão é um número único que consiste no tempo de abertura do bar + tipo de padrão + seu status + direção do padrão + período de tempo + símbolo da série temporal. Usando esse código, determinaremos que exatamente esse padrão já está na lista de padrões.


A seção pública da classe declara métodos padrão de biblioteca:

public:
//--- Set pattern (1) integer, (2) real and (3) string properties
   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;  }
//--- Return (1) integer, (2) real and (3) string pattern properties from the property array
   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)];      }

//--- Return the flag of the pattern supporting the specified 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; }
//--- Return itself
   CPattern         *GetObject(void)                                       { return &this;}

//--- Compare CPattern objects by all possible properties (for sorting the lists by a specified pattern object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CPattern objects with each other by all properties (to search equal pattern objects)
   bool              IsEqual(CPattern* compared_obj) const;
//--- Constructors
                     CPattern(){ this.m_type=OBJECT_DE_TYPE_SERIES_PATTERN; }
protected:
//--- Protected parametric constructor
                     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:                     
//--- Destructor
                    ~CPattern(void);


Métodos para acesso simplificado às propriedades do objeto padrão, métodos para descrever as propriedades do objeto padrão, bem como métodos para trabalhar com as cores dos objetos gráficos também são declarados lá:

//+------------------------------------------------------------------+ 
//| Methods of a simplified access to the pattern object properties  |
//+------------------------------------------------------------------+
//--- Return (1) type, (2) direction, (3) period, (4) status,
//--- (5) code, (6) pattern defining bar time,
//--- (7) number of candles forming the pattern
   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);                     }
//--- Return pattern defining bar prices
   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);                   }
//--- Return pattern (1) symbol and (2) name
   string            Symbol(void)                                    const { return this.GetProperty(PATTERN_PROP_SYMBOL);                            }
   string            Name(void)                                      const { return this.GetProperty(PATTERN_PROP_NAME);                              }
//+------------------------------------------------------------------+
//| Descriptions of pattern object properties                        |
//+------------------------------------------------------------------+
//--- Get description of pattern (1) integer, (2) real and (3) string property
   string            GetPropertyDescription(ENUM_PATTERN_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_PATTERN_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_PATTERN_PROP_STRING property);

//--- Return description of the pattern (1) status, (2) type and (3) direction
   virtual string    StatusDescription(void) const { return NULL; }
   virtual string    TypeDescription(void)   const { return NULL; }
   string            DirectDescription(void) const;
//--- Display the description of the object properties in the journal (full_prop=true - all properties, false - supported ones only - implemented in descendant classes)
   virtual void      Print(const bool full_prop=false,const bool dash=false);
//--- Display a short description of the object in the journal
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);
//--- Return a short name of a pattern object
   virtual string    Header(void);
//+------------------------------------------------------------------+
//| Handle graphical display                                         |
//+------------------------------------------------------------------+
protected:
//--- Remove a graphical object
   bool              DeleteGraphObj(bool redraw=false);
//--- Set graphical object display colors for the (1) bullish, (2) bearish and (3) bidirectional pattern
   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;        }
//--- Create the info panel object
   bool              CreateInfoPanel(void);
//--- Create the info panel appearance
   virtual void      CreateInfoPanelView(void){}
public:
//--- Set graphical object display colors and pattern display color
   void              SetColors(const color color_bullish,const color color_bearish,const color color_bidirect,const bool redraw=false);
//--- Set the background color for the (1) bullish, (2) bearish and (3) bidirectional pattern panel
   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;  }
//--- Set the background color for the (1) bullish, (2) bearish and (3) bidirectional pattern panel by setting the values of the RGB color components
   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);

//--- Draw a pattern icon on the chart
   void              Draw(const bool redraw=false);
//--- (1) Display, (2) hide the pattern icon on the chart
   void              Show(const bool redraw=false);
   void              Hide(const bool redraw=false);
//--- (1) Display and (2) hide the info panel on the chart
   void              ShowInfoPanel(const int x,const int y);
   void              HideInfoPanel(void);
  };


Vamos considerar a implementação dos métodos declarados.

No construtor da classe, defina as propriedades do objeto padrão e os parâmetros do objeto gráfico — o rótulo do padrão no gráfico e o painel de informações:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
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)
  {
//--- Set pattern object properties
   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);
//--- Create symbol code
   this.m_symbol_code=0;
   for(int i=0;i<(int)symbol.Length();i++)
      this.m_symbol_code+=symbol.GetChar(i);
//--- Pattern code = defining bar time + type + status + pattern direction + timeframe + symbol code
   ulong code=(ulong)rates.time+type+status+direction+timeframe+this.m_symbol_code;
   this.SetProperty(PATTERN_PROP_CODE,code);
//--- Set pattern graphical objects parameters (chart labels)
   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;
     }
//--- Set base colors of the pattern information panels
   this.m_color_panel_bullish=clrLightGray;
   this.m_color_panel_bearish=clrLightGray;
   this.m_color_panel_bidirect=clrLightGray;
   this.m_form=NULL;
  }


No destrutor da classe, exclua os objetos gráficos criados:

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CPattern::~CPattern(void)
  {
//--- Delete the form object and pattern label on the chart
   if(this.m_form!=NULL)
      delete this.m_form;
   this.DeleteGraphObj();
  }


O método de comparação dos objetos CPattern por uma propriedade especificada:

//+--------------------------------------------------------------------+
//| Compare CPattern objects with each other by the specified property |
//+--------------------------------------------------------------------+
int CPattern::Compare(const CObject *node,const int mode=0) const
  {
   const CPattern *obj_compared=node;
//--- compare integer properties of two patterns
   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);
     }
//--- compare real properties of two patterns
   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);
     }
//--- compare string properties of two patterns
   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;
  }

Este é um método padrão da biblioteca para comparar as propriedades de dois objetos.


O método de comparação dos objetos CPattern por todas as propriedades:

//+------------------------------------------------------------------+
//| Compare CPattern objects with each other by all properties       |
//+------------------------------------------------------------------+
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;
  }

Este também é um método padrão da biblioteca. Ele retorna true apenas se todas as propriedades dos dois objetos sendo comparados forem iguais.


Métodos para enviar descrições das propriedades do padrão para o jornal:

//+------------------------------------------------------------------+
//| Send pattern properties to the journal                           |
//+------------------------------------------------------------------+
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");
  }
//+------------------------------------------------------------------+
//| Display the short pattern description in the journal             |
//+------------------------------------------------------------------+
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());
  }
//+------------------------------------------------------------------+
//| Return a short name of a pattern object                          |
//+------------------------------------------------------------------+
string CPattern::Header(void)
  {
   return(this.StatusDescription()+" "+this.TypeDescription());
  }
//+------------------------------------------------------------------+
//| Return the description of the pattern integer property           |
//+------------------------------------------------------------------+
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)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return the description of the pattern real 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)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return the description of the pattern string property            |
//+------------------------------------------------------------------+
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)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return the pattern direction description                         |
//+------------------------------------------------------------------+
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";
     }
  }

Métodos semelhantes foram descritos mais de uma vez em artigos anteriores sobre a biblioteca, e não retornaremos à sua descrição aqui - tudo é bastante simples e claro.


Métodos para trabalhar com objetos gráficos:

//+------------------------------------------------------------------+
//| Delete a graphical label object of a chart pattern               |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Create the info panel                                            |
//+------------------------------------------------------------------+
bool CPattern::CreateInfoPanel(void)
  {
   int x=0, y=0;
//--- If the panel object has already been created earlier, return 'true'
   if(this.m_form!=NULL)
      return true;
//--- Determine the price of the upper left corner between the candle High and Low
   double price=(this.BarPriceHigh()+this.BarPriceLow())/2;
//--- Obtain the panel X and Y coordinates using the bar time and calculated price
   if(!::ChartTimePriceToXY(this.m_chart_id,0,this.Time(),price,x,y))
      return false;
//--- Create the panel object
   this.m_form=this.CreateForm(this.ID(),this.Name(),x,y,4,4);
   if(this.m_form==NULL)
      return false;
//--- Draw the panel appearance
   this.CreateInfoPanelView();
   return true;
  }
//+------------------------------------------------------------------+
//| Display the info panel on the chart                              |
//+------------------------------------------------------------------+
void CPattern::ShowInfoPanel(const int x,const int y)
  {
//--- If there is no panel object yet, create it
   if(this.m_form==NULL)
      if(!this.CreateInfoPanel())
         return;
//--- Get the chart width and height
   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);
//--- Calculate the X and Y coordinates of the panel so that it does not go beyond the chart
   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);
//--- Set the calculated coordinates and display the panel
   if(this.m_form.SetCoordX(cx) && this.m_form.SetCoordY(cy))
      this.m_form.Show();
  }
//+------------------------------------------------------------------+
//| Hide the info panel on the chart                                 |
//+------------------------------------------------------------------+
void CPattern::HideInfoPanel(void)
  {
   if(this.m_form!=NULL)
      this.m_form.Hide();
  }
//+------------------------------------------------------------------+
//| Draw the pattern icon on the chart                               |
//+------------------------------------------------------------------+
void CPattern::Draw(const bool redraw=false)
  {
//--- If the graphical object has not yet been created, create it
   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;
     }
//--- Otherwise - display
   else
      this.Show(redraw);
  }
//+------------------------------------------------------------------+
//| Display the pattern icon on the chart                            |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Hide the pattern icon on the chart                               |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set graphical object and                                         |
//| and pattern display colors                                       |
//+------------------------------------------------------------------+
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);
  }

Os métodos são bastante simples e comentados. Não faz muito sentido desmontar cada um deles - todos os métodos são claros ao ler seu código.

O objeto básico de padrão abstrato está pronto. Faremos todos os padrões planejados para a biblioteca com base nele. Os parâmetros exatos e as propriedades usadas/não usadas devem ser definidos nos padrões.

Vamos começar com o simples mas útil padrão de Price Action Pin Bar.


Padrão Pin Bar

Barras com um corpo curto, uma sombra longa e praticamente sem segunda sombra são os sinais mais importantes no gráfico de preços. Eles frequentemente fornecem uma dica forte (melhor do que outras barras) sobre para onde o preço pode ir, dado o ambiente atual e as condições de mercado. 

A classe será feita da maneira mais simples possível - para cada classe herdada do objeto de padrão base, precisamos apenas indicar algumas propriedades exclusivas desse padrão e indicar quais propriedades são suportadas na classe descendente e quais não são.

Vamos olhar a classe do padrão Pin Bar, que continuamos a escrever no mesmo arquivo que a classe de padrão base:

//+------------------------------------------------------------------+
//| Pin Bar pattern class                                            |
//+------------------------------------------------------------------+
class CPatternPinBar : public CPattern
  {
protected:
//--- Create the info panel appearance
   virtual void      CreateInfoPanelView(void);
public:
//--- Return the flag of the pattern supporting the specified 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; }
   
//--- Return description of the pattern (1) status and (2) type
   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); }

//--- Constructor
                     CPatternPinBar(const uint id,const string symbol,const ENUM_TIMEFRAMES timeframe,MqlRates &rates,const ENUM_PATTERN_DIRECTION direct);
  };

Métodos que retornam descrições do status e do tipo do padrão retornam as strings "Price Action Formation" e "Pin Bar", respectivamente. Os métodos que retornam flags de uso de propriedade retornam true para todas as propriedades aqui. Ao adicionar novos padrões e novas propriedades de barras para padrões, proibiremos as propriedades não relacionadas ao padrão Pin Bar.

Na string de inicialização do construtor da classe, passe o "Price Action" status do padrão, "Pin Bar" tipo de padrão e os parâmetros restantes, passados nas entradas do construtor, para a classe pai:

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

No corpo do construtor, defina o nome do padrão como "Pin Bar" e o número de velas que compõem o padrão como 1.


O método virtual que cria a aparência do painel de informações será diferente para cada padrão — ele exibirá as propriedades inerentes ao padrão. Para o padrão Pin Bar, o método será assim:

//+------------------------------------------------------------------+
//| Create the info panel appearance                                 |
//+------------------------------------------------------------------+
void CPatternPinBar::CreateInfoPanelView(void)
  {
//--- If the form object is not created, leave
   if(this.m_form==NULL)
      return;
//--- Change the color tone for bullish and bearish patterns: the bullish ones will have a blue tint, while the bearish ones will have a red tint
   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;
//--- Declare the array for the initial and final colors of the gradient fill
   color clr[2]={};
//--- Depending on the direction of the pattern, change the lightness of the corresponding colors - the initial one is a little darker, the final one is a little lighter
   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;
     }
   
//--- Set the background and form frame colors
   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);
//--- Create strings to describe the pattern, its parameters and search criteria
   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));
//--- Set the coordinates of the panel and calculate its width and height depending on the size of the texts placed on the panel
   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())));
//--- Set the width and height of the panel according to the calculated values
   this.m_form.SetWidth(w);
   this.m_form.SetHeight(h);
//--- Depending on the chart size and coordinates, we calculate the coordinates of the panel so that it does not go beyond the chart
   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);
//--- Fill the background with a gradient color
   this.m_form.Erase(clr,200,true,false);
//--- Draw the panel frame, an icon with (i), draw the header text with the proportions of a candle and separate the header with a horizontal line
   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);
//--- Under the horizontal line, enter the pattern description with its search criteria and the date of the pattern-defining bar
   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);
//--- Update the panel while redrawing the chart
   this.m_form.Update(true);
  }

A lógica do método está totalmente descrita nos comentários do código. No cabeçalho, exiba o nome do padrão e as proporções da vela na qual o padrão foi encontrado. Sob o cabeçalho, exibiremos a direção do padrão, seus critérios de busca e a data/hora da barra que define o padrão:

As proporções da vela são especificadas no cabeçalho:

  • 16.22 — proporção do corpo da vela em relação ao tamanho total da vela, 
  • 18.92 — proporção da sombra superior em relação ao tamanho total da vela, 
  • 64.86 — proporção da sombra inferior em relação ao tamanho total da vela.

O cabeçalho indica a direção do padrão e seus critérios de busca:

  • 30.00 — o corpo não deve exceder 30% do tamanho total da vela, 
  • 60.00 — a maior sombra deve ser pelo menos 60% do tamanho total da vela, 
  • 30.00 — a menor sombra não deve ser mais do que 30% do tamanho total da vela.

Para diferentes padrões, seus critérios de busca serão diferentes, portanto, dados diferentes serão exibidos no painel de informações, que é o que o método virtual faz, desenhando a aparência do painel.

Terminamos com as classes de padrões por enquanto. Agora precisamos integrá-las na biblioteca.


Esse conjunto de ferramentas é necessário para que possamos classificar os padrões. Adicione tudo o que precisamos na classe CSelect do arquivo de biblioteca \MQL5\Include\DoEasy\ServicesSelect.mqh.

Primeiramente, inclua o arquivo da classe de padrão no arquivo da classe CSelect:

//+------------------------------------------------------------------+
//|                                                       Select.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#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"


Declare os métodos para lidar com os padrões imediatamente após anunciar os métodos para lidar com as barras de séries temporais:

//+------------------------------------------------------------------+
//| Methods of working with timeseries bars                          |
//+------------------------------------------------------------------+
   //--- Return the list of bars with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion
   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);
   //--- Return the bar index in the list with the maximum value of the bar's (1) integer, (2) real and (3) string properties
   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);
   //--- Return the bar index in the list with the minimum value of the bar's (1) integer, (2) real and (3) string properties
   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);
//+------------------------------------------------------------------+
//| Methods for working with timeseries patterns                     |
//+------------------------------------------------------------------+
   //--- Return the list of patterns with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion
   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);
   //--- Return the pattern index in the list with the maximum value of the pattern (1) integer, (2) real and (3) string properties
   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);
   //--- Return the pattern index in the list with the minimum value of the pattern (1) integer, (2) real and (3) string properties
   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);
//+------------------------------------------------------------------+
//| Methods of working with indicator buffers                        |
//+------------------------------------------------------------------+


Vamos escrever sua implementação fora do corpo da classe:

//+------------------------------------------------------------------+
//| Methods for working with lists of timeseries patterns            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Return the list of patterns with one integer                     |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the list of patterns with one real                        |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the list of patterns with one string                      |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the pattern index in the list                             |
//| with the maximum integer property value                          |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the pattern index in the list                             |
//| with the maximum real property value                             |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the pattern index in the list                             |
//| with the maximum string property value                           |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the pattern index in the list                             |
//| with the minimum integer property value                          |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the pattern index in the list                             |
//| with the minimum real property value                             |
//+------------------------------------------------------------------+
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;
  }
//+------------------------------------------------------------------+
//| Return the pattern index in the list                             |
//| with the minimum string property value                           |
//+------------------------------------------------------------------+
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;
  }

A classe CSelect foi considerada no terceiro artigo que descreve a biblioteca. Para listas de todos os objetos onde é necessário buscar e classificar por propriedades do objeto, métodos logicamente idênticos são implementados na classe CSelect. Para objetos de padrão, tudo é exatamente igual. Portanto, após ler a descrição da classe, podemos entender todos os métodos acima.

A única coisa que agora distingue a classe discutida anteriormente é o método CompareValues() para comparar os valores de dois objetos. Anteriormente, parecia o seguinte:

//+------------------------------------------------------------------+
//| Method for comparing two values                                  |
//+------------------------------------------------------------------+
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
     );
  }

No momento, a construção if-else usada no método antigo foi substituída por switch:

//+------------------------------------------------------------------+
//| Method for comparing two values                                  |
//+------------------------------------------------------------------+
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;
     }
  }

Dessa forma, a comparação deve funcionar mais rápido.


Classes de controle de padrão

Vamos criar uma classe de controle de padrão para cada padrão, e até mesmo para padrões idênticos com parâmetros diferentes. Nesta classe, armazenaremos as propriedades especificadas para a busca de um padrão, organizaremos sua busca na série temporal e retornaremos ponteiros para os padrões buscados. Cada padrão terá seu próprio ID exclusivo, consistindo no nome do símbolo, período de tempo, tipo de padrão, direção do padrão e a soma de seus parâmetros. Assim, mesmo dois padrões idênticos no mesmo símbolo e período de gráfico, mas com parâmetros diferentes, serão independentes e diferentes. Além disso, eles estarão presentes na lista de todos os padrões.

De acordo com a ordem existente de arquivos na biblioteca, cada novo tipo de classe tem seu próprio arquivo - isso organiza a estrutura da biblioteca e reduz o tamanho de cada arquivo. Mas, neste caso, tive que colocar as classes de controle de padrão no arquivo da classe de séries temporais \MQL5\Include\DoEasy\Objects\SeriesSeriesDE.mqh. Isso se deve ao fato de que há muitas interconexões de diferentes classes na biblioteca. Portanto, se dividirmos a classe de séries temporais e as classes de controle de padrão em arquivos diferentes e conectarmos o arquivo das classes de controle de padrão ao arquivo de séries temporais, alguns dos arquivos param de compilar, já que o compilador não tem acesso ao arquivo de séries temporais em um lugar e ao arquivo da classe de controle de padrão em outro. Até agora, não consegui conectar tudo corretamente, por mais que tenha tentado. Eventualmente, decidi escrever as classes de controle de padrão diretamente no arquivo da classe de séries temporais onde uma das classes de controle de padrão estará localizada.

A estrutura será assim: para cada padrão com seu conjunto de propriedades e parâmetros, será criada sua própria classe de controle. O número de padrões criados para busca e o número de diferentes variações dos padrões do mesmo tipo necessários são iguais ao número de objetos de controle de padrão. Em seguida, esses objetos criados são colocados na lista da classe de controle para todos os objetos de controle de padrão criados. A partir daí, é fornecido o acesso aos objetos de gestão. A partir daí, por sua vez, obtemos acesso diretamente aos padrões.

Abra o arquivo da classe de séries temporais \MQL5\Include\DoEasy\Objects\SeriesSeriesDE.mqh. Vamos começar a desenvolver uma nova classe para gerenciar o padrão abstrato:

//+------------------------------------------------------------------+
//|                                                     SeriesDE.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\Select.mqh"
#include "..\..\Services\NewBarObj.mqh"
#include "Bar.mqh"
//+------------------------------------------------------------------+
//| Abstract pattern control class                                   |
//+------------------------------------------------------------------+
class CPatternControl : public CBaseObjExt
  {
private:
   ENUM_TIMEFRAMES   m_timeframe;                                                // Pattern timeseries chart period
   string            m_symbol;                                                   // Pattern timeseries symbol
   double            m_point;                                                    // Symbol Point
   bool              m_used;                                                     // Pattern use flag
   bool              m_drawing;                                                  // Flag for drawing the pattern icon on the chart
//--- Handled pattern
   ENUM_PATTERN_TYPE m_type_pattern;                                             // Pattern type
protected:
//--- Candle proportions
   double            m_ratio_body_to_candle_size;                                // Percentage ratio of the candle body to the full size of the candle
   double            m_ratio_larger_shadow_to_candle_size;                       // Percentage ratio of the size of the larger shadow to the size of the candle
   double            m_ratio_smaller_shadow_to_candle_size;                      // Percentage ratio of the size of the smaller shadow to the size of the candle
   ulong             m_object_id;                                                // Unique object code based on pattern search criteria
//--- List views
   CArrayObj        *m_list_series;                                              // Pointer to the timeseries list
   CArrayObj        *m_list_all_patterns;                                        // Pointer to the list of all patterns
   CPattern          m_pattern_instance;                                         // Pattern object for searching by property
   ulong             m_symbol_code;                                              // Chart symbol name as a number

//--- (1) Search for a pattern, return direction (or -1 if no pattern is found),
//--- (2) create a pattern with a specified direction,
//--- (3) create and return a unique pattern code,
//--- (4) return the list of patterns managed by the object
   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;                                        }

//--- Create object ID based on pattern search criteria
   virtual ulong     CreateObjectID(void)                                        { return 0;                                           }

public:
//--- Return itself
   CPatternControl  *GetObject(void)                                             { return &this;                                       }
//--- (1) Set and (2) return the pattern usage flag
   void              SetUsed(const bool flag)                                    { this.m_used=flag;                                   }
   bool              IsUsed(void)                                          const { return this.m_used;                                 }
//--- (1) Set and (2) return the pattern drawing flag
   void              SetDrawing(const bool flag)                                 { this.m_drawing=flag;                                }
   bool              IsDrawing(void)                                       const { return this.m_drawing;                              }
   
//--- Set the necessary percentage ratio of the candle body to the full size of the candle,
//--- size of the (2) upper and (3) lower shadow to the candle size
   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;   }
//--- Return the percentage ratio (1) of the candle body to the full size of the candle,
//--- size of the (2) upper and (3) lower shadow to the candle size
   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;  }

//--- Return object ID based on pattern search criteria
   virtual ulong     ObjectID(void)                                        const { return this.m_object_id;                            }

//--- Return pattern (1) type, (2) timeframe, (3) symbol, (4) symbol Point, (5) symbol code
   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;                          }

//--- Compare CPatternControl objects by all possible properties
   virtual int       Compare(const CObject *node,const int mode=0) const;

//--- Search for patterns and add found ones to the list of all patterns
   virtual int       CreateAndRefreshPatternList(void);
//--- Display patterns on the chart
   void              DrawPatterns(const bool redraw=false);
   
//--- Protected parametric constructor
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);
  };

Todas as variáveis e métodos estão assinados. Sua finalidade deve ser clara a partir de suas descrições.

A classe tem apenas um construtor paramétrico protegido, já que essa classe não é usada separadamente. As classes herdadas dela terão um construtor público, onde os parâmetros correspondentes são passados para o construtor protegido da classe pai, de acordo com o tipo de padrão para o qual o objeto de controle é criado.

O construtor paramétrico protegido recebe os parâmetros do padrão criado e os ponteiros para listas externas: lista de séries temporais e a lista de todos os padrões. A lista de inicialização nos permite especificar os critérios de busca padrão do padrão e os flags para usar o padrão e desenhar rótulos de padrão. Todos os parâmetros passados são então ajustados e definidos no corpo do construtor, os ponteiros passados para o método são atribuídos aos ponteiros para as listas da classe e um código de símbolo é criado:

//+------------------------------------------------------------------+
//| CPatternControl::Protected parametric constructor                |
//+------------------------------------------------------------------+
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);
  }

Os ponteiros para listas passadas para o construtor são necessários para indicar com quais listas externas, criadas externamente, esta classe trabalha. Ao atribuir ponteiros para listas externas aos ponteiros para listas da classe, determinamos precisamente que a classe trabalha exatamente com aquelas listas que foram criadas externamente, e não com quaisquer outras instâncias da classe CArrayObj.


O método que compara os objetos CPatternControl entre si:

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

Aqui, cada propriedade do objeto atual é comparada com a propriedade correspondente do objeto comparado. 0 é retornado apenas se cada uma das propriedades comparadas for igual.


O método que busca padrões e adiciona os encontrados à lista de todos os padrões:

//+------------------------------------------------------------------+
//| CPatternControl::Search for patterns and add                     |
//| found ones to the list of all patterns                           |
//+------------------------------------------------------------------+
int CPatternControl::CreateAndRefreshPatternList(void)
  {
//--- If not used, leave
   if(!this.m_used)
      return 0;
//--- Reset the timeseries event flag and clear the list of all timeseries pattern events
   this.m_is_event=false;
   this.m_list_events.Clear();
//--- Get the opening date of the last (current) bar
   datetime time_open=0;
   if(!::SeriesInfoInteger(this.Symbol(),this.Timeframe(),SERIES_LASTBAR_DATE,time_open))
      return 0;
//--- Get a list of all bars in the timeseries except the current one
   CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,time_open,LESS);
   if(list==NULL || list.Total()==0)
      return 0;
//--- Sort the resulting list by bar opening time
   list.Sort(SORT_BY_BAR_TIME);
//--- In a loop from the latest bar,
   for(int i=list.Total()-1;i>=0;i--)
     {
      //--- get the next bar object from the list
      CBar *bar=list.At(i);
      if(bar==NULL)
         continue;
      //--- look for a pattern relative to the received bar
      ENUM_PATTERN_DIRECTION direction=this.FindPattern(bar.Time(),1);
      //--- If there is no pattern, go to the next bar
      if(direction==WRONG_VALUE)
         continue;
         
      //--- Pattern found on the current bar of the loop
      //--- unique pattern code = candle opening time + type + status + pattern direction + timeframe + timeseries symbol
      ulong code=this.GetPatternCode(direction,bar.Time());
      //--- Set the pattern code to the sample
      this.m_pattern_instance.SetProperty(PATTERN_PROP_CODE,code);
      //--- Sort the list of all patterns by the unique pattern code
      this.m_list_all_patterns.Sort(SORT_BY_PATTERN_CODE);
      //--- search for a pattern in the list using a unique code
      int index=this.m_list_all_patterns.Search(&this.m_pattern_instance);
      //--- If there is no pattern equal to the sample in the list of all patterns
      if(index==WRONG_VALUE)
        {
         //--- Create the pattern object
         CPattern *pattern=this.CreatePattern(direction,this.m_list_all_patterns.Total(),bar);
         if(pattern==NULL)
            continue;
         //--- Sort the list of all patterns by time and insert the pattern into the list by its time
         this.m_list_all_patterns.Sort(SORT_BY_PATTERN_TIME);
         if(!this.m_list_all_patterns.InsertSort(pattern))
           {
            delete pattern;
            continue;
           }
         //--- If the drawing flag is set, draw the pattern label on the chart
         if(this.m_drawing)
            pattern.Draw();
        }
     }
//--- Sort the list of all patterns by time and return the total number of patterns in the list
   this.m_list_all_patterns.Sort(SORT_BY_PATTERN_TIME);
   return m_list_all_patterns.Total();
  }

A lógica do método foi descrita em detalhes nos comentários do código. Em resumo: usando a lista de todos os bares, exceto o atual (os padrões devem ser buscados apenas em bares concluídos), procuramos um padrão usando o método virtual FindPattern(), cuja implementação deve ser feita em classes herdadas, pois cada padrão é buscado de uma forma diferente. Se o padrão for encontrado, um novo objeto padrão é criado, novamente usando o método virtual CreatePattern(), implementado em classes herdadas pelo mesmo motivo. O objeto recém-criado é colocado na lista de todos os padrões da biblioteca.


O método que exibe rótulos de padrão em um gráfico:

//+------------------------------------------------------------------+
//| Display pattern labels on the chart                              |
//+------------------------------------------------------------------+
void CPatternControl::DrawPatterns(const bool redraw=false)
  {
//--- Get a list of patterns controlled by the control object
   CArrayObj *list=this.GetListPatterns();
   if(list==NULL || list.Total()==0)
      return;
//--- Sort the obtained list by pattern time
   list.Sort(SORT_BY_PATTERN_TIME);
//--- In a loop from the latest pattern,
   for(int i=list.Total()-1;i>=0;i--)
     {
      //--- get the next pattern object
      CPattern *obj=list.At(i);
      if(obj==NULL)
         continue;
      //--- Display the pattern label on the chart
      obj.Draw(false);
     }
//--- At the end of the cycle, redraw the chart if the flag is set
   if(redraw)
      ::ChartRedraw(this.m_chart_id);
  }

A lógica do método está comentada no código. Em resumo, obtemos uma lista de apenas aqueles padrões que são controlados por este objeto de controle. Em um loop, usando a lista resultante, obtemos cada próximo objeto padrão e exibimos seu rótulo gráfico no gráfico. O gráfico é redesenhado no final do loop para evitar que o gráfico seja redesenhado em cada iteração do loop.

A classe básica do objeto de controle de padrão está pronta. Agora precisamos escrever classes herdadas, nas quais os tipos de padrões e seus parâmetros já estão precisamente especificados.


Como hoje estamos fazendo apenas um padrão - Pin Bar, criaremos um objeto para controlá-lo Vamos continuar escrevendo o código no mesmo arquivo:

//+------------------------------------------------------------------+
//| Pin Bar pattern control class                                    |
//+------------------------------------------------------------------+
class CPatternControlPinBar : public CPatternControl
  {
protected:
//--- (1) Search for a pattern, return direction (or -1),
//--- (2) create a pattern with a specified direction,
//--- (3) create and return a unique pattern code
//--- (4) return the list of patterns managed by the object
   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
                       {
                        //--- unique pattern code = candle opening time + type + status + pattern direction + timeframe + timeseries symbol
                        return(time+PATTERN_TYPE_PIN_BAR+PATTERN_STATUS_PA+direction+this.Timeframe()+this.m_symbol_code);
                       }
   virtual CArrayObj*GetListPatterns(void);
//--- Create object ID based on pattern search criteria
   virtual ulong     CreateObjectID(void);

public:
//--- Parametric constructor
                     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();
                       }
  };

Na lista de inicialização do construtor da classe, passe o status do padrão Price Action e o tipo de padrão Pin Bar para a classe pai. Além disso, os parâmetros do construtor passam ponteiros para listas externas e critérios de busca de padrão.


O método que cria um ID de objeto com base nos critérios de busca do padrão:

//+------------------------------------------------------------------+
//| Create object ID based on pattern search criteria                |
//+------------------------------------------------------------------+
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);
  }

Três critérios (percentagens do corpo da vela, maior e menor sombras em relação ao tamanho da vela inteira) são especificados em números reais (percentagens) e não podem exceder 100. Portanto, os convertemos em valores inteiros multiplicando por 100 e, em seguida, criamos um ID ulong usando o método UshortToLong() da biblioteca padrão de objetos estendidos, preenchendo os bits especificados do número long com valores ushort:

//+------------------------------------------------------------------+
//| Pack a 'ushort' number to a passed 'long' number                 |
//+------------------------------------------------------------------+
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));
  }
//+------------------------------------------------------------------+
//| Convert a 'ushort' value to a specified 'long' number byte       |
//+------------------------------------------------------------------+
long CBaseObjExt::UshortToByte(const ushort value,const uchar to_byte) const
  {
   return(long)value<<(16*to_byte);
  }


Um método virtual que cria um padrão com a direção especificada:

//+--------------------------------------------------------------------+
//| CPatternControlPinBar::Create a pattern with a specified direction |
//+--------------------------------------------------------------------+
CPattern *CPatternControlPinBar::CreatePattern(const ENUM_PATTERN_DIRECTION direction,const uint id,CBar *bar)
  {
//--- If invalid indicator is passed to the bar object, return NULL
   if(bar==NULL)
      return NULL;
//--- Fill the MqlRates structure with bar data
   MqlRates rates={0};
   rates.time=bar.Time();
   rates.open=bar.Open();
   rates.high=bar.High();
   rates.low=bar.Low();
   rates.close=bar.Close();
//--- Create a new Pin Bar pattern
   CPatternPinBar *obj=new CPatternPinBar(id,this.Symbol(),this.Timeframe(),rates,direction);
   if(obj==NULL)
      return NULL;
//--- set the proportions of the candle the pattern was found on to the properties of the created pattern object
   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());
//--- set the search criteria of the candle the pattern was found on to the properties of the created pattern object
   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());
//--- Set the control object ID to the pattern object
   obj.SetProperty(PATTERN_PROP_CTRL_OBJ_ID,this.ObjectID());
//--- Return the pointer to a created object
   return obj;
  }

A lógica do método é descrita nos comentários do código. Podemos ver que o ponteiro para o objeto de controle de padrão também está registrado no objeto padrão criado. Assim, tendo recebido o ponteiro para um objeto padrão em algum lugar do programa, podemos usá-lo para acessar o objeto de controle que criou este padrão e, em seguida, manipulá-lo. Em outras palavras, temos um acesso bidirecional aqui - do objeto de controle para o padrão e vice-versa.


O método que busca o padrão:

//+------------------------------------------------------------------+
//| CPatternControlPinBar::Search for the pattern                    |
//+------------------------------------------------------------------+
ENUM_PATTERN_DIRECTION CPatternControlPinBar::FindPattern(const datetime series_bar_time,const uint min_body_size) const
  {
//--- Pointers to objects
   CBar *bar=NULL;
   CPatternPinBar *pin_bar=NULL;
//--- Get data for one bar by time
   CArrayObj *list=CSelect::ByBarProperty(this.m_list_series,BAR_PROP_TIME,series_bar_time,EQUAL);
//--- If the list is empty, return -1
   if(list==NULL || list.Total()==0)
      return WRONG_VALUE;
//--- he size of the candle body should be less than or equal to RatioBodyToCandleSizeValue() (default 30%) of the entire candle size,
//--- in this case, the body size should not be less than 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);
//--- If the list is empty - there are no patterns, return -1
   if(list==NULL || list.Total()==0)
      return WRONG_VALUE;
      
//--- Define the bullish pattern
//--- The lower shadow should be equal to or greater than RatioLargerShadowToCandleSizeValue() (default 60%) of the entire candle size
   CArrayObj *list_bullish=CSelect::ByBarProperty(list,BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.RatioLargerShadowToCandleSizeValue(),EQUAL_OR_MORE);
//--- The upper shadow should be less than or equal to RatioSmallerShadowToCandleSizeValue() (default 30%) of the entire candle size
   list_bullish=CSelect::ByBarProperty(list_bullish,BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.RatioSmallerShadowToCandleSizeValue(),EQUAL_OR_LESS);
//--- If a pattern is found on the bar
   if(list_bullish!=NULL && list_bullish.Total()>0)
      return PATTERN_DIRECTION_BULLISH;
//--- Define the bearish pattern
//--- The upper shadow should be equal to or greater than RatioLargerShadowToCandleSizeValue() (default 60%) of the entire candle size
   CArrayObj *list_bearish=CSelect::ByBarProperty(list,BAR_PROP_RATIO_UPPER_SHADOW_TO_CANDLE_SIZE,this.RatioLargerShadowToCandleSizeValue(),EQUAL_OR_MORE);
//--- The lower shadow should be less than or equal to RatioSmallerShadowToCandleSizeValue() (default 30%) of the entire candle size
   list_bearish=CSelect::ByBarProperty(list_bearish,BAR_PROP_RATIO_LOWER_SHADOW_TO_CANDLE_SIZE,this.RatioSmallerShadowToCandleSizeValue(),EQUAL_OR_LESS);
//--- If a pattern is found on the bar
   if(list_bearish!=NULL && list_bearish.Total()>0)
      return PATTERN_DIRECTION_BEARISH;
//--- No patterns found - return -1
   return WRONG_VALUE;
  }

A lógica do método está comentada no código. Em resumo, um Pin Bar é uma formação de Price Action de uma barra, então precisamos de apenas uma barra de série temporal. Obtemos uma barra com base no tempo da barra passada para o método. Em seguida, descobrimos as proporções do corpo da vela em relação ao seu tamanho total. Se o corpo for maior que o tamanho permitido, definitivamente não há padrão, retornamos -1. Se o critério para o tamanho do corpo da vela for atendido, então, da mesma forma, primeiro verificamos as sombras da vela para valores de tamanho aceitáveis para um padrão de alta e, depois, se não houver padrão de alta, verificamos as sombras da vela para valores de tamanho de padrão de baixa. Se um padrão for encontrado, retornamos sua direção. Caso contrário, retornamos -1.


O método que retorna uma lista de padrões gerenciados pelo objeto:

//+------------------------------------------------------------------+
//| Returns the list of patterns managed by the object               |
//+------------------------------------------------------------------+
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);
  }

Na lista de todos os padrões, procuramos apenas padrões com o período do gráfico definido para este objeto.
Na lista resultante, procuramos padrões com o símbolo definido para este objeto.
Extraímos apenas padrões Pin Bar da lista resultante.
Retornamos o ponteiro para a lista de apenas aqueles padrões cujo ID do objeto de controle está definido.

Se a lista não pôde ser obtida em alguma etapa, então NULL é retornado.

O objeto de controle do padrão Pin Bar está pronto. Nos próximos artigos, adicionarei gradualmente novos padrões e novos objetos para gerenciá-los.


Agora precisamos escrever a classe para gerenciar os objetos de controle de padrão criados acima. Vamos continuar escrevendo no mesmo arquivo.

Em sua essência, a classe é uma lista de objetos de controle de padrão criados e um conjunto de métodos que fornecem acesso a eles. Todos os métodos são do mesmo tipo e serão implementados diretamente no corpo da classe.

A seção privada contém uma lista de objetos de controle de padrão e listas de séries temporais e todos os padrões. A seção pública contém métodos que retornam um timeframe, um símbolo e um ponteiro para o objeto:

//+------------------------------------------------------------------+
//| Pattern control class                                            |
//+------------------------------------------------------------------+
class CPatternsControl : public CBaseObjExt
  {
private:
   CArrayObj         m_list_controls;                                   // List of pattern management controllers
   CArrayObj        *m_list_series;                                     // Pointer to the timeseries list
   CArrayObj        *m_list_all_patterns;                               // Pointer to the list of all patterns
//--- Timeseries data
   ENUM_TIMEFRAMES   m_timeframe;                                       // Timeseries timeframe
   string            m_symbol;                                          // Timeseries symbol
   
public:
//--- Return (1) timeframe, (2) timeseries symbol, (3) itself
   ENUM_TIMEFRAMES   Timeframe(void)                                       const { return this.m_timeframe; }
   string            Symbol(void)                                          const { return this.m_symbol;    }
   CPatternsControl *GetObject(void)                                             { return &this;            }
   
protected:


A seção protegida contém métodos que retornam objetos de controle de padrão. Apenas o método que retorna o objeto de controle do padrão Pin Bar com os parâmetros especificados está completamente pronto:

//--- Return the Pin Bar pattern control object
   CPatternControl  *GetObjControlPatternPinBar(const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                                const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                                const double ratio_smaller_shadow=30)  // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        //--- In a loop through the list of control objects,
                        int total=this.m_list_controls.Total();
                        for(int i=0;i<total;i++)
                          {
                           //--- get the next object
                           CPatternControl *obj=this.m_list_controls.At(i);
                           //--- if this is not a Pin Bar pattern control object, go to the next one
                           if(obj==NULL || obj.TypePattern()!=PATTERN_TYPE_PIN_BAR)
                              continue;
                           //--- Check search conditions and return the result
                           if(ratio_body==obj.RatioBodyToCandleSizeValue() && ratio_larger_shadow==obj.RatioLargerShadowToCandleSizeValue() && ratio_smaller_shadow==obj.RatioSmallerShadowToCandleSizeValue())
                              return obj;
                          }
                        //--- Not found - return NULL
                        return NULL;
                       }


Os métodos restantes são criados na forma de esboços. Vamos ver a lista completa de métodos:

protected:
//--- Return the Harami pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Harami Cross pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Tweezer pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Piercing Line pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Cloud Cover pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Three White Soldiers pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Three Black Crows pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Shooting Star pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Hammer pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Inverted Hammer pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Hanging Man pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Doji pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Dragonfly Doji pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Gravestone Doji pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Morning Star pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Morning Doji Star pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Evening Star pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Evening Doji Star pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Three Stars pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Abandoned Body pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }

//--- Price Action
//--- Return the Pivot Point Reversal pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Outside Bar pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Inside Bar pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }
//--- Return the Pin Bar pattern control object
   CPatternControl  *GetObjControlPatternPinBar(const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                                const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                                const double ratio_smaller_shadow=30)  // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        //--- In a loop through the list of control objects,
                        int total=this.m_list_controls.Total();
                        for(int i=0;i<total;i++)
                          {
                           //--- get the next object
                           CPatternControl *obj=this.m_list_controls.At(i);
                           //--- if this is not a Pin Bar pattern control object, go to the next one
                           if(obj==NULL || obj.TypePattern()!=PATTERN_TYPE_PIN_BAR)
                              continue;
                           //--- Check search conditions and return the result
                           if(ratio_body==obj.RatioBodyToCandleSizeValue() && ratio_larger_shadow==obj.RatioLargerShadowToCandleSizeValue() && ratio_smaller_shadow==obj.RatioSmallerShadowToCandleSizeValue())
                              return obj;
                          }
                        //--- Not found - return NULL
                        return NULL;
                       }
//--- Return the Rails pattern control object
   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;
                           //--- Check search conditions and return the result
                           //if(condition)
                           //   return obj;
                          }
                        return NULL;
                       }

public:

Eu irei adicionar as entradas necessárias para criar cada padrão específico em cada um dos métodos ao criar novos padrões.


A seção pública da classe conterá uma lista de métodos que definem flags para o uso de padrões e criam objetos de controle. Para cada padrão, os parâmetros do método indicarão as propriedades inerentes a ele. O método para definir a flag do padrão Pin Bar:

//--- Set the flag for using the Pin Bar pattern and create a control object if it does not already exist
   void              SetUsedPatternPinBar(const bool flag,                       // Price Action Pin Bar usage flag
                                          const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                          const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                          const double ratio_smaller_shadow=30)  // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        //--- Get the pointer to the Pin Bar pattern control object with the specified parameters
                        CPatternControlPinBar *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        //--- If the pointer is received (the object exists), set the use flag 
                        if(obj!=NULL)
                           obj.SetUsed(flag);
                        //--- f there is no object and the flag is passed as 'true'
                        else if(flag)
                          {
                           //--- Create a new Pin Bar pattern control object with the specified parameters
                           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;
                           //--- Add pointer to the created object to the list
                           if(!this.m_list_controls.Add(obj))
                             {
                              delete obj;
                              return;
                             }
                           //--- Set the usage flag and pattern parameters to the control object
                           obj.SetUsed(flag);
                           obj.SetRatioBodyToCandleSizeValue(ratio_body);
                           obj.SetRatioLargerShadowToCandleSizeValue(ratio_larger_shadow);
                           obj.SetRatioSmallerShadowToCandleSizeValue(ratio_smaller_shadow);
                           obj.CreateAndRefreshPatternList();
                          }
                       }


Os métodos restantes estão escritos apenas como modelos - eu os complementarei à medida que novos padrões forem criados:

public:
//+------------------------------------------------------------------+
//| Methods for setting the pattern use flag                         |
//+------------------------------------------------------------------+
//--- Set the flag for using the Harami pattern and create a control object if it does not already exist
   void              SetUsedPatternHarami(const bool flag)
                       {
                        
                       }
//--- Set the flag for using the Harami Cross pattern and create a control object if it does not already exist
   void              SetUsedPatternHaramiCross(const bool flag)
                       {
                        
                       }
//--- Set the flag for using the Tweezer pattern and create a control object if it does not already exist
   void              SetUsedPatternTweezer(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Piercing Line pattern and create a control object if it does not already exist
   void              SetUsedPatternPiercingLine(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Cloud Cover pattern and create a control object if it does not already exist
   void              SetUsedPatternDarkCloudCover(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Three White Soldiers pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeWhiteSoldiers(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Three Black Crows pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeBlackCrows(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Shooting Star pattern and create a control object if it does not already exist
   void              SetUsedPatternShootingStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Hammer pattern and create a control object if it does not already exist
   void              SetUsedPatternHammer(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Inverted Hammer pattern and create a control object if it does not already exist
   void              SetUsedPatternInvertedHammer(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Hanging Man pattern and create a control object if it does not already exist
   void              SetUsedPatternHangingMan(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Doji pattern and create a control object if it does not already exist
   void              SetUsedPatternDoji(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Dragonfly Doji pattern and create a control object if it does not already exist
   void              SetUsedPatternDragonflyDoji(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Doji Gravestone pattern and create a control object if it does not already exist
   void              SetUsedPatternGravestoneDoji(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Morning Star pattern and create a control object if it does not already exist
   void              SetUsedPatternMorningStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Morning Doji Star pattern and create a control object if it does not already exist
   void              SetUsedPatternMorningDojiStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Evening Star pattern and create a control object if it does not already exist
   void              SetUsedPatternEveningStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Evening Doji Star pattern and create a control object if it does not already exist
   void              SetUsedPatternEveningDojiStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Three Stars pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeStars(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Abandoned Baby pattern and create a control object if it does not already exist
   void              SetUsedPatternAbandonedBaby(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pivot Point Reversal pattern and create a control object if it does not already exist
//--- Price Action
   void              SetUsedPatternPivotPointReversal(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pattern Outside and create a control object if it does not already exist
   void              SetUsedPatternOutsideBar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pattern Inside and create a control object if it does not already exist
   void              SetUsedPatternInsideBar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pin Bar pattern and create a control object if it does not already exist
   void              SetUsedPatternPinBar(const bool flag,                       // Price Action Pin Bar usage flag
                                          const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                          const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                          const double ratio_smaller_shadow=30)  // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        //--- Get the pointer to the Pin Bar pattern control object with the specified parameters
                        CPatternControlPinBar *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        //--- If the pointer is received (the object exists), set the use flag 
                        if(obj!=NULL)
                           obj.SetUsed(flag);
                        //--- f there is no object and the flag is passed as 'true'
                        else if(flag)
                          {
                           //--- Create a new Pin Bar pattern control object with the specified parameters
                           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;
                           //--- Add pointer to the created object to the list
                           if(!this.m_list_controls.Add(obj))
                             {
                              delete obj;
                              return;
                             }
                           //--- Set the usage flag and pattern parameters to the control object
                           obj.SetUsed(flag);
                           obj.SetRatioBodyToCandleSizeValue(ratio_body);
                           obj.SetRatioLargerShadowToCandleSizeValue(ratio_larger_shadow);
                           obj.SetRatioSmallerShadowToCandleSizeValue(ratio_smaller_shadow);
                           obj.CreateAndRefreshPatternList();
                          }
                       }
//--- Set the flag for using the Rails pattern and create a control object if it does not already exist
   void              SetUsedPatternRails(const bool flag)
                       {
                       
                       }


Os métodos para retornar a flag de uso do padrão. Aqui, apenas o método para retornar a flag de uso do padrão Pin Bar também está pronto:

//--- Return the flag of using the Pin Bar pattern
   bool              IsUsedPatternPinBar(const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                         const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                         const double ratio_smaller_shadow=30)   // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        //--- Get the pattern control object based on its parameters
                        CPatternControl *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        //--- Return the pattern use flag, or 'false' if the object is not found 
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }


Os métodos restantes são feitos na forma de esboços, nos quais as entradas dos padrões não estão especificadas:

//+------------------------------------------------------------------+
//| Methods for returning the pattern usage flag                     |
//+------------------------------------------------------------------+
//--- Candle formations
//--- Return the flag of using the Harami pattern
   bool              IsUsedPatternHarami(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHarami();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Harami Cross pattern
   bool              IsUsedPatternHaramiCross(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHaramiCross();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Tweezer pattern
   bool              IsUsedPatternTweezer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternTweezer();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Piercing Line pattern
   bool              IsUsedPatternPiercingLine(void)
                       {
                        CPatternControl *obj=GetObjControlPatternPiercingLine();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Cloud Cover pattern
   bool              IsUsedPatternDarkCloudCover(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDarkCloudCover();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Three White Soldiers pattern
   bool              IsUsedPatternThreeWhiteSoldiers(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeWhiteSoldiers();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Three Black Crows pattern
   bool              IsUsedPatternThreeBlackCrows(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeBlackCrows();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Shooting Star pattern
   bool              IsUsedPatternShootingStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternShootingStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Hammer pattern
   bool              IsUsedPatternHammer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHammer();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Inverted Hammer pattern
   bool              IsUsedPatternInvertedHammer(void)
                       {
                        CPatternControl *obj=GetObjControlPatternInvertedHammer();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Hanging Man pattern
   bool              IsUsedPatternHangingMan(void)
                       {
                        CPatternControl *obj=GetObjControlPatternHangingMan();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Doji pattern
   bool              IsUsedPatternDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDoji();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Dragonfly Doji pattern
   bool              IsUsedPatternDragonflyDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternDragonflyDoji();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Gravestone Doji pattern
   bool              IsUsedPatternGravestoneDoji(void)
                       {
                        CPatternControl *obj=GetObjControlPatternGravestoneDoji();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Morning Star pattern
   bool              IsUsedPatternMorningStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Morning Doji Star pattern
   bool              IsUsedPatternMorningDojiStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningDojiStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Evening Star pattern
   bool              IsUsedPatternEveningStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Evening Doji Star pattern
   bool              IsUsedPatternEveningDojiStar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningDojiStar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Three Stars pattern
   bool              IsUsedPatternThreeStars(void)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeStars();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Abandoned Baby pattern
   bool              IsUsedPatternAbandonedBaby(void)
                       {
                        CPatternControl *obj=GetObjControlPatternAbandonedBaby();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Price Action
//--- Return the flag of using the Pivot Point Reversal pattern
   bool              IsUsedPatternPivotPointReversal(void)
                       {
                        CPatternControl *obj=GetObjControlPatternPivotPointReversal();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Pattern Outside
   bool              IsUsedPatternOutsideBar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternOutsideBar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Inside Bar pattern
   bool              IsUsedPatternInsideBar(void)
                       {
                        CPatternControl *obj=GetObjControlPatternInsideBar();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Pin Bar pattern
   bool              IsUsedPatternPinBar(const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                         const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                         const double ratio_smaller_shadow=30)   // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        //--- Get the pattern control object based on its parameters
                        CPatternControl *obj=this.GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        //--- Return the pattern use flag, or 'false' if the object is not found 
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }
//--- Return the flag of using the Rails pattern
   bool              IsUsedPatternRails(void)
                       {
                        CPatternControl *obj=GetObjControlPatternRails();
                        return(obj!=NULL ? obj.IsUsed() : false);
                       }


O método que busca e atualiza todos os padrões ativos:

//+------------------------------------------------------------------+
//| Pattern data update methods                                      |
//+------------------------------------------------------------------+
//--- Search and update all active patterns
   void              RefreshAll(void)
                       {
                        //--- In a loop through the list of pattern control objects,
                        int total=this.m_list_controls.Total();
                        for(int i=0;i<total;i++)
                          {
                           //--- get the next control object
                           CPatternControl *ctrl=this.m_list_controls.At(i);
                           if(ctrl==NULL)
                              continue;
                           //--- If the object is received, search and create a new pattern 
                           ctrl.CreateAndRefreshPatternList();
                          }
                        //--- At the end of the loop, display the pattern icons on the chart 
                        this.DrawPatternPinBar();
                       }


O método que busca e atualiza todos os padrões ativos: Apenas o método que desenha os rótulos do padrão Pin Bar está completamente pronto. Os métodos restantes são implementados na forma de modelos sem entradas de padrões:

//+------------------------------------------------------------------+
//| Methods for drawing patterns on a chart                          |
//+------------------------------------------------------------------+
//--- Set Harami pattern labels on the chart
   void              DrawPatternHarami(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHarami();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Harami Cross pattern labels on the chart
   void              DrawPatternHaramiCross(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHaramiCross();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Tweezer pattern labels on the chart
   void              DrawPatternTweezer(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternTweezer();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Piercing Line pattern labels on the chart
   void              DrawPatternPiercingLine(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternPiercingLine();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Cloud Cover pattern labels on the chart
   void              DrawPatternDarkCloudCover(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternDarkCloudCover();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Three White Soldiers pattern labels on the chart
   void              DrawPatternThreeWhiteSoldiers(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeWhiteSoldiers();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Three Black Crows pattern labels on the chart
   void              DrawPatternThreeBlackCrows(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeBlackCrows();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Shooting Star pattern labels on the chart
   void              DrawPatternShootingStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternShootingStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Hammer pattern labels on the chart
   void              DrawPatternHammer(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHammer();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Inverted Hammer pattern labels on the chart
   void              DrawPatternInvertedHammer(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternInvertedHammer();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Hanging Man pattern labels on the chart
   void              DrawPatternHangingMan(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternHangingMan();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Doji pattern labels on the chart
   void              DrawPatternDoji(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternDoji();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Dragonfly Doji pattern labels on the chart
   void              DrawPatternDragonflyDoji(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternDragonflyDoji();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Engraved Doji pattern labels on the chart
   void              DrawPatternGravestoneDoji(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternGravestoneDoji();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Morning Star pattern labels on the chart
   void              DrawPatternMorningStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Morning Doji Star pattern labels on the chart
   void              DrawPatternMorningDojiStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternMorningDojiStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Evening Star pattern labels on the chart
   void              DrawPatternEveningStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Morning Doji Star pattern labels on the chart
   void              DrawPatternEveningDojiStar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternEveningDojiStar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Three Stars pattern labels on the chart
   void              DrawPatternThreeStars(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternThreeStars();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Abandoned Baby pattern labels on the chart
   void              DrawPatternAbandonedBaby(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternAbandonedBaby();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Pivot Point Reversal pattern labels on the chart
//--- Price Action
   void              DrawPatternPivotPointReversal(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternPivotPointReversal();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Outside Bar pattern labels on the chart
   void              DrawPatternOutsideBar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternOutsideBar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Inside Bar pattern labels on the chart
   void              DrawPatternInsideBar(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternInsideBar();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
//--- Set Pin Bar pattern labels on the chart
   void              DrawPatternPinBar(const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                       const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                       const double ratio_smaller_shadow=30,  // Percentage ratio of the size of the smaller shadow to the size of the candle
                                       const bool redraw=false)               // Chart redraw flag
                       {
                        //--- Get the pattern control object with the specified parameters 
                        CPatternControl *obj=GetObjControlPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                        if(obj==NULL)
                           return;
                        //--- Draw pattern labels on the chart
                        obj.DrawPatterns(redraw);
                       }
//--- Set Rails pattern labels on the chart
   void              DrawPatternRails(const bool redraw=false)
                       {
                        CPatternControl *obj=GetObjControlPatternRails();
                        if(obj==NULL)
                           return;
                        obj.DrawPatterns(redraw);
                       }
                       
//--- Constructor
                     CPatternsControl(const string symbol,const ENUM_TIMEFRAMES timeframe,CArrayObj *list_timeseries,CArrayObj *list_all_patterns);
  };


No construtor da classe, defina o tipo de objeto da biblioteca, ajuste e defina o símbolo e o timeframe do gráfico e defina os ponteiros para as listas externas, passadas nos parâmetros do construtor, para os ponteiros das listas de séries temporais e todos os padrões:

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

As classes de controle de padrões estão prontas.


Agora precisamos encaixar as classes de objetos de controle de padrões preparadas nas classes de séries temporais e organizar o acesso a elas.

Vamos fazer algumas alterações na classe de séries temporais no mesmo arquivo \MQL5\Include\DoEasy\Objects\SeriesSeriesDE.mqh.

Na seção privada, declare o ponteiro para o objeto de controle de padrão. Na seção protegida, declare o ponteiro para a lista de todos os padrões de todas as séries temporais de símbolos, enquanto na seção pública, declare o método que retorna o ponteiro para o objeto de controle de padrão:

//+------------------------------------------------------------------+
//| Timeseries class                                                 |
//+------------------------------------------------------------------+
class CSeriesDE : public CBaseObj
  {
private:
   ENUM_TIMEFRAMES   m_timeframe;                                       // Timeframe
   string            m_symbol;                                          // Symbol
   string            m_period_description;                              // Timeframe string description
   datetime          m_firstdate;                                       // The very first date by a period symbol at the moment
   datetime          m_lastbar_date;                                    // Time of opening the last bar by period symbol
   uint              m_amount;                                          // Amount of applied timeseries data
   uint              m_required;                                        // Required amount of applied timeseries data
   uint              m_bars;                                            // Number of bars in history by symbol and timeframe
   bool              m_sync;                                            // Synchronized data flag
   CArrayObj         m_list_series;                                     // Timeseries list
   CNewBarObj        m_new_bar_obj;                                     // "New bar" object
   CPatternsControl *m_patterns_control;                                // Pointer to pattern control object
//--- Set the very first date by a period symbol at the moment and the new time of opening the last bar by a period symbol
   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;                               // Pointer to the list of all patterns of all timeseries of all symbols
public:
//--- Return (1) itself, (2) timeseries list, (3) timeseries "New bar" object and (4) pattern management object
   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;}


A classe possui apenas um destrutor criado por padrão. Declare o destrutor da classe. Além disso, adicione os ponteiros para a lista externa de todos os padrões aos construtores da classe. Escreva os métodos para manipular o objeto de controle de padrão repetindo métodos semelhantes de objetos. Aqui, apenas os métodos correspondentes do objeto de controle de padrão serão chamados:

//--- Constructors
                     CSeriesDE(CArrayObj *list);
                     CSeriesDE(CArrayObj *list,const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0);
                    ~CSeriesDE(void);
//+------------------------------------------------------------------+
//| Working with patterns                                            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for setting the pattern use and data update flag         |
//+------------------------------------------------------------------+
//--- Set the flag for using the Harami pattern and create a control object if it does not already exist
   void              SetUsedPatternHarami(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Harami Cross pattern and create a control object if it does not already exist
   void              SetUsedPatternHaramiCross(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Tweezer pattern and create a control object if it does not already exist
   void              SetUsedPatternTweezer(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Piercing Line pattern and create a control object if it does not already exist
   void              SetUsedPatternPiercingLine(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Cloud Cover pattern and create a control object if it does not already exist
   void              SetUsedPatternDarkCloudCover(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Three White Soldiers pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeWhiteSoldiers(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Three Black Crows pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeBlackCrows(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Shooting Star pattern and create a control object if it does not already exist
   void              SetUsedPatternShootingStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Hammer pattern and create a control object if it does not already exist
   void              SetUsedPatternHammer(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Inverted Hammer pattern and create a control object if it does not already exist
   void              SetUsedPatternInvertedHammer(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Hanging Man pattern and create a control object if it does not already exist
   void              SetUsedPatternHangingMan(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Doji pattern and create a control object if it does not already exist
   void              SetUsedPatternDoji(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Dragonfly Doji pattern and create a control object if it does not already exist
   void              SetUsedPatternDragonflyDoji(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Doji Gravestone pattern and create a control object if it does not already exist
   void              SetUsedPatternGravestoneDoji(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Morning Star pattern and create a control object if it does not already exist
   void              SetUsedPatternMorningStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Morning Doji Star pattern and create a control object if it does not already exist
   void              SetUsedPatternMorningDojiStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Evening Star pattern and create a control object if it does not already exist
   void              SetUsedPatternEveningStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Evening Doji Star pattern and create a control object if it does not already exist
   void              SetUsedPatternEveningDojiStar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Three Stars pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeStars(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Abandoned Baby pattern and create a control object if it does not already exist
   void              SetUsedPatternAbandonedBaby(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pivot Point Reversal pattern and create a control object if it does not already exist
//--- Price Action
   void              SetUsedPatternPivotPointReversal(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pattern Outside and create a control object if it does not already exist
   void              SetUsedPatternOutsideBar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pattern Inside and create a control object if it does not already exist
   void              SetUsedPatternInsideBar(const bool flag)
                       {
                       
                       }
//--- Set the flag for using the Pin Bar pattern and create a control object if it does not already exist
   void              SetUsedPatternPinBar(const bool flag,                       // Price Action Pin Bar usage flag
                                          const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                          const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                          const double ratio_smaller_shadow=30)  // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        if(this.m_patterns_control==NULL)
                           return;
                        this.m_patterns_control.SetUsedPatternPinBar(flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                       }
//--- Set the flag for using the Rails pattern and create a control object if it does not already exist
   void              SetUsedPatternRails(const bool flag)
                       {
                       
                       }
//+------------------------------------------------------------------+
//| Methods for returning the pattern usage flag                     |
//+------------------------------------------------------------------+
//--- Candle formations
//--- Return the flag of using the Harami pattern
   bool              IsUsedPatternHarami(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHarami() : false);
                       }
//--- Return the flag of using the Harami Cross pattern
   bool              IsUsedPatternHaramiCross(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHaramiCross() : false);
                       }
//--- Return the flag of using the Tweezer pattern
   bool              IsUsedPatternTweezer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternTweezer() : false);
                       }
//--- Return the flag of using the Piercing Line pattern
   bool              IsUsedPatternPiercingLine(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternPiercingLine() : false);
                       }
//--- Return the flag of using the Cloud Cover pattern
   bool              IsUsedPatternDarkCloudCover(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternDarkCloudCover() : false);
                       }
//--- Return the flag of using the Three White Soldiers pattern
   bool              IsUsedPatternThreeWhiteSoldiers(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternThreeWhiteSoldiers() : false);
                       }
//--- Return the flag of using the Three Black Crows pattern
   bool              IsUsedPatternThreeBlackCrows(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternThreeBlackCrows() : false);
                       }
//--- Return the flag of using the Shooting Star pattern
   bool              IsUsedPatternShootingStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternShootingStar() : false);
                       }
//--- Return the flag of using the Hammer pattern
   bool              IsUsedPatternHammer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHammer() : false);
                       }
//--- Return the flag of using the Inverted Hammer pattern
   bool              IsUsedPatternInvertedHammer(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternInvertedHammer() : false);
                       }
//--- Return the flag of using the Hanging Man pattern
   bool              IsUsedPatternHangingMan(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternHangingMan() : false);
                       }
//--- Return the flag of using the Doji pattern
   bool              IsUsedPatternDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternDoji() : false);
                       }
//--- Return the flag of using the Dragonfly Doji pattern
   bool              IsUsedPatternDragonflyDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternDragonflyDoji() : false);
                       }
//--- Return the flag of using the Gravestone Doji pattern
   bool              IsUsedPatternGravestoneDoji(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternGravestoneDoji() : false);
                       }
//--- Return the flag of using the Morning Star pattern
   bool              IsUsedPatternMorningStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternMorningStar() : false);
                       }
//--- Return the flag of using the Morning Doji Star pattern
   bool              IsUsedPatternMorningDojiStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternMorningDojiStar() : false);
                       }
//--- Return the flag of using the Evening Star pattern
   bool              IsUsedPatternEveningStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternEveningStar() : false);
                       }
//--- Return the flag of using the Evening Doji Star pattern
   bool              IsUsedPatternEveningDojiStar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternEveningDojiStar() : false);
                       }
//--- Return the flag of using the Three Stars pattern
   bool              IsUsedPatternThreeStars(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternThreeStars() : false);
                       }
//--- Return the flag of using the Abandoned Baby pattern
   bool              IsUsedPatternAbandonedBaby(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternAbandonedBaby() : false);
                       }
//--- Price Action
//--- Return the flag of using the Pivot Point Reversal pattern
   bool              IsUsedPatternPivotPointReversal(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternPivotPointReversal() : false);
                       }
//--- Return the flag of using the Pattern Outside
   bool              IsUsedPatternOutsideBar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternOutsideBar() : false);
                       }
//--- Return the flag of using the Inside Bar pattern
   bool              IsUsedPatternInsideBar(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternInsideBar() : false);
                       }
//--- Return the flag of using the Pin Bar pattern
   bool              IsUsedPatternPinBar(const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                         const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                         const double ratio_smaller_shadow=30)   // Percentage ratio of the size of the smaller shadow to the size of the candle
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
                       }
//--- Return the flag of using the Rails pattern
   bool              IsUsedPatternRails(void)
                       {
                        return(this.m_patterns_control!=NULL ? this.m_patterns_control.IsUsedPatternRails() : false);
                       }
                       
//+------------------------------------------------------------------+
//| Methods for drawing patterns on a chart                          |
//+------------------------------------------------------------------+
//--- Set Harami pattern labels on the chart
   void              DrawPatternHarami(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHarami(redraw);
                       }
//--- Set Harami Cross pattern labels on the chart
   void              DrawPatternHaramiCross(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHaramiCross(redraw);
                       }
//--- Set Tweezer pattern labels on the chart
   void              DrawPatternTweezer(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternTweezer(redraw);
                       }
//--- Set Piercing Line pattern labels on the chart
   void              DrawPatternPiercingLine(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternPiercingLine(redraw);
                       }
//--- Set Cloud Cover pattern labels on the chart
   void              DrawPatternDarkCloudCover(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternDarkCloudCover(redraw);
                       }
//--- Set Three White Soldiers pattern labels on the chart
   void              DrawPatternThreeWhiteSoldiers(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternThreeWhiteSoldiers(redraw);
                       }
//--- Set Three Black Crows pattern labels on the chart
   void              DrawPatternThreeBlackCrows(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternThreeBlackCrows(redraw);
                       }
//--- Set Shooting Star pattern labels on the chart
   void              DrawPatternShootingStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternShootingStar(redraw);
                       }
//--- Set Hammer pattern labels on the chart
   void              DrawPatternHammer(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHammer(redraw);
                       }
//--- Set Inverted Hammer pattern labels on the chart
   void              DrawPatternInvertedHammer(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternInvertedHammer(redraw);
                       }
//--- Set Hanging Man pattern labels on the chart
   void              DrawPatternHangingMan(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternHangingMan(redraw);
                       }
//--- Set Doji pattern labels on the chart
   void              DrawPatternDoji(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternDoji(redraw);
                       }
//--- Set Dragonfly Doji pattern labels on the chart
   void              DrawPatternDragonflyDoji(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternDragonflyDoji(redraw);
                       }
//--- Set Engraved Doji pattern labels on the chart
   void              DrawPatternGravestoneDoji(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternGravestoneDoji(redraw);
                       }
//--- Set Morning Star pattern labels on the chart
   void              DrawPatternMorningStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternMorningStar(redraw);
                       }
//--- Set Morning Doji Star pattern labels on the chart
   void              DrawPatternMorningDojiStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternMorningDojiStar(redraw);
                       }
//--- Set Evening Star pattern labels on the chart
   void              DrawPatternEveningStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternEveningStar(redraw);
                       }
//--- Set Morning Doji Star pattern labels on the chart
   void              DrawPatternEveningDojiStar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternEveningDojiStar(redraw);
                       }
//--- Set Three Stars pattern labels on the chart
   void              DrawPatternThreeStars(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternThreeStars(redraw);
                       }
//--- Set Abandoned Baby pattern labels on the chart
   void              DrawPatternAbandonedBaby(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternAbandonedBaby(redraw);
                       }
//--- Set Pivot Point Reversal pattern labels on the chart
//--- Price Action
   void              DrawPatternPivotPointReversal(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternPivotPointReversal(redraw);
                       }
//--- Set Outside Bar pattern labels on the chart
   void              DrawPatternOutsideBar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternOutsideBar(redraw);
                       }
//--- Set Inside Bar pattern labels on the chart
   void              DrawPatternInsideBar(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternInsideBar(redraw);
                       }
//--- Set Pin Bar pattern labels on the chart
   void              DrawPatternPinBar(const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                       const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                       const double ratio_smaller_shadow=30,  // Percentage ratio of the size of the smaller shadow to the size of the candle
                                       const bool redraw=false)               // Chart redraw flag
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
                       }
//--- Set Rails pattern labels on the chart
   void              DrawPatternRails(const bool redraw=false)
                       {
                        if(this.m_patterns_control!=NULL)
                           this.m_patterns_control.DrawPatternRails(redraw);
                       }
  };


Nas implementações dos construtores da classe, atribua o ponteiro para a lista externa, passada ao construtor, ao ponteiro para a lista de todos os padrões e crie um novo objeto de controle de padrão:

//+------------------------------------------------------------------+
//| Constructor 1 (current symbol and period timeseries)             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Constructor 2 (specified symbol and period timeseries)           |
//+------------------------------------------------------------------+
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);
  }


No destrutor da classe, exclua o objeto de controle de padrão criado no construtor:

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSeriesDE::~CSeriesDE(void)
  {
   if(this.m_patterns_control!=NULL)
      delete this.m_patterns_control;
  }


Adicione o bloco de código para pesquisar e atualizar a lista de padrões ao método de atualização da lista e dos dados de séries temporais para procurar padrões:

//+------------------------------------------------------------------+
//| Update timeseries list and data                                  |
//+------------------------------------------------------------------+
void CSeriesDE::Refresh(SDataCalculate &data_calculate)
  {
//--- If the timeseries is not used, exit
   if(!this.m_available)
      return;
   MqlRates rates[1];
//--- Set the flag of sorting the list of bars by time
   this.m_list_series.Sort(SORT_BY_BAR_TIME);
//--- If a new bar is present on a symbol and period
   if(this.IsNewBarManual(data_calculate.rates.time))
     {
      //--- create a new bar object and add it to the end of the list
      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;
        }
      //--- Write the very first date by a period symbol at the moment and the new time of opening the last bar by a period symbol 
      this.SetServerDate();
      //--- if the timeseries exceeds the requested number of bars, remove the earliest bar
      if(this.m_list_series.Total()>(int)this.m_required)
         this.m_list_series.Delete(0);
   
      //--- Update data of all timeseries patterns
      if(this.m_patterns_control==NULL)
         return;
      this.m_patterns_control.RefreshAll();
      
      //--- save the new bar time as the previous one for the subsequent new bar check
      this.SaveNewBarTime(data_calculate.rates.time);
     }
     
//--- Get the bar index with the maximum time (zero bar) and bar object from the list by the obtained index
   int index=CSelect::FindBarMax(this.GetList(),BAR_PROP_TIME);
   CBar *bar=this.m_list_series.At(index);
   if(bar==NULL)
      return;
//--- if the work is performed in an indicator and the timeseries belongs to the current symbol and timeframe,
//--- copy price parameters (passed to the method from the outside) to the bar price structure
   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;
     }
//--- otherwise, get data to the bar price structure from the environment
   else
      copied=::CopyRates(this.m_symbol,this.m_timeframe,0,1,rates);
//--- If the prices are obtained, set the new properties from the price structure for the bar object
   if(copied==1)
      bar.SetProperties(rates[0]);
  }


Na seção protegida da classe do arquivo de séries temporais de símbolos \MQL5\Include\DoEasy\Objects\SeriesTimeSeriesDE.mqh, declare o ponteiro para a lista de todos os padrões de todas as séries temporais de todos os símbolos, enquanto na seção pública, declare o método que retorna o ponteiro para a lista:

//+------------------------------------------------------------------+
//| Symbol timeseries class                                          |
//+------------------------------------------------------------------+
class CTimeSeriesDE : public CBaseObjExt
  {
private:
   string            m_symbol;                                             // Timeseries symbol
   CNewTickObj       m_new_tick;                                           // "New tick" object
   CArrayObj         m_list_series;                                        // List of timeseries by timeframes
   datetime          m_server_firstdate;                                   // The very first date in history by a server symbol
   datetime          m_terminal_firstdate;                                 // The very first date in history by a symbol in the client terminal
//--- Return (1) the timeframe index in the list and (2) the timeframe by the list index
   int               IndexTimeframe(const ENUM_TIMEFRAMES timeframe);
   ENUM_TIMEFRAMES   TimeframeByIndex(const uchar index)             const { return TimeframeByEnumIndex(uchar(index+1));                       }
//--- Set the very first date in history by symbol on the server and in the client terminal
   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;                                  // Pointer to the list of all patterns of all timeseries of all symbols

public:
//--- Return (1) itself, full list of (2) timeseries, (3) patterns, (4) specified timeseries object and (5) timeseries object by index
   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);                               }


Assim como nos construtores da classe de séries temporais, passaremos o ponteiro para a lista externa de padrões e declararemos os métodos de manipulação de objetos de controle de padrões:

//--- Constructors
                     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);
                     
//+------------------------------------------------------------------+
//| Methods for setting the pattern use flag                         |
//+------------------------------------------------------------------+
//--- Set the flag for using the Harami pattern and create a control object if it does not already exist
   void              SetUsedPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Harami Cross pattern and create a control object if it does not already exist
   void              SetUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Tweezer pattern and create a control object if it does not already exist
   void              SetUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Piercing Line pattern and create a control object if it does not already exist
   void              SetUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Cloud Cover pattern and create a control object if it does not already exist
   void              SetUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Three White Soldiers pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Three Black Crows pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Shooting Star pattern and create a control object if it does not already exist
   void              SetUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Hammer pattern and create a control object if it does not already exist
   void              SetUsedPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Inverted Hammer pattern and create a control object if it does not already exist
   void              SetUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Hanging Man pattern and create a control object if it does not already exist
   void              SetUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Doji pattern and create a control object if it does not already exist
   void              SetUsedPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Dragonfly Doji pattern and create a control object if it does not already exist
   void              SetUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Doji Gravestone pattern and create a control object if it does not already exist
   void              SetUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Morning Star pattern and create a control object if it does not already exist
   void              SetUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Morning Doji Star pattern and create a control object if it does not already exist
   void              SetUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Evening Star pattern and create a control object if it does not already exist
   void              SetUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Evening Doji Star pattern and create a control object if it does not already exist
   void              SetUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Three Stars pattern and create a control object if it does not already exist
   void              SetUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Abandoned Baby pattern and create a control object if it does not already exist
   void              SetUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Pivot Point Reversal pattern and create a control object if it does not already exist
//--- Price Action
   void              SetUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Pattern Outside and create a control object if it does not already exist
   void              SetUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Pattern Inside and create a control object if it does not already exist
   void              SetUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Pin Bar pattern and create a control object if it does not already exist
   void              SetUsedPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                          const bool flag,                       // Price Action Pin Bar usage flag
                                          const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                          const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                          const double ratio_smaller_shadow=30); // Percentage ratio of the size of the smaller shadow to the size of the candle
//--- Set the flag for using the Rails pattern and create a control object if it does not already exist
   void              SetUsedPatternRails(const ENUM_TIMEFRAMES timeframe,const bool flag);
   
//+------------------------------------------------------------------+
//| Methods for returning the pattern usage flag                     |
//+------------------------------------------------------------------+
//--- Candle formations
//--- Return the flag of using the Harami pattern
   bool              IsUsedPatternHarami(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Harami Cross pattern
   bool              IsUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Tweezer pattern
   bool              IsUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Piercing Line pattern
   bool              IsUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Cloud Cover pattern
   bool              IsUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Three White Soldiers pattern
   bool              IsUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Three Black Crows pattern
   bool              IsUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Shooting Star pattern
   bool              IsUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Hammer pattern
   bool              IsUsedPatternHammer(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Inverted Hammer pattern
   bool              IsUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Hanging Man pattern
   bool              IsUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Doji pattern
   bool              IsUsedPatternDoji(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Dragonfly Doji pattern
   bool              IsUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Gravestone Doji pattern
   bool              IsUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Morning Star pattern
   bool              IsUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Morning Doji Star pattern
   bool              IsUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Evening Star pattern
   bool              IsUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Evening Doji Star pattern
   bool              IsUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Three Stars pattern
   bool              IsUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Abandoned Baby pattern
   bool              IsUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe);
//--- Price Action
//--- Return the flag of using the Pivot Point Reversal pattern
   bool              IsUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Pattern Outside
   bool              IsUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Inside Bar pattern
   bool              IsUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Pin Bar pattern
   bool              IsUsedPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                         const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                         const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                         const double ratio_smaller_shadow=30);  // Percentage ratio of the size of the smaller shadow to the size of the candle
//--- Return the flag of using the Rails pattern
   bool              IsUsedPatternRails(const ENUM_TIMEFRAMES timeframe);
   
//+------------------------------------------------------------------+
//| Methods for drawing patterns on a chart                          |
//+------------------------------------------------------------------+
//--- Draw Harami pattern labels on the chart
   void              DrawPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Harami Cross pattern labels on the chart
   void              DrawPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Tweezer pattern labels on the chart
   void              DrawPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Piercing Line pattern labels on the chart
   void              DrawPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Dark Cloud Cover pattern labels on the chart
   void              DrawPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Three White Soldiers pattern labels on the chart
   void              DrawPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Three Black Crows pattern labels on the chart
   void              DrawPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Shooting Star pattern labels on the chart
   void              DrawPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Hammer pattern labels on the chart
   void              DrawPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Inverted Hammer pattern labels on the chart
   void              DrawPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Hanging Man pattern labels on the chart
   void              DrawPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Doji pattern labels on the chart
   void              DrawPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Dragonfly Doji pattern labels on the chart
   void              DrawPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Gravestone Doji pattern labels on the chart
   void              DrawPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Morning Star pattern labels on the chart
   void              DrawPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Morning Doji Star pattern labels on the chart
   void              DrawPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Evening Star pattern labels on the chart
   void              DrawPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Evening Doji Star pattern labels on the chart
   void              DrawPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Three Stars pattern labels on the chart
   void              DrawPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Abandoned Baby pattern labels on the chart
   void              DrawPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Pivot Point Reversal pattern labels on the chart
//--- Price Action
   void              DrawPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Pattern Outside labels on the chart
   void              DrawPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Inside Bar pattern labels on the chart
   void              DrawPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Pin Bar pattern labels on the chart
   void              DrawPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                       const double ratio_body=30,            // Percentage ratio of the candle body to the full size of the candle
                                       const double ratio_larger_shadow=60,   // Percentage ratio of the size of the larger shadow to the size of the candle
                                       const double ratio_smaller_shadow=30,  // Percentage ratio of the size of the smaller shadow to the size of the candle
                                       const bool redraw=false);              // Chart redraw flag
//--- Draw Rails pattern labels on the chart
   void              DrawPatternRails(const ENUM_TIMEFRAMES timeframe,const bool redraw=false);

  };

Aqui, as entradas são destinadas apenas aos métodos de manipulação do padrão Pin Bar. Nos métodos restantes, adicionaremos essas entradas ao criar as classes de novos padrões.


No construtor da classe, atribua o ponteiro para a lista externa, passada nos parâmetros do construtor, ao ponteiro para a lista de todos os padrões:

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


O método que retorna o índice de um timeframe na lista usa um objeto temporário para pesquisar o índice. Ao criar um novo objeto de séries temporais, agora é necessário passar o ponteiro para a lista externa. Em vez de um ponteiro real para uma lista real, aqui passamos o ponteiro para o objeto da lista vazia, já que este é um objeto temporário, que é então excluído (este comportamento precisa ser corrigido posteriormente - não devemos criar e excluir constantemente novos objetos, mas sim criar um temporário no pool global e usá-lo como uma instância, atribuindo NULL a ele):

//+------------------------------------------------------------------+
//| Return the timeframe index in the list                           |
//+------------------------------------------------------------------+
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;
  }


Passe o ponteiro para a lista de padrões no construtor no método que adiciona a lista de séries temporais especificada à lista:

//+------------------------------------------------------------------+
//| Add the specified timeseries list to the list                    |
//+------------------------------------------------------------------+
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;
  }


No final do listagem da classe, escreva as implementações dos métodos declarados para manipular os padrões:

//+------------------------------------------------------------------+
//| Handling timeseries patterns                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for setting the pattern use flag                         |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Set the flag of using the Harami pattern                         |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHarami(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Harami Cross pattern                   |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHaramiCross(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Tweezer pattern                        |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternTweezer(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Piercing Line pattern                  |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternPiercingLine(flag);
  }
//+------------------------------------------------------------------+
//|Set the flag of using the Cloud Cover pattern                     |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternDarkCloudCover(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Three White Soldiers pattern           |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternThreeWhiteSoldiers(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Three Black Crows pattern              |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternThreeBlackCrows(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Shooting Star pattern                  |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternShootingStar(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Hammer pattern                         |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHammer(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Inverted Hammer pattern                |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternInvertedHammer(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Hanging Man pattern                    |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternHangingMan(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Doji pattern                           |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternDoji(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Dragonfly Doji pattern                 |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternDragonflyDoji(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Gravestone Doji pattern                |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternGravestoneDoji(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Morning Star pattern                   |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternMorningStar(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Morning Doji Star pattern              |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternMorningDojiStar(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Evening Star pattern                   |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternEveningStar(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Evening Doji Star pattern              |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternEveningDojiStar(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Three Stars pattern                    |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternThreeStars(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Abandoned Baby pattern                 |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternAbandonedBaby(flag);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Set the flag of using the Pivot Point Reversal pattern           |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternPivotPointReversal(flag);
  }
//+------------------------------------------------------------------+
//|Set the flag of using the Pattern Outside                         |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternOutsideBar(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Inside Bar pattern                     |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
                     CSeriesDE *series=this.GetSeries(timeframe);
                     if(series!=NULL)
                        series.SetUsedPatternInsideBar(flag);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Pin Bar pattern                        |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                         const bool flag,                        // Price Action Pin Bar usage flag
                                         const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                         const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                         const double ratio_smaller_shadow=30)   // Percentage ratio of the size of the smaller shadow to the size of the candle
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternPinBar(flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Rails pattern                          |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesDE::SetUsedPatternRails(const ENUM_TIMEFRAMES timeframe,const bool flag)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.SetUsedPatternRails(flag);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for returning the pattern usage flag                     |
//+------------------------------------------------------------------+
//--- Candle formations
//+------------------------------------------------------------------+
//| Return the flag of using the Harami pattern                      |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHarami(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHarami() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Harami Cross pattern                |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHaramiCross(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHaramiCross() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Tweezer pattern                     |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternTweezer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternTweezer() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Piercing Line pattern               |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternPiercingLine(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternPiercingLine() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Cloud Cover pattern                 |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternDarkCloudCover() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Three White Soldiers pattern        |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternThreeWhiteSoldiers() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Three Black Crows pattern           |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternThreeBlackCrows() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Shooting Star pattern               |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternShootingStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternShootingStar() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Hammer pattern                      |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHammer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHammer() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Inverted Hammer pattern             |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternInvertedHammer() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Hanging Man pattern                 |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternHangingMan(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternHangingMan() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Doji pattern                        |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternDoji() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Dragonfly Doji pattern              |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternDragonflyDoji() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Gravestone Doji pattern             |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternGravestoneDoji() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Morning Star pattern                |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternMorningStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternMorningStar() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Morning Doji Star pattern           |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternMorningDojiStar() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Evening Star pattern                |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternEveningStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternEveningStar() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Evening Doji Star pattern           |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternEveningDojiStar() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Three Stars pattern                 |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternThreeStars(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternThreeStars() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Abandoned Baby pattern              |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternAbandonedBaby() : false);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Return the flag of using the Pivot Point Reversal pattern        |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternPivotPointReversal() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Pattern Outside                     |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternOutsideBar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternOutsideBar() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Inside Bar pattern                  |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternInsideBar(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternInsideBar() : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Pin Bar pattern                     |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                        const double ratio_body=30,           // Percentage ratio of the candle body to the full size of the candle
                                        const double ratio_larger_shadow=60,  // Percentage ratio of the size of the larger shadow to the size of the candle
                                        const double ratio_smaller_shadow=30) // Percentage ratio of the size of the smaller shadow to the size of the candle
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Rails pattern                       |
//+------------------------------------------------------------------+
bool CTimeSeriesDE::IsUsedPatternRails(const ENUM_TIMEFRAMES timeframe)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   return(series!=NULL ? series.IsUsedPatternRails() : false);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for drawing patterns on a chart                          |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Draw Harami pattern labels on the chart                          |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHarami(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHarami(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Harami Cross pattern labels on the chart                    |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHaramiCross(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHaramiCross(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Tweezer pattern labels on the chart                         |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternTweezer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternTweezer(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Piercing Line pattern labels on the chart                   |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternPiercingLine(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternPiercingLine(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Dark Cloud Cover pattern labels on the chart                |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternDarkCloudCover(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternDarkCloudCover(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Three White Soldiers pattern labels on the chart            |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternThreeWhiteSoldiers(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternThreeWhiteSoldiers(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Three Black Crows pattern labels on the chart               |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternThreeBlackCrows(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternThreeBlackCrows(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Shooting Star pattern labels on the chart                   |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternShootingStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternShootingStar(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Hammer pattern labels on the chart                          |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHammer(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Inverted Hammer pattern labels on the chart                 |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternInvertedHammer(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternInvertedHammer(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Hanging Man pattern labels on the chart                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternHangingMan(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternHangingMan(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Doji pattern labels on the chart                            |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternDoji(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Dragonfly Doji pattern labels on the chart                  |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternDragonflyDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternDragonflyDoji(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Gravestone Doji pattern labels on the chart                 |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternGravestoneDoji(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternGravestoneDoji(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Morning Star pattern labels on the chart                    |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternMorningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternMorningStar(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Morning Doji Star pattern labels on the chart               |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternMorningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternMorningDojiStar(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Evening Star pattern labels on the chart                    |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternEveningStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternEveningStar(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Evening Doji Star pattern labels on the chart               |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternEveningDojiStar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternEveningDojiStar(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Three Stars pattern labels on the chart                     |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternThreeStars(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternThreeStars(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Abandoned Baby pattern labels on the chart                  |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternAbandonedBaby(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternAbandonedBaby(redraw);
  }
//--- Price Action
//+------------------------------------------------------------------+
//|  Draw Pivot Point Reversal pattern labels on the chart           |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternPivotPointReversal(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternPivotPointReversal(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Pattern Outside labels on the chart                         |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternOutsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternOutsideBar(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Inside Bar pattern labels on the chart                      |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternInsideBar(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternInsideBar(redraw);
  }
//+------------------------------------------------------------------+
//| Draw Pin Bar pattern labels on the chart                         |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternPinBar(const ENUM_TIMEFRAMES timeframe,
                                      const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                      const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                      const double ratio_smaller_shadow=30,   // Percentage ratio of the size of the smaller shadow to the size of the candle
                                      const bool redraw=false)                // Chart redraw flag
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternPinBar(ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
  }
//+------------------------------------------------------------------+
//| Draw Rails pattern labels on the chart                           |
//+------------------------------------------------------------------+
void CTimeSeriesDE::DrawPatternRails(const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
  {
   CSeriesDE *series=this.GetSeries(timeframe);
   if(series!=NULL)
      series.DrawPatternRails(redraw);
  }

Todos os métodos são idênticos. Primeiro, obtemos o ponteiro para as séries temporais pelo timeframe especificado. Depois, chamamos seu método para manipular o padrão correspondente. As entradas nos métodos apresentados são indicadas apenas para o padrão Pin Bar finalizado. Para todos os outros métodos, adicionaremos os parâmetros ao criar as classes de novos padrões.


Agora, modificações semelhantes precisam ser feitas na classe de coleção de séries temporais no arquivo \MQL5\Include\DoEasy\CollectionsTimeSeriesCollection.mqh.

Passamos o ponteiro para a lista externa de todos os padrões para os construtores de classe acima. Essa lista será criada na classe atual, assim como o método que retorna o ponteiro para ela:

//+------------------------------------------------------------------+
//| Symbol timeseries collection                                     |
//+------------------------------------------------------------------+
class CTimeSeriesCollection : public CBaseObjExt
  {
private:
   CListObj                m_list;                    // List of applied symbol timeseries
   CListObj                m_list_all_patterns;       // List of all patterns of all used symbol timeseries

//--- Return the timeseries index by symbol name
   int                     IndexTimeSeries(const string symbol);
public:
//--- Return (1) oneself, (2) the timeseries list and (3) the list of patterns
   CTimeSeriesCollection  *GetObject(void)            { return &this;                     }
   CArrayObj              *GetList(void)              { return &this.m_list;              }
   CArrayObj              *GetListAllPatterns(void)   { return &this.m_list_all_patterns; }

//--- Return (1) the timeseries object of the specified symbol and (2) the timeseries object of the specified symbol/period
   CTimeSeriesDE          *GetTimeseries(const string symbol);
   CSeriesDE              *GetSeries(const string symbol,const ENUM_TIMEFRAMES timeframe);


Na seção pública, declare os métodos para manipular os padrões:

//--- Copy the specified double property of the specified timeseries of the specified symbol to the array
//--- Regardless of the array indexing direction, copying is performed the same way as copying to a timeseries array
   bool                    CopyToBufferAsSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                const ENUM_BAR_PROP_DOUBLE property,
                                                double &array[],
                                                const double empty=EMPTY_VALUE);
                                                
//+------------------------------------------------------------------+
//| Handling timeseries patterns                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for setting the pattern use flag                         |
//+------------------------------------------------------------------+
//--- Set the flag for using the Harami pattern and create a control object if it does not already exist
   void                    SetUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Harami Cross pattern and create a control object if it does not already exist
   void                    SetUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Tweezer pattern and create a control object if it does not already exist
   void                    SetUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Piercing Line pattern and create a control object if it does not already exist
   void                    SetUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Cloud Cover pattern and create a control object if it does not already exist
   void                    SetUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Three White Soldiers pattern and create a control object if it does not already exist
   void                    SetUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Three Black Crows pattern and create a control object if it does not already exist
   void                    SetUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Shooting Star pattern and create a control object if it does not already exist
   void                    SetUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Hammer pattern and create a control object if it does not already exist
   void                    SetUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Inverted Hammer pattern and create a control object if it does not already exist
   void                    SetUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Hanging Man pattern and create a control object if it does not already exist
   void                    SetUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Doji pattern and create a control object if it does not already exist
   void                    SetUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Dragonfly Doji pattern and create a control object if it does not already exist
   void                    SetUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Doji Gravestone pattern and create a control object if it does not already exist
   void                    SetUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Morning Star pattern and create a control object if it does not already exist
   void                    SetUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Morning Doji Star pattern and create a control object if it does not already exist
   void                    SetUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Evening Star pattern and create a control object if it does not already exist
   void                    SetUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Evening Doji Star pattern and create a control object if it does not already exist
   void                    SetUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Three Stars pattern and create a control object if it does not already exist
   void                    SetUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Abandoned Baby pattern and create a control object if it does not already exist
   void                    SetUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Price Action
//--- Set the flag for using the Pivot Point Reversal pattern and create a control object if it does not already exist
   void                    SetUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Pattern Outside and create a control object if it does not already exist
   void                    SetUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Pattern Inside and create a control object if it does not already exist
   void                    SetUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//--- Set the flag for using the Pin Bar pattern and create a control object if it does not already exist
   void                    SetUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                const bool flag,                        // Price Action Pin Bar usage flag
                                                const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                                const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                                const double ratio_smaller_shadow=30);  // Percentage ratio of the size of the smaller shadow to the size of the candle
//--- Set the flag for using the Rails pattern and create a control object if it does not already exist
   void                    SetUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for returning the pattern usage flag                     |
//+------------------------------------------------------------------+
//--- Candle formations
//--- Return the flag of using the Harami pattern
   bool                    IsUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Harami Cross pattern
   bool                    IsUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Tweezer pattern
   bool                    IsUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Piercing Line pattern
   bool                    IsUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Cloud Cover pattern
   bool                    IsUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Three White Soldiers pattern
   bool                    IsUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Three Black Crows pattern
   bool                    IsUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Shooting Star pattern
   bool                    IsUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Hammer pattern
   bool                    IsUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Inverted Hammer pattern
   bool                    IsUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Hanging Man pattern
   bool                    IsUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Doji pattern
   bool                    IsUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Dragonfly Doji pattern
   bool                    IsUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Gravestone Doji pattern
   bool                    IsUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Morning Star pattern
   bool                    IsUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Morning Doji Star pattern
   bool                    IsUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Evening Star pattern
   bool                    IsUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Evening Doji Star pattern
   bool                    IsUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Three Stars pattern
   bool                    IsUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Abandoned Baby pattern
   bool                    IsUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Price Action
//--- Return the flag of using the Pivot Point Reversal pattern
   bool                    IsUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Pattern Outside
   bool                    IsUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Inside Bar pattern
   bool                    IsUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
//--- Return the flag of using the Pin Bar pattern
   bool                    IsUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                               const double ratio_body=30,           // Percentage ratio of the candle body to the full size of the candle
                                               const double ratio_larger_shadow=60,  // Percentage ratio of the size of the larger shadow to the size of the candle
                                               const double ratio_smaller_shadow=30);// Percentage ratio of the size of the smaller shadow to the size of the candle
//--- Return the flag of using the Rails pattern
   bool                    IsUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe);
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for drawing patterns on a chart                          |
//+------------------------------------------------------------------+
//--- Draw Harami pattern labels on the chart
   void                    DrawPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Harami Cross pattern labels on the chart
   void                    DrawPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Tweezer pattern labels on the chart
   void                    DrawPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Piercing Line pattern labels on the chart
   void                    DrawPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Dark Cloud Cover pattern labels on the chart
   void                    DrawPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Three White Soldiers pattern labels on the chart
   void                    DrawPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Three Black Crows pattern labels on the chart
   void                    DrawPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Shooting Star pattern labels on the chart
   void                    DrawPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Hammer pattern labels on the chart
   void                    DrawPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Inverted Hammer pattern labels on the chart
   void                    DrawPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Hanging Man pattern labels on the chart
   void                    DrawPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Doji pattern labels on the chart
   void                    DrawPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Dragonfly Doji pattern labels on the chart
   void                    DrawPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Gravestone Doji pattern labels on the chart
   void                    DrawPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Morning Star pattern labels on the chart
   void                    DrawPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Morning Doji Star pattern labels on the chart
   void                    DrawPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Evening Star pattern labels on the chart
   void                    DrawPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Evening Doji Star pattern labels on the chart
   void                    DrawPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Three Stars pattern labels on the chart
   void                    DrawPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Abandoned Baby pattern labels on the chart
   void                    DrawPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Price Action
//--- Draw Pivot Point Reversal pattern labels on the chart
   void                    DrawPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Pattern Outside labels on the chart
   void                    DrawPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Inside Bar pattern labels on the chart
   void                    DrawPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
//--- Draw Pin Bar pattern labels on the chart
   void                    DrawPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                             const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                             const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                             const double ratio_smaller_shadow=30,   // Percentage ratio of the size of the smaller shadow to the size of the candle
                                             const bool redraw=false);               // Chart redraw flag
//--- Draw Rails pattern labels on the chart
   void                    DrawPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false);
                                                
//--- Constructor
                           CTimeSeriesCollection();
  };


No construtor da classe, limpe a lista de todos os padrões, defina a flag de lista ordenada para ela e atribua a ela o ID da lista de padrões:

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


No método que retorna o índice da série temporal pelo nome do símbolo, crie uma lista vazia e passe o ponteiro para ela ao construtor da série temporal sendo criada:

//+------------------------------------------------------------------+
//| Return the timeseries index by symbol name                       |
//+------------------------------------------------------------------+
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;
  }


No método que cria a lista de coleção de séries temporais de símbolos, passe o ponteiro para a lista de todos os padrões para o construtor da série temporal criada:

//+------------------------------------------------------------------+
//| Create the symbol timeseries collection list                     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::CreateCollection(const CArrayObj *list_symbols)
  {
//--- If an empty list of symbol objects is passed, exit
   if(list_symbols==NULL)
      return false;
//--- Get the number of symbol objects in the passed list
   int total=list_symbols.Total();
//--- Clear the timeseries collection list
   this.m_list.Clear();
//--- In a loop by all symbol objects
   for(int i=0;i<total;i++)
     {
      //--- get the next symbol object
      CSymbol *symbol_obj=list_symbols.At(i);
      //--- if failed to get a symbol object, move on to the next one in the list
      if(symbol_obj==NULL)
         continue;
      //--- Create a new timeseries object with the current symbol name
      CTimeSeriesDE *timeseries=new CTimeSeriesDE(this.GetListAllPatterns(),symbol_obj.Name());
      //--- If failed to create the timeseries object, move on to the next symbol in the list
      if(timeseries==NULL)
         continue;
      //--- Set the sorted list flag for the timeseries collection list
      this.m_list.Sort();
      //--- If the object with the same symbol name is already present in the timeseries collection list, remove the timeseries object
      if(this.m_list.Search(timeseries)>WRONG_VALUE)
         delete timeseries;
      //--- if failed to add the timeseries object to the collection list, remove the timeseries object
      else 
         if(!this.m_list.Add(timeseries))
            delete timeseries;
     }
//--- Return the flag indicating that the created collection list has a size greater than zero
   return this.m_list.Total()>0;
  }


No final do listagem, escreva as implementações dos métodos para manipular os padrões:

//+------------------------------------------------------------------+
//| Handling timeseries patterns                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for setting the pattern use flag                         |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Set the flag of using the Harami pattern                         |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Harami Cross pattern                   |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Tweezer pattern                        |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Piercing Line pattern                  |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//|Set the flag of using the Cloud Cover pattern                     |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Three White Soldiers pattern           |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Three Black Crows pattern              |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Shooting Star pattern                  |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Hammer pattern                         |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Inverted Hammer pattern                |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Hanging Man pattern                    |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Doji pattern                           |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Dragonfly Doji pattern                 |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Gravestone Doji pattern                |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Morning Star pattern                   |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Morning Doji Star pattern              |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Evening Star pattern                   |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Evening Doji Star pattern              |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Three Stars pattern                    |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Abandoned Baby pattern                 |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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
//+------------------------------------------------------------------+
//| Set the flag of using the Pivot Point Reversal pattern           |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//|Set the flag of using the Pattern Outside                         |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Inside Bar pattern                     |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Pin Bar pattern                        |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::SetUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                 const bool flag,                        // Price Action Pin Bar usage flag
                                                 const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                                 const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                                 const double ratio_smaller_shadow=30)   // Percentage ratio of the size of the smaller shadow to the size of the candle
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.SetUsedPatternPinBar(timeframe,flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
  }
//+------------------------------------------------------------------+
//| Set the flag of using the Rails pattern                          |
//| and create a control object if it does not exist yet             |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for returning the pattern usage flag                     |
//+------------------------------------------------------------------+
//--- Candle formations
//+------------------------------------------------------------------+
//| Return the flag of using the Harami pattern                      |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHarami(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Harami Cross pattern                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHaramiCross(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Tweezer pattern                     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternTweezer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Piercing Line pattern               |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternPiercingLine(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Cloud Cover pattern                 |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternDarkCloudCover(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Three White Soldiers pattern        |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternThreeWhiteSoldiers(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Three Black Crows pattern           |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternThreeBlackCrows(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Shooting Star pattern               |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternShootingStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Hammer pattern                      |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHammer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Inverted Hammer pattern             |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternInvertedHammer(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Hanging Man pattern                 |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternHangingMan(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Doji pattern                        |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Dragonfly Doji pattern              |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternDragonflyDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Gravestone Doji pattern             |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternGravestoneDoji(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Morning Star pattern                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternMorningStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Morning Doji Star pattern           |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternMorningDojiStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Evening Star pattern                |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternEveningStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Evening Doji Star pattern           |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternEveningDojiStar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Three Stars pattern                 |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternThreeStars(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Abandoned Baby pattern              |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternAbandonedBaby(timeframe) : false);
  }
//--- Price Action
//+------------------------------------------------------------------+
//| Return the flag of using the Pivot Point Reversal pattern        |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternPivotPointReversal(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Pattern Outside                     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternOutsideBar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Inside Bar pattern                  |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternInsideBar(timeframe) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Pin Bar pattern                     |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                const double ratio_body=30,           // Percentage ratio of the candle body to the full size of the candle
                                                const double ratio_larger_shadow=60,  // Percentage ratio of the size of the larger shadow to the size of the candle
                                                const double ratio_smaller_shadow=30) // Percentage ratio of the size of the smaller shadow to the size of the candle
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternPinBar(timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow) : false);
  }
//+------------------------------------------------------------------+
//| Return the flag of using the Rails pattern                       |
//+------------------------------------------------------------------+
bool CTimeSeriesCollection::IsUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   return(timeseries!=NULL ? timeseries.IsUsedPatternRails(timeframe) : false);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Methods for drawing patterns on a chart                          |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Draw Harami pattern labels on the chart                          |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Harami Cross pattern labels on the chart                    |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Tweezer pattern labels on the chart                         |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Piercing Line pattern labels on the chart                   |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Dark Cloud Cover pattern labels on the chart                |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Three White Soldiers pattern labels on the chart            |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Three Black Crows pattern labels on the chart               |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Shooting Star pattern labels on the chart                   |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Hammer pattern labels on the chart                          |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Inverted Hammer pattern labels on the chart                 |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Hanging Man pattern labels on the chart                     |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Doji pattern labels on the chart                            |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Dragonfly Doji pattern labels on the chart                  |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Gravestone Doji pattern labels on the chart                 |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Morning Star pattern labels on the chart                    |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Morning Doji Star pattern labels on the chart               |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Evening Star pattern labels on the chart                    |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Evening Doji Star pattern labels on the chart               |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Three Stars pattern labels on the chart                     |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Abandoned Baby pattern labels on the chart                  |
//+------------------------------------------------------------------+
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
//+------------------------------------------------------------------+
//|  Draw Pivot Point Reversal pattern labels on the chart           |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Pattern Outside labels on the chart                         |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Inside Bar pattern labels on the chart                      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Draw Pin Bar pattern labels on the chart                         |
//+------------------------------------------------------------------+
void CTimeSeriesCollection::DrawPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                              const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                              const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                              const double ratio_smaller_shadow=30,   // Percentage ratio of the size of the smaller shadow to the size of the candle
                                              const bool redraw=false)                // Chart redraw flag
  {
   CTimeSeriesDE *timeseries=this.GetTimeseries(symbol);
   if(timeseries!=NULL)
      timeseries.DrawPatternPinBar(timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
  }
//+------------------------------------------------------------------+
//| Draw Rails pattern labels on the chart                           |
//+------------------------------------------------------------------+
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);
  }

A lógica de todos os métodos é simples - obtemos o ponteiro para a série temporal e usamos seus métodos para manipular os padrões criados acima. Os métodos para manipular o padrão Pin Bar estão completamente prontos. O restante será finalizado ao criar novos padrões.


Agora, vamos fazer modificações semelhantes na classe principal da biblioteca CEngine em \MQL5\Include\DoEasyEngine.mqh.

Na seção de manipulação de séries temporais, adicione os métodos para trabalhar com padrões de séries temporais:

//--- Copy the specified double property of the specified timeseries of the specified symbol to the array
//--- Regardless of the array indexing direction, copying is performed the same way as copying to a timeseries array
   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);}

//--- Returns a complete list of patterns
   CArrayObj           *GetListAllPatterns(void)
                          { return this.m_time_series.GetListAllPatterns();   }
//--- Return a list of patterns for the specified symbol and timeframe
   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);
                          }
//--- Return a list of specified patterns for the specified symbol and timeframe
   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);
                          }
//--- Return a list of patterns based on the specified bar opening time on a symbol and timeframe
   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);
                          }
//--- Return a list of specified patterns based on the specified bar opening time on a symbol and timeframe
   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);
                          }
//--- Return a pointer to the specified pattern based on the opening time of the bar on the chart of the specified symbol and timeframe
   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);
                          }

//--- Set the flag for using the Harami pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHarami(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Harami Cross pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHaramiCross(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Tweezer pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternTweezer(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Piercing Line pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternPiercingLine(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Cloud Cover pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternDarkCloudCover(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Three White Soldiers pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternThreeWhiteSoldiers(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Three Black Crows pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternThreeBlackCrows(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Shooting Star pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternShootingStar(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Hammer pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHammer(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Inverted Hammer pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternInvertedHammer(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Hanging Man pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternHangingMan(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Doji pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternDoji(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Dragonfly Doji pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternDragonflyDoji(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Doji Gravestone pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternGravestoneDoji(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Morning Star pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternMorningStar(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Morning Doji Star pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternMorningDojiStar(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Evening Star pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternEveningStar(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Evening Doji Star pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternEveningDojiStar(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Three Stars pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternThreeStars(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Abandoned Baby pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternAbandonedBaby(symbol,timeframe,flag);
                          }
//--- Price Action
//--- Set the flag for using the Pivot Point Reversal pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternPivotPointReversal(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Pattern Outside and create a control object if it does not already exist
   void                 SeriesSetUsedPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternOutsideBar(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Pattern Inside and create a control object if it does not already exist
   void                 SeriesSetUsedPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternInsideBar(symbol,timeframe,flag);
                          }
//--- Set the flag for using the Pin Bar pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                   const bool flag,                        // Price Action Pin Bar usage flag
                                                   const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                                   const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                                   const double ratio_smaller_shadow=30)   // Percentage ratio of the size of the smaller shadow to the size of the candle
                          {
                           this.m_time_series.SetUsedPatternPinBar(symbol,timeframe,flag,ratio_body,ratio_larger_shadow,ratio_smaller_shadow);
                          }
//--- Set the flag for using the Rails pattern and create a control object if it does not already exist
   void                 SeriesSetUsedPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag)
                          {
                           this.m_time_series.SetUsedPatternRails(symbol,timeframe,flag);
                          }

//--- Draw Harami pattern labels on the chart
   void                 SeriesDrawPatternHarami(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHarami(symbol,timeframe,redraw);
                          }
//--- Draw Harami Cross pattern labels on the chart
   void                 SeriesDrawPatternHaramiCross(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHaramiCross(symbol,timeframe,redraw);
                          }
//--- Draw Tweezer pattern labels on the chart
   void                 SeriesDrawPatternTweezer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternTweezer(symbol,timeframe,redraw);
                          }
//--- Draw Piercing Line pattern labels on the chart
   void                 SeriesDrawPatternPiercingLine(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternPiercingLine(symbol,timeframe,redraw);
                          }
//--- Draw Dark Cloud Cover pattern labels on the chart
   void                 SeriesDrawPatternDarkCloudCover(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternDarkCloudCover(symbol,timeframe,redraw);
                          }
//--- Draw Three White Soldiers pattern labels on the chart
   void                 SeriesDrawPatternThreeWhiteSoldiers(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternThreeWhiteSoldiers(symbol,timeframe,redraw);
                          }
//--- Draw Three Black Crows pattern labels on the chart
   void                 SeriesDrawPatternThreeBlackCrows(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternThreeBlackCrows(symbol,timeframe,redraw);
                          }
//--- Draw Shooting Star pattern labels on the chart
   void                 SeriesDrawPatternShootingStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternShootingStar(symbol,timeframe,redraw);
                          }
//--- Draw Hammer pattern labels on the chart
   void                 SeriesDrawPatternHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHammer(symbol,timeframe,redraw);
                          }
//--- Draw Inverted Hammer pattern labels on the chart
   void                 SeriesDrawPatternInvertedHammer(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternInvertedHammer(symbol,timeframe,redraw);
                          }
//--- Draw Hanging Man pattern labels on the chart
   void                 SeriesDrawPatternHangingMan(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternHangingMan(symbol,timeframe,redraw);
                          }
//--- Draw Doji pattern labels on the chart
   void                 SeriesDrawPatternDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternDoji(symbol,timeframe,redraw);
                          }
//--- Draw Dragonfly Doji pattern labels on the chart
   void                 SeriesDrawPatternDragonflyDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternDragonflyDoji(symbol,timeframe,redraw);
                          }
//--- Draw Gravestone Doji pattern labels on the chart
   void                 SeriesDrawPatternGravestoneDoji(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternGravestoneDoji(symbol,timeframe,redraw);
                          }
//--- Draw Morning Star pattern labels on the chart
   void                 SeriesDrawPatternMorningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternMorningStar(symbol,timeframe,redraw);
                          }
//--- Draw Morning Doji Star pattern labels on the chart
   void                 SeriesDrawPatternMorningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternMorningDojiStar(symbol,timeframe,redraw);
                          }
//--- Draw Evening Star pattern labels on the chart
   void                 SeriesDrawPatternEveningStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternEveningStar(symbol,timeframe,redraw);
                          }
//--- Draw Evening Doji Star pattern labels on the chart
   void                 SeriesDrawPatternEveningDojiStar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternEveningDojiStar(symbol,timeframe,redraw);
                          }
//--- Draw Three Stars pattern labels on the chart
   void                 SeriesDrawPatternThreeStars(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternThreeStars(symbol,timeframe,redraw);
                          }
//--- Draw Abandoned Baby pattern labels on the chart
   void                 SeriesDrawPatternAbandonedBaby(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternAbandonedBaby(symbol,timeframe,redraw);
                          }
//--- Price Action
//--- Draw Pivot Point Reversal pattern labels on the chart
   void                 SeriesDrawPatternPivotPointReversal(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternPivotPointReversal(symbol,timeframe,redraw);
                          }
//--- Draw Pattern Outside labels on the chart
   void                 SeriesDrawPatternOutsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternOutsideBar(symbol,timeframe,redraw);
                          }
//--- Draw Inside Bar pattern labels on the chart
   void                 SeriesDrawPatternInsideBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternInsideBar(symbol,timeframe,redraw);
                          }
//--- Draw Pin Bar pattern labels on the chart
   void                 SeriesDrawPatternPinBar(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                                const double ratio_body=30,             // Percentage ratio of the candle body to the full size of the candle
                                                const double ratio_larger_shadow=60,    // Percentage ratio of the size of the larger shadow to the size of the candle
                                                const double ratio_smaller_shadow=30,   // Percentage ratio of the size of the smaller shadow to the size of the candle
                                                const bool redraw=false)                // Chart redraw flag
                          {
                           this.m_time_series.DrawPatternPinBar(symbol,timeframe,ratio_body,ratio_larger_shadow,ratio_smaller_shadow,redraw);
                           if(redraw)
                              ::ChartRedraw();
                          }
   //--- Draw Rails pattern labels on the chart
   void                 SeriesDrawPatternRails(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool redraw=false)
                          {
                           this.m_time_series.DrawPatternRails(symbol,timeframe,redraw);
                          }

//--- Hide icons of all patterns
   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();
                          }
//--- Hides the icons of all patterns except the specified one
   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();
                          }

//--- Hide the info panels of all patterns
   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();
                          }
//--- Hides info panels of all patterns except the specified one
   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();
                          }

//--- Return (1) the tick series collection, (2) the list of tick series from the tick series collection
   CTickSeriesCollection *GetTickSeriesCollection(void)                                { return &this.m_tick_series;                                  }
   CArrayObj           *GetListTickSeries(void)                                        { return this.m_tick_series.GetList();                         }

Aqui, os métodos para manipular padrões Pin Bar e listas de objetos de padrões com base em propriedades especificadas estão totalmente preparados. Vou refinar gradualmente aqueles métodos que atualmente estão na forma de esboços enquanto adiciono novos padrões.

No manipulador de eventos de novo tick, comente temporariamente a atualização dos dados do tick, pois a manipulação de ticks às vezes causa congelamentos prolongados no gráfico. Ainda não está claro onde está a razão - pode ser em algum lugar no código da biblioteca (embora tudo tenha funcionado bem anteriormente), ou pode estar relacionado às atualizações do terminal:

//+------------------------------------------------------------------+
//| NewTick event handler                                            |
//+------------------------------------------------------------------+
void CEngine::OnTick(SDataCalculate &data_calculate,const uint required=0)
  {
//--- If this is not a EA, exit
   if(this.m_program_type!=PROGRAM_EXPERT)
      return;
//--- Re-create empty timeseries and update the current symbol timeseries
   this.SeriesSync(data_calculate,required);
   this.SeriesRefresh(NULL,data_calculate);
//--- Commented out because TickSeriesRefresh causes freezes - I will look into it later
   //this.TickSeriesRefresh(NULL);
//--- end
  }

Isso é tudo por enquanto. Vamos testar os resultados.


Teste

Para realizar o teste, vou usar o EA do artigo "Outras classes na biblioteca DoEasy (parte 72): Acompanhamento e registro dos parâmetros de objetos de gráfico na coleção"
e salvá-lo na nova pasta \MQL5\Experts\TestDoEasyPart134 como TestDoEasyPart134.mq5.

Nas entradas, adicione as proporções de velas usadas para buscar padrões, habilite o trabalho apenas no timeframe atual e desative o uso de profundidade de mercado, sinais e acompanhamento de eventos de gráfico:

//--- 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


No manipulador OnInit(), prepare a lista de padrões para trabalhar com ela:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Calling the function displays the list of enumeration constants in the journal 
//--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity
   //EnumNumbersTest();

//--- Set EA global variables
   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);
//--- Initialize random group numbers
   group1=0;
   group2=0;
   srand(GetTickCount());
   
//--- Initialize DoEasy library
   OnInitDoEasy();
   
//--- Check and remove remaining EA graphical objects
   if(IsPresentObectByPrefix(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Create the button panel
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      return INIT_FAILED;
//--- Set trailing activation button status
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);
//--- Reset states of the buttons for working using pending requests
   for(int i=0;i<14;i++)
     {
      ButtonState(butt_data[i].name+"_PRICE",false);
      ButtonState(butt_data[i].name+"_TIME",false);
     }

//--- Check playing a standard sound by macro substitution and a custom sound by description
   engine.PlaySoundByDescription(SND_OK);
//--- Wait for 600 milliseconds
   engine.Pause(600);
   engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","Falling coin 2"));

//--- Check the calculation of the cursor coordinates in the chart windows.
//--- Allow the current chart to track mouse movement events
   if(engine.ChartGetMainChart()!=NULL)
      engine.ChartGetMainChart().SetEventMouseMoveON();

//--- Clear the list of all patterns
   engine.GetListAllPatterns().Clear();
//--- Set the flag of using the Pin Bar pattern with the parameters specified in the settings
   engine.SeriesSetUsedPatternPinBar(NULL,PERIOD_CURRENT,true,InpPinBarRatioBody,InpPinBarRatioLarger,InpPinBarRatioSmaller);
//--- Hide all pattern icons, if any
   engine.SeriesPatternHideAll();
//--- Hide all pattern info panels, if any
   engine.SeriesPatternHideAllInfoPanels();
//--- Display the pattern icons on the chart with the parameters specified in the settings
   engine.SeriesDrawPatternPinBar(NULL,PERIOD_CURRENT,InpPinBarRatioBody,InpPinBarRatioLarger,InpPinBarRatioSmaller,true);
//---
   return(INIT_SUCCEEDED);
  }


No manipulador de eventos OnChartEvent(), adicione o manuseio de eventos de alteração de gráfico, para que qualquer alteração oculte os painéis de informações atualmente ativos. Além disso, adicione o bloco de código que exibe esses painéis no gráfico ao passar o cursor sobre a vela onde o padrão foi encontrado:

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- If working in the tester, exit
   if(MQLInfoInteger(MQL_TESTER))
      return;
//--- Handling mouse events
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Handle pressing the buttons in the panel
      if(StringFind(sparam,"BUTT_")>0)
         PressButtonEvents(sparam);
     }
//--- Handling DoEasy library events
   if(id>CHARTEVENT_CUSTOM-1)
     {
      OnDoEasyEvent(id,lparam,dparam,sparam);
     }
//--- Chart change
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Whenever the chart changes, hide all information panels 
      engine.SeriesPatternHideAllInfoPanels();
      return;
     }
//--- Check ChartXYToTimePrice()
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- Get the chart object of the current (main) program chart
      CChartObj *chart=engine.ChartGetMainChart();
      if(chart==NULL)
         return;
      //--- Get the index of a subwindow the cursor is located at
      int wnd_num=chart.XYToTimePrice(lparam,dparam);
      if(wnd_num==WRONG_VALUE)
         return;
      //--- Get the calculated cursor location time and price
      datetime time=chart.TimeFromXY();
      double price=chart.PriceFromXY();
      //--- Get the window object of the chart the cursor is located in by the subwindow index
      CChartWnd *wnd=chart.GetWindowByNum(wnd_num);
      if(wnd==NULL)
         return;
      //--- If X and Y coordinates are calculated by time and price (make a reverse conversion),
      if(wnd.TimePriceToXY(time,price))
        {
         //--- in the comment, show the time, price and index of the window that are calculated by X and Y cursor coordinates,
         //--- as well as the cursor X and Y coordinates converted back from the time and price
         //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(),")"
         //  );
         
         //--- Get the bar open time on the chart using the cursor time
         datetime bar_time=GetStartTimeOfBarFast(PERIOD_CURRENT,time);
         //--- Get a pattern from the chart bar the open time was found for 
         CPattern *pinbar=engine.GetPattern(Symbol(),Period(),bar_time,PATTERN_TYPE_PIN_BAR);
         //--- If there is a Pin Bar pattern on the bar 
         if(pinbar!=NULL)
           {
            //--- If the cursor is within the candle size
            if(price>=pinbar.BarPriceLow() && price<=pinbar.BarPriceHigh())
              {
               //--- Print a short description of the pattern in the journal
               pinbar.PrintShort(true);
               //--- Get the chart coordinates where you want to display the information panel
               int x=0;
               int y=0;
               if(ChartTimePriceToXY(pinbar.GetChartID(),0,bar_time,price,x,y))
                 {
                  //--- Hide all panels except those belonging to the current pattern under the cursor
                  engine.SeriesPatternHideAllInfoPanelsExceptOne(pinbar.Code());
                  //--- Display the information panel on the chart
                  pinbar.ShowInfoPanel(x,y);
                 }
              }
           }
        }
     }
  }

Isso funcionará da seguinte forma: as etiquetas dos padrões encontrados serão exibidas no gráfico. Se passarmos o cursor sobre uma barra com uma etiqueta (dentro do seu High e Low), será exibido um painel de informações com uma pequena descrição do padrão. Ao passar o cursor do mouse sobre outra barra com um padrão, o painel do primeiro padrão será oculto e o painel daquele para o qual o cursor foi movido será exibido. Qualquer painel exibido no gráfico permanecerá visível até que o gráfico seja alterado de alguma forma, por exemplo, movido para a direita ou esquerda. Esta é a solução mais simples para o teste no momento. Em seguida, provavelmente faremos o ocultamento automático dos painéis ao longo do tempo.

Compile o EA e lance-o no gráfico:

Podemos ver que o gráfico contém marcas dos padrões encontrados nas velas. Ao passar o cursor, os painéis de informações aparecem com uma descrição do padrão, seus parâmetros e critérios de busca. A coloração dos painéis é diferente para padrões altistas e baixistas. Se o cursor for removido da barra, o painel de informações permanecerá nela e só será removido quando outro painel de um padrão diferente for aberto, ou quando o gráfico for deslocado.


O que vem a seguir?

No próximo artigo, continuaremos a desenvolver padrões.

Todos os arquivos criados estão anexados ao artigo e podem ser baixados para estudo e testes.

Voltar ao conteúdo

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/14339

Arquivos anexados |
MQL5.zip (5275.56 KB)
Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Desenvolvendo um EA multimoeda (Parte 5): tamanho de posição variável Desenvolvendo um EA multimoeda (Parte 5): tamanho de posição variável
Nos capítulos anteriores, o EA desenvolvido só podia usar um tamanho de posição fixo para negociações. Isso é adequado para testes, mas não é aconselhável ao negociar mediante uma conta real. Vamos adicionar a capacidade de operar com tamanhos de posição variáveis.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Rede neural na prática: Esboçando um neurônio Rede neural na prática: Esboçando um neurônio
Neste artigo, faremos a confecção de um neurônio básico. Apesar de ele ser algo simples, e muitos acharem que o código é totalmente bobo e sem nenhum propósito. Quero que você, meu caro leitor, e entusiasta pelo tema de redes neurais. Brinque e se divirta estudando este simples esboço de neurônio. Não precisa ficar com receio de mexer no código a fim de entender o mesmo.