English Русский 中文 Deutsch 日本語 Português
preview
Creación de un Panel de administración de operaciones en MQL5 (Parte I): Creación de una interfaz de mensajería

Creación de un Panel de administración de operaciones en MQL5 (Parte I): Creación de una interfaz de mensajería

MetaTrader 5Ejemplos |
535 3
Clemence Benjamin
Clemence Benjamin

Introducción

Es posible interactuar con los usuarios de su sistema directamente desde MetaTrader 5. Esta es una forma en que un administrador puede compartir información en tiempo real sobre el rendimiento del sistema. También puede servir como validación de señales del sistema enviadas recientemente a un canal social. Si lees hasta el final, podrás ver cómo es posible crear una interfaz interactiva, como se muestra en esta imagen:

Panel de administración de sistemas.

Panel de administrador de sistemas: Índice Boom 500, H1


Panel de administración

Panel de comunicaciones del administrador (MetaTrader 5) y aplicación Telegram (recepción de mensajes en tiempo real del administrador)

En el mundo hiperconectado de hoy, donde millones de transacciones se ejecutan en cuestión de milisegundos, contar con canales de comunicación eficientes en los ecosistemas comerciales es más crítico que nunca. Tenga en cuenta que más del 70% de los traders ahora confían en plataformas de mensajería instantánea como Telegram para obtener actualizaciones en tiempo real, lo que muestra una tendencia hacia soluciones de comunicación integradas en entornos comerciales. Este cambio subraya la necesidad de que los traders reciban acceso algorítmico e inmediato a información y recomendaciones de expertos.

Para los traders y desarrolladores que utilizan MetaTrader 5, el desafío consiste en superar la brecha entre la generación automatizada de señales y la intervención humana efectiva a través de la distancia. El Panel de administración ofrece a los administradores del sistema la capacidad de establecer una comunicación rápida y directa con comerciantes dispersos globalmente. Al aprovechar este sistema, los administradores pueden validar o invalidar señales sin problemas y proporcionar comentarios o recomendaciones esenciales a los comerciantes a través de plataformas como Telegram.

Este artículo analiza la creación de este Panel de administración vital utilizando MQL5. Ofrece una guía paso a paso sobre el desarrollo de este programa que mejora la comunicación y la supervisión comercial. Exploraremos cómo aprovechar el poder de MQL5 para construir un sistema integral que facilite la gestión eficaz de señales e integre la comunicación inmediata con los traders, revolucionando así la forma en que se realizan las operaciones comerciales a nivel mundial.

Diagrama de flujo de señales

Diagrama de flujo de señales

El diagrama de flujo ilustra los roles del sistema, los usuarios y los administradores en un ecosistema comercial, junto con las herramientas asociadas.

A continuación se presenta un resumen de lo que cubriremos en esta discusión:

  1. Comprensión de las coordenadas en el desarrollo de la interfaz gráfica de usuario de MetaTrader 5
  2. Comprenda los archivos de biblioteca en el desarrollo de MQL5
  3. Creación de un algoritmo de Panel de administrador personalizado en MQL5
  4. Integración de la API de Telegram para la comunicación con los traders
  5. Probando el Panel de administración
  6. Consejos de uso
  7. Conclusión


Comprensión de las coordenadas en el desarrollo de la interfaz gráfica de usuario de MetaTrader 5

Al desarrollar interfaces gráficas de usuario (GUI) dentro de la plataforma MetaTrader 5, es esencial comprender el sistema de coordenadas que define cómo se posicionan y dimensionan los elementos gráficos en un gráfico.

Sistema de coordenadas:

El sistema de coordenadas en MetaTrader 5 es un espacio bidimensional definido por ejes horizontales (x) y verticales (y). Cada ventana del gráfico tiene su propio sistema de coordenadas, comenzando desde la esquina superior izquierda, que se designa como el punto de origen (0,0).

Elementos de posicionamiento:

Para posicionar elementos dentro del espacio de coordenadas del gráfico, normalmente se especifican dos puntos mediante coordenadas:

  • Esquina superior izquierda: definida por las coordenadas (x1, y1). Esta es la posición donde comienza el elemento.
  • Esquina inferior derecha: definida por las coordenadas (x2, y2). Esto marca el extremo diagonal del elemento.

Cálculo de ancho y alto:

Las dimensiones del elemento GUI se derivan de la diferencia entre estas coordenadas:

  • Ancho: Calculado como (Ancho = x2 - x1)
  • Altura: Calculada como (Altura = y2 - y1)

Estos cálculos determinan el tamaño de su elemento, garantizando que se ajuste dentro de los límites especificados en el gráfico.

Ejemplo de disposición del Panel

Ejemplo de diseño de interfaz gráfica de usuario y ejemplo de uso en MQL5

Ejemplo de aplicación práctica

Al crear cuadros de diálogo o controles gráficos, como paneles o botones, el uso de estas coordenadas le ayudará a establecer un posicionamiento y un tamaño claros y precisos. Este enfoque garantiza que todos los componentes de la GUI estén ubicados y escalados de manera uniforme para ajustarse al espacio disponible en la ventana del gráfico, lo que contribuye a una interfaz de usuario cohesiva. Comprender y utilizar eficazmente este sistema de coordenadas es fundamental para crear aplicaciones intuitivas y visualmente atractivas dentro del entorno MetaTrader 5.

Otro ejemplo: Creación de un panel simple con un botón en MetaTrader 5

Creemos un panel simple con un botón en la ventana del gráfico de MetaTrader 5 utilizando el sistema de coordenadas descrito anteriormente.

Definir las coordenadas:

Primero, definiremos las coordenadas tanto del panel como del botón. Posicionaremos el panel en la esquina superior izquierda del gráfico y colocaremos el botón dentro de este panel.

Coordenadas del panel:

  • Esquina superior izquierda (x1, y1): (10, 10)
  • Esquina inferior derecha (x2, y2): (200, 100)

Estas coordenadas crearán un panel que comienza a 10 píxeles desde la parte superior y 10 píxeles desde la izquierda de la ventana del gráfico, con un ancho de 190 píxeles (200 menos 10) y una altura de 90 píxeles (100 menos 10).

Coordenadas del botón:

  • Esquina superior izquierda (x1, y1): (20, 20)
  • Esquina inferior derecha (x2, y2): (180, 60)

Estas coordenadas colocarán el botón dentro del panel, comenzando a 20 píxeles desde la parte superior y 20 píxeles desde la izquierda del panel, con un ancho de 160 píxeles (180 menos 20) y una altura de 40 píxeles (60 menos 20). Al menos ahora tienes las matemáticas en mente.


Comprenda los archivos de biblioteca en el desarrollo de MQL5

En MQL5, los archivos ".mqh" son archivos de encabezado que se utilizan para organizar y modularizar el código dentro de la plataforma MetaTrader 5, que se utiliza principalmente para desarrollar algoritmos comerciales e indicadores personalizados. Los archivos son un componente crucial para una gestión de código eficiente y fácil de mantener en proyectos MQL5 complejos.

En MetaEditor, puede navegar para localizar el archivo de inclusión en la carpeta MQL5 de la siguiente manera:

Cómo localizar los archivos de inclusión

Cómo localizar los archivos #include en MQL5

Aquí hay una explicación de su propósito y uso:

Propósito de los archivos (.mqh):

1. Reutilización de código: los archivos ".mqh" están diseñados para contener componentes de código reutilizables, como definiciones de funciones, declaraciones de clases y definiciones de macros, que pueden compartirse entre múltiples programas MQL5.
2. Modularidad: al separar el código en diferentes archivos, los desarrolladores pueden crear aplicaciones modulares. Esto permite aislar, mantener y desarrollar funcionalidades específicas del código de forma independiente.
3. Organización: el uso de archivos de encabezado ayuda a organizar el código de forma lógica. Los desarrolladores pueden mantener diferentes partes de su aplicación separadas en varios archivos, por ejemplo, colocando funciones de utilidad o constantes en encabezados dedicados.

Contenido típico de los archivos (.mqh):

  •  Declaraciones de funciones: funciones que se pueden utilizar en múltiples scripts.
  •  Clases y estructuras: definiciones e implementaciones de clases y estructuras utilizadas para la programación orientada a objetos.
  •  Constantes y macros: valores constantes y macros definidos que se pueden usar globalmente.
  •  Incluye: El archivo también puede incluir otros archivos `.mqh`, creando así una jerarquía o cadena de funcionalidades incluidas.

Cómo utilizar archivos (.mqh):

Para utilizar un archivo ".mqh" en su script MQL5 (como un archivo ".mq5" u otro archivo ".mqh"), inclúyalo utilizando la directiva #include. He aquí un ejemplo:
#include <MyLibrary.mqh>

Esta directiva le dice al compilador que incluya el contenido de "MyLibrary.mqh" en el punto donde aparece la directiva #include, permitiendo que tu script acceda a las funciones, clases o macros definidas dentro de la cabecera incluida.

Beneficios:

  • Legibilidad mejorada: al abstraer el código complejo en encabezados, el script principal permanece más limpio y más fácil de entender.
  • Mantenimiento simplificado: se pueden realizar cambios o actualizaciones en un solo archivo de encabezado, y todos los scripts que lo incluyan heredarán automáticamente estas actualizaciones.
  • Colaboración: en entornos de equipo, dividir el código en varios archivos puede facilitar una mejor colaboración, ya que diferentes miembros del equipo pueden trabajar en partes separadas de la base de código sin conflictos.

Por ejemplo, en este proyecto implementaremos los archivos resumidos en esta tabla:

Nombre del archivo Tipo de archivo Descripción
Dialog.mqh: Archivo de biblioteca
  • Es probable que este archivo de encabezado contenga definiciones de clases e implementaciones de métodos para crear y administrar ventanas de diálogo, manejar eventos y personalizar la apariencia y el comportamiento de los diálogos en la GUI.

  • Al utilizar cuadros de diálogo, podemos facilitar interacciones de usuario más sofisticadas, encapsulando varios controles (como botones y campos de texto) para solicitar entradas o proporcionar información directamente en el contexto del gráfico.

Button.mqh: Archivo de la biblioteca
  •   Los botones son elementos fundamentales de la interfaz de usuario que permiten a los usuarios activar acciones o enviar datos. Este encabezado normalmente proporciona métodos para crear botones, manejar eventos de clic y personalizar las propiedades y el comportamiento de los botones.

  • Es probable que contenga implementaciones para escuchas de eventos o funciones de devolución de llamada que respondan a las interacciones del usuario, lo que facilita la integración de la funcionalidad con las acciones del usuario.
Edit.mqh:  Archivo de la biblioteca
  •   Los controles de edición, a menudo conocidos como cuadros de texto o campos de entrada, permiten a los usuarios ingresar o modificar datos textuales. Este encabezado proporciona la estructura necesaria para integrar capacidades de ingreso de texto en la aplicación.
  • Podemos establecer propiedades para estos controles de edición, como texto predeterminado, fuente y reglas de validación de entrada, garantizando que las entradas del usuario se capturen con precisión y se manejen adecuadamente.


Creación de un algoritmo de Panel de administrador personalizado en MQL5

Cree una nueva plantilla de Experto en MetaEditor y llámela “Panel de administración” o cualquier otro nombre único. Conserve únicamente las propiedades del desarrollador (su nombre, versión y copyright) y borre el resto de la plantilla. Luego sigue la guía a continuación para construir tu panel.

Crear un nuevo experto en MetaEditor

Crear un nuevo experto en MetaEditor

Al construir el programa "Admin Panel.mq5", nos aseguramos de que cada elemento tenga un propósito específico manteniendo al mismo tiempo un flujo cohesivo. La base de nuestro programa comienza con la inclusión de bibliotecas clave como "Trade.mqh", "Dialog.mqh", "Button.mqh" y "Edit.mqh", que proporcionan clases y funciones esenciales para crear interfaces interactivas basadas en gráficos. Al incorporarlos, aprovechamos los recursos existentes, lo que nos permite centrarnos en la funcionalidad personalizada.

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>

Luego definimos la clase "CScalableDialog" para administrar un panel escalable y arrastrable dentro del gráfico. Esta clase extiende "CDialog", que proporciona una base flexible para nuestro panel. Al diseñar esto, implementé métodos como "HandleDragging" para permitir a los usuarios mover el panel fácilmente y "SetSize" para permitir el cambio de tamaño dinámico. Esto nos da la capacidad de crear una interfaz fácil de usar que puede adaptarse a diferentes tamaños de pantalla y preferencias de usuario, haciendo que la herramienta sea versátil.

class CScalableDialog : public CDialog
{
protected:
    bool m_Dragging;
    int m_OffsetX, m_OffsetY;
    int m_width, m_height;

public:
    CScalableDialog() : m_Dragging(false), m_OffsetX(1020), m_OffsetY(720), m_width(500), m_height(400) {}

    void HandleDragging(const int id, const long lparam, const double dparam)
    {
        if (id == CHARTEVENT_MOUSE_MOVE && m_Dragging)
        {
            int new_x = (int)lparam - m_OffsetX;
            int new_y = (int)dparam - m_OffsetY;
            SetXPosition(new_x, new_y);
        }
        else if (id == CHARTEVENT_OBJECT_CLICK)
        {
            m_OffsetX = (int)lparam;
            m_OffsetY = (int)dparam;
            m_Dragging = true;
        }
        else if (id == CHARTEVENT_CLICK)
        {
            m_Dragging = false;
        }
    }

    void SetSize(int width, int height)
    {
        m_width = width;
        m_height = height;
        UpdateDialogSize();
    }

    void UpdateDialogSize()
    {
        ObjectSetInteger(ChartID(), Name(), OBJPROP_XSIZE, m_width);
        ObjectSetInteger(ChartID(), Name(), OBJPROP_YSIZE, m_height);
    }

    void SetXPosition(int x, int y)
    {
        ObjectSetInteger(ChartID(), Name(), OBJPROP_XDISTANCE, x);
        ObjectSetInteger(ChartID(), Name(), OBJPROP_YDISTANCE, y);
        UpdateDialogSize();
    }
};

Dentro de la función "OnInit", nos centramos en inicializar los componentes de la interfaz. Esto incluye la creación de botones, cuadros de entrada y la configuración del diseño del panel. Presté mucha atención a garantizar que cada elemento estuviera correctamente posicionado y fuera funcional. El (adminPanel. Create) establece el diálogo principal, mientras que las líneas subsiguientes agregan botones como "sendButton", "quickMessageButton" y botones de utilidad para minimizar y cerrar el panel. Aquí, me aseguré de que todos los componentes interactuaran sin problemas dentro del panel. 

int OnInit()
{
    long chart_id = ChartID();

    if (!adminPanel.Create(chart_id, "Admin Panel", 0, 30, 30, 500, 400))
    {
        Print("Failed to create dialog");
        return INIT_FAILED;
    }

    if (!inputBox.Create(chart_id, "InputBox", 0, 5, 5, 460,50 ))
    {
        Print("Failed to create input box");
        return INIT_FAILED;
    }
    adminPanel.Add(inputBox);

    if (!sendButton.Create(chart_id, "SendButton", 0, 270, 50, 460, 80))
    {
        Print("Failed to create send button");
        return INIT_FAILED;
    }
    sendButton.Text("Send Message");
    adminPanel.Add(sendButton);

    if (!quickMessageButton.Create(chart_id, "QuickMessageButton", 0, 180, 200, 350, 230))
    {
        Print("Failed to create quick message button");
        return INIT_FAILED;
    }
    quickMessageButton.Text("Invalid Signal");
    adminPanel.Add(quickMessageButton);

    if (!minimizeButton.Create(chart_id, "MinimizeButton",0, 405, -22, 435, 0))
    {
        Print("Failed to create minimize button");
        return INIT_FAILED;
    }
    minimizeButton.Text("_");
    adminPanel.Add(minimizeButton);

    if (!closeButton.Create(chart_id, "CloseButton",0 , +435, -22,+465,0))
    {
        Print("Failed to create close button");
        return INIT_FAILED;
    }
    closeButton.Text("X");
    adminPanel.Add(closeButton);

    adminPanel.Show();
    ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_CREATE, true);
    ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_DELETE, true);
    ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_WHEEL, true);
    ChartRedraw();

    Print("Initialization complete");
    return INIT_SUCCEEDED;
}

La función "OnChartEvent" es donde gestionamos la lógica de interacción. Esta función maneja varias acciones del usuario, como clics, movimientos del mouse y eventos de creación de objetos. Al llamar a métodos como "HandleDragging", permitimos que el panel responda dinámicamente a la entrada del usuario. La estructura de conmutación dentro de "OnChartEvent" nos permite enrutar de manera eficiente diferentes eventos a sus respectivos controladores, lo que garantiza que la interfaz siga siendo receptiva e intuitiva. 

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
    adminPanel.HandleDragging(id, lparam, dparam);

    switch(id)
    {
        case CHARTEVENT_KEYDOWN:
            Print("Key pressed: code=", lparam);
            break;
        
        case CHARTEVENT_MOUSE_MOVE:
            Print("Mouse move: x=", lparam, "  y=", dparam);
            break;

        case CHARTEVENT_OBJECT_CREATE:
            Print("Created object: ", sparam);
            break;

        case CHARTEVENT_OBJECT_DELETE:
            Print("Deleted object: ", sparam);
            break;

        case CHARTEVENT_CLICK:
            Print("Mouse click on chart: x=", lparam, "  y=", dparam);
            break;

        case CHARTEVENT_OBJECT_CLICK:
            if (sparam == "SendButton")
            {
                OnSendButtonClick();
            }
            else if (sparam == "QuickMessageButton")
            {
                OnQuickMessageButtonClick();
            }
            else if (sparam == "MinimizeButton")
            {
                OnMinimizeButtonClick();
            }
            else if (sparam == "CloseButton")
            {
                OnCloseButtonClick();
            }
            break;
    }
}

Finalmente, las funciones de manejo de clics de botones ("OnSendButtonClick", "OnQuickMessageButtonClick", "OnMinimizeButtonClick" y "OnCloseButtonClick") son donde el programa ejecuta acciones específicas basadas en la entrada del usuario. Por ejemplo, "OnSendButtonClick" recupera el mensaje del cuadro de entrada y lo envía a Telegram, proporcionando información sobre el éxito de la operación. Estas funciones son sencillas pero cruciales, ya que traducen las acciones del usuario en resultados significativos. Aquí, me aseguré de que la interfaz no solo fuera funcional, sino que también se alineara con las expectativas del usuario.
void OnSendButtonClick()
{
    string customMessage = inputBox.Text();
    if (SendMessageToTelegram(customMessage))
    {
        Print("Message sent: ", customMessage);
    }
    else
    {
        Print("Failed to send message.");
    }
}

void OnQuickMessageButtonClick()
{
    if (SendMessageToTelegram(QuickMessage))
    {
        Print("Quick message sent: ", QuickMessage);
    }
    else
    {
        Print("Failed to send quick message.");
    }
}

void OnMinimizeButtonClick()
{
    static bool minimized = false;
    if (minimized)
    {
        adminPanel.SetSize(500, 400);
        minimized = false;
    }
    else
    {
        adminPanel.SetSize(500, 30);
        minimized = true;
    }
}

void OnCloseButtonClick()
{
    adminPanel.Destroy();
    Print("Panel closed.");
}


Integración de la API de Telegram para la comunicación con los traders

Al integrar la mensajería de Telegram dentro del programa MQL5, creamos la función "SendMessageToTelegram" para facilitar la comunicación entre nuestra interfaz comercial y un chat de Telegram. La función comienza definiendo dos variables cruciales: "botToken" y "chatId". Estos son identificadores únicos proporcionados por Telegram que nos permiten autenticar nuestro bot y especificar el chat donde se enviará el mensaje. Al codificar estos valores, garantizamos que el mensaje se envíe al destino correcto de forma segura y eficiente. Puedes visitar api.telegram.org, o mi anterior artículo, para obtener más información sobre "BOT TOKEN" y "CHAT ID".

string botToken = "BOT TOKEN";
string chatId = "CHAT ID";

Luego construimos la string "url", que es el punto final de la API de Telegram Bot, combinándola con el "botToken" para crear la URL completa necesaria para enviar mensajes. Este paso es crucial ya que configura la conexión con el servidor de Telegram, lo que permite que nuestro sistema interactúe con él mediante programación. Junto con esto, declaramos una matriz "char" "post_data" para contener la carga útil del mensaje, que se formateará en JSON para cumplir con los requisitos de la API.

string url = "https://api.telegram.org/bot" + botToken + "/sendMessage";
char post_data[];

Para formatear el mensaje en JSON, concatenamos el "chatId" y el texto del "mensaje" real en la cadena "jsonMessage". Luego, esta cadena se convierte en una matriz de caracteres utilizando "StringToCharArray", y la matriz se redimensiona en consecuencia utilizando "ArrayResize" para garantizar que se ajuste a los datos correctamente. Este paso garantiza que la estructura del mensaje sea compatible con las expectativas de la API de Telegram, lo cual es esencial para una comunicación exitosa.

string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}";
ArrayResize(post_data, StringToCharArray(jsonMessage, post_data));

Luego, la función establece una variable "timeout" para definir cuánto tiempo debe esperar el programa una respuesta del servidor de Telegram. Preparamos una matriz "result" para almacenar la respuesta del servidor y una cadena "responseHeaders" para cualquier información adicional devuelta. Estas variables son importantes para manejar la respuesta y diagnosticar cualquier problema que pueda surgir durante la solicitud.

int timeout = 5000;
char result[];
string responseHeaders;

La función "WebRequest" es donde se produce la comunicación real con la API de Telegram. Enviamos la solicitud "POST" a la URL, pasando los encabezados necesarios, el tiempo de espera y "post_data". Si la solicitud es exitosa, lo que se indica mediante una respuesta HTTP 200, la función imprime un mensaje de éxito y devuelve "verdadero". De lo contrario, imprime el código de estado HTTP y el mensaje de error, devolviendo "falso". Esta gestión de errores es vital para la depuración y garantizar que nuestra funcionalidad de envío de mensajes sea confiable.

int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders);

if (res == 200) // HTTP 200 OK
{
    Print("Message sent successfully: ", message);
    return true;
}
else
{
    Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError());
    Print("Response: ", CharArrayToString(result));
    return false;
}

Aquí está nuestro código final después de combinar todos los fragmentos:

//+------------------------------------------------------------------+
//|                                          Admin Panel.mq5         |
//|                   Copyright 2024, Clemence Benjamin              |
//|       https://www.mql5.com/en/users/billionaire2024/seller       |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property description "A responsive Admin Panel. Send messages to your telegram clients without leaving MT5"
#property version   "1.06"

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>

//+------------------------------------------------------------------+
//| Creating a scalable and draggable panel                          |
//+------------------------------------------------------------------+
class CScalableDialog : public CDialog
{
protected:
    bool m_Dragging;
    int m_OffsetX, m_OffsetY;
    int m_width, m_height;

public:
    CScalableDialog() : m_Dragging(false), m_OffsetX(1020), m_OffsetY(720), m_width(500), m_height(400) {}

    // Handle the event to allow dragging
    void HandleDragging(const int id, const long lparam, const double dparam)
    {
        if (id == CHARTEVENT_MOUSE_MOVE && m_Dragging)
        {
            int new_x = (int)lparam - m_OffsetX;
            int new_y = (int)dparam - m_OffsetY;
            SetXPosition(new_x, new_y); // Update the position without changing size
        }
        else if (id == CHARTEVENT_OBJECT_CLICK)
        {
            m_OffsetX = (int)lparam;
            m_OffsetY = (int)dparam;
            m_Dragging = true;
        }
        else if (id == CHARTEVENT_CLICK)
        {
            m_Dragging = false;
        }
    }

    void SetSize(int width, int height)
{
    m_width = width;
    m_height = height;

    // Call the method to update the size of the dialog
    UpdateDialogSize();
}

void UpdateDialogSize()
{
    // Adjust the internal layout or size of the controls within the dialog here
    // Example: Resize or reposition child controls based on the new dimensions

    // Ensure that dialog dimensions are respected within its design
    ObjectSetInteger(ChartID(), Name(), OBJPROP_CORNER, 0); // This aligns the dialog to the chart corner
    ObjectSetInteger(ChartID(), Name(), OBJPROP_XSIZE, m_width);  // Width of the dialog
    ObjectSetInteger(ChartID(), Name(), OBJPROP_YSIZE, m_height); // Height of the dialog
}


  void SetXPosition(int x, int y)
{
    // Set the X and Y positions of the dialog panel
    ObjectSetInteger(ChartID(), Name(), OBJPROP_XDISTANCE, x);
    ObjectSetInteger(ChartID(), Name(), OBJPROP_YDISTANCE, y);

    // Call the method to update the size of the dialog
    UpdateDialogSize();
}


};

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
input string QuickMessage = "Invalid Signal"; // Default quick message

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
CScalableDialog adminPanel;
CButton sendButton;
CButton quickMessageButton;
CButton minimizeButton;
CButton closeButton;
CEdit inputBox;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    long chart_id = ChartID();

    // Create the dialog
    if (!adminPanel.Create(chart_id, "Admin Panel", 0, 30, 30, 500, 400))
    {
        Print("Failed to create dialog");
        return INIT_FAILED;
    }

    // Create the input box
    if (!inputBox.Create(chart_id, "InputBox", 0, 5, 5, 460,50 ))
    {
        Print("Failed to create input box");
        return INIT_FAILED;
    }
    adminPanel.Add(inputBox);

    // Create the send button for custom messages
    if (!sendButton.Create(chart_id, "SendButton", 0, 270, 50, 460, 80))
    {
        Print("Failed to create send button");
        return INIT_FAILED;
    }
    sendButton.Text("Send Message");
    adminPanel.Add(sendButton);

    // Create the quick message button
    if (!quickMessageButton.Create(chart_id, "QuickMessageButton", 0, 180, 200, 350, 230))
    {
        Print("Failed to create quick message button");
        return INIT_FAILED;
    }
    quickMessageButton.Text("Invalid Signal");
    adminPanel.Add(quickMessageButton);

    // Create the minimize button
    if (!minimizeButton.Create(chart_id, "MinimizeButton",0, 405, -22, 435, 0))
    {
        Print("Failed to create minimize button");
        return INIT_FAILED;
    }
    minimizeButton.Text("_");
    adminPanel.Add(minimizeButton);

    // Create the close button
    if (!closeButton.Create(chart_id, "CloseButton",0 , +435, -22,+465,0))
    {
        Print("Failed to create close button");
        return INIT_FAILED;
    }
    closeButton.Text("X");
    adminPanel.Add(closeButton);

    adminPanel.Show();

    // Enable chart events
    ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_CREATE, true);
    ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_DELETE, true);
    ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_WHEEL, true);
    ChartRedraw();

    Print("Initialization complete");
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    adminPanel.Destroy();
    Print("Deinitialization complete");
}

//+------------------------------------------------------------------+
//| Expert event handling function                                   |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
    // Handle dragging and other events
    adminPanel.HandleDragging(id, lparam, dparam);

    // Handle different types of events
    switch(id)
    {
        case CHARTEVENT_KEYDOWN:
            Print("Key pressed: code=", lparam);
            break;
        
        case CHARTEVENT_MOUSE_MOVE:
            Print("Mouse move: x=", lparam, "  y=", dparam);
            break;

        case CHARTEVENT_OBJECT_CREATE:
            Print("Created object: ", sparam);
            break;

        case CHARTEVENT_OBJECT_DELETE:
            Print("Deleted object: ", sparam);
            break;

        case CHARTEVENT_CLICK:
            Print("Mouse click on chart: x=", lparam, "  y=", dparam);
            break;

        case CHARTEVENT_OBJECT_CLICK:
            if (sparam == "SendButton")
            {
                OnSendButtonClick();
            }
            else if (sparam == "QuickMessageButton")
            {
                OnQuickMessageButtonClick();
            }
            else if (sparam == "MinimizeButton")
            {
                OnMinimizeButtonClick();
            }
            else if (sparam == "CloseButton")
            {
                OnCloseButtonClick();
            }
            break;

        default:
            if (id > CHARTEVENT_CUSTOM)
                Print("Custom event ID=", id, " lparam=", lparam, " dparam=", dparam, " sparam=", sparam);
            break;
    }
}

//+------------------------------------------------------------------+
//| Function to handle custom message send button click              |
//+------------------------------------------------------------------+
void OnSendButtonClick()
{
    string message = inputBox.Text();
    if (message != "")
    {
        if(SendMessageToTelegram(message))
            Print("Custom message sent: ", message);
        else
            Print("Failed to send custom message.");
    }
    else
    {
        Print("No message entered.");
    }
}

//+------------------------------------------------------------------+
//| Function to handle quick message button click                    |
//+------------------------------------------------------------------+
void OnQuickMessageButtonClick()
{
    if(SendMessageToTelegram(QuickMessage))
        Print("Quick Message Button Clicked - Quick message sent: ", QuickMessage);
    else
        Print("Failed to send quick message.");
}

//+------------------------------------------------------------------+
//| Function to handle minimize button click                         |
//+------------------------------------------------------------------+
void OnMinimizeButtonClick()
{
    static bool minimized = false;
    if (minimized)
    {
        // Restore full size
        adminPanel.SetSize(500, 400);  // Restore full size (400x200)
    }
    else
    {
        // Minimize to header only
        adminPanel.SetSize(100, 80);   // Minimize height to 30 (keeping the width 400)
    }
    minimized = !minimized;
}

//+------------------------------------------------------------------+
//| Function to handle close button click                            |
//+------------------------------------------------------------------+
void OnCloseButtonClick()
{
    adminPanel.Destroy();
    Print("Admin Panel closed.");
}

///+------------------------------------------------------------------+
//| Function to send the message to Telegram                         |
//+------------------------------------------------------------------+
bool SendMessageToTelegram(string message)
{
    // Replace with your bot token and chat ID
    string botToken = "Your BOT TOKEN";
    string chatId = "Your Chat ID";

    string url = "https://api.telegram.org/bot" + botToken + "/sendMessage";
    char post_data[];

    // Prepare the message data
    string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}";

    // Resize the character array to fit the JSON payload
    ArrayResize(post_data, StringToCharArray(jsonMessage, post_data));

    int timeout = 5000;
    char result[];
    string responseHeaders;

    // Make the WebRequest
    int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders);

    if (res == 200) // HTTP 200 OK
    {
        Print("Message sent successfully: ", message);
        return true;
    }
    else
    {
        Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError());
        Print("Response: ", CharArrayToString(result));
        return false;
    }
}


Probando el Panel de administración

Después de una compilación exitosa, lanzamos el programa y funcionó según lo previsto.

Cómo iniciar el Panel de administración desde un Asesor Experto.

Lanzamiento del Panel de administración desde un experto: Índice Boom 500


Consejos de uso

Si has creado un bot y un canal de Telegram, y tienes acceso a la API de bots de Telegram, sólo tienes que editar el código fuente de abajo para codificar tu token de bot y tu ID de chat para usar el Panel de Administración. Como alternativa, puede simplemente obtener los tokens e introducirlos en el EA compilado que se proporciona en los archivos adjuntos a continuación, sin necesidad de modificar el código fuente.

Introduce tu bot, token y Chat ID

Input Bot Token and Chat ID


Conclusión

En conclusión, el desarrollo del Asesor Experto del Panel de Administración en MQL5 demuestra un avance significativo en la gestión y comunicación con los traders directamente desde la plataforma MetaTrader 5. Al integrar una GUI dinámica y escalable con capacidades de mensajería en tiempo real a través de Telegram, esta herramienta mejora la eficiencia y la capacidad de respuesta en las operaciones comerciales. La capacidad de enviar mensajes rápidos o notificaciones personalizadas directamente desde el panel permite una comunicación inmediata, garantizando que la información crítica se transmita sin demora. Este proyecto subraya el potencial de combinar interfaces fáciles de usar con herramientas de comunicación sólidas, allanando el camino para soluciones de gestión comercial más interactivas y efectivas.

Es esencial un mayor desarrollo, incluida la adición de otros botones rápidos para reducir el tiempo entre escribir y enviar mensajes, especialmente en respuesta al comportamiento reciente del mercado. Profundizaremos en esto en futuros escritos de esta serie. ¡Os aprecio, Traders! Feliz desarrollo.

Sus comentarios siempre son bienvenidos. Por favor explore los archivos adjuntos del proyecto.

 Nombre del archivo Descripción del archivo
Admin Panel.mq5 Código fuente del Panel de administración.
Admin Panel.ex5 Listo para ejecutar el Panel de administración experto. Solo necesitas ingresar tu token de bot correcto y la identificación del chat
 (terminal64_bK0FbSvNmw)  Una imagen que muestra cómo funciona el Panel de administración.

Volver al inicio

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

Archivos adjuntos |
Admin_Panel.mq5 (21.75 KB)
Admin_Panel.ex5 (121.76 KB)
Cracker Delicious
Cracker Delicious | 22 ago 2024 en 02:39
Gracias
Clemence Benjamin
Clemence Benjamin | 23 ago 2024 en 10:09
Cracker Delicious #:
Gracias

Bienvenido@Cracker Delicious

Clemence Benjamin
Clemence Benjamin | 23 ago 2024 en 13:43

En MetaTrader 5, si planeas usar el Panel de Administración compilado adjunto en el archivo, asegúrate de presionar Ctrl + O para habilitar WebRequest bajo la configuración del Asesor Experto. Además, añade el enlace a la API de Telegram para que funcione.

Permitir WebRequest



Automatización de estrategias comerciales con la estrategia de tendencia Parabolic SAR en MQL5: Creación de un asesor experto eficaz Automatización de estrategias comerciales con la estrategia de tendencia Parabolic SAR en MQL5: Creación de un asesor experto eficaz
En este artículo, automatizaremos las estrategias comerciales con la estrategia Parabolic SAR en MQL5: Creación de un asesor experto eficaz. El EA realizará operaciones basadas en las tendencias identificadas por el indicador Parabolic SAR.
Redes neuronales en el trading: Modelos del espacio de estados Redes neuronales en el trading: Modelos del espacio de estados
Una gran cantidad de los modelos que hemos revisado hasta ahora se basan en la arquitectura del Transformer. No obstante, pueden resultar ineficientes al trabajar con secuencias largas. En este artículo le propongo familiarizarse con una rama alternativa de pronóstico de series temporales basada en modelos del espacio de estados.
Creación de un asesor experto integrado de MQL5 y Telegram (Parte 3): Envío de señales de MQL5 a Telegram Creación de un asesor experto integrado de MQL5 y Telegram (Parte 3): Envío de señales de MQL5 a Telegram
En este artículo, creamos un Asesor Experto MQL5 que codifica capturas de pantalla de gráficos como datos de imagen y las envía a un chat de Telegram a través de peticiones HTTP. Al integrar la codificación y transmisión de fotos, mejoramos el sistema existente MQL5-Telegram con perspectivas visuales de trading directamente dentro de Telegram.
Obtenga una ventaja sobre cualquier mercado (Parte III): Índice de gasto de Visa Obtenga una ventaja sobre cualquier mercado (Parte III): Índice de gasto de Visa
En el mundo de los macrodatos, hay millones de conjuntos de datos alternativos que pueden mejorar nuestras estrategias de negociación. En esta serie de artículos le ayudaremos a identificar los conjuntos de datos públicos más informativos.