English Русский 中文 Deutsch 日本語
preview
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 25): Rompefractales de doble EMA

Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 25): Rompefractales de doble EMA

MetaTrader 5Indicadores |
139 3
Christian Benjamin
Christian Benjamin

Contenido



Introducción

El objetivo de este artículo es presentar el desarrollo de una herramienta diseñada para facilitar el análisis de la evolución de los precios, proporcionando una evaluación más profunda y detallada mediante el indicador Fractals, creado originalmente por Bill Williams.

Bill M. Williams (1932-2019) fue un influyente trader y autor estadounidense, reconocido por sus contribuciones a la psicología del trading, el análisis técnico y la teoría del caos en los mercados financieros. A lo largo de su carrera, Williams estudió los mercados de valores, materias primas y divisas (Forex), y desarrolló una serie de innovadoras herramientas de análisis técnico para identificar tendencias y posibles puntos de reversión. Entre sus indicadores más destacados se encuentran el oscilador acelerador/desacelerador, el indicador Alligator, el oscilador Awesome, el indicador Fractals, el oscilador Gator y el índice de facilitación del mercado. Hoy en día, estos indicadores se utilizan ampliamente en los mercados de divisas, de valores y otros mercados financieros por su eficacia a la hora de analizar el comportamiento del mercado.

El indicador de fractales, un componente clave de la metodología de Williams, se combina en nuestro enfoque con las medias móviles exponenciales (EMA) de 14 y 200 períodos. Al integrar los patrones fractales con estos filtros de tendencia dinámicos, nuestro Asesor Experto (EA) está diseñado para identificar con precisión posibles cambios de tendencia en el mercado, al tiempo que garantiza la alineación con la dirección general de la tendencia. Esta estrategia combinada mejora la toma de decisiones de inversión al permitir la detección temprana de señales de reversión y confirmar la fuerza de la tendencia, lo que en última instancia conduce a puntos de entrada más fiables y con mayor probabilidad de éxito. La sinergia entre el análisis fractal y las medias móviles proporciona a los operadores una poderosa herramienta para interpretar la acción del precio con mayor profundidad, lo que ayuda a optimizar el momento oportuno y a mejorar los resultados de las operaciones.


Comprender la estrategia

Nuestro asesor experto (EA) utiliza tres indicadores técnicos clave: el indicador Fractal, EMA 14 y EMA 200. El indicador fractal, desarrollado por Bill Williams, es una herramienta popular en el análisis técnico para identificar posibles cambios de tendencia. Detecta patrones de precios específicos, denominados fractales, que aparecen como máximos o mínimos locales, lo que indica posibles puntos de inflexión en el mercado. Estos fractales sirven como niveles de soporte o resistencia, proporcionando a los operadores señales visuales que les ayudan a determinar con mayor precisión el momento de entrada y salida.

La media móvil exponencial (EMA) se diferencia fundamentalmente de la media móvil simple (SMA) al asignar mayor peso a los datos de precios más recientes, lo que da como resultado un indicador más sensible. Esta ponderación se logra mediante un factor de suavizado que enfatiza exponencialmente los precios recientes, lo que permite que la EMA reaccione con mayor rapidez a los cambios del mercado. En consecuencia, las EMA son muy eficaces para detectar tendencias emergentes y proporcionar señales tempranas de cambios de tendencia, especialmente en períodos más cortos.

La EMA 14 refleja el impulso del mercado a corto plazo en nuestra estrategia, reaccionando rápidamente a los movimientos recientes de los precios, lo que la hace adecuada para entrar en el mercado en el momento oportuno. Por el contrario, la EMA 200 es un indicador de tendencia a largo plazo que suaviza las fluctuaciones a corto plazo para revelar la dirección general del mercado. Cuando el precio se sitúa por encima de la EMA 200, indica una tendencia alcista a largo plazo; cuando está por debajo, implica una tendencia bajista. Además, la EMA 200 suele actuar como un nivel dinámico de soporte o resistencia, lo que ayuda a los operadores a filtrar las señales falsas y confirmar la validez de la tendencia.

Señal de compra (ruptura alcista):

Se activa una señal de compra cuando se cumplen simultáneamente varias condiciones, lo que indica un fuerte movimiento alcista. En primer lugar, el EA monitoriza el nivel del fractal mínimo más reciente (nivel de soporte). Busca un escenario en el que el precio actual del mercado supere este nivel de soporte fractal, lo que indicaría una posible ruptura. Para confirmar que el mercado está en una tendencia alcista, el EA comprueba si el precio actual está por encima de la EMA 14 y la EMA 200; si la EMA 14 está por encima de la EMA 200, indica una tendencia alcista. Cuando se dan estas condiciones, se genera una señal de compra. En el gráfico se colocan señales visuales, como una flecha hacia arriba y una etiqueta, y se puede activar una alerta para notificar al operador.

  • El precio cruza por encima del nivel de soporte fractal más reciente.
  • El precio actual está por encima de la EMA 14 y la EMA 200.
  • La EMA 14 se sitúa por encima de la EMA 200, lo que confirma una tendencia alcista.

Figura 1. Ruptura alcista

Señal de venta (ruptura bajista):

Por el contrario, se genera una señal de venta cuando el precio cruza por debajo de un máximo fractal significativo (nivel de resistencia), lo que indica un posible movimiento a la baja. El EA observa el máximo fractal más reciente y espera a que el precio de mercado rompa a la baja este nivel. Para verificar que el mercado tiene una tendencia a la baja, se confirma que el precio actual está por debajo de ambas EMA, con la EMA 14 por debajo de la EMA 200, lo que indica una tendencia bajista. Cuando se cumplen estos criterios, es decir, cuando el precio cruza por debajo del nivel fractal de resistencia mientras la tendencia sigue siendo bajista, se emite una señal de venta. Se muestran marcadores visuales similares, como flechas hacia abajo y etiquetas, y se pueden activar alertas.

  • El precio cruza por debajo del nivel fractal de resistencia más reciente.
  • El precio actual está por debajo de la EMA 14 y la EMA 200.
  • La EMA 14 se sitúa por debajo de la EMA 200, lo que confirma una tendencia a la baja.

Figura 2. Ruptura bajista


Desglose de los componentes del código

Este asesor experto integra el análisis fractal con filtros de tendencia de media móvil para identificar y visualizar posibles puntos de ruptura en el mercado. Al trazar niveles horizontales en los máximos y mínimos fractales recientes, se marcan zonas críticas de soporte y resistencia. Cuando el precio cruza estos niveles en la dirección confirmada por la tendencia de la EMA, el EA genera señales visuales (flechas y etiquetas) y alertas sonoras, lo que simplifica el proceso de toma de decisiones del operador. Su diseño modular, con funciones dedicadas al dibujo, la señalización y la gestión de datos, lo hace adaptable a diversos estilos y preferencias de negociación. Además, el énfasis en la gestión de recursos y la limpieza garantiza la estabilidad y la claridad durante la operación. En definitiva, esta sofisticada combinación de indicadores y señales visuales proporciona una herramienta completa para los operadores que buscan aprovechar las oportunidades de ruptura fractal dentro de un entorno de tendencia.

Encabezado y metadatos

La sección inicial del código contiene metadatos que describen la autoría, la versión y la información de licencia del script. Los comentarios incluidos entre //+------------------------------------------------------------------+ sirven para identificar el propósito del script y proporcionar la atribución. Las directivas #property especifican el titular de los derechos de autor, un hipervínculo al perfil del autor en la comunidad de MetaTrader, el número de versión y imponen normas de compilación estrictas. La directiva #property strict es especialmente importante, ya que indica al compilador que se atenga a normas de codificación más estrictas, detectando posibles errores como variables no declaradas o discrepancias de tipos. Estos metadatos y directivas no influyen en la lógica de ejecución, sino que sirven como documentación y garantizan la calidad del código durante la compilación.

//+------------------------------------------------------------------+
//|                              Fractal Breakout, EMA 14 and EMA 200|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/en/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

Parámetros de entrada

Esta sección define todos los parámetros configurables que un usuario puede modificar sin alterar el código principal. Estos parámetros incluyen el intervalo de tiempo para el análisis (InpTimeframe), el número de barras que se van a examinar (InpHistoryBars) y los períodos de las dos medias móviles exponenciales (EMA), que sirven como filtros de tendencia (InpEMA14Period e InpEMA200Period).

Los parámetros de color (InpBullColor e InpBearColor) permiten personalizar el aspecto de las flechas y las líneas que indican las rupturas. Las etiquetas de texto (InpBullText e InpBearText) proporcionan anotaciones descriptivas para las señales, lo que mejora la claridad del gráfico. El desplazamiento de la flecha (InpArrowOffset) y el tamaño de la fuente (InpArrowFontSize) ofrecen un mayor control sobre la presentación visual, lo que permite al operador colocar las etiquetas de forma cómoda.

El sistema de alertas se controla mediante InpAlertsEnabled, que activa o desactiva las notificaciones emergentes, y InpAlertSoundFile, que especifica el archivo de sonido que se reproduce al detectar una alerta. Estos parámetros hacen que el EA sea flexible y adaptable a diferentes estilos de negociación y preferencias visuales, lo que permite a los usuarios adaptarlo a sus necesidades específicas.

