
Creación de un modelo de restricción de tendencia de velas (Parte 5): Sistema de notificaciones (Parte II)
Contenido
- Introducción
- Integración de Telegram en Trend Constraint
- Entendiendo la API del bot de Telegram
- Instalación de módulos Python de Telegram en Windows
- Comprender el script de Python send_telegram_messages
- Configuración del indicador Trend Constraint para Telegram
- Código final
- Tratamiento de errores
- Resultados de la pruebas
- Conclusión
Introducción
En el artículo anterior presentamos brevemente el proceso de integración. Al dividirlo en subsecciones, nuestro objetivo era simplificar la comprensión del proceso paso a paso. Es esencial contar con una base sólida y esperamos que el trabajo preliminar que hemos realizado sea sólido a medida que profundizamos para lograr que estas integraciones funcionen sin problemas, en particular dentro de nuestro modelo de restricción de tendencias. En última instancia, nuestro objetivo es recibir cómodamente notificaciones tanto en Telegram como en WhatsApp una vez concluido el proyecto. Esta configuración garantizará que nos mantengamos informados de los indicadores sin perdernos ninguna señal, todo mientras interactuamos con amigos y familiares en las redes sociales. Compartir señales directamente en la plataforma social será muy sencillo, eliminando la necesidad de cambiar entre aplicaciones.
El objetivo de este artículo es guiarnos a través de cada paso de forma integral hasta lograr los resultados deseados. Con los conocimientos básicos adquiridos en el artículo anterior, ahora todo está claro. Explicaré cada línea de código que compone el programa integrado. Hay cuatro componentes clave en este proyecto relacionado con la integración de Telegram que deben tenerse en cuenta constantemente.
- API del bot de Telegram.
- Script de Python.
- Servidor dedicado para alojar el script cuando se trata de solicitudes web.
- Nuestro programa indicador está configurado para Telegram.
Esta es una descripción general básica de los componentes involucrados en el proceso de integración principal. Si bien he mencionado específicamente Telegram y WhatsApp, cabe señalar que también se pueden integrar otras plataformas de redes sociales, siempre que haya un lenguaje de programación disponible para facilitar el proceso. Reconociendo la importancia de la compatibilidad de lenguajes en la programación, hemos incorporado Python y MQL5 en un solo proyecto. Esto resalta el beneficio de estar familiarizado con varios lenguajes como Python, C++, ONNX y C#. Este conocimiento puede ayudar en gran medida a los programadores de MQL5 a desarrollar funcionalidades dentro de la plataforma e integrarlas con otras API sociales.
La integración práctica de Telegram nos guiará a la tercera subsección de la Parte 5 de la serie de artículos, donde integraremos aún más WhatsApp, siguiendo una estructura similar a Telegram pero utilizando una API de mensajería en lugar de la API. Sobre la base que hemos establecido, esta tarea será más fácil ya que ahora tenemos los principios en mente.
Integración de Telegram en Trend Constraint
Continuemos con nuestro importante proyecto: en este punto, prácticamente continuamos desde donde lo dejamos. Basándome en mi investigación, existen varios métodos para conseguirlo siempre y cuando se entienda la lógica del código, pero he optado por centrarme en un método que consiste en utilizar un script de Python y la función ShellExecuteW para facilitar la interacción entre un indicador de MetaTrader 5 y un bot para Telegram. Profundizaré más en estos aspectos. Este enfoque ofrece una ventaja, ya que es relativamente sencillo para aquellos familiarizados con Python y MQL5. No requiere modificaciones extensas en el indicador MQL5. La única desventaja es que requiere dependencias externas como scripts y bibliotecas de Python.
El objetivo es mejorar la accesibilidad de las señales de MetaTrader 5 en Telegram para una audiencia más amplia y facilitar el intercambio y el reenvío mediante la implementación de bots de Telegram.
En un artículo anterior (Parte I), hablé del método de integración que utiliza la función WebRequest. Sin embargo, al revisar la documentación de MQL5, se descubrió que este método no es ideal para integrar indicadores, pero funciona bien con robots.
Se debe tener precaución al utilizar archivos DLL, ya que pueden representar riesgos graves si se emplean con aplicaciones no confiables. Es fundamental comprender y confiar plenamente en la funcionalidad de estos sistemas en su computadora para evitar ataques y hackeos.
Entendiendo la API del bot de Telegram
Supongo que ya eres un usuario activo de Telegram. El proyecto requiere mayor personalización y privacidad, incluidos detalles que guardaré para mí. Sigue las instrucciones para crear tu bot de Telegram con un nombre único, como hice yo usando @Botfather. He llamado al bot Trend Constraint, con el nombre de usuario @trend_constraint_bot. Puedes crear tu propio bot de forma similar con un nombre único. A continuación te explicamos brevemente cómo empezar a utilizar Botfather. Sigue las instrucciones de Botfather para completar el proceso. Una vez hecho esto, recibirás un bot token para acceder a la API. Después, inicia una conversación con el bot, añádelo a un grupo o a un canal para empezar a chatear. Cada chat tiene un ID único que el bot utilizará para interactuar con un usuario específico. Este chat también se utiliza para pasar señales del indicador MetaTrader 5 a un usuario de Telegram.
Después de haber configurado todo, visité el bot API utilizando el navegador Chrome. Recuerda el bot token que recibiste de Botfather, utiliza el enlace a la API https://api.telegram.org/bot<tu bot-token>/getUpdates , reemplaza el texto resaltado por tu bot token para que funcione.
Ejemplo: https://api.telegram.org/bot9004946256:shTUYuq52f8CHLt8BLdYGHYJi2QM6H3donA/getUpdates
Nota: El token API resaltado se generó aleatoriamente con fines educativos. Utilice el proporcionado por @BotFather para su robot. Asegúrese de realizar un chat con el bot para que la API muestre lo que queremos. También actualice la pestaña del navegador API para que puedan aparecer nuevas actualizaciones de chat. Marque la casilla de verificación de impresión bonita en la pestaña del navegador API para tener un diseño fácil de seguir.
La API mostrará un código JSON para la comunicación en curso con el bot. En primer lugar, definamos JSON (JavaScript Object Notation) como un formato ligero de intercambio de datos fácil de leer y escribir para los humanos y fácil de analizar y generar para las máquinas. Se utiliza habitualmente para transmitir datos en aplicaciones web (por ejemplo, entre un servidor y un cliente) y para configurar aplicaciones y almacenamiento de datos. Está estructurado por objetos y matrices.
A continuación se muestra un JSON de la API que se mostró después de enviar el mensaje «hey» al bot:
{ "ok": true, "result": [ { "update_id": 464310132, "message": { "message_id": 12, "from": { "id": 7049213628, "is_bot": false, "first_name": "Clemence", "last_name": "Benjamin", "username": "benjc_trade_advisor", "language_code": "en" }, "chat": { "id": 7049213628, "first_name": "Clemence", "last_name": "Benjamin", "username": "benjc_trade_advisor", "type": "private" }, "date": 1719044625, "text": "hey" }
He aquí una explicación detallada del código JSON:
Estructura de nivel superior:
- ok: Se trata de un valor booleano que indica el éxito de la solicitud de la API. En este caso, es verdadero, lo que significa que la solicitud se ha realizado correctamente.
- result: Es un array que contiene uno o más objetos de actualización. En este ejemplo, hay un objeto de actualización.
Cada elemento de la matriz de resultados representa una actualización. Aquí tenemos una única actualización:
- update_id: Se trata de un identificador único para la actualización. Ayuda a realizar un seguimiento de las actualizaciones y a garantizar que ninguna se omita o se procese varias veces. En este caso, 'update_id' arroja:
- 464310132.
El objeto message
Este objeto contiene información sobre el mensaje que activó la actualización:
- message_id: Se trata de un identificador único para el mensaje dentro del chat. Aquí son 12.
- from: Este objeto contiene información sobre el remitente del mensaje:
- id: El identificador único del usuario que envió el mensaje. En este caso, es 7049213628.
- is_bot: Este valor booleano indica si el remitente es un bot. En este caso, es falso, lo que significa que el remitente es un humano.
- first_name: El nombre del remitente, que es Clemence.
- last_name: El apellido del remitente, que es Benjamin.
- language_code: El código de idioma que representa la configuración de idioma del remitente. En este caso, aqui es en inglés.
- chat: Este objeto contiene información sobre el chat al que se envió el mensaje.
- id: El identificador único para el chat. Como se trata de un chat privado, coincide con el ID del usuario (7049213628).
- first_name: El nombre del participante en el chat, que es Clemence.
- last_name: El apellido del participante en el chat, que es Benjamin.
- type: El tipo de chat. En este caso, es privado, lo que indica que se trata de un chat individual entre el usuario y el bot.
- date: La fecha y hora en que se envió el mensaje, representada como una marca de tiempo Unix (segundos desde el 1 de enero de 1970). En este caso, la marca de tiempo es 1719044625.
- text: El contenido real del mensaje, que es «hey».
He decidido dejar a un lado la sección de chat del JSON para que podamos centrarnos fácilmente en la parte más importante que es el ID de chat que vamos a necesitar en nuestro programa indicador. Consulte el siguiente fragmento JSON:
"chat": { "id": 7049213628, "first_name": "Clemence", "last_name": "Benjamin", "username": "benjc_trade_advisor", "type": "private" }
El objeto «chat» proporciona información detallada sobre el chat en el que se envió el mensaje, incluido el identificador único del chat, el nombre y apellidos de los participantes y el tipo de chat. En este caso, especifica un chat privado en el que participa un usuario llamado Clemence Benjamin. Veamos una explicación detallada del objeto «chat»:
id:
- Descripción: Es el identificador único del chat.
- Valor: 7049213628
- Importancia: En el contexto de los chats privados, este ID suele coincidir con el ID de usuario del participante implicado en el chat.
first_name:
- Descripción: El nombre del participante en el chat.
- Valor: Clemence
- Importancia: Ayuda a identificar al usuario por su nombre dentro del chat.
last_name:
- Descripción: El apellido del participante en el chat.
- Valor: Benjamin
- Importancia: Complementa al nombre para identificar plenamente al usuario dentro del chat.
"username"
- Descripción: Es la llave.
- Valor: «benjc_trade_advisor»
- Importancia: Esta línea indica que el nombre de usuario asociado al objeto (como un usuario, bot o chat) es «benjc_trade_advisor». Este nombre de usuario se utiliza normalmente para identificar la entidad en un formato reconocible dentro de las aplicaciones o sistemas que utilizan los datos JSON.
Tipo:
- Descripción: El tipo de chat.
- Valor: Privado.
- Importancia: Indica que este chat es una conversación individual entre el usuario y el bot (a diferencia de un chat de grupo o un canal).
Resumen:
El objetivo de la sección mencionada era desarrollar un bot de Telegram que funcionara y adquirir el token del bot y el ID del chat, elementos cruciales para el proyecto principal. Profundizamos en la API para comprender mejor cada componente. Tener el token del bot y el ID del chat nos permitirá avanzar con el proceso de integración, donde también exploraremos varios lenguajes de programación.
Instalación de módulos Python de Telegram en Windows
Necesitamos tener Python instalado en la computadora. Asegúrese de que su computadora esté conectada con acceso a Internet. Puedes descargarlo desde Python.org. Hice esta guía prácticamente en una computadora con Windows. Puede ser un enfoque diferente en Mac, Linux y otros entornos. Una vez terminada la instalación de Python, el siguiente paso es instalar también los módulos API de Telegram de Python, que permitirán que los scripts de Python para Telegram se ejecuten correctamente. Abra cmd.exe (símbolo del sistema de Windows) y ejecute el siguiente fragmento de código. Copie el código y péguelo en el símbolo del sistema de Windows. Presione Enter en el teclado para permitir que el código inicie la descarga y espere unos momentos mientras el módulo finaliza la instalación.
pip install pyTelegramBotAPI
A continuación se muestra una captura de pantalla parcial del símbolo del sistema.
Cuando haya terminado, puede cerrar la ventana y reiniciar el equipo.
Después de completar este paso, su computadora ahora estará bien preparada para ejecutar los scripts de Python para interactuar con la API de Telegram. En la siguiente etapa, examinaremos el código de cerca para configurar nuestro sistema para la tarea.
Comprender el script de Python send_telegram_messages
Veamos la construcción del script. Y luego daré el código final en un fragmento. El archivo debe llamarse 'send_telegram_message.py'.
El script comienza importando los módulos necesarios de la siguiente manera:
- import telebot: Importa el módulo que proporciona las funciones necesarias para interactuar con la API del bot de Telegram.
- import sys: Importa el módulo que permite al script utilizar argumentos de línea de comandos.
import telebot import sys
Pasamos a declarar el API_TOKEN y la ID de chat:
- API_TOKEN: Esta variable almacena el token de la API que se utiliza para autentificar al bot con los servidores de Telegram.
- CHAT_ID: Un valor único de identidad de cada chat entre el usuario y Telegram, y entre canal y grupos.
API_TOKEN = '9004946256:shTUYuq52f8CHLt8BLdYGHYJi2QM6H3donA' #Replace the API TOKEN with your bot tokrn from @BotFather CHAT_ID = '7049213628' #Replace the ID with your actual Chat ID from the telebot API
Necesitamos inicializar el objeto TeleBot con el token de API proporcionado, para permitir la interacción con la API del bot de Telegram.
bot = telebot.TeleBot(API_TOKEN)
El siguiente fragmento de código de Python define una función para enviar un mensaje a través de Telegram, como excepciones de manejo de errores asociados con la API y el sistema.
def send_telegram_message(message): try: bot.send_message(CHAT_ID, message) print("Message sent successfully!") except telebot.apihelper.ApiTelegramException as e: print(f"Failed to send message: {e}") except Exception as e: print(f"An error occurred: {e}")
La parte final del código es una condición que garantiza que este bloque de código se ejecute solo si el script se ejecuta directamente, no si se importa como módulo. Recupera el mensaje de los argumentos de la línea de comandos o establece un mensaje predeterminado si no se proporcionan argumentos.
if __name__ == "__main__": message = sys.argv[1] if len(sys.argv) > 1 else "Test message" send_telegram_message(message)
Resumiendo todo tenemos nuestro código final, guarda el archivo como send_telegram_message.py y en tu carpeta de scripts de Python. Descubrí que el acceso a la carpeta de scripts funciona bien.
import telebot import sys API_TOKEN = '9004946256:shTUYuq52f8CHLt8BLdYGHYJi2QM6H3donA'#Replace with your API_TOKEN given by BotFather CHAT_ID = '7049213628' #Replace with your CHAT_ID bot = telebot.TeleBot(API_TOKEN) def send_telegram_message(message): try: bot.send_message(CHAT_ID, message) print("Message sent successfully!") except telebot.apihelper.ApiTelegramException as e: print(f"Failed to send message: {e}") except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": message = sys.argv[1] if len(sys.argv) > 1 else "Test message" send_telegram_message(message)
El siguiente paso importante es configurar el indicador MQL5 para llamar al script de Python.
Configuración del indicador Trend Constraint para Telegram
Aquí tenemos que modificar la función myAlert en el indicador MQL5 para llamar al script de Python usando la función ShellExecuteW. Esta función ejecutará el script de Python y pasará el mensaje de alerta como argumento.
Así es como lo modificamos en Trend Constraint, he incluido los dos fragmentos de código antes de la modificación y después de la modificación:
Antes de la modificación:
void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend Constraint V1.05 @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } else if(type == "indicator") { if(Audible_Alerts) Alert(type+" | Trend Constraint V1.05 @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Push_Notifications) SendNotification(type+" | Trend Constraint V1.05 @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } }
Después de la modificación:
//--- ShellExecuteW declaration ---------------------------------------------- #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import datetime last_alert_time; input int alert_cooldown_seconds = 60; // Cooldown period in seconds, this helps to avoid instant continuous alerting depending on indicator conditions //Modify the myAlert Function for telegram notification void myAlert(string type, string message) { datetime current_time = TimeCurrent(); if (current_time - last_alert_time < alert_cooldown_seconds) { // Skip alert if within cooldown period return; } last_alert_time = current_time; string full_message = type + " | Trend Constraint V1.04 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message; if (type == "print") { Print(message); } else if (type == "error") { Print(type + " | Trend Constraint V1.04 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message); } else if (type == "order") { // Add order alert handling if needed } else if (type == "modify") { // Add modify alert handling if needed } else if (type == "indicator") { if (Audible_Alerts) { Alert(full_message); } if (Push_Notifications) { SendNotification(full_message); } // Send to Telegram string python_path = "C:\\Users\\Pro_tech\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\Pro_tech\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py"; string command = python_path + " \"" + script_path + "\" \"" + full_message + "\""; Print("Executing command to send Telegram message: ", command); // Use cmd.exe to execute the command and then wait for 5 seconds string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 1); if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); } } } //--- End of Telegram Integration functions ---------------------------------------
Voy a explicar brevemente qué es lo que hace la modificación.
Primero necesitamos importar la función ShellExecuteW de la librería de Windows shell32.dll, permitiendo al programa MQL5 ejecutar comandos externos, en este caso está ejecutando el script send_telegram_message.py. El programa no funcionará sin declarar la función ShellExecuteW. También implementamos el enfriamiento para restringir la ejecución instantánea continua de cmd.exe debido a algunas condiciones de indicador mal configuradas. En mi caso, como mencioné en el artículo anterior, había una condición de alerta en el Buffer 5 y 6 del Trend Constraint V1.04 que causó múltiples alertas de señales en un corto tiempo. El resultado fue peor cuando integré la función Telegram , el cmd.exe se lanzó varias veces al instante y el ordenador se congeló. Para paliarlo he tenido que permitir que el indicador sólo se dibuje sin myAlert() . En otras palabras, lo silencié convirtiéndolo en comentarios, que como sabes los comentarios no se ejecutan en el programa.
//--- ShellExecuteW declaration ---------------------------------------------- #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import
La otra parte crucial del código es:
// Send to Telegram string python_path = "C:\\Users\\Pro_tech\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\Pro_tech\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py"; string command = python_path + " \"" + script_path + "\" \"" + full_message + "\"";
El código anterior construye un comando para ejecutar un script de Python desde un programa indicador de MetaTrader 5, especificando las rutas al intérprete de Python y al script, así como el mensaje que se enviará. Por favor, para el texto resaltado debe reemplazarlo con su propio texto para la ruta dependiendo de su computadora. Esto lo di como ejemplo desde mi computadora.
Código final
Habiendo explicado todo e integrado exitosamente, ahora tenemos una nueva característica y actualizamos a Trend Constraint V1.05.
//+------------------------------------------------------------------+ //| Trend Constraint V1.05.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com" #property version "1.05" #property description "A model that seeks to produce sell signals when D1 candle is Bearish only and buy signals when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 6 #property indicator_plots 6 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFF3C00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #property indicator_type3 DRAW_ARROW #property indicator_width3 2 #property indicator_color3 0xE8351A #property indicator_label3 "Buy Reversal" #property indicator_type4 DRAW_ARROW #property indicator_width4 2 #property indicator_color4 0x1A1AE8 #property indicator_label4 "Sell Reversal" #property indicator_type5 DRAW_LINE #property indicator_style5 STYLE_SOLID #property indicator_width5 2 #property indicator_color5 0xFFAA00 #property indicator_label5 "Buy" #property indicator_type6 DRAW_LINE #property indicator_style6 STYLE_SOLID #property indicator_width6 2 #property indicator_color6 0x0000FF #property indicator_label6 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double Buffer3[]; double Buffer4[]; double Buffer5[]; double Buffer6[]; input double Oversold = 30; input double Overbought = 70; input int Slow_MA_period = 200; input int Fast_MA_period = 100; datetime time_alert; //used when sending alert input bool Audible_Alerts = true; input bool Push_Notifications = true; double myPoint; //initialized in OnInit int RSI_handle; double RSI[]; double Open[]; double Close[]; int MA_handle; double MA[]; int MA_handle2; double MA2[]; int MA_handle3; double MA3[]; int MA_handle4; double MA4[]; double Low[]; double High[]; int MA_handle5; double MA5[]; int MA_handle6; double MA6[]; int MA_handle7; double MA7[]; //--- ShellExecuteW declaration ---------------------------------------------- #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import //--- functions for telegram integration ----------------------------------------------- datetime last_alert_time; input int alert_cooldown_seconds = 60; // Cooldown period in seconds void myAlert(string type, string message) { datetime current_time = TimeCurrent(); if (current_time - last_alert_time < alert_cooldown_seconds) { // Skip alert if within cooldown period return; } last_alert_time = current_time; string full_message = type + " | Trend Constraint V1.05 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message; if (type == "print") { Print(message); } else if (type == "error") { Print(type + " | Trend Constraint V1.05 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message); } else if (type == "order") { // Add order alert handling if needed } else if (type == "modify") { // Add modify alert handling if needed } else if (type == "indicator") { if (Audible_Alerts) { Alert(full_message); } if (Push_Notifications) { SendNotification(full_message); } // Send to Telegram //Remember to replace the storages path with your actual path. string python_path = "C:\\Users\\Pro_tech\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\Pro_tech\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py"; string command = python_path + " \"" + script_path + "\" \"" + full_message + "\""; // Debugging: Print the command being executed Print("Executing command to send Telegram message: ", command); // Use cmd.exe to execute the command and then wait for 5 seconds string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 1); if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); } } } //+------------------------------------------------------------------+ //| 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, 241); 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, 242); SetIndexBuffer(2, Buffer3); PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(2, PLOT_ARROW, 236); SetIndexBuffer(3, Buffer4); PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(3, PLOT_ARROW, 238); SetIndexBuffer(4, Buffer5); PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); SetIndexBuffer(5, Buffer6); PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE); if(RSI_handle < 0) { Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle3 = iMA(NULL, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle3 < 0) { Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle4 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle4 < 0) { Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle5 = iMA(NULL, PERIOD_CURRENT, Fast_MA_period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle5 < 0) { Print("The creation of iMA has failed: MA_handle5=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle6 = iMA(NULL, PERIOD_CURRENT, Slow_MA_period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle6 < 0) { Print("The creation of iMA has failed: MA_handle6=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle7 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle7 < 0) { Print("The creation of iMA has failed: MA_handle7=", 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); ArraySetAsSeries(Buffer3, true); ArraySetAsSeries(Buffer4, true); ArraySetAsSeries(Buffer5, true); ArraySetAsSeries(Buffer6, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); ArrayInitialize(Buffer3, EMPTY_VALUE); ArrayInitialize(Buffer4, EMPTY_VALUE); ArrayInitialize(Buffer5, EMPTY_VALUE); ArrayInitialize(Buffer6, EMPTY_VALUE); } else limit++; datetime Time[]; datetime TimeShift[]; if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total); ArraySetAsSeries(TimeShift, true); int barshift_M1[]; ArrayResize(barshift_M1, rates_total); int barshift_D1[]; ArrayResize(barshift_D1, rates_total); for(int i = 0; i < rates_total; i++) { barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]); barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]); } if(BarsCalculated(RSI_handle) <= 0) return(0); if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total); ArraySetAsSeries(RSI, true); if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total); ArraySetAsSeries(Open, true); if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, 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(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(BarsCalculated(MA_handle3) <= 0) return(0); if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total); ArraySetAsSeries(MA3, true); if(BarsCalculated(MA_handle4) <= 0) return(0); if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total); ArraySetAsSeries(MA4, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); if(BarsCalculated(MA_handle5) <= 0) return(0); if(CopyBuffer(MA_handle5, 0, 0, rates_total, MA5) <= 0) return(rates_total); ArraySetAsSeries(MA5, true); if(BarsCalculated(MA_handle6) <= 0) return(0); if(CopyBuffer(MA_handle6, 0, 0, rates_total, MA6) <= 0) return(rates_total); ArraySetAsSeries(MA6, true); if(BarsCalculated(MA_handle7) <= 0) return(0); if(CopyBuffer(MA_handle7, 0, 0, rates_total, MA7) <= 0) return(rates_total); ArraySetAsSeries(MA7, 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 if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue; if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue; //Indicator Buffer 1 if(RSI[i] < Oversold && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close && MA[i] > MA2[i] //Moving Average > Moving Average && MA3[i] > MA4[i] //Moving Average > Moving Average ) { Buffer1[i] = Low[1+i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open time_alert = Time[1]; } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(RSI[i] > Overbought && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close && MA[i] < MA2[i] //Moving Average < Moving Average && MA3[i] < MA4[i] //Moving Average < Moving Average ) { Buffer2[i] = High[1+i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open time_alert = Time[1]; } else { Buffer2[i] = EMPTY_VALUE; } //Indicator Buffer 3 if(MA5[i] > MA6[i] && MA5[i+1] < MA6[i+1] //Moving Average crosses above Moving Average ) { Buffer3[i] = Low[i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Reversal"); //Alert on next bar open time_alert = Time[1]; } else { Buffer3[i] = EMPTY_VALUE; } //Indicator Buffer 4 if(MA5[i] < MA6[i] && MA5[i+1] > MA6[i+1] //Moving Average crosses below Moving Average ) { Buffer4[i] = High[i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Reversal"); //Alert on next bar open time_alert = Time[1]; } else { Buffer4[i] = EMPTY_VALUE; } //Indicator Buffer 5, Alert muted by turning it into a comment if(MA3[i] > MA7[i] //Moving Average > Moving Average ) { Buffer5[i] = MA3[i]; //Set indicator value at Moving Average //if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open //time_alert = Time[1]; } else { Buffer5[i] = EMPTY_VALUE; } //Indicator Buffer 6, Alert muted by turning it into a comment if(MA3[i] < MA7[i] //Moving Average < Moving Average ) { Buffer6[i] = MA3[i]; //Set indicator value at Moving Average //if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open //time_alert = Time[1]; } else { Buffer6[i] = EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+
Tratamiento de errores
Error al enviar el mensaje: La solicitud a la API de Telegram no ha tenido éxito. Código de error: 401. Descripción: No autorizado.
Según mis pruebas el código de error anterior se debía a un API_TOKEN disfuncional como el que hemos utilizado como ejemplo anteriormente. Debe utilizar un valor API_TOKEN que funcione. He borrado la mayoría de los errores para llegar a un código de trabajo limpio para esta guía. Sin embargo, puede cometer errores al editar o cambiar el código, por lo que debe comprobar cuidadosamente cada paso que dé.
Resultados de las pruebas
Después de añadir el indicador al gráfico, activé la opción de permitir DLLs para permitir que nuestro indicador ejecute scripts a través del símbolo del sistema. La imagen animada muestra cómo se añade el indicador y su apariencia en el gráfico.
Puede comprobar si el script está funcionando ejecutando el archivo en su ruta a través de símbolo del sistema. Ver la imagen de abajo. Con el símbolo del sistema abierto en la carpeta con el script, escriba python send_telegram_message.py . Un mensaje enviado con éxito, la respuesta muestra que el script está funcionando y el mensaje de prueba también se reenvía al chat.
La imagen de resultado de abajo muestra el inicio de una conversación con el bot que nos permitió obtener el la ID de chat en la API del bot. También muestra la señal entrante enviada por el bot desde Trend Constraint V1.05. Las señales llegaron inmediatamente tal como se generaron en la plataforma MetaTrader 5.
Conclusión
Hemos integrado con éxito Telegram en nuestro modelo. Trend Constraint V1.05 ha avanzado significativamente, ahora puede pasar señales interna y externamente, beneficiando a los traders de todo el mundo con acceso a Telegram. La transmisión de la señal es rápida, sin retrasos debido a la eficiente ejecución del algoritmo. El sistema está dedicado a un indicador específico dentro de la plataforma, lo que garantiza que no haya interferencias con otras funciones. Las señales se transmiten de forma segura directamente a una identificación específica. Estos sistemas pueden alojarse en un servidor privado virtual para un funcionamiento continuo, proporcionando a los usuarios un suministro de señal estable. Estos proyectos pueden encontrar errores durante el desarrollo, pero me complace haberlos resuelto con éxito.
Espero que este proyecto te haya inspirado de alguna manera. Si está trabajando en un proyecto y ha encontrado desafíos con este tipo de integración, no dude en compartir sus ideas en la sección de discusión a continuación. Se adjuntan los archivos fuente que puedes modificar para tus proyectos y explorar algunas ideas con la ayuda de los comentarios proporcionados con fines educativos. A continuación, planeamos integrar otra plataforma social popular: WhatsApp.
Adjunto | Descripción |
---|---|
send_telegram_message.py | El script para permitir que el indicador pase notificaciones a Telegram. Contiene API_Token y la ID de chat. |
Trend Constraint V1.05.mq5 | El código fuente del programa indicador principal de MQL5. |
Telebot_API.txt | Estructura de la API de Telegram. |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/14968





- 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