Estudio de técnicas de análisis de velas (Parte III): Biblioteca para el trabajo con patrones

19 junio 2019, 09:04
Alexander Fedosov
0
1 430

Contenido

Introducción

Los métodos de análisis de velas analizados anteriormente se enmarcaban dentro de una investigación cuyo objetivo en el primer artículo era comprobar cuán válidos son los patrones existentes en la realidad actual; mientras que en el segundo artículoconsistía en ampliar los límites de la investigación de este método de análisis del mercado. Los criterios de valoración desarrollados nos han permitido estudiar, poner a prueba y comparar un amplio abanico de combinaciones de patrones. Para ello, hemos desarrollado la aplicación personalizada Pattern Analyzer, que dispone de un enorme conjunto de ajustes para el análisis de patrones. Sin embargo, la teoría y la investigación solo nos proporcionan informacion y conclusiones. Y lo lógico sería utilizar dicha información en la práctica.

El objetivo de este artículo es crear una herramienta personalizada que nos permita obtener y usar la matriz completa de información sobre los patrones vistos anteriormente. Para ello, desarrollaremos una biblioteca que podremos utilizar en nuestros indicadores, paneles comerciales, expertos, etc.    


Estructura de la biblioteca

Antes de comenzar a crear la estructura de la biblioteca, las clases y las conexiones, debemos comprender claramente, con qué datos vamos a operar. Es decir, debemos separar los métodos responsables de los datos de entrada y aquellos que nos darán los resultados. Para que resulte más comprensible, la creación de la estructura general se apoyará en una solución visual desarrollada en los anteriores artículos, más concretamente en la aplicación Pattern Analyzer. 

Para comenzar, vamos a analizar todos los parámetros de entrada de la aplicación que de una forma u otra puedan influir en los resultados al simular los patrones.

Fig.1 Parámetros de entrada en la pestaña Ajustes.

Bloque 1. Aquí se representa la lista completa de tipos simples de vela de los que constan tanto los patrones existentes, como los generados. Cada uno de los tipos tiene sus ajustes, que podemos ver pulsando el icono de rueda dentada en la esquina superior derecha de la representación visual de la vela. Además, debemos notar, que para los tipos de vela del primero al quinto existe un solo ajuste, pero para la vela de tipo Martillo, existen dos. 

Bloque 2. Coeficientes de peso. Tienen tres parámetros К1, К2, К3 e influyen en los resultados de valoración de la efectividad de los patrones. 

Bloque 3. Valor umbral de la tendencia en puntos. 

Bloque 4. Velas usadas al realizar la simulación de los parámetros generados. Aquí vamos a necesitar los números ordinales o índices de las velas. De acuerdo con estos, obtendremos la información sobre cualquier patrón de cualquier dimensión hasta tres.

Bloque 5. Número de velas en el patrón. Asimismo, este ajuste se aplica solo a los patrones personalizados. 

A continuación, vamos a estudiar la pestaña Análisis, prestando especial atención a los parámetros de entrada en la misma.

Fig.2 Parámetros de entrada en la pestaña Análisis.

Bloque 6. En este bloque se ubican los ajustes del marco temporal actual, así como el Intervalo de muestra de datos en el que se investigan los patrones. 

Bloque 7. Nombres de los patrones existentes. También es, de alguna forma, un parámetro de entrada. Aunque no tiene posibilidad de realizar edición alguna en la aplicación, es necesario al recurrir a un patrón para obtener información sobre el mismo.

Ahora vamos a detallar qué información podemos obtener al investigar un patrón. Esto es necesario para componer correctamente la estructura de los métodos en la clase.

  • Patrones encontrados. Número de patrones encontrados del tipo indicado.
  • Frecuencia. Indicador en tanto por ciento del número de patrones encontrados respecto al intervalo de muestra total.
  • Probabilidad de movimiento hacia arriba y hacia abajo. 
  • Coeficientes de efectividad al moverse hacia arriba y hacia abajo para el modelo de vela establecido.

Desarrollo de la biblioteca

Bien, una vez hemos definido los puntos principales a cumplir antes de la implementación programática, vamos a crear la propia biblioteca. Para comenzar, vamos a crear el archivo con las enumeraciones necesarias Enums.mqh.

//+------------------------------------------------------------------+
//|                                                        Enums.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Candlestick type                                                 |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // Undefined
   CAND_MARIBOZU,       // Marubozu
   CAND_DOJI,           // Doji
   CAND_SPIN_TOP,       // Spinning Top
   CAND_HAMMER,         // Hammer
   CAND_INVERT_HAMMER,  // Inverted Hammer
   CAND_LONG,           // Long
   CAND_SHORT           // Short
  };
//+------------------------------------------------------------------+
//| Pattern type                                                     |
//+------------------------------------------------------------------+
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
  };
//+------------------------------------------------------------------+
//| Trend type                                                       |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Uptrend
   DOWN,                //Downtrend
   FLAT                 //Flat
  };
//+------------------------------------------------------------------+

Aquí vamos a definir la lista de tipos simples de vela, de tipos de patrones existentes y el tipo de tendencia, la información necesaria para identificar los patrones existentes en el gráfico.

A continuación, crearemos el archivo Pattern.mqh, en el que se creará la clase CPattern . Además, al inicio, en la sección privada, declararemos aquellas variables para los parámetros sobre las que hablamos en el artículo anterior. Asimismo, incluiremos de inmediato el archivo con las enumeraciones.

//+------------------------------------------------------------------+
//|                                                      Pattern.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#include "Enums.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CPattern
  {
private:
   //--- Weights
   double            m_k1;
   double            m_k2;
   double            m_k3;
   //--- Threshold trend value in points
   int               m_threshold_value;
   //--- Long candlestick setup coefficient
   double            m_long_coef;
   //--- Short candlestick setup coefficient
   double            m_short_coef;
   //--- Doji candlestick setup coefficient
   double            m_doji_coef;
   //--- Marubozu candlestick setup coefficient
   double            m_maribozu_coef;
   //--- Spinning Top candlestick setup coefficient
   double            m_spin_coef;
   //--- Hammer candlestick setup coefficient
   double            m_hummer_coef1;
   double            m_hummer_coef2;
   //--- Sampling range for the preset patterns
   int               m_range_total;
   //--- Period to determine the trend
   int               m_trend_period;
   //--- Found patterns
   int               m_found;
   //--- Occurrence of patterns
   double            m_coincidence;
   //--- Probability of upward or downward movement
   double            m_probability1;
   double            m_probability2;
   //--- Efficiency
   double            m_efficiency1;
   double            m_efficiency2;
   //--- Simple candlestick patterns
   struct CANDLE_STRUCTURE
     {
      double            m_open;
      double            m_high;
      double            m_low;
      double            m_close;                      // OHLC
      TYPE_TREND        m_trend;                      // Trend
      bool              m_bull;                       // Bullish candlestick
      double            m_bodysize;                   // Body size
      TYPE_CANDLESTICK  m_type;                       // Candlestick type
     };
   //--- Pattern efficiency evaluation properties
   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 podemos ver por el listado de arriba, se han añadido dos estructuras. La priemera, CANDLE_STRUCTURE, es necesaria para determinar el tipo de vela en el gráfico. Además, debemos prestar atención a que en ella se usan dos tipos de enumeraciones: el tipo de tendencia TYPE_TREND, y TYPE_CANDLESTICK del archivo Enums.mqh, analizados anteriormente y creados precisamente para esta estructura. La segunda estructura, RATING_SET, registra las valoraciones del movimiento del precio después de la aparición del patrón establecido. Podrá encontrar información más detallada sobre ello en el primer artículo.

Ahora, vamos a analizar una parte de la sección pública de la clase en la que se describen los métodos que permiten configurar y obtener los valores de los parámetros de entrada descritos en el apartado de la estructura de la biblioteca.

public:
                     CPattern(void);
                    ~CPattern(void);
   //--- Set and return weight coefficients
   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);                  }
   //--- Set and return the threshold trend value
   void              Threshold(const int threshold)                  { m_threshold_value=threshold;   }
   int               Threshold(void)                                 { return(m_threshold_value);     }
   //--- Set and return the long candlestick setup coefficient
   void              Long_coef(const double long_coef)               { m_long_coef=long_coef;         }
   double            Long_coef(void)                                 { return(m_long_coef);           }
   //--- Set and return the short candlestick setup coefficient
   void              Short_coef(const double short_coef)             { m_short_coef=short_coef;       }
   double            Short_coef(void)                                { return(m_short_coef);          }
   //--- Set and return the doji candlestick setup coefficient
   void              Doji_coef(const double doji_coef)               { m_doji_coef=doji_coef;         }
   double            Doji_coef(void)                                 { return(m_doji_coef);           }
   //--- Set and return the marubozu candlestick setup coefficient
   void              Maribozu_coef(const double maribozu_coef)       { m_maribozu_coef=maribozu_coef; }
   double            Maribozu_coef(void)                             { return(m_maribozu_coef);       }
   //--- Set and return the Spinning Top candlestick setup coefficient
   void              Spin_coef(const double spin_coef)               { m_spin_coef=spin_coef;         }
   double            Spin_coef(void)                                 { return(m_spin_coef);           }
   //--- Set and return the Hammer candlestick setup coefficient
   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);        }
   //--- Set and return the sampling range for preset parameters
   void              Range(const int range_total)                    { m_range_total=range_total;     }
   int               Range(void)                                     { return(m_range_total);         }
   //--- Set and return the number of candlesticks for trend calculation  
   void              TrendPeriod(const int period)                   { m_trend_period=period;         }
   int               TrendPeriod(void)                               { return(m_trend_period);        }

En el constructor de la clase, describimos los parámetros por defecto de la forma establecida en la aplicación, en las pestañas de Ajuste.

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

En la segunda parte de la sección pública de la clase CPattern, se describen los métodos de procesamiento de los parámetros de entrada declarados por nosotros, así como la obtención de las propiedades y características de los patrones investigados.

Vamos a analizar en profundidad cada uno de ellos, puesto que una mejor comprensión del algoritmo de funcionamiento nos permitirá usarlos con mayor eficacia al crear indicadores, paneles comerciales o expertos.

CandleType

Retorna el tipo de vela seleccionada de los patrones existentes, enumerados en la lista TYPE_CANDLESTICK.
TYPE_CANDLESTICK  CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift);

Parámetros

  • symbol — Símbolo seleccionado para la búsqueda
  • timeframe  Marco temporal elegido
  • shift  Índice de la vela seleccionada para el análisis, comenzando por 0.

Valor retornado

Tipo de vela seleccionada de la enumeración TYPE_CANDLESTICK.

//+------------------------------------------------------------------+
//| Candlestick type                                                 |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // Undefined
   CAND_MARIBOZU,       // Marubozu
   CAND_DOJI,           // Doji
   CAND_SPIN_TOP,       // Spinning Top
   CAND_HAMMER,         // Hammer
   CAND_INVERT_HAMMER,  // Inverted Hammer
   CAND_LONG,           // Long
   CAND_SHORT           // Short
  };

Implementación

//+------------------------------------------------------------------+
//| Returns the type of the selected candlestick                     |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Candlestick type recognition                                     |
//+------------------------------------------------------------------+
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);
//--- Get details of the previous candlestick
   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;

//--- Determine the trend direction
   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;
//--- Determine if it is a bullish or a bearish candlestick
   res.m_bull=res.m_open<res.m_close;
//--- Get the absolute size of candlestick body
   res.m_bodysize=MathAbs(res.m_open-res.m_close);
//--- Get sizes of shadows
   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;
//--- Calculate average body size of previous candlesticks
   double sum=0;
   for(int i=1; i<=aver_period; i++)
      sum=sum+MathAbs(rt[i].open-rt[i].close);
   sum=sum/aver_period;

//--- Determine the candlestick type   
   res.m_type=CAND_NONE;
//--- long 
   if(res.m_bodysize>sum*m_long_coef)
      res.m_type=CAND_LONG;
//--- sort 
   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;
//--- hammer
   if(shade_low>res.m_bodysize*m_hummer_coef2 && shade_high<res.m_bodysize*m_hummer_coef1)
      res.m_type=CAND_HAMMER;
//--- invert hammer
   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);
  }

En el método público CandleType(), se usa el método de reconocimiento de la vela GetCandleType(). Se trata de un método privado; sus argumentos incluyen el símbolo del instrumento actual, el marco temporal y el número de vela, aparte del puntero a la estructura. Con la ayuda de sus parámetros, se realiza el cálculo y la identificación del patrón.

PatternType

Reconoce el tipo de patrón con la vela elegida. Tiene 5 sobrecargas del método, debido a que sus argumentos pueden ser tanto los patrones existentes de la enumeración TYPE_PATTERN, como los generados que consten de una, dos o tres velas. Asimismo, también puede ser un argumento la matriz de patrones de la enumeración TYPE_PATTERN.

   //--- Recognizing the pattern type
   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);
   //--- Recognizing the set of patterns
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift);

Parámetros

  • symbol — Símbolo seleccionado para la búsqueda.
  • timeframe Marco temporal elegido.
  • pattern,pattern[] Tipo de patrón existente de la lista TYPE_PATTERN.

Puntero a la matriz de patrones existentes de la lista TYPE_PATTERN.

//+------------------------------------------------------------------+
//| Pattern type                                                     |
//+------------------------------------------------------------------+
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
  };
  • index,index1,index2,index3  Índice de la vela de tipo simple(bloque 4 fig.1).
  • shift  Índice de la vela seleccionada para el análisis, comenzando por 0.

Valor retornado

Valor del tipo bool.

Implementación

Puesto que existen 5 tipos de implementación del método PatternType, vamos a analizarlo por separado con diferentes argumentos. El primero de ellos busca cualquiera de los patrones establecidos de la enumeración TYPE_PATTERN ya existentes. Como podemos ver más abajo, para ello se usa el método privado CheckPattern.

//+------------------------------------------------------------------+
//| Recognizing a pre-defined pattern                                |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Checks and returns the pattern type                              |
//+------------------------------------------------------------------+
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);                                           // Previous candlestick
   GetCandleType(symbol,timeframe,cand1,shift-1);                                         // Current candlestick
//--- Inverted Hammer, bullish model
   if(cand2.m_trend==DOWN &&                                                              // Checking the trend direction
      cand2.m_type==CAND_INVERT_HAMMER)                                                   // Checking the "Inverted Hammer"
      pattern=INVERT_HUMMER;
//--- Hanging man, bearish
   else if(cand2.m_trend==UPPER && // Checking the trend direction
      cand2.m_type==CAND_HAMMER) // Checking "Hammer"
      pattern=HANDING_MAN;
//--- Hammer, bullish model
   else if(cand2.m_trend==DOWN && // Checking the trend direction
      cand2.m_type==CAND_HAMMER) // Checking "Hammer"
      pattern=HUMMER;
//--- Shooting Star, bearish model
   else if(cand1.m_trend==UPPER && cand2.m_trend==UPPER && // Checking the trend direction
      cand2.m_type==CAND_INVERT_HAMMER && cand1.m_close<=cand2.m_open) // Checking "Inverted Hammer"
      pattern=SHOOTING_STAR;
//--- Engulfing, bullish model
   else if(cand1.m_trend==DOWN && cand1.m_bull && cand2.m_trend==DOWN && !cand2.m_bull && // Checking trend direction and candlestick direction
      cand1.m_bodysize>cand2.m_bodysize &&
      cand1.m_close>=cand2.m_open && cand1.m_open<cand2.m_close)
      pattern=ENGULFING_BULL;
//--- Engulfing, bearish model
   else if(cand1.m_trend==UPPER && cand1.m_bull && cand2.m_trend==UPPER && !cand2.m_bull && // Checking trend direction and candlestick direction
      cand1.m_bodysize<cand2.m_bodysize &&
      cand1.m_close<=cand2.m_open && cand1.m_open>cand2.m_close)
      pattern=ENGULFING_BEAR;
//--- Harami Cross, bullish
   else if(cand2.m_trend==DOWN && !cand2.m_bull && // Checking trend direction and candlestick direction
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Checking the "long" first candlestick and the doji candlestick
      cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // Doji is inside the first candlestick body
      pattern=HARAMI_CROSS_BULL;
//--- Harami Cross, bearish model
   else if(cand2.m_trend==UPPER && cand2.m_bull && // Checking trend direction and candlestick direction
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Checking the "long" candlestick and the doji candlestick
      cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // Doji is inside the first candlestick body 
      pattern=HARAMI_CROSS_BEAR;
//--- Harami, bullish
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // Checking trend direction and candlestick direction
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Checking the "long" first candlestick
      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // The second candle is not Doji and first candlestick body is larger than that of the second one
                    cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // Second candlestick body is inside the first candlestick body 
                    pattern=HARAMI_BULL;
//--- Harami, bearish
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // Checking trend direction and candlestick direction
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Checking the "long" first candlestick

      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // The second candle is not Doji and first candlestick body is larger than that of the second one
                    cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // Second candlestick body is inside the first candlestick body 
                    pattern=HARAMI_BEAR;
//--- Doji Star, bullish
   else if(cand1.m_trend==DOWN && !cand2.m_bull && // Checking trend direction and candlestick direction
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Checking the 1st "long" candlestick and the 2nd doji
      cand1.m_close<=cand2.m_open) // Doji Open is lower or equal to 1st candle Close
      pattern=DOJI_STAR_BULL;
//--- Doji Star, bearish
   else if(cand1.m_trend==UPPER && cand2.m_bull && // Checking trend direction and candlestick direction
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Checking the 1st "long" candlestick and the 2nd doji
      cand1.m_open>=cand2.m_close) //Doji Open price is higher or equal to 1st candle Close
      pattern=DOJI_STAR_BEAR;
//--- Piercing, bullish model
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // Checking trend direction and candlestick direction
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Checking the "long" candlestick
      cand1.m_close>(cand2.m_close+cand2.m_open)/2 && // 2nd candle Close is above the middle of the 1st candlestick
      cand2.m_open>cand1.m_close && cand2.m_close>=cand1.m_open)
      pattern=PIERCING_LINE;
//--- Dark Cloud Cover, bearish
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // Checking trend direction and candlestick direction
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // Checking the "long" candlestick
      cand1.m_close<(cand2.m_close+cand2.m_open)/2 && // Close 2 is below the middle of the 1st candlestick body
      cand1.m_close<cand2.m_open && cand2.m_close<=cand1.m_open)
      pattern=DARK_CLOUD_COVER;
   return(pattern);
  }
//+------------------------------------------------------------------+

El siguiente tipo del método PatternType solo se diferencia del anterior en que se transmite la matriz de patrones buscados en lugar del argumento del tipo de patrón buscado:

//+------------------------------------------------------------------+
//| Recognizing an array of patterns                                 |
//+------------------------------------------------------------------+
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);
  }

A continuación, vamos a analizar la implementación del método PatternType para los patrones generados de tipos simples de vela. Como ya hemos dicho antes, hay tres tipos de patrones, que constan de una, dos y tres velas. Echémosles un vistazo uno por uno:

//+------------------------------------------------------------------+
//| Recognizing a pattern by candlestick index                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,int shift)
  {
//--- Verify the candlestick index
   if(index<0 || index>11)
      return(false);
//---
   CANDLE_STRUCTURE cand,cur_cand;
   RATING_SET ratings;
   ZeroMemory(cand);
   IndexToPatternType(cand,index);
//--- Get the current candlestick type
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Current candlestick
//---
   if(cur_cand.m_type==cand.m_type && cur_cand.m_bull==cand.m_bull)
      return(true);
   return(false);
  }

Esta es la implementación del método de búsqueda del patrón de una vela: en esencia, su sentido se parece al del método CandleType(), sin embargo, los argumentos transmitidos son diferentes en cuanto a su tipo y amplitud de muestra. Asimismo, en la implementación de este método debemos prestar atención al método IndextoPatternType(), que no se ha utilizado anteriormente:

   //--- Converts the candlestick index to its type
   void              IndexToPatternType(CANDLE_STRUCTURE &res,int index);

Este convierte el índice de un tipo simple de vela en su tipo, transmitiéndolo posteriormente a la estructura establecida.

A continuación, vamos a analizar el método para un patrón que consta de dos velas de tipo simple:

//+------------------------------------------------------------------+
//| Recognizing a pattern by candlestick index                       |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int shift)
  {
//--- Verify the candlestick index
   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);
//--- Get the current candlestick type
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // Previous candlestick
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Current candlestick
//---
   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);
  }

La implementación es muy similar a la anterior, pero en la actual, hay que prestar atención a una particularidad al elegir el índice de la vela para el análisis: dado que el patrón consta de dos velas, el tipo de vela index1 será para la vela desplazada en shift, y el tipo index2, para la desplazada en shift+1. La misma peculiaridad concierne a la implementación del método para el patrón de tres velas:

//+------------------------------------------------------------------+
//| Recognizing a pattern by candlestick index                       |
//+------------------------------------------------------------------+
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);

//--- Get the current candlestick type
   GetCandleType(symbol,timeframe,prev_cand2,shift+2);                            // Previous candlestick
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // Previous candlestick
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // Current candlestick
//---
   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 el número de patrones del tipo establecido localizados Tiene 3 sobrecargas del método para los patrones TYPE_PATTERN existentes, y también para los patrones generados que consten 1-3 tipos simples de vela.

   //--- Returns the number of found patterns of the specified type
   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 seleccionado para la búsqueda.
  • timeframe  Marco temporal elegido.
  • patternTipo de patrón existente de la lista TYPE_PATTERN.
  • index,index1,index2,index3 Índice de la vela de tipo simple(bloque 4 fig.1).

Valor retornado

Número de patrones del tipo establecido localizados.

Implementación

El propia implementación programática de este método es bastante sencilla. La mayor parte del trabajo de recopilación de estadísticas lo realiza el método privado PatternStat().

//+------------------------------------------------------------------+
//| Returns the number of found patterns of the specified type       |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Returns the number of found patterns of the specified type       |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Returns the number of found patterns of the specified type       |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| Returns the number of found patterns of the specified type       |
//+------------------------------------------------------------------+
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);
  }

El propio método PatternStat() tiene dos tipos, para los patrones existentes y para los generados. Vamos a verlos con detalle. El primero de ellos es para los patrones de la enumeración TYPE_PATTERN:

//+------------------------------------------------------------------+
//| Get statistics on the given pattern                              |
//+------------------------------------------------------------------+
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);
  }

El segundo es para los patrones generados compuestos mediante los índices de los tipos simples de vela.

//+------------------------------------------------------------------+
//| Get statistics on the given pattern                              |
//+------------------------------------------------------------------+
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)
        {
         //--- Get the current candlestick type
         GetCandleType(symbol,timeframe,cur_cand,i);                                       // Current candlestick
         //---
         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)
        {
         //--- Get the current candlestick type
         GetCandleType(symbol,timeframe,prev_cand,i);                                        // Previous candlestick
         GetCandleType(symbol,timeframe,cur_cand,i-1);                                       // Current candlestick
         //---

         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)
        {
         //--- Get the current candlestick type
         GetCandleType(symbol,timeframe,prev_cand2,i);                                       // Previous candlestick
         GetCandleType(symbol,timeframe,prev_cand,i-1);                                      // Previous candlestick
         GetCandleType(symbol,timeframe,cur_cand,i-2);                                       // Current candlestick
         //---
         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);
  }

En ambas implementaciones del método encontramos otro más que antes no habíamos visto. Se trata del método privado CoefCalculation():

   //--- Calculates coefficients 
   bool              CoefCalculation(RATING_SET &rate,int found);

Dicho método procesa todos los resultados obtenidos al buscar y simular un patrón. Y precisamente en sus argumentos se encuentra el puntero a la estructura RATING_SET, encargada de la recopilación de datos sobre los resultados de la simulación de la efectividad del patrón y sobre el número de patrones encontrados. En el propio método CoefCalculation() tiene lugar el cálculo de los demás indicadores y propiedades de los patrones investigados, que veremos un poco más tarde.

//+------------------------------------------------------------------+
//| Calculating efficiency assessment coefficients                   |
//+------------------------------------------------------------------+
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 la frecuencia de aparición del patrón establecido en tanto por ciento. Tiene 3 sobrecargas del método para los patrones TYPE_PATTERN existentes, y también para los patrones generados que consten 1-3 tipos simples de vela.

   //--- Returns the frequency of the pattern occurrence
   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 seleccionado para la búsqueda.
  • timeframeMarco temporal elegido.
  • patternTipo de patrón existente de la lista TYPE_PATTERN.
  • index,index1,index2,index3Índice de la vela de tipo simple(bloque 4 fig.1).

Valor retornado

Frecuencia de aparición del patrón establecido en tanto por ciento.

Implementación

Análoga al método Found(), la única diferencia es que se retorna el valor de la variable m_coincidence.

//+------------------------------------------------------------------+
//| Returns the frequency of the pattern occurrence                  |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Returns the frequency of the pattern occurrence                  |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Returns the frequency of the pattern occurrence                  |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| Returns the frequency of the pattern occurrence                  |
//+------------------------------------------------------------------+
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 la probabilidad de movimiento tras el patrón establecido en tanto por ciento. Tiene 3 sobrecargas del método para los patrones TYPE_PATTERN existentes, y también para los patrones generados que consten 1-3 tipos simples de vela.

   //--- Returns the probability of movement after the given pattern 
   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 seleccionado para la búsqueda.
  • timeframeMarco temporal elegido.
  • patternTipo de patrón existente de la lista TYPE_PATTERN.
  • index,index1,index2,index 3Índice de la vela de tipo simple(bloque 4 fig.1).

  • trendTipo de tendencia TYPE_TREND
//+------------------------------------------------------------------+
//| Trend type                                                       |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Uptrend
   DOWN,                //Downtrend
   FLAT                 //Flat
  };
//+------------------------------------------------------------------+

Valor retornado

Probabilidad de movimiento tras el patrón establecido en tanto por ciento.

Implementación

Análoga al método Found(), la única diferencia es que se retorna el valor de la variable m_probability1 o m_probability2, dependiendo del tipo de tendencia elegida.

//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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 el coeficiente de efectividad del patrón establecido. Tiene 3 sobrecargas del método para los patrones TYPE_PATTERN existentes, y también para los patrones generados que consten 1-3 tipos simples de vela.

   //--- Returns the pattern efficiency coefficient 
   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 seleccionado para la búsqueda.
  • timeframeMarco temporal elegido.
  • patternTipo de patrón existente de la lista TYPE_PATTERN.
  • index,index1,index2,index3Índice de la vela de tipo simple(bloque 4 fig.1).
  • trendTipo de tendencia TYPE_TREND
//+------------------------------------------------------------------+
//| Trend type                                                       |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               //Uptrend
   DOWN,                //Downtrend
   FLAT                 //Flat
  };
//+------------------------------------------------------------------+

Valor retornado

Coeficiente de efectividad del patrón establecido.

Implementación

Análoga al método Found(), la única diferencia es que se retorna el valor de la variable m_efficiency1 o m_efficiency2, dependiendo del tipo de tendencia elegida.

//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Returns the probability of movement after the given pattern      |
//+------------------------------------------------------------------+
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);
  }

Aplicación práctica

Una vez analizadas las herramientas de trabajo, vamos a implementar dos indicadores y un experto comercial como ejemplo de uso de esta biblioteca.

CandleDetector

En primer lugar, implementaremos un indicador que mostrará en el gráfico una vela del tipo que establezcamos de la lista TYPE_CANDLESTICK. Vamos a crear la carpeta Pattern en la carpeta Indicators. En ella, crearemos un archivo con el nombre CandleDetector.mq5, y en este, procederemos a la creación del indicador. Asimismo, incluiremos la biblioteca Pattern.mqh, para acceder al trabajo con patrones, además de ajustar las propiedades iniciales del 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>
//+----------------------------------------------+
//|  Indicator drawing parameters                |
//+----------------------------------------------+
//---- Drawing the indicator as a label
#property indicator_type1   DRAW_ARROW
//---- Indicator line width
#property indicator_width1  1

El siguiente paso consistirá en determinar los ajustes clave que influirán en la representación de este u otro tipo de vela. 

//+----------------------------------------------+
//| Indicator input parameters                   |
//+----------------------------------------------+
input TYPE_CANDLESTICK  CandleType=1;                 // Candlestick type
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; 

A continuación, configuramos en la inicialización el aspecto del indicador, determinando además para la búsqueda del indicador todos los valores de los parámetros de entrada.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//---- Initialize variables of data calculation start
   min_rates_total=TrendPeriod+1;
//---- Define the accuracy of indicator values to be displayed
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- Set the dynamic array Signal[] as an indicator buffer
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- Shift indicator 1 drawing start
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- Set indexing of elements in buffers as in timeseries   
   ArraySetAsSeries(Signal,true);
//---- Set indicator values which will not be visible on the chart
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- Indicator symbol
   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);
  }

En la parte del indicador dedicada a los cálculos, solo debemos prestar atención al método CandleType() utilizado para la búsqueda del tipo de vela en el gráfico.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---- Check if there are enough bars for calculation
   if(rates_total<min_rates_total)
      return(0);
//---- Declare local variables 
   int limit,bar;
//---- Set indexing of elements in arrays as in timeseries  
   ArraySetAsSeries(low,true);
//---- Calculate the 'first' starting number for the bars recalculation cycle
   if(prev_calculated>rates_total || prev_calculated<=0)          // Check the first start of indicator calculation
      limit=rates_total-min_rates_total;                          // Starting index for calculating all bars
   else
      limit=rates_total-prev_calculated;                          // Starting index for calculating new bars
//---- Main indicator calculation loop
   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);
  }
//+------------------------------------------------------------------+

Más abajo, podemos ver un ejemplo del funcionamiento de este indicador en la fig.3 (búsqueda del tipo de vela Larga).

Fig.3 Ejemplo de funcionamiento del indicador CandleDetector.

PatternDetector

El segundo indicador para el ejemplo, será un indicador que busca en el gráfico el patrón establecido de la enumeración TYPE_PATTERN. La implementación programática es muy similar a la anterior, la única diferencia reside en un parámetro de entrada, así como en el método usado en la parte dedicada a los cálculos.

//+----------------------------------------------+
//| Indicator input parameters                   |
//+----------------------------------------------+
input TYPE_PATTERN      PatternType=1;                // Pattern type
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[];
//---- Declare integer variables for the data calculation start
int min_rates_total;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+  
void OnInit()
  {
//---- Initialize variables of data calculation start
   min_rates_total=TrendPeriod+2;
//---- Define the accuracy of indicator values to be displayed
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- Set SignUp[] dynamic array as an indicator buffer
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- Shift indicator 1 drawing start
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- Set indexing of elements in buffers as in timeseries   
   ArraySetAsSeries(Signal,true);
//---- Set indicator values which will not be visible on the chart
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- Indicator symbol
   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);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---- Check if there are enough bars for calculation
   if(rates_total<min_rates_total)
      return(0);
//---- Declare local variables 
   int limit,bar;
//---- Set indexing of elements in arrays as in timeseries  
   ArraySetAsSeries(low,true);
//---- Calculate the 'first' starting number for the bars recalculation cycle
   if(prev_calculated>rates_total || prev_calculated<=0)       // Check the first start of indicator calculation
      limit=rates_total-min_rates_total;                       // Starting index for calculating all bars
   else
      limit=rates_total-prev_calculated;                       // Starting index for calculating new bars
//---- Main indicator calculation loop
   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);
  }
//+------------------------------------------------------------------+

Los resultados del funcionamiento del indicador PatternDetector se muestran en la fig.4 (búsqueda del patrón Envolvente - modelo alcista).

Fig.4 Ejemplo de funcionamiento del indicador PatternDetector.

Bien, ahora vamos a crear un experto comercial que buscará en el gráfico los patrones establecidos y abrirá posiciones dependiendo del patrón seleccionado. En este caso, además, para cada tipo de transacción en este asesor se podrá usar un tipo de patrón propio. Aparte, usaremos un modo en el que los patrones se podrán elegir de entre los existentes o de los generados a partir de tipos simples de vela.

Para comenzar, vamos a crear en la carpeta Experts la carpeta Pattern, y en ella, el archivo PatternExpert.mq5, en el que escribiremos el código del futuro experto comercial. En la primera etapa, incluimos la biblioteca para trabajar con patrones Pattern.mqh, así como la biblioteca de operaciones comerciales Trade.mqh. Declaramos los ejemplares de la clases e introducimos la enumeración PATTERN_MODE, necesaria para alternar entre los patrones existentes y los generados.

//+------------------------------------------------------------------+
//|                                                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;
//+------------------------------------------------------------------+
//| Pattern search mode                                              |
//+------------------------------------------------------------------+
enum PATTERN_MODE
  {
   EXISTING,
   GENERATED
  };

Ahora, vamos a decidir los parámetros de entrada del experto comercial. En el primer bloque, estarán los siguientes parámetros del experto:

//+------------------------------------------------------------------+
//| Expert Advisor input parameters                                  |
//+------------------------------------------------------------------+
input    string               Inp_EaComment="Pattern Strategy";         // EA Comment
input    double               Inp_Lot=0.01;                             // Lot
input    MarginMode           Inp_MMode=LOT;                            // Money Management

//--- EA parameters
input    string               Inp_Str_label="===EA parameters===";      // Label
input    int                  Inp_MagicNum=1111;                        // Magic number
input    int                  Inp_StopLoss=40;                          // Stop Loss(points)
input    int                  Inp_TakeProfit=30;                        // Take Profit(points)

En la segunda parte, se encontrarán los parámetros para los ajustes y el comercio. 

//--- Trading parameters
input ENUM_TIMEFRAMES         Timeframe=PERIOD_CURRENT;                 // Current Timeframe
input PATTERN_MODE            PatternMode=0;                            // Pattern Mode
input TYPE_PATTERN            BuyPatternType=ENGULFING_BULL;            // Buy Pattern Type
input TYPE_PATTERN            SellPatternType=ENGULFING_BEAR;           // Sell Pattern Type
input uint                    BuyIndex1=1;                              // BuyIndex of simple candle1
input uint                    BuyIndex2=0;                              // BuyIndex of simple candle2
input uint                    BuyIndex3=0;                              // BuyIndex of simple candle3
input uint                    SellIndex1=1;                             // SellIndex of simple candle1
input uint                    SellIndex2=0;                             // SellIndex of simple candle2
input uint                    SellIndex3=0;                             // SellIndex of simple candle3
input double                  LongCoef=1.3;                             // Long candle coef
input double                  ShortCoef=0.5;                            // Short candle coef
input double                  DojiCoef=0.04;                            // Doji candle coef
input double                  MaribozuCoef=0.01;                        // Maribozu candle coef
input double                  SpinCoef=1;                               // Spin candle coef
input double                  HummerCoef1=0.1;                          // Hummer candle coef1
input double                  HummerCoef2=2;                            // Hummer candle coef2
input int                     TrendPeriod=5;                            // Trend Period

Vamos a ver algunos de ellos con mayor detalle:

  • Current Timeframe — Marco temporal de trabajo elegido. Cómodo a la hora de optimizar Por defecto, se encuentra el actual en el gráfico.
  • Pattern Mode — Modo de selección de patrones. EXISTING — patrones existentes. Al elegir esta opción, funcionan los dos siguientes ajustes Buy Pattern Type y Sell Pattern Type. GENERATED - patrones generados. Con esta opción, Buy/Sell Pattern Type son ignorados, y se usan BuyIndex1-3 y SellIndex1-3.
  • Buy Pattern Type/ Sell PAtternType — seleccionar un patrón cuya aparición conllevará la apertura de una posición larga/corta. 
  • BuyIndex1-3/SellIndex1-3 — selccionar un patrón compuesto de tipos simples de vela (fig.1 Bloque 4), cuya aparición conllevará la apertura de una posición larga/corta. 

Los demás parámetros permanecen igual que en los indicadores analizados anteriormente. En el bloque de inicialización, aparte de definir las comprobaciones, establecemos el valor Trend Period, que influye en la detección de los patrones en el gráfico.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Checking connection to the trade server
   if(!TerminalInfoInteger(TERMINAL_CONNECTED))
     {
      Print(Inp_EaComment,": No Connection!");
      return(INIT_FAILED);
     }
//--- Checking automated trading permission
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      Print(Inp_EaComment,": Trade is not allowed!");
      return(INIT_FAILED);
     }
//---
   Pat.TrendPeriod(TrendPeriod);
//---
   return(INIT_SUCCEEDED);
  }

La parte dedicada a los cálculos es fácil de comprender, sin embargo, vamos a analizar cómo funcionan las funciones de búsqueda de las señales de venta y compra.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!Trade.IsOpenedByMagic(Inp_MagicNum))
     {
      //--- Opening an order if there is a buy signal
      if(BuySignal())
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
      //--- Opening an order if there is a sell signal
      if(SellSignal())
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
     }
  }

Ambas funciones son análogas, por eso, vamos a analizar una de ellas, BuySignal(), la búsqueda de señales de compra.

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

En la propia función, se comprueba en primer lugar qué modo ha sido establecido: patrones existentes o generados. Partiendo de ello, se usan los parámetros de entrada, o bien TYPE_PATTERN, o bien el conjunto de índices del patrón generado.

Ahora, realizamos la simulación y optimización del asesor comercial obtenido en dos modos: con los patrones existentes de la enumeración TYPE_PATTERN y con ayuda de los patrones generados de las velas de tipo simple en la misma fig.1 en el cuarto bloque.

Para la simulación del experto comercial obtenido, seleccionaremos los parámetros iniciales:

  • Intervalo: Para el modo Uptrend 01.01.2018 — 15.03.2018.
  • Pareja de divisas: EURUSD.
  • Modo de comercio: Sin retrasos. Las estaretegias no se relacionan con las de alta precisión, por eso la influencia de los retrasos es muy pequeña.
  • Simulación: OHLC en М1. 
  • Depósito inicial: 1000 USD.
  • Apalancamiento: 1:500.
  • Servidor: MetaQuotes-Demo.
  • Cotizaciones: de 5 dígitos.

Modo de patrones generados.

Vamos a elegir los parámetros que serán simulados y optimizados.

Fig.5 Conjunto de parámetros optimizados en el modo de patrones generados.

En la fig.5 se muestran las condiciones de simulación y optimización, asimismo, en la segunda columna Valor, se muestran los mejores patrones según los resultados de la simulación. El propio gráfico y los resultados del backtest se muestran en la fig.6, un poco más abajo. 

Fig.6 Resultados de la simulación de los mejores parámetros en el modo de patrones generados.

Modo de patrones existentes.

Vamos a establecer los parámetros de simulación y optimización.

Fig.7 Conjunto de parámetros optimizados en el modo de patrones existentes. 

Al igual que en la anterior simulación, en la segunda columna se muestran los parámetros del mejor resultado de la optimización. AHora, vamos a realizar un test único, cuyos resultados se podrán observar en la fig.8, un poco más abajo.

Fig.8 Resultados de la simulación de los mejores parámetros en el modo de patrones existentes.


Conclusión

Al final del artículo se adjunta un fichero con todos los archivos enumerados, clasificados por carpetas. Por eso, para que funcione correctamente, basta con colocar la carpeta MQL5 en la carpeta raíz del terminal. Para encontrar la carpeta raíz del terminal en la que se encuentra la carpeta MQL5, debemos pulsar en MetaTarder5 la combinación de teclas Ctrl+Shift+D o usar el menú contextual como se muestra en la fig.9, más abajo.

Fig.9 Búsqueda de la carpeta MQL5 en la carpeta raíz de MetaTrader5.

Programas usados en el artículo:

#
 Nombre
Tipo
Descripción
1
Pattern.mqh Biblioteca  Biblioteca para trabajar con patrones
2 CandleDetector.mq5 Indicador  Indicador de búsqueda de velas
3 PatternDetector.mq5 Indicador  Indicador de búsqueda de patrones
4 PatternExpert.mq5  Experto   Asesor experto para trabajar con patrones
5 Trade.mqh Biblioteca  Clase de funciones comerciales



Traducción del ruso hecha por MetaQuotes Software Corp.
Artículo original: https://www.mql5.com/ru/articles/5751

Archivos adjuntos |
MQL5.zip (452.51 KB)
Optimización de color de estrategias comerciales Optimización de color de estrategias comerciales

En este artículo, vamos a realizar un experimento del coloreo de los resultados de la optimización. Como se sabe, el color se determina por tres parámetros: los niveles del color rojo, verde y azul (RGB en inglés, Red — rojo, Green — verde, Blue — azul). Hay otros métodos de codificar el color, pero igualmente se usan tres parámetros. Así, tres parámetros de la simulación pueden ser convertidos en un color que el trader percibe visualmente. Lea este artículo para averiguar si esta representación va a ser útil.

Indicadores MTF como herramienta de análisis técnico Indicadores MTF como herramienta de análisis técnico

La mayoría de nosotros estamos de acuerdo en que el proceso de análisis de la situación actual de mercado comienza por el estudio de los marcos temporales mayores del gráfico. Esto sucede hasta que pasemos al gráfico en el que realizamos las transacciones. Esta opción de análisis es una de las condiciones del comercio exitoso, indispensable para lograr un enfoque profesional de dicha tarea. En este artículo, vamos a hablar sobre los indicadores de marco temporal múltiple y los métodos de creación de los mismos. Mostraremos ejemplos de código en MQL5, realizaremos una valoración de los puntos fuertes y débiles de cada versión, y también ofreceremos un nuevo enfoque respecto a los indicadores que usan el modo MTF.

Cómo escribir una biblioteca DLL para MQL5 en 10 minutos (Parte II): Escribiendo en el entorno de Visual Studio 2017 Cómo escribir una biblioteca DLL para MQL5 en 10 minutos (Parte II): Escribiendo en el entorno de Visual Studio 2017

El artículo original «básico» de ningún modo perdió su actualidad, y todos los interesados en este asunto deben leerlo sí o sí. Pero ya pasó bastante tiempo desde aquel entonces, y ahora la versión Visual Studio 2017 es de la actualidad, disponiendo de una interfaz ligeramente modificada, mientras que la propia plataforma MetaTrader 5 tampoco estaba sin desarrollo. El presente artículo describe las etapas de la creación del proyecto DLL, sus configuraciones y el trabajo común con las herramientas del terminal MetaTrader 5.

Utilidad para la selección y navegación en MQL5 y MQL4: aumentando la informatividad de los gráficos Utilidad para la selección y navegación en MQL5 y MQL4: aumentando la informatividad de los gráficos

En este artículo, continuaremos expandiendo la funcionalidad de nuestra utilidad. Esta vez, añadiremos las posibilidades de visualizar la información en el gráfico, que sirve para facilitar nuestra negociación. En particular, añadiremos en el gráfico los precios máximos y mínimos del día anterior, niveles redondos, precios máximos y mínimos durante el año, hora del inicio de la sesión, etc.