input ENUM_TIMEFRAMES InpTimeframe      = PERIOD_CURRENT;  // chart TF
input int             InpHistoryBars    = 200;             // bars back to scan
input int             InpEMA14Period    = 14;              // fast EMA
input int             InpEMA200Period   = 200;             // slow EMA
input color           InpBullColor      = clrLime;         // bullish arrow color
input color           InpBearColor      = clrRed;          // bearish arrow color
input string          InpBullText       = "BULL Break";    // bullish label
input string          InpBearText       = "BEAR Break";    // bearish label
input int             InpArrowOffset    = 20;              // offset in points for label
input int             InpArrowFontSize  = 12;              // size of the arrow glyph
input bool            InpAlertsEnabled  = true;            // show pop-up alerts
input string          InpAlertSoundFile = "alert.wav";     // sound file in /Sounds/

Variables globales e identificadores de indicadores

Las variables declaradas fuera de las funciones sirven como almacenamiento para los identificadores de indicadores y las matrices de datos fractales. Los identificadores (hFractals, hEMA14, hEMA200) son referencias a las instancias de los indicadores creadas durante la inicialización. Son esenciales porque permiten que el EA interactúe con los búferes de los indicadores, obteniendo datos históricos y en tiempo real. Las matrices fractalUp[] y fractalDown[] son búferes asignados dinámicamente que almacenarán los puntos máximos y mínimos del fractal, respectivamente. Al gestionarlas como variables globales, se garantiza que se pueda acceder a ellas en todo el script, especialmente durante el procesamiento OnTick, donde se lleva a cabo el análisis en tiempo real.

int  hFractals, hEMA14, hEMA200;
double fractalUp[], fractalDown[];

Inicialización (OnInit)

Durante el inicio, se invoca la función OnInit para configurar los recursos necesarios. Crea manejadores de indicadores para fractales y medias móviles exponenciales (EMA) utilizando funciones como iFractals e iMA, especificando el símbolo y el intervalo de tiempo. Es fundamental que la creación de estos identificadores se realice correctamente; si alguno de ellos no es válido (por ejemplo, debido a parámetros incorrectos o a datos no disponibles), la inicialización fallará, lo que impedirá que el EA se ejecute correctamente.

A continuación, el código configura las matrices de datos fractales para que funcionen como series, lo que significa que los datos más recientes estarán en el índice 0, lo que simplifica el análisis retrospectivo. Al redimensionar estas matrices al número de barras especificado, se garantiza que los búferes de datos tengan el tamaño adecuado para un procesamiento eficiente. En general, este paso sienta las bases para una recuperación fiable de los datos, lo cual es fundamental para una detección precisa de las rupturas.

int OnInit()
  {
   hFractals = iFractals(_Symbol, InpTimeframe);
   hEMA14    = iMA(_Symbol, InpTimeframe, InpEMA14Period, 0, MODE_EMA, PRICE_CLOSE);
   hEMA200   = iMA(_Symbol, InpTimeframe, InpEMA200Period,0, MODE_EMA, PRICE_CLOSE);
   if(hFractals==INVALID_HANDLE || hEMA14==INVALID_HANDLE || hEMA200==INVALID_HANDLE)
      return(INIT_FAILED);

   ArraySetAsSeries(fractalUp,   true);
   ArraySetAsSeries(fractalDown, true);
   ArrayResize(fractalUp,   InpHistoryBars);
   ArrayResize(fractalDown, InpHistoryBars);
   return(INIT_SUCCEEDED);
  }

Desinicialización (OnDeinit)

Cuando se elimina el EA del gráfico o se cierra la terminal, se ejecuta OnDeinit para liberar los recursos. Libera los identificadores de los indicadores mediante IndicatorRelease, lo que libera la memoria asociada y evita fugas. Además, recorre todos los objetos presentes en el gráfico, identificando y eliminando aquellos que comienzan por «FB_», que son las señales visuales (flechas, etiquetas, líneas) creadas durante el funcionamiento. Esta limpieza garantiza que no queden objetos residuales que saturen el gráfico una vez desactivado el EA, lo que permite mantener un entorno de gráficos ordenado y evita posibles conflictos o confusiones durante los análisis posteriores.

void OnDeinit(const int reason)
  {
   if(hFractals!=INVALID_HANDLE)
      IndicatorRelease(hFractals);
   if(hEMA14   !=INVALID_HANDLE)
      IndicatorRelease(hEMA14);
   if(hEMA200  !=INVALID_HANDLE)
      IndicatorRelease(hEMA200);

   for(int i=ObjectsTotal(0)-1; i>=0; i--)
     {
      string n = ObjectName(0,i);
      if(StringFind(n,"FB_")>=0)
         ObjectDelete(0,n);
     }
  }

