Estudio de técnicas de análisis de velas (Parte III): Biblioteca para el trabajo con patrones
Contenido
- Introducción
- Estructura de la biblioteca
- Desarrollo de la biblioteca
- CandleType. Tipo de vela elegida
- PatternType. Tipo de patrón
- Found. Número de patrones del tipo establecido localizados
- Coincidence. Frecuencia del patrón del tipo establecido
- Probability. Probabilidad de movimiento después de aparecer el patrón establecido
- Efficiency. Coeficiente de efectividad del patrón establecido
- Aplicación práctica
- CandleDetector. Indicador de búsqueda de velas
- PatternDetector. Indicador de búsqueda de patrones
- PatternExpert. Asesor experto para trabajar con patrones
- Conclusión
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
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.
- pattern — Tipo 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
- symbol — Símbolo seleccionado para la búsqueda.
- timeframe — Marco temporal elegido.
- pattern — Tipo 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
- symbol — Símbolo seleccionado para la búsqueda.
- timeframe — Marco temporal elegido.
- pattern — Tipo 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).
- trend— Tipo 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
- symbol — Símbolo seleccionado para la búsqueda.
- timeframe — Marco temporal elegido.
- pattern — Tipo de patrón existente de la lista TYPE_PATTERN.
- index,index1,index2,index3 — Índice de la vela de tipo simple(bloque 4 fig.1).
- trend — Tipo 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 Ltd.
Artículo original: https://www.mql5.com/ru/articles/5751
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso