Estudo de técnicas de análise de velas (parte III): Biblioteca para trabalhar com os padrões

Alexander Fedosov | 25 abril, 2019

Índice

Introdução

Nós já consideramos as técnicas de análise de velas: a existência dos padrões sob as condições atuais de mercado foi verificada no primeiro artigo, e a tentativa de expansão dessas pesquisas foi feita no segundo artigo. Usando os critérios de avaliação de desenvolvimento, nós estudamos, testamos e comparamos uma ampla gama de possíveis combinações de padrões. Para este propósito, nós desenvolvemos uma aplicação personalizada Pattern Analyzer com um grande conjunto de configurações para o estudo de padrões. No entanto, a teoria e pesquisa só podem fornecer informações e conclusões. A continuação lógica da tarefa é usá-los em condições reais.

Portanto, o objetivo deste artigo é criar uma ferramenta personalizada, que permita aos usuários receber e usar todo array de informações sobre os padrões discutidos anteriormente. Nós vamos criar uma biblioteca que você poderá usar em seus próprios indicadores, painéis de negociação, Expert Advisors, etc.    


Estrutura da biblioteca

Antes de procedermos para a criação da estrutura da biblioteca, classes e os arquivos de inclusão, vamos definir os dados que nós usaremos. Ou seja, nós precisamos separar os métodos responsáveis pelos dados de entrada e os métodos que fornecerão os resultados. A estrutura geral da biblioteca será baseada na solução visual desenvolvida nos artigos anteriores — o Pattern Analyzer. 

Vamos começar com os dados de entrada do aplicativo que podem influenciar o resultado ao testar os padrões.

Fig.1 Parâmetros de entrada na guia Setting.

Bloco 1. Este bloco apresenta a lista dos tipos de velas que consistem os padrões existentes e gerados. Cada um dos tipos tem suas configurações, que você pode visualizar clicando no ícone da engrenagem no canto superior direito da página de visualização da vela. Os tipos de vela de 1-5 possuem apenas uma configuração, enquanto o martelo (Hammer) possui duas delas. 

Bloco 2 Coeficientes de peso. Existem três parâmetros К1, К2, К3 que afetam o resultado da avaliação da eficiência do padrão. 

Bloco 3 Valor do limiar da tendência em pontos. 

Bloco 4 Velas usadas ao testar os padrões gerados. Aqui, nós precisaremos dos números da sequência ou dos índices da vela. Usando esses dados, nós poderemos obter as informações sobre qualquer padrão de qualquer tamanho, até três velas.

Bloco 5 Número de velas no padrão. Esta configuração é aplicável apenas para os padrões personalizados. 

Em seguida, nós vamos ver a guia Analyze e os parâmetros de entrada contidos nela.

Fig.2 Parâmetros de entrada na guia Analyze.

Bloco 6 este bloco contém as configurações do período gráfico atual e o intervalo da amostra de dados usada para a análise do padrão. 

Bloco 7 Nomes dos padrões existentes. Ele também possui uma entrada que não pode ser editada a partir da aplicação, mas é necessária para acessar um padrão e obter as informações dele.

Vamos enumerar aqui os dados que podem ser obtidos a partir da análise de padrões. Isso é necessário para a criação de uma estrutura de métodos correta em uma classe.

Desenvolvimento da biblioteca

Depois de determinar os pontos básicos, vamos proceder para a criação da biblioteca. Vamos começar com a criação de um arquivo com as enumerações necessárias Enums.mqh

//+------------------------------------------------------------------+
//|                                                        Enums.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. | 
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Tipo da vela                                                     |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // Indefinido
   CAND_MARIBOZU,       // Marubozu
   CAND_DOJI,           // Doji
   CAND_SPIN_TOP,       // Spinning Top
   CAND_HAMMER,         // Martelo
   CAND_INVERT_HAMMER,  // Martelo Invertido
   CAND_LONG,           // Vela de Alta
   CAND_SHORT           // Vela de Baixa
  };
//+------------------------------------------------------------------+
//| Tipo do padrão                                                   |
//+------------------------------------------------------------------+
enum TYPE_PATTERN
  {
   NONE,
   HUMMER,
   INVERT_HUMMER,
   HANDING_MAN,
   SHOOTING_STAR,
   ENGULFING_BULL,
   ENGULFING_BEAR,
   HARAMI_BULL,
   HARAMI_BEAR,
   HARAMI_CROSS_BULL,
   HARAMI_CROSS_BEAR,
   DOJI_STAR_BULL,
   DOJI_STAR_BEAR,
   PIERCING_LINE,
   DARK_CLOUD_COVER
  };
//+------------------------------------------------------------------+
//| Tipo da tendência                                                |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Tendência de alta
   DOWN,                //Tendência de baixa
   FLAT                 //Lateralizado
  };
//+------------------------------------------------------------------+

Aqui, nós determinaremos a lista dos tipos de vela simples usados, os tipos de padrões existentes e o tipo da tendência - os dados são necessários para identificar os padrões existentes no gráfico.

Depois disso, nós vamos criar o arquivo Pattern.mqh. A classe CPattern será criada nela e, em sua seção privada, nós declararemos as variáveis para os parâmetros mencionados na seção anterior. Nós também precisamos incluir o arquivo com as enumerações.

//+------------------------------------------------------------------+
//|                                                      Pattern.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |  
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#include "Enums.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CPattern
  {
private:
   //--- Pesos
   double            m_k1;
   double            m_k2;
   double            m_k3;
   //--- Valor do limiar da tendência em pontos
   int               m_threshold_value;
   //--- Configuração do coeficiente da vela de alta
   double            m_long_coef;
   //--- Configuração do coeficiente da vela de baixa
   double            m_short_coef;
   //--- Configuração do coeficiente da vela Doji
   double            m_doji_coef;
   //--- Configuração do coeficiente da vela Marubozu
   double            m_maribozu_coef;
   //--- Configuração do coeficiente da vela Spinning Top
   double            m_spin_coef;
   //--- Configuração do coeficiente da vela Martelo
   double            m_hummer_coef1;
   double            m_hummer_coef2;
   //--- Faixa de amostragem para os padrões predefinidos
   int               m_range_total;
   //--- Período para determinar a tendência
   int               m_trend_period;
   //--- Padrões encontrados
   int               m_found;
   //--- Ocorrência dos padrões
   double            m_coincidence;
   //--- Probabilidade do movimento de alta ou baixa
   double            m_probability1;
   double            m_probability2;
   //--- Eficiência
   double            m_efficiency1;
   double            m_efficiency2;
   //--- Padrões simples de velas
   struct CANDLE_STRUCTURE
     {
      double            m_open;
      double            m_high;
      double            m_low;
      double            m_close;                      // OHLC
      TYPE_TREND        m_trend;                      // Tendência
      bool              m_bull;                       // Vela de Alta
      double            m_bodysize;                   // Tamanho do corpo
      TYPE_CANDLESTICK  m_type;                       // Tipo da vela
     };
   //--- Propriedades da avaliação da eficiência do padrão
   struct RATING_SET
     {
      int               m_a_uptrend;
      int               m_b_uptrend;
      int               m_c_uptrend;
      int               m_a_dntrend;
      int               m_b_dntrend;
      int               m_c_dntrend;
     };

Como pode ser visto no código acima, duas estruturas foram adicionadas ao nosso programa. A primeira estrutura, CANDLE_STRUCTURE, é necessária para determinar o tipo de vela no gráfico. Observe que os dois tipos de enumerações da tendência são usados nessa estrutura: TYPE_TREND e TYPE_CANDLESTICK do arquivo Enums.mqh que foi considerado anteriormente e criado para essa estrutura. A segunda estrutura, RATING_SET, armazena os registros das estimativas do movimento de preço após o surgimento do padrão. Por favor, leia o primeiro artigo para mais detalhes.

Agora, considere a parte da seção public da classe, que descreve os métodos para customizar e recuperar os valores dos parâmetros de entrada, que são descritos na seção estrutura da biblioteca.

public:
                     CPattern(void);
                    ~CPattern(void);
   //--- Define e retorna os coeficientes de peso
   void              K1(const double k1)                             { m_k1=k1;                       }
   double            K1(void)                                        { return(m_k1);                  }
   void              K2(const double k2)                             { m_k2=k2;                       }
   double            K2(void)                                        { return(m_k2);                  }
   void              K3(const double k3)                             { m_k3=k3;                       }
   double            K3(void)                                        { return(m_k3);                  }
   //--- Define e retorna o valor da tendência do limiar
   void              Threshold(const int threshold)                  { m_threshold_value=threshold;   }
   int               Threshold(void)                                 { return(m_threshold_value);     }
   //--- Define e retorna o coeficiente de configuração da vela de alta
   void              Long_coef(const double long_coef)               { m_long_coef=long_coef;         }
   double            Long_coef(void)                                 { return(m_long_coef);           }
   //--- Define e retorna o coeficiente de configuração da vela de baixa
   void              Short_coef(const double short_coef)             { m_short_coef=short_coef;       }
   double            Short_coef(void)                                { return(m_short_coef);          }
   //--- Define e retorna o coeficiente de configuração da vela doji
   void              Doji_coef(const double doji_coef)               { m_doji_coef=doji_coef;         }
   double            Doji_coef(void)                                 { return(m_doji_coef);           }
   //--- Define e retorna o coeficiente de configuração da vela marubozu
   void              Maribozu_coef(const double maribozu_coef)       { m_maribozu_coef=maribozu_coef; }
   double            Maribozu_coef(void)                             { return(m_maribozu_coef);       }
   //--- Define e retorna o coeficiente de configuração da vela Spinning Top
   void              Spin_coef(const double spin_coef)               { m_spin_coef=spin_coef;         }
   double            Spin_coef(void)                                 { return(m_spin_coef);           }
   //--- Define e retorna o coeficiente de configuração da vela Martelo
   void              Hummer_coef1(const double hummer_coef1)         { m_hummer_coef1=hummer_coef1;   }
   void              Hummer_coef2(const double hummer_coef2)         { m_hummer_coef2=hummer_coef2;   }
   double            Hummer_coef1(void)                              { return(m_hummer_coef1);        }
   double            Hummer_coef2(void)                              { return(m_hummer_coef2);        }
   //--- Define e retorna a faixa de amostragem para os parâmetros predefinidos
   void              Range(const int range_total)                    { m_range_total=range_total;     }
   int               Range(void)                                     { return(m_range_total);         }
   //--- Define e retorna o número de velas para o cálculo da tendência  
   void              TrendPeriod(const int period)                   { m_trend_period=period;         }
   int               TrendPeriod(void)                               { return(m_trend_period);        }

No construtor de classe, nós descreveremos os parâmetros padrão, conforme especificado na aplicação, nas guias Settings.

//+------------------------------------------------------------------+
//| Construtor                                                       |
//+------------------------------------------------------------------+
CPattern::CPattern(void) : m_k1(1),
                           m_k2(0.5),
                           m_k3(0.25),
                           m_threshold_value(100),
                           m_long_coef(1.3),
                           m_short_coef(0.5),
                           m_doji_coef(0.04),
                           m_maribozu_coef(0.01),
                           m_spin_coef(1),
                           m_hummer_coef1(0.1),
                           m_hummer_coef2(2),
                           m_range_total(8000),
                           m_trend_period(5)
  {
  }

A segunda parte da seção public da classe CPattern fornece uma descrição dos métodos para processar os parâmetros de entrada declarados e para obter as propriedades e características dos padrões.

Vamos ver cada um deles em detalhes. É importante entender o algoritmo operacional para poder usá-los de maneira eficiente na criação de indicadores, painéis de negociação ou Expert Advisors.

CandleType

Retorna o tipo da vela selecionada dos padrões existentes listados em TYPE_CANDLESTICK.
TYPE_CANDLESTICK  CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift);

Parâmetros

Valor de Retorno

O tipo da vela selecionada da enumeração TYPE_CANDLESTICK.

//+------------------------------------------------------------------+
//| Tipo da vela                                                     |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // Indefinido
   CAND_MARIBOZU,       // Marubozu
   CAND_DOJI,           // Doji
   CAND_SPIN_TOP,       // Spinning Top
   CAND_HAMMER,         // Martelo
   CAND_INVERT_HAMMER,  // Martelo Invertido
   CAND_LONG,           // Vela de Alta
   CAND_SHORT           // Vela de Baixa
  };

Implementação

//+------------------------------------------------------------------+
//| Retorna o tipo da vela selecionada                               |
//+------------------------------------------------------------------+
TYPE_CANDLESTICK CPattern::CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift)
  {
   CANDLE_STRUCTURE res;
   if(GetCandleType(symbol,timeframe,res,shift))
      return(res.m_type);
   return(CAND_NONE);
  }
//+------------------------------------------------------------------+
//| Reconhecimento do tipo da vela                                   |
//+------------------------------------------------------------------+
bool CPattern::GetCandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,CANDLE_STRUCTURE &res,const int shift)
  {
   MqlRates rt[];
   int aver_period=m_trend_period;
   double aver=0;
   SymbolSelect(symbol,true);
   int copied=CopyRates(symbol,timeframe,shift,aver_period+1,rt);
//--- Obtém os detalhes da vela anterior
   if(copied<aver_period)
      return(false);
//---
   res.m_open=rt[aver_period].open;
   res.m_high=rt[aver_period].high;
   res.m_low=rt[aver_period].low;
   res.m_close=rt[aver_period].close;

//--- Determina a direção da tendência
   for(int i=0;i<aver_period;i++)
      aver+=rt[i].close;
   aver/=aver_period;

   if(aver<res.m_close)
      res.m_trend=UPPER;
   if(aver>res.m_close)
      res.m_trend=DOWN;
   if(aver==res.m_close)
      res.m_trend=FLAT;
//--- Determina se é uma vela de alta ou de baixa
   res.m_bull=res.m_open<res.m_close;
//--- Obtém o tamanho absoluto do corpo da vela
   res.m_bodysize=MathAbs(res.m_open-res.m_close);
//--- Obtém os tamanhos das sombras
   double shade_low=res.m_close-res.m_low;
   double shade_high=res.m_high-res.m_open;
   if(res.m_bull)
     {
      shade_low=res.m_open-res.m_low;
      shade_high=res.m_high-res.m_close;
     }
   double HL=res.m_high-res.m_low;
//--- Calcula o tamanho médio do corpo das velas anteriores
   double sum=0;
   for(int i=1; i<=aver_period; i++)
      sum=sum+MathAbs(rt[i].open-rt[i].close);
   sum=sum/aver_period;

//--- Determina o tipo de vela   
   res.m_type=CAND_NONE;
//--- alta 
   if(res.m_bodysize>sum*m_long_coef)
      res.m_type=CAND_LONG;
//--- baixa 
   if(res.m_bodysize<sum*m_short_coef)
      res.m_type=CAND_SHORT;
//--- doji
   if(res.m_bodysize<HL*m_doji_coef)
      res.m_type=CAND_DOJI;
//--- marubozu
   if((shade_low<res.m_bodysize*m_maribozu_coef || shade_high<res.m_bodysize*m_maribozu_coef) && res.m_bodysize>0)
      res.m_type=CAND_MARIBOZU;
//--- martelo
   if(shade_low>res.m_bodysize*m_hummer_coef2 && shade_high<res.m_bodysize*m_hummer_coef1)
      res.m_type=CAND_HAMMER;
//--- martelo invertido
   if(shade_low<res.m_bodysize*m_hummer_coef1 && shade_high>res.m_bodysize*m_hummer_coef2)
      res.m_type=CAND_INVERT_HAMMER;
//--- spinning top
   if(res.m_type==CAND_SHORT && shade_low>res.m_bodysize*m_spin_coef && shade_high>res.m_bodysize*m_spin_coef)
      res.m_type=CAND_SPIN_TOP;
//---
   ArrayFree(rt);
   return(true);
  }

O método de reconhecimento da vela GetCandleType() é usado no método público GetCandleType(). GetCandleType() é um método privado. Seus argumentos incluem o símbolo atual, o período gráfico e o número de velas, bem como um ponteiro para a estrutura. O cálculo e a identificação do padrão são realizados com base nesses parâmetros.

PatternType

Reconhece o tipo de padrão com a vela selecionada. Ele tem 5 sobrecargas de método porque os argumentos podem ser de padrões existentes da enumeração TYPE_PATTERN ou padrões gerados que consistem em uma, duas ou três velas. Um argumento também pode ser um array de padrões da enumeração TYPE_PATTERN.

   //--- Reconhecendo o tipo do padrão
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,const int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,const int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,const int shift);
   //--- Reconhecendo o conjunto de padrões
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift);

Parâmetros

Um ponteiro para o array de padrões existentes da lista TYPE_PATTERN.

//+------------------------------------------------------------------+
//| Tipo do padrão                                                   |
//+------------------------------------------------------------------+
enum TYPE_PATTERN
  {
   NONE,
   HUMMER,
   INVERT_HUMMER,
   HANDING_MAN,
   SHOOTING_STAR,
   ENGULFING_BULL,
   ENGULFING_BEAR,
   HARAMI_BULL,
   HARAMI_BEAR,
   HARAMI_CROSS_BULL,
   HARAMI_CROSS_BEAR,
   DOJI_STAR_BULL,
   DOJI_STAR_BEAR,
   PIERCING_LINE,
   DARK_CLOUD_COVER
  };

Valor de Retorno

Um valor booleano.

Implementação

Como existem 5 tipos de implementações do método PatternType, nós vamos analisá-lo separadamente com vários argumentos. O primeiro deles buscar por um padrão existente da enumeração TYPE_PATTERN. Como pode ser visto abaixo, isso é feito usando o método privado CheckPattern.

//+------------------------------------------------------------------+
//| Reconhecendo um padrão pré-definido                              |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,const int shift)
  {
   if(CheckPattern(symbol,timeframe,shift)==pattern)
      return(true);
   return(false);
  }
//+------------------------------------------------------------------+
//| Verifica e retorna o tipo do padrão                              |
//+------------------------------------------------------------------+
TYPE_PATTERN CPattern::CheckPattern(const string symbol,const ENUM_TIMEFRAMES timeframe,int shift)
  {
   CANDLE_STRUCTURE cand1,cand2;
   TYPE_PATTERN pattern=NONE;
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   GetCandleType(symbol,timeframe,cand2,shift);                                           // Vela anterior
   GetCandleType(symbol,timeframe,cand1,shift-1);                                         // Vela atual
//--- Martelo invertido, modelo altista
   if(cand2.m_trend==DOWN &&                                                              // Verifica a direção da tendência
      cand2.m_type==CAND_INVERT_HAMMER)                                                   // Verifica o "Martelo invertido"
      pattern=INVERT_HUMMER;
//--- Enforcado, baixista
   else if(cand2.m_trend==UPPER && // Verifica a direção da tendência
      cand2.m_type==CAND_HAMMER) // Verifica o "Martelo"
      pattern=HANDING_MAN;
//--- Martelo, modelo altista
   else if(cand2.m_trend==DOWN && // Verifica a direção da tendência
      cand2.m_type==CAND_HAMMER) // Verifica o "Martelo"
      pattern=HUMMER;
//--- Estrela Cadente, modelo baixista
   else if(cand1.m_trend==UPPER && cand2.m_trend==UPPER && // Verifica a direção da tendência
      cand2.m_type==CAND_INVERT_HAMMER && cand1.m_close<=cand2.m_open) // Verifica o "Martelo invertido"
      pattern=SHOOTING_STAR;
//--- Engolfo de alta, modelo altista
   else if(cand1.m_trend==DOWN && cand1.m_bull && cand2.m_trend==DOWN && !cand2.m_bull && // Verifica a direção da tendência e da vela
      cand1.m_bodysize>cand2.m_bodysize &&
      cand1.m_close>=cand2.m_open && cand1.m_open<cand2.m_close)
      pattern=ENGULFING_BULL;
//--- Engolfo de baixa, modelo baixista
   else if(cand1.m_trend==UPPER && cand1.m_bull && cand2.m_trend==UPPER && !cand2.m_bull && // Verifica a direção da tendência e da vela
      cand1.m_bodysize<cand2.m_bodysize &&
      cand1.m_close<=cand2.m_open && cand1.m_open>cand2.m_close)
      pattern=ENGULFING_BEAR;
//--- Harami Cross, altista
   else if(cand2.m_trend==DOWN && !cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Verifica a primeira vela de "alta" e o Doji
      cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // Doji está dentro do corpo da primeira vela
      pattern=HARAMI_CROSS_BULL;
//--- Harami Cross, modelo baixista
   else if(cand2.m_trend==UPPER && cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Verifica a primeira vela de "alta" e o Doji
      cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // Doji está dentro do corpo da primeira vela 
      pattern=HARAMI_CROSS_BEAR;
//--- Harami de alta, altista
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Verifica a primeira vela de "alta"
      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // A segunda vela não é Doji e a primeira vela é maior que a segunda
                    cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // O corpo da segunda vela está dentro do corpo da primeira 
                    pattern=HARAMI_BULL;
//--- Harami de baixa, baixista
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Verifica a primeira vela de "alta"

      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // A segunda vela não é Doji e a primeira vela é maior que a segunda
                    cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // O corpo da segunda vela está dentro do corpo da primeira 
                    pattern=HARAMI_BEAR;
//--- Estrela Doji, altista
   else if(cand1.m_trend==DOWN && !cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Verifica a primeira vela de "alta" e o Doji
      cand1.m_close<=cand2.m_open) // Abertura do Doji é menor ou igual ao fechamento da primeira vela
      pattern=DOJI_STAR_BULL;
//--- Estrela Doji, baixista
   else if(cand1.m_trend==UPPER && cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Verifica a primeira vela de "alta" e o Doji
      cand1.m_open>=cand2.m_close) //Abertura do Doji é maior ou igual ao fechamento da primeira vela
      pattern=DOJI_STAR_BEAR;
//--- Piercing, modelo altista
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Verifica a vela de "alta"
      cand1.m_close>(cand2.m_close+cand2.m_open)/2 && // Fechamento da segunda vela está acima do meio da primeira vela
      cand2.m_open>cand1.m_close && cand2.m_close>=cand1.m_open)
      pattern=PIERCING_LINE;
//--- Núvem Negra, baixista
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // Verifica a direção da tendência e da vela
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Verifica a vela de "alta"
      cand1.m_close<(cand2.m_close+cand2.m_open)/2 && // Fechamento 2 está abaixo do meio do primeiro corpo da vela
      cand1.m_close<cand2.m_open && cand2.m_close<=cand1.m_open)
      pattern=DARK_CLOUD_COVER;
   return(pattern);
  }
//+------------------------------------------------------------------+

O próximo tipo do método PatternType difere do anterior, já que o array de padrões buscados é passado em vez do argumento do tipo do padrão:

//+------------------------------------------------------------------+
//| Reconhecendo o array de padrões                                  |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift)
  {
   for(int i=0;i<ArraySize(pattern);i++)
     {
      if(CheckPattern(symbol,timeframe,shift)==pattern[i])
         return(true);
     }
   return(false);
  }

Em seguida, vamos considerar a implementação do método PatternType para trabalhar com os padrões gerados a partir dos tipos simples de velas. Existem três tipos desses padrões: consistindo de um, dois ou três velas. Vamos considerá-los um por um:

//+------------------------------------------------------------------+
//| Reconhecendo um padrão pelo índice da vela                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,int shift)
  {
//--- Verifica o índice das velas
   if(index<0 || index>11)
      return(false);
//---
   CANDLE_STRUCTURE cand,cur_cand;
   RATING_SET ratings;
   ZeroMemory(cand);
   IndexToPatternType(cand,index);
//--- Obtém o tipo de vela atual
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Vela atual
//---
   if(cur_cand.m_type==cand.m_type && cur_cand.m_bull==cand.m_bull)
      return(true);
   return(false);
  }

Esta é a implementação de um método buscando por um padrão de uma vela, que é muito semelhante ao método CandleType(), embora o tipo e o intervalo de argumentos passados sejam diferentes. Preste atenção ao método privado IndextoPatternType() que não foi usado anteriormente:

   //--- Converte o índice da vela para o seu tipo
   void              IndexToPatternType(CANDLE_STRUCTURE &res,int index);

Converte o índice de um tipo simples de vela no seu tipo e passa para a estrutura especificada.

Aqui está o método para o padrão de duas velas:

//+------------------------------------------------------------------+
//| Reconhecendo um padrão pelo índice da vela                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int shift)
  {
//--- Verifica o índice das velas
   if(index1<0 || index1>11 || index2<0 || index2>11)
      return(false);
//---
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand;
   RATING_SET ratings;
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   IndexToPatternType(cand1,index1);
   IndexToPatternType(cand2,index2);
//--- Obtém o tipo de vela atual
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // Vela anterior
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Vela atual
//---
   if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
      prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull)
      return(true);
   return(false);
  }

A implementação do código é muito semelhante à anterior. No entanto, observe que o seguinte recurso deve ser levado em consideração ao selecionar o índice de velas para análise: como o padrão consiste de duas velas, o tipo da vela 'index1' será deslocado por 'shift' e para index2 - por 'shift+1 '. A mesma peculiaridade diz respeito à implementação do método para os padrões de três velas:

//+------------------------------------------------------------------+
//| Reconhecendo um padrão pelo índice da vela                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,int shift)
  {
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2;
   RATING_SET ratings;
//---
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   ZeroMemory(cand3);
//---
   IndexToPatternType(cand1,index1);
   IndexToPatternType(cand2,index2);
   IndexToPatternType(cand3,index3);

//--- Obtém o tipo de vela atual
   GetCandleType(symbol,timeframe,prev_cand2,shift+2);                            // Vela anterior
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // Vela anterior
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Vela atual
//---
   if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
      prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && 
      prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull)
      return(true);
   return(false);
  }

Found

Retorna o número de padrões encontrados do tipo especificado. Ele possui 3 sobrecargas de métodos para os padrões existentes TYPE_PATTERN, bem como para padrões gerados que consistem de 1-3 tipos simples de velas.

   //--- Retorna o número de padrões encontrados do tipo especificado
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);

Parâmetros

  • symbol  Símbolo selecionado para a busca.
  • timeframe  Período gráfico selecionado.
  • patternTipo de padrão existente da TYPE_PATTERN.
  • index,index1,index2,index3 Índice da vela de tipo simples (bloco 4 na Fig.1).

Valor de Retorno

O número de padrões encontrados do tipo especificado.

Implementação

A implementação deste método é bastante simples. As principais operações relacionadas à coleta de estatísticas são realizadas pelo método privado PatternStat().

//+------------------------------------------------------------------+
//| Retorna o número de padrões encontrados do tipo especificado     |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Retorna o número de padrões encontrados do tipo especificado     |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Retorna o número de padrões encontrados do tipo especificado     |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Retorna o número de padrões encontrados do tipo especificado     |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   return(m_found);
  }

O método PatternStat() possui dois tipos: para padrões existentes e gerados. Vamos examiná-los em detalhes. O primeiro é destinado a padrões da enumeração TYPE_PATTERN:

//+------------------------------------------------------------------+
//| Obtém estatísticas sobre o padrão dado                           |
//+------------------------------------------------------------------+
CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
//---
   int pattern_counter=0;
//---
   RATING_SET pattern_coef={0,0,0,0,0,0};
//---
   for(int i=m_range_total;i>4;i--)
     {
      if(CheckPattern(symbol,timeframe,i)==pattern)
        {
         pattern_counter++;
         if(pattern==HUMMER || pattern==INVERT_HUMMER || pattern==HANDING_MAN)
            GetCategory(symbol,timeframe,pattern_coef,i-3);
         else
            GetCategory(symbol,timeframe,pattern_coef,i-4);
        }
     }
//---
   CoefCalculation(pattern_coef,pattern_counter);
  }

O segundo é usado para padrões gerados que consistem em índices de tipos simples de velas.

//+------------------------------------------------------------------+
//| Obtém estatísticas sobre o padrão dado                           |
//+------------------------------------------------------------------+
void CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2=0,int index3=0)
  {
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2;
   RATING_SET rating={0,0,0,0,0,0};
   int pattern_total=0,pattern_size=1;
//---
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   ZeroMemory(cand3);
   ZeroMemory(cur_cand);
   ZeroMemory(prev_cand);
   ZeroMemory(prev_cand2);
//---
   if(index2>0)
      pattern_size=2;
   if(index3>0)
      pattern_size=3;
//---
   if(pattern_size==1)
      IndexToPatternType(cand1,index1);
   else if(pattern_size==2)
     {
      IndexToPatternType(cand1,index1);
      IndexToPatternType(cand2,index2);
     }
   else if(pattern_size==3)
     {
      IndexToPatternType(cand1,index1);
      IndexToPatternType(cand2,index2);
      IndexToPatternType(cand3,index3);
     }
//---
   for(int i=m_range_total;i>5;i--)
     {
      if(pattern_size==1)
        {
         //--- Obtém o tipo de vela atual
         GetCandleType(symbol,timeframe,cur_cand,i);                                       // Vela atual
         //---
         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-3);
           }
        }
      else if(pattern_size==2)
        {
         //--- Obtém o tipo de vela atual
         GetCandleType(symbol,timeframe,prev_cand,i);                                        // Vela anterior
         GetCandleType(symbol,timeframe,cur_cand,i-1);                                       // Vela atual
         //---

         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
            prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-4);
           }
        }
      else if(pattern_size==3)
        {
         //--- Obtém o tipo de vela atual
         GetCandleType(symbol,timeframe,prev_cand2,i);                                       // Vela anterior
         GetCandleType(symbol,timeframe,prev_cand,i-1);                                      // Vela anterior
         GetCandleType(symbol,timeframe,cur_cand,i-2);                                       // Vela atual
         //---
         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
            prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && 
            prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-5);
           }
        }
     }
//---
   CoefCalculation(rating,pattern_total);
  }

Essas duas implementações do método contêm um novo método. Este é o método privado CoefCalculation():

   //--- Calcula os coeficientes 
   bool              CoefCalculation(RATING_SET &rate,int found);

Ele processa todos os resultados obtidos ao buscar e testar padrões. Seus argumentos contêm um ponteiro para a estrutura RATING_SET, que é responsável pela coleta de dados referentes aos resultados do teste da eficiência padrão e ao número de padrões encontrados. Todos os outros parâmetros e propriedades dos padrões analisados são calculados no método CoefCalculation().

//+------------------------------------------------------------------+
//| Cálculo dos coeficientes de avaliação de eficiência              |
//+------------------------------------------------------------------+
bool CPattern::CoefCalculation(RATING_SET &rate,int found)
  {
   int sum1=0,sum2=0;
   sum1=rate.m_a_uptrend+rate.m_b_uptrend+rate.m_c_uptrend;
   sum2=rate.m_a_dntrend+rate.m_b_dntrend+rate.m_c_dntrend;
//---
   m_probability1=(found>0)?NormalizeDouble((double)sum1/found*100,2):0;
   m_probability2=(found>0)?NormalizeDouble((double)sum2/found*100,2):0;
   m_efficiency1=(found>0)?NormalizeDouble((m_k1*rate.m_a_uptrend+m_k2*rate.m_b_uptrend+m_k3*rate.m_c_uptrend)/found,3):0;
   m_efficiency2=(found>0)?NormalizeDouble((m_k1*rate.m_a_dntrend+m_k2*rate.m_b_dntrend+m_k3*rate.m_c_dntrend)/found,3):0;
   m_found=found;
   m_coincidence=((double)found/m_range_total*100);
   return(true);
  }

Coincidence

Retorna a frequência da ocorrência do padrão. Ele possui 3 sobrecargas de métodos para os padrões existentes TYPE_PATTERN, bem como para padrões gerados que consistem de 1-3 tipos simples de velas.

   //--- Retorna a frequência da ocorrência do padrão
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);

