
Criando um Expert Advisor Integrado MQL5-Telegram (Parte 4): Modularizando Funções de Código para Maior Reutilização
Introdução
No artigo anterior desta série, exploramos o processo de envio de capturas de tela com legendas do MetaTrader 5 para o Telegram. Nossa abordagem, embora eficaz, era bastante direta e um tanto inflexível. Encadeamos os componentes necessários para capturar uma captura de tela, convertê-la ou codificá-la em uma forma compatível com mensagens e enviá-la para o Telegram. Embora essa configuração funcionasse, ela resultava em uma quantidade razoável de código repetitivo e de difícil manutenção. Então, o que podemos fazer para melhorar essa implementação? Migrar para uma base de código mais modular! Esse é o primeiro passo para um sistema mais flexível e mais fácil de manter.
Nesta quarta parte da nossa série, focaremos em melhorar a reutilização do nosso programa através da modularização do código. Realizaremos uma discussão detalhada sobre os princípios de modularização de código e, mais especificamente, como esses princípios se aplicam ao nosso projeto. Em seguida, apresentaremos instruções passo a passo para reorganizar nosso script mql5 existente em funções separadas e bem definidas. Ao final, você poderá escolher entre usar o programa antigo, monolítico, ou um novo Expert Advisor (EA) modular com o mesmo resultado.
Depois disso, alteraremos nosso código atual de forma metódica para que ele assuma um novo papel dentro do nosso programa. Dividiremos o código em funções distintas, cada uma com a responsabilidade de realizar uma única tarefa: enviar mensagens, tirar capturas de tela e codificar dados na forma necessária para a transmissão. Mostraremos como cada parte se encaixa na nova estrutura e, mais importante, como cada função executa sua tarefa sem repetições desnecessárias e de forma que permita atualizar e expandir o programa facilmente.
Para concluir, falaremos sobre os processos de teste e verificação do código modularizado da estratégia. Isso incluirá a verificação do funcionamento correto de cada função, o desempenho do sistema como um todo e a comparação dos resultados com o código antigo. Embora estejamos usando o termo modularização, estamos apenas falando sobre tornar nossos Expert Advisors mais compreensíveis e fáceis de manter. Ao final deste artigo, você entenderá por que este é um passo importante no desenvolvimento e terá uma visão clara de como o fizemos e dos benefícios esperados. Aqui estão os tópicos que seguiremos para criar o Expert Advisor (EA):
- Compreendendo a Necessidade de Modularização
- Refatorando o Código de Envio de Mensagens
- Modularizando Funções de Captura de Tela
- Testando e Implementando Funções Modulares
- Conclusão
Ao final, teremos produzido um Expert Advisor MQL5-Telegram organizado e eficiente em MetaQuotes Language 5 (MQL5). Este código modular e bem estruturado permite fácil integração, é altamente flexível e requer muito menos esforço para atualizações e adição de novas funcionalidades do que se fosse escrito da maneira tradicional. Ele não só realiza tarefas de envio de mensagens, como também cuida da captura de tela e do armazenamento de dados, fazendo isso de forma gerenciável e escalável, estabelecendo assim uma base sólida para melhorias futuras. Então, vamos começar.
Compreendendo a Necessidade de Modularização
Vamos examinar a ideia da modularização de código, que é uma técnica fundamental da engenharia de software para organizar e gerenciar grandes bases de código. Quando um programa é modularizado, ele é dividido em partes menores e gerenciáveis que são quase auto contidas. Cada uma dessas partes (ou módulos) realiza uma função específica e interage com outros módulos de forma bem definida. Claro, ainda precisamos escrever a maior parte do programa, então também veremos alguns princípios e conceitos básicos que orientam como modularizar um programa.
Tanto as fases de desenvolvimento quanto as de manutenção demonstram os benefícios da modularização. Na hora de escrever o código, os desenvolvedores podem se concentrar em um módulo por vez. O código de cada módulo é implementado, testado e depurado antes de seguir para o próximo. Depois que o sistema está em operação, se for necessária alguma mudança, geralmente ela pode ser feita em apenas um módulo. Alterações em um módulo afetam muito pouco os demais. O resultado final é um sistema muito mais estável com menor custo para alterações ou reparos. Como ilustração, nosso Expert Advisor MQL5 pode enviar mensagens quando certos eventos ocorrem. Um de nossos módulos faz isso. Outro módulo pode tirar capturas de tela e salvá-las. Se quisermos ampliar a função de captura de tela, poderemos fazê-lo sem afetar o módulo que envia mensagens.
Garantir a manutenibilidade de um programa é algo que parece simples — e de fato é — porque envolve manter tudo que faz o programa funcionar em ordem limpa e organizada. Quase tudo o que dissemos até agora é uma introdução a este parágrafo essencial, pois nada contribui mais para a manutenibilidade do que criar módulos que contenham todos os elementos necessários para atender às partes interessadas — uma parte para você, uma parte para mim e uma parte para aquela função ali. Ao garantir tudo isso, também garantimos a reutilização, pois uma vez que um módulo faz o que deve, ele está perfeito.
Vamos demonstrar a modularização do código do Expert Advisor MQL5 dividindo-o em funções e classes bem definidas. Veremos como conectar esses módulos para realizar tarefas específicas, como enviar mensagens de texto, capturar telas e reestruturar os dados inseridos em nosso sistema para que ele funcione como desejado. Ao final, esperamos entender como essas mudanças tornam nosso Expert Advisor mais eficiente, fácil de manter e escalável.
Refatorando o Código de Envio de Mensagens
A primeira coisa que faremos é criar uma função ou módulo personalizado onde possamos inserir a lógica que será encapsulada e organizada para máxima reutilização. A primeira função será responsável por enviar uma mensagem simples.
//+------------------------------------------------------------------+ //| FUNCTION TO SEND SIMPLE MESSAGE | //+------------------------------------------------------------------+ void sendSimpleMessage(){ //... }
Aqui, encapsulamos o processo de envio de uma mensagem para o Telegram dentro de uma função chamada "sendSimpleMessage". Essa estrutura modular simplifica a manutenção, o gerenciamento e a reutilização do código dentro do Expert Advisor (EA). Usamos uma função do tipo void, ou seja, uma função que não retorna valor. Em vez disso, ela opera enviando uma mensagem para o Telegram. A função também é capaz de lidar com o sucesso e a falha da operação "nos bastidores", para que o código não fique sobrecarregado com diversos comandos if. Essa encapsulação permite que o programa principal chame a função sempre que quiser enviar uma mensagem, sem precisar se preocupar com os detalhes da API do Telegram.
Para permitir flexibilidade na operação de envio de mensagens, precisamos incluir parâmetros que possam ser reutilizados automaticamente para permitir o envio de diferentes textos sempre que necessário, além da URL da API, o token do bot e o ID do chat.
void sendSimpleMessage(string custom_message,const string api_url, const string bot_token,const string chat_id, int timeout=10000){ //... }
Aqui, definimos uma função void chamada "sendSimpleMessage", que reflete seu propósito: enviar uma mensagem simples para o Telegram sem anexos complexos ou processamento de dados. Ela é preenchida com quatro parâmetros de entrada obrigatórios: "custom_message", "api_url", "bot_token" e "chat_id", e um parâmetro de entrada opcional: "timeout". Vamos detalhar os parâmetros de maneira estruturada para facilitar a compreensão.
- custom_message: Este é um parâmetro do tipo string que contém a mensagem de texto que queremos enviar ao Telegram.
- api_url: Este é um parâmetro do tipo string que contém a URL base da API do Bot do Telegram. Essa URL é usada para solicitar o endpoint correto da API.
- bot_token: Outro parâmetro do tipo string que contém o token exclusivo do bot, necessário para autenticar o bot e autorizá-lo a enviar mensagens.
- chat_id: Este parâmetro do tipo string especifica o identificador exclusivo do chat ou canal do Telegram para onde a mensagem será enviada.
- timeout: Este é um parâmetro opcional do tipo inteiro que define o tempo (em milissegundos) que a função deve aguardar uma resposta da API do Telegram antes de considerar que houve um tempo excedido. O valor padrão é 10.000 milissegundos (10 segundos), mas o usuário pode fornecer um valor de timeout personalizado, se desejar.
Você pode ter notado que usamos a palavra-chave const em alguns dos argumentos de entrada. Isso significa que os valores passados são finais e não podem ser alterados, modificados ou substituídos dentro do corpo da função, o que garante que não ocorram erros de sobrescrita na função. Em seguida, só precisamos transferir os trechos de código responsáveis por enviar mensagens simples do formulário padrão para dentro da função.
char data[]; // Array to hold data to be sent in the web request (empty in this case) char res[]; // Array to hold the response data from the web request string resHeaders; // String to hold the response headers from the web request string message = custom_message; const string url = api_url + "/bot" + bot_token + "/sendmessage?chat_id=" + chat_id + "&text=" + message; // Send the web request to the Telegram API int send_res = WebRequest("POST", url, "", timeout, data, res, resHeaders);
Começamos declarando um par de arrays: "data" e "res". O array "data" está vazio, já que não estamos enviando nenhum corpo de dados em nossa solicitação web — estamos apenas enviando a mensagem como um parâmetro da URL. O array "res" armazenará os dados da resposta do servidor após realizarmos a solicitação. Também declaramos uma string chamada "resHeaders", que armazenará quaisquer cabeçalhos de resposta enviados pela API do Telegram.
Em seguida, pegamos a "custom_message" do parâmetro de entrada e a atribuímos à variável message. Isso nos dá, essencialmente, a capacidade de manipular ou repassar a mensagem dentro da função, se necessário.
Construímos a URL da solicitação da API juntando diversos componentes: a "api_url" básica, o endpoint "/bot", o "bot_token" de autenticação e o "chat_id" do destinatário. A isso, adicionamos o texto da mensagem como parâmetro de URL: "&text=". O resultado é uma URL completa que contém todos os dados necessários para a chamada da API.
Por fim, passamos a lógica da solicitação web para a função WebRequest. Essa função é responsável por enviar uma solicitação HTTP POST para a API do Telegram. Ela utiliza a URL que acabamos de construir para a API. O valor de timeout da solicitação, que por padrão é de 10 segundos (ou outro valor especificado pelo usuário), determina quanto tempo a solicitação aguardará uma resposta antes de desistir. A solicitação é enviada com um array de dados vazio (que também poderia ser apenas um objeto vazio no formato JavaScript Object Notation – JSON), e qualquer resposta que a API nos enviar de volta é armazenada no array res e na string resHeaders.
Por fim, basta adicionarmos a lógica de verificação do status da resposta da solicitação web.
// Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); } else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", api_url, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); }
O código final da função para enviar uma mensagem simples do MetaTrader 5 para o Telegram é o seguinte:
//+------------------------------------------------------------------+ //| FUNCTION TO SEND SIMPLE MESSAGE | //+------------------------------------------------------------------+ void sendSimpleMessage(string custom_message,const string api_url, const string bot_token,const string chat_id, int timeout=10000){ char data[]; // Array to hold data to be sent in the web request (empty in this case) char res[]; // Array to hold the response data from the web request string resHeaders; // String to hold the response headers from the web request string message = custom_message; const string url = api_url + "/bot" + bot_token + "/sendmessage?chat_id=" + chat_id + "&text=" + message; // Send the web request to the Telegram API int send_res = WebRequest("POST", url, "", timeout, data, res, resHeaders); // Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); } else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", api_url, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); } }
Para garantir que isso funcione perfeitamente, vamos ao manipulador de eventos OnInit, comentar os trechos de código desnecessários e chamar a função. Chamar a função envolverá digitar seu nome e fornecer os parâmetros necessários.
string msg = "EA INITIALIZED ON CHART " + _Symbol; // Message to send, including the chart symbol sendSimpleMessage(msg,TG_API_URL,botTkn,chatID,10000);
Aqui, invocamos a função "sendSimpleMessage" para entregar uma mensagem ao chat no Telegram. Primeiro, construímos uma string chamada "msg", que é simplesmente a concatenação das palavras "EA INITIALIZED ON CHART" com o símbolo atual do gráfico (_Symbol). O destinatário dessa mensagem será notificado de que o Expert Advisor foi inicializado em um determinado gráfico.
Depois de definirmos a mensagem de texto que queremos enviar, chamamos a função "sendSimpleMessage". Passamos os quatro argumentos da função. O primeiro argumento é apenas a mensagem de texto que queremos enviar, então é chamado de "msg". O segundo argumento é uma constante chamada "TG_API_URL", que é a URL base da API do Bot do Telegram. O terceiro argumento é o token de acesso do bot ("botTkn") e o quarto argumento ("chatID") é o ID do chat ou canal no Telegram para onde o bot enviará a mensagem. Por fim, especificamos um valor de timeout de 10 segundos (10000 milissegundos). Se o servidor do Telegram não responder após esse tempo, consideramos uma falha, e a função retornará um código de erro. Durante o teste, recebemos a seguinte mensagem:
Isso foi um sucesso. Agora você pode ver que não precisamos de trechos de código longos para realizar ações semelhantes. Tudo que precisamos é chamar a função responsável e passar os respectivos argumentos. Vamos enviar outra mensagem simples informando ao usuário o período (timeframe) do gráfico.
string new_msg = "THE CURRENT TIMEFRAME IS "+EnumToString(_Period); sendSimpleMessage(new_msg,TG_API_URL,botTkn,chatID,10000);
Aqui, definimos uma nova variável string chamada "new_msg". A nova variável é criada ao unirmos o texto "THE CURRENT TIMEFRAME IS " com a versão em string do valor de _Period (o período atual do gráfico). Isso é feito usando a função EnumToString, que traduz o valor de _Period para uma forma legível por humanos. Por exemplo, se o gráfico estiver definido para um período de 1 hora, "new_msg" conterá o texto "THE CURRENT TIMEFRAME IS PERIOD_H1". Depois disso, a mesma função para envio de mensagens simples é chamada e é só isso. Você pode ver como isso é fácil. Ao rodar um teste, temos o seguinte resultado:
Podemos ver como o envio do código foi simples. Usamos apenas duas linhas de código para fazer isso. Agora, passaremos ao envio de uma mensagem codificada complexa. Não haverá muita mudança na função. Ela herdará a mesma lógica. No entanto, como estamos enviando mensagens complexas, queremos tratar erros que possam ocorrer. Assim, em vez de apenas declarar uma função do tipo void, teremos uma função com tipo de dado integer, que retornará códigos específicos que indicam falha ou sucesso ao chamar a função. Portanto, no escopo global, teremos que definir os códigos de erro.
#define FAILED_CODE -1 #define SUCCEEDED_CODE +1
Aqui, definimos duas constantes, "FAILED_CODE" e "SUCCEEDED_CODE", usando a diretiva do pré-processador #define. Atribuímos valores inteiros específicos às constantes para representar os resultados das operações: "FAILED_CODE" é definido como -1 e representa uma falha, enquanto "SUCCEEDED_CODE" é definido como +1 e representa um sucesso. Essas constantes podem ser quaisquer valores que você considerar adequados. Após a declaração delas, então prosseguimos para construir nossa função.
int sendEncodedMessage(string custom_message,const string api_url, const string bot_token,const string chat_id, int timeout=10000){ //... }
Aqui, definimos uma função inteira chamada "sendEncodedMessage", o que significa que a função retornará valores inteiros. Os dados da requisição web permanecerão os mesmos. No entanto, precisaremos verificar se houve sucesso ou falha no status da resposta e tomar as ações necessárias.
// Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); return (SUCCEEDED_CODE); }
Aqui, se o status da resposta for de sucesso e a mensagem for enviada corretamente, retornamos "SUCCEEDED_CODE". Caso contrário, se o status da resposta for de falha, retornamos "FAILED_CODE".
else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", api_url, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); return (FAILED_CODE); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); return (FAILED_CODE); }
Finalmente, precisamos retornar o código de sucesso se tudo passar até este ponto, da seguinte forma:
return (SUCCEEDED_CODE);
O retorno de sucesso ao final é muito importante, pois pode haver a possibilidade de nenhuma das subfunções ser executada, e a função precisa retornar um inteiro. Se tentarmos compilar o programa sem o código de retorno, recebemos um erro como abaixo:
Assim, o código completo da função responsável por enviar mensagens complexas é o seguinte:
//+------------------------------------------------------------------+ //| FUNCTION TO SEND ENCODED MESSAGE | //+------------------------------------------------------------------+ //#define FAILED_CODE -1 //#define SUCCEEDED_CODE +1 int sendEncodedMessage(string custom_message,const string api_url, const string bot_token,const string chat_id, int timeout=10000){ char data[]; // Array to hold data to be sent in the web request (empty in this case) char res[]; // Array to hold the response data from the web request string resHeaders; // String to hold the response headers from the web request string message = custom_message; const string url = api_url + "/bot" + bot_token + "/sendmessage?chat_id=" + chat_id + "&text=" + message; // Send the web request to the Telegram API int send_res = WebRequest("POST", url, "", timeout, data, res, resHeaders); // Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); return (SUCCEEDED_CODE); } else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", api_url, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); return (FAILED_CODE); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); return (FAILED_CODE); } return (SUCCEEDED_CODE); }
Agora vamos enviar as informações da conta em segmentos concatenados com caracteres emoji para o Telegram e ver a resposta. A mesma estrutura de código será adotada para isso, mas explicaremos brevemente o que exatamente fazemos.
////--- Account Status Update: double accountEquity = AccountInfoDouble(ACCOUNT_EQUITY); double accountFreeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); string complex_msg = "\xF680 EA INITIALIZED ON CHART " + _Symbol + "\xF680" +"\n\xF4CA Account Status \xF4CA" +"\nEquity: $" +DoubleToString(accountEquity,2) +"\nFree Margin: $" +DoubleToString(accountFreeMargin,2); string encloded_msg = UrlEncode(complex_msg); complex_msg = encloded_msg; sendEncodedMessage(complex_msg,TG_API_URL,botTkn,chatID,10000);
Começamos acessando o patrimônio da conta e a margem livre, usando AccountInfoDouble e passando como argumentos ACCOUNT_EQUITY e ACCOUNT_MARGIN_FREE, respectivamente. Eles recuperam o patrimônio da conta e a margem livre em tempo real. Construímos uma mensagem detalhada, "complex_msg", na qual usamos o símbolo do gráfico, juntamente com o patrimônio da conta e a margem livre, e a formatamos com emojis. Enviamos a mensagem usando a API do Telegram, mas primeiro precisamos garantir que ela seja segura para transmissão via HTTP. Fazemos isso codificando a mensagem com a função "UrlEncode". Após enviarmos a mensagem, isso é o que obtemos no app do Telegram.
Você pode ver que a mensagem complexa foi recebida com sucesso no Telegram. Então, concluímos completamente as funções de envio de mensagens. É relativamente claro que, ao encapsular a funcionalidade anterior em uma função, tornamos o código mais limpo e permitimos que o processo de envio de mensagens seja reutilizado facilmente em múltiplos locais. Isso será particularmente útil quando avançarmos para modularizar ainda mais o código, como ao adicionar funções para o envio de imagens e tratamento de erros. Isso será feito na próxima seção.
Modularizando Funções de Captura de Tela
Aqui, precisamos construir uma função que receba os parâmetros necessários e envie as imagens do gráfico para o Telegram. Sua estrutura de código será idêntica à que usamos para enviar mensagens codificadas.
int sendScreenShot(string screenshot_name,const string telegram_url, const string bot_token,const string chat_id, string caption=""){ //... }
Declaramos uma função inteira chamada "sendScreenShot", o que significa que ela retornará um valor inteiro. A função recebe vários parâmetros, garantindo flexibilidade e modularidade.
- O parâmetro "screenshot_name" refere-se ao nome do arquivo da captura de tela que será enviado, permitindo especificar diferentes capturas.
- Os parâmetros "telegram_url", "bot_token" e "chat_id" são as entradas principais necessárias para a comunicação com a API do Telegram, tornando a função adaptável a várias configurações de bot e contas do Telegram.
- Um parâmetro opcional, "caption", permite anexar texto descritivo à captura de tela, aumentando a funcionalidade ao possibilitar a anotação das capturas antes do envio.
Como a mesma estrutura de código permanece, vamos nos concentrar apenas na lógica de retorno. A primeira abordagem será no caso em que tentamos abrir e ler o conteúdo da imagem.
int screenshot_Handle = INVALID_HANDLE; screenshot_Handle = FileOpen(screenshot_name,FILE_READ|FILE_BIN); if(screenshot_Handle == INVALID_HANDLE){ Print("INVALID SCREENSHOT HANDLE. REVERTING NOW!"); return(FAILED_CODE); }
Aqui, se não conseguirmos abrir os dados da captura de tela a serem enviados ao Telegram, retornamos “FAILED_CODE” da função, sinalizando que a operação de envio da captura não pode prosseguir devido ao problema de acesso ao arquivo. Em seguida, apenas herdamos a mesma lógica para verificar o status da resposta e os respectivos logs de mensagem e códigos de status conforme abaixo:
// Send the web request to the Telegram API int send_res = WebRequest("POST",URL,HEADERS,10000, DATA, res, resHeaders); // Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM SCREENSHOT FILE SENT SUCCESSFULLY"); return (SUCCEEDED_CODE); } else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", telegram_url, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM SCREENSHOT FILE"); return (FAILED_CODE); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); return (FAILED_CODE); } return (SUCCEEDED_CODE);
A função completa responsável pelo envio dos arquivos de captura de tela do gráfico é a seguinte:
//+------------------------------------------------------------------+ //| FUNCTION TO SEND CHART SCREENSHOT FILES | //+------------------------------------------------------------------+ int sendScreenShot(string screenshot_name,const string telegram_url, const string bot_token,const string chat_id, string caption=""){ int screenshot_Handle = INVALID_HANDLE; screenshot_Handle = FileOpen(screenshot_name,FILE_READ|FILE_BIN); if(screenshot_Handle == INVALID_HANDLE){ Print("INVALID SCREENSHOT HANDLE. REVERTING NOW!"); return(FAILED_CODE); } else if (screenshot_Handle != INVALID_HANDLE){ Print("SCREENSHOT WAS SAVED & OPENED SUCCESSFULLY FOR READING."); Print("HANDLE ID = ",screenshot_Handle,". IT IS NOW READY FOR ENCODING."); } int screenshot_Handle_Size = (int)FileSize(screenshot_Handle); if (screenshot_Handle_Size > 0){ Print("CHART SCREENSHOT FILE SIZE = ",screenshot_Handle_Size); } uchar photoArr_Data[]; ArrayResize(photoArr_Data,screenshot_Handle_Size); FileReadArray(screenshot_Handle,photoArr_Data,0,screenshot_Handle_Size); if (ArraySize(photoArr_Data) > 0){ Print("READ SCREENSHOT FILE DATA SIZE = ",ArraySize(photoArr_Data)); } FileClose(screenshot_Handle); //ArrayPrint(photoArr_Data); //--- create boundary: (data -> base64 -> 1024 bytes -> md5) //Encodes the photo data into base64 format //This is part of preparing the data for transmission over HTTP. uchar base64[]; uchar key[]; CryptEncode(CRYPT_BASE64,photoArr_Data,key,base64); if (ArraySize(base64) > 0){ Print("Transformed BASE-64 data = ",ArraySize(base64)); //Print("The whole data is as below:"); //ArrayPrint(base64); } //Copy the first 1024 bytes of the base64-encoded data into a temporary array uchar temporaryArr[1024]= {0}; //Print("FILLED TEMPORARY ARRAY WITH ZERO (0) IS AS BELOW:"); //ArrayPrint(temporaryArr); ArrayCopy(temporaryArr,base64,0,0,1024); //Print("FIRST 1024 BYTES OF THE ENCODED DATA IS AS FOLLOWS:"); //ArrayPrint(temporaryArr); //Create an MD5 hash of the temporary array //This hash will be used as part of the boundary in the multipart/form-data uchar md5[]; CryptEncode(CRYPT_HASH_MD5,temporaryArr,key,md5); if (ArraySize(md5) > 0){ Print("SIZE OF MD5 HASH OF TEMPORARY ARRAY = ",ArraySize(md5)); Print("MD5 HASH boundary in multipart/form-data is as follows:"); ArrayPrint(md5); } //Format MD5 hash as a hexadecimal string & //truncate it to 16 characters to create the boundary. string HexaDecimal_Hash=NULL;//Used to store the hexadecimal representation of MD5 hash int total=ArraySize(md5); for(int i=0; i<total; i++){ HexaDecimal_Hash+=StringFormat("%02X",md5[i]); } Print("Formatted MD5 Hash String is: \n",HexaDecimal_Hash); HexaDecimal_Hash=StringSubstr(HexaDecimal_Hash,0,16);//truncate HexaDecimal_Hash string to its first 16 characters //done to comply with a specific length requirement for the boundary //in the multipart/form-data of the HTTP request. Print("Final Truncated (16 characters) MD5 Hash String is: \n",HexaDecimal_Hash); //--- WebRequest char DATA[]; string URL = NULL; URL = telegram_url+"/bot"+bot_token+"/sendPhoto"; //--- add chart_id //Append a carriage return and newline character sequence to the DATA array. //In the context of HTTP, \r\n is used to denote the end of a line //and is often required to separate different parts of an HTTP request. ArrayAdd(DATA,"\r\n"); //Append a boundary marker to the DATA array. //Typically, the boundary marker is composed of two hyphens (--) //followed by a unique hash string and then a newline sequence. //In multipart/form-data requests, boundaries are used to separate //different pieces of data. ArrayAdd(DATA,"--"+HexaDecimal_Hash+"\r\n"); //Add a Content-Disposition header for a form-data part named chat_id. //The Content-Disposition header is used to indicate that the following data //is a form field with the name chat_id. ArrayAdd(DATA,"Content-Disposition: form-data; name=\"chat_id\"\r\n"); //Again, append a newline sequence to the DATA array to end the header section //before the value of the chat_id is added. ArrayAdd(DATA,"\r\n"); //Append the actual chat ID value to the DATA array. ArrayAdd(DATA,chat_id); //Finally, Append another newline sequence to the DATA array to signify //the end of the chat_id form-data part. ArrayAdd(DATA,"\r\n"); // EXAMPLE OF USING CONVERSIONS //uchar array[] = { 72, 101, 108, 108, 111, 0 }; // "Hello" in ASCII //string output = CharArrayToString(array,0,WHOLE_ARRAY,CP_ACP); //Print("EXAMPLE OUTPUT OF CONVERSION = ",output); // Hello Print("CHAT ID DATA:"); ArrayPrint(DATA); string chatID_Data = CharArrayToString(DATA,0,WHOLE_ARRAY,CP_UTF8); Print("SIMPLE CHAT ID DATA IS AS FOLLOWS:",chatID_Data); //--- Caption string CAPTION_STRING = NULL; CAPTION_STRING = caption; if(StringLen(CAPTION_STRING) > 0){ ArrayAdd(DATA,"--"+HexaDecimal_Hash+"\r\n"); ArrayAdd(DATA,"Content-Disposition: form-data; name=\"caption\"\r\n"); ArrayAdd(DATA,"\r\n"); ArrayAdd(DATA,CAPTION_STRING); ArrayAdd(DATA,"\r\n"); } //--- ArrayAdd(DATA,"--"+HexaDecimal_Hash+"\r\n"); ArrayAdd(DATA,"Content-Disposition: form-data; name=\"photo\"; filename=\"Upload_ScreenShot.jpg\"\r\n"); ArrayAdd(DATA,"\r\n"); ArrayAdd(DATA,photoArr_Data); ArrayAdd(DATA,"\r\n"); ArrayAdd(DATA,"--"+HexaDecimal_Hash+"--\r\n"); Print("FINAL FULL PHOTO DATA BEING SENT:"); ArrayPrint(DATA); string final_Simple_Data = CharArrayToString(DATA,0,WHOLE_ARRAY,CP_ACP); Print("FINAL FULL SIMPLE PHOTO DATA BEING SENT:",final_Simple_Data); string HEADERS = NULL; HEADERS = "Content-Type: multipart/form-data; boundary="+HexaDecimal_Hash+"\r\n"; Print("SCREENSHOT SENDING HAS BEEN INITIATED SUCCESSFULLY."); //char data[]; // Array to hold data to be sent in the web request (empty in this case) char res[]; // Array to hold the response data from the web request string resHeaders; // String to hold the response headers from the web request //string msg = "EA INITIALIZED ON CHART " + _Symbol; // Message to send, including the chart symbol //const string url = TG_API_URL + "/bot" + botTkn + "/sendmessage?chat_id=" + chatID + // "&text=" + msg; // Send the web request to the Telegram API int send_res = WebRequest("POST",URL,HEADERS,10000, DATA, res, resHeaders); // Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM SCREENSHOT FILE SENT SUCCESSFULLY"); return (SUCCEEDED_CODE); } else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", telegram_url, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM SCREENSHOT FILE"); return (FAILED_CODE); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); return (FAILED_CODE); } return (SUCCEEDED_CODE); }
Agora temos a função para enviar uma captura de tela, mas não temos uma função para obter os arquivos de captura. Primeiro, vamos criar uma função para obter o arquivo de imagem do gráfico ao qual o programa está anexado, já que ela não exigirá muitos parâmetros.
//+------------------------------------------------------------------+ //| FUNCTION TO GET SCREENSHOT OF CURRENT CHART | //+------------------------------------------------------------------+ int getScreenshot_of_Current_Chart(string screenshot_name){ //--- First delete an instance of the screenshot file if it already exists if(FileIsExist(screenshot_name)){ FileDelete(screenshot_name); Print("Chart Screenshot was found and deleted."); ChartRedraw(0); } ChartScreenShot(0,screenshot_name,1366,768,ALIGN_RIGHT); // Wait for 30 secs to save screenshot if not yet saved int wait_loops = 60; while(!FileIsExist(screenshot_name) && --wait_loops > 0){ Sleep(500); } if(!FileIsExist(screenshot_name)){ Print("THE SPECIFIED SCREENSHOT DOES NOT EXIST (WAS NOT SAVED). REVERTING NOW!"); return (FAILED_CODE); } else if(FileIsExist(screenshot_name)){ Print("THE CHART SCREENSHOT WAS SAVED SUCCESSFULLY TO THE DATA-BASE."); return (SUCCEEDED_CODE); } return (SUCCEEDED_CODE); }
Aqui, declaramos uma função inteira, “getScreenshot_of_Current_Chart”, para realizar o processo de captura e salvamento de uma captura de tela do gráfico atual no MetaTrader 5. A função recebe um parâmetro, “screenshot_name”, que contém o nome desejado para o arquivo onde a captura será salva. Iniciamos a função verificando se já existe um arquivo com o nome “screenshot_name”. Se existir, excluímos o arquivo pré-existente. Esse passo é crucial porque, se não o excluíssemos, inevitavelmente teríamos um problema de sobrescrita — uma situação em que uma nova captura acabaria com o mesmo nome de um arquivo recém-deletado.
Também invocamos a função ChartRedraw para atualizar a exibição do gráfico antes de realizarmos a captura. Em seguida, para obter a captura do gráfico em seu estado atual, chamamos a função ChartScreenShot, informando o nome que desejamos dar ao arquivo, as dimensões desejadas e o alinhamento. Logo depois, usamos um laço while para verificar a existência do arquivo. Aguardamos até 30 segundos para que o arquivo apareça antes de prosseguir para a próxima etapa, sem, de forma alguma, retardar o processamento caso demore para gerar a captura.
Caso o arquivo continue inexistente após esse intervalo, geramos uma mensagem de erro informando que a captura não foi salva e retornamos claramente “FAILED_CODE”. Se, no entanto, o arquivo for encontrado, emitimos uma mensagem de sucesso e retornamos “SUCCEEDED_CODE”. Em essência, permitimos dois resultados possíveis para nossa operação e os rotulamos de forma inequívoca. A função para abrir um gráfico personalizado e tirar uma captura herda a mesma lógica.
//+------------------------------------------------------------------+ //| FUNCTION TO GET SCREENSHOT OF A NEW CHART | //+------------------------------------------------------------------+ int getScreenshot_of_New_Chart(string screenshot_name,string symbol_name, ENUM_TIMEFRAMES period_name){ //--- First delete an instance of the screenshot file if it already exists if(FileIsExist(screenshot_name)){ FileDelete(screenshot_name); Print("Chart Screenshot was found and deleted."); ChartRedraw(0); } long chart_id=ChartOpen(symbol_name,period_name); ChartSetInteger(chart_id,CHART_BRING_TO_TOP,true); // update chart int wait=60; while(--wait>0){//decrease the value of wait by 1 before loop condition check if(SeriesInfoInteger(symbol_name,period_name,SERIES_SYNCHRONIZED)){ break; // if prices up to date, terminate the loop and proceed } } ChartRedraw(chart_id); ChartSetInteger(chart_id,CHART_SHOW_GRID,false); ChartSetInteger(chart_id,CHART_SHOW_PERIOD_SEP,false); ChartSetInteger(chart_id,CHART_COLOR_CANDLE_BEAR,clrRed); ChartSetInteger(chart_id,CHART_COLOR_CANDLE_BULL,clrBlue); ChartSetInteger(chart_id,CHART_COLOR_BACKGROUND,clrLightSalmon); ChartScreenShot(chart_id,screenshot_name,1366,768,ALIGN_RIGHT); Print("OPENED CHART PAUSED FOR 10 SECONDS TO TAKE SCREENSHOT."); Sleep(10000); // sleep for 10 secs to see the opened chart ChartClose(chart_id); // Wait for 30 secs to save screenshot if not yet saved int wait_loops = 60; while(!FileIsExist(screenshot_name) && --wait_loops > 0){ Sleep(500); } if(!FileIsExist(screenshot_name)){ Print("THE SPECIFIED SCREENSHOT DOES NOT EXIST (WAS NOT SAVED). REVERTING NOW!"); return (FAILED_CODE); } else if(FileIsExist(screenshot_name)){ Print("THE CHART SCREENSHOT WAS SAVED SUCCESSFULLY TO THE DATA-BASE."); return (SUCCEEDED_CODE); } return (SUCCEEDED_CODE); }
Aqui, declaramos uma função inteira que recebe três parâmetros: o nome da imagem, o nome do símbolo e o período do gráfico a ser aberto. Até o momento, temos as funções necessárias para obter capturas de tela e enviá-las ao Telegram. Vamos prosseguir para obter e enviar a captura do gráfico atual e ver o que obtemos. Para isso, aplicamos o seguinte trecho de código.
getScreenshot_of_Current_Chart(SCREENSHOT_FILE_NAME);
sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,NULL);
Aqui, simplesmente chamamos as duas funções responsáveis por obter e enviar a captura salva, respectivamente, passando os parâmetros de entrada necessários. Você pode ver como a lógica agora ficou pequena. Apenas duas linhas de código são suficientes para realizar o processo. Ao compilar, obtemos a seguinte saída:
Podemos ver que conseguimos receber o arquivo de captura do gráfico atual no chat do Telegram. Até este ponto, quase tudo o que é necessário foi coberto e, assim, podemos observar como os códigos de retorno podem indicar falha ou sucesso das funções. Para este exemplo, usaremos a lógica de gráfico novo.
int get_screenshot_new_chart_result = getScreenshot_of_New_Chart(SCREENSHOT_FILE_NAME,_Symbol,_Period); if (get_screenshot_new_chart_result == FAILED_CODE){ string result_msg = "NEW CHART SCREENSHOT COULDN'T BE SAVED. REVERT NOW."; Print(result_msg); sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,10000); return (INIT_FAILED); } else if (get_screenshot_new_chart_result == SUCCEEDED_CODE){ string result_msg = "SUCCESS. NEW CHART SCREENSHOT WAS SAVED. CONTINUE NOW."; Print(result_msg); sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,10000); string sending_msg = "\x2705\SCREENSHOT SENDING HAS BEEN INITIATED SUCCESSFULLY."; sending_msg += "\n\x270C\YOU SHOULD RECEIVE THE IMAGE FILE WITHIN 10 SECONDS"; string encoded_sending_msg = UrlEncode(sending_msg); Print(encoded_sending_msg); sendEncodedMessage(encoded_sending_msg,TG_API_URL,botTkn,chatID,10000); }
Aqui, tratamos a saída da função “getScreenshot_of_New_Chart”. Essa função executa o trabalho de capturar e salvar uma captura do gráfico novo. Chamamos a função com parâmetros claros: o nome desejado para o arquivo de captura, o símbolo atual do gráfico e o timeframe. O resultado da função é armazenado em uma variável chamada “get_screenshot_new_chart_result”. Se esse resultado for um sucesso, seguimos para a próxima parte do programa. Se falhar, tratamos o erro de maneira adequada.
Quando recebemos “FAILED_CODE”, isso indica que o salvamento da captura falhou. Nesse caso, geramos uma mensagem de erro que deixa claro ao usuário que houve um problema no processo de salvamento da captura. Essa mensagem é exibida no terminal e também enviada ao chat do Telegram usando a função “sendSimpleMessage”. Em seguida, retornamos “INIT_FAILED” como código de retorno, informando que a operação não foi bem-sucedida e que a próxima etapa não deve ser tentada. Isso encerra o processo de inicialização.
Por outro lado, se o resultado for “SUCCEEDED_CODE”, isso significa que a captura foi salva com sucesso. Preparamos e exibimos uma mensagem indicando que o terminal enviou um comando de sucesso após tirar a captura. Em seguida, utilizamos “sendSimpleMessage” para informar ao usuário que a captura foi salva e que ele deve receber o arquivo em breve. O processo de envio da mensagem é claro, conciso e executado corretamente. O comando de envio da captura ao usuário foi bem-sucedido, e ele deverá receber o arquivo em cerca de 10 segundos. No log, obtemos o seguinte registro:
No chat do Telegram, recebemos a seguinte saída:
Você pode ver que agora é fácil enviar várias instâncias de mensagens ao chat do Telegram sem esforço. Tudo o que precisamos fazer agora é chamar a função de envio de captura para transmitir o arquivo de imagem. Isso é feito por meio da lógica abaixo:
sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,NULL);
Ao executar o código, obtemos os seguintes resultados:
Isso foi um sucesso. Você pode notar que a imagem recebida não possui legenda. Isso ocorre porque escolhemos ter o campo de legenda como NULL, o que significa que nenhuma legenda será considerada. Para incluir a legenda, basta definir o campo de legenda e passá-lo à função. Nossa legenda padrão será usada para a ilustração conforme abaixo:
//--- Caption string CAPTION = NULL; CAPTION = "Screenshot of Symbol: "+Symbol()+ " ("+EnumToString(ENUM_TIMEFRAMES(_Period))+ ") @ Time: "+TimeToString(TimeCurrent()); sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,CAPTION);
Após a compilação, recebemos uma captura de tela do gráfico personalizado recém-aberto com os parâmetros padrão conforme descrito, mas, mais importante, com uma legenda que ilustra o símbolo do gráfico, o período e o horário em que foi capturado e enviado ao Telegram.
Isso foi um sucesso. Agora temos um programa totalmente funcional que utiliza funções para se comunicar com o chat do Telegram. Só precisamos fazer alguns testes e implementar as funções modulares que criamos para enviar sinais de negociação baseados em cruzamentos de Médias Móveis da plataforma MetaTrader 5 para chats do Telegram. Isso será abordado explicitamente na próxima seção.
Testando e Implementando Funções Modulares
Nesta seção, mudaremos o foco da construção de funções individuais para a aplicação dessas funções em situações de negociação reais, onde confirmações de sinal provocam respostas específicas. Nosso objetivo agora é verificar se as funções que modularizamos — como as de captura de tela e envio de mensagens — funcionarão em conjunto na estrutura maior que estamos construindo. Ao colocar a lógica do nosso Expert Advisor (EA) em funções reutilizáveis, podemos melhor servir ao propósito de enviar capturas de tela do gráfico ou atualizar o status da conta, de forma que mantenha a lógica do EA — um EA que opera no princípio de acionar determinadas funções quando condições específicas são atendidas.
Este tópico mostrará como invocamos essas funções modulares quando os sinais de negociação são confirmados, garantindo que todos os componentes funcionem eficientemente em cenários do mundo real. Testaremos rigorosamente a confiabilidade dessas funções, executando-as repetidamente, e verificaremos se elas suportam as exigências de gerenciamento de erros ao mesmo tempo em que cumprem sua tarefa principal de enviar mensagens de confirmação de sinal ao Telegram de forma precisa e oportuna. Ao fazer isso, não apenas verificaremos a funcionalidade do nosso código, mas também daremos um passo em direção à criação de um sistema de gerenciamento de sinais de negociação quase completamente robusto e que lide graciosamente com condições de erro. Agora só precisamos deslocar o trecho de código de inicialização para a seção de geração de sinais. Para um sinal de compra, seu trecho de código será o seguinte:
// BUY POSITION OPENED. GET READY TO SEND MESSAGE TO TELEGRAM Print("BUY POSITION OPENED. SEND MESSAGE TO TELEGRAM NOW."); //char data[]; // Array to hold data to be sent in the web request (empty in this case) //char res[]; // Array to hold the response data from the web request //string resHeaders; // String to hold the response headers from the web request ushort MONEYBAG = 0xF4B0; string MONEYBAG_Emoji_code = ShortToString(MONEYBAG); string msg = "\xF680 Opened Buy Position." +"\n====================" +"\n"+MONEYBAG_Emoji_code+"Price = "+DoubleToString(openPrice,_Digits) +"\n\xF412\Time = "+TimeToString(iTime(_Symbol,_Period,0),TIME_SECONDS) +"\n\xF551\Time Current = "+TimeToString(TimeCurrent(),TIME_SECONDS) +"\n\xF525 Lotsize = "+DoubleToString(lotSize,2) +"\n\x274E\Stop loss = "+DoubleToString(stopLoss,_Digits) +"\n\x2705\Take Profit = "+DoubleToString(takeProfit,_Digits) +"\n_________________________" +"\n\xF5FD\Time Local = "+TimeToString(TimeLocal(),TIME_DATE) +" @ "+TimeToString(TimeLocal(),TIME_SECONDS) ; string encloded_msg = UrlEncode(msg); msg = encloded_msg; sendEncodedMessage(msg,TG_API_URL,botTkn,chatID,10000); int get_screenshot_current_chart_result = getScreenshot_of_Current_Chart(SCREENSHOT_FILE_NAME); if (get_screenshot_current_chart_result == FAILED_CODE){ string result_msg = "CURRENT CHART SCREENSHOT COULDN'T BE SAVED. REVERT NOW."; Print(result_msg); sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,10000); return; } else if (get_screenshot_current_chart_result == SUCCEEDED_CODE){ string result_msg = "SUCCESS. CURRENT CHART SCREENSHOT WAS SAVED. CONTINUE NOW."; Print(result_msg); sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,10000); string sending_msg = "\x2705\SCREENSHOT SENDING HAS BEEN INITIATED SUCCESSFULLY."; sending_msg += "\n\x270C\YOU SHOULD RECEIVE THE IMAGE FILE WITHIN 10 SECONDS"; string encoded_sending_msg = UrlEncode(sending_msg); Print(encoded_sending_msg); sendEncodedMessage(encoded_sending_msg,TG_API_URL,botTkn,chatID,10000); } //--- Caption string CAPTION = NULL; CAPTION = "Screenshot of Symbol: "+Symbol()+ " ("+EnumToString(ENUM_TIMEFRAMES(_Period))+ ") @ Time: "+TimeToString(TimeCurrent()); sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,CAPTION);
Aqui, concentramos apenas em informar sobre o sinal gerado e enviar uma captura de tela do gráfico atual, mostrando os níveis de negociação. Para a confirmação de um sinal de venda, uma lógica similar é adaptada da seguinte forma:
// SELL POSITION OPENED. GET READY TO SEND MESSAGE TO TELEGRAM Print("SELL POSITION OPENED. SEND MESSAGE TO TELEGRAM NOW."); //char data[]; // Array to hold data to be sent in the web request (empty in this case) //char res[]; // Array to hold the response data from the web request //string resHeaders; // String to hold the response headers from the web request ushort MONEYBAG = 0xF4B0; string MONEYBAG_Emoji_code = ShortToString(MONEYBAG); string msg = "\xF680 Opened Sell Position." +"\n====================" +"\n"+MONEYBAG_Emoji_code+"Price = "+DoubleToString(openPrice,_Digits) +"\n\xF412\Time = "+TimeToString(iTime(_Symbol,_Period,0),TIME_SECONDS) +"\n\xF551\Time Current = "+TimeToString(TimeCurrent(),TIME_SECONDS) +"\n\xF525 Lotsize = "+DoubleToString(lotSize,2) +"\n\x274E\Stop loss = "+DoubleToString(stopLoss,_Digits) +"\n\x2705\Take Profit = "+DoubleToString(takeProfit,_Digits) +"\n_________________________" +"\n\xF5FD\Time Local = "+TimeToString(TimeLocal(),TIME_DATE) +" @ "+TimeToString(TimeLocal(),TIME_SECONDS) ; string encloded_msg = UrlEncode(msg); msg = encloded_msg; sendEncodedMessage(msg,TG_API_URL,botTkn,chatID,10000); int get_screenshot_current_chart_result = getScreenshot_of_Current_Chart(SCREENSHOT_FILE_NAME); if (get_screenshot_current_chart_result == FAILED_CODE){ string result_msg = "CURRENT CHART SCREENSHOT COULDN'T BE SAVED. REVERT NOW."; Print(result_msg); sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,10000); return; } else if (get_screenshot_current_chart_result == SUCCEEDED_CODE){ string result_msg = "SUCCESS. CURRENT CHART SCREENSHOT WAS SAVED. CONTINUE NOW."; Print(result_msg); sendSimpleMessage(result_msg,TG_API_URL,botTkn,chatID,10000); string sending_msg = "\x2705\SCREENSHOT SENDING HAS BEEN INITIATED SUCCESSFULLY."; sending_msg += "\n\x270C\YOU SHOULD RECEIVE THE IMAGE FILE WITHIN 10 SECONDS"; string encoded_sending_msg = UrlEncode(sending_msg); Print(encoded_sending_msg); sendEncodedMessage(encoded_sending_msg,TG_API_URL,botTkn,chatID,10000); } //--- Caption string CAPTION = NULL; CAPTION = "Screenshot of Symbol: "+Symbol()+ " ("+EnumToString(ENUM_TIMEFRAMES(_Period))+ ") @ Time: "+TimeToString(TimeCurrent()); sendScreenShot(SCREENSHOT_FILE_NAME,TG_API_URL,botTkn,chatID,CAPTION);
Para confirmar que sinais foram gerados, vamos mudar para um período de 1 minuto e aguardar as respostas de sinal. O primeiro sinal que recebemos é uma configuração de venda. Ele é gerado conforme mostrado abaixo no terminal de negociação:
Log de sinal de venda do MetaTrader 5:
Mensagem de venda recebida no campo de chat do Telegram:
Pelas imagens acima fornecidas, podemos ver que a configuração de sinal de venda foi confirmada no terminal de negociação, mensagens importantes são registradas no diário, e os dados de posição e capturas de tela correspondentes são enviados ao grupo do Telegram. Agora esperamos que, quando ocorrer um cruzamento de alta, fechemos a posição de venda existente, abramos uma posição de compra e enviemos a informação ao grupo do Telegram também. A configuração de confirmação no terminal de negociação é a seguinte:
Log de sinal de compra do MetaTrader 5:
Mensagem de compra recebida no campo de chat do Telegram:
Para visualizar o marco de forma mais eficiente, aqui está um vídeo detalhado baseado no desempenho do Expert Advisor desde sua compilação, passando pela inicialização e abertura de trades baseados nos sinais gerados, e como os metadados são transmitidos do MQL5 para o Telegram.
Até este ponto, podemos ver que a modularização do código das funções foi um sucesso. A integração do MQL5 e do Telegram agora funciona perfeitamente. Usando funções modulares, que invocamos para confirmar sinais, conseguimos automatizar o envio de mensagens e captura de telas, de modo que cada evento ou atualização-chave seja injetado no chat do Telegram com a força de um nocaute do Dana White assim que ocorrer. E testamos o suficiente para termos confiança de que funciona. Em termos de atuar como ponte entre MQL5 e Telegram, esta implementação é confiável e flexível — um bom design modular no qual podemos construir integrações mais complexas posteriormente.
Conclusão
Este artigo descreve a integração da MetaQuotes Language 5 (MQL5) com o Telegram, com foco na criação de funções modulares para o envio de mensagens e capturas de tela de gráficos de negociação. O projeto modular aprimora a eficiência, escalabilidade e a manutenção do Expert Advisor (EA) sem complexidade desnecessária.
No próximo artigo, exploraremos um sistema de comunicação bidirecional, permitindo que o Telegram envie comandos ao MetaTrader 5 e controle as ações do EA. Essa integração possibilitará interações mais avançadas, como solicitar dados de negociação ao vivo ou capturas de tela diretamente pelo Telegram, ampliando os limites da integração MQL5-Telegram. Fique atento para novidades.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15706





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso