English Русский Deutsch 日本語
preview
Introducción a MQL5 (Parte 25): Creación de un asesor experto (EA) que opere a partir de objetos del gráfico (II)

Introducción a MQL5 (Parte 25): Creación de un asesor experto (EA) que opere a partir de objetos del gráfico (II)

MetaTrader 5Sistemas comerciales |
30 1
ALGOYIN LTD
Israel Pelumi Abioye

Introducción

¡Bienvenidos de nuevo a la parte 25 de la serie Introducción a MQL5! En el artículo anterior, exploramos cómo la combinación del análisis manual de gráficos con la ejecución automatizada de operaciones mediante objetos gráficos ayuda a cerrar la brecha entre las operaciones discrecionales y las automatizadas. Ese proyecto se centró en las zonas de soporte y resistencia dibujadas con la herramienta Rectángulo.

Este artículo es una continuación de ese concepto, pero esta vez utilizaremos líneas de tendencia. Entre las técnicas más utilizadas en el análisis técnico, las líneas de tendencia ayudan a determinar la dirección del mercado, así como los posibles puntos de ruptura o reversión. Crearemos un Asesor Experto (EA) capaz de identificar líneas de tendencia en el gráfico y que, en función del estado del mercado, inicie automáticamente operaciones cuando el precio rompa por encima o por debajo de ella.

 

Cómo funciona el EA

El usuario dibujará manualmente dos líneas de tendencia en el gráfico, que serán utilizadas por el Asesor Experto (EA). Una línea que indica una tendencia bajista se traza desde un punto más alto a uno más bajo, mientras que otra que indica una tendencia alcista se traza desde un punto más bajo a uno más alto. El Asesor Experto utilizará sus nombres para identificar los objetos correspondientes en el gráfico. Esto implica que el usuario deberá introducir los nombres exactos de las líneas de tendencia en los ajustes de entrada. Incluso cuando hay varias líneas de tendencia en el gráfico, este método proporciona al EA una referencia clara sobre qué objetos debe vigilar.

Además, el usuario tendrá la posibilidad de especificar el marco temporal que debe seguir el Asesor Experto (EA) debe seguir, el tamaño del lote que desea utilizar y el estilo de negociación que desea emplear. Entre los modos de negociación disponibles se encuentran dos opciones: aquella en la que el Asesor Experto (EA) gestiona tanto las condiciones de reversión como las de ruptura y retest en función del comportamiento del precio alrededor de la línea de tendencia, y la reversión, en la que el EA abre una operación cuando el precio toca la línea de tendencia y muestra una señal de reversión. El modo de ruptura y retest espera a que el precio rompa la línea de tendencia antes de abrir una operación.

Figura 1: Cómo funciona el EA

Para la gestión de operaciones, el EA establecerá automáticamente los niveles de stop loss (SL) y take profit (TP) en función de la última vela cerrada.

  • En una operación de compra, el stop loss se colocará en el mínimo de la vela cerrada más recientemente.
  • En una operación de venta, el stop loss se colocará en el máximo de la vela que cerró más recientemente.
  • El nivel de toma de ganancias (TP) se establecerá en 1:4 de la distancia entre el precio de entrada y el nivel de stop-loss.

Figura 2: Reversión

Figura 3: Ruptura y retest



Identificación de líneas de tendencia

La siguiente etapa consiste en explorar cómo el Asesor Experto (EA) reconocerá las líneas de tendencia en el gráfico ahora que usted comprende a fondo su funcionamiento. El EA necesita un método sencillo para distinguir entre las líneas que indican la tendencia alcista y la bajista, ya que depende de las líneas de tendencia dibujadas por el usuario.

Para ello se utilizarán los nombres de las líneas de tendencia. Los nombres que el usuario introduzca en la configuración serán utilizados por el Asesor Experto (EA) para buscar elementos en el gráfico. Mediante la coincidencia de nombres, el EA puede localizar con precisión cada línea de tendencia en el gráfico y seguir su posición en tiempo real. El EA solo reaccionará ante las líneas de tendencia concretas que el usuario haya seleccionado, aunque el gráfico contenga otras líneas o elementos gráficos.

Ejemplo:
input string down_trend = ""; // Down Trend Line
input string up_trend = ""; // Up Trend Line

ulong chart_id = ChartID();
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true);

  }

Explicación:

El asesor experto (EA) debe comprender las líneas de tendencia del gráfico antes de poder reconocerlas y manipularlas. Para ello, diseñamos opciones de entrada que permiten al usuario introducir los nombres de las dos líneas de tendencia. Una línea se utilizará para indicar la tendencia bajista, mientras que la otra se utilizará para simbolizar la tendencia alcista. Incluso cuando hay muchos otros dibujos o símbolos, esta técnica de denominación ayuda al EA a identificar con precisión qué objetos del gráfico debe seguir / cuáles son los objetos relevantes para su lógica.

Figura 4: Nombre del objeto

El EA también debe conocer el gráfico con el que está trabajando. Cada gráfico en MetaTrader 5 incluye un ID de gráfico, que es un número de identificación especial. Al obtener esta identificación, el EA garantiza que solo interactuará con el gráfico apropiado y sus elementos.

Extender las líneas de tendencia hacia el lado derecho del gráfico es un componente crucial de esta configuración. Debido a esta modificación, las líneas de tendencia pueden extenderse hacia futuras regiones de precios y continuar más allá de sus puntos de anclaje. Dado que permite al EA identificar las interacciones de precios con las líneas de tendencia incluso después de que se hayan formado nuevas velas, se trata de un paso crucial. Sin esta extensión, las líneas se detendrían en sus puntos de anclaje, lo que imposibilitaría que el EA detectara próximas rupturas o reversiones. A medida que el mercado cambia, extenderlos más allá de los puntos de anclaje garantiza una detección fiable de señales y un seguimiento continuo.

