Creación de un modelo de restricción de tendencia de velas (Parte 1): Para EAs e Indicadores Técnicos
Contenido
- Introducción
- Anatomía de las velas de plazos superiores
- Desarrollo de la estrategia (Moving Average Crossover) más el código
- Justificación de la restricción y su aplicación más el código
- Ventajas de utilizar el código
- Conclusión
Introducción
Como alternativa al uso de las medias móviles para definir las tendencias del mercado, la naturaleza alcista o bajista de las velas de plazos superiores puede proporcionar información valiosa sobre la dirección del mercado. Por ejemplo, dentro de una vela D1 o H4, hay una actividad subyacente significativa que ocurre en los marcos temporales M1 e incluso en los ticks que dan forma a su formación. Al capitalizar las oportunidades de compra que presentan las velas D1 alcistas y vender durante las fases bajistas, los operadores pueden obtener una ventaja. La combinación de estos indicadores con indicadores técnicos nativos en plazos inferiores ayuda a identificar los puntos de entrada, lo que ofrece una ventaja estratégica a los operadores. Cuando se trata de una vela diaria alcista, los operadores deben esperar pacientemente a que las condiciones favorables del mercado se alineen antes de montar con confianza la tendencia.
Este artículo tiene como objetivo clasificar eficazmente la vela actual como alcista o bajista utilizando el código MQL5, estableciendo una condición para vender sólo cuando es bajista y comprar cuando es alcista.
Este modelo pretende limitar el generador de señales a la producción de señales alineadas con la tendencia actual de la vela. Piense en una valla que impide la entrada a determinadas criaturas en función del tamaño de su cuerpo, mientras que permite la entrada a otras. Aplicamos un concepto similar para filtrar las señales seleccionadas y conservar sólo las más óptimas. Para ello, el modelo analiza las velas y las tendencias del mercado en los marcos temporales superiores, creando así una barrera virtual que sólo permite el paso de las señales que se ajustan a la tendencia predominante. Este proceso de filtrado selectivo mejora la precisión y fiabilidad de las señales generadas, garantizando que sólo se presenten al usuario las oportunidades de negociación más favorables.
Al final de este artículo, usted debe ser capaz de:
- Comprender la acción del precio con toda la vela D1 en los plazos microscópicos disponibles.
- Crear un buffer de indicador de cruce de medias móviles (MA) que incluya la condición de restricción de tendencia en un marco temporal superior.
- Comprender el concepto de filtrar las mejores señales de una estrategia determinada.
Anatomía de las velas de plazos superiores
Fig. 1.1: La anatomía de D1 vista en el marco temporal M5 para los sintéticos del índice Boom 500.
La imagen de arriba muestra una barra roja de velas D1 en el extremo izquierdo y una acción de precio M5 en el derecho delimitada entre separadores de periodos diarios. Se observa una clara tendencia bajista, apoyada por la naturaleza bajista de la vela diaria, que indica una mayor probabilidad de venta. La configuración enfatiza la ejecución de operaciones en alineación con la vela diaria, lo que refleja la aparición de la idea de restricción del desarrollo de una tendencia de marco de tiempo superior.
Desarrollo de estrategias (Moving Average Crossover)
El desarrollo de una estrategia de negociación requiere una combinación de análisis, pruebas y perfeccionamiento continuo. Una estrategia de negociación eficaz debe basarse en un conocimiento profundo del mercado, así como en un conjunto claro de reglas y directrices a seguir. Es importante supervisar y ajustar constantemente la estrategia a medida que cambian las condiciones del mercado, para adaptarse a las nuevas tendencias y oportunidades. Mediante el análisis continuo de los datos, la realización de pruebas retrospectivas de diferentes enfoques y los ajustes necesarios, los operadores pueden aumentar sus posibilidades de éxito en el mercado.
Antes de proceder a nuestra estrategia de cruce de MA, a continuación se presenta un esquema que resume los consejos clave para el desarrollo de la estrategia:
- Defina sus objetivos y su tolerancia al riesgo
- Conozca el mercado
- Elija su estilo de negociación
- Elaborar normas de entrada y salida
- Aplicar estrategias de gestión de riesgos
- Pruebe su estrategia
- Optimice y perfeccione
- Comercio en papel antes de salir al mercado
- Supervisar y evaluar
- Establecer las condiciones de la estrategia (En este caso cruce de EMA7 por encima o por debajo de EMA21)
- Establezca el estilo de visualización del indicador, que puede ser una flecha o cualquier forma geométrica disponible en MetaTrader 5
- (Opcional) si el indicador va a ser personalizable por el usuario, establezca las entradas
He decidido incluir aquí el código final sin muchas explicaciones para centrarme en el algoritmo de restricciones, nuestro tema principal en este artículo. El siguiente programa está listo para compilar y generar señales de compra y venta. Después del código, analizaremos los resultados en el gráfico MT5 e identificaremos el problema que abordará el algoritmo de restricción.
//Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #property description "A model that seek to produce sell signal when D1 candle is Bearish only and buy signal when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // Custom indicator initialization function int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //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[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation //Indicator Buffer 1 if(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //copy the code to meta editor to compile it
El 12.04.24, el gráfico de resultados de la prueba EURUSD indica el inicio de un período observado en los plazos M1. Los cruces se muestran con flechas que indican su posición: rojas para las señales de venta y azules para las de compra. A pesar de ello, una visión más amplia revela una clara tendencia bajista, lo que indica una vela D1 bajista. El indicador de cruce está emitiendo ambas señales, haciendo caso omiso de la tendencia predominante, lo que plantea un problema importante. Las señales contradictorias crean un escenario desafiante para los operadores que intentan navegar por el mercado. Si bien los plazos M1 sugieren posibles oportunidades a corto plazo, la tendencia bajista generalizada en la vela D1 hace temer por la sostenibilidad de cualquier movimiento alcista. En este artículo, abordaremos esta cuestión limitando nuestras señales a la tendencia D1.
Fig. 1.2 : Resultado de la prueba del indicador de cruce MA antes de la restricción.
El resultado de la vela D1 es bajista con flechas de compra y venta generadas por la condición de cruce de MA. Muchas señales se consideran falsas o fuera de tendencia, lo que puede rectificarse incorporando la restricción de tendencia del marco temporal superior. La tabla resultante a continuación se creó utilizando la información de los gráficos desde el inicio del día hasta el cierre.
Tipo de señal | Unidades |
---|---|
Señales de venta | 29 |
Señales de compra | 28 |
Total | 57 |
Señales falsas y fuera de tendencia | 41 |
Señales exitosas | 25 |
Justificación de la restricción y su aplicación
Imagina tener una mezcla de granos de maíz y trigo; uno es más grueso que el otro. Para separarlos, empleamos un tamiz. Esta acción confina el grano de maíz, permitiendo que sólo pase el trigo, lo que demuestra un nivel de control. Esta analogía concuerda con el concepto de limitación temporal superior que estamos examinando. Actúa como un filtro, filtrando ciertas señales y reteniendo sólo las que están en armonía con la tendencia predominante. La restricción temporal superior, similar al tamiz, afina nuestro enfoque, permitiéndonos discernir los elementos esenciales de la tendencia del mercado. Filtrando el ruido, podemos comprender mejor la dinámica subyacente, lo que facilita una toma de decisiones más informada. Este planteamiento estratégico mejora nuestra capacidad para navegar por las complejidades del panorama financiero, garantizando que nos mantenemos alineados con la dirección general, como el sorgo separado del grano de maíz, revelando la verdadera esencia del movimiento del mercado.
Definir la naturaleza de la vela D1 como condición para la restricción de tendencia que codificamos anteriormente.- Definí mi sentimiento actual del mercado como alcista o bajista comparando el precio de cierre del día anterior, que es similar al precio de apertura del día actual, y los precios de cierre de las velas M1 del marco temporal inferior.
- Examinemos el código. El código está bien estructurado y es fácil de seguir.
Para una vela alcista:
cierre de la vela M1 anterior >= cierre de la vela D1 anterior
Para una vela bajista:
cierre de la vela M1 anterior <= cierre de la vela D1 anterior
Las matemáticas sugieren que con una vela D1 alcista como impulsora de la tendencia, sólo recibiremos señales de compra y lo contrario es cierto para una vela D1 bajista.
Optamos por el cierre del marco temporal inferior como punto de comparación con nuestra apertura D1 en lugar de utilizar otros aspectos como el precio de compra y venta o el cierre del día actual, ya que este último no muestra flechas en el gráfico como se desea según esta estrategia y estilo de indicador. Por lo tanto, al centrarnos en el cierre del marco temporal inferior en relación con nuestra apertura D1, podemos alinear eficazmente nuestra estrategia con las señales visuales y los indicadores deseados en el gráfico. Este planteamiento aumenta la claridad y precisión de nuestras decisiones comerciales, garantizando un proceso de análisis más ágil y eficaz.
if(Close[1+barshift_M1[i]] >= Open[1+barshift_D1[i]] //Candlestick Close >= Candlestick Open ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; }
El código anterior representa una condición de vela D1 alcista. Recuerde que lo contrario es válido para los bajistas.
- Por último, presento el código final en el que la restricción se integra perfectamente con el indicador de cruce de medias móviles.
/Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #property description "A model that seek to produce sell signal when D1 candle is Bearish only and buy signal when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5/ #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Close[]; double Close2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // Custom indicator initialization function int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } // 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[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; datetime TimeShift[]; if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total); ArraySetAsSeries(TimeShift, true); int barshift_M1[]; ArrayResize(barshift_M1, rates_total); int barshift_D1[]; ArrayResize(barshift_D1, rates_total); for(int i = 0; i < rates_total; i++) { barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]); barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]); } if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(CopyClose(Symbol(), PERIOD_M1, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close2) <= 0) return(rates_total); ArraySetAsSeries(Close2, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue; if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue; //Indicator Buffer 1 if(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average && Close[1+barshift_M1[i]] >= Close2[1+barshift_D1[i]] //Candlestick Close >= Candlestick Close ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average && Close[1+barshift_M1[i]] <= Close2[1+barshift_D1[i]] //Candlestick Close <= Candlestick Close ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); }
El resultado del código anterior es excelente. Consulte la imagen siguiente.
Fig. 1.3: Restricción de tendencia aplicada y el resultado es sorprendente.
Tipo de señal | Unidades |
---|---|
Señal de venta | 27 |
Señal de compra | 1 |
Total | 28 |
Señales falsas y fuera de tendencia | 3 |
Señales exitosas | 25 |
En la tabla anterior, observamos un impacto positivo de la restricción de tendencia de marco temporal superior como filtro, lo que se traduce en más victorias que fracasos, por lo que es ideal para los EA. Comparando las tablas de resultados anterior y actual, observamos que las señales acertadas mantuvieron su valor, mientras que todas las señales falsas se redujeron. Esta mejora de la precisión de la señal indica una tendencia positiva en nuestra metodología de análisis de datos. Al perfeccionar nuestros algoritmos y criterios, hemos minimizado eficazmente la aparición de señales falsas, mejorando la fiabilidad general de nuestros resultados. De cara al futuro, estos avances contribuirán sin duda a una toma de decisiones más informada y a mejorar los resultados de nuestras estrategias.
Ventajas de utilizar el código
Las ventajas de imponer restricciones a las tendencias de plazos más largos mejoran la claridad de la dirección del mercado, reduciendo las tendencias a la sobrecompra y fomentando un enfoque más disciplinado de las decisiones de negociación.. Este método también puede proporcionar una perspectiva más amplia, ayudando a los operadores a evitar quedar atrapados en las fluctuaciones a corto plazo y permitiéndoles alinear sus estrategias con la tendencia predominante a largo plazo. Al centrarse en el panorama general, los operadores están mejor equipados para filtrar el ruido y tomar decisiones más informadas basadas en la tendencia subyacente. Este enfoque fomenta la paciencia y una comprensión más profunda de la dinámica del mercado, lo que en última instancia conduce a resultados comerciales más consistentes y rentables. Además, las restricciones en las tendencias de plazos más largos pueden servir como valiosas herramientas para la gestión del riesgo, permitiendo a los operadores establecer niveles claros para los puntos de entrada y salida basados en una evaluación estratégica de las condiciones del mercado.
En resumen;
- Mayor precisión de los indicadores generadores de señales
- Mejor gestión del riesgo
- Mayor rentabilidad
- Menos trabajo
- Menos señales
Conclusión
Las velas de los marcos temporales superiores ejercen una influencia significativa en las tendencias de los marcos temporales inferiores, ya sean alcistas o bajistas, dirigiendo esencialmente los mercados. Sobre la base de diversos estudios, es aconsejable considerar la compra durante las velas alcistas del día en marcos de tiempo más bajos y la venta durante las velas bajistas. Personalmente, la integración del concepto de restricciones de tendencias en plazos más largos, como éste, podría ser crucial en el desarrollo del EA e indicadores para obtener resultados positivos sostenidos. Surge la pregunta: ¿Debemos descartar ahora las medias móviles como instrumentos de definición de tendencias? Tal vez el próximo artículo arroje luz sobre esta cuestión a medida que profundicemos en el perfeccionamiento y la evolución de este concepto. Adjunto están los archivos de código fuente que puedes ver en MetaEditor y los archivos EX5 en la plataforma MetaTrader 5.
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/14347
- 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