English Русский 中文 Deutsch 日本語
preview
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 16): Introducción a la teoría de los cuartos (II) - Intrusion Detector EA

Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 16): Introducción a la teoría de los cuartos (II) - Intrusion Detector EA

MetaTrader 5Sistemas comerciales |
70 0
Christian Benjamin
Christian Benjamin

Introducción

En nuestro artículo anterior, presentamos el Quarters Drawer Script, una herramienta diseñada para trazar visualmente los niveles de cuartos en el gráfico, lo que hace que el análisis del mercado sea más intuitivo. Este concepto se deriva de la teoría de los cuartos, introducida originalmente por Ilian Yotov ( The Quarters Theory: The Revolutionary New Foreign Currencies Trading Method, 2009). Dibujar correctamente estos cuartos ha demostrado ser un método eficaz para simplificar el análisis de la evolución de los precios. Sin embargo, supervisar manualmente estos niveles a medida que el precio interactúa con ellos requiere mucho tiempo y atención.

Para hacer frente a este reto, me complace presentar el Intrusion Detector EA, una solución diseñada para automatizar el proceso de supervisión. Este EA realiza un seguimiento continuo de los gráficos, detectando cuándo el precio alcanza cualquier nivel cuartil, ya sea pequeño, grande, importante, por encima o por debajo. Además, ofrece comentarios e información instantáneos basados en la teoría de los cuartos de Ilian Yotov, lo que ayuda a todos los operadores a anticipar las posibles reacciones del mercado. En este artículo, comenzaremos por revisar la herramienta Quarters Drawer, luego profundizaremos en el concepto estratégico y la implementación de MQL5, analizaremos los resultados de las pruebas y concluiremos con las conclusiones principales. Consulte el índice que aparece a continuación para obtener una descripción general estructurada.

Contenido



Revisión del artículo anterior

No me detendré demasiado en esta sección, ya que el Quarters Drawer Script se trató en profundidad en nuestro artículo anterior. Sin embargo, si aún no lo ha leído, le recomiendo encarecidamente que siga los enlaces proporcionados para comprender plenamente los conceptos fundamentales. Ese artículo se centraba principalmente en automatizar el dibujo de los niveles de cuartos, haciendo que el análisis del mercado fuera más estructurado y eficiente.

Como se mencionó anteriormente, la teoría de los cuartos fue descubierta por Ilian Yotov y posteriormente presentada a la comunidad de traders. Un punto crucial, que quizá no se haya destacado lo suficiente en el último artículo, es que esta teoría es muy aplicable a los pares de divisas, lo que la convierte en una herramienta esencial para los operadores de divisas. Para comprender mejor cómo funcionan estos niveles de cuartos, echa un vistazo al siguiente diagrama, que representa visualmente la estructura de la teoría.

Niveles de cuartos

Figura 1. Niveles de cuartos

Nuestra herramienta Quarters Drawer ofreció resultados notables, trazando correctamente los cuartos grandes, los overshoots, los undershoots y los cuartos menores. Más importante aún, observamos que el precio interactuaba constantemente con estos niveles y respondía a ellos, lo que reforzaba la legitimidad y eficacia de la teoría de Yotov. No se trataba solo de un ejercicio teórico, sino que la herramienta validó el poder de los niveles de cuartos en condiciones reales de mercado. Ahora, analicemos el siguiente diagrama para revisar algunas de nuestras conclusiones y observaciones clave.

Resultados

Figura 2. Resultados


Concepto estratégico e implementación en MQL5

Lógica central

El Intrusion Detector EA se centra en trazar los niveles psicológicos clave de los precios utilizando la teoría de cuartos. Divide el mercado en rangos de 1000 pips, con los números enteros principales como columna vertebral. Dentro de estos, marca los cuartos grandes (zonas de 250 pips) y, si está habilitado, los cuartos pequeños para una granularidad aún más fina. El EA también traza áreas de overshoot y undershoot, captando extensiones de precios que podrían engañar a los operadores. En cada tick, analiza el precio actual, comprueba si se está acercando a estos niveles clave dentro de una tolerancia establecida (también conocida como margen de error) y activa alertas si ocurre algo.

El objetivo principal aquí es detectar posibles puntos de inflexión, rupturas o falsas rupturas antes de que se hagan evidentes para todos los demás. Si el precio se está enfriando cerca de un número entero importante, el EA lo marca como una zona clave de soporte o resistencia. Si se mantiene en torno al nivel de un cuarto grande, indica que podría producirse un movimiento de 250 pips. ¿Zonas de overshoot y undershoot? Ayudan a señalar trampas en las que el precio podría revertirse bruscamente. El EA se asegura de no enviar alertas innecesarias mediante el seguimiento de las intrusiones y actualiza un panel de comentarios inmediatos para que siempre estés al tanto de lo que está sucediendo. Todo está diseñado para mantenerte a la vanguardia, haciendo que la teoría del cuarto sea práctica y aplicable.

Implementación

En este EA, comenzamos con un encabezado que incluye metadatos sobre el EA, como su nombre («Intrusion Detector»), detalles sobre los derechos de autor y un enlace al perfil del desarrollador. Las directivas #property especifican estos detalles y aplican reglas de compilación estrictas, lo que garantiza que el código se ajuste a los estándares MQL5 modernos.

//+------------------------------------------------------------------+
//|                                             Intrusion Detector   |
//|                             Copyright 2025, Christian Benjamin   |
//|                        https://www.mql5.com/en/users/lynnchris   |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

A continuación, definimos un conjunto de parámetros de entrada que le permiten personalizar el comportamiento del EA sin modificar el código. Los parámetros incluyen valores numéricos como MajorStep, que determina el intervalo entre los niveles principales (definiendo efectivamente un rango de 1000 pips), y AlertTolerance, que establece el umbral de proximidad para detectar cuándo el precio «toca» un nivel específico. Las entradas booleanas controlan si el EA dibuja líneas adicionales, como líneas de cuartos grandes y pequeños, así como áreas de sobrepasamiento alrededor de esos niveles principales.

Además, los ajustes de color se definen utilizando valores hexadecimales (o colores predefinidos) para garantizar que cada tipo de línea, ya sea principal, cuarto grande, cuarto pequeño u overshoot, aparezca con el estilo visual deseado en el gráfico. A continuación se muestran los estilos de línea y los ajustes de grosor, lo que le permite personalizar aún más el aspecto de estas líneas dibujadas.

Configuración de ajustes

input double MajorStep          = 0.1000;   // Difference between Major Whole Numbers (defines the 1000-PIP Range)
input bool   DrawLargeQuarters  = true;     // Draw intermediate Large Quarter lines.
input bool   DrawSmallQuarters  = false;    // Draw Small Quarter lines.
input bool   DrawOvershootAreas = true;     // Mark overshoot/undershoot areas for Large Quarter lines.
input double AlertTolerance     = 0.0025;   // Tolerance for detecting a "touch"

  • MajorStep: Define el intervalo entre los niveles principales (por ejemplo, un rango de 1000 pips).
  • DrawLargeQuarters y DrawSmallQuarters: Valores booleanos que controlan si el EA debe dibujar líneas adicionales dentro del rango..
  • DrawOvershootAreas: Determina si se deben dibujar líneas adicionales de « overshoot» y « undershoot» cerca de los niveles de cuartos grandes.
  • AlertTolerance: Especifica cuánto debe acercarse el precio a un nivel (dentro de 0,0025) para considerarlo un «toque».

Configuración de color

input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for Major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for Large Quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for Small Quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

Los colores se definen para cada tipo de línea, de modo que cuando se dibujan en el gráfico coincidan visualmente con la descripción.

Configuración del estilo y grosor de línea

input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

Cada tipo de línea (principal, cuarto grande, overshoot, cuarto pequeño) tiene su propio estilo (sólido, punteado, discontinuo) y ajustes de grosor.

Mensajes de comentarios personalizables

Estos mensajes describen la importancia de cada nivel cuando el precio lo «alcanza». Más adelante se utilizan para crear una tabla de comentarios.

  • MajorSupportReason: Esto indica que existe un nivel de soporte significativo en el mercado. Si el precio cae por debajo de este nivel, sugiere que puede producirse un cambio en el rango de negociación, lo que podría dar lugar a nuevas caídas de precios.
  • MajorResistanceReason: Esto significa un nivel de resistencia crítico. Si el precio supera esta resistencia, podría indicar el inicio de un nuevo rango de cotización, lo que podría dar lugar a un movimiento alcista del precio.
  • LargeQuarterReason: Esta afirmación señala que una ruptura decisiva del precio en este nivel podría provocar un movimiento sustancial del precio, potencialmente de hasta 250 pips. Esto implica que los operadores deben estar atentos a este nivel para detectar posibles oportunidades de negociación.
  • OvershootReason: Esto implica que el precio está probando un nivel de ruptura y, si no logra mantener el impulso, es probable que se produzca un cambio en la dirección del precio. Esto significa que los operadores deben ser cautelosos si el precio se dispara por encima de un nivel clave sin un fuerte apoyo de compra.
  • UndershootReason: Esto indica que no ha habido suficiente interés alcista en el mercado, lo que sugiere que podría producirse un cambio a una tendencia bajista. Los operadores deben observar atentamente esta señal para detectar posibles oportunidades de venta en corto.
  • SmallQuarterReason: Esto se refiere a una fluctuación menor del precio dentro del mercado. Esto sugiere que el precio se está moviendo en pequeños incrementos y puede que no indique ninguna oportunidad comercial significativa ni cambios en la tendencia.

input string MajorSupportReason    = "Key support level. Break below signals range shift.";
input string MajorResistanceReason = "Pivotal resistance. Breakout above may start new range.";
input string LargeQuarterReason    = "Decisive break could trigger next 250-PIP move.";
input string OvershootReason       = "Test of breakout; reversal likely if momentum fails.";
input string UndershootReason      = "Insufficient bullish force; possible bearish reversal.";
input string SmallQuarterReason    = "Minor fluctuation.";

Se utiliza una variable booleana global, intrusionAlerted, para garantizar que las alertas solo se activen una vez por cada evento de intrusión, evitando notificaciones repetidas cuando el precio se mantiene en torno a un nivel.

// Global flag to avoid repeated alerts while price lingers at a level
bool intrusionAlerted = false;

La función DrawHorizontalLine es el núcleo de la salida visual del EA. Esta función toma parámetros como el nombre de la línea, el precio, el color, el ancho y el estilo, y primero comprueba si ya existe una línea con ese nombre; si es así, la línea se elimina. A continuación, crea una nueva línea horizontal al precio especificado y establece sus propiedades en consecuencia, asegurándose de que la línea se extienda hacia la parte derecha del gráfico. Este enfoque modular facilita la reutilización de la función cada vez que es necesario dibujar un nuevo nivel.

void DrawHorizontalLine(string name, double price, color lineColor, int width, ENUM_LINE_STYLE style)
{
   if(ObjectFind(0, name) != -1)
      ObjectDelete(0, name);

   if(!ObjectCreate(0, name, OBJ_HLINE, 0, 0, price))
   {
      Print("Failed to create line: ", name);
      return;
   }
   ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
   ObjectSetInteger(0, name, OBJPROP_STYLE, style);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
}

La función DrawQuarters utiliza DrawHorizontalLine para dibujar los límites principales del rango de 1000 pips (calculado en función del precio actual), así como líneas adicionales dentro de ese rango. Si está habilitado, el EA dibuja líneas de «cuarto grande» dividiendo el rango en cuatro segmentos. Para cada una de estas líneas, si las áreas de overshoot están habilitadas, la función también dibuja líneas ligeramente por encima y por debajo del nivel principal para indicar posibles overshoots o undershoots. Cuando la opción está activada, el EA incluso subdivide el rango en líneas de «cuarto pequeño» aún más precisas, lo que le proporciona indicaciones visuales más detalladas sobre la estructura de precios.

void DrawQuarters(double currentPrice)
{
   // Calculate the boundaries of the current 1000-PIP Range
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

   // Draw Major Whole Number lines (defining the 1000-PIP Range)
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);

   // Draw Large Quarter lines and their overshoot/undershoot areas if enabled
   if(DrawLargeQuarters)
   {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
      {
         double level = lowerMajor + i * LQIncrement;
         string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);

         if(DrawOvershootAreas)
         {
            double offset = MajorStep / 40.0; // approximately 25 pips if MajorStep=0.1000
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
         }
      }
   }

   // Draw Small Quarter lines if enabled (optional, finer divisions)
   if(DrawSmallQuarters)
   {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
      {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
         {
            double level = segStart + j * smallQuarter;
            string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j);
            DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle);
         }
      }
   }
}

Otra función esencial es CreateOrUpdateLabel, que se encarga de mostrar el texto en el gráfico. Esta función comprueba si una etiqueta ya existe y la crea si no es así. A continuación, actualiza el texto, el color, el tamaño de fuente y otras propiedades de la etiqueta, utilizando una fuente monoespaciada (Courier New) para garantizar que los datos tabulares permanezcan perfectamente alineados. Esta función es especialmente importante para actualizar los comentarios que explican las condiciones del mercado.

void CreateOrUpdateLabel(string name, string text, int corner, int xdist, int ydist, color txtColor, int fontSize)
{
   if(ObjectFind(0, name) == -1)
   {
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, ydist);
      // Set a monospaced font for tabular display (Courier New)
      ObjectSetString(0, name, OBJPROP_FONT, "Courier New");
   }
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_COLOR, txtColor);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
}