Figura 5: Precio de anclaje


Obtención de datos de velas y de la línea de tendencia bajista

Para que el EA pueda examinar cómo se mueve el precio alrededor de las líneas de tendencia, el siguiente paso es recuperar los datos de las velas y de las líneas de tendencia. El EA copiará primero los datos de las últimas cinco velas del gráfico. Basándonos únicamente en estas velas recientes, podemos determinar si es posible una ruptura o una reversión.

El EA recopilará los datos de la línea de tendencia dentro del mismo rango de cinco velas después de obtener los datos de las velas. Solo tendrá en cuenta los precios de la línea de tendencia que coincidan con esas velas recientes, en lugar de los puntos de anclaje. De esta forma, el EA podrá comparar los movimientos actuales de las velas con los niveles de precios precisos de las líneas de tendencia para ese mismo período de tiempo.

El EA puede identificar cuándo un precio rompe por encima, por debajo o revierte una línea de tendencia examinando la correlación entre los precios de la línea de tendencia y las últimas cinco velas. Esta técnica garantiza que el EA responda únicamente a los movimientos de mercado más recientes y relevantes, y mejora la precisión del proceso de detección.

Analogía

Consideremos al EA como un vigilante constante del mercado, similar a un detective que examina la escena de un crimen. Cada vela representa lo que sucedió en términos de precio en un momento determinado, al igual que una fotografía. Por su parte, la línea de tendencia, que indica límites importantes, se asemeja a una cuerda extendida sobre el gráfico.

El Asesor Experto examina cada vela por separado, prestando especial atención a las últimas cinco. Analiza las propiedades de cada vela, así como la ubicación precisa de la línea de tendencia en ese momento en particular. Este procedimiento es como mirar dos fotos simultáneamente, una de las cuales muestra el movimiento de la vela y la otra la ubicación de la línea de tendencia durante ese movimiento.

El EA inicia su análisis tras recopilar estos datos. Plantea preguntas como: ¿el máximo o el mínimo de la vela tocaron la línea de tendencia? ¿Estaba por encima o por debajo cuando la vela la cruzó? ¿Hubo una vela alcista o bajista?

De forma similar a como un operador inspecciona visualmente un gráfico para ver cuándo el precio toca o rompe una línea, el Asesor Experto (EA, por sus siglas en inglés) puede comprender cómo interactuó la vela con la línea de tendencia comparando ambos datos de forma conjunta.

Ejemplo:
input string down_trend = ""; // Down Trend Line
input string up_trend = ""; // Up Trend Line
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT; // TIME FRAME

ulong chart_id = ChartID();

double close_price[];
double open_price[];
double low_price[];
double high_price[];
datetime time_price[];

double td_line_value;
double td1_line_value;
double td2_line_value;
double td3_line_value;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true);

   CopyOpen(_Symbol, time_frame, 1, 5, open_price);
   CopyClose(_Symbol, time_frame, 1, 5, close_price);
   CopyLow(_Symbol, time_frame, 1, 5, low_price);
   CopyHigh(_Symbol, time_frame, 1, 5, high_price);
   CopyTime(_Symbol, time_frame, 1, 5, time_price);

//DOWN TREND

   td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
   td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
   td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
   td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

  }

Explicación:

En este paso inicial, el programa establece el intervalo de tiempo en el que se ejecutará y se prepara para almacenar la información de las velas en contenedores vacíos. Los precios de apertura, cierre, máximo y mínimo de cada vela, junto con el momento preciso en que apareció la vela en el gráfico, se almacenarán posteriormente en estos contenedores. Antes de comenzar el análisis, esta configuración garantiza que el programa pueda obtener datos de precios completos y bien estructurados del mercado.

double td_line_value;
double td1_line_value;
double td2_line_value;
double td3_line_value;

En esta etapa, se configuran espacios de almacenamiento para albergar datos numéricos que muestren la ubicación de la línea de tendencia en momentos específicos. El ordenador utilizará estas cifras para comparar la evolución del precio de mercado con la línea descendente del gráfico. A continuación, los contenedores se organizan de forma que la información más reciente aparezca primero. Ahora, el ordenador puede analizar la actividad reciente del mercado con mayor facilidad, ya que puede acceder a las velas más recientes al instante, evitando la necesidad de examinar datos antiguos. Además, todos los contenedores quedan correctamente organizados antes de recibir los valores del mercado.

A continuación, el programa recopila información sobre las últimas cinco velas. Recopila sus precios, así como los momentos en que se mostraron en el gráfico. El programa puede monitorear los movimientos de precios alrededor de la línea de tendencia y determinar si se está desarrollando un patrón de ruptura o de reversión utilizando esta breve serie de velas.

td_line_value  = ObjectGetValueByTime(chart_id, down_trend, time_price[0], 0);
td1_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[1], 0);
td2_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[2], 0);
td3_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[3], 0);

Cada línea obtiene el valor del precio de la línea de tendencia en un momento determinado de la vela. El primer parámetro indica a la función qué gráfico debe examinar; además, el segundo parámetro especifica el nombre del objeto (en este caso, la línea de tendencia bajista), el momento exacto en el que debe realizarse la comprobación (correspondiente a la formación de cada vela) y la ventana del gráfico (siendo 0 el gráfico principal de precios).

En términos sencillos, esta función comprueba dónde se encontraba la línea de tendencia en el instante exacto en que apareció cada vela. El EA puede entonces comparar el pico, el mínimo o el cierre de la vela con la posición de la línea, ya que devuelve el nivel de precio de la línea en ese momento. Esto ayuda a identificar situaciones de ruptura o reversión, ya que permite determinar si la vela tocó o cruzó la línea de tendencia.

 