Procesamiento principal (OnTick)

La lógica principal se encuentra en la función OnTick, que se ejecuta cada vez que llega un nuevo tick del mercado. Empieza por recuperar los últimos valores de las dos medias móviles exponenciales (EMA) mediante CopyBuffer. Estos valores de la media móvil exponencial (EMA) sirven como filtros de tendencia: su posición relativa indica si el mercado se encuentra en una tendencia alcista o bajista, lo que ayuda a tomar la decisión sobre una ruptura. Si falla la recuperación de datos de la EMA, la función se detiene prematuramente para evitar señales erróneas. A continuación, la función recupera los búferes de datos fractales tanto del fractal máximo como del mínimo más recientes, de nuevo con comprobación de errores. A continuación, el código recorre estos búferes hacia atrás para encontrar los fractales válidos más recientes, ignorando cualquier marcador de posición EMPTY_VALUEs. Al identificar los puntos fractales significativos más recientes, el EA determina los niveles críticos de soporte o resistencia que podrían desencadenar rupturas. A continuación, dibuja líneas horizontales en estos niveles como referencia visual, utilizando una función auxiliar. La información de depuración del terminal proporciona información en tiempo real sobre los niveles, los precios y los estados de la EMA, lo que ayuda a los operadores a verificar la lógica.

Finalmente, el EA comprueba las condiciones de ruptura: una ruptura bajista se produce cuando el cierre anterior estuvo por encima del nivel inferior, el cierre actual lo cruza por debajo y el precio está por debajo de ambas EMA en una tendencia bajista. Por el contrario, se reconoce una ruptura alcista cuando el cierre anterior estuvo por debajo del nivel superior, el cruce actual está por encima de este y el precio está por encima de ambas EMA en una tendencia alcista. La detección de estas condiciones activa la función de señalización.

void OnTick()
  {
   // 1) Read current EMAs
   double ema14Arr[1], ema200Arr[1];
   if(CopyBuffer(hEMA14,0,0,1,ema14Arr)<=0 || CopyBuffer(hEMA200,0,0,1,ema200Arr)<=0)
      return;
   double ema14_now  = ema14Arr[0];
   double ema200_now = ema200Arr[0];

   // 2) Read fractal history (skip current bar)
   if(CopyBuffer(hFractals,0,1,InpHistoryBars,fractalUp)<=0 ||
      CopyBuffer(hFractals,1,1,InpHistoryBars,fractalDown)<=0)
      return;

   // 3) Find most recent valid fractals (ignore EMPTY_VALUE)
   int upShift=-1, downShift=-1;
   for(int i=1; i<InpHistoryBars; i++)
     {
      if(fractalUp[i]   != EMPTY_VALUE && upShift<0)
         upShift   = i+1;
      if(fractalDown[i] != EMPTY_VALUE && downShift<0)
         downShift = i+1;
      if(upShift>0 && downShift>0)
         break;
     }

   // 4) Levels
   double lvlUp   = (upShift>0)   ? fractalUp[upShift-1]     : 0.0;
   double lvlDown = (downShift>0) ? fractalDown[downShift-1] : 0.0;

   // 5) Draw level lines
   DrawHLine("FB_LevelUp",   lvlUp,   InpBullColor);
   DrawHLine("FB_LevelDown", lvlDown, InpBearColor);

   // 6) DEBUG print
   double prevC = iClose(_Symbol,InpTimeframe,1);
   double currC = iClose(_Symbol,InpTimeframe,0);
   PrintFormat(
      "DBG lvlUp=%.5f lvlDown=%.5f prevC=%.5f currC=%.5f EMA14=%.5f EMA200=%.5f",
      lvlUp, lvlDown, prevC, currC, ema14_now, ema200_now
   );

   // 7) Breakouts on the last closed candle (shift=1)

   // Bearish breakout detection
   if(lvlDown>0
      && prevC>=lvlDown && currC<lvlDown
      && currC<ema14_now && currC<ema200_now
      && ema200_now>ema14_now)
     {
      Print(">>> Bear breakout triggered");
      Signal(false, 1, lvlDown, ema14_now, ema200_now);
     }

   // Bullish breakout detection
   if(lvlUp>0
      && prevC<=lvlUp && currC>lvlUp
      && currC>ema14_now && currC>ema200_now
      && ema14_now>ema200_now)
     {
      Print(">>> Bull breakout triggered");
      Signal(true, 1, lvlUp, ema14_now, ema200_now);
     }
  }

