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

Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 7): Signal Pulse EA

MetaTrader 5Ejemplos |
183 0
Christian Benjamin
Christian Benjamin

Contenido



Introducción

En este artículo, exploraremos cómo desarrollar un Asesor Experto (Expert Advisor, EA) en MQL5 llamado Signal Pulse EA. El EA utilizará una combinación de indicadores de bandas de Bollinger y oscilador estocástico en tres marcos temporales diferentes para detectar señales de compra y venta. El objetivo de este EA es ayudar a los operadores a tomar decisiones informadas confirmando las señales de múltiples marcos temporales antes de entrar en una operación. Hemos incorporado múltiples marcos temporales, Bandas de Bollinger (BB) y el oscilador estocástico para la generación de señales. Nuestro objetivo es minimizar las señales falsas, que pueden resultar frustrantes para los operadores. Al combinar estos elementos, nuestro objetivo es mejorar la precisión de nuestras señales de trading. A continuación, he tabulado la importancia de cada componente en nuestra herramienta de generación de señales.

  • Múltiples marcos temporales
Ventaja Descripción
Gestión de riesgos El uso de múltiples marcos temporales permite al EA analizar el mercado desde diferentes perspectivas, reduciendo el impacto de señales falsas y mejorando la gestión de riesgos.
Confianza en las señales Al confirmar señales en múltiples períodos de tiempo, el EA gana confianza en la dirección de la operación, lo que reduce la probabilidad de ingresar a una operación con una señal débil o falsa.
Diversificación El análisis de múltiples marcos temporales proporciona una visión más diversificada del mercado, lo que permite que el EA se adapte a las condiciones cambiantes del mercado y tome decisiones comerciales más informadas.
  • Estocástico
Ventaja Descripción
Condiciones de sobrecompra/sobreventa
El estocástico ayuda a identificar condiciones de sobrecompra y sobreventa, indicando posibles puntos de reversión en el mercado.
Herramienta de confirmación
El estocástico sirve como herramienta de confirmación para las Bandas de Bollinger, garantizando que el EA no ingrese a una operación basándose únicamente en señales de BB.
Filtrado de señales falsas
Al utilizar el estocástico, el EA puede filtrar señales falsas generadas por las Bandas de Bollinger, especialmente durante períodos de alta volatilidad.

  • Bandas de Bollinger
Ventaja Descripción
Indicación de volatilidad
Las Bandas de Bollinger indican el nivel de volatilidad en el mercado, lo que ayuda al EA a comprender el estado de ánimo del mercado y las posibles oportunidades comerciales.
Niveles de soporte/resistencia
Las Bandas de Bollinger actúan como niveles dinámicos de soporte y resistencia, proporcionando al EA posibles puntos de entrada y salida.
Confirmación de tendencia 
El ancho de las Bandas de Bollinger puede confirmar o negar la presencia de una tendencia, lo que ayuda al EA a tomar decisiones comerciales informadas.

La interacción entre múltiples marcos temporales, el estocástico y las Bandas de Bollinger (BB) mejora significativamente la eficacia del EA para generar señales comerciales confiables y gestionar el riesgo. Al analizar señales en varios períodos de tiempo, el EA garantiza que las oportunidades comerciales se confirmen mediante una fuerte confluencia de indicadores tanto del estocástico como del BB. This multidimensional approach reduces the likelihood of false signals, as the EA identifies potential trades only when there is robust evidence supporting the decision. Como resultado, la combinación de estos elementos aumenta la fiabilidad de las señales generadas y mejora la gestión general del riesgo, lo que permite a los operadores tomar decisiones más informadas basadas en un mayor grado de confianza y precisión. 


Entendiendo la estrategia

El script Signal Pulse genera señales comerciales basadas en la alineación de las Bandas de Bollinger y el oscilador estocástico en tres períodos de tiempo (M15, M30 y H1). Las condiciones para cada señal son las siguientes:

Señal de compra

  1. Condición de las Bandas de Bollinger: El precio toca la banda inferior de las Bandas de Bollinger en los tres marcos temporales.
  2. Condición del oscilador estocástico: El oscilador estocástico indica una condición de sobreventa en los tres marcos temporales, normalmente por debajo de 20.
  3. Requisito de confirmación: Deben cumplirse ambas condiciones simultáneamente en los marcos temporales M15, M30 y H1 para generar una señal de compra.

CONDICIONES DE COMPRA

Figura 1. Condiciones de compra

Señal de venta

  1. Condición de las Bandas de Bollinger: El precio toca la banda superior de las Bandas de Bollinger en los tres marcos temporales.
  2. Condición del oscilador estocástico: El oscilador estocástico indica una condición de sobrecompra en los tres marcos temporales, normalmente por encima de 80.
  3. Requisito de confirmación: Deben cumplirse ambas condiciones simultáneamente en los marcos temporales M15, M30 y H1 para generar una señal de venta.

CONDICIONES DE VENTA

Figura 2. Condiciones de venta

Visualicemos este proceso a través del diagrama siguiente.  

TABLA DE GENERACIÓN DE SEÑALES

Figura 3. Proceso de generación de señales


Código MQL5

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping

// Signal tracking structure
struct SignalInfo
  {
   datetime          time;
   double            price;
   bool              isBuySignal;
  };

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle)
  {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
     }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand))
     {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value)
  {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
     }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer))   // %D line
     {
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal()
  {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3))
     {
      Print("Error retrieving Bollinger Bands data.");
      return;
     }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3))
     {
      Print("Error retrieving Stochastic data.");
      return;
     }

// Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

// Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1))
     {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
     }

   if(sellSignal && !ArrowExists(close1))
     {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
     }
  }

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price)
  {
   for(int i = 0; i < ArraySize(signalPrices); i++)
     {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance)
        {
         return true; // Arrow exists in the same price region
        }
     }
   return false; // No arrow exists in the same region
  }

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick()
  {
   CheckAndGenerateSignal();
  }

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--)
     {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1)
        {
         ObjectDelete(chart_id, name);
        }
     }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
  }
//+------------------------------------------------------------------+



Desglose del código

Este análisis del Signal Pulse EA explorará los diversos componentes del Asesor Experto, sus mecanismos operativos y la lógica subyacente de sus funcionalidades, paso a paso.
  • Encabezado, propiedades y parámetros de entrada

Al comienzo de nuestro EA, incluimos un encabezado que proporciona metadatos esenciales. Esto consta del nombre del EA, detalles de derechos de autor y un enlace donde puede obtener más información sobre nuestro trabajo. Pero lo que realmente te ayuda como trader son los parámetros de entrada. Estas configuraciones personalizables le permiten adaptar el comportamiento del EA para que se ajuste a su estilo comercial.

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping
Aquí, especificamos diferentes marcos temporales (M15, M30 y H1), lo que le permite analizar los movimientos de precios en varios períodos. También definimos los parámetros de las bandas de Bollinger, como su periodo y desviación, junto con los ajustes del oscilador estocástico, incluidos sus periodos %K y %D. Incluso incluimos ajustes visuales para las flechas que marcarán las señales de compra y venta en su gráfico, junto con parámetros diseñados para minimizar el desorden visual al evitar que las flechas se superpongan.
  •  Seguimiento de señales y estructuras

A continuación, definimos la estructura SignalInfo, que desempeña un papel fundamental en la organización de nuestras señales de trading. Esta estructura recopila información sobre cuándo se produjo una señal, el precio en ese momento y si se trataba de una señal de compra o de venta. Además, configuramos matrices para almacenar esta información de forma dinámica. 

// Signal tracking structure
struct SignalInfo {
   datetime time;
   double price;
   bool isBuySignal;
};

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];
Con las matrices signalTimes, signalPrices y signalBuySignals, mantenemos un registro claro de las señales de trading que genera el EA a lo largo del tiempo, lo que facilita mucho el manejo de múltiples señales sin confundirse.
  •  Funciones de recuperación de indicadores

Ahora vamos a profundizar en las funciones que utilizamos para recuperar los valores de los indicadores, concretamente los indicadores de Bandas de Bollinger y estocásticos.. 

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle) {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
   }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand)) {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
}

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value) {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
   }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer)) { // %D line
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
}
La primera función, GetBollingerBands(), obtiene los niveles superior, medio e inferior de las Bandas de Bollinger para un periodo de tiempo determinado. Crea un identificador para el indicador y comprueba si se ha creado correctamente. Si todo está correcto, copia los valores de la banda en matrices, que luego podemos utilizar para nuestra lógica de negociación. Del mismo modo, la función GetStochastic() recupera los valores %K y %D del oscilador estocástico. Utiliza los mismos procedimientos de comprobación de errores y copia de datos, lo que garantiza que siempre obtengamos datos precisos para nuestra toma de decisiones.

  • Comprobación y generación de señales

Una vez gestionados los indicadores, pasamos ahora a la función CheckAndGenerateSignal(), que contiene la lógica central de nuestro EA. Esta función llama a nuestras funciones indicadoras definidas anteriormente para recopilar datos de las Bandas de Bollinger y los indicadores estocásticos en todos los marcos temporales especificados. Además, obtiene los últimos precios de cierre para estos periodos de tiempo.

La función comprueba las señales de compra y venta basándose en las condiciones actuales del mercado. Se activa una señal de compra cuando los precios de cierre están por debajo de la banda de Bollinger inferior y los valores estocásticos indican condiciones de sobreventa (menos de 5). Por el contrario, las señales de venta surgen cuando los precios superan la banda de Bollinger superior, con lecturas estocásticas superiores a 95, lo que sugiere condiciones de sobrecompra.

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal() {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3)) {
      Print("Error retrieving Bollinger Bands data.");
      return;
   }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3)) {
      Print("Error retrieving Stochastic data.");
      return;
   }

   // Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

   // Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1)) {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
   }

   if(sellSignal && !ArrowExists(close1)) {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
   }
}

Además, antes de colocar una flecha para indicar una señal en el gráfico, la función se asegura de que ninguna flecha existente se superponga invocando la función ArrowExists(). Si todo está correcto, crea la flecha adecuada y almacena la información sobre la señal en nuestras matrices previamente definidas.

  • Comprobación de existencia de flecha

En nuestro afán por conseguir un gráfico ordenado, la función ArrowExists() desempeña un papel importante al comprobar si hay alguna flecha existente cerca del precio de la señal actual. Esto evita que se superpongan varias flechas, lo que podría generar confusión. Al comparar el nuevo precio de la señal con los precios almacenados en la matriz signalPrices, determinamos si una flecha existente está lo suficientemente cerca como para justificar que no se cree una nueva.

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price) {
   for(int i = 0; i < ArraySize(signalPrices); i++) {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance) {
         return true; // Arrow exists in the same price region
      }
   }
   return false; // No arrow exists in the same region
}

  • Funciones OnTick y OnDeinit

Por último, tenemos las funciones OnTick() y OnDeinit(). La función OnTick() se llama cada vez que hay un nuevo tick del mercado, lo que garantiza que nuestro EA siga respondiendo y esté actualizado. Invoca la función CheckAndGenerateSignal() para reevaluar las posibles señales de trading basándose en los datos más recientes.

Por el contrario, la función OnDeinit() se llama cuando se elimina el EA o se cierra el terminal. Su función es eliminar cualquier objeto gráfico creado por el EA, concretamente las flechas que marcan las señales de compra y venta, manteniendo así un gráfico despejado.

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick() {
   CheckAndGenerateSignal();
}

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   // Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--) {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1) {
         ObjectDelete(chart_id, name);
      }
   }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
}

Además, en el EA Signal Pulse, ajustamos los niveles de umbral del oscilador estocástico para garantizar que solo se generen las señales más fiables. Estos ajustes se centran en confirmar que el mercado está en condiciones extremas (sobreventa para señales de compra o sobrecompra para señales de venta) antes de tomar medidas.

  • Condición de sobreventa: Señal de compra
bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                 (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition

Para una señal de compra, el precio debe estar en o por debajo de la banda de Bollinger inferior en los tres marcos temporales (M15, M30, H1), lo que indica una fuerte presión bajista. Además, el valor %K del oscilador estocástico debe ser inferior a 5 en los tres marcos temporales. Este valor indica una situación de sobreventa extrema en la que es muy probable que el mercado experimente un cambio de tendencia al alza. El umbral más estricto de < 5 garantiza que el EA solo tenga en cuenta las señales en las que la probabilidad de una reversión sea significativamente alta.

  • Condición de sobrecompra: Señal de venta

bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                  (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

Para una señal de venta, el precio debe estar en o por encima de la banda de Bollinger superior en los tres marcos temporales, lo que indica un fuerte impulso alcista que pronto podría revertirse. El valor %K del oscilador estocástico debe superar el 95 en todos los marcos temporales, lo que indica una situación de sobrecompra extrema en la que es probable que el mercado entre en una fase bajista. Esta condición estricta garantiza que el EA evite señales de venta falsas durante movimientos moderados de precios o consolidaciones.


Pruebas y resultados

  • Pruebas retrospectivas con datos históricos
El backtesting (prueba retrospectiva) es un componente fundamental del desarrollo de Asesores Expertos, ya que permite a los operadores analizar el rendimiento de sus Asesores Experto a partir de datos históricos de precios. Este proceso ayuda a identificar la rentabilidad, precisión y solidez del EA, lo que permite a los operadores perfeccionar su estrategia y optimizar su rendimiento.
1. Cargar datos históricos

Para comenzar a realizar pruebas retrospectivas, es esencial cargar datos históricos de alta calidad a nivel de tick para el instrumento y los períodos de tiempo elegidos. Estos datos servirán como base para evaluar el desempeño del EA. Es fundamental garantizar que los datos sean precisos y confiables, ya que cualquier discrepancia puede llevar a conclusiones incorrectas sobre el desempeño del EA.

2. Establecer parámetros de prueba

Una vez cargados los datos, es el momento de configurar el Probador de estrategias en MetaTrader con los parámetros necesarios. Esto incluye:
  • Símbolo: Seleccione el par de divisas o el activo que desea negociar.
  • Periodo: Utilice los mismos períodos de tiempo que las configuraciones del EA (por ejemplo, M15, M30, H1).
  • Spread: Establezca un spread realista o fijo para simular los costos comerciales y garantizar que los resultados sean representativos de las condiciones comerciales del mundo real.
  • Optimización: Pruebe los parámetros de entrada (por ejemplo, el período de las Bandas de Bollinger, los umbrales estocásticos) para obtener un rendimiento óptimo.
3. Evaluar resultados
Después de configurar los parámetros de prueba, es hora de analizar las métricas de salida:
  • Rentabilidad: Evalúe la utilidad neta y el factor de utilidad del EA para determinar su rentabilidad general.
  • Riesgo: Evalúe la reducción máxima para medir la tolerancia al riesgo del EA.
  • Tasa de ganancias y frecuencia comercial: Analice la cantidad de operaciones ganadoras y la frecuencia comercial para comprender el desempeño del EA en diferentes condiciones del mercado.

Repasemos los resultados de las pruebas que se proporcionan a continuación.

RESULTADO DE LA PRUEBA 1

Figura 4. Resultado de la prueba 1

RESULTADO 2

Figura 5. Resultado de la prueba 2

Los diagramas anteriores ilustran la prueba de rendimiento del EA. En el GIF podemos observar el registro de cada señal detectada. Puede realizar más pruebas modificando los parámetros de entrada, los marcos temporales y los niveles estocásticos hasta lograr resultados que satisfagan sus requisitos.


Conclusión

En este artículo, hemos desarrollado el Asesor Experto «Signal Pulse», que combina los indicadores de Bandas de Bollinger y oscilador estocástico para generar señales de trading en los marcos temporales M15, M30 y H1. El sistema identifica condiciones de sobrecompra/sobreventa solo cuando se alinean múltiples marcos temporales, lo que aumenta la probabilidad de éxito. Es esencial realizar pruebas retrospectivas exhaustivas en diversas condiciones de mercado. Las mejoras futuras podrían incluir la incorporación de filtros de dirección de tendencias, gestión avanzada de riesgos y el perfeccionamiento de la lógica de las señales para diferentes tipos de mercados. Animamos a los operadores a utilizar «Signal Pulse» junto con sus propias estrategias y técnicas para lograr un enfoque integral del trading.

Fecha Nombre de la herramienta  Descripción Versión  Actualizaciones  Notas
01/10/24 Chart Projector Script para superponer la acción del precio del día anterior con efecto fantasma. 1.0 Lanzamiento inicial Primera herramienta en Lynnchris Tool Chest.
18/11/24 Analytical Comment Proporciona información del día anterior en formato tabular y anticipa la dirección futura del mercado. 1.0 Lanzamiento inicial Segunda herramienta en Lynnchris Tool Chest.
27/11/24 Analytics Master Actualización periódica de las métricas del mercado cada dos horas.  1.01 Segundo lanzamiento Tercera herramienta en Lynnchris Tool Chest.
02/12/24 Analytics Forecaster  Actualización periódica de las métricas del mercado cada dos horas con integración en Telegram. 1.1 Tercera edición Herramienta número 4
09/12/24 Volatility Navigator El EA analiza las condiciones del mercado utilizando los indicadores Bandas de Bollinger, RSI y ATR. 1.0 Lanzamiento inicial Herramienta número 5
19/12/24 Reaper de señales de reversión a la media.  Analiza el mercado utilizando la estrategia de reversión a la media y proporciona señales.  1.0  Lanzamiento inicial  Herramienta número 6 
9/01/2025  Signal Pulse  Analizador de múltiples marcos temporales 1.0  Lanzamiento inicial  Herramienta número 7 

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

Archivos adjuntos |
Modelos ocultos de Markov para la predicción de la volatilidad siguiendo tendencias Modelos ocultos de Markov para la predicción de la volatilidad siguiendo tendencias
Los modelos ocultos de Markov (Hidden Markov Models, HMM) son potentes herramientas estadísticas que identifican los estados subyacentes del mercado mediante el análisis de los movimientos observables de los precios. En el ámbito bursátil, los HMM mejoran la predicción de la volatilidad y proporcionan información para las estrategias de seguimiento de tendencias mediante la modelización y la anticipación de los cambios en los regímenes de mercado. En este artículo, presentaremos el procedimiento completo para desarrollar una estrategia de seguimiento de tendencias que utiliza HMM para predecir la volatilidad como filtro.
Kit de herramientas de negociación MQL5 (Parte 6): Ampliación de la libreria EX5 de gestión del historial con las funciones de última orden pendiente completada Kit de herramientas de negociación MQL5 (Parte 6): Ampliación de la libreria EX5 de gestión del historial con las funciones de última orden pendiente completada
Aprenda a crear un módulo EX5 de funciones exportables que consultan y guardan datos de forma fluida para el pedido pendiente completado más recientemente. En esta guía paso a paso, mejoraremos la librería History Management EX5 desarrollando funciones específicas y compartimentadas para recuperar las propiedades esenciales de la última orden pendiente completada. Estas propiedades incluyen el tipo de orden, el tiempo de configuración, el tiempo de ejecución, el tipo de ejecución y otros detalles críticos necesarios para la gestión y el análisis eficaces del historial de operaciones de las órdenes pendientes.
Dominando los registros (Parte 3): Exploración de controladores para guardar registros Dominando los registros (Parte 3): Exploración de controladores para guardar registros
En este artículo, exploraremos el concepto de controladores en la librería de registro, comprenderemos cómo funcionan y crearemos tres implementaciones iniciales: Console, Database y File. Cubriremos todo, desde la estructura básica de los controladores hasta las pruebas prácticas, preparando el terreno para su plena funcionalidad en futuros artículos.
Características del Wizard MQL5 que debe conocer (Parte 52): Accelerator Oscillator (AC) Características del Wizard MQL5 que debe conocer (Parte 52): Accelerator Oscillator (AC)
El Accelerator Oscillator es otro indicador de Bill Williams que sigue la aceleración del impulso del precio y no solo su ritmo. Aunque es muy similar al oscilador Awesome que analizamos en un artículo reciente, busca evitar los efectos de retraso centrándose más en la aceleración que en la velocidad. Como siempre, examinamos qué patrones podemos obtener de esto y también qué importancia podría tener cada uno de ellos en el trading a través de un asesor experto creado por el Asistente MQL5 (MQL5 Wizard).