Identificación de la reversión de la tendencia bajista

La siguiente etapa consiste en encontrar un cambio de tendencia a la baja, lo que indica una oportunidad de venta. En este caso, el EA (Asesor Experto) vigilará la interacción entre la línea de tendencia bajista y las velas recientes. El Asesor Experto determinará si una vela cierra por debajo de la línea, lo que indicaría una posible reversión, cuando el precio se acerque o la toque. Este comportamiento puede ser un indicio de una operación de venta, ya que indica que los vendedores están recuperando el control del mercado.

Pero es importante evitar operar en exceso o duplicar las señales. Antes de hacerlo, el EA comprueba en primer lugar que no haya habido ninguna señal de trading reciente en las últimas barras. Esto garantiza que el programa solo reaccione a nuevas configuraciones y evita que abra operaciones redundantes o innecesarias en el mismo marco temporal.

Ejemplo:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true);

   CopyOpen(_Symbol, time_frame, 1, 5, open_price);
   CopyClose(_Symbol, time_frame, 1, 5, close_price);
   CopyLow(_Symbol, time_frame, 1, 5, low_price);
   CopyHigh(_Symbol, time_frame, 1, 5, high_price);
   CopyTime(_Symbol, time_frame, 1, 5, time_price);

//DOWN TREND

   td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
   td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
   td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
   td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

   bool prev_touch_down = false;

   if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
      ||
      (high_price[2] > td2_line_value && close_price[2] < open_price[2])
     )
     {
      prev_touch_down = true;
     }
   int no_bars_down = 0;
   for(int i = 0; i <= 3; i++)
     {
      if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
        {
         for(int j = i; j >= 0; j--)
           {
            if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
              {
               no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

               break;
              }
           }
         break;
        }
     }
  }

Explicación:

bool prev_touch_down = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {
   prev_touch_down = true;
  }

En la primera línea, una variable se inicializa como falsa. Esta variable actúa como un marcador para indicar si recientemente hubo una reacción bajista válida tras tocar la línea de tendencia bajista. Dado que no se encontró tal condición al principio, la bandera sigue siendo falsa. La idea es que esta variable se actualizará a verdadero después de que el sistema confirme una reacción bajista a la línea de tendencia. Esta variable puede utilizarse posteriormente para controlar las acciones comerciales futuras, incluyendo la posibilidad de evitar señales de venta múltiples o repetidas en un corto marco temporal.

La condición de la instrucción if examina dos velas recientes para ver si alguna de ellas satisface las condiciones de reversión. (high_price[1] > td1_line_value && close_price[1] < open_price[1]) es la primera parte de la condición que examina la vela que cerró justo antes de la actual. Determina si el pico de la vela cruzó la línea de tendencia en ese momento, lo que significa que el precio tocó o penetró marginalmente la línea. La vela se confirma entonces como bajista al comprobarse que cerró a un precio inferior al de apertura. Para poner a prueba la línea de tendencia, es posible que los compradores hayan impulsado el precio al alza, pero los vendedores retomaron el control e hicieron bajar el mercado, dejando una mecha de rechazo por encima.

Para registrar los rechazos anteriores, la segunda sección examina la vela de hace dos barras. Se considera legítimo si una de las dos velas cumple con los criterios de rechazo.

El código encerrado entre llaves cambia el valor del indicador a verdadero cuando la condición se evalúa como verdadera. Según este informe, el mercado ya ha reaccionado negativamente a la tendencia a la baja. Este indicador puede utilizarse como medida de protección en fases posteriores del programa para evitar el exceso de operaciones, asegurándose de que los contactos repetidos en torno a la misma ubicación no provoquen que el sistema genere señales de venta adicionales.

En conclusión, este bloque de código ayuda a localizar una señal legítima de reversión de la tendencia bajista. Cuando una vela se aproxima a la línea de tendencia desde abajo, la toca y cierra a la baja, se confirma que lo ha hecho. El programa sienta las bases para una ejecución de operaciones más disciplinada al identificar este comportamiento y señalarlo. De este modo, las reversiones bajistas solo se confirman cuando la acción del precio muestra un rechazo claro en la línea de tendencia, lo que permite evitar señales duplicadas innecesarias.

int no_bars_down = 0;

for(int i = 0; i <= 3; i++)
  {
   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
     {
      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {
            no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

            break;
           }
        }
      break;
     }
  }

int no_bars_down = 0; se utiliza para inicializar un contador a cero al comienzo del código. Este contador registrará el número de barras transcurridas desde el último toque y rechazo legítimo de la línea de tendencia bajista. El bucle analiza las últimas cuatro velas para comprobar si el precio de apertura sigue por debajo de la línea de tendencia y si el máximo de cada vela la ha cruzado. Esto facilita la identificación de las velas que han tocado la línea de tendencia desde abajo, lo cual es el indicio inicial de una posible reversión.

Tras detectar una vela de este tipo, el programa busca hacia atrás para localizar la primera que cierra por debajo de la línea de tendencia y que es bajista. Esta etapa valida la señal de una posible oportunidad de venta al confirmar que el mercado rechazó la línea de tendencia. El programa determina el número de barras transcurridas desde la vela de confirmación hasta el momento actual. Este recuento ayuda a evitar alertas repetidas o duplicadas. El EA se asegura de considerar únicamente nuevas oportunidades de negociación después de que se haya producido un movimiento suficiente del mercado, haciendo un seguimiento del número de barras desde el último rechazo válido. Esto reduce significativamente el exceso de operaciones.

 

Agregar las condiciones de entrada

El siguiente paso es añadir la condición de entrada para la operación de venta. Ahora, el Asesor Experto (EA) puede especificar las circunstancias exactas en las que creará una posición después de verificar que se ha producido el cambio de tendencia bajista y de asegurarse de que no se ha activado ninguna señal reciente. Para garantizar que solo las configuraciones válidas inicien operaciones, esto implica combinar el contacto con la línea de tendencia, la confirmación de la vela bajista y el número de barras desde la última señal. El EA puede entrar en el mercado de forma metódica y evitar el exceso de operaciones estableciendo estas reglas de entrada, que garantizan que cada operación se corresponda con el patrón de reversión del gráfico.

Ejemplo:

#include <Trade/Trade.mqh>
CTrade trade;

int MagicNumber = 53217;
datetime lastTradeBarTime = 0;
double ask_price;
double take_profit;
//+------------------------------------------------------------------+
//| Expert initialization function                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArraySetAsSeries(close_price, true);
   ArraySetAsSeries(open_price, true);
   ArraySetAsSeries(low_price, true);
   ArraySetAsSeries(high_price, true);
   ArraySetAsSeries(time_price, true);

   trade.SetExpertMagicNumber(MagicNumber);

//---
   return(INIT_SUCCEEDED);
  }
ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
datetime currentBarTime = iTime(_Symbol, time_frame, 0);

if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value)
    || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value))
   && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value)
   && (no_bars_down < 3)
   && prev_touch_down == false
   && (currentBarTime != lastTradeBarTime)
  )
  {
   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));

   trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;
  }

Explicación:

La biblioteca de negociación estándar para MQL5 se incluye en la primera línea, #include<Trade/Trade.mqh> . Esta biblioteca pone a disposición del EA las funciones y clases necesarias para realizar operaciones, modificar órdenes y mantener posiciones. El EA utilizará la instancia del objeto de operación creado por la línea CTrade trade; para colocar órdenes de manera metódica y segura.

int MagicNumber = 53217; define un número mágico. Se trata de un número especial asociado a cada operación que abre este EA. El EA puede distinguir sus operaciones de las operaciones manuales o de las operaciones abiertas por otros EA gracias a SetExpertMagicNumber (MagicNumber). Esto es fundamental para gestionar las posiciones, modificarlas o cerrarlas posteriormente sin influir en otras operaciones.

La entrada double lot_size = 0.6; se utiliza para definir el tamaño de la operación. Esto permite al usuario modificar el tamaño de cada operación directamente desde la configuración de entrada. datetime currentBarTime = iTime(_Symbol, time_frame, 0); almacena la hora de la vela más reciente, y ask_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); recupera el precio Ask actual del mercado. Con estos valores se establecen el precio de entrada, se calcula el punto de toma de ganancias y se evitan las operaciones múltiples en la misma vela.

(high_price[1] >= td1_line_value && open_price[1] < td1_line_value) 
|| (high_price[2] >= td2_line_value && open_price[2] < td2_line_value) 
|| (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) 
|| (high_price[0] >= td_line_value)

Esta línea determina si alguna de las velas más recientes ha tocado o incluso cruzado marginalmente la línea de tendencia bajista. (high_price[1] >= td1_line_value && open_price[1] < td1_line_value, por ejemplo) confirma que el máximo de la vela de hace una barra estaba por encima de la línea de tendencia, pero su apertura estaba por debajo de ella. Esto demuestra la aproximación del precio a la línea de tendencia y la posible situación de reversión que generó. Las velas de hace dos barras, las de hace tres barras y la vela actual están sujetas al mismo razonamiento. Al utilizar el operador lógico OR, se garantiza que la condición se cumplirá si alguna de estas velas satisface este requisito.

Posteriormente, se añadió la condición que confirma un rechazo bajista definitivo, examinando tanto la vela actual como la anterior. Esto indica que los vendedores han ganado fuerza y que el impulso está disminuyendo, y garantiza que la vela más reciente cierre por debajo de la línea de tendencia. Además, para que se considere bajista, la vela debe cerrar por debajo de su precio de apertura. Para que la estructura de precios se mantenga estable y la señal de reversión sea más precisa, la vela anterior también debe haber abierto por debajo de la línea de tendencia.

Este requisito garantiza que la vela más reciente confirme un cambio de tendencia bajista. Esto verifica que la vela cerró por debajo de la línea de tendencia, lo que indica una disminución del impulso y la toma de control por parte de los vendedores. La presión bajista se confirma cuando la vela cierra a un precio inferior al de apertura. Además, para que la vela anterior hubiera mantenido una tendencia bajista constante, debería haber abierto por debajo de la línea de tendencia. En conjunto, estas condiciones ayudan a prevenir entradas erróneas provocadas por fluctuaciones transitorias de precios y aumentan la validez de la señal de reversión.

Al comparar la hora de la vela actual con la hora de la última operación realizada, la condición (currentBarTime!= lastTradeBarTime) hace que el EA no abra varias operaciones en la misma vela, permitiendo así solo una entrada por barra. El EA determina el punto de toma de ganancias una vez que se cumplen todos los requisitos de entrada, multiplicando por cuatro la diferencia absoluta entre el precio de venta actual y el máximo de la vela de confirmación para determinar una relación riesgo-recompensa positiva.

Utilizando el tamaño de lote designado, el símbolo, el precio de entrada, el stop loss en el máximo de la vela de confirmación y el take profit calculado, ejecuta la operación de venta. Para garantizar una ejecución de operaciones disciplinada y metódica, el Asesor Experto actualiza el valor de lastTradeBarTime a la hora de la vela actual una vez realizada la operación. Esto evita que se realicen numerosas transacciones en la misma barra.

A continuación, el EA debe poder decidir si operar una ruptura con retest o una simple reversión. Aunque hasta ahora solo hemos abordado la situación de reversión de la tendencia bajista, puede ver cómo el EA determina una señal de reversión legítima repasando las condiciones que acabamos de analizar. Una vez que se establece por completo la lógica de reversión, estas mismas ideas pueden modificarse para manejar una técnica de ruptura y retest.

Ejemplo:

input string down_trend = ""; // Down Trend Line
input string up_trend = ""; // Up Trend Line
input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT; // TIME FRAME
input double lot_size = 0.6; // LOT SIZE

enum line_type
  {
   reversal = 0, //REVERSAL
   break_out = 1, //BREAK-OUT
   reverse_break = 2 // REVERSAL AND BREAK-OUT
  };
input line_type line_exe =  reversal; // MODE
if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value)
    || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value))
   && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value)
   && (no_bars_down < 3)
   && prev_touch_down == false
   && (currentBarTime != lastTradeBarTime)
   && (line_exe == reversal || line_exe == reverse_break)
  )
  {
   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));

   trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;
  }

Resultado:

Figura 6: Reversión de la tendencia bajista


Identificación de la ruptura de la tendencia bajista y el posterior retest

El asesor experto (EA) primero observa si una vela cierra por encima de la línea de tendencia bajista, lo que indica que se ha roto la resistencia anterior, antes de ejecutar una configuración de ruptura y retest orientada a una compra. Sin embargo, el Asesor Experto no comienza a operar de inmediato. Se espera un retest en la que el precio toque y regrese a la línea de tendencia rota, lo que indicaría que la resistencia anterior ahora actúa como soporte.

Tras la confirmación del retest, el EA busca una vela alcista que siga al punto de contacto. Esta confirmación alcista corrobora el punto de entrada y demuestra que los compradores están tomando el control. El Asesor Experto (EA) inicia una orden de compra cuando se cumplen estos tres criterios: una ruptura, un toque de retest y una vela alcista confirmatoria. Al garantizar que las operaciones se realicen únicamente después de que la ruptura se haya validado mediante el movimiento del precio, esta estrategia ayuda a evitar entrar demasiado pronto y reduce la posibilidad de rupturas falsas.

Ejemplo:

td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

bool prev_touch_down = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {
   prev_touch_down = true;
  }
int no_bars_down = 0;
for(int i = 0; i <= 3; i++)
  {
   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
     {
      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {
            no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());
            break;
           }
        }
      break;
     }
  }

//DOWN TREND

td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0);
td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0);
td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0);
td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0);

bool prev_touch_down = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {
   prev_touch_down = true;
  }
int no_bars_down = 0;
for(int i = 0; i <= 3; i++)
  {
   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0))
     {
      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {
            no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

            break;
           }
        }
      break;
     }

ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
datetime currentBarTime = iTime(_Symbol, time_frame, 0);

if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value)
    || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value))
   && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value)
   && (no_bars_down < 3)
   && prev_touch_down == false
   && (currentBarTime != lastTradeBarTime)
   && (line_exe == reversal || line_exe == reverse_break)
  )
  {
   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));

   trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;

  }

// DOWNTREND BREAKOUT AMD RETEST
bool prev_touch_break_out_down = false;

if((low_price[1] < td1_line_value && close_price[1] > open_price[1]) ||
   (low_price[2] < td2_line_value && close_price[2] > open_price[2] && open_price[2] > td2_line_value))
  {
   prev_touch_break_out_down = true;
  }

int no_bars_down_breakout = 0;

for(int i = 0; i <= 3; i++)
  {

   if(low_price[i] < ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0) &&
      open_price[i] > ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0))
     {

      for(int j = i; j >= 0; j--)
        {
         if(close_price[j] > open_price[j] &&
            close_price[j] > ObjectGetValueByTime(chart_id, down_trend, time_price[j], 0))
           {

            no_bars_down_breakout = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());
            break;
           }
        }
      break;
     }
  }
 
if(
   ((low_price[0] < td_line_value && open_price[0] > td_line_value) ||
    (low_price[1] < td1_line_value && open_price[1] > td1_line_value) ||
    (low_price[2] < td2_line_value && open_price[2] > td2_line_value) ||
    (low_price[3] < td3_line_value && open_price[3] > td3_line_value)) &&
   (close_price[0] > open_price[0]) && close_price[0] > td_line_value &&
   (no_bars_down_breakout < 3) &&
   (prev_touch_break_out_down == false) &&
   (currentBarTime != lastTradeBarTime)
   && (line_exe == break_out || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0], take_profit);

   lastTradeBarTime = currentBarTime;
  }

Explicación:

En la sección inicial del código se define un indicador booleano para controlar si ya se ha producido una interacción reciente de ruptura y retest en la tendencia bajista. Al utilizar esta bandera, el EA puede evitar que la misma configuración genere operaciones adicionales. El siguiente requisito determina si ya se ha iniciado un escenario de ruptura, analizando las últimas velas. 

Además, comprueba si la vela ha abierto por encima de la línea de tendencia para confirmar que el precio la ha traspasado y la ha vuelto a poner a prueba. Para evitar que el EA abra demasiadas operaciones con demasiada frecuencia, un contador registra el número de barras desde la última ruptura, y se activa una bandera para señalar que ya se ha producido un toque de ruptura.

El punto de ruptura se determina iterando a través de las velas más recientes en el bucle principal. Comienza buscando una vela en la que la apertura estuviera por encima de la línea de tendencia y el mínimo por debajo de ella. Esto indica la primera penetración de la línea de tendencia, que es el preludio de una ruptura. Tras el descubrimiento de dicha vela, un bucle anidado busca hacia atrás para localizar una vela posterior que cierre por encima de la línea de tendencia y sea alcista. Esto demuestra que la línea de tendencia se ha desplazado eficazmente de la resistencia al soporte y que la ruptura es legítima. Una vez obtenida esta confirmación, ambos bucles se detienen para evitar comprobaciones adicionales innecesarias y el contador se ajusta para reflejar el número de barras desde la ruptura.

Este razonamiento de ruptura y retest difiere significativamente de una inversión. El EA busca una vela bajista que toque la línea de tendencia desde abajo para indicar un rechazo durante una reversión. La estrategia de ruptura y retest consiste en que el Asesor Experto (EA) espere a que una vela rompa por encima de la línea de tendencia bajista, seguida de un retest y una vela alcista que confirme la tendencia. La configuración de ruptura es apropiada para operaciones que siguen un cambio verificado en la dirección del mercado, ya que el énfasis está en ganar impulso después de que se rompe la línea de tendencia, en lugar de aprovechar un rechazo de precio.

if(
   ((low_price[0] < td_line_value && open_price[0] > td_line_value) ||
    (low_price[1] < td1_line_value && open_price[1] > td1_line_value) ||
    (low_price[2] < td2_line_value && open_price[2] > td2_line_value) ||
    (low_price[3] < td3_line_value && open_price[3] > td3_line_value)) &&
   (close_price[0] > open_price[0]) && close_price[0] > td_line_value &&
   (no_bars_down_breakout < 3) &&
   (prev_touch_break_out_down == false) &&
   (currentBarTime != lastTradeBarTime)
   && (line_exe == break_out || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0], take_profit);

   lastTradeBarTime = currentBarTime;
  }

La primera sección de la condición determina si la línea de tendencia bajista ha sido rota. Analiza las velas más recientes para determinar si alguna de ellas tuvo una apertura por encima de la línea de tendencia y un mínimo que cayó por debajo de ella. Esto sugiere un posible avance, ya que la vela rompió la línea de tendencia desde arriba. Este mecanismo permite confirmaciones diferidas al garantizar que el EA detecte toques de ruptura en las tres velas anteriores, además de la vela actual.

La condición (close_price[0] > open_price[0]) viene a continuación. La vela actual es alcista y cerró por encima de la línea de tendencia si && close_price[0] > td_line_value. El hecho de que los compradores tengan el control y que la línea de tendencia haya pasado efectivamente de resistencia a soporte sirve como confirmación de la ruptura.

Al realizar un seguimiento de la cantidad de barras desde la última configuración confirmada, se asegura de que las operaciones no se realicen demasiado cerca de una ruptura anterior. Esto permite que el EA se concentre en nuevas posibilidades y evite operar en exceso. Al verificar que no se haya registrado ningún toque de ruptura reciente, también evita transacciones duplicadas derivadas de la misma acción del precio. Por último, comprueba que no se haya realizado ya ninguna operación en la misma barra, garantizando así que solo se ejecute una operación por vela.

Verifica que el Asesor Experto (EA) esté en un modo que permita operaciones de ruptura, ya sea por sí mismo o con reversiones. Utilizando una relación riesgo-recompensa favorable, el EA calcula el beneficio objetivo basándose en la distancia entre el precio actual y el mínimo de la vela de confirmación una vez que se hayan cumplido todos los requisitos de la operación. Posteriormente, ejecuta una operación de compra con el tamaño de lote especificado, asigna el beneficio calculado, establece el stop loss en el mínimo de la vela de ruptura y registra la hora de la operación para evitar entradas duplicadas en la misma vela.

Resultado:

Figura 7: Ruptura y retest


Identificación de la reversión de la tendencia alcista

El siguiente paso después de aprender a reconocer las rupturas y las configuraciones de reversión en una línea de tendencia ascendente es identificar posibles puntos de inflexión. El razonamiento que explica la tendencia alcista es básicamente el opuesto al de la tendencia bajista. La línea de tendencia que se observa aquí indica un nivel de soporte, y no de resistencia. Cuando el mínimo de una vela reciente toca o se acerca a la línea de tendencia alcista y una vela alcista cierra por encima de su apertura, se trata de una señal de reversión legítima. Esto sugiere una posible oportunidad de compra, ya que demuestra que el precio ha puesto a prueba el soporte y los compradores están empezando a ganar terreno.

Para evitar realizar varias operaciones a partir de la misma prueba de soporte, el Asesor Experto se asegura de que no se hayan generado señales recientes, al igual que en la reversión de la tendencia bajista. Al comparar la hora de la vela actual con la hora de la operación más reciente, también se asegura de que solo se permita una operación por vela. El EA puede gestionar el riesgo de forma consistente y evitar el exceso de operaciones, al tiempo que identifica metódicamente los cambios de tendencia alcista replicando la lógica de cambio de tendencia bajista.

Ejemplo:

double t_line_value;
double t1_line_value;
double t2_line_value;
double t3_line_value;
// UP TREND
t_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[0],0);
t1_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[1],0);
t2_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[2],0);
t3_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[3],0);

int no_bars_up = 0;

for(int i = 0; i <= 3; i++)
  {

   if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
      open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
     {

      for(int j = i; j >= 0; j--)
        {

         if(close_price[j] > open_price[j] &&
            close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
           {

            no_bars_up = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());

            break;
           }
        }
      break;
     }
  }

bool prev_touch_up = false;

if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) ||
   (low_price[2] < t2_line_value && close_price[2] > open_price[2]))
  {

   prev_touch_up = true;  // Flag that a recent touch already occurred

  }
 
if(
   ((low_price[0] < t_line_value && open_price[0] > t_line_value) ||
    (low_price[1] < t1_line_value && open_price[1] > t1_line_value) ||
    (low_price[2] < t2_line_value && open_price[2] > t2_line_value) ||
    (low_price[3] < t3_line_value && open_price[3] > t3_line_value))
   &&
   (close_price[0] > open_price[0]) && close_price[0] > t_line_value
   &&
   (no_bars_up < 3)
   &&
   prev_touch_up == false
   &&
   (currentBarTime != lastTradeBarTime)
   &&
   (line_exe == reversal || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0],take_profit);
   lastTradeBarTime = currentBarTime; 
 
  }

Explicación:

El valor de la línea de tendencia alcista en el momento de las velas más recientes se almacena en variables que se inicializan en la primera sección. El EA puede evaluar la actividad de los precios en relación con la línea de tendencia en distintos momentos, ya que cada variable está asociada a una vela diferente. Esto garantiza que el Asesor Experto pueda observar las cuatro velas más recientes y es crucial para identificar las interacciones entre el precio y la línea de tendencia.

En el siguiente paso se obtienen los valores precisos de la línea de tendencia para las últimas velas. El EA puede determinar con precisión si el mínimo de una vela tocó o penetró la línea de tendencia alcista, que es la necesidad inicial para una reversión de la tendencia alcista, obteniendo el precio de la línea en el momento de cada vela.

El número de barras desde la última configuración de reversión verificada se registra mediante un contador inicializado. Al identificar una vela que pueda indicar una prueba de soporte, el EA itera sobre las velas más recientes hasta que el mínimo cae por debajo de la línea de tendencia y la apertura se sitúa por encima de ella. Para verificar que los compradores están interviniendo, un bucle anidado dentro de este busca una vela posterior que cierre al alza y por encima de la línea de tendencia. Para evitar alertas repetidas en rápida sucesión, el contador se actualiza para reflejar la cantidad de barras desde la confirmación.

A continuación, se establece un indicador booleano para mostrar si la línea de tendencia ya ha tocado un valor recientemente. El EA analiza las últimas velas para determinar si alguna de ellas cerró al alza después de caer por debajo de la línea de tendencia. Para garantizar que no se realicen múltiples operaciones a partir de la misma interacción de precios, la bandera se establece en verdadero si existe dicha vela.

Por último, antes de realizar una orden de compra, el EA tiene en cuenta una serie de factores. Verifica que la vela actual sea alcista y cierre por encima de la línea de tendencia, que ningún toque reciente haya activado ya una operación, que la operación no se haya ejecutado ya en la vela actual, que el modo de ejecución permita operaciones de reversión y que una de las velas recientes haya tocado o penetrado la línea de tendencia.

La distancia entre el precio de venta y el mínimo de la vela de confirmación, incrementada por un multiplicador para una relación riesgo-recompensa positiva, es la forma en que el EA determina el punto de toma de ganancias si se cumplen todas estas condiciones. Después de eso, aplica la toma de ganancias, realiza una operación de compra, cambia el tiempo de la última barra de negociación para evitar múltiples operaciones en la misma vela y coloca el stop loss en el mínimo de la vela de reversión.


Identificación de la ruptura de la tendencia alcista y el posterior retest

Tras comprender los cambios de tendencia alcista, procedemos a identificar las posibilidades de ruptura y retest en una línea de tendencia ascendente. En este caso, una vela que cae por debajo de la línea de tendencia confirma la ruptura, al indicar que se ha roto el soporte. El EA espera un retest después de esta ruptura, que ocurre cuando el máximo de una vela posterior cruza de nuevo la línea de tendencia. Este retest demuestra que el soporte roto ahora actúa como resistencia. Una vez validado este retest, el EA busca una vela bajista para indicar una entrada de venta, lo que significaría que los vendedores han tomado el control.

Ejemplo:
// UP TREND
t_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[0],0);
t1_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[1],0);
t2_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[2],0);
t3_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[3],0);

int no_bars_up = 0;

for(int i = 0; i <= 3; i++)
  {

   if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) &&
      open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0))
     {

      for(int j = i; j >= 0; j--)
        {

         if(close_price[j] > open_price[j] &&
            close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0))
           {

            no_bars_up = Bars(_Symbol, time_frame, time_price[j], TimeCurrent());

            break;
           }
        }
      break;
     }
  }

bool prev_touch_up = false;

if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) ||
   (low_price[2] < t2_line_value && close_price[2] > open_price[2]))
  {

   prev_touch_up = true;  // Flag that a recent touch already occurred

  }

if(
   ((low_price[0] < t_line_value && open_price[0] > t_line_value) ||
    (low_price[1] < t1_line_value && open_price[1] > t1_line_value) ||
    (low_price[2] < t2_line_value && open_price[2] > t2_line_value) ||
    (low_price[3] < t3_line_value && open_price[3] > t3_line_value))
   &&
   (close_price[0] > open_price[0]) && close_price[0] > t_line_value
   &&
   (no_bars_up < 3)
   &&
   prev_touch_up == false
   &&
   (currentBarTime != lastTradeBarTime)
   &&
   (line_exe == reversal || line_exe == reverse_break)
)
  {
   take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4));

   trade.Buy(lot_size, _Symbol, ask_price, low_price[0],take_profit);
   lastTradeBarTime = currentBarTime; // Update last trade bar time to avoid duplicate signals
  }

// UPTREND BREAKOUT AMD RETEST

bool prev_touch_break_out_up = false;

if((high_price[1] > td1_line_value && close_price[1] < open_price[1])
   ||
   (high_price[2] > td2_line_value && close_price[2] < open_price[2])
  )
  {

   prev_touch_break_out_up = true;

  }

int no_bars_up_break_out = 0;

for(int i = 0; i <= 3; i++)
  {

   if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0)
     )
     {

      for(int j = i; j >= 0; j--)
        {

         if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0))
           {

            no_bars_up_break_out = Bars(_Symbol,time_frame,time_price[j],TimeCurrent());

            break;

           }

        }
      break;

     }

  }

if(((high_price[1] >= t1_line_value && open_price[1] < t1_line_value) || (high_price[2] >= t2_line_value && open_price[2] < t2_line_value)
    || (high_price[3] >= t3_line_value && open_price[3] < t3_line_value) || (high_price[0] >= t_line_value))
   && (close_price[0] < t_line_value && close_price[0] < open_price[0] && open_price[1] < t1_line_value)
   && (no_bars_up_break_out < 3)
   && (no_bars_up_break_out == false)
   && (currentBarTime != lastTradeBarTime)
   && (line_exe == break_out || line_exe == reverse_break)
  )
  {

   take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4));
   trade.Sell(lot_size,_Symbol,ask_price,high_price[0], take_profit);
   lastTradeBarTime = currentBarTime;

  }

Explicación:

Para determinar si ya se ha producido un toque de ruptura reciente, la primera sección establece una bandera booleana. Cuando la vela cerró a la baja, el EA analizó las velas anteriores para ver si su pico tocaba la línea de tendencia desde abajo. Para evitar que varias señales provengan del mismo evento de interrupción, el indicador se establece en verdadero si se detecta dicho contacto. Esto garantiza que la misma interacción de precios no provocará que el EA inicie operaciones nuevamente.

El asesor experto determina entonces cuántas barras han transcurrido desde la última ruptura verificada. Analiza las velas más recientes para identificar aquellas en las que la apertura estuvo por debajo de la línea de tendencia y el máximo por encima de ella. Un bucle anidado dentro de este busca una vela de seguimiento que cierre por debajo de la línea de tendencia de forma bajista. Para garantizar que las operaciones no se realicen demasiado cerca de una ruptura anterior, el EA cuenta las barras entre esta vela y la barra actual después de haberla detectado. Para evitar el exceso de operaciones y mantener bajo control la frecuencia de las entradas, se utiliza este conteo de barras.

Se combinan varias comprobaciones para proporcionar el criterio principal para ejecutar una operación de venta. Para validar el retest, primero se confirma que una de las velas más recientes ha tocado o cruzado por encima de la línea de tendencia. A continuación, determina si la vela actual cae por debajo de la línea de tendencia y es bajista, lo que indica que los vendedores están ganando terreno. Al comparar la hora de la barra actual con la última operación ejecutada, también se asegura de que no haya demasiadas barras desde la última ruptura como para permitir una nueva operación, de que ningún toque de ruptura reciente ya haya activado una operación y de que solo se ejecute una operación por vela. Por último, certifica que las operaciones de ruptura están permitidas en el modo EA.

Cuando se cumplen todos estos requisitos, el EA determina el punto de toma de ganancias multiplicando la distancia entre el precio de venta actual y el máximo de la vela de confirmación por un factor para producir una buena relación riesgo-recompensa. Después, aplica el cálculo de toma de ganancias, coloca el stop loss en el máximo de la vela de ruptura, ejecuta una orden de venta con el tamaño de lote designado y actualiza la hora de la última barra de negociación. Al eliminar las operaciones duplicadas o prematuras, esta lógica garantiza que el EA capture de forma consistente las posibilidades de ruptura y retest de la tendencia alcista.

 

Conclusión

Como continuación del estudio anterior sobre objetos gráficos, nos centramos en las líneas de tendencia en lugar de en los rectángulos. Cuando el precio se desvía o rompe las líneas de tendencia en el gráfico, aprenderá a crear un Asesor Experto (EA) que pueda identificarlas y ejecutar operaciones automáticamente. Al combinar el trading automático con el análisis manual de líneas de tendencia, este enfoque transforma una herramienta técnica popular en señales de trading útiles en MQL5.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/19968

Stanislav Korotky
Stanislav Korotky | 22 oct 2025 en 16:20
En el artículo «TradeObjects: Automatización de la negociación basada en objetos gráficos de MetaTrader» se ha presentado una solución de este tipo más flexible y potente.
Optimización por Comunidad de Científicos: Teoría Optimización por Comunidad de Científicos: Teoría
Secretos para la optimización efectiva de estrategias de trading en enfoques metaheurísticos. El algoritmo de Optimización de Comunidad de Científicos (CoSO) es un nuevo algoritmo basado en la población, inspirado en los mecanismos de la comunidad científica. A diferencia de las metáforas naturales tradicionales, el CoSO modela aspectos únicos de la actividad científica humana: la publicación de resultados en revistas, la competencia por subvenciones y la formación de equipos de investigación.
Simulación de mercado: Position View (XIV) Simulación de mercado: Position View (XIV)
Ahora implementaremos esta solución porque MQL5 sigue el mismo principio que la programación basada en eventos. Los desarrolladores utilizan este modelo con frecuencia al crear DLL. Sé que, al principio, el funcionamiento basado en eventos parecerá confuso y carente de lógica. Pero, en este artículo, presentaré los principios de la programación basada en eventos con mayor claridad para que tú, que estás empezando, comprendas adecuadamente su funcionamiento. Entender lo que comenzaré a explicar en este artículo te ayudará en tu vida como programador.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Del básico al intermedio: Clases (I) Del básico al intermedio: Clases (I)
En este artículo explicamos qué es una clase y por qué surgió este concepto. Aunque el tema es interesante, aquí nos centraremos en los principios que rigen la programación en MQL5. Este artículo es solo una introducción.