Dibujar líneas horizontales (DrawHLine)

Esta función de utilidad gestiona la creación y actualización de líneas horizontales en el gráfico. Al invocarse, comprueba si existe una línea con el nombre especificado; si no, crea una nueva línea punteada en el nivel de precio dado con el color especificado. Si la línea ya existe, simplemente actualiza su posición. Este método evita la superposición de varias líneas y garantiza que los niveles visuales se mantengan actualizados con el análisis fractal más reciente. El estilo punteado ayuda a distinguir estas líneas de otros elementos del gráfico, enfatizando su función como niveles de soporte o resistencia. Estas señales visuales son de gran valor para los operadores, ya que permiten reconocer rápidamente las zonas de ruptura y facilitan la toma de decisiones, ya sea manual o automatizada.

void DrawHLine(string name, double price, color clr)
  {
   if(price<=0)
      return;
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_HLINE,0,0,price);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
     }
   else
      ObjectSetDouble(0,name,OBJPROP_PRICE,price);
  }

Señalización y visualización (Signal)

La función Signal engloba todas las acciones relacionadas con la señalización de un evento de ruptura. Comienza por recuperar la marca de tiempo de la barra en la que se produjo la señal, lo que garantiza la colocación precisa de los objetos visuales. A continuación, crea un objeto de flecha en el nivel de ruptura, que apunta hacia arriba o hacia abajo dependiendo de si la tendencia es alcista o bajista, con un código de colores que coincide con la tendencia. La apariencia de la flecha se personaliza con parámetros de ancho y tamaño para mayor claridad. Junto a la flecha, se añade una etiqueta de texto ligeramente desplazada verticalmente, en la que aparece un mensaje descriptivo como «BULL Break» o «BEAR Break», lo que refuerza la señal visual.

La función registra un mensaje detallado en la pestaña «Expertos», que incluye la hora exacta, el nivel, el precio de cierre y los valores de la media móvil exponencial (EMA), lo que proporciona un registro completo de las señales. Si las alertas están activadas, aparece un mensaje emergente y se reproduce un archivo de sonido para avisar al operador de inmediato. Esta combinación de señales visuales, auditivas y basadas en registros garantiza que los operadores sean informados de inmediato de posibles oportunidades de ruptura, lo que les permite actuar a tiempo.

void Signal(bool isBull, int shift, double level, double ema14, double ema200)
  {
   datetime t     = iTime(_Symbol,InpTimeframe,shift);
   double   price = level;
   string   side  = isBull ? "Bull" : "Bear";

   // Arrow
   string arrowName = StringFormat("FB_%sArrow_%d", side, (int)t);
   ObjectCreate(0, arrowName, OBJ_ARROW, 0, t, price);
   ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE,    isBull?233:234);
   ObjectSetInteger(0, arrowName, OBJPROP_COLOR,        isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, arrowName, OBJPROP_WIDTH,        2);
   ObjectSetInteger(0, arrowName, OBJPROP_FONTSIZE,     InpArrowFontSize);

   // Label
   string lab = arrowName + "_L";
   double offset = (isBull ? InpArrowOffset : -InpArrowOffset) * _Point;
   ObjectCreate(0, lab, OBJ_TEXT, 0, t, price + offset);
   ObjectSetString(0, lab, OBJPROP_TEXT,    isBull?InpBullText:InpBearText);
   ObjectSetInteger(0, lab, OBJPROP_COLOR,  isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, lab, OBJPROP_FONTSIZE, 11);

   // Log message
   string msg = StringFormat(
                   "%s breakout at %s | Level=%.5f | Close=%.5f | EMA14=%.5f | EMA200=%.5f",
                   side, TimeToString(t, TIME_DATE|TIME_SECONDS),
                   level, iClose(_Symbol,InpTimeframe,shift),
                   ema14, ema200
                );
   Print(msg);

   // Alert and sound
   if(InpAlertsEnabled)
     {
      Alert(msg);
      if(StringLen(InpAlertSoundFile)>0)
         PlaySound(InpAlertSoundFile);
     }
  }

Código MQL5

//+------------------------------------------------------------------+
//|                              Fractal Breakout, EMA 14 and EMA 200|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/en/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

//---inputs
input ENUM_TIMEFRAMES InpTimeframe      = PERIOD_CURRENT;  // chart TF
input int             InpHistoryBars    = 200;             // bars back to scan
input int             InpEMA14Period    = 14;              // fast EMA
input int             InpEMA200Period   = 200;             // slow EMA
input color           InpBullColor      = clrLime;         // bullish arrow color
input color           InpBearColor      = clrRed;          // bearish arrow color
input string          InpBullText       = "BULL Break";    // bullish label
input string          InpBearText       = "BEAR Break";    // bearish label
input int             InpArrowOffset    = 20;              // offset in points for label
input int             InpArrowFontSize  = 12;              // size of the arrow glyph
input bool            InpAlertsEnabled  = true;            // show pop-up alerts
input string          InpAlertSoundFile = "alert.wav";     // sound file in /Sounds/

//---indicator handles & buffers
int  hFractals, hEMA14, hEMA200;
double fractalUp[], fractalDown[];

//+------------------------------------------------------------------+
//| Expert initialization                                            |
//+------------------------------------------------------------------+
int OnInit()
  {
   hFractals = iFractals(_Symbol, InpTimeframe);
   hEMA14    = iMA(_Symbol, InpTimeframe, InpEMA14Period, 0, MODE_EMA, PRICE_CLOSE);
   hEMA200   = iMA(_Symbol, InpTimeframe, InpEMA200Period,0, MODE_EMA, PRICE_CLOSE);
   if(hFractals==INVALID_HANDLE || hEMA14==INVALID_HANDLE || hEMA200==INVALID_HANDLE)
      return(INIT_FAILED);

   ArraySetAsSeries(fractalUp,   true);
   ArraySetAsSeries(fractalDown, true);
   ArrayResize(fractalUp,   InpHistoryBars);
   ArrayResize(fractalDown, InpHistoryBars);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(hFractals!=INVALID_HANDLE)
      IndicatorRelease(hFractals);
   if(hEMA14   !=INVALID_HANDLE)
      IndicatorRelease(hEMA14);
   if(hEMA200  !=INVALID_HANDLE)
      IndicatorRelease(hEMA200);

   for(int i=ObjectsTotal(0)-1; i>=0; i--)
     {
      string n = ObjectName(0,i);
      if(StringFind(n,"FB_")>=0)
         ObjectDelete(0,n);
     }
  }

//+------------------------------------------------------------------+
//| Tick handler                                                     |
//+------------------------------------------------------------------+
void OnTick()
  {
// 1) Read current EMAs
   double ema14Arr[1], ema200Arr[1];
   if(CopyBuffer(hEMA14,0,0,1,ema14Arr)<=0 || CopyBuffer(hEMA200,0,0,1,ema200Arr)<=0)
      return;
   double ema14_now  = ema14Arr[0];
   double ema200_now = ema200Arr[0];

// 2) Read fractal history (skip current bar)
   if(CopyBuffer(hFractals,0,1,InpHistoryBars,fractalUp)<=0 ||
      CopyBuffer(hFractals,1,1,InpHistoryBars,fractalDown)<=0)
      return;

// 3) Find most recent valid fractals (ignore EMPTY_VALUE)
   int upShift=-1, downShift=-1;
   for(int i=1; i<InpHistoryBars; i++)
     {
      if(fractalUp[i]   != EMPTY_VALUE && upShift<0)
         upShift   = i+1;
      if(fractalDown[i] != EMPTY_VALUE && downShift<0)
         downShift = i+1;
      if(upShift>0 && downShift>0)
         break;
     }

// 4) Levels
   double lvlUp   = (upShift>0)   ? fractalUp[upShift-1]     : 0.0;
   double lvlDown = (downShift>0) ? fractalDown[downShift-1] : 0.0;

// 5) Draw level lines
   DrawHLine("FB_LevelUp",   lvlUp,   InpBullColor);
   DrawHLine("FB_LevelDown", lvlDown, InpBearColor);

// 6) DEBUG print
   double prevC = iClose(_Symbol,InpTimeframe,1);
   double currC = iClose(_Symbol,InpTimeframe,0);
   PrintFormat(
      "DBG lvlUp=%.5f lvlDown=%.5f prevC=%.5f currC=%.5f EMA14=%.5f EMA200=%.5f",
      lvlUp, lvlDown, prevC, currC, ema14_now, ema200_now
   );

// 7) Breakouts on the last closed candle (shift=1)

// Bearish breakout
   if(lvlDown>0
      && prevC>=lvlDown && currC<lvlDown
      && currC<ema14_now && currC<ema200_now
      && ema200_now>ema14_now)
     {
      Print(">>> Bear breakout triggered");
      Signal(false, 1, lvlDown, ema14_now, ema200_now);
     }
// Bullish breakout
   if(lvlUp>0
      && prevC<=lvlUp && currC>lvlUp
      && currC>ema14_now && currC>ema200_now
      && ema14_now>ema200_now)
     {
      Print(">>> Bull breakout triggered");
      Signal(true, 1, lvlUp, ema14_now, ema200_now);
     }
  }

//+------------------------------------------------------------------+
//| Draw or update a dotted HLine                                    |
//+------------------------------------------------------------------+
void DrawHLine(string name, double price, color clr)
  {
   if(price<=0)
      return;
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_HLINE,0,0,price);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
     }
   else
      ObjectSetDouble(0,name,OBJPROP_PRICE,price);
  }

//+------------------------------------------------------------------+
//| Plot arrow, label, log & alert                                   |
//+------------------------------------------------------------------+
void Signal(bool isBull, int shift, double level, double ema14, double ema200)
  {
   datetime t     = iTime(_Symbol,InpTimeframe,shift);
   double   price = level;
   string   side  = isBull ? "Bull" : "Bear";

// Arrow
   string arrowName = StringFormat("FB_%sArrow_%d", side, (int)t);
   ObjectCreate(0, arrowName, OBJ_ARROW, 0, t, price);
   ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE,    isBull?233:234);
   ObjectSetInteger(0, arrowName, OBJPROP_COLOR,        isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, arrowName, OBJPROP_WIDTH,        2);
   ObjectSetInteger(0, arrowName, OBJPROP_FONTSIZE,     InpArrowFontSize);

// Label
   string lab = arrowName + "_L";
   double offset = (isBull ? InpArrowOffset : -InpArrowOffset) * _Point;
   ObjectCreate(0, lab, OBJ_TEXT, 0, t, price + offset);
   ObjectSetString(0, lab, OBJPROP_TEXT,    isBull?InpBullText:InpBearText);
   ObjectSetInteger(0, lab, OBJPROP_COLOR,  isBull?InpBullColor:InpBearColor);
   ObjectSetInteger(0, lab, OBJPROP_FONTSIZE, 11);

// Expert log
   string msg = StringFormat(
                   "%s breakout at %s | Level=%.5f | Close=%.5f | EMA14=%.5f | EMA200=%.5f",
                   side, TimeToString(t, TIME_DATE|TIME_SECONDS),
                   level, iClose(_Symbol,InpTimeframe,shift),
                   ema14, ema200
                );
   Print(msg);

// Pop-up alert + optional sound
   if(InpAlertsEnabled)
     {
      Alert(msg);
      if(StringLen(InpAlertSoundFile)>0)
         PlaySound(InpAlertSoundFile);
     }
  }
//+------------------------------------------------------------------+


Resultados

Para probar el EA, primero compile el código usando MetaEditor. Una vez compilado, puede aplicarlo a un gráfico en MetaTrader 5 para realizar pruebas en tiempo real o ejecutarlo directamente a través del Probador de Estrategias para realizar pruebas retrospectivas. He realizado pruebas de este Asesor Experto tanto en condiciones de mercado reales como en pruebas retrospectivas históricas. Este proceso es esencial para ajustar con precisión los parámetros del EA, lograr el comportamiento de negociación deseado y optimizar su rendimiento.

El gráfico de la imagen inferior muestra cómo el EA identifica un cambio significativo en el mercado utilizando indicadores fractales y EMA. En concreto, el EA detecta una ruptura fractal bajista en un nivel de soporte clave, que se marca visualmente en el gráfico. El movimiento de precios posterior confirma el cambio de tendencia, ya que el mercado continúa a la baja, alineándose con la tendencia de la EMA, donde la EMA 14 cruza por debajo de la EMA 200, lo que indica un cambio hacia una tendencia bajista. Las señales visuales, como el indicador "BEAR Break", facilitan la toma de decisiones disciplinadas al entrar y salir de la zona. Este resultado demuestra la capacidad del EA para reconocer los primeros indicios de un cambio de tendencia, lo que permite a los operadores aprovechar las oportunidades de alta probabilidad y evitar las señales falsas.

Figura 3. Rompimiento bajista en el índice Step

El GIF que aparece a continuación muestra el proceso de detección y confirmación en tiempo real de un cambio de tendencia por parte del EA. Destaca cómo el sistema de indicadores identifica un nivel de soporte o resistencia fractal y señala una posible ruptura, lo que lleva al operador a plantearse abrir una posición. A medida que el mercado se mueve en la dirección prevista, las señales del EA se ven confirmadas por la alineación de las medias móviles exponenciales (EMA); la EMA de 14 cruza por debajo de la EMA de 200, lo que confirma la tendencia bajista. Las señales visuales, como las flechas y las alertas, muestran cómo el EA facilita la toma de decisiones oportuna. Este ejemplo pone de relieve la importancia de la detección temprana, combinada con la confirmación de la tendencia, lo que refuerza la confianza a la hora de operar y reduce la probabilidad de entrar en el mercado de forma errónea.

Figura 4. Backtesting en V75 (1 s)


Conclusión

Este Asesor Experto aprovecha el potencial del indicador Fractals de Bill Williams, junto con medias móviles exponenciales a corto y largo plazo, para identificar puntos de entrada con alta probabilidad de éxito. Al combinar estas herramientas, detecta señales tempranas de cambio de tendencia que se confirman en relación con la tendencia predominante del mercado, lo que mejora la precisión y la coherencia en la ejecución de las operaciones. Las rigurosas pruebas retrospectivas y las pruebas en tiempo real han demostrado su flexibilidad en diversas condiciones de mercado y, una vez ajustados, sus parámetros pueden adaptarse para obtener un rendimiento óptimo. Gracias a sus flechas y etiquetas intuitivas en el gráfico, además de la ejecución de órdenes totalmente automatizada, este EA aporta disciplina y rapidez a tu rutina de trading. En esencia, ofrece un marco sistemático y basado en reglas para el análisis de la evolución de los precios, ideal para los operadores que buscan combinar el rigor técnico con la automatización.

Echa un vistazo a nuestras herramientas destacadas en la tabla que aparece a continuación.





   
Chart Projector
Analytical Comment
Analytics Master
Analytics Forecaster 
Volatility Navigator
Mean Reversion Signal Reaper
Signal Pulse 
Metrics Board 
External Flow
VWAP
Heikin Ashi   FibVWAP  
RSI DIVERGENCE
Parabolic Stop and Reverse (PSAR) 
Quarters Drawer Script
Intrusion Detector
TrendLoom Tool  Quarters Board 
ZigZag Analyzer  Correlation Pathfinder  Market Structure Flip Detector Tool
Correlation Dashboard   Currency Strength Meter 
PAQ Analysis Tool 
Barra de pines, patrón envolvente y divergencia del RSI
Rompefractales de doble EMA        

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

Archivos adjuntos |
Delly
Delly | 4 jun 2025 en 09:17
Interesante artículo, y gracias por el código fuente de EA. Lo probaré y daré mi opinión.
Christian Benjamin
Christian Benjamin | 9 jun 2025 en 19:54
Delly Kabongo #:
Interesante artículo, y gracias por el código fuente de EA. Lo probaré y daré mi opinión.
Gracias por ponerte en contacto con nosotros. Sus comentarios son muy apreciados y siempre bienvenidos.
ABEL OLUFEMI FAMODU
ABEL OLUFEMI FAMODU | 11 jun 2025 en 20:29
Un artículo muy interesante. Ayudará mucho a simplificar la estrategia de trading.
Aprendizaje automático y Data Science (Parte 42): Pronóstico de series temporales de Forex con ARIMA en Python, todo lo que necesitas saber Aprendizaje automático y Data Science (Parte 42): Pronóstico de series temporales de Forex con ARIMA en Python, todo lo que necesitas saber
ARIMA, siglas de AutoRegressive Integrated Moving Average —en español, “modelo autorregresivo integrado de media móvil”—, es un potente modelo tradicional de pronóstico de series temporales. Gracias a su capacidad para detectar picos y fluctuaciones en los datos de una serie temporal, este modelo puede realizar predicciones precisas sobre los valores siguientes. En este artículo, vamos a entender qué es, cómo funciona, qué se puede hacer con él para predecir los próximos precios del mercado con gran precisión y mucho más.
Dominando los registros (Parte 7): Cómo mostrar los registros en un gráfico Dominando los registros (Parte 7): Cómo mostrar los registros en un gráfico
Descubre cómo mostrar los registros directamente en el gráfico de MetaTrader de forma organizada, con marcos, títulos y scroll automático. En este artículo te mostramos cómo crear un sistema visual de registros con MQL5, ideal para supervisar en tiempo real lo que hace tu robot.
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.
Características del Wizard MQL5 que debe conocer (Parte 67): Uso de patrones de TRIX y Williams Percent Range (WPR) Características del Wizard MQL5 que debe conocer (Parte 67): Uso de patrones de TRIX y Williams Percent Range (WPR)
El oscilador de media móvil exponencial triple (TRIX) y el oscilador de rango porcentual de Williams son otro par de indicadores que podrían utilizarse conjuntamente dentro de un Asesor Experto MQL5. Este par de indicadores, al igual que los que hemos analizado recientemente, también es complementario, ya que TRIX define la tendencia, mientras que el indicador Williams Percent Range confirma los niveles de soporte y resistencia. Como siempre, utilizamos el asistente MQL5 para evaluar el potencial que puedan tener estos dos indicadores.