Cuando el EA se inicializa (en la función OnInit), crea una etiqueta persistente en la esquina superior izquierda del gráfico con el mensaje «Intrusion Detector Initialized». Por el contrario, cuando se elimina el EA (mediante la función OnDeinit), se limpia eliminando esta etiqueta para mantener el gráfico ordenado.

int OnInit()
{
   // Create a persistent commentary label in the top-left corner
   CreateOrUpdateLabel("IntrusionCommentary", "Intrusion Detector Initialized", CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);
   return(INIT_SUCCEEDED);
}

El núcleo del EA reside en la función OnTick, que se ejecuta con cada nuevo tick del mercado. Cuando el EA recibe un nuevo tick, se activa la función OnTick. El primer paso de esta función es inicializar un indicador denominado intrusionDetected con el valor falso y recuperar la oferta actual del mercado utilizando SymbolInfoDouble(_Symbol, SYMBOL_BID). Si el precio devuelto es 0 (lo que indica un valor no válido o no disponible), la función se cierra de inmediato.

void OnTick()
{
   bool intrusionDetected = false;
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;

A continuación, el EA llama a la función DrawQuarters con el precio actual. Esta llamada es responsable de dibujar todos los niveles clave en el gráfico, incluyendo los niveles principales, las líneas de cuartos grandes y, si está habilitado, las líneas de cuartos más pequeñas, proporcionando la estructura visual que define nuestro rango. Inmediatamente después, el EA vuelve a calcular los límites del rango actual de 1000 pips determinando el nivel lowerMajor utilizando MathFloor(currentPrice / MajorStep) * MajorStep y, a continuación, añadiendo el MajorStep para encontrar el nivel upperMajor.

   // Draw the quarter lines first
   DrawQuarters(currentPrice);

Para proporcionar un comentario claro sobre lo que detecta el EA, se construye una cadena tabular. Esta tabla comienza con un encabezado que define tres columnas: Zona, precio y motivo. Estas columnas se utilizan para enumerar la importancia de cada nivel cuando el precio se acerca a ellos.

   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

El siguiente paso consiste en comprobar si el precio se encuentra cerca de niveles clave. El EA comprueba primero si el precio se encuentra dentro de la tolerancia especificada del límite inferior (Soporte principal) o del límite superior (Resistencia principal). Si se cumple cualquiera de las dos condiciones, la función añade una fila a la tabla de comentarios con el mensaje adecuado (utilizando mensajes predefinidos como «Key support level. Break below signals range shift." para el soporte, y un mensaje similar para la resistencia) y establece intrusionDetected en verdadero.<

// Check for Major Support
if(MathAbs(currentPrice - lowerMajor) <= AlertTolerance)
{
   table += StringFormat("%-18s | %-8s | %s\n", "Major Support", DoubleToString(lowerMajor,4), MajorSupportReason);
   intrusionDetected = true;
}
// Check for Major Resistance
if(MathAbs(currentPrice - upperMajor) <= AlertTolerance)
{
   table += StringFormat("%-18s | %-8s | %s\n", "Major Resistance", DoubleToString(upperMajor,4), MajorResistanceReason);
   intrusionDetected = true;
}

Si se habilita el dibujo de líneas de cuartos grandes, el EA divide el rango en cuartos y recorre estos niveles intermedios. Para cada cuarto grande, comprueba si el precio está dentro de la tolerancia; si lo está, añade una fila correspondiente (con un mensaje como «Decisive break could trigger next 250-PIP move.») a la tabla. Además, si se habilitan las áreas «overshoot», la función calcula un pequeño desplazamiento por encima y por debajo de cada cuarto de nivel grande y comprueba si el precio toca estas zonas «overshoot» o «undershoot», añadiendo de nuevo una fila a la tabla si se cumple la condición.

if(DrawLargeQuarters)
{
   double LQIncrement = MajorStep / 4.0;
   for(int i = 1; i < 4; i++)
   {
      double level = lowerMajor + i * LQIncrement;
      if(MathAbs(currentPrice - level) <= AlertTolerance)
      {
         table += StringFormat("%-18s | %-8s | %s\n", "Large Quarter", DoubleToString(level,4), LargeQuarterReason);
         intrusionDetected = true;
      }
      if(DrawOvershootAreas)
      {
         double offset = MajorStep / 40.0; // ~25 pips
         double overshootUp = level + offset;
         double undershootDown = level - offset;
         if(MathAbs(currentPrice - overshootUp) <= AlertTolerance)
         {
            table += StringFormat("%-18s | %-8s | %s\n", "Overshoot", DoubleToString(overshootUp,4), OvershootReason);
            intrusionDetected = true;
         }
         if(MathAbs(currentPrice - undershootDown) <= AlertTolerance)
         {
            table += StringFormat("%-18s | %-8s | %s\n", "Undershoot", DoubleToString(undershootDown,4), UndershootReason);
            intrusionDetected = true;
         }
      }
   }
}

Opcionalmente, si el EA está configurado para dibujar pequeñas líneas de cuarto, el rango se subdivide aún más. La función itera sobre estas divisiones más precisas y realiza comprobaciones de proximidad similares, añadiendo filas con un mensaje «Minor fluctuation» cada vez que el precio se acerca a uno de estos pequeños niveles de cuartos.

if(DrawSmallQuarters)
{
   double segStep = MajorStep / 10.0;
   double smallQuarter = segStep / 4.0;
   for(int seg = 0; seg < 10; seg++)
   {
      double segStart = lowerMajor + seg * segStep;
      for(int j = 1; j < 4; j++)
      {
         double level = segStart + j * smallQuarter;
         if(MathAbs(currentPrice - level) <= AlertTolerance)
         {
            table += StringFormat("%-18s | %-8s | %s\n", "Small Quarter", DoubleToString(level,4), SmallQuarterReason);
            intrusionDetected = true;
         }
      }
   }
}

Si ninguno de los niveles activa una intrusión (es decir, intrusionDetected sigue siendo falso), el EA construye un mensaje predeterminado. Este mensaje informa al usuario de que no se ha detectado ninguna intrusión significativa y que el mercado parece estar consolidándose, al tiempo que muestra el precio actual.

   // If no zones were triggered, still provide full information
   if(!intrusionDetected)
   {
      table = StringFormat("No significant intrusion detected.\nCurrent Price: %s\nMarket consolidating within established quarters.\n", DoubleToString(currentPrice,4));
   }

Después de crear la tabla de comentarios, el EA actualiza una etiqueta del gráfico utilizando la función CreateOrUpdateLabel, lo que garantiza que el último análisis se muestre claramente en el gráfico. Por último, si se detecta una intrusión y no se ha enviado previamente ninguna alerta (rastreada por el indicador intrusionAlerted), el EA activa una alerta con el contenido de la tabla y establece el indicador en verdadero para evitar notificaciones repetidas. Para garantizar que todos los objetos nuevos y las actualizaciones sean visibles de inmediato, la función finaliza llamando a ChartRedraw.

   // Update the label with the commentary table.
   CreateOrUpdateLabel("IntrusionCommentary", table, CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);

   // Trigger an alert only once per intrusion event.
   if(intrusionDetected && !intrusionAlerted)
   {
      Alert(table);
      intrusionAlerted = true;
   }
   if(!intrusionDetected)
      intrusionAlerted = false;

   ChartRedraw();
}

Código MQL5 completo

//+------------------------------------------------------------------+
//|                                               Intrusion Detector |
//|                               Copyright 2025, Christian Benjamin |
//|                          https://www.mql5.com/en/users/lynnchris |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

//---- Input parameters -------------------------------------------------
input double MajorStep          = 0.1000;   // Difference between Major Whole Numbers (defines the 1000-PIP Range)
input bool   DrawLargeQuarters  = true;     // Draw intermediate Large Quarter lines.
input bool   DrawSmallQuarters  = false;    // Draw Small Quarter lines.
input bool   DrawOvershootAreas = true;     // Mark overshoot/undershoot areas for Large Quarter lines.
input double AlertTolerance     = 0.0025;   // Tolerance for detecting a "touch" (e.g., ~25 pips for a pair where 1 pip=0.0001)

//---- Color settings ---------------------------------------------------
input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for Major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for Large Quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for Small Quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

//---- Line style and thickness settings -------------------------------
input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

//---- Commentary Messages (customizable) -----------------------------
input string MajorSupportReason    = "Key support level. Break below signals range shift.";
input string MajorResistanceReason = "Pivotal resistance. Breakout above may start new range.";
input string LargeQuarterReason    = "Decisive break could trigger next 250-PIP move.";
input string OvershootReason       = "Test of breakout; reversal likely if momentum fails.";
input string UndershootReason      = "Insufficient bullish force; possible bearish reversal.";
input string SmallQuarterReason    = "Minor fluctuation.";

// Global flag to avoid repeated alerts while price lingers at a level
bool intrusionAlerted = false;

//+------------------------------------------------------------------+
//| DrawHorizontalLine: Creates or replaces a horizontal line        |
//+------------------------------------------------------------------+
void DrawHorizontalLine(string name, double price, color lineColor, int width, ENUM_LINE_STYLE style)
  {
   if(ObjectFind(0, name) != -1)
      ObjectDelete(0, name);

   if(!ObjectCreate(0, name, OBJ_HLINE, 0, 0, price))
     {
      Print("Failed to create line: ", name);
      return;
     }
   ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
   ObjectSetInteger(0, name, OBJPROP_STYLE, style);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
  }

//+------------------------------------------------------------------+
//| DrawQuarters: Draws all quarter lines based on the current price |
//+------------------------------------------------------------------+
void DrawQuarters(double currentPrice)
  {
// Calculate the boundaries of the current 1000-PIP Range
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

// Draw Major Whole Number lines (defining the 1000-PIP Range)
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);

// Draw Large Quarter lines and their overshoot/undershoot areas if enabled
   if(DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);

         if(DrawOvershootAreas)
           {
            double offset = MajorStep / 40.0; // approximately 25 pips if MajorStep=0.1000
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - offset, OvershootColor, OvershootLineWidth, OvershootLineStyle);
           }
        }
     }

// Draw Small Quarter lines if enabled (optional, finer divisions)
   if(DrawSmallQuarters)
     {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
        {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
           {
            double level = segStart + j * smallQuarter;
            string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j);
            DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle);
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| CreateOrUpdateLabel: Creates or updates a label with given text  |
//+------------------------------------------------------------------+
void CreateOrUpdateLabel(string name, string text, int corner, int xdist, int ydist, color txtColor, int fontSize)
  {
   if(ObjectFind(0, name) == -1)
     {
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, corner);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(0, name, OBJPROP_YDISTANCE, ydist);
      // Set a monospaced font for tabular display (Courier New)
      ObjectSetString(0, name, OBJPROP_FONT, "Courier New");
     }
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_COLOR, txtColor);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
  }

//+------------------------------------------------------------------+
//| OnInit: Initialization function for the EA                       |
//+------------------------------------------------------------------+
int OnInit()
  {
// Create a persistent commentary label in the top-left corner
   CreateOrUpdateLabel("IntrusionCommentary", "Intrusion Detector Initialized", CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| OnDeinit: Deinitialization function for the EA                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Remove the commentary label on exit
   ObjectDelete(0, "IntrusionCommentary");
  }

//+------------------------------------------------------------------+
//| OnTick: Main function called on every tick                       |
//+------------------------------------------------------------------+
void OnTick()
  {
   bool intrusionDetected = true;
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;

// Draw the quarter lines first
   DrawQuarters(currentPrice);

// Calculate boundaries of the current 1000-PIP Range
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;

// Build a tabular commentary string with a header.
   string header = StringFormat("%-18s | %-8s | %s\n", "Zone", "Price", "Reason");
   string separator = "----------------------------------------------\n";
   string table = header + separator;

// Check for Major Support
   if(MathAbs(currentPrice - lowerMajor) <= AlertTolerance)
     {
      table += StringFormat("%-18s | %-8s | %s\n", "Major Support", DoubleToString(lowerMajor,4), MajorSupportReason);
      intrusionDetected = true;
     }
// Check for Major Resistance
   if(MathAbs(currentPrice - upperMajor) <= AlertTolerance)
     {
      table += StringFormat("%-18s | %-8s | %s\n", "Major Resistance", DoubleToString(upperMajor,4), MajorResistanceReason);
      intrusionDetected = true;
     }

// Check Large Quarter Levels and Overshoot/Undershoot Zones
   if(DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         if(MathAbs(currentPrice - level) <= AlertTolerance)
           {
            table += StringFormat("%-18s | %-8s | %s\n", "Large Quarter", DoubleToString(level,4), LargeQuarterReason);
            intrusionDetected = true;
           }
         if(DrawOvershootAreas)
           {
            double offset = MajorStep / 40.0; // ~25 pips
            double overshootUp = level + offset;
            double undershootDown = level - offset;
            if(MathAbs(currentPrice - overshootUp) <= AlertTolerance)
              {
               table += StringFormat("%-18s | %-8s | %s\n", "Overshoot", DoubleToString(overshootUp,4), OvershootReason);
               intrusionDetected = true;
              }
            if(MathAbs(currentPrice - undershootDown) <= AlertTolerance)
              {
               table += StringFormat("%-18s | %-8s | %s\n", "Undershoot", DoubleToString(undershootDown,4), UndershootReason);
               intrusionDetected = true;
              }
           }
        }
     }

// Check Small Quarter Levels (if enabled)
   if(DrawSmallQuarters)
     {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
        {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
           {
            double level = segStart + j * smallQuarter;
            if(MathAbs(currentPrice - level) <= AlertTolerance)
              {
               table += StringFormat("%-18s | %-8s | %s\n", "Small Quarter", DoubleToString(level,4), SmallQuarterReason);
               intrusionDetected = true;
              }
           }
        }
     }

// If no zones were triggered, still provide full information
   if(!intrusionDetected)
     {
      table = StringFormat("No significant intrusion detected.\nCurrent Price: %s\nMarket consolidating within established quarters.\n", DoubleToString(currentPrice,4));
     }

// Update the label with the commentary table.
   CreateOrUpdateLabel("IntrusionCommentary", table, CORNER_LEFT_UPPER, 10, 10, clrWhite, 14);

// Trigger an alert only once per intrusion event.
   if(intrusionDetected && !intrusionAlerted)
     {
      Alert(table);
      // Alternatively, you could use: PlaySound("alert.wav");
      intrusionAlerted = true;
     }
   if(!intrusionDetected)
      intrusionAlerted = false;

   ChartRedraw();
  }
