Introducción a MQL5 (Parte 26): Creación de un EA basado en zonas de soporte y resistencia
Introducción
¡Bienvenidos de nuevo a la parte 26 de la serie Introducción a MQL5! En este artículo, nos centraremos en las zonas de soporte y resistencia, que se encuentran entre los conceptos más fundamentales del análisis técnico, y exploraremos cómo crear un Asesor Experto (EA) que realice operaciones basándose en estos niveles de precios cruciales. Los participantes del mercado suelen tomar decisiones importantes en sus operaciones, basándose en barreras psicológicas conocidas como zonas de soporte y resistencia. La resistencia indica un nivel donde la presión vendedora es lo suficientemente fuerte como para detener el movimiento alcista, mientras que el soporte indica un nivel donde la presión compradora tiende a superar la presión vendedora y provoca que los precios repunten.
En la parte 24 de esta serie, vimos cómo configurar manualmente las zonas de soporte y resistencia utilizando el objeto gráfico «rectángulo». Esto te permitió crear un sistema de negociación semiautomatizado que reacciona a las zonas que dibujas. Sin embargo, ¿qué ocurre si deseas que el EA identifique automáticamente, sin intervención humana, todas las zonas de soporte y resistencia en el gráfico? Este artículo abordará específicamente ese tema. Como de costumbre, abordaremos los principios de MQL5 de una manera práctica y accesible para principiantes, utilizando un enfoque basado en proyectos. Descubrirás cómo identificar estas zonas mediante programación, realizar un seguimiento de los movimientos de precios a su alrededor y crear un Asesor Experto (EA) que responda de forma sensata a posibles reversiones.
Cómo funciona el EA
En este proyecto, estamos creando un Asesor Experto (EA) que busca automáticamente zonas de soporte y resistencia dentro de un número determinado de barras. En lugar de basarse en zonas dibujadas manualmente, el EA analizará los movimientos recientes de los precios para detectar áreas donde el mercado ha reaccionado repetidamente, ya sea rebotando al alza (soporte) o revirtiendo a la baja (resistencia).
Soporte
Para encontrar todos los mínimos de oscilación, el EA primero recorre el número de barras especificado. Un mínimo oscilante es una vela que indica un breve mínimo en la acción del precio cuando su precio mínimo es inferior al de las velas que la preceden y la siguen inmediatamente.
Tras identificar un mínimo de oscilación, el EA descubre el valor mínimo entre los precios de apertura y cierre de la vela, así como el precio mínimo exacto de la vela que lo creó. La posible zona de soporte está definida por estos dos valores, aunque esto aún no se ha verificado. Después de este mínimo de oscilación, el EA analiza las velas posteriores para comprobar si se forma otro mínimo en la misma zona. El mínimo entre la apertura y el cierre de la vela que generó el primer mínimo oscilante debe ser mayor que el segundo mínimo oscilante. Esta recurrencia sugiere que el mercado ha vuelto a examinar la región, realzando su importancia.
Tras identificar esta zona de soporte, el EA confirma que ninguna vela ha roto por debajo de ella. La zona se considera inválida y no se tiene en cuenta si alguna vela cierra por debajo de ella. El EA pasa a un marco temporal inferior para estar atento a un cambio de carácter alcista cuando la zona se haya mantenido estable. Se inicia una operación de compra cuando se identifica un cambio de estructura de este tipo, lo que indica que el mercado está siendo dominado por los compradores y que la zona de soporte se ha mantenido firme.

Resistencia
Para encontrar cada máximo de oscilación, el EA primero recorre el número de barras elegido. Un máximo de oscilación es una vela que marca un máximo local breve cuando su precio máximo es superior al de las velas que la preceden y la siguen inmediatamente.
Una vez identificado un máximo de oscilación, el EA registra el precio máximo de la vela, así como el valor más alto entre sus precios de apertura y cierre. Aunque aún no se ha verificado, estas cifras indican la posible zona de resistencia. Para determinar si se ha desarrollado otro máximo de oscilación dentro de la misma zona, el EA entonces mira hacia adelante desde el tiempo de oscilación. El segundo swing high debe quedar por encima del cuerpo de la primera vela, es decir, por encima del rango comprendido entre su apertura y cierre. Este rechazo repetido en el mismo nivel indica una fuerte presión vendedora, lo que confirma el potencial de la zona como barrera.
A continuación, el EA verifica que ninguna vela haya superado la zona de resistencia indicada. La zona se considera inválida y se ignora si una vela cierra por encima de ella. El EA se desplaza a un marco temporal inferior para estar atento a un cambio de carácter bajista una vez que la zona siga siendo válida. El Asesor Experto (EA) inicia una operación de venta cuando se produce este cambio estructural bajista, ya que indica que los vendedores están recuperando el control desde ese nivel de resistencia.

Identificación de los primeros mínimos de oscilación
Ahora que comprendemos mejor el proyecto, nuestro siguiente paso será encontrar la zona de soporte. Encontrar varios mínimos importantes en el gráfico es la primera etapa de este proceso. Estos mínimos oscilantes indican posibles regiones donde puede existir presión compradora, ya que muestran puntos donde el mercado dejó de bajar momentáneamente y volvió a subir. El EA podrá detectar posibles zonas de soporte que, posteriormente, podrían servir como puntos de entrada para posibles señales de compra al identificar estos swing bajos.
Primero, debemos copiar los datos relevantes de las velas. A continuación, especificaremos cuántas barras queremos que el EA busque al identificar posibles zonas de soporte y resistencia. Luego desarrollaremos una función para detectar los máximos y mínimos de oscilación dentro del rango seleccionado. Esta función servirá de base para detectar puntos de inflexión importantes en los precios, necesarios para determinar niveles fiables de soporte y resistencia.
Ejemplo:input ENUM_TIMEFRAMES timeframe = PERIOD_W1; //SUPPORT AND RESISTANCE TIMEFRAME double open[]; double close[]; double low[]; double high[]; datetime time[]; int bars_check = 200; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyOpen(_Symbol, timeframe, TimeCurrent(), bars_check, open); CopyClose(_Symbol, timeframe, TimeCurrent(), bars_check, close); CopyLow(_Symbol, timeframe, TimeCurrent(), bars_check, low); CopyHigh(_Symbol, timeframe, TimeCurrent(), bars_check, high); CopyTime(_Symbol, timeframe, TimeCurrent(), bars_check, time); } //+------------------------------------------------------------------+ //| FUNCTION FOR SWING LOW | //+------------------------------------------------------------------+ bool IsSwingLow(const double &low_price[], int index, int lookback) { for(int i = 1; i <= lookback; i++) { if(low_price[index] > low_price[index - i] || low_price[index] > low_price[index + i]) return false; } return true; } //+------------------------------------------------------------------+ //| FUNCTION FOR SWING HIGH | //+------------------------------------------------------------------+ bool IsSwingHigh(const double &high_price[], int index, int lookback) { for(int i = 1; i <= lookback; i++) { if(high_price[index] < high_price[index - i] || high_price[index] < high_price[index + i]) return false; // If the current high is not the highest, return false. } return true; }
Explicación:
El usuario puede seleccionar el período de tiempo para buscar zonas de resistencia y soporte. Los arrays contendrán los datos de las velas. Según la opción bars_check, el EA analizará 200 velas en busca de puntos de inflexión. El programa copia el precio y el tiempo de cada vela en el gráfico. _Symbol, el primer argumento, indica al EA que transfiera los datos del activo que está asociado actualmente con el gráfico. El segundo parámetro es "timeframe" e indica el período de tiempo seleccionado por el usuario. El usuario puede especificar cualquier intervalo de tiempo que desee para el análisis, ya que se define como un dato de entrada. El siguiente parámetro, a partir del cual debe comenzar la copia de datos, es donde hemos utilizado la función TimeCurrent().
Dado que esta función devuelve la hora del servidor en este preciso momento, el EA comienza a copiar los datos de la vela más reciente. Para saber cuántas velas debe copiar el EA, utilice el argumento bars_check. Aquí, indica que el EA extraerá información de las 200 barras anteriores al momento actual. El EA puede organizar los datos para un análisis posterior utilizando el último argumento, que indica la matriz (apertura, cierre, mínimo, máximo o hora) en la que se almacenarán los datos copiados.
La función IsSwingLow() requiere tres argumentos. El precio mínimo de cada vela está contenido en una matriz llamada low_price[], que es el primer parámetro. La vela actual que se está analizando viene especificada por el segundo parámetro, el índice. El número de velas que deben compararse antes y después de la actual viene determinado por el tercer parámetro, lookback. Un bucle dentro de la función compara el precio mínimo de la vela actual con los mínimos de las velas cercanas, desde 1 hasta el valor de referencia. La función devuelve falso, lo que indica que el mínimo actual no es un mínimo de oscilación, si es superior a cualquiera de los mínimos vecinos. La función devuelve verdadero, lo que indica que se trata de un mínimo de oscilación legítimo, si se mantiene como el más bajo en comparación con todas las velas cercanas.
Esto es lo contrario de cómo funciona la función IsSwingHigh(). Para determinar si el máximo de la vela actual es mayor que los máximos de las velas adyacentes dentro del rango de análisis especificado, utiliza el array high_price[]. El máximo actual no se considera válido si resulta inferior al de cualquiera de las velas vecinas. Se identifica como un máximo de oscilación si devuelve verdadero en caso contrario.
El siguiente paso, tras copiar los datos de las velas, es encontrar todos los mínimos de oscilación en el gráfico. Estos mínimos oscilantes son puntos donde el precio repuntó momentáneamente, creando posibles zonas de soporte. Nuestras zonas de soporte se crearán utilizando cada mínimo detectado como primer punto de referencia. A continuación, el EA verificará estas zonas buscando más toques y reacciones dentro del mismo rango de precios.
Ejemplo:input ENUM_TIMEFRAMES timeframe = PERIOD_W1; //SUPPORT AND RESISTANCE TIMEFRAME double open[]; double close[]; double low[]; double high[]; datetime time[]; int bars_check = 200; double first_sup_price; double first_sup_min_body_price; datetime first_sup_time; string support_object; ulong chart_id = ChartID(); int total_symbol_bars; int z = 7; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- ObjectsDeleteAll(chart_id); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyOpen(_Symbol, timeframe, TimeCurrent(), bars_check, open); CopyClose(_Symbol, timeframe, TimeCurrent(), bars_check, close); CopyLow(_Symbol, timeframe, TimeCurrent(), bars_check, low); CopyHigh(_Symbol, timeframe, TimeCurrent(), bars_check, high); CopyTime(_Symbol, timeframe, TimeCurrent(), bars_check, time); total_symbol_bars = Bars(_Symbol, timeframe); if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); } } } } //+------------------------------------------------------------------+ //| FUNCTION FOR SWING LOW | //+------------------------------------------------------------------+ bool IsSwingLow(const double &low_price[], int index, int lookback) { for(int i = 1; i <= lookback; i++) { if(low_price[index] > low_price[index - i] || low_price[index] > low_price[index + i]) return false; } return true; } //+------------------------------------------------------------------+ //| FUNCTION FOR SWING HIGH | //+------------------------------------------------------------------+ bool IsSwingHigh(const double &high_price[], int index, int lookback) { for(int i = 1; i <= lookback; i++) { if(high_price[index] < high_price[index - i] || high_price[index] < high_price[index + i]) return false; // If the current high is not the highest, return false. } return true; }
Resultado:

Explicación:
Cada mínimo de oscilación que encontramos contiene información básica que preservamos definiendo variables para mantener las características vitales. Registra el precio mínimo real de la vela de mínimo oscilante, guarda la hora en que se produjo dicho mínimo y representa el límite inferior del cuerpo de la vela como el valor menor entre los precios de apertura y cierre.
Hacemos un seguimiento de la información importante sobre cada mínimo de oscilación, como la hora en que ocurrió, el límite inferior del cuerpo de la vela y el precio mínimo real. Para gestionar los objetos gráficos, se recupera el ID del gráfico y se crea una variable para guardar el nombre del objeto rectangular que representa la zona de soporte. Utilizando un periodo de tiempo de siete velas como referencia, se identifican los mínimos de oscilación válidos. Tras confirmar que hay al menos 200 velas disponibles en el gráfico, el EA recorre los datos desde la séptima vela.
La función de mínimo oscilante es utilizada por el programa dentro del bucle para determinar si cada vela forma un patrón de mínimo oscilante. Si esto ocurre, el software registra la marca de tiempo de la vela, el precio mínimo y el valor más pequeño entre los precios de apertura y cierre. Posteriormente, combina la palabra "SUPPORT" con el precio del soporte para darle a la zona de soporte un nombre distintivo.
Al examinar cada vela para comprobar si su mínimo es inferior a los mínimos de las siete velas anteriores y posteriores, el ordenador detecta automáticamente los mínimos de oscilación. Cuando se identifica un mínimo de oscilación, se anota el momento exacto en que la vela establece la zona de soporte, junto con el precio más bajo y el menor valor entre la apertura y el cierre. Esta zona se representa visualmente en el gráfico mediante un rectángulo estilizado con color y relleno, que se extiende desde el mínimo alcanzado hasta el momento actual. Al combinar la palabra "SUPPORT" con su precio, cada zona de soporte recibe un nombre distintivo que facilita su seguimiento y visualización en el gráfico.
El programa utiliza un rectángulo que abarca el período comprendido entre el precio del mínimo de oscilación y el borde inferior de su cuerpo, desde el momento del mínimo de oscilación hasta la vela actual, para indicar gráficamente las zonas de soporte en el gráfico.
Identificación de los mínimos del segundo oscilación
La siguiente etapa consiste en determinar si se ha formado otro mínimo oscilante dentro de la zona que previamente estaba marcada por el primer mínimo oscilante. Esto respalda la autenticidad y la solidez del área de soporte. Desde el momento del primer mínimo oscilatorio, el EA estará atento a la aparición de un segundo mínimo oscilatorio cuyo precio mínimo aún se encuentre dentro de los límites de la zona de soporte previamente determinada, es decir, entre el precio más bajo de la primera vela del mínimo oscilatorio y el precio mínimo de su cuerpo. Cuando se satisface esta necesidad, el mercado ha respetado repetidamente el mismo nivel de precios, fortaleciendo la zona de soporte y aumentando su fiabilidad para posibles oportunidades de compra.
Ejemplo:double second_sup_price; datetime second_sup_time; string first_low_txt; string second_low_txt;
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- CopyOpen(_Symbol, timeframe, TimeCurrent(), bars_check, open); CopyClose(_Symbol, timeframe, TimeCurrent(), bars_check, close); CopyLow(_Symbol, timeframe, TimeCurrent(), bars_check, low); CopyHigh(_Symbol, timeframe, TimeCurrent(), bars_check, high); CopyTime(_Symbol, timeframe, TimeCurrent(), bars_check, time); total_symbol_bars = Bars(_Symbol, timeframe); if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); break; } } } } } }
Resultado:

Explicación:
Monitoreamos su tiempo y precio antes de buscar un segundo mínimo de oscilación, y marcamos ambos mínimos de oscilación en el gráfico para una fácil identificación visual. Luego se busca un segundo mínimo oscilante que se produzca después del primero utilizando un bucle for. Una vela después del primer mínimo oscilatorio, o i + 1, el bucle comienza a comprobar y continúa a través de las barras restantes. La función de mínimo oscilante evalúa cada vela dentro del bucle para ver si genera otro patrón de mínimo oscilante.
El programa determina simultáneamente si el mínimo del segundo mínimo oscilatorio cae dentro de la primera zona de soporte, o entre el precio más bajo del primer mínimo oscilatorio y el precio mínimo del cuerpo. El programa confirma que se ha desarrollado un segundo mínimo legítimo dentro de la zona de soporte registrando el precio y la hora del nuevo mínimo de oscilación si se cumplen estos criterios.
Para dibujar la zona de soporte solo cuando ambos mínimos de oscilación confirmen la misma área, ahora debemos reubicar el objeto rectangular que construimos previamente dentro de este bucle. Esto garantiza que la zona sea simplemente un nivel de soporte validado y que no se trace demasiado pronto.
Identificación de la ruptura de la zona de soporte
Los dos mínimos de oscilación que hemos encontrado hasta ahora han dado un giro en el mismo rango de precios, creando lo que parece ser una posible zona de soporte. Pero no todas las zonas con dos inversiones son adecuadas para nuestro enfoque. Solo deseamos conservar las zonas en las que el mercado haya respetado el nivel en dos ocasiones sin caer por debajo de él. Para garantizar esto, debemos excluir cualquier zona que haya experimentado una ruptura previamente. Al limitar el énfasis del EA a zonas de soporte sólidas y activas donde el precio ha demostrado un respeto y un rechazo inequívocos, este paso mejorará la precisión de las futuras señales de trading.
Ejemplo:double second_sup_price; datetime second_sup_time; string first_low_txt; string second_low_txt; int sup_bars; int sup_min_low_index; double sup_min_low_price;
if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; sup_bars = Bars(_Symbol,timeframe,first_sup_time,TimeCurrent()); sup_min_low_index = ArrayMinimum(low,i,sup_bars); sup_min_low_price = low[sup_min_low_index]; if(sup_min_low_price >= first_sup_price) { support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); } break; } } } } }
Resultado:

Explicación:
Para determinar si el mercado ha caído por debajo de la zona de soporte designada o si la zona sigue siendo válida, en esta sección de la explicación se introducen tres variables. Entre el momento del mínimo inicial y el presente, la primera variable cuenta el número de velas que se han creado. Esto ayuda a definir el rango de barras que se examinarán para confirmar la zona de soporte o buscar una posible ruptura.
El programa determina entonces qué vela de ese rango tiene el precio más bajo, lo que indica el punto en el que se ha producido el mayor movimiento a la baja desde el primer mínimo. A continuación, se obtiene el valor real del precio en ese punto más bajo y se guarda para su posterior análisis.
Posteriormente, se aplica un criterio para determinar si el mercado ha roto por debajo o ha respetado la zona de soporte. Se considera que la zona de soporte es legítima y que el mercado mantiene ese nivel si el precio más bajo detectado se mantiene por encima o igual al primer precio mínimo de oscilación. En esta situación, el área de soporte se representa visualmente en el gráfico mediante el dibujo de componentes gráficos como rectángulos, líneas o etiquetas. Se considera que se ha producido una ruptura si el precio más bajo cae por debajo del nivel de soporte original; en este caso, no se muestran objetos gráficos porque la zona ya no es válida.
Identificación de un cambio de carácter alcista
Tras confirmar una zona de soporte válida, la siguiente etapa consiste en detectar un cambio de tendencia alcista. El mercado ha rechazado dos veces esta zona de soporte, lo que indica actividad compradora, y ya se ha definido en este punto con dos mínimos de oscilación. Pero el hecho de que una zona haya sido rechazada dos veces no es suficiente para establecer una posible reversión alcista; también necesitamos ver un cambio notable en la estructura del mercado.
Para ello, esperamos a que el mercado vuelva a situarse en la zona de soporte. Comenzamos a buscar un patrón de cambio de carácter alcista (CHOCH) cuando el precio regresa a la zona. Este patrón refleja un cambio de impulso bajista a alcista. En este caso, el patrón debe formar una serie de puntos de estructura de mercado, que incluye una secuencia estructural formada por un máximo, un mínimo, un máximo inferior y un mínimo inferior; su ruptura posterior confirma un cambio de carácter alcista. Observamos si una vela rompe y cierra por encima del máximo inferior una vez que se ha formado el mínimo inferior. Esta ruptura indica un cambio de dirección y confirma que los compradores han tomado el control.
El cambio de carácter se detecta en un marco temporal inferior, que es el que se utiliza para ejecutar la operación. El marco temporal inferior se utiliza para confirmar la entrada mediante la identificación de un cambio de carácter alcista dentro o cerca de las zonas de soporte y resistencia que se identificaron inicialmente en un marco temporal superior. Este método de múltiples marcos temporales garantiza entradas precisas y oportunas en las operaciones.
Identificación de niveles mínimos y máximos inferiores
Comenzaremos nuestro análisis con la barra más reciente del gráfico, ya que queremos determinar el cambio de carácter más reciente. Esto implica que el mínimo inferior, que es el punto más reciente en el que el precio estableció un nuevo mínimo, debería ser lo primero que busquemos. A continuación, determinaremos el máximo inferior, luego el mínimo y, por último, el máximo.
Ejemplo:
input ENUM_TIMEFRAMES timeframe = PERIOD_M30; //SUPPORT AND RESISTANCE TIMEFRAME input ENUM_TIMEFRAMES exe_timeframe = PERIOD_M5; //EXECUTION TIMEFRAME
double exe_open[]; double exe_close[]; double exe_low[]; double exe_high[]; datetime exe_time[]; int exe_total_symbol_bars; double lower_high; datetime lower_high_time; double lower_low; datetime lower_low_time; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- ArraySetAsSeries(exe_close,true); ArraySetAsSeries(exe_open,true); ArraySetAsSeries(exe_high,true); ArraySetAsSeries(exe_low,true); ArraySetAsSeries(exe_time,true); //--- return(INIT_SUCCEEDED); }
CopyOpen(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_open); CopyClose(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_close); CopyLow(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_low); CopyHigh(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_high); CopyTime(_Symbol, exe_timeframe, TimeCurrent(), bars_check, exe_time);
if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; sup_bars = Bars(_Symbol,timeframe,first_sup_time,TimeCurrent()); sup_min_low_index = ArrayMinimum(low,i,sup_bars); sup_min_low_price = low[sup_min_low_index]; if(sup_min_low_price >= first_sup_price) { support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); exe_total_symbol_bars = Bars(_Symbol, exe_timeframe); if(exe_total_symbol_bars >= bars_check) { for(int k = 4; k < bars_check-3; k++) { if(IsSwingLow(exe_low, k, 3)) { lower_low = exe_low[k]; lower_low_time = exe_time[k]; for(int l = k; l < bars_check-3; l++) { if(IsSwingHigh(exe_high,l,3)) { lower_high = exe_high[l]; lower_high_time = exe_time[l]; break; } } break; } } } } break; } } } } }
Explicación:
En esta área programática, el enfoque principal es la preparación y el análisis de datos para la ejecución de operaciones comerciales basadas en el cambio de carácter (CHoCH). En primer lugar, se define el marco temporal de ejecución, que en este caso tiene una duración más corta, como el gráfico de 5 minutos. Para capturar con mayor precisión los movimientos del mercado, las confirmaciones reales de las entradas de operaciones se producen en un período inferior, incluso cuando las zonas de soporte y resistencia se indican en marcos temporales superiores, como los gráficos diarios o semanales.
Posteriormente, se crean matrices para almacenar los datos de precio y tiempo de las velas del período de ejecución. Estos conjuntos de datos son esenciales para el análisis estructural, ya que proporcionan al EA una referencia precisa de los máximos, mínimos, aperturas y cierres de cada vela. Junto con el precio y la hora del máximo y mínimo más recientes, se proporcionan otras variables para mantener el número total de velas disponibles.
El programa primero verifica que haya suficientes velas en el marco temporal elegido para realizar un análisis útil antes de continuar. Busca mínimos de oscilación analizando cada vela después de la confirmación. Cuando el mínimo de la vela actual está por debajo de los mínimos de algunas velas anteriores y posteriores, se demuestra que es un mínimo de oscilación, lo que indica que se ha alcanzado el fondo del mercado local. El mínimo inferior es el precio y el momento en que se produce el mínimo oscilatorio cuando se descubre.
Tras identificar un mínimo inferior, el software procede a buscar el siguiente máximo de oscilación. Cuando el máximo de una vela supera los máximos de las velas adyacentes, lo que indica un pico transitorio, se demuestra que se trata de un máximo de oscilación. Tras identificar el mínimo y el máximo inferiores, la fase de análisis ha terminado y el EA está preparado para evaluar la estructura del mercado en busca de posibles cambios de carácter bajista o alcista.
Identificación de niveles bajos y altos
La siguiente etapa, tras determinar el mínimo inferior y el máximo inferior, consiste en encontrar el nuevo mínimo y el nuevo máximo que le siguen. Esta fase garantiza que la estructura del mercado esté configurada correctamente para validar un cambio de carácter válido. El mercado se encontraba previamente en declive cuando el máximo inferior estaba por encima del mínimo inferior.
Para indicar un debilitamiento del movimiento bajista, el nuevo mínimo formado debería situarse entre los dos, es decir, por debajo del máximo inferior pero por encima del mínimo inferior. El mercado ha cambiado su dinámica de bajista a alcista, lo que indica el comienzo de un posible repunte si el máximo posterior, que se convierte en un máximo más alto, supera todos los máximos y mínimos anteriores.
Ejemplo:
double low_l; datetime low_time; double high_h; datetime high_time;
for(int m = l; m < bars_check-3; m++) { if(IsSwingLow(exe_low, m, 3)) { low_l = exe_low[m]; low_time = exe_time[m]; for(int n = m; n < bars_check-3; n++) { if(IsSwingHigh(exe_high,n,3)) { high_h = exe_high[n]; high_time = exe_time[n]; break; } } break; }
Explicación:
Esta sección del software utiliza una serie de criterios para identificar los próximos puntos de inflexión significativos que respaldan un cambio de tendencia alcista. Estos consisten en el precio y el tiempo de oscilación mínimos y máximos recientemente establecidos. El EA puede determinar si la estructura del mercado ha cambiado de una tendencia bajista a una alcista mediante el monitoreo de estos parámetros.
El programa busca en las velas recientes un nuevo mínimo de oscilación antes de identificar estas ubicaciones. Tras detectar el nuevo mínimo, busca rápidamente el siguiente máximo, anotando su precio y el momento en que se produce. Encontrar el nuevo punto máximo de oscilación y almacenar sus detalles completa la identificación de la secuencia de oscilación crucial necesaria para evaluar la alteración estructural.
Cuando una vela alcista cierra por encima del máximo inferior que se creó previamente, confirma un cambio de tendencia alcista. Este acontecimiento pone fin, en esencia, al período bajista, al indicar que los compradores han tomado el control. La formación de máximos y mínimos cada vez más altos en el mercado indica un posible cambio de tendencia y el inicio de una nueva estructura alcista.
Ejemplo:
datetime start_choch_time;if(total_symbol_bars >= bars_check) { for(int i = z ; i < bars_check - z; i++) { if(IsSwingLow(low, i, z)) { first_sup_price = low[i]; first_sup_min_body_price = MathMin(close[i], open[i]); first_sup_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingLow(low, j, z) && low[j] <= first_sup_min_body_price && low[j] >= first_sup_price) { second_sup_price = low[j]; second_sup_time = time[j]; start_choch_time = time[j+z]; sup_bars = Bars(_Symbol,timeframe,first_sup_time,TimeCurrent()); sup_min_low_index = ArrayMinimum(low,i,sup_bars); sup_min_low_price = low[sup_min_low_index]; if(sup_min_low_price >= first_sup_price) { support_object = StringFormat("SUPPORT %f",first_sup_price); ObjectCreate(chart_id,support_object,OBJ_RECTANGLE,0,first_sup_time,first_sup_price,TimeCurrent(),first_sup_min_body_price); ObjectSetInteger(chart_id,support_object,OBJPROP_COLOR,clrBlue); ObjectSetInteger(chart_id,support_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,support_object,OBJPROP_FILL,true); first_low_txt = StringFormat("FIRST LOW%d",i); ObjectCreate(chart_id,first_low_txt,OBJ_TEXT,0,first_sup_time,first_sup_price); ObjectSetString(chart_id,first_low_txt,OBJPROP_TEXT,"1"); second_low_txt = StringFormat("SECOND LOW%d",i); ObjectCreate(chart_id,second_low_txt,OBJ_TEXT,0,second_sup_time,second_sup_price); ObjectSetString(chart_id,second_low_txt,OBJPROP_TEXT,"2"); exe_total_symbol_bars = Bars(_Symbol, exe_timeframe); if(exe_total_symbol_bars >= bars_check) { for(int k = 4; k < bars_check-3; k++) { if(IsSwingLow(exe_low, k, 3)) { lower_low = exe_low[k]; lower_low_time = exe_time[k]; for(int l = k; l < bars_check-3; l++) { if(IsSwingHigh(exe_high,l,3)) { lower_high = exe_high[l]; lower_high_time = exe_time[l]; for(int m = l; m < bars_check-3; m++) { if(IsSwingLow(exe_low, m, 3)) { low_l = exe_low[m]; low_time = exe_time[m]; for(int n = m; n < bars_check-3; n++) { if(IsSwingHigh(exe_high,n,3)) { high_h = exe_high[n]; high_time = exe_time[n]; for(int o = k; o > 0; o--) { if(exe_close[o] > lower_high && exe_open[o] < lower_high) { if(lower_high > lower_low && low_l < lower_high && low_l > lower_low && high_h > low_l && high_h > lower_high && lower_low <= first_sup_min_body_price && lower_low >= first_sup_price && high_time > start_choch_time) { ObjectCreate(chart_id,"LLLH",OBJ_TREND,0,lower_low_time,lower_low,lower_high_time,lower_high); ObjectSetInteger(chart_id,"LLLH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LLLH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LHL",OBJ_TREND,0,lower_high_time,lower_high,low_time,low_l); ObjectSetInteger(chart_id,"LHL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LHL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LH",OBJ_TREND,0,low_time,low_l,high_time,high_h); ObjectSetInteger(chart_id,"LH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"S Cross Line",OBJ_TREND,0,lower_high_time,lower_high,exe_time[o],lower_high); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_WIDTH,2); } break; } } break; } } break; } } break; } } break; } } } } break; } } } } }

Explicación:
Esta parte establece primero un punto de referencia para indicar el momento adecuado para comenzar el análisis de cambio de carácter (CHOCH). Esto garantiza que, tras verificar la zona de soporte más reciente, el programa solo comenzará a buscar cambios estructurales.
A continuación, el programa analiza las velas en orden inverso para identificar una que cierre por encima del máximo inferior, lo que indica el comienzo de un cambio alcista en el sentimiento del mercado. Una vela que cierra por encima del máximo inferior y abre por debajo del mismo proporciona fuertes indicios de un avance significativo y una posible reversión del mercado.
Tras localizar dicha vela, el programa ejecuta una serie de pruebas de verificación para asegurarse de que el cambio de carácter sea válido. El EA conecta los principales puntos de inflexión (mínimo inferior, máximo inferior, nuevo mínimo y máximo superior) en el gráfico para indicar gráficamente la estructura una vez que se cumplen todos estos requisitos. Además, llama la atención sobre la vela de ruptura que cerró por encima del máximo inferior, lo que indica que los compradores han retomado el control del mercado y actúa como la última confirmación de un cambio de carácter alcista.
Ejecución de operaciones
Todas las confirmaciones anteriores se combinan para crear una posible configuración de operación en la última sección de la lógica, que está dedicada a la ejecución de la operación. El código comprueba ahora si se han cumplido todos y cada uno de los requisitos especificados para un «Change of Character» (CHoCH) alcista. El software marca entonces la estructura en el gráfico y se prepara para ejecutar la operación tras la confirmación.
Ejemplo:
#include <Trade/Trade.mqh>
CTrade trade;
input ENUM_TIMEFRAMES timeframe = PERIOD_W1; //SUPPORT AND RESISTANCE TIMEFRAME input ENUM_TIMEFRAMES exe_timeframe = PERIOD_M30; //EXECUTION TIMEFRAME input double lot_size = 0.2; // Lot Size input double RRR = 3; //RRR double ask_price; double take_profit; datetime lastTradeBarTime = 0;
datetime currentBarTime = iTime(_Symbol, exe_timeframe, 0); ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
for(int o = k; o > 0; o--) { if(exe_close[o] > lower_high && exe_open[o] < lower_high) { if(lower_high > lower_low && low_l < lower_high && low_l > lower_low && high_h > low_l && high_h > lower_high && lower_low <= first_sup_min_body_price && lower_low >= first_sup_price && high_time > start_choch_time) { ObjectCreate(chart_id,"LLLH",OBJ_TREND,0,lower_low_time,lower_low,lower_high_time,lower_high); ObjectSetInteger(chart_id,"LLLH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LLLH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LHL",OBJ_TREND,0,lower_high_time,lower_high,low_time,low_l); ObjectSetInteger(chart_id,"LHL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LHL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"LH",OBJ_TREND,0,low_time,low_l,high_time,high_h); ObjectSetInteger(chart_id,"LH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"LH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"S Cross Line",OBJ_TREND,0,lower_high_time,lower_high,exe_time[o],lower_high); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"S Cross Line",OBJPROP_WIDTH,2); if(exe_time[1] == exe_time[o] && currentBarTime != lastTradeBarTime) { take_profit = MathAbs(ask_price + ((ask_price - lower_low) * RRR)); trade.Buy(lot_size,_Symbol,ask_price,lower_low,take_profit); lastTradeBarTime = currentBarTime; } } break; } }
Resultado:

Explicación:
Tras verificar un «Change of Character» (CHoCH) alcista, en esta sección se describe la configuración de la operación y el procedimiento de ejecución. Para que el sistema coloque automáticamente órdenes de compra cuando se cumplan todos los requisitos de negociación, primero debe habilitar las actividades comerciales. Los parámetros de la operación se definen mediante una serie de datos de entrada, entre los que se incluyen el tamaño del lote para cada operación, los plazos para la detección y ejecución de soportes/resistencias y la relación riesgo-recompensa (RRR), que establece el beneficio deseado en relación con el riesgo.
Para garantizar que solo reaccione una vez por cada vela, el algoritmo también monitoriza el precio actual del mercado y la duración de la vela. Esto evita ejecutar más de una operación en la misma barra. El programa verifica que todos los parámetros estén en orden antes de realizar una operación, como el momento previsto de la vela y la ausencia de operaciones previas en esa barra. Basándose en el RRR, determina el nivel de toma de ganancias después de la confirmación, coloca el stop loss en el mínimo inferior e inicia automáticamente una operación de compra. Como resultado, se garantiza que las operaciones comerciales sean disciplinadas, consistentes y se basen en mecanismos de mercado establecidos, en lugar de juicios arbitrarios.
Identificación de la zona de resistencia
También hay que determinar la zona de resistencia, que es justo lo opuesto a la zona de soporte. Los máximos de oscilación se utilizan para identificar la zona de resistencia, mientras que los mínimos de oscilación se utilizan para identificar la zona de soporte. Dicho de otro modo, buscamos zonas donde el mercado ha rechazado el avance alcista, en lugar de áreas donde se ha resistido a un movimiento bajista.
La misma lógica que determina el soporte también determina una zona de resistencia, pero lo contrario es cierto. Antes de definir la zona que rodea un máximo oscilante, primero identificamos dicho máximo. Tras determinar y marcar el primer máximo, el siguiente paso es evaluar si se ha desarrollado un segundo máximo dentro de la misma zona de resistencia. El precio ha puesto a prueba y rechazado la zona dos veces, demostrando su validez como zona de resistencia, si el mercado realiza un segundo máximo dentro de la zona resaltada.
Es posible que al mercado le resulte difícil superar esta zona de resistencia e incluso que retroceda, lo que podría representar una oportunidad de venta. Sin embargo, debemos esperar a que se produzca un cambio de carácter bajista para verificar si realmente se está desarrollando una configuración bajista. En consecuencia, el mercado debe empezar a formar máximos más bajos y mínimos más bajos, en lugar de seguir formando máximos más altos y mínimos más bajos. La señal definitiva de que los vendedores han tomado el control y de que puede producirse un movimiento a la baja es este cambio de carácter bajista que tiene lugar dentro o cerca de la zona de resistencia.
Ejemplo:
double first_res_price; double first_res_max_body_price; datetime first_res_time; double second_res_price; datetime second_res_time; string resistance_object; int res_bars; int res_max_high_index; double res_max_high_price; string first_high_txt; string second_high_txt; double higher_high; datetime higher_high_time; double higher_low; datetime higher_low_time;
//RESISTANCE for(int i = z ; i < bars_check - z; i++) { if(IsSwingHigh(high, i, z)) { first_res_price = high[i]; first_res_max_body_price = MathMax(close[i], open[i]); first_res_time = time[i]; for(int j = i+1; j < bars_check - z; j++) { if(IsSwingHigh(high, j, z) && high[j] >= first_res_max_body_price && high[j] <= first_res_price) { second_res_price = high[j]; second_res_time = time[j]; start_choch_time = time[j+z]; resistance_object = StringFormat("RESISTANCE %f",first_res_price); res_bars = Bars(_Symbol,timeframe,first_res_time,TimeCurrent()); res_max_high_index = ArrayMaximum(high,i,res_bars); res_max_high_price = high[res_max_high_index]; if(res_max_high_price <= first_res_price) { ObjectCreate(chart_id,resistance_object,OBJ_RECTANGLE,0,first_res_time,first_res_price,TimeCurrent(),first_res_max_body_price); ObjectSetInteger(chart_id,resistance_object,OBJPROP_COLOR,clrGreen); ObjectSetInteger(chart_id,resistance_object,OBJPROP_BACK,true); ObjectSetInteger(chart_id,resistance_object,OBJPROP_FILL,true); first_high_txt = StringFormat("FIRST HIGH%d",i); ObjectCreate(chart_id,first_high_txt,OBJ_TEXT,0,first_res_time,first_res_price); ObjectSetString(chart_id,first_high_txt,OBJPROP_TEXT,"1"); second_high_txt = StringFormat("SECOND HIGH%d",i); ObjectCreate(chart_id,second_high_txt,OBJ_TEXT,0,second_res_time,second_res_price); ObjectSetString(chart_id,second_high_txt,OBJPROP_TEXT,"2"); if(exe_total_symbol_bars >= bars_check) { for(int k = 4; k < bars_check-3; k++) { if(IsSwingHigh(exe_high, k, 3)) { higher_high = exe_high[k]; higher_high_time = exe_time[k]; for(int l = k; l < bars_check-3; l++) { if(IsSwingLow(exe_low,l,3)) { higher_low = exe_low[l]; higher_low_time = exe_time[l]; for(int m = l; m < bars_check-3; m++) { if(IsSwingHigh(exe_high, m, 3)) { high_h = exe_high[m]; high_time = exe_time[m]; for(int n = m; n < bars_check-3; n++) { if(IsSwingLow(exe_low,n,3)) { low_l = exe_low[n]; low_time = exe_time[n]; for(int o = k; o > 0; o--) { if(exe_close[o] < higher_low && exe_open[o] > higher_low) { if(higher_low < higher_high && high_h > higher_low && high_h < higher_high && low_l < high_h && low_l < higher_low && higher_high >= first_res_max_body_price && higher_high <= first_res_price && low_time > start_choch_time) { ObjectCreate(chart_id,"HHHL",OBJ_TREND,0,higher_high_time,higher_high,higher_low_time,higher_low); ObjectSetInteger(chart_id,"HHHL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"HHHL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"HLH",OBJ_TREND,0,higher_low_time,higher_low,high_time,high_h); ObjectSetInteger(chart_id,"HLH",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"HLH",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"HL",OBJ_TREND,0,high_time,high_h,low_time,low_l); ObjectSetInteger(chart_id,"HL",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"HL",OBJPROP_WIDTH,2); ObjectCreate(chart_id,"R Cross Line",OBJ_TREND,0,higher_low_time,higher_low,exe_time[o],higher_low); ObjectSetInteger(chart_id,"R Cross Line",OBJPROP_COLOR,clrRed); ObjectSetInteger(chart_id,"R Cross Line",OBJPROP_WIDTH,2); if(exe_time[1] == exe_time[o] && currentBarTime != lastTradeBarTime) { take_profit = MathAbs(ask_price - ((high_h - ask_price) * RRR)); trade.Sell(lot_size,_Symbol,ask_price,higher_high,take_profit); lastTradeBarTime = currentBarTime; } } break; } } break; } } break; } } break; } } break; } } } } break; } } } }
Resultado:

Explicación:
Encontrar máximos de oscilación notables en el gráfico, recorriendo las velas en bucle, es el primer paso para determinar la zona de resistencia. El primer paso consiste en encontrar un máximo de oscilación y anotar su precio máximo, el mayor entre su precio de apertura y su precio de cierre, y el momento en que se formó. El programa busca un segundo máximo de oscilación que caiga dentro de la zona que define el primer máximo después de detectar este máximo de oscilación inicial.
El mercado ha puesto a prueba la región en dos ocasiones, confirmando su validez como zona de resistencia con su segundo máximo. Antes de dibujar el rectángulo visual para la región de resistencia en el gráfico, el ordenador determina el precio más alto entre los dos máximos para asegurarse de que ninguna vela haya roto por encima de la zona. Para identificar las dos ubicaciones que componen la zona, el programa utiliza objetos de texto para designar los máximos de oscilación primero y segundo.
El programa busca entonces un cambio de carácter bajista para confirmar la operación tras detectar la zona de resistencia. Busca una secuencia de precios con un máximo creciente, seguido de un mínimo creciente, luego un máximo decreciente y un mínimo decreciente, creando un patrón bajista, utilizando un período inferior designado para la ejecución. La aplicación crea líneas de tendencia que unen los máximos y mínimos relevantes para su visualización, registrándolos junto con sus marcas de tiempo.
Cuando una vela bajista cierra por debajo del mínimo más alto del patrón, sirve como confirmación final. El Asesor Experto (EA) determina el punto de toma de ganancias multiplicando la distancia entre el precio de entrada y el máximo del patrón por la relación riesgo-recompensa, y luego ejecuta una operación de venta cuando esta condición coincide con la zona de resistencia. Al comparar la hora de la barra actual con la operación más reciente que se ejecutó, el método garantiza que cada vela contenga solo una operación. Con este método, las zonas de resistencia se identifican automáticamente, se verifican mediante patrones de acción del precio y las operaciones solo se ejecutan cuando se cumplen todos los requisitos.
Nota:
La estrategia de este artículo se basa completamente en proyectos y tiene como objetivo enseñar a los lectores MQL5 a través de aplicaciones prácticas en el mundo real. No es un método garantizado para obtener beneficios en el trading en tiempo real.
Conclusión
El EA que hemos desarrollado identifica zonas de soporte y resistencia mediante la detección de máximos y mínimos oscilantes que se han puesto a prueba al menos dos veces, lo que garantiza que dichas zonas sean significativas. A continuación, monitoriza cambios de carácter alcistas o bajistas en un marco temporal inferior, confirmando los puntos de entrada adecuados. Al combinar la detección de zonas en marcos temporales superiores con la acción del precio en marcos temporales inferiores, el EA puede ejecutar automáticamente operaciones con niveles definidos de stop loss y take profit.
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/20021
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Del básico al intermedio: Clases (III)
Particularidades del trabajo con números del tipo double en MQL4
Simulación de mercado: Position View (XVI)
- 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