English Русский 中文 Deutsch 日本語
preview
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

MetaTrader 5Sistemas comerciales |
51 3
Christian Benjamin
Christian Benjamin

Contenido



Introducción

Los métodos de análisis de mercado y de confirmación de entrada difieren entre los analistas de tendencias. Muchos traders revisan múltiples marcos temporales como M1, M5 y M15 o H1, H4 y W1 para validar sus entradas y aumentar la confiabilidad de la señal. En lugar de cambiar los períodos de tiempo para medir la tendencia general, simplemente presiona un botón y recibes una actualización a tiempo o te actualizas automáticamente. ¿Alguna vez has visto una venta en un marco de tiempo inferior, has entrado en una operación y luego has abierto un gráfico en un marco de tiempo superior solo para descubrir una tendencia de compra?

TrendLoom Tool está diseñado para evitar ese problema. Cuenta con un panel con siete botones que representan varios estilos de negociación. Cada botón muestra tres marcos temporales que se analizan conjuntamente utilizando medias móviles para generar señales como COMPRAR, VENDER o NEUTRAL. Esta sólida herramienta proporciona actualizaciones de confirmación rápidas y se actualiza continuamente con señales relevantes a medida que se detectan.


Descripción general de la estrategia

TrendLoom Tool está estructurado como una interfaz gráfica (panel). El panel contiene siete botones, cada uno de los cuales corresponde a una estrategia comercial específica.
  • Enfoque a corto plazo (M1, M5, M15)
  • Scalping/Intradía (M5, M15, H1)
  • Operaciones de swing trading (M15, H1, H4)
  • Operaciones con tendencias (H1, H4, D1)
  • Confirmación de tendencia MTF (H1, H4, W1)
  • Scalper corto/Tendencia media (M5, H1, D1)
  • Tendencia a largo plazo (H1, D1, W1)

Veamos cómo el EA genera una señal de COMPRA, VENTA o NEUTRAL cuando se pulsa un botón.

  • Recopilación de datos: Para cada uno de los tres marcos temporales (por ejemplo, M1, M5 y M15), el EA recupera el precio de cierre de la última vela completamente completada.
  • Cálculo de la SMA: Para cada intervalo de tiempo, el EA calcula una media móvil simple (SMA) de 50 períodos. Este SMA actúa como referencia para el precio actual.
Generación de señales individuales: El EA compara el precio de cierre con la SMA correspondiente.

  • Si el precio está por encima de la SMA, lo considera una señal alcista y le asigna un valor de +1.
  • Si el precio está por debajo de la SMA, lo considera una señal bajista y le asigna un valor de -1.
  • Cuando el precio es igual al SMA, la señal es neutral (0).

Combinación de las señales

  • Las tres señales individuales (una de cada intervalo de tiempo) se suman.
  • Determinación de la señal final:
  • Si la suma es 2 o más, indica un fuerte impulso alcista. El EA devuelve una señal de «COMPRA».
  • Si la suma es -2 o menos, indica un fuerte impulso bajista. El EA devuelve una señal de «VENTA».
  • De lo contrario, las señales son mixtas o neutras, por lo que el EA devuelve «NEUTRAL».

Revisemos el siguiente diagrama para comprender mejor el proceso.

Diagrama de flujo

Figura 1. Diagrama de flujo


Implementación en MQL5

En la parte superior, verás los comentarios del encabezado y las definiciones de propiedades del EA. Estas líneas sirven como metadatos para la EA, especificando sus derechos de autor, versión y vinculándola a su fuente. La directiva #property strict se utiliza para aplicar reglas de compilación más estrictas, lo que ayuda a evitar errores comunes de codificación.

//+------------------------------------------------------------------+
//|                                                 TrendLoom EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"
#property strict

A continuación, el código incluye varios archivos de encabezado que proporcionan controles de diálogo, botones, etiquetas y paneles. También incorpora controles de objetos de gráfico para mostrar texto en el gráfico. Esta inclusión modular permite al EA utilizar clases preconstruidas para la interfaz de usuario.