Parâmetros

  • symbolSímbolo selecionado para a busca.
  • timeframePeríodo gráfico selecionado.
  • patternTipo de padrão existente da TYPE_PATTERN.
  • index,index1,index2,index3Índice da vela de tipo simples (bloco 4 na Fig.1).

Valor de Retorno

A frequência de ocorrência do padrão em porcentagem.

Implementação

Semelhante ao método Found(). A única diferença é que ele retorna o valor da variável m_coincidence.

//+------------------------------------------------------------------+
//| Retorna a frequência da ocorrência do padrão                     |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Retorna a frequência da ocorrência do padrão                     |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Retorna a frequência da ocorrência do padrão                     |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Retorna a frequência da ocorrência do padrão                     |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   return(m_coincidence);
  }

Probability

Retorna a probabilidade percentual do movimento após o padrão especificado. Ele possui 3 sobrecargas de métodos para os padrões existentes TYPE_PATTERN, bem como para padrões gerados que consistem de 1-3 tipos simples de velas.

   //--- Retorna a probabilidade do movimento após o padrão especificado 
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);

Parâmetros

  • symbolSímbolo selecionado para a busca.
  • timeframePeríodo gráfico selecionado.
  • patternTipo de padrão existente da TYPE_PATTERN.
  • index,index1,index2,index 3Índice da vela de tipo simples (bloco 4 na Fig.1).

  • trendTYPE_TREND
//+------------------------------------------------------------------+
//| Tipo da tendência                                                |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Tendência de alta
   DOWN,                //Tendência de baixa
   FLAT                 //Lateralizado
  };
//+------------------------------------------------------------------+

Valor de Retorno

A probabilidade percentual do movimento após o padrão dado.

Implementação

Semelhante ao método Found(). A única diferença é que ele retorna o valor da variável m_probability1 ou m_probability2, dependendo do tipo da tendência selecionada.

//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,pattern);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }

Efficiency

Retorna o coeficiente de eficiência do padrão. Ele possui 3 sobrecargas de métodos para os padrões existentes TYPE_PATTERN, bem como para padrões gerados que consistem de 1-3 tipos simples de velas.

   //--- Retorna o coeficiente de eficiência do padrão 
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);

Parâmetros

  • symbolSímbolo selecionado para a busca.
  • timeframePeríodo gráfico selecionado.
  • patternTipo de padrão existente da TYPE_PATTERN.
  • index,index1,index2,index3Índice da vela de tipo simples (bloco 4 na Fig.1).
  • trendtrend type, TYPE_TREND
//+------------------------------------------------------------------+
//| Tipo da tendência                                                |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Tendência de alta
   DOWN,                //Tendência de baixa
   FLAT                 //Lateralizado
  };
//+------------------------------------------------------------------+

Valor de Retorno

O coeficiente de eficiência do padrão.

Implementação

Semelhante ao método Found(). A única diferença é que ele retorna o valor da variável m_efficiency1 ou m_efficiency2 dependendo do tipo da tendência selecionada.

//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,pattern);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| Retorna a probabilidade do movimento após o padrão dado          |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }

Uso prático

Tendo considerado as ferramentas para o trabalho com os padrões, vamos implementar dois indicadores e um Expert Advisor para demonstrar o uso da biblioteca.

CandleDetector

Vamos começar com o indicador que mostra em um gráfico uma vela do tipo selecionado da enumeração TYPE_CANDLESTICK. Crie a pasta Pattern na pasta de Indicators. Nesta pasta, crie o arquivo CandleDetector.mq5 no qual o indicador será criado. Vamos incluir a biblioteca Pattern.mqh para trabalhar com padrões e definir as propriedades iniciais do futuro indicador:

//+------------------------------------------------------------------+
//|                                               CandleDetector.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |  
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
#include <Pattern/Pattern.mqh>
//+----------------------------------------------+
//|  Parâmetros de desenho do indicador          |
//+----------------------------------------------+
//---- Exibição do rótulo do indicador
#property indicator_type1   DRAW_ARROW
//---- Largura da linha do indicador
#property indicator_width1  1

O próximo passo é determinar as principais configurações que afetarão a exibição deste ou daquele tipo de vela. 

//+----------------------------------------------+
//| Parâmetros de entrada do indicador           |
//+----------------------------------------------+
input TYPE_CANDLESTICK  CandleType=1;                 // Tipo de vela
input color             LabelColor=clrCrimson;
input double            LongCoef=1.3;
input double            ShortCoef=0.5;
input double            DojiCoef=0.04;
input double            MaribozuCoef=0.01;
input double            SpinCoef=1;
input double            HummerCoef1=0.1;
input double            HummerCoef2=2;
input int               TrendPeriod=5; 

Em seguida, na inicialização, configure a aparência do indicador e determine todos os valores dos parâmetros de entrada para a busca.

//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+
int OnInit()
  {
//---- Inicializa as variáveis de início do cálculo de dados
   min_rates_total=TrendPeriod+1;
//---- Define a precisão dos valores dos indicadores a serem exibidos
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- Configura o array dinâmico Signal[] como um buffer do indicador
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- Desloca por 1 o início do desenho do indicador
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- Define a indexação de elementos nos buffers como na série temporal   
   ArraySetAsSeries(Signal,true);
//---- Define os valores do indicador que não serão visíveis no gráfico
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- símbolo do indicador
   PlotIndexSetInteger(0,PLOT_ARROW,108);
//---
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor);
//----
   Pat.Long_coef(LongCoef);
   Pat.Short_coef(ShortCoef);
   Pat.Doji_coef(DojiCoef);
   Pat.Maribozu_coef(MaribozuCoef);
   Pat.Spin_coef(SpinCoef);
   Pat.Hummer_coef1(HummerCoef1);
   Pat.Hummer_coef2(HummerCoef2);
   Pat.TrendPeriod(TrendPeriod);
   return(INIT_SUCCEEDED);
  }

Preste atenção ao método CandleType() — ele é usado para buscar o tipo da vela selecionado no gráfico.

//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---- Verifica se existem barras suficientes para o cálculo
   if(rates_total<min_rates_total)
      return(0);
//---- Declara as variáveis locais 
   int limit,bar;
//---- Define a indexação de elementos nos buffers como na série temporal  
   ArraySetAsSeries(low,true);
//---- Calcula o 'primeiro' número inicial para o ciclo de recálculo das barras
   if(prev_calculated>rates_total || prev_calculated<=0)          // Verifica o primeiro início do cálculo do indicador
      limit=rates_total-min_rates_total;                          // Inicia o índice para calcular todas as barras
   else
      limit=rates_total-prev_calculated;                          // Inicia o índice para calcular novas barras
//---- Loop de cálculo do indicador principal
   for(bar=limit; bar>=0; bar--)
     {
      Signal[bar]=0.0;
      if(Pat.CandleType(Symbol(),PERIOD_CURRENT,bar)==CandleType)
         Signal[bar]=low[bar]-200*_Point;
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

O exemplo de funcionamento do indicador é mostrado na Fig.3 (Busca por uma vela de alta).

Fig.3 Exemplo do funcionamento do indicador CandleDetector.

PatternDetector

O segundo indicador buscará um padrão especificado da enumeração TYPE_PATTERN. A implementação é muito semelhante à anterior. Este código difere em um parâmetro de entrada e no método usado na parte do cálculo.

//+----------------------------------------------+
//| Parâmetros de entrada do indicador           |
//+----------------------------------------------+
input TYPE_PATTERN      PatternType=1;                // Tipo do padrão
input color             LabelColor=clrCrimson;
input double            LongCoef=1.3;
input double            ShortCoef=0.5;
input double            DojiCoef=0.04;
input double            MaribozuCoef=0.01;
input double            SpinCoef=1;
input double            HummerCoef1=0.1;
input double            HummerCoef2=2;
input int               TrendPeriod=5;
//---
CPattern Pat;
double Signal[];
//---- Declara as variáveis inteiras para o início do cálculo de dados
int min_rates_total;
//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+  
void OnInit()
  {
//---- Inicializa as variáveis de início do cálculo de dados
   min_rates_total=TrendPeriod+2;
//---- Define a precisão dos valores dos indicadores a serem exibidos
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- Configura o array dinâmico SignUp[] como um buffer do indicador
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- Desloca por 1 o início do desenho do indicador
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- Define a indexação de elementos nos buffers como na série temporal   
   ArraySetAsSeries(Signal,true);
//---- Define os valores do indicador que não serão visíveis no gráfico
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- símbolo do indicador
   PlotIndexSetInteger(0,PLOT_ARROW,108);
//---
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor);
//----
   Pat.Long_coef(LongCoef);
   Pat.Short_coef(ShortCoef);
   Pat.Doji_coef(DojiCoef);
   Pat.Maribozu_coef(MaribozuCoef);
   Pat.Spin_coef(SpinCoef);
   Pat.Hummer_coef1(HummerCoef1);
   Pat.Hummer_coef2(HummerCoef2);
   Pat.TrendPeriod(TrendPeriod);
  }
//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---- Verifica se existem barras suficientes para o cálculo
   if(rates_total<min_rates_total)
      return(0);
//---- Declara as variáveis locais 
   int limit,bar;
//---- Define a indexação de elementos nos buffers como na série temporal  
   ArraySetAsSeries(low,true);
//---- Calcula o 'primeiro' número inicial para o ciclo de recálculo das barras
   if(prev_calculated>rates_total || prev_calculated<=0)       // Verifica o primeiro início do cálculo do indicador
      limit=rates_total-min_rates_total;                       // Inicia o índice para calcular todas as barras
   else
      limit=rates_total-prev_calculated;                       // Inicia o índice para calcular novas barras
//---- Loop de cálculo do indicador principal
   for(bar=limit; bar>0; bar--)
     {
      Signal[bar]=0.0;
      if(Pat.PatternType(_Symbol,_Period,PatternType,bar))
         Signal[bar]=low[bar]-200*_Point;
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

Os resultados do funcionamento do PatternDetector são mostrados na Fig.4 (busca pelo padrão Engolfo de alta).

Fig.4 Exemplo do funcionamento do indicador PatternDetector.

Agora vamos criar um Expert Advisor, que pode encontrar padrões no gráfico e posições abertas, dependendo do padrão selecionado. Tipos de padrão individuais podem ser usados para cada tipo de negócio. Um modo adicional permitirá a escolha entre padrões existentes e padrões gerados usando os tipos simples de velas.

Vamos criar a pasta Pattern na pasta Experts e adicionar o PatternExpert.mq5, em que o código do EA será escrito. No primeiro estágio, inclua a biblioteca Pattern.mqh para trabalhar com os padrões e a biblioteca de operações de negociação Trade.mqh. Declare as instâncias de classe e introduza a enumeração PATTERN_MODE, que permite alternar entre os padrões existentes e gerados.

//+------------------------------------------------------------------+
//|                                                PatternExpert.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |  
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
#include <Pattern/Pattern.mqh>
#include "Trade.mqh" 
CTradeBase Trade;
CPattern Pat;
//+------------------------------------------------------------------+
//| Modo de busca do padrão                                          |
//+------------------------------------------------------------------+
enum PATTERN_MODE
  {
   EXISTING,
   GENERATED
  };

Agora defina os parâmetros de entrada do Expert Advisor. Os parâmetros do EA são fornecidos no primeiro bloco:

//+------------------------------------------------------------------+
//| Parâmetros de entrada do Expert Advisor                          |
//+------------------------------------------------------------------+
input    string               Inp_EaComment="Pattern Strategy";         // Comentário do EA
input    double               Inp_Lot=0.01;                             // Lote
input    MarginMode           Inp_MMode=LOT;                            // Gestão de capital

//--- Parâmetros do EA
input    string               Inp_Str_label="===EA parameters===";      // Rótulo
input    int                  Inp_MagicNum=1111;                        // Número mágico
input    int                  Inp_StopLoss=40;                          // Stop Loss(pontos)
input    int                  Inp_TakeProfit=30;                        // Take Profit(pontos)

A segunda parte contém as configurações e os parâmetros de negociação. 

//--- Parâmetros de negociação
input ENUM_TIMEFRAMES         Timeframe=PERIOD_CURRENT;                 // Período gráfico atual
input PATTERN_MODE            PatternMode=0;                            // Modo do padrão
input TYPE_PATTERN            BuyPatternType=ENGULFING_BULL;            // Tipo do padrão de compra
input TYPE_PATTERN            SellPatternType=ENGULFING_BEAR;           // Tipo do padrão de venda
input uint                    BuyIndex1=1;                              // BuyIndex do candle1 simples
input uint                    BuyIndex2=0;                              // BuyIndex do candle2 simples
input uint                    BuyIndex3=0;                              // BuyIndex do candle3 simples
input uint                    SellIndex1=1;                             // SellIndex do candle1 simples
input uint                    SellIndex2=0;                             // SellIndex do candle2 simples
input uint                    SellIndex3=0;                             // SellIndex do candle3 simples
input double                  LongCoef=1.3;                             // Coeficiente da vela de alta
input double                  ShortCoef=0.5;                            // Coeficiente da vela de baixa
input double                  DojiCoef=0.04;                            // Coeficiente da vela Doji
input double                  MaribozuCoef=0.01;                        // Coeficiente da vela Maribozu
input double                  SpinCoef=1;                               // Coeficiente da vela Spin
input double                  HummerCoef1=0.1;                          // Coeficiente da vela Martelo
input double                  HummerCoef2=2;                            // Coeficiente da vela Martelo
input int                     TrendPeriod=5;                            // Período da tendência

Vamos considerar alguns desses parâmetros em mais detalhes:

  • Período gráfico atual — período gráfico selecionado para as operações. Permite a seleção do período gráfico durante a otimização. O período gráfico atual do gráfico é selecionado por padrão.
  • Modo do padrão — modo de seleção do padrão. EXISTING — padrões existentes; duas configurações para o Tipo Padrão de Compra e Padrão de Venda são aplicáveis neste modo. GENERATED - padrões gerados. Neste modo, as configurações de Tipo de Padrão de Compra/Venda são ignoradas e BuyIndex1-3 e SellIndex1-3 são usadas no lugar.
  • Tipo do Padrão de Compra/ Tipo do Padrão de Venda — seleciona os padrões para abrir as operações de negociação apropriadas. 
  • BuyIndex1-3/SellIndex1-3 — seleciona um padrão gerado dos tipos de vela simples (Fig.1 Bloco 4), no momento em que uma posição comprada/vendida será aberta. 

Outros parâmetros são semelhantes aos indicadores considerados acima. Além da verificações, defina nos blocos de inicialização o valor do período da tendência que afeta a detecção dos padrões no gráfico.

//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Verifica a conexão com o servidor de negociação
   if(!TerminalInfoInteger(TERMINAL_CONNECTED))
     {
      Print(Inp_EaComment,": No Connection!");
      return(INIT_FAILED);
     }
//--- Verifica a permissão da negociação automatizada
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      Print(Inp_EaComment,": Trade is not allowed!");
      return(INIT_FAILED);
     }
//---
   Pat.TrendPeriod(TrendPeriod);
//---
   return(INIT_SUCCEEDED);
  }

A parte do cálculo é fácil de entender. Vamos considerar as funções de busca do sinal de compra e venda.

//+------------------------------------------------------------------+
//| Função Tick do Expert                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!Trade.IsOpenedByMagic(Inp_MagicNum))
     {
      //--- Abrindo uma ordem se houver um sinal de compra
      if(BuySignal())
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
      //--- Abrindo uma ordem se houver um sinal de venda
      if(SellSignal())
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
     }
  }

Essas funções são semelhantes e, portanto, vamos considerar apenas uma delas, a BuySignal(), que procura por um sinal de compra.

//+------------------------------------------------------------------+
//| Condições de Compra                                              |
//+------------------------------------------------------------------+
bool BuySignal()
  {
   if(PatternMode==0)
     {
      if(BuyPatternType==NONE)
         return(false);
      if(Pat.PatternType(_Symbol,Timeframe,BuyPatternType,1))
         return(true);
     }
   else if(PatternMode==1)
     {
      if(BuyIndex1>0 && BuyIndex2==0 && BuyIndex3==0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,1))
            return(true);
        }
      else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3==0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,1))
            return(true);
        }
      else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3>0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,BuyIndex3,1))
            return(true);
        }
     }
   return(false);
  }

A função contém uma verificação do modo atual selecionado, padrões existentes ou padrões gerados. Os parâmetros de entrada são selecionados de acordo: TYPE_PATTERN ou um conjunto de índices do padrão gerado.

Vamos testar e otimizar o Expert Advisor resultante em dois modos: com padrões existentes da enumeração TYPE_PATTERN e com padrões gerados que consistem nos tipos de velas simples mostrados no Bloco 4 da Fig.1.

O Expert Advisor será testado com os seguintes parâmetros:

  • Intervalo: para o modo Uptrend 01.01.2018 — 15.03.2018.
  • Par de moeda: EURUSD.
  • Modo de negociação: Sem atraso. Estas não são estratégias de negociação de alta frequência, portanto o efeito dos atrasos é mínimo.
  • Teste: 1 Minuto OHLC. 
  • Depósito inicial: 1000 USD.
  • Alavancagem: 1:500.
  • Servidor: MetaQuotes-Demo.
  • Cotação: 5-digit.

Modo Padrões Gerados.

Vamos determinar os parâmetros a serem testados e otimizados.

Fig.5 Conjunto de parâmetros para otimização no modo Padrões Gerados.

A Fig.5 mostra as condições de teste e otimização. Os melhores parâmetros obtidos como resultado do teste são mostrados na segunda coluna Value. Os resultados do teste e o gráfico são mostrados na Figura 6 abaixo. 

Fig.6 Resultado do teste de melhor parâmetro no modo Padrões Gerados.

Modo Padrões Existentes.

Defina os parâmetros para teste e otimização.

Fig.7 Conjunto de parâmetros para a otimização no modo Padrões Existentes. 

Novamente, os parâmetros do melhor resultado de otimização são mostrados na segunda coluna. Agora vamos realizar um único teste. Os resultados são mostrados abaixo, na Figura 8.

Fig.8 Resultado do teste de melhor parâmetro no modo Padrões Existentes.


Conclusões

O arquivo anexado abaixo contém todos os arquivos descritos corretamente organizados em pastas. Para uma operação correta, você deve salvar a pasta MQL5 na pasta raiz do terminal Para encontrar essa pasta raiz na qual a pasta MQL5 está localizada, pressione Ctrl+Shift+D na MetaTrader 5 ou use o menu de contexto conforme mostrado na Figura 9.

Fig.9 Como encontrar a pasta MQL5 na pasta raiz da MetaTrader5.

Programas utilizados no artigo

#
 Nome
Tipo
Descrição
1
Pattern.mqh Biblioteca  Biblioteca para trabalhar com os padrões
2 CandleDetector.mq5 Indicador  Indicador de busca de velas
3 PatternDetector.mq5 Indicador  Indicador de busca do padrão
4 PatternExpert.mq5  Expert Advisor   Um Expert Advisor de negociação que trabalha com os padrões
5 Trade.mqh Biblioteca  Classe de funções de negociação