Desarrollamos un asesor experto para controlar los puntos de entrada en las operaciones swing
Contenido:
- Introducción
- Breve historia de BTCUSD de 2021 a 2024
- Desarrollamos un asesor experto para controlar los puntos de entrada en las operaciones swing
- Paso 1: Presentación de la estrategia EMA 100
- Segundo paso: Indicador de seguimiento
- Tercer paso: Desarrollo del asesor
- Pruebas y optimización
- Resultados y análisis
- Conclusión
Introducción
El BTCUSD es uno de los pares más llamativos con importantes perspectivas a largo plazo. Hoy lo hemos elegido como caso de estudio en el que basar nuestro proceso de desarrollo.
El precio del bitcoin se caracteriza por una gran volatilidad impulsada por el sentimiento del mercado, los factores macroeconómicos y el desarrollo de mecanismos reguladores. Identificar niveles de entrada rentables entre dichas fluctuaciones es una tarea nada trivial, especialmente para los tráders que se basan únicamente en el análisis manual. Por ejemplo, en los últimos dos años, el precio del BTC ha tocado un rango que va desde mínimos en torno a los 16.000 dólares hasta un máximo histórico de 99.645,39 dólares en noviembre de 2024. Durante este periodo, surgieron varias oportunidades de entrada importantes en la EMA 100, una estrategia que ofrece información valiosa para las estrategias comerciales a largo plazo.
La solución al reto anteriormente definido es desarrollar un asesor experto MQL5 para controlar las señales de entrada en transacciones a largo plazo. Este asesor experto:
- Supervisará continuamente los movimientos de precios del par especificado.
- Utilizará la EMA 100 como nivel dinámico de apoyo o resistencia, identificando así posibles oportunidades de entrada.
- Alertará a los tráders cuando se cumplan determinadas condiciones, como que el precio rebote en la EMA 100.
Esta herramienta automatizará el análisis para que los tráders puedan concentrarse en la toma de decisiones en lugar de en la supervisión constante.
La siguiente imagen muestra los niveles de apoyo clave para BTC según la EMA de 100 días.

BTCUSD, H4: Tipo de cambio del Bitcoin respecto al dólar estadounidense: Rebote del precio desde la EMA 100
Breve historia de BTCUSD de 2021 a 2024
Entre 2021 y 2024, el bitcoin experimentó cambios sustanciales en su precio. Tras una fuerte caída en 2022, cuando el bitcoin cerró por debajo de los 20.000 dólares debido al aumento de los tipos de interés y el descenso del mercado, el bitcoin repuntó de 16.530 dólares hasta alcanzar los 42.258 dólares en 2023. El bitcoin se disparó en 2024 tras la aprobación de los ETF de bitcoin al contado y la bajada de tipos de la Reserva Federal estadounidense, alcanzando un máximo de 99.645,39 dólares en noviembre.
Al momento de escribir estas líneas, el par cotiza en torno a los 97.300 dólares, lo que supone un aumento significativo del 146,5% respecto al precio de un año antes. Según CoinGecko, el máximo histórico, fijado a principios de diciembre de 2024, fue de 99.645,39 dólares.

Gráfico diario de BTCUSD para el periodo 2021-2024
Desarrollamos un asesor experto para controlar los puntos de entrada en las operaciones swing
Hemos dividido el proceso de desarrollo en tres pasos para optimizar el proceso de creación de un EA completo. El primer paso consistirá en familiarizarnos con la media móvil que utilizaremos como base para desarrollar nuestro propio indicador. Este indicador será una herramienta independiente y también servirá de base para crear el EA para el seguimiento en los próximos pasos.
Paso 1: Presentamos la estrategia EMA 100
La media móvil exponencial (EMA) es un indicador muy usado que da más peso a los datos recientes. En particular, la EMA 100 representa un nivel crítico para la negociación y con frecuencia actúa como un fuerte nivel de apoyo o resistencia. Históricamente, muchas oportunidades de entrada rentables en bitcoin han llegado en momentos en que el precio rebota en la EMA 100, especialmente durante periodos de alta volatilidad.
Segundo paso: Indicador de seguimiento
Dado que estamos usando la media móvil exponencial (EMA) integrada en el terminal MetaTrader 5, hemos decido desarrollar primero un indicador de seguimiento basado en esta herramienta incorporada. Este enfoque simplifica el proceso de identificación de las zonas clave de interés en los movimientos de precios. Según mi experiencia, el indicador puede enviar alertas a través de notificaciones del terminal, notificaciones push e incluso email.
Sin embargo, carece de la capacidad de gestionar las solicitudes web necesarias para los servicios de alerta avanzados, como la integración con las redes sociales más populares. Para lidiar con esta limitación, iremos al paso 3, donde implementaremos el indicador en el asesor experto. Esta conversión ofrece una funcionalidad más sólida, incluida una comunicación fluida a través de Telegram, lo cual aporta versatilidad y eficacia al sistema de seguimiento.
El proceso de elaboración de nuestro indicador para el seguimiento se divide en los siguientes componentes:
Propiedades y metadatos:
En esta sección se definen los metadatos más importantes del asesor experto, incluido el titular de los derechos de autor, un enlace al perfil del autor, el número de versión y una breve descripción de la finalidad del indicador. Esta información resulta fundamental para la documentación y permite a los usuarios comprender rápidamente la idea del autor y la funcionalidad prevista.
#property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "EMA 100 Monitoring Indicator"
En esta parte configuraremos la representación visual del indicador en el gráfico comercial. La directiva #property indicator_chart_window especifica que el asesor experto trabajará en la ventana principal del gráfico. Al definir dos búferes para los indicadores (indicator_buffers 2), preparamos la posibilidad de mostrar dos señales diferentes. Las propiedades indicator_type1 e indicator_type2 indican que ambos indicadores se mostrarán como flechas con colores distintos (naranja y azul) y etiquetas que dicen "Busque un rebote de la EMA 100". Esta configuración aumenta la transparencia para los tráders al ofrecer señales visuales instantáneas de posibles oportunidades comerciales basadas en la interacción del precio con la media móvil exponencial (EMA).
///Properties and Settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFFAA00 #property indicator_label1 "Look for EMA 100 bounce " #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Look for EMA 100 bounce "
Definición de búferes
Esta sección define los búferes para los indicadores que almacenan los valores de las señales generadas por el asesor experto. Buffer1 y Buffer2 se declaran como arrays de tipo double que almacenan los datos para dos tipos de señales relacionadas con los movimientos del precio y de la EMA. Las constantes PLOT_MAXIMUM_BARS_BACK y OMIT_OLDEST_BARS se establecen para controlar el procesamiento de los datos históricos y garantizar que el programa se ejecute de forma eficiente sin sobrecargar el sistema con datos obsoletos. Este enfoque ayuda a mantener la productividad al tiempo que ofrece al usuario información pertinente y oportuna.
#define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[];
Parámetros de entrada:
En esta parte, definiremos los parámetros de entrada que puede configurar el usuario que aumentan la flexibilidad del EA. La línea input int EMA_Period = 100; sirve para especificar el periodo de cálculo de la media móvil exponencial, lo cual permite adaptar el asesor experto a diferentes estrategias comerciales. Además, las banderas Audible_Alerts y Push_Notifications se activarán por defecto, lo que garantizará el envío en tiempo real de alertas y notificaciones sobre eventos importantes del mercado. También se declararán otras variables como Low, High y MA_handle, que almacenarán los datos de precios y se utilizarán para los cálculos de medias móviles, desempeñando así un papel crucial en las operaciones del EA.
input int EMA_Period = 100; datetime time_alert; //used when sending alert bool Audible_Alerts = true; bool Push_Notifications = true; double myPoint; //initialized in OnInit double Low[]; int MA_handle; double MA[]; double High[];
Función de alertas:
La función myAlert está diseñada para centralizar la gestión de alertas en el asesor experto. Recibe dos parámetros: el tipo que define la clase de alerta (por ejemplo, "print", "error", "indicator"), y un mensaje que contiene el texto de la alerta. Dependiendo del tipo, la función imprimirá un mensaje de depuración o enviará alertas relacionadas con los cambios en el mercado. Este enfoque mejorará la organización y legibilidad del código, simplificando el trabajo técnico. Proporcionando alertas sonoras y notificaciones push, esta función garantizará que los usuarios estén al tanto de los movimientos importantes del mercado, lo que resulta crucial para tomar decisiones comerciales a tiempo.
void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } else if(type == "indicator") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Audible_Alerts) Alert(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Push_Notifications) SendNotification(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } }
Función de inicialización:
La función OnInit actúa como punto de entrada cuando se carga el asesor experto. Esta inicializa los búferes para el indicador y establece los cálculos para la media móvil exponencial. El uso de SetIndexBuffer vincula búferes específicos a gráficos de indicadores, proporcionando así la capacidad de mostrar valores en el gráfico. La función también comprueba si el manejador de la media móvil (MA_handle) se ha creado correctamente, lo cual permitirá corregir errores y mejorar la fiabilidad. Si se produce algún problema durante la inicialización, se mostrarán mensajes de error explícitos para facilitar al usuario su solución. Este ajuste resulta fundamental para garantizar el correcto funcionamiento del EA inmediatamente después de su inicio.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 233); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 234); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, EMA_Period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); }
Función de cálculo:
La función OnCalculate es el corazón del asesor experto, y contiene la lógica de cálculo de los valores del indicador. La función procesa los datos del mercado, obtiene información sobre los precios y calcula una media móvil. La función comenzará determinando cuántas métricas totales hay que procesar, basándose en el número total de métricas y en el número de estas procesadas previamente. A continuación, la función inicializará los búferes y recuperará los datos necesarios, como el precio mínimo y máximo, antes de iniciar el ciclo principal. Este ciclo iterará los datos de precios, probando las condiciones para generar señales comerciales basadas en las interacciones del precio con las EMA. La eficacia de esta función resulta fundamental porque permite al EA reaccionar dinámicamente a los cambios del mercado en tiempo real.
int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; datetime Time[]; if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total); ArraySetAsSeries(Time, true);
Lógica básica:
En la función OnCalculate de la lógica principal se analizarán los movimientos de los precios en relación con la EMA. Esta comprobará determinadas condiciones, como cuándo el precio mínimo cruza la EMA hacia abajo, o cuándo el precio máximo cruza la EMA hacia arriba. Cuando se cumplan dichas condiciones, los búferes correspondientes (Buffer1 para rebotes por debajo de la EMA y Buffer2 para rebotes por encima) se llenarán con los precios mínimos o máximos actuales, y se crearán alertas para el usuario. Este mecanismo supone la base para proporcionar señales comerciales con capacidad de respuesta, lo que permite a los tráders tomar decisiones informadas basadas en el análisis técnico. Un planteamiento claro y estructurado de la definición de los valores de los indicadores garantizará que los usuarios reciban información oportuna y pertinente sobre las posibles oportunidades comerciales.
//--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation //Indicator Buffer 1 if(Low[i] < MA[i] && Low[i+1] > MA[i+1] //Candlestick Low crosses below Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(High[i] > MA[i] && High[i+1] < MA[i+1] //Candlestick High crosses above Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+
Aquí se presenta el código completo de los indicadores, sin errores:
#property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "EMA 100 Monitoring Indicator" //--- indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFFAA00 #property indicator_label1 "Look for EMA 100 bounce " #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Look for EMA 100 bounce " #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; input int EMA_Period = 100; datetime time_alert; //used when sending alert bool Audible_Alerts = true; bool Push_Notifications = true; double myPoint; //initialized in OnInit double Low[]; int MA_handle; double MA[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } else if(type == "indicator") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Audible_Alerts) Alert(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Push_Notifications) SendNotification(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } } //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 233); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 234); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, EMA_Period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; datetime Time[]; if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total); ArraySetAsSeries(Time, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation //Indicator Buffer 1 if(Low[i] < MA[i] && Low[i+1] > MA[i+1] //Candlestick Low crosses below Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(High[i] > MA[i] && High[i+1] < MA[i+1] //Candlestick High crosses above Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+
Paso 3: Desarrollo de asesores
En esta sección, aprenderá el proceso de desarrollo de un simple pero eficaz asesor experto para el seguimiento de los puntos de entrada de operaciones swing en MQL5. Este EA está diseñado para monitorizar los precios del mercado (con un enfoque particular sobre el bitcoin como ejemplo) y enviar alertas basadas en condiciones predeterminadas.
Para simplificar este proceso, omitiremos la información sobre los metadatos, pues los tratamos con detalle en la fase de desarrollo de los indicadores. Asimismo, desglosaremos el código paso a paso y nos aseguraremos de que cada parte sea fácil de entender e implementar.
1. Parámetros de entrada:
input string IndicatorName = "ema100_monitoring_indicator"; // Name of the custom indicator input bool EnableTerminalAlerts = true; input bool EnablePushNotifications = true; input bool EnableTelegramAlerts = false; input string TelegramBotToken = "YOUR_BOT_TOKEN"; // Replace with your bot token input string TelegramChatID = "YOUR_CHAT_ID"; // Replace with your chat ID
En esta parte definiremos varios parámetros de entrada personalizables que aumentarán la flexibilidad y usabilidad del asesor experto. El parámetro IndicatorName nos permitirá especificar el nombre del indicador personalizado que queremos monitorizar: el valor por defecto será "Bitcoin Monitor". Las banderas booleanas EnableTerminalAlerts, EnablePushNotifications y EnableTelegramAlerts nos permitirán personalizar las alertas. Por ejemplo, podremos elegir recibir notificaciones directamente en el terminal comercial, en nuestro dispositivo móvil o a través de Telegram. Además, para recibir alertas en Telegram deberemos proporcionar el token de nuestro bot de Telegram y nuestro ID de chat. Esta personalización permitirá a otros usuarios optimizar su experiencia comercial en función de sus preferencias y necesidades.
2. Manejadores de indicadores:
int indicatorHandle = INVALID_HANDLE; int emaHandle = INVALID_HANDLE;
Esta sección declarará las variables necesarias para controlar los indicadores utilizados en el asesor experto. Las variables indicatorHandle y emaHandle almacenarán las referencias al indicador personalizado y a la media móvil exponencial (EMA), respectivamente. Ambos manejadores se inicializarán como INVALID_HANDLE, lo que significa que aún no se les ha asignado un valor. Esta configuración resulta extremadamente importante para la funcionalidad del EA, ya que permite al programa interactuar con los indicadores especificados y recibir datos relevantes del mercado para su análisis.
3. Función de alertas:
void AlertMessage(string message) { if (EnableTerminalAlerts) Alert(message); if (EnablePushNotifications) SendNotification(message); if (EnableTelegramAlerts) SendTelegramMessage(message); }
La función AlertMessage juega un papel clave en la gestión de alertas en los asesores expertos. Esta función admite un parámetro string: el mensaje que contiene el texto de la alerta que se va a enviar. La función comprueba la configuración del usuario en cuanto al tipo de alertas (alertas de terminal, notificaciones push o mensajes a Telegram) y envía el mensaje de la forma correspondiente. Centralizando el control de las alertas en esta función, el código queda más organizado y es más fácil de manejar. Esta funcionalidad resulta especialmente importante para los tráders que dependen de las notificaciones instantáneas para tomar decisiones informadas basadas en los movimientos del mercado.
4. Alertas de Telegram:
void SendTelegramMessage(string message) { if (EnableTelegramAlerts) { string url = "https://api.telegram.org/bot" + TelegramBotToken + "/sendMessage?chat_id=" + TelegramChatID + "&text=" + message; int timeout = 5000; ResetLastError(); char postData[]; uchar result[]; string response; int res = WebRequest("GET", url, NULL, timeout, postData, result, response); if (res != 200) { Print("Telegram WebRequest failed. Error: ", GetLastError(), ", HTTP Code: ", res); } else { Print("Telegram message sent successfully: ", response); } } }
Para simplificar la comunicación con los usuarios, se implementa la función SendTelegramMessage. Esta función compone una URL que utiliza la API de Telegram para enviar mensajes a un chat específico. Primero comprueba que las alertas de Telegram estén activadas. Si es así, la función prepara y envía una solicitud GET al servidor de Telegram con la URL compuesta, así como el token del bot y el ID del chat. La función también gestiona los posibles errores de solicitud, ofreciendo al usuario información si el mensaje no se envía. Esta funcionalidad permitirá a los usuarios recibir alertas directamente en Telegram, haciéndolas más accesibles y cómodas.
5. Función de inicialización:
int OnInit() { Print("Bitcoin Monitoring EA started."); // Attach the custom indicator to the chart indicatorHandle = iCustom(_Symbol, _Period, IndicatorName); if (indicatorHandle == INVALID_HANDLE) { Print("Failed to attach indicator: ", IndicatorName, ". Error: ", GetLastError()); return(INIT_FAILED); } // Attach built-in EMA 100 to the chart emaHandle = iMA(_Symbol, _Period, 100, 0, MODE_EMA, PRICE_CLOSE); if (emaHandle == INVALID_HANDLE) { Print("Failed to create EMA 100. Error: ", GetLastError()); return(INIT_FAILED); } // Add EMA 100 to the terminal chart if (!ChartIndicatorAdd(0, 0, emaHandle)) { Print("Failed to add EMA 100 to the chart. Error: ", GetLastError()); } return(INIT_SUCCEEDED); }
La función OnInit se ejecuta en el primer inicio del asesor experto. Se encarga de configurar los indicadores necesarios y asegurarse de que el EA está listo para trabajar. Dentro de esta función, se adjuntará un indicador personalizado al gráfico a través de su nombre, y se comprobará el manejador para confirmar que se ha adjuntado correctamente. Si el archivo adjunto falla, se mostrará un mensaje de error para ayudar a diagnosticar el problema. Además, la función creará una EMA con un periodo de 100 y comprobará si tiene éxito antes de añadirla al gráfico. Una correcta inicialización resulta extremadamente importante para la funcionalidad del EA, ya que garantizará que todos los componentes estén correctamente configurados y listos para procesar los datos del mercado.
6. Función de desinicialización:
void OnDeinit(const int reason) { Print(" EA stopped."); if (indicatorHandle != INVALID_HANDLE) { IndicatorRelease(indicatorHandle); } if (emaHandle != INVALID_HANDLE) { IndicatorRelease(emaHandle); } }
La función OnDeinit se llamará cuando el asesor experto se retire del gráfico o cuando se cierre el terminal. Su principal objetivo es liberar recursos y evitar fugas de memoria. Esta función comprobará si los manejadores del indicador son válidos y, en caso afirmativo, los liberará para liberar recursos del sistema. La función también muestra un mensaje que indicará que el EA se ha detenido, ofreciendo así a los usuarios información explícita sobre el estado del EA. Una desinicialización correcta resulta fundamental para mantener un rendimiento y un orden óptimos en el entorno comercial.
7. Lógica básica:
void OnTick() { static datetime lastAlertTime = 0; // Prevent repeated alerts for the same signal if (indicatorHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE) return; double buffer1[], buffer2[]; ArraySetAsSeries(buffer1, true); ArraySetAsSeries(buffer2, true); // Read data from the custom indicator if (CopyBuffer(indicatorHandle, 0, 0, 1, buffer1) < 0) { Print("Failed to copy Buffer1. Error: ", GetLastError()); return; } if (CopyBuffer(indicatorHandle, 1, 0, 1, buffer2) < 0) { Print("Failed to copy Buffer2. Error: ", GetLastError()); return; } // Check for signals in Buffer1 if (buffer1[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (Low). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Check for signals in Buffer2 if (buffer2[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (High). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Debugging EMA 100 value double emaValueArray[]; ArraySetAsSeries(emaValueArray, true); // Ensure it's set as series if (CopyBuffer(emaHandle, 0, 0, 1, emaValueArray) > 0) { Print("EMA 100 Current Value: ", emaValueArray[0]); } else { Print("Failed to read EMA 100 buffer. Error: ", GetLastError()); } }
La función OnTick contiene la lógica básica del EA y se ejecuta cada vez que el mercado recibe un nuevo tick de datos. Esta función comprobará la validez de los indicadores antes de calcularlos. Asimismo, inicializará los arrays para almacenar los datos del indicador personalizado y recuperará los últimos valores de los búferes del indicador. Si se detecta una señal en alguno de los búferes, la función creará una alerta a través de la función AlertMessage, notificando a los usuarios las posibles oportunidades comerciales. Además, la función obtendrá el valor actual de la EMA con fines de depuración, lo que posibilitará una mayor transparencia en el funcionamiento del EA. Este análisis en tiempo real permitirá al asesor experto reaccionar rápidamente a los cambios del mercado, lo cual lo convierte en una valiosa herramienta para los tráders.
Así que aquí tenemos el código completo de nuestro EA:
//+------------------------------------------------------------------+ //| Bitcoin Monitoring Expert Advisor | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "BTCUSD Monitoring Expert Advisor" //--- Input parameters input string IndicatorName = "ema100_monitoring_indicator"; // Name of the custom indicator input bool EnableTerminalAlerts = true; input bool EnablePushNotifications = true; input bool EnableTelegramAlerts = false; input string TelegramBotToken = "YOUR_BOT_TOKEN"; // Replace with your bot token input string TelegramChatID = "YOUR_CHAT_ID"; // Replace with your chat ID //--- Indicator handles int indicatorHandle = INVALID_HANDLE; int emaHandle = INVALID_HANDLE; //--- Alert function void AlertMessage(string message) { if (EnableTerminalAlerts) Alert(message); if (EnablePushNotifications) SendNotification(message); if (EnableTelegramAlerts) SendTelegramMessage(message); } //--- Telegram Alerting void SendTelegramMessage(string message) { if (EnableTelegramAlerts) { string url = "https://api.telegram.org/bot" + TelegramBotToken + "/sendMessage?chat_id=" + TelegramChatID + "&text=" + message; int timeout = 5000; ResetLastError(); char postData[]; uchar result[]; string response; int res = WebRequest("GET", url, NULL, timeout, postData, result, response); if (res != 200) { Print("Telegram WebRequest failed. Error: ", GetLastError(), ", HTTP Code: ", res); } else { Print("Telegram message sent successfully: ", response); } } } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("Bitcoin Monitoring EA started."); // Attach the custom indicator to the chart indicatorHandle = iCustom(_Symbol, _Period, IndicatorName); if (indicatorHandle == INVALID_HANDLE) { Print("Failed to attach indicator: ", IndicatorName, ". Error: ", GetLastError()); return(INIT_FAILED); } // Attach built-in EMA 100 to the chart emaHandle = iMA(_Symbol, _Period, 100, 0, MODE_EMA, PRICE_CLOSE); if (emaHandle == INVALID_HANDLE) { Print("Failed to create EMA 100. Error: ", GetLastError()); return(INIT_FAILED); } // Add EMA 100 to the terminal chart if (!ChartIndicatorAdd(0, 0, emaHandle)) { Print("Failed to add EMA 100 to the chart. Error: ", GetLastError()); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("Bitcoin Monitoring EA stopped."); if (indicatorHandle != INVALID_HANDLE) { IndicatorRelease(indicatorHandle); } if (emaHandle != INVALID_HANDLE) { IndicatorRelease(emaHandle); } } void OnTick() { static datetime lastAlertTime = 0; // Prevent repeated alerts for the same signal if (indicatorHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE) return; double buffer1[], buffer2[]; ArraySetAsSeries(buffer1, true); ArraySetAsSeries(buffer2, true); // Read data from the custom indicator if (CopyBuffer(indicatorHandle, 0, 0, 1, buffer1) < 0) { Print("Failed to copy Buffer1. Error: ", GetLastError()); return; } if (CopyBuffer(indicatorHandle, 1, 0, 1, buffer2) < 0) { Print("Failed to copy Buffer2. Error: ", GetLastError()); return; } // Check for signals in Buffer1 if (buffer1[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (Low). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Check for signals in Buffer2 if (buffer2[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (High). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Debugging EMA 100 value double emaValueArray[]; ArraySetAsSeries(emaValueArray, true); // Ensure it's set as series if (CopyBuffer(emaHandle, 0, 0, 1, emaValueArray) > 0) { Print("EMA 100 Current Value: ", emaValueArray[0]); } else { Print("Failed to read EMA 100 buffer. Error: ", GetLastError()); } }
Pruebas y optimización
Después de compilar con éxito el código, empezaremos a probarlo utilizando el simulador de estrategias en el terminal MetaTrader 5. Las siguientes imágenes muestran el proceso y los resultados de las pruebas.

Asesor para la monitorización del Bitcoin: ejecución en el simulador de estrategias
Durante el inicio en el simulador de estrategias, hemos demostrado con éxito las capacidades para el seguimiento de precios en tiempo real del asesor experto. A continuación le mostramos una ilustración que demuestra el proceso del asesor experto y su eficacia.

Seguimiento por ticks de las variaciones de precio del bitcoin: 2022
Resultados y análisis
Ya hemos demostrado con éxito el funcionamiento del indicador observando su interacción con la EMA 100 en marcos temporales grandes, en particular en H4 y D1. El sistema ha demostrado la capacidad de enviar alertas de tres formas distintas, entre ellas en forma de notificación de Telegram. El precio ha estado rebotando constantemente desde la EMA seleccionada, como se ve en nuestras ilustraciones. La siguiente imagen muestra el inicio del asesor experto y el indicador en el terminal MetaTrader 5, demostrando su integración y funcionalidad.

Adición de un asesor experto y un indicador al gráfico
Conclusión
El asesor de seguimiento que hemos desarrollado en este artículo será una herramienta valiosa para todos los tráders. Automatizando el seguimiento de los precios e integrando estrategias como la EMA 100, minimizamos el trabajo manual necesario para identificar oportunidades comerciales. Aunque hemos desarrollado el asesor experto para BTCUSD, puede ser adaptado para otros instrumentos, además de personalizado para indicadores adicionales. Este proyecto sirve de marco sencillo y motivador para los principiantes. La perfección no tiene límites: pruebe distintos enfoques.
Descargue el asesor experto y el indicador adjuntos, pruébelos con datos históricos con su configuración preferida y mejórelos para adaptarlos a su estrategia comercial. Esté a la vanguardia del dinámico mundo del trading combinando el análisis técnico con la automatización. Tenga en cuenta que este sistema está pensado únicamente para la monitorización y las alertas, no incluye ninguna funcionalidad comercial en esta fase. Nuestros contactos de Telegram están aquí: enlace 1 y enlace 2.
Tabla con archivos adjuntos:
| Archivos | Descripción |
|---|---|
| ema100_monitoring_indicator.mq5 | Indicador personalizado basado en la estrategia de rebote EMA 100 |
| bitcoin_monitoring_expert.mq5 | Asesor experto que implementa la funcionalidad de alertas en Telegram vía WebRequest y realiza un seguimiento continuo. |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16563
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 5): Volatility Navigator EA
Indicador de previsión de volatilidad con Python
Métodos de ensamble para mejorar predicciones numéricas en MQL5
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso