Estudio de las figuras técnicas de Merrill
Contenido
Introducción
El primer intento de crear un sistema de las figuras de precios fue tomado por Robert Levy en 1971. Usaba las figuras de cinco puntas de la oscilación del precio, y luego, testeaba su relevancia. No consiguió resultados significativos, pero dentro de 10 años, su trabajo fue continuado por Arthur Merrill.
Dividió las figuras en dos categorías, que tenían la forma de las letras inglesas M y W. Cada categoría contaba con 16 figuras. Además, cada categoría tenía sus propias subcategorías. Merrill propuso 6 subcategorías:
- Tendencia alcista
- Tendencia bajista
- Triángulo
- Expansión
- Cabeza y hombros
- Cabeza y hombros invertida
Nuestra tarea consiste en averiguar hasta qué punto las figuras técnicas de Merrill nos pueden ser útiles en las condiciones actuales. Para eso, ha sido diseñada una aplicación que nos permitirá ejecutar el testeo. Aparte de eso, sería interesante aplicar este modelo a diferentes tipos de datos, tales como el precio de cierre, sus máximos y mínimos y los indicadores del tipo oscilatorio.
Teoría y área de aplicación
Para que esté bien claro de qué manera y para qué datos de entrada vamos a aplicar el modelo de las figuras técnicas de Merrill, es necesario aclarar qué es lo que representan. Hay dos categorías principales: son figuras que tienen la forma de las letras inglesas M y W. Se llaman los patrones de M y los patrones de W. Cada una de estas categorías incluye 16 figuras.
En la figura 1, se muestran 16 patrones M que, de una manera u otra, parecen a la letra M. Como podemos observar, su diferencia consiste en la ubicación mutua de cinco puntos que forman el patrón:
Fig. 1 Representación visual de los patrones M
La figura 2 muestra 16 patrones W que parecen a la letra W. Vamos a encontrar un conjunto común de estos dos grupos en los gráficos de precios y en los indicadores, además, vamos a analizar, evaluar y buscar posibles regularidades.
Fig. 2 Representación visual de los patrones W
Es que la idea esencial de cualquier patrón consiste en lo siguiente: cuando aparece una u otra formación, esperar, con un determinado grado de probabilidad, la aparición del precio en la dirección deseada y obtener el beneficio.
Vamos a mostrar unos ejemplos para aclarar al máximo en qué campo y cómo vamos a analizar las figuras técnicas de Merrill. En la figura 3, se muestra un gráfico lineal habitual de los precios de USDCAD en el marco temporal (timeframe) H1. Hoy en día, este tipo de representación no se usa muy a menudo, porque las velas japonesas y las barras han encontrado mayor aceptación.
Fig. 3 Gráfico lineal de los precios de cierre de USDCAD, en H1
Aquí, incluso a simple vista, podemos identificar algunas figuras técnicas descritas más arriba. Será el primer campo del estudio, es decir, la aplicación al gráfico lineal con los precios de cierre. Además, comprobaremos los gráficos lineales con los precios de apertura, máximos y mínimos.
El segundo campo del análisis abarca los indicadores del tipo oscilatorio:
- Average True Range (ATR) — indicador de la volatilidad del mercado.
- Commodity Channel Index (CCI) — índice del canal que mide la desviación del precio del instrumento financiero de su precio medio estadístico.
- DeMarker (DeM) — indicador técnico de Demark.
- Force Index (FRC) — indicador técnico del índice de fuerza.
- Williams’ Percent Range (WPR) — rango porcentual de Williams, indicador dinámico que determina el estado de sobrecompra/sobreventa.
- Relative Strength Index (RSI) — indicador técnico «Índice de fuerza relativa».
- Momentum — indicador técnico del ritmo. Mide la variación del precio de un instrumento financiero durante un determinado período de tiempo.
Como método para evaluar las figuras técnicas que van a aplicarse tanto al precio, como a los indicadores oscilatorios descritos, usaremos la técnica propuesta en mi artículo Estudio de técnicas de análisis de velas (Parte I): comprobando los patrones existentes. Su idea es bastante simple:
- Identificación de la figura técnica analizada en la parte especificada de la muestra.
- Análisis del movimiento del precio después de la identificación.
- Recopilación de los datos obtenidos y cálculo de la eficacia de la figura técnica.
Desarrollando la herramientas para el testeo
Antes de empezar a desarrollar las herramientas, tenemos que aclarar qué configuraciones y ajustes debe contener. Va a incluir un panel con dos pestañas: Análisis y Configuraciones. Además, usaremos los ajustes de la ventana de las configuraciones del EA. En total, habrá tres secciones principales que incluirán sus herramientas para trabajar con figuras técnicas. Ahora, describiremos las configuraciones de cada sección.
La pestaña Análisis incluye lo siguiente:
- Dos conjuntos de botones para seleccionar los tipos de las figuras técnicas a testear. Además, incluye los botones All M y All W para seleccionar/quitar rápidamente los grupos de figuras tipo M y W.
- Conjunto de botones para seleccionar los timeframes a testear y el botón ALL para seleccionar/quitar el grupo entero de botones.
- Campo de entrada «Valor límite de tendencia en puntos». Es un valor del beneficio en puntos que debe ser alcanzado por el precio máximo a lo largo de tres velas tras la identificación de la figura de Merrill analizada.
- Botón que abre la ventana de diálogo para seleccionar la fecha Inicial y Final y la hora del testeo.
- Campo de entrada con casilla de verificación (checkbox) y un botón representa un filtro para buscar instrumentos financieros necesarios. Tiene un preset — Major. Muestra los pares de divisas mayores. El checkbox desactiva el filtro y muestra todos los instrumentos disponibles.
- Los símbolos seleccionados en la tabla a través del filtro, al seleccionar los cuales, se realiza el análisis de las figuras técnicas.
- Tablas de los resultados compuesta de siete columnas:
- Nombre de la figura. En la columna, se muestra el nombre de la figura analizada según Merrill. Por ejemplo, M10 o W 12.
- Encontrado. Número de figuras encontradas del tipo establecido en la muestra predeterminada.
- Timeframe. Muestra el timeframe en el que ha sido realizado el análisis de la figura especificada.
- P, Uptrend. Es la probabilidad del movimiento del precio hasta el valor «Tendencia límite en puntos» después de la aparición de una figura técnica en la dirección alcista.
- P, Dntrend. Es la probabilidad del movimiento del precio hasta el valor «Tendencia límite en puntos» después de la aparición de una figura técnica en la dirección bajista.
- K, UpTrend/K, DnTrend. Es el coeficiente descrito en mi artículo Estudio de técnicas de análisis de velas (Parte I): comprobando los patrones existentes. Su idea consiste en estimar con qué rapidez el precio alcance el profit establecido después de la aparición de la figura técnica analizada en la tendencia alcista y bajista.
La figura 4 muestra la representación visual de todas las herramientas y parámetros descritos.
Fig. 4 Implementación de la pestaña Análisis
Ahora, hablaremos de la segunda pestaña, Configuraciones:
- Indicador utilizado. Permite seleccionar un indicador al que va a aplicarse la búsqueda y el análisis de las figuras técnicas de Merrill.
- Coeficientes de pesos. Se usan en el cálculo de los coeficientes descritos antes: K, UpTrend/DnTrend.
- Idioma de la interfaz. Lista desplegable para seleccionar el idioma de la interfaz: ruso o inglés.
Puede ver la pestaña con ajustes en la imagen de abajo:
Fig. 5 Implementación de la pestaña Configuraciones
La última sección de las configuraciones utiliza la ventana «Propiedades del EA» (atajo de teclado F7) donde se establecen los ajustes del indicadores aplicados que figuran debajo del encabezado Indicador usado. La figura 6 muestra la ventana de la última sección de las configuraciones.
Fig. 6 Ventana de ajustes de indicadores usados
A la hora de definir los ajustes en esta ventana, hay que tomar en cuenta las siguientes particularidades:
- El primer ajuste "Applied price" utiliza una variable tipo enumeración ENUM_APPLIED_PRICE, que tiene siete valores: precio de apertura, cierre, High y Low, precio de mediana, típico y medio ponderado. Pues bien, para analizar el precio del gráfico, hay que usar los cuatro primeros de esta enumeración, porque los demás se usan para calcular los indicadores.
- Si queremos usar los indicadores en el análisis de las figuras, el ajuste "Applied price" va a afectar los indicadores que utilizan la variable tipo ENUM_APPLIED_PRICE en sus cálculos. A saber: ATR, CCI, RSI.
Vamos a considerar ahora la implementación informática de la interfaz de la aplicación descrita anteriormente, así como, la técnica de la búsqueda y del análisis de las figuras técnicas de Merrill.
Para crear la interfaz gráfica, se usa el método CreateGUI(), que se compone de los métodos que crean la ventana principal de la interfaz CreateWindow() y la ventana de diálogo CreateWindowSetting1() para seleccionar el intervalo temporal del análisis.
//+------------------------------------------------------------------+ //| Crea la interfaz gráfica del programa | //+------------------------------------------------------------------+ bool CProgram::CreateGUI(void) { //--- Creación del panel if(!CreateWindow("Merrill Patterns")) return(false); //--- Creando la ventana de diálogo if(!CreateWindowSetting1("Ajuste del intervalo de fechas")) return(false); //--- Terminar la creación de GUI CWndEvents::CompletedGUI(); return(true); }
Ahora, veremos de qué se compone cada uno de estos métodos. El primero será la ventana principal de la interfaz. Se compone de la implementación de la pestaña Análisis que incluye los controles descritos en la figura 4.
//+------------------------------------------------------------------+ //| Pestaña Analyze | //+------------------------------------------------------------------+ //--- Creando los botones del conjunto de patrones if(!CreatePatternSet(m_patterns,10,10)) return(false); //--- Encabezado de timeframes if(!CreateTFLabel(m_text_labels[1],10,105,0)) return(false); //--- Creando los botones del conjunto de timeframes if(!CreateTimeframeSet(m_timeframes,10,125,0)) return(false); //--- Campo de búsqueda del filtro de símbolos if(!CreateSymbolsFilter(m_symb_filter1,m_request1,10,180,0)) return(false); //--- Creando el botón de la selección del intervalo de fechas if(!CreateDateRange(m_request3,280,180,0)) return(false); //--- Creando el campo de entrada del valor límite del beneficio if(!CreateThresholdValue(m_threshold1,400,180,100,0)) return(false); //--- Creando la tabla de símbolos if(!CreateSymbTable(m_symb_table1,10,225,0)) return(false); //--- Creando la tabla de resultados if(!CreateTable1(m_table1,120,225,0)) return(false);
Y también, de la pestaña Configuraciones descrita en la figura 5.
//+------------------------------------------------------------------+ //| Pestaña Settings | //+------------------------------------------------------------------+ //--- if(!CreateButtonsGroup1(10,50)) return(false); //--- Etiquetas de texto if(!CreateTextLabel(m_text_labels[0],10,100)) return(false); if(!CreateTextLabel(m_text_labels[3],10,10)) return(false); //--- Campos de edición if(!CreateCoef(m_coef1,10,140,"K1",1)) return(false); if(!CreateCoef(m_coef2,100,140,"K2",0.5)) return(false); if(!CreateCoef(m_coef3,200,140,"K3",0.25)) return(false); if(!CreateLanguageSetting(m_lang_setting,10,180,1)) return(false); //--- Barra de estado if(!CreateStatusBar(1,26)) return(false); //--- return(true); }
Por favor, consulte los códigos fuente adjuntos al artículo para ver la implementación más detallada de los métodos aplicados que implementan los controles de la interfaz.
El método que implementa la ventana de diálogo para seleccionar los intervalos temporales es el siguiente:
//+------------------------------------------------------------------+ //| Crea la ventana de diálogo para seleccionar el intervalo de | //| fechas en la pestaña Análisis | //+------------------------------------------------------------------+ bool CProgram::CreateWindowSetting1(const string caption_text) { //--- Añadimos el puntero de la ventana en el array de ventanas CWndContainer::AddWindow(m_window[2]); //--- Coordenadas int x=m_request3.X(); int y=m_request3.Y()+m_request3.YSize(); //--- Propiedades m_window[2].XSize(372); m_window[2].YSize(230); m_window[2].WindowType(W_DIALOG); //--- Creando formulario if(!m_window[2].CreateWindow(m_chart_id,m_subwin,caption_text,x,y)) return(false); //--- if(!CreateCalendar(m_calendar1,m_window[2],10,25,D'01.01.2019',1)) return(false); if(!CreateCalendar(m_calendar2,m_window[2],201,25,m_calendar2.Today(),1)) return(false); //--- if(!CreateTimeEdit(m_time_edit1,m_window[2],10,200,"Время",1)) return(false); if(!CreateTimeEdit(m_time_edit2,m_window[2],200,200,"Время",1)) return(false); //--- return(true); }
Ahora, estudiaremos más detalladamente las técnicas del estudio de las figuras técnicas, su búsqueda y estimación. Para eso, rastrearemos toda la secuencia de acciones de este algoritmo. Primero, examinaremos el archivo MerrillPatterns.mq5 en el que se inicializa este algoritmo.
//--- Incluir la clase de la aplicación #include "Program.mqh" CProgram program; //+------------------------------------------------------------------+ //| Parámetros de entrada del EA | //+------------------------------------------------------------------+ input ENUM_APPLIED_PRICE Inp_Price1 = PRICE_CLOSE; // Applied price input int Inp_ATR_Peroid = 5; // ATR Period input int Inp_CCI_Peroid = 5; // CCI Period input int Inp_DeM_Peroid = 5; // DeMarker Period input int Inp_ForcePeriod = 13; // ForceIndex Period input ENUM_MA_METHOD Inp_ForceMAMethod = MODE_SMA; // ForceIndex MA method input ENUM_APPLIED_PRICE Inp_ForceAppliedPrice = PRICE_CLOSE; // ForceIndex Applied price input ENUM_APPLIED_VOLUME Inp_ForceAppliedVolume = VOLUME_TICK; // ForceIndex Volumes input int Inp_WPR_Period = 5; // WPR Period input int Inp_RSI_Period = 5; // RSI Period //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- program.OnInitEvent(); //--- Definimos el panel del trading if(!program.CreateGUI()) { ::Print(__FUNCTION__," > Fallo al crear la interfaz gráfica"); return(INIT_FAILED); } //--- program.InitializePrice(Inp_Price1); program.InitializeATR(Inp_ATR_Peroid); program.InitializeCCI(Inp_CCI_Peroid); program.InitializeDeM(Inp_DeM_Peroid); program.InitializeForce(Inp_ForcePeriod,Inp_ForceMAMethod,Inp_ForceAppliedPrice,Inp_ForceAppliedVolume); program.InitializeWPR(Inp_WPR_Period); program.InitializeRSI(Inp_RSI_Period); return(INIT_SUCCEEDED); }
Aparte de los parámetros de entrada de los indicadores, en la sección OnInit(), se crea un envoltorio gráfico, y luego, se realiza la inicialización de los datos definidos en la ventana de Propiedades.Todos los métodos pasan los ajustes externos en las variables internas.
//--- void InitializePrice(ENUM_APPLIED_PRICE price) { m_applied_price=price; } void InitializeATR(int period) { m_atr_period=period; } void InitializeCCI(int period) { m_cci_period=period; } void InitializeDeM(int period) { m_dem_period=period; } void InitializeWPR(int period) { m_wpr_period=period; } void InitializeRSI(int period) { m_rsi_period=period; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CProgram::InitializeForce(int period,ENUM_MA_METHOD ma_method,ENUM_APPLIED_PRICE price,ENUM_APPLIED_VOLUME volume) { m_force_period=period; m_force_ma_method=ma_method; m_force_applied_price=price; m_force_applied_volume=volume; } //+-----------------------------------------------------------------
Después de eso, la aplicación está lista para el uso y todas las demás configuraciones se pasan para la interfaz gráfica diseñada. Antes hemos dicho que el inicio del cálculo se realiza de acuerdo con la selección del instrumento financiero de la tabla de los símbolos (punto 6, fig. 4), lo mismo ocurre después de terminar la entrada en «Valor límite de la tendencia en puntos» (punto 3, fig. 4). Ambos eventos inicializan el mismo método ChangeSymbol1() para empezar a recopilar los datos definidos, con el fin de prepararlos para el análisis.
//+------------------------------------------------------------------+ //| Selección del símbolo en la pestaña Análisis | //+------------------------------------------------------------------+ bool CProgram::ChangeSymbol1(const long id) { //--- Comprobando el identificador del elemento if(id!=m_symb_table1.Id()) return(false); //--- Salir si la línea no ha sido encontrada if(m_symb_table1.SelectedItem()==WRONG_VALUE) { //--- Mostrar la descripción completa del símbolo en la barra de estado m_status_bar.SetValue(0,"Símbolo para el análisis no seleccionado"); m_status_bar.GetItemPointer(0).Update(true); return(false); } //--- Obtenemos el símbolo seleccionado string symbol=m_symb_table1.GetValue(0,m_symb_table1.SelectedItem()); //--- Mostrar la descripción completa del símbolo en la barra de estado string val=(m_lang_index==0)?"Símbolo seleccionado: ":"Selected symbol: "; m_status_bar.SetValue(0,val+::SymbolInfoString(symbol,SYMBOL_DESCRIPTION)); m_status_bar.GetItemPointer(0).Update(true); //--- GetResult(symbol); return(true); }
El sentido de su trabajo consiste en determinar el instrumento comercial seleccionado de la tabla de los símbolos y pasar su valor en la barra de estado y en el método GetResult(). Vamos a considerarlo con más detalle, ya que el trabajo principal se realiza precisamente en este método.
//+------------------------------------------------------------------+ //| Procesamiento de los resultados de la búsqueda de los patrones | //+------------------------------------------------------------------+ bool CProgram::GetResult(const string symbol) { //--- Estructura para estimar la eficacia de las figuras RATING_SET m_coef[]; //--- Tipos de figuras PATTERN_TYPE pattern_types[]; //--- ArrayResize(pattern_types,33); for(int i=0;i<33;i++) { if(i==16) pattern_types[i]=-1; if(i<16) pattern_types[i]=PATTERN_TYPE(i); if(i>16) pattern_types[i]=PATTERN_TYPE(i-1); } //--- Definimos los timeframes seleccionados GetTimeframes(m_timeframes,m_cur_timeframes); int total=ArraySize(m_cur_timeframes); //--- Comprobación de un timeframe como mínimo if(total<1) { if(m_lang_index==0) MessageBox("No ha seleccionado el timeframe de trabajo","Error",MB_OK); else if(m_lang_index==1) MessageBox("You have not selected a working timeframe!","Error",MB_OK); return(false); } int count=0; m_total_row=0; //--- Eliminar todas las líneas m_table1.DeleteAllRows(); //--- Obtener intervalo de fechas datetime start=StringToTime(TimeToString(m_calendar1.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit1.GetHours()+":"+(string)m_time_edit1.GetMinutes()+":00"); datetime end=StringToTime(TimeToString(m_calendar2.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit2.GetHours()+":"+(string)m_time_edit2.GetMinutes()+":00"); //--- Verificando si las fechas establecidas son correctas if(start>end || end>TimeCurrent()) { if(m_lang_index==0) MessageBox("Intervalo de fechas inválido","Error",MB_OK); else if(m_lang_index==1) MessageBox("Incorrect date range selected!","Error",MB_OK); return(false); } //--- for(int k=0;k<33;k++) { if(k==16) continue; //--- Obtener figuras seleccionadas para el análisis if(m_patterns[k].IsPressed()) { ArrayResize(m_m_total,total); ArrayResize(m_coef,total); ZeroMemory(m_m_total); ZeroMemory(m_coef); count++; //--- Cálculo según timeframes for(int j=0;j<total;j++) { double arr[]; //--- Obtener datos para el análisis int copied=GetData(m_buttons_group1.SelectedButtonIndex(),symbol,m_cur_timeframes[j],start,end,arr); //--- if(copied<9) MessageBox("Faltan datos para el análisis","Error",MB_OK); for(int i=0;i<copied;i++) { if(i>copied-9) continue; //--- Condición para la búsqueda del patrón double A=arr[i]; double B=arr[i+1]; double C=arr[i+2]; double D=arr[i+3]; double E=arr[i+4]; if(GetPatternType(A,B,C,D,E)==pattern_types[k]) { m_m_total[j]++; GetCategory(symbol,i+5,m_coef[j],m_cur_timeframes[j],m_threshold_value1); } } //--- Añadir resultado a la tabla AddRow(m_table1,m_patterns[k].LabelText(),m_coef[j],m_m_total[j],m_cur_timeframes[j]); } } } //--- if(count>0) { //--- m_table1.DeleteRow(m_total_row); //--- Actualizar la tabla m_table1.Update(true); m_table1.GetScrollVPointer().Update(true); } else { if(m_lang_index==0) MessageBox("Patrón no seleccionado","Error",MB_OK); else if(m_lang_index==1) MessageBox("You have not chosen a pattern!","Error",MB_OK); } return(true); }
Para empezar, hay que explicar los tipos de las variables introducidas el principio del método.La primera de ellas representa la estructura RATING_SET.
struct RATING_SET { int a_uptrend; int b_uptrend; int c_uptrend; int a_dntrend; int b_dntrend; int c_dntrend; };
Incluye 6 variables tipo int y es necesaria para escribir en ellas los resultados respecto a la frecuencia con la que el precio iba en la dirección establecida tras la identificación de la figura, y con qué rapidez la alcanzaba. Por ejemplo, para una tendencia alcista y el valor límite de la tendencia establecido en 100 puntos en el dígito 5, al encontrar una figura y superar el precio de este valor con una vela, la variable a_uptrend recibe un uno; si el precio ha alcanzado 100 puntos con 2 velas, un uno se escribe en b_uptrend. En nuestro método, vamos a usar el array de estas estructuras m_coef[].
El segundo tipo de la variable es PATTERN_TYPE. Es una enumeración en la que se reúnen todos tipos de las figuras técnicas de Merrill.
//+------------------------------------------------------------------+ //| Tipo de la figura | //+------------------------------------------------------------------+ enum PATTERN_TYPE { M1,M2,M3,M4,M5,M6,M7,M8, M9,M10,M11,M12,M13,M14,M15,M16, W1,W2,W3,W4,W5,W6,W7,W8, W9,W10,W11,W12,W13,W14,W15,W16 };
En el método, se usa el array de enumeraciones pattern_types[]. Luego, se verifica qué timeframes han sido seleccionados en la aplicación para el trabajo. Esta información se procesa por el método GetTimeframes().
//+------------------------------------------------------------------+ //| Obtener array de timeframes seleccionados | //+------------------------------------------------------------------+ void CProgram::GetTimeframes(CButton &buttons[],ENUM_TIMEFRAMES &timeframe[]) { string tf[22]= { "M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30", "H1","H2","H3","H4","H6","H8","H12","D1","W1","MN" }; int j=0; ArrayResize(timeframe,22); for(int i=0;i<22;i++) { if(buttons[i].IsPressed()) { timeframe[j]=StringToTimeframe(tf[i]); j++; } } ArrayResize(timeframe,j); }
Y escribe eso en el array de timeframes m_cur_timeframes[] definido anteriormente. Luego, obtenemos el intervalo temporal para el trabajo.
En el primer ciclo, empezamos a comprobar la pulsación de botones seleccionados, que responden de los tipos de la figuras y que definen el conjunto de las figuras analizadas. En el siguiente ciclo, cada una de las figuras se analiza en los timeframes seleccionados antes. Pues, aquí hemos llegado a la pregunta, ¿a qué datos van a aplicarse los ajustes de las figuras y timeframes seleccionados antes? El método GetData() se encarga de eso. El determina los ajustes establecidos en la ventana de las propiedades del EA, así como, el Indicador usado (punto 1, fig. 5), en la ventana de la configuración de la aplicación.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CProgram::GetData(int index,string symb,ENUM_TIMEFRAMES tf,datetime start,datetime end,double &arr[]) { //--- int Handle=INVALID_HANDLE,copied; //--- Precio de cierre if(index==0) { MqlRates rt[]; ZeroMemory(rt); copied=CopyRates(symb,tf,start,end,rt); ArrayResize(arr,copied); for(int i=0;i<copied;i++) { arr[i]=rt[i].close; if(m_applied_price==PRICE_OPEN) arr[i]=rt[i].open; else if(m_applied_price==PRICE_CLOSE) arr[i]=rt[i].close; else if(m_applied_price==PRICE_HIGH) arr[i]=rt[i].high; else if(m_applied_price==PRICE_LOW) arr[i]=rt[i].low; } return(copied); } //--- ATR if(index==1) Handle=iATR(symb,tf,m_atr_period,m_applied_price); //--- CCI if(index==2) Handle=iCCI(symb,tf,m_cci_period,m_applied_price); //--- DeMarker if(index==3) Handle=iDeMarker(symb,tf,m_dem_period); //--- Force Index if(index==4) Handle=iForce(symb,tf,m_force_period,m_force_ma_method,m_force_applied_volume); //--- WPR if(index==5) Handle=iWPR(symb,tf,m_wpr_period); //--- RSI if(index==6) Handle=iRSI(symb,tf,m_rsi_period,m_applied_price); //--- if(Handle==INVALID_HANDLE) { Print("Fallo al recibir el handle del indicador"); return(-1); } copied=CopyBuffer(Handle,0,start,end,arr); return(copied); }
Después de que los datos para el análisis hayan sido obtenidos, el algoritmo pasa al método GetPatternType(), a través del cual se realiza la búsqueda de todos los patrones establecidos anteriormente en los timeframes seleccionados.
//+------------------------------------------------------------------+ //| Identificación de patrones | //+------------------------------------------------------------------+ PATTERN_TYPE CProgram::GetPatternType(double A,double B,double C,double D,double E) { //--- M1 if(B>A && A>D && D>C && C>E) return(M1); //--- M2 if(B>A && A>D && D>E && E>C) return(M2); //--- M3 if(B>D && D>A && A>C && C>E) return(M3); //--- M4 if(B>D && D>A && A>E && E>C) return(M4); //--- M5 if(D>B && B>A && A>C && C>E) return(M5); //--- M6 if(D>B && B>A && A>E && E>C) return(M6); //--- M7 if(B>D && D>C && C>A && A>E) return(M7); //--- M8 if(B>D && D>E && E>A && A>C) return(M8); //--- M9 if(D>B && B>C && C>A && A>E) return(M9); //--- M10 if(D>B && B>E && E>A && A>C) return(M10); //--- M11 if(D>E && E>B && B>A && A>C) return(M11); //--- M12 if(B>D && D>C && C>E && E>A) return(M12); //--- M13 if(B>D && D>E && E>C && C>A) return(M13); //--- M14 if(D>B && B>C && C>E && E>A) return(M14); //--- M15 if(D>B && B>E && E>C && C>A) return(M15); //--- M16 if(D>E && E>B && B>C && C>A) return(M16); //--- W1 if(A>C && C>B && B>E && E>D) return(W1); //--- W2 if(A>C && C>E && E>B && B>D) return(W2); //--- W3 if(A>E && E>C && C>B && B>D) return(W3); //--- W4 if(A>C && C>E && E>D && D>B) return(W4); //--- W5 if(A>E && E>C && C>D && D>B) return(W5); //--- W6 if(C>A && A>B && B>E && E>D) return(W6); //--- W7 if(C>A && A>E && E>B && B>D) return(W7); //--- W8 if(E>A && A>C && C>B && B>D) return(W8); //--- W9 if(C>A && A>E && E>D && D>B) return(W9); //--- W10 if(E>A && A>C && C>D && D>B) return(W10); //--- W11 if(C>E && E>A && A>B && B>D) return(W11); //--- W12 if(E>C && C>A && A>B && B>D) return(W12); //--- W13 if(C>E && E>A && A>D && D>B) return(W13); //--- W14 if(E>C && C>A && A>D && D>B) return(W14); //--- W15 if(C>E && E>D && D>A && A>B) return(W15); //--- W16 if(E>C && C>D && D>A && A>B) return(W16); return(-1); }
Al encontrar una figura técnica, se realiza su estimación a través del método GetCategory(). Pues, precisamente aquí, se usa el array de estructuras tipo RATING_SET definido anteriormente.
//+------------------------------------------------------------------+ //| Definir categorías del beneficio | //+------------------------------------------------------------------+ bool CProgram::GetCategory(const string symbol,const int shift,RATING_SET &rate,ENUM_TIMEFRAMES timeframe,int threshold) { MqlRates rt[]; datetime start=StringToTime(TimeToString(m_calendar1.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit1.GetHours()+":"+(string)m_time_edit1.GetMinutes()+":00"); start+=PeriodSeconds(timeframe)*shift; int copied=CopyRates(symbol,timeframe,start,4,rt); //--- Obtenemos datos de las velas anteriores if(copied<4) return(false); double high1,high2,high3,low1,low2,low3,close0,point; close0=rt[0].close; high1=rt[1].high; high2=rt[2].high; high3=rt[3].high; low1=rt[1].low; low2=rt[2].low; low3=rt[3].low; if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point)) return(false); //--- Comprobación en Uptrend if((int)((high1-close0)/point)>=threshold) { rate.a_uptrend++; } else if((int)((high2-close0)/point)>=threshold) { rate.b_uptrend++; } else if((int)((high3-close0)/point)>=threshold) { rate.c_uptrend++; } //--- Comprobación en Downtrend if((int)((close0-low1)/point)>=threshold) { rate.a_dntrend++; } else if((int)((close0-low2)/point)>=threshold) { rate.b_dntrend++; } else if((int)((close0-low3)/point)>=threshold) { rate.c_dntrend++; } return(true); }
Los datos de la estimación procesados se transmiten en el método AddRow(), que calcula los valores de las probabilidades y coeficientes de la eficacia y los introduce en la tabla de resultados.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CProgram::AddRow(CTable &table,string pattern_name,RATING_SET &rate,int found,ENUM_TIMEFRAMES timeframe) { int row=m_total_row; double p1,p2,k1,k2; int sum1=0,sum2=0; sum1=rate.a_uptrend+rate.b_uptrend+rate.c_uptrend; sum2=rate.a_dntrend+rate.b_dntrend+rate.c_dntrend; //--- p1=(found>0)?(double)sum1/found*100:0; p2=(found>0)?(double)sum2/found*100:0; k1=(found>0)?(m_k1*rate.a_uptrend+m_k2*rate.b_uptrend+m_k3*rate.c_uptrend)/found:0; k2=(found>0)?(m_k1*rate.a_dntrend+m_k2*rate.b_dntrend+m_k3*rate.c_dntrend)/found:0; //--- table.AddRow(row); table.SetValue(0,row,pattern_name); table.SetValue(1,row,(string)found); table.SetValue(2,row,TimeframeToString(timeframe)); table.SetValue(3,row,DoubleToString(p1,2),2); table.SetValue(4,row,DoubleToString(p2,2),2); table.SetValue(5,row,DoubleToString(k1,2),2); table.SetValue(6,row,DoubleToString(k2,2),2); ZeroMemory(rate); m_total_row++; }
Para despejar posibles dudas respecto al uso de la aplicación, por favor, vea el vídeo de abajo que contiene ejemplos del cálculo con diferentes ajustes.
Recomendaciones para el testeo de las figuras técnicas de Merrill:
- Para un correcto trabajo de la aplicación, es necesario tener cargados los datos históricos para el instrumento financiero seleccionado.
- No se recomienda cargar todos los patrones y todos los timeframes a la vez, porque el procesamiento de los resultados puede tardar bastante tiempo.
- Los escenarios más comunes que suponen dificultades en el trabajo, han sido dotados con ayudas. Por ejemplo, timeframe o patrón no establecidos, fecha inválida.
- Preste atención en los ajustes en las propiedades del EA (fig. 6), y si tiene dudas, lea el artículo otra vez.
- El tema del método del cálculo de la eficacia de los patrones ha sido discutido dos veces en este artículo, referiéndose al artículo donde todo eso se describe detalladamente. Puesto que, al establecer los coeficientes de peso en la pestaña de configuraciones, es necesario comprender muy bien su influencia en la estimación de los patrones.
Conclusiones
Al final del articulo se adjunta el archivo comprimido con todos los ficheros mencionados, ordenados por carpetas. Por eso, para un trabajo correcto basta con colocar la carpeta MQL5 en la raíz del terminal. Para abrir el directorio raíz del terminal que contiene la carpeta MQL5, pulse en la combinación Ctrl+Shift+D o utilice el menú contextual, tal como se muestra en la imagen 7.
Fig. 7 Abrir la carpeta MQL5 en el directorio raíz del terminal MetaTrader 5
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/7022
- 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