Estas incluyen librerías de referencia de directivas en la carpeta «Include» de tu MetaEditor. Los archivos de la subcarpeta Controls ofrecen clases integradas para cuadros de diálogo y botones. También ofrecen clases para etiquetas y paneles. Este diseño simplifica la creación de una interfaz interactiva sin necesidad de reescribir el código. El archivo de la subcarpeta ChartObjects (ChartObjectsTxtControls.mqh) permite mostrar texto dinámico en el gráfico.

#include <Controls/Dialog.mqh>
#include <Controls/Button.mqh>
#include <Controls/Label.mqh>
#include <Controls/Panel.mqh>
#include <ChartObjects/ChartObjectsTxtControls.mqh>  // Adjusted include path (singular folder)

A continuación, se definen las constantes para la alineación del texto y un valor de color. Esta práctica mejora la claridad y la facilidad de mantenimiento del código.

#ifndef ALIGN_LEFT
  #define ALIGN_LEFT   0
#endif
#ifndef ALIGN_CENTER
  #define ALIGN_CENTER 1
#endif
#ifndef ALIGN_RIGHT
  #define ALIGN_RIGHT  2
#endif

#define clrSilver 0xC0C0C0

El EA declara los parámetros de entrada que ajustan la apariencia y la posición del panel y sus botones. PanelX, PanelY y PanelWidth establecen la geometría del panel, mientras que las entradas de color definen el tema visual. Las dimensiones de los botones se controlan con btnWidth, btnHeight y btnSpacing, y el EA te permite personalizar tanto el diseño como los colores. Esta configuración ofrece flexibilidad para adaptar la interfaz de usuario a sus necesidades.

//---- Input parameters -----------------------------------------------
input int    PanelX               = 10;
input int    PanelY               = 10;
input int    PanelWidth           = 250;
input int    btnWidth             = 220;
input int    btnHeight            = 30;
input int    btnSpacing           = 5;

input color  PanelBackgroundColor = clrDimGray;
input color  PanelHeaderColor     = clrBlueViolet;
input color  ButtonBgColor        = clrBlack;
input color  ButtonTextColor      = clrBlueViolet;
input color  AnalysisTextColor    = clrLime;

Las matrices almacenan los nombres y los textos de los botones, lo que hace que actualizar o añadir nuevos botones sea rápido y sencillo. Este diseño centraliza toda la información relacionada con los botones en un solo lugar, por lo que las modificaciones solo requieren pequeños ajustes. También mejora la coherencia en toda la interfaz de usuario y reduce la posibilidad de errores. El método ofrece flexibilidad para futuras mejoras y mantiene el código limpio y organizado.

//---- Button Names and Texts (7 analysis options) --------------------
string buttonNames[7] =
  {
   "btnShortTerm",
   "btnScalping",
   "btnSwing",
   "btnTrend",
   "btnMTFTrend",
   "btnShortScalper",
   "btnLongTerm"
  };

string buttonTexts[7] =
  {
   "Short Term Focus\n(M1, M5, M15)",
   "Scalping/Intraday\n(M5, M15, H1)",
   "Swing Trading\n(M15, H1, H4)",
   "Trend Trading\n(H1, H4, D1)",
   "MTF Trend Confirm\n(H1, H4, W1)",
   "Short Scalper/Mid Trend\n(M5, H1, D1)",
   "Long Term Trend\n(H1, D1, W1)"
  };

Las macros globales definen los nombres del encabezado del panel y la etiqueta de análisis. Estas macros garantizan la coherencia en todo el código y actúan como fuente única para estos identificadores. Al centralizar estos nombres, las actualizaciones de los componentes del panel se vuelven más fáciles y se reduce el riesgo de errores tipográficos. Este enfoque simplifica el mantenimiento y garantiza un código coherente y claro.

// Global object names for panel header and analysis label
#define PANEL_BG "PanelBG"
#define PANEL_HEADER "PanelHeader"
#define ANALYSIS_LABEL "AnalysisResult"

A continuación, el código declara dos funciones auxiliares: GetSMA calcula la media móvil simple y AnalyzeTimeframes realiza un análisis de mercado en múltiples marcos temporales. Estas funciones constituyen la lógica central del análisis de mercado.

//--- Helper function declarations
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift);
string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3);

La clase personalizada CTrendLoomPanel hereda de CAppDialog. Agrupa todos los elementos de la interfaz de usuario, como la etiqueta del encabezado, el panel principal, los botones y la etiqueta de resultados. Este diseño crea una interfaz modular que es más fácil de gestionar y ampliar.

Creación del panel

El método CreateTrendPanel crea primero una ventana de diálogo. A continuación, configura una etiqueta de encabezado con texto, color, tamaño y estilo de fuente personalizados. La alineación se establece mediante la función ObjectSetInteger.

bool CreateTrendPanel(const long chart, const string name, const int x1, const int y1, const int x2, const int y2)
{
   if(!CAppDialog::Create(chart, name, 0, x1, y1, x2, y2))
   {
      Print("Failed to create TrendLoom dialog.");
      return false;
   }
   if(!m_lblHeader.Create(0, "TrendLoomHeader", 0, 10, 10, x2 - x1 - 20, 30))
   {
      Print("Failed to create header label.");
      return false;
   }
   m_lblHeader.Text("TrendLoom EA");
   m_lblHeader.Color(PanelHeaderColor);
   m_lblHeader.FontSize(14);
   m_lblHeader.Font("Segoe UI");
   Add(m_lblHeader);
   if(!ObjectSetInteger(0L, m_lblHeader.Name(), OBJPROP_ALIGN, (long)ALIGN_CENTER))
      Print("Failed to set header alignment");

El método continúa creando el panel principal y calcula dinámicamente sus dimensiones. A continuación, crea cada botón y los coloca uno tras otro. Por último, se añade una etiqueta de resultados debajo de los botones para mostrar el resultado del análisis.

Gestión de eventos

El método OnEvent procesa las interacciones del usuario. Cuando se hace clic en un botón, se llama a AnalyzeTimeframes con los parámetros de marco temporal adecuados. El resultado del análisis se actualiza en el panel y se muestra una alerta.

bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(sparam == "btnShortTerm")
   {
      string res = AnalyzeTimeframes(PERIOD_M1, PERIOD_M5, PERIOD_M15);
      string out = "Short Term Focus: " + res;
      UpdateResults(out);
      Alert(out);
      return true;
   }
   else if(sparam == "btnScalping")
   {
      string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_M15, PERIOD_H1);
      string out = "Scalping/Intraday: " + res;
      UpdateResults(out);
      Alert(out);
      return true;
   }
   // Additional conditions for other buttons
   return false;
}

Actualización de la interfaz de usuario

El método UpdateResults actualiza la etiqueta de resultados con nuevos datos de análisis. A continuación, llama a ChartRedraw para que la información actualizada aparezca inmediatamente.

void UpdateResults(const string &result)
{
   m_lblResults.Text("Analysis Result: " + result);
   ChartRedraw();
}

Funciones básicas de análisis

Cálculo de la media móvil simple (SMA)

La función GetSMA calcula la SMA creando un identificador de indicador con la función iMA. Copia los valores SMA del búfer del indicador y, a continuación, libera el identificador para liberar recursos.
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift)
{
   int handle = iMA(symbol, timeframe, period, 0, MODE_SMA, PRICE_CLOSE);
   if(handle == INVALID_HANDLE)
   {
      Print("Failed to create iMA handle for timeframe ", timeframe);
      return 0.0;
   }
   double sma[];
   if(CopyBuffer(handle, 0, shift, 1, sma) <= 0)
   {
      Print("Failed to copy buffer for timeframe ", timeframe);
      IndicatorRelease(handle);
      return 0.0;
   }
   double result = sma[0];
   IndicatorRelease(handle);
   return result;
}

Análisis de múltiples marcos temporales

La función AnalyzeTimeframes recupera el precio de cierre y la SMA para tres marcos temporales y asigna una señal alcista cuando el precio supera la SMA o una señal bajista cuando cae por debajo. Suma las señales individuales para generar una recomendación final: COMPRAR cuando la suma es 2 o superior, VENDER cuando es -2 o inferior y NEUTRAL en los demás casos. Cada intervalo de tiempo se evalúa de forma independiente para obtener una visión equilibrada de las tendencias del mercado, mientras que el parámetro de cambio garantiza que solo se utilice la última vela completada para el análisis. La combinación de señales de múltiples marcos temporales reduce el impacto del ruido transitorio del mercado y el ajuste del período SMA refina aún más la sensibilidad de las señales de trading.

string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3)
{
   int period = 50;
   int shift  = 1; // last completed candle

   double price1 = iClose(_Symbol, tf1, shift);
   double sma1   = GetSMA(_Symbol, tf1, period, shift);
   int signal1   = (price1 > sma1) ? 1 : (price1 < sma1 ? -1 : 0);

   double price2 = iClose(_Symbol, tf2, shift);
   double sma2   = GetSMA(_Symbol, tf2, period, shift);
   int signal2   = (price2 > sma2) ? 1 : (price2 < sma2 ? -1 : 0);

   double price3 = iClose(_Symbol, tf3, shift);
   double sma3   = GetSMA(_Symbol, tf3, period, shift);
   int signal3   = (price3 > sma3) ? 1 : (price3 < sma3 ? -1 : 0);

   int sum = signal1 + signal2 + signal3;
   if(sum >= 2)
      return "BUY";
   else if(sum <= -2)
      return "SELL";
   else
      return "NEUTRAL";
}
Las funciones del ciclo de vida de EA se encargan de la inicialización, la limpieza y el procesamiento de eventos. La función OnInit crea el panel utilizando los parámetros de entrada. Si falla la creación del panel, el EA devuelve un error de inicialización.
int OnInit()
{
   if(!TrendPanel.CreateTrendPanel(0, "TrendLoom Panel", PanelX, PanelY, PanelX + PanelWidth + 20, PanelY + 400))
   {
      Print("Failed to create TrendLoom Panel.");
      return INIT_FAILED;
   }
   return INIT_SUCCEEDED;
}

La función OnDeinit limpia destruyendo el panel cuando se elimina el EA o se cierra el gráfico.

void OnDeinit(const int reason)
{
   TrendPanel.Destroy(reason);
}

Por último, la función OnChartEvent reenvía los eventos del gráfico al controlador de eventos del panel para que la interfaz siga respondiendo.

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   TrendPanel.ChartEvent(id, lparam, dparam, sparam);
}

En MetaEditor, los archivos necesarios se almacenan en la carpeta «Include». Para acceder a los archivos especificados tal y como se muestra en el fragmento, consulte las subcarpetas tal y como se muestra en los diagramas siguientes. Esta organización garantiza que el compilador encuentre los archivos de control de cuadros de diálogo, botones, etiquetas y paneles en la carpeta Include/Controls, y los controles de objetos de gráficos en la carpeta Include/ChartObjects.

#include <Controls/Dialog.mqh>
#include <Controls/Button.mqh>
#include <Controls/Label.mqh>
#include <Controls/Panel.mqh>
#include <ChartObjects/ChartObjectsTxtControls.mqh>  // Adjusted include path (singular folder)

Paso 1

Figura 2. Paso 1

Paso 2

Figura 3. Paso 2


Código MQL5

//+------------------------------------------------------------------+
//|                                                 TrendLoom EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"
#property strict

#include <Controls/Dialog.mqh>
#include <Controls/Button.mqh>
#include <Controls/Label.mqh>
#include <Controls/Panel.mqh>
#include <ChartObjects/ChartObjectsTxtControls.mqh>  // Adjusted include path (singular folder)

// Define alignment constants if not already defined
#ifndef ALIGN_LEFT
#define ALIGN_LEFT   0
#endif
#ifndef ALIGN_CENTER
#define ALIGN_CENTER 1
#endif
#ifndef ALIGN_RIGHT
#define ALIGN_RIGHT  2
#endif

#define clrSilver 0xC0C0C0

//---- Input parameters -----------------------------------------------
input int    PanelX               = 10;       // Top-left X coordinate of panel
input int    PanelY               = 10;       // Top-left Y coordinate of panel
input int    PanelWidth           = 250;      // Panel width (for longer text)
input int    btnWidth             = 220;      // Button width
input int    btnHeight            = 30;       // Button height
input int    btnSpacing           = 5;        // Spacing between buttons

input color  PanelBackgroundColor = clrDimGray;     // Panel background color
input color  PanelHeaderColor     = clrBlueViolet;  // Panel header text color

input color  ButtonBgColor        = clrBlack;       // Button background color
input color  ButtonTextColor      = clrBlueViolet;  // Button text color

input color  AnalysisTextColor    = clrLime;        // Analysis result text color

//---- Button Names and Texts (7 analysis options) --------------------
string buttonNames[7] =
  {
   "btnShortTerm",
   "btnScalping",
   "btnSwing",
   "btnTrend",
   "btnMTFTrend",
   "btnShortScalper",
   "btnLongTerm"
  };

string buttonTexts[7] =
  {
   "Short Term Focus\n(M1, M5, M15)",
   "Scalping/Intraday\n(M5, M15, H1)",
   "Swing Trading\n(M15, H1, H4)",
   "Trend Trading\n(H1, H4, D1)",
   "MTF Trend Confirm\n(H1, H4, W1)",
   "Short Scalper/Mid Trend\n(M5, H1, D1)",
   "Long Term Trend\n(H1, D1, W1)"
  };

// Global object names for panel header and analysis label
#define PANEL_BG "PanelBG"
#define PANEL_HEADER "PanelHeader"
#define ANALYSIS_LABEL "AnalysisResult"

//--- Helper function declarations
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift);
string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3);

//------------------------------------------------------------------------------
// CTrendLoomPanel class - A modern, modular panel for TrendLoom EA
//------------------------------------------------------------------------------
class CTrendLoomPanel : public CAppDialog
  {
private:
   CLabel            m_lblHeader;
   CPanel            m_panelMain;
   CButton           m_btnShortTerm;
   CButton           m_btnScalping;
   CButton           m_btnSwing;
   CButton           m_btnTrend;
   CButton           m_btnMTFTrend;
   CButton           m_btnShortScalper;
   CButton           m_btnLongTerm;
   CLabel            m_lblResults;

public:
   // Create the TrendLoom Panel dialog
   bool              CreateTrendPanel(const long chart, const string name, const int x1, const int y1, const int x2, const int y2)
     {
      if(!CAppDialog::Create(chart, name, 0, x1, y1, x2, y2))
        {
         Print("Failed to create TrendLoom dialog.");
         return false;
        }
      // Create header label
      if(!m_lblHeader.Create(0, "TrendLoomHeader", 0, 10, 10, x2 - x1 - 20, 30))
        {
         Print("Failed to create header label.");
         return false;
        }
      m_lblHeader.Text("TrendLoom EA");
      m_lblHeader.Color(PanelHeaderColor);
      m_lblHeader.FontSize(14);
      m_lblHeader.Font("Segoe UI");
      Add(m_lblHeader);
      // Set header text alignment to center using ObjectSetInteger
      if(!ObjectSetInteger(0L, m_lblHeader.Name(), OBJPROP_ALIGN, (long)ALIGN_CENTER))
         Print("Failed to set header alignment");

      // Create main panel background
      int panelBottom = 50 + (btnHeight + btnSpacing) * 7 + btnSpacing;
      if(!m_panelMain.Create(0, "TrendLoomPanel", 0, 10, 50, x2 - x1 - 10, panelBottom))
        {
         Print("Failed to create main panel.");
         return false;
        }
      m_panelMain.Color(PanelBackgroundColor);
      m_panelMain.BorderType(BORDER_RAISED);
      m_panelMain.ColorBorder(clrSilver);
      Add(m_panelMain);

      // Starting coordinates for buttons
      int btnX = 20; // relative to dialog
      int btnY = 60;
      int buttonWidth = btnWidth;
      int buttonHeight = btnHeight;

      // Create each button with a modern look
      if(!m_btnShortTerm.Create(0, buttonNames[0], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnShortTerm.Text(buttonTexts[0]);
      m_btnShortTerm.Font("Segoe UI");
      m_btnShortTerm.FontSize(12);
      m_btnShortTerm.Color(ButtonBgColor);
      Add(m_btnShortTerm);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnScalping.Create(0, buttonNames[1], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnScalping.Text(buttonTexts[1]);
      m_btnScalping.Font("Segoe UI");
      m_btnScalping.FontSize(12);
      m_btnScalping.Color(ButtonBgColor);
      Add(m_btnScalping);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnSwing.Create(0, buttonNames[2], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnSwing.Text(buttonTexts[2]);
      m_btnSwing.Font("Segoe UI");
      m_btnSwing.FontSize(12);
      m_btnSwing.Color(ButtonBgColor);
      Add(m_btnSwing);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnTrend.Create(0, buttonNames[3], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnTrend.Text(buttonTexts[3]);
      m_btnTrend.Font("Segoe UI");
      m_btnTrend.FontSize(12);
      m_btnTrend.Color(ButtonBgColor);
      Add(m_btnTrend);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnMTFTrend.Create(0, buttonNames[4], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnMTFTrend.Text(buttonTexts[4]);
      m_btnMTFTrend.Font("Segoe UI");
      m_btnMTFTrend.FontSize(12);
      m_btnMTFTrend.Color(ButtonBgColor);
      Add(m_btnMTFTrend);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnShortScalper.Create(0, buttonNames[5], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnShortScalper.Text(buttonTexts[5]);
      m_btnShortScalper.Font("Segoe UI");
      m_btnShortScalper.FontSize(12);
      m_btnShortScalper.Color(ButtonBgColor);
      Add(m_btnShortScalper);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnLongTerm.Create(0, buttonNames[6], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnLongTerm.Text(buttonTexts[6]);
      m_btnLongTerm.Font("Segoe UI");
      m_btnLongTerm.FontSize(12);
      m_btnLongTerm.Color(ButtonBgColor);
      Add(m_btnLongTerm);
      btnY += buttonHeight + btnSpacing;

      // Create results label below the buttons
      if(!m_lblResults.Create(0, "TrendResults", 0, btnX, btnY, btnX + buttonWidth, btnY + 30))
         return false;
      m_lblResults.Text("Analysis Result: [Waiting for Input]");
      m_lblResults.Font("Segoe UI");
      m_lblResults.FontSize(12);
      m_lblResults.Color(AnalysisTextColor);
      Add(m_lblResults);
      // Set results text alignment to left using ObjectSetInteger
      if(!ObjectSetInteger(0L, m_lblResults.Name(), OBJPROP_ALIGN, (long)ALIGN_LEFT))
         Print("Failed to set results alignment");

      Show();
      return true;
     }

   // Process events (button clicks)
   bool              OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
     {
      if(sparam == "btnShortTerm")
        {
         string res = AnalyzeTimeframes(PERIOD_M1, PERIOD_M5, PERIOD_M15);
         string out = "Short Term Focus: " + res;
         UpdateResults(out);
         Alert(out);
         return true;
        }
      else
         if(sparam == "btnScalping")
           {
            string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_M15, PERIOD_H1);
            string out = "Scalping/Intraday: " + res;
            UpdateResults(out);
            Alert(out);
            return true;
           }
         else
            if(sparam == "btnSwing")
              {
               string res = AnalyzeTimeframes(PERIOD_M15, PERIOD_H1, PERIOD_H4);
               string out = "Swing Trading: " + res;
               UpdateResults(out);
               Alert(out);
               return true;
              }
            else
               if(sparam == "btnTrend")
                 {
                  string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_H4, PERIOD_D1);
                  string out = "Trend Trading: " + res;
                  UpdateResults(out);
                  Alert(out);
                  return true;
                 }
               else
                  if(sparam == "btnMTFTrend")
                    {
                     string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_H4, PERIOD_W1);
                     string out = "MTF Trend Confirm: " + res;
                     UpdateResults(out);
                     Alert(out);
                     return true;
                    }
                  else
                     if(sparam == "btnShortScalper")
                       {
                        string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_H1, PERIOD_D1);
                        string out = "Short Scalper/Mid Trend: " + res;
                        UpdateResults(out);
                        Alert(out);
                        return true;
                       }
                     else
                        if(sparam == "btnLongTerm")
                          {
                           string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_D1, PERIOD_W1);
                           string out = "Long Term Trend: " + res;
                           UpdateResults(out);
                           Alert(out);
                           return true;
                          }
      return false;
     }

   bool              ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
     {
      return OnEvent(id, lparam, dparam, sparam);
     }

   // Update the results label and refresh the chart
   void              UpdateResults(const string &result)
     {
      m_lblResults.Text("Analysis Result: " + result);
      ChartRedraw();
     }
  };

// Global instance of the TrendLoom Panel
CTrendLoomPanel TrendPanel;

//------------------------------------------------------------------------------
// Helper functions (core analysis logic)
//------------------------------------------------------------------------------
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift)
  {
   int handle = iMA(symbol, timeframe, period, 0, MODE_SMA, PRICE_CLOSE);
   if(handle == INVALID_HANDLE)
     {
      Print("Failed to create iMA handle for timeframe ", timeframe);
      return 0.0;
     }
   double sma[];  // dynamic array to store SMA values
   if(CopyBuffer(handle, 0, shift, 1, sma) <= 0)
     {
      Print("Failed to copy buffer for timeframe ", timeframe);
      IndicatorRelease(handle);
      return 0.0;
     }
   double result = sma[0];
   IndicatorRelease(handle);
   return result;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3)
  {
   int period = 50;
   int shift  = 1; // last completed candle

   double price1 = iClose(_Symbol, tf1, shift);
   double sma1   = GetSMA(_Symbol, tf1, period, shift);
   int signal1   = (price1 > sma1) ? 1 : (price1 < sma1 ? -1 : 0);

   double price2 = iClose(_Symbol, tf2, shift);
   double sma2   = GetSMA(_Symbol, tf2, period, shift);
   int signal2   = (price2 > sma2) ? 1 : (price2 < sma2 ? -1 : 0);

   double price3 = iClose(_Symbol, tf3, shift);
   double sma3   = GetSMA(_Symbol, tf3, period, shift);
   int signal3   = (price3 > sma3) ? 1 : (price3 < sma3 ? -1 : 0);

   int sum = signal1 + signal2 + signal3;
   if(sum >= 2)
      return "BUY";
   else
      if(sum <= -2)
         return "SELL";
      else
         return "NEUTRAL";
  }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(!TrendPanel.CreateTrendPanel(0, "TrendLoom Panel", PanelX, PanelY, PanelX + PanelWidth + 20, PanelY + 400))
     {
      Print("Failed to create TrendLoom Panel.");
      return INIT_FAILED;
     }
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   TrendPanel.Destroy(reason);
  }

//+------------------------------------------------------------------+
//| Chart Event Handler                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   TrendPanel.ChartEvent(id, lparam, dparam, sparam);
  }
//+------------------------------------------------------------------+


Resultados

Es de vital importancia que todos los operadores prueben exhaustivamente sus sistemas antes de utilizarlos en operaciones reales. Las pruebas implican realizar pruebas retrospectivas con datos históricos para ver cómo habría funcionado el sistema sin arriesgar ningún capital. También puede utilizar cuentas demo en vivo para observar el rendimiento real en tiempo real. Este proceso le ayuda a perfeccionar y desarrollar una herramienta más fiable que podrá utilizar con confianza en una cuenta real. Personalmente, prefiero dedicar mucho tiempo a probar y perfeccionar el EA para obtener resultados más sólidos.

En esta sección, presento los resultados de las pruebas del EA ejecutado en el gráfico. Lo probé con una volatilidad de 75 (1s) y obtuvo resultados maravillosos y rentables. Todos los botones funcionan correctamente y los análisis se actualizan casi al instante cuando pulsas un botón. Repasemos la primera prueba a continuación.

Figura 4. Prueba de volatilidad 75 (1s)

A continuación se muestra un diagrama que ilustra cómo se comportó el mercado tras ejecutar una operación basada en la señal proporcionada. Este diagrama continúa la operación mostrada en el GIF anterior. Utilicé el marco temporal M1 para ofrecer una visión más amplia de las operaciones.

Figura 5. Prueba de volatilidad 75 (1s)


Conclusión

Tras haber creado y probado el EA, puedo confirmar con total seguridad que tiene un impacto positivo en el análisis del mercado. Su rápido procesamiento de señales y su evaluación general de tendencias han producido resultados muy potentes en los índices de volatilidad. Sin embargo, esta herramienta sirve como ayuda complementaria y no como proveedor definitivo de señales. Te recomiendo que lo pruebes a fondo y ajustes los parámetros según tus preferencias. También puedes modificarlo aún más para personalizar la apariencia de los botones. Úsalo para confirmar tu estrategia general, he visto que es eficaz en ese sentido.

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 Herramienta número 1
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 Herramienta número 2
27/11/24 Analytics Master Actualización periódica de las métricas del mercado cada dos horas.  1.01 Segundo lanzamiento Herramienta número 3
02/12/24 Analytics Forecaster  Actualización periódica de las métricas del mercado cada dos horas con integración de Telegram. 1.1 Tercera edición Herramienta número 4
09/12/24 Volatility Navigator EA que 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 Mean 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 inicial Herramienta número 8 
21/01/25 External Flow Análisis mediante librerías externas. 1.0  Lanzamiento inicial Herramienta número 9 
27/01/25 VWAP Volume Weighted Average Price (Precio medio ponderado por volumen).   1.3  Lanzamiento inicial  Herramienta número 10 
02/02/25  Heikin Ashi  Suavización de tendencias e identificación de señales de reversión.  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.0 Lanzamiento inicial  Herramienta número 14
20/02/25  Quarters Drawer Script  Dibuja los niveles de los cuartos en el gráfico.  1.0  Lanzamiento inicial  Herramienta número 15 
27/02/25  Intrusion Detector Detectar y alertar cuando el precio alcanza niveles de cuartos. 1.0   Lanzamiento inicial Herramienta número 16 
27/02/25  TrendLoom Tool  Panel de análisis de múltiples marcos temporales. 1.0 Lanzamiento inicial Herramienta número 17

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

Archivos adjuntos |
TrendLoom_EA.mq5 (26.63 KB)
linfo2
linfo2 | 21 mar 2025 en 03:01
Wow Fantástico, puedo ver que hay una gran cantidad de esfuerzo puesto en esto, gracias por compartir su enfoque y el código
Christian Benjamin
Christian Benjamin | 21 mar 2025 en 11:21
linfo2 #:
Wow Fantástico, puedo ver que hay un montón de esfuerzo puesto en esto, gracias por compartir su enfoque y el código.
No hay de qué. Gracias a ti también por llegar a cabo👏.
gardee005
gardee005 | 25 mar 2025 en 16:49
me gusta mucho tu trabajo, te he estado siguiendo. buen abanico de ideas, con aplicación. ¡gracias!
Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
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
En nuestro artículo anterior presentamos un script sencillo llamado «The Quarters Drawer». Partiendo de esa base, ahora damos el siguiente paso creando un Asesor Experto (Expert Advisor, EA) de monitoreo, destinado a seguir estos cuartos y a proporcionar supervisión sobre posibles reacciones del mercado en dichos niveles. Acompáñenos mientras exploramos el proceso de desarrollo de una herramienta de detección de zonas en este artículo.
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.
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.