//+------------------------------------------------------------------+


Resultados

Aquí presentaré los resultados que obtuve tras probar la herramienta en un entorno de mercado real, aunque utilicé una cuenta demo para este fin. A continuación se muestra un diagrama que representa el dólar neozelandés (NZD) frente al dólar estadounidense (USD). El precio se acercó al nivel de undershoot, lo que activó una alerta. 

La alerta proporcionó información crítica, incluida la zona identificada, que en este caso era la zona de undershoot. El nivel de precios específico en el que se detectó esta zona es 0,5725. Además, la alerta incluía un análisis de las condiciones del mercado en ese nivel, indicando un impulso alcista insuficiente y la posibilidad de una reversión bajista.

NZDUSD

Figura 3. NZD frente a USD

A continuación se muestra la información registrada en la pestaña Expertos de MetaTrader 5.

2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       Alert: Zone               | Price    | Reason
2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       ----------------------------------------------
2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       Undershoot         | 0.5725   | Insufficient bullish force; possible bearish reversal.
2025.02.25 16:55:37.188 Intrusion Detector EA (NZDUSD,H1)       

Echemos un vistazo a la operación que realicé tras esta detección y un análisis más detallado.

Operaciones realizadas

Figura 3. Prueba de trading

A continuación se muestra la última posición del mercado, aunque cerré mis operaciones rápidamente.

Movimiento del mercado

Figura 5. Movimiento del mercado

La figura 6 que aparece a continuación es un GIF que muestra una prueba que realicé con el par de divisas USDCAD, en la que se identificaron dos zonas en las que el precio reaccionó al rebasamiento y al nivel de cuarto grande.

USDCAD

Figura 6. USDCAD



Conclusión

Nuestro asesor experto actúa como un potente asistente de análisis, diseñado específicamente para supervisar las zonas de precios en consonancia con la teoría de los cuartos. Esta herramienta es especialmente valiosa para los operadores que incorporan la teoría de los cuartos en su análisis de mercado. Según nuestras exhaustivas pruebas, el EA destaca en la detección de zonas clave de precios, la emisión de alertas oportunas y la supervisión eficaz del mercado en segundo plano. Este avance supone un importante paso adelante en la automatización del análisis de mercado utilizando la teoría de los cuartos. Anteriormente, nos centramos en automatizar el dibujo de cuartos, y ahora hemos avanzado hacia la supervisión de cuartos en tiempo real. Esta mejora garantiza que los operadores sean informados rápidamente cada vez que el precio interactúa con estos niveles críticos, acompañados de una explicación concisa de los posibles cambios en el mercado.

Sin embargo, esta no es la etapa final de nuestro viaje. Se esperan más innovaciones en la aplicación de la teoría de cuartos en la automatización del mercado. Dicho esto, animo a todos los operadores que utilicen esta herramienta a integrar sus propias estrategias en lugar de confiar únicamente en las señales proporcionadas. Un enfoque integral, que combina la automatización con la experiencia personal, conduce a decisiones comerciales informadas.

FechaNombre de la herramienta DescripciónVersión Actualizaciones Notas
01/10/24Chart ProjectorScript para superponer la acción del precio del día anterior con efecto fantasma.1.0Lanzamiento inicialHerramienta número 1
18/11/24Analytical CommentProporciona información del día anterior en formato tabular y anticipa la dirección futura del mercado.1.0Lanzamiento inicialHerramienta número 2
27/11/24Analytics MasterActualización periódica de las métricas del mercado cada dos horas. 1.01Segundo lanzamientoHerramienta número 3
02/12/24Analytics Forecaster Actualización periódica de las métricas del mercado cada dos horas con integración de Telegram.1.1Tercera ediciónHerramienta número 4
09/12/24Volatility NavigatorEA que analiza las condiciones del mercado utilizando los indicadores Bandas de Bollinger, RSI y ATR.1.0Lanzamiento inicialHerramienta número 5
19/12/24Mean Reversion Signal Reaper Analiza el mercado utilizando la estrategia de reversión a la media y proporciona señales. 1.0 Lanzamiento inicial Herramienta número 6 
09/01/25 Signal Pulse Analizador de múltiples marcos temporales.1.0 Lanzamiento inicial Herramienta número 7 
17/01/25 Metrics Board Panel con botón para análisis. 1.0 Lanzamiento inicialHerramienta número 8 
21/01/25External FlowAnálisis mediante librerías externas.1.0 Lanzamiento inicialHerramienta número 9 
27/01/25VWAPVolume Weighted Average Price  1.3 Lanzamiento inicial Herramienta número 10 
02/02/25 Heikin Ashi Identificación de señales de suavizado y reversión de tendencias. 1.0 Lanzamiento inicial Herramienta número 11
04/02/25 FibVWAP Generación de señales mediante análisis de Python. 1.0 Lanzamiento inicial Herramienta número 12
14/02/25 RSI DIVERGENCE Acción del precio frente a divergencias del RSI. 1.0 Lanzamiento inicial Herramienta número 13 
17/02/25 Parabolic Stop and Reverse (PSAR) Automatización de la estrategia PSAR.1.0Lanzamiento inicial Herramienta número 14
20/02/25 Quarters Drawer Script Dibujar los niveles de cuartos en el gráfico. 1.0 Lanzamiento inicial Herramienta número 15 
27/02/25Intrusion DetectorDetectar y alertar cuando el precio alcanza niveles de cuartos.1.0Lanzamiento inicialHerramienta número 16

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

Archivos adjuntos |
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 17): Asesor experto TrendLoom Tool Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 17): Asesor experto TrendLoom Tool
Como observador de la acción del precio y trader, he notado que cuando una tendencia se confirma en múltiples marcos temporales, suele continuar en esa dirección. Lo que puede variar es la duración de la tendencia, y esto depende del tipo de trader que seas, si mantienes posiciones a largo plazo o te dedicas al scalping. Los plazos que elijas para la confirmación desempeñan un papel crucial. Echa un vistazo a este artículo para conocer un sistema rápido y automatizado que te ayuda a analizar la tendencia general en diferentes marcos temporales con solo hacer clic en un botón o mediante actualizaciones periódicas.
Un nuevo enfoque para los criterios personalizados en las optimizaciones (Parte 1): Ejemplos de funciones de activación Un nuevo enfoque para los criterios personalizados en las optimizaciones (Parte 1): Ejemplos de funciones de activación
El primero de una serie de artículos que analizan las matemáticas de los criterios personalizados, con especial atención a las funciones no lineales utilizadas en las redes neuronales, el código MQL5 para su implementación y el uso de compensaciones específicas y correccionales.
De principiante a experto: Indicador de fuerza de soporte y resistencia (SRSI) De principiante a experto: Indicador de fuerza de soporte y resistencia (SRSI)
En este artículo compartiremos información sobre cómo aprovechar la programación MQL5 para identificar los niveles del mercado, diferenciando entre los niveles de precios más débiles y los más fuertes. Desarrollaremos completamente un indicador de fuerza de soporte y resistencia (Support and Resistance Strength Indicator, SRSI) funcional.
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 15): Introducción a la teoría de los cuartos (I) - Dibujando la teoría de cuartos Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 15): Introducción a la teoría de los cuartos (I) - Dibujando la teoría de cuartos
Los puntos de soporte y resistencia son niveles críticos que indican posibles reversiones y continuaciones de la tendencia. Aunque identificar estos niveles puede resultar complicado, una vez que los localices, estarás bien preparado para navegar por el mercado. Si necesitas más ayuda, échale un vistazo a la herramienta Quarters Drawer que aparece en este artículo, te ayudará a identificar los niveles de soporte y resistencia principales y secundarios.