English Русский 中文 Español Deutsch 日本語
preview
Criando um Painel de Administrador de Negociação em MQL5 (Parte I): Construindo uma Interface de Mensagens

Criando um Painel de Administrador de Negociação em MQL5 (Parte I): Construindo uma Interface de Mensagens

MetaTrader 5Exemplos | 17 abril 2025, 07:46
152 0
Clemence Benjamin
Clemence Benjamin

Introdução

É possível interagir com os usuários do seu sistema diretamente no MetaTrader 5. Essa é uma maneira de um administrador compartilhar insights em tempo real sobre o desempenho do sistema. Também pode servir como validação de sinais do sistema recentemente entregues para um canal social. Se você ler até o final, poderá ver como é possível criar uma interface interativa, como mostrado nesta imagem:

Painel de Administrador de Sistemas.

Painel de Administrador de Sistemas: Boom 500 Index, H1


Painel de administração

Painel de Comunicações do Administrador (MetaTrader 5) e App Telegram (recebendo mensagens em tempo real do administrador)

No mundo hiperconectado de hoje, onde milhões de negociações são executadas em milissegundos, ter canais de comunicação eficientes em ecossistemas de negociação é mais crítico do que nunca. Considere que mais de 70% dos traders agora dependem de plataformas de mensagens instantâneas como o Telegram para atualizações em tempo real, destacando uma tendência em direção a soluções de comunicação integradas em ambientes de negociação. Essa mudança destaca a necessidade de traders receberem insights e recomendações de especialistas de forma algorítmica e imediata.

Para traders e desenvolvedores que usam o MetaTrader 5, o desafio está em fazer a ponte entre a geração automatizada de sinais e a intervenção humana eficaz à distância. O painel de administração oferece aos administradores de sistemas a capacidade de estabelecer uma comunicação rápida e direta com traders dispersos globalmente. Ao aproveitar este sistema, os administradores podem validar ou invalidar sinais de maneira contínua e fornecer comentários ou recomendações essenciais aos traders através de plataformas como o Telegram.

Este artigo discute a criação deste painel de administração vital usando MQL5. Oferece um passo a passo para desenvolver este programa que melhora a comunicação e supervisão de negociações. Vamos explorar como aproveitar o poder do MQL5 para construir um sistema abrangente que facilite o gerenciamento eficaz de sinais e integre a comunicação imediata com traders, revolucionando a forma como as operações de negociação são conduzidas globalmente.

Diagrama de Fluxo de Sinais

Diagrama de Fluxo de Sinais

O diagrama de fluxo ilustra os papéis do sistema, usuários e administradores em um ecossistema de negociação, junto com as ferramentas associadas.

Aqui está um resumo do que abordaremos nesta discussão:

  1. Compreendendo Coordenadas no Desenvolvimento de GUI do MetaTrader 5
  2. Entendendo os arquivos de biblioteca no desenvolvimento MQL5
  3. Criando um algoritmo personalizado de Painel de Administrador em MQL5
  4. Integrando a API do Telegram para comunicação com Traders
  5. Testando o Painel de Administração
  6. Dicas de Uso
  7. Conclusão


Compreendendo Coordenadas no Desenvolvimento de GUI do MetaTrader 5

Ao desenvolver interfaces gráficas de usuário (GUIs) na plataforma MetaTrader 5, é essencial compreender o sistema de coordenadas que define como os elementos gráficos são posicionados e dimensionados em um gráfico.

Sistema de Coordenadas:

O sistema de coordenadas no MetaTrader 5 é um espaço bidimensional definido pelos eixos horizontal (x) e vertical (y). Cada janela de gráfico tem seu próprio sistema de coordenadas, começando do canto superior esquerdo, que é designado como o ponto de origem (0,0).

Posicionando Elementos:

Para posicionar elementos dentro do espaço de coordenadas do gráfico, normalmente você especifica dois pontos usando coordenadas:

  • Canto superior esquerdo: Definido pelas coordenadas (x1, y1). Este é o ponto onde o elemento começa.
  • Canto inferior direito: Definido pelas coordenadas (x2, y2). Este marca o final diagonal do elemento.

Cálculo de Largura e Altura:

As dimensões do elemento da GUI são derivadas da diferença entre essas coordenadas:

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

Esses cálculos determinam o tamanho do seu elemento, garantindo que ele se ajuste dentro dos limites especificados no gráfico.

Exemplo de Layout do Painel

Exemplo de layout de GUI & uso exemplo em MQL5

Exemplo de Aplicação Prática

Ao criar diálogos ou controles gráficos, como painéis ou botões, o uso dessas coordenadas ajuda você a estabelecer um posicionamento e dimensionamento claros e precisos. Essa abordagem garante que todos os componentes da GUI sejam colocados e dimensionados de maneira consistente para se ajustarem ao espaço disponível na janela do gráfico, contribuindo para uma interface de usuário coesa. Compreender e utilizar eficazmente esse sistema de coordenadas é fundamental para criar aplicativos intuitivos e visualmente atraentes dentro do ambiente MetaTrader 5.

Outro exemplo: Criando um Painel Simples com um Botão no MetaTrader 5

Vamos criar um painel simples com um botão na janela do gráfico do MetaTrader 5 usando o sistema de coordenadas descrito anteriormente.

Definir as Coordenadas:

Primeiro, vamos definir as coordenadas para tanto o painel quanto o botão. Vamos posicionar o painel no canto superior esquerdo do gráfico e colocar o botão dentro deste painel.

Coordenadas do Painel:

  • Canto superior esquerdo (x1, y1): (10, 10)
  • Canto inferior direito (x2, y2): (200, 100)

Essas coordenadas criarão um painel que começa 10 pixels do topo e 10 pixels da esquerda da janela do gráfico, com uma largura de 190 pixels (200 menos 10) e uma altura de 90 pixels (100 menos 10).

Coordenadas do Botão:

  • Canto superior esquerdo (x1, y1): (20, 20)
  • Canto inferior direito (x2, y2): (180, 60)

Essas coordenadas vão colocar o botão dentro do painel, começando 20 pixels do topo e 20 pixels da esquerda do painel, com uma largura de 160 pixels (180 menos 20) e uma altura de 40 pixels (60 menos 20). Pelo menos agora você tem a matemática em mente.


Entendendo os arquivos de biblioteca no desenvolvimento MQL5

Em MQL5, os arquivos ".mqh" são arquivos de cabeçalho usados para organizar e modularizar o código dentro da plataforma MetaTrader 5, que é principalmente utilizada para desenvolver algoritmos de negociação e indicadores personalizados. Esses arquivos são um componente crucial para um gerenciamento eficiente e sustentável de código em projetos complexos de MQL5.

No MetaEditor, você pode navegar para localizar o arquivo de inclusão na pasta MQL5 da seguinte forma:

Localizando os arquivos de Inclusão

Localizando os arquivos #include no MQL5

Aqui está uma explicação sobre seu propósito e uso:

Propósito dos Arquivos (.mqh):

1. Reusabilidade de Código: Arquivos ".mqh" são projetados para armazenar componentes de código reutilizáveis, como definições de funções, declarações de classes e definições de macros, que podem ser compartilhados entre vários programas MQL5.
2. Modularidade: Ao separar o código em diferentes arquivos, os desenvolvedores podem criar aplicativos modulares. Isso permite que funcionalidades específicas do código sejam isoladas, mantidas e desenvolvidas de forma independente.
3. Organização: Usar arquivos de cabeçalho ajuda na organização lógica do código. Os desenvolvedores podem manter diferentes partes de sua aplicação separadas em arquivos distintos, como colocar funções utilitárias ou constantes em cabeçalhos dedicados.

Conteúdo Típico dos Arquivos (.mqh):

  •  Declarações de Funções: Funções que podem ser usadas em vários scripts.
  •  Classes e Estruturas: Definições e implementações de classes e estruturas usadas para programação orientada a objetos.
  •  Constantes e Macros: Valores constantes e macros definidos que podem ser usados globalmente.
  •  Inclusões: O arquivo também pode incluir outros arquivos .mqh, criando assim uma hierarquia ou cadeia de funcionalidades incluídas.

Como usar os arquivos (.mqh):

Para usar um arquivo ".mqh" em seu script MQL5 (como um ".mq5" ou outro arquivo ".mqh"), você o inclui usando a diretiva #include. Aqui está um exemplo.
#include <MyLibrary.mqh>

Esta diretiva informa ao compilador para incluir o conteúdo de "MyLibrary.mqh" no ponto onde a diretiva #include aparece, permitindo que seu script acesse as funções, classes ou macros definidas no cabeçalho incluído.

Benefícios:

  • Melhoria na Legibilidade: Ao abstrair o código complexo para cabeçalhos, o script principal permanece mais limpo e fácil de entender.
  • Manutenção Simplificada: Alterações ou atualizações podem ser feitas em um único arquivo de cabeçalho, e todos os scripts que o incluírem automaticamente herdarão essas atualizações.
  • Colaboração: Em ambientes de equipe, dividir o código em vários arquivos pode facilitar uma melhor colaboração, já que diferentes membros da equipe podem trabalhar em partes separadas da base de código sem conflitos.

Por exemplo, neste projeto, implementaremos os arquivos resumidos nesta tabela:

Nome do Arquivo Tipo de Arquivo Descrição
Dialog.mqh: Arquivo de biblioteca;
  • Este arquivo de cabeçalho provavelmente contém definições de classes e implementações de métodos para criar e gerenciar janelas de diálogo, manipulando eventos e personalizando a aparência e o comportamento dos diálogos na interface gráfica.

  • Ao usar diálogos, podemos facilitar interações mais sofisticadas com o usuário, encapsulando vários controles (como botões e campos de texto) para solicitar entradas ou fornecer informações diretamente no contexto do gráfico.

Button.mqh: Arquivo de biblioteca
  •   Botões são elementos fundamentais de UI que permitem que os usuários acionem ações ou enviem dados. Este cabeçalho normalmente fornece métodos para criar botões, lidar com eventos de clique e personalizar as propriedades e o comportamento dos botões.

  • Este cabeçalho normalmente fornece métodos para criar botões, lidar com eventos de clique e personalizar as propriedades e o comportamento dos botões.
Edit.mqh:  Arquivo de biblioteca
  •   Este cabeçalho normalmente fornece métodos para criar botões, lidar com eventos de clique e personalizar as propriedades e o comportamento dos botões. Este cabeçalho fornece a estrutura necessária para integrar funcionalidades de entrada de texto na aplicação.
  • Podemos definir propriedades para esses controles de edição, como texto padrão, fonte e regras de validação de entrada, garantindo que as entradas do usuário sejam capturadas com precisão e tratadas adequadamente.


Criando um algoritmo personalizado de Painel de Administrador em MQL5

Crie um novo modelo de Expert no MetaEditor, nomeando-o como "Painel de Administrador" ou qualquer outro nome único. Mantenha apenas as propriedades de Desenvolvedor—seu nome, versão e copyright—e limpe o restante do modelo. Em seguida, siga o guia abaixo para construir seu painel.

Criar um novo Expert no MetaEditor

Criar um novo Expert no MetaEditor

Ao construir o programa "Admin Panel.mq5", garantimos que cada elemento tenha um propósito específico, mantendo um fluxo coeso. A base do nosso programa começa com a inclusão de bibliotecas chave, como "Trade.mqh", "Dialog.mqh", "Button.mqh" e "Edit.mqh", que fornecem classes e funções essenciais para criar interfaces interativas baseadas em gráficos. Ao incorporar essas bibliotecas, aproveitamos recursos existentes, permitindo-nos focar na funcionalidade personalizada.

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

Em seguida, definimos a classe "CScalableDialog" para gerenciar um painel escalável e arrastável dentro do gráfico. Esta classe estende "CDialog", que fornece uma base flexível para o nosso painel. Ao projetar isso, implementei métodos como "HandleDragging" para permitir que os usuários movam facilmente o painel e "SetSize" para permitir redimensionamento dinâmico. Isso nos dá a capacidade de criar uma interface amigável que pode se adaptar a diferentes tamanhos de tela e preferências dos usuários, tornando a ferramenta 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 da função "OnInit", focamos na inicialização dos componentes da interface. Isso inclui criar botões, caixas de entrada e configurar o layout do painel. Prestei muita atenção para garantir que cada elemento fosse posicionado corretamente e fosse funcional. O método (adminPanel. Creat)estabelece o diálogo principal, enquanto as linhas subsequentes adicionam botões como "sendButton", "quickMessageButton" e botões utilitários para minimizar e fechar o painel. Aqui, garanti que todos os componentes interagissem suavemente dentro do painel. 

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;
}

A função "OnChartEvent" é onde gerenciamos a lógica de interação. Esta função lida com várias ações do usuário, como cliques, movimentos do mouse e eventos de criação de objetos. Chamando métodos como "HandleDragging", permitimos que o painel responda dinamicamente à entrada do usuário. A estrutura switch-case dentro de "OnChartEvent" nos permite rotear de maneira eficiente os diferentes eventos para seus respectivos manipuladores, garantindo que a interface permaneça responsiva 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;
    }
}

Por fim, as funções de manipulação de cliques nos botões ("OnSendButtonClick", "OnQuickMessageButtonClick", "OnMinimizeButtonClick" e "OnCloseButtonClick") são onde o programa executa ações específicas com base na entrada do usuário. Por exemplo, "OnSendButtonClick" recupera a mensagem da caixa de entrada e a envia para o Telegram, fornecendo um feedback sobre o sucesso da operação. Essas funções são simples, mas cruciais, pois traduzem as ações do usuário em resultados significativos. Aqui, garanti que a interface não fosse apenas funcional, mas também estivesse alinhada com as expectativas do usuário.
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.");
}


Integrando a API do Telegram para comunicação com Traders

Ao integrar o envio de mensagens do Telegram dentro do programa MQL5, criamos a função "SendMessageToTelegram" para facilitar a comunicação entre nossa interface de negociação e um chat do Telegram. A função começa definindo duas variáveis cruciais: "botToken" e "chatId". Esses são identificadores exclusivos fornecidos pelo Telegram que nos permitem autenticar nosso bot e especificar o chat para onde a mensagem será enviada. Ao codificar esses valores diretamente, garantimos que a mensagem seja enviada para o destino correto de forma segura e eficiente. Você pode visitar api.telegram.org ou minhas escritas anteriores para saber mais sobre "BOT TOKEN" e "CHAT ID."

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

Em seguida, construímos a string "url", que é o endpoint para a API do Bot do Telegram, combinando-a com o "botToken" para criar a URL completa necessária para enviar mensagens. Essa etapa é crucial, pois configura a conexão com o servidor do Telegram, permitindo que nosso sistema interaja com ele programaticamente. Juntamente com isso, declaramos um array "char" chamado "post_data" para armazenar o payload da mensagem, que será formatado em JSON para atender aos requisitos da API.

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

Para formatar a mensagem em JSON, concatenamos o "chatId" e o texto da "mensagem" real na string "jsonMessage". Essa string é então convertida em um array de caracteres usando "StringToCharArray", e o array é redimensionado adequadamente usando "ArrayResize" para garantir que os dados se ajustem corretamente. Essa etapa garante que a estrutura da mensagem seja compatível com as expectativas da API do Telegram, o que é essencial para uma comunicação bem-sucedida.

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

A função então define uma variável "timeout" para determinar quanto tempo o programa deve esperar por uma resposta do servidor do Telegram. Preparamos um array "result" para armazenar a resposta do servidor e uma string "responseHeaders" para qualquer informação adicional retornada. Essas variáveis são importantes para lidar com a resposta e diagnosticar qualquer problema que possa surgir durante a solicitação.

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

A função "WebRequest" é onde ocorre a comunicação real com a API do Telegram. Enviamos a solicitação "POST" para a URL, passando os cabeçalhos necessários, o timeout e o "post_data". Se a solicitação for bem-sucedida, indicada por uma resposta HTTP 200, a função imprime uma mensagem de sucesso e retorna "true". Caso contrário, imprime o código de status HTTP e a mensagem de erro, retornando "false". Esse tratamento de erros é vital para depuração e para garantir que nossa funcionalidade de envio de mensagens seja confiável.

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;
}

Aqui está nosso código final após combinar todos os trechos:

//+------------------------------------------------------------------+
//|                                          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;
    }
}


Testando o Painel de Administração

Após uma compilação bem-sucedida, lançamos o programa, e ele funcionou como esperado.

Lançando o Painel de Administrador a partir dos Expert Advisors

Lançando o Painel de Administrador a partir dos Experts: Boom 500 Index


Dicas de Uso

Se você criou um bot do Telegram e um canal, e tem acesso à API do bot do Telegram, você só precisa editar o código-fonte abaixo para codificar diretamente seu token de bot e ID do chat para usar o Painel de Administração. Alternativamente, você pode simplesmente obter os tokens e inseri-los no EA compilado fornecido nos anexos abaixo, sem precisar modificar o código-fonte.

Insira seu token de bot e ID do chat

Insira o Token do Bot e o ID do Chat


Conclusão

Em conclusão, o desenvolvimento do Expert Advisor Painel de Administração em MQL5 demonstra um avanço significativo na gestão e comunicação com os traders diretamente da plataforma MetaTrader 5. Ao integrar uma GUI dinâmica e escalável com recursos de mensagens em tempo real através do Telegram, esta ferramenta aprimora a eficiência e a capacidade de resposta nas operações de negociação. A capacidade de enviar mensagens rápidas ou notificações personalizadas diretamente do painel permite uma comunicação imediata, garantindo que informações críticas sejam transmitidas sem atraso. Este projeto destaca o potencial de combinar interfaces amigáveis com ferramentas de comunicação robustas, abrindo caminho para soluções de gerenciamento de negociações mais interativas e eficazes.

O desenvolvimento adicional é essencial, incluindo a adição de outros botões rápidos para reduzir o tempo entre digitar e enviar mensagens, especialmente em resposta ao comportamento recente do mercado. Aprofundaremos mais sobre isso em escritos futuros desta série. Agradeço a você, Traders! Feliz desenvolvimento.

Seu feedback é sempre bem-vindo. Por favor, explore os arquivos anexados em seus projetos.

 Nome do Arquivo Descrição do Arquivo
Admin Panel.mq5 Código-fonte do Painel de Administração.
Admin Panel.ex5 Painel de Administração Expert pronto para rodar. Você só precisa inserir o Token do Bot correto e o ID do chat.
 (terminal64_bK0FbSvNmw)  Uma imagem mostrando como o Painel de Administração funciona.

Voltar ao topo

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15417

Arquivos anexados |
Admin_Panel.mq5 (21.75 KB)
Admin_Panel.ex5 (121.76 KB)
Automatizando Estratégias de Negociação com a Estratégia Parabolic SAR em MQL5: Criando um Expert Advisor Eficaz Automatizando Estratégias de Negociação com a Estratégia Parabolic SAR em MQL5: Criando um Expert Advisor Eficaz
Neste artigo, vamos automatizar as estratégias de negociação com a Estratégia Parabolic SAR em MQL5: Criando um Expert Advisor Eficaz. O EA realizará negociações com base nas tendências identificadas pelo indicador Parabolic SAR.
Redes neurais em trading: Representação adaptativa de grafos (NAFS) Redes neurais em trading: Representação adaptativa de grafos (NAFS)
Apresentamos o método NAFS (Node-Adaptive Feature Smoothing), uma abordagem não paramétrica para criar representações de nós que não requer o treinamento de parâmetros. O NAFS extrai as características de cada nó considerando seus vizinhos e, então, combina essas características de forma adaptativa para formar a representação final.
Criando um Expert Advisor Integrado com MQL5-Telegram (Parte 3): Enviando Capturas de Tela de Gráficos com Legendas de MQL5 para o Telegram Criando um Expert Advisor Integrado com MQL5-Telegram (Parte 3): Enviando Capturas de Tela de Gráficos com Legendas de MQL5 para o Telegram
Neste artigo, criamos um Expert Advisor em MQL5 que codifica capturas de tela de gráficos como dados de imagem e os envia para um chat do Telegram via requisições HTTP. Ao integrar a codificação e transmissão de fotos, aprimoramos o sistema MQL5-Telegram existente com insights visuais de trading diretamente no Telegram.
Redes neurais em trading: Transformer contrativo de padrões (Conclusão) Redes neurais em trading: Transformer contrativo de padrões (Conclusão)
No último artigo da série, analisamos o framework Atom-Motif Contrastive Transformer (AMCT), que utiliza aprendizado contrastivo para identificar padrões-chave em todos os níveis, desde os elementos básicos até estruturas complexas. Neste artigo, continuamos a implementar as abordagens do AMCT com recursos do MQL5.