Construindo um Modelo de Restrição de Tendência com Candlestick (Parte 5): Sistema de Notificação (Parte III)
Conteúdo
- Introdução
- Configurando uma API de Mensagens
- O script (send_whatsapp_message.py)
- Modificando o Indicador de Restrição de Tendência para Notificações no WhatsApp
- Testando
- Segurança
- Conclusão
Introdução
Agora ampliamos a acessibilidade aos sinais em nosso modelo, tornando-o benéfico para todos os usuários. Além disso, motivamos diversos desenvolvedores iniciantes a integrar redes sociais para sinais em nossa conhecida plataforma de negociação MetaTrader 5. Vamos concluir mergulhando nos detalhes da integração com o WhatsApp. Vamos concluir mergulhando nos detalhes da integração com o WhatsApp. A Meta introduziu um novo recurso de canais no WhatsApp, o que pode ajudar os sinais a alcançarem um público mais amplo. Como afirmado por Porter Gale em seu livro, "Your Network Is Your Net Worth", é crucial fazer parte de uma comunidade para prosperar. Com avanços como esses, podemos impactar uma grande comunidade, especialmente em plataformas populares como Telegram e WhatsApp.
Decidi incluir um fluxograma descrevendo o processo de integração de qualquer plataforma social com o MetaTrader 5. Este é um desenvolvimento resumido passo a passo baseado na minha pesquisa. As etapas críticas estão claramente delineadas no fluxograma. Deixe-me explicar brevemente algumas das etapas envolvidas. O fluxograma narra as experiências encontradas durante o desenvolvimento. É importante estar preparado para refazer certos processos, pois erros podem ocorrer. Neste artigo, focarei apenas no que verifiquei ser eficaz, embora tenha sido feito um trabalho considerável de depuração durante o processo de redação. Estas são as etapas que seguimos na (Parte II) ao integrar o Telegram ao Indicador de Restrição de Tendência para notificações.
Integração de Plataformas Sociais com Fluxograma do MetaTrader 5

O fluxograma simplifica como entendemos todo o processo de integração da etapa final, a etapa de decisão, que tem dois resultados possíveis: Sim ou Não.
O teste foi bem-sucedido?
Se Sim:Se Não:
- Implantar Integração
- Monitorar e Manter (Tudo está funcionando bem e podemos começar a usar nosso novo sistema conforme o objetivo original)
- Fim (O final de uma integração bem-sucedida)
- Depurar e Corrigir Problemas (voltar para Configurar Ambiente de Desenvolvimento, a ideia é principalmente revisar todas as etapas para verificar erros, corrigi-los e testar novamente)
- Explorar Outras Opções (voltar para tentar outras plataformas sociais, portanto, as etapas anteriores, caso não haja API disponível)
Configurando uma API de Mensagens
Com base no fluxograma fornecido, decidimos avançar na integração do WhatsApp, como fizemos com o Telegram no artigo anterior. Ambas as plataformas oferecem APIs que se alinham aos nossos objetivos. A decisão de optar pelo WhatsApp se deve principalmente à sua ampla base de usuários. Pessoalmente, uso o WhatsApp com mais frequência do que qualquer outra plataforma social, e receber sinais por meio desta plataforma me ajudará a monitorar efetivamente meu negócio no MetaTrader 5.
De acordo com whatsthebigdata, em julho de 2023, o WhatsApp tinha cerca de 2,78 bilhões de usuários ativos únicos em todo o mundo. Este popular aplicativo de mensagens alcançou a marca de 2 bilhões em 2020 e espera-se que alcance 3,14 bilhões até 2025.
Os valores estatísticos devem ser considerados ao selecionar plataformas para ajudar a aumentar nosso patrimônio líquido por meio dessas redes. Diversos provedores de API de mensagens podem ser encontrados online, com diferentes níveis de facilidade de uso e praticidade. Muitos oferecem uso em período de teste, mas exigem assinaturas para acessar recursos avançados. Com base na minha pesquisa, algumas opções disponíveis na internet incluem:
Usei o Twilio para este projeto porque ele oferece acesso à API de uma maneira mais amigável ao usuário e é adequado para a integração do WhatsApp. As opções fornecidas são eficazes, embora o processo de configuração possa ser complexo e assinaturas sejam necessárias para acessar outros recursos essenciais. No entanto, vale a pena explorá-los para ampliar o entendimento.
Criei minha conta no Twilio e configurei tudo. Os elementos-chave necessários do site são account_sid, auth_token, o número do WhatsApp atribuído no sandbox do Twilio e seu próprio número receptor para iniciar conversas. Todas as credenciais necessárias para o script podem ser encontradas na página da sua conta Twilio.

Ao navegar até a seção de console da sua conta Twilio, você pode localizar onde ele envia mensagens do WhatsApp. Lá, você verá o número do sandbox, que será salvo no lado da API para encaminhar as notificações provenientes do MetaTrader 5 para os números de WhatsApp associados. Infelizmente, ele só envia para os participantes associados. Veja abaixo uma captura de tela mostrando a mensagem de associação que você precisa enviar para o número do sandbox para ingressar. Comece salvando o número do sandbox na sua lista de contatos, localize-o e envie "join so-cave". Automaticamente, assim que isso for feito, você pode executar o script de integração com mensagens de teste no prompt de comando e ver o funcionamento.

Aqui está uma captura de tela de eu ingressando:
Neste ponto, obtivemos as credenciais da API necessárias para o processo de integração, conforme descrito no fluxograma. Vamos agora avançar para a próxima etapa, onde abordaremos a aplicação dessas credenciais em detalhes.
O script (send_whatsapp_message.py)
Podemos utilizar o IDLE para a criação do script. Ele vem pré-instalado com o interpretador Python. Alternativamente, eu prefiro opções de código aberto, como o Notepad++ para a criação do script. O Notepad++ oferece suporte a várias linguagens com formatação adequada. Comece criando um novo arquivo, nomeie-o como send_whatsapp_message.py. É recomendável salvar seu arquivo de script na pasta scripts junto com o interpretador Python. Não encontrei problemas ao testar o programa a partir desse diretório.
Começaremos importando módulos em nosso script:
import sys import requests
- import sys: Este módulo fornece acesso a algumas variáveis usadas ou mantidas pelo interpretador Python. Permite que você interaja com o interpretador.
- import requests: Este módulo é usado para enviar solicitações HTTP. Simplifica o processo de fazer requisições para APIs.
A próxima etapa define as funções:
def send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message): url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json" data = { "From": f"whatsapp:{from_whatsapp_number}", "To": f"whatsapp:{to_whatsapp_number}", "Body": message, } response = requests.post(url, data=data, auth=(account_sid, auth_token)) if response.status_code == 201: print("Message sent successfully") else: print(f"Failed to send message: {response.status_code} - {response.text}")
send_whatsapp_message: Esta função envia uma mensagem no WhatsApp utilizando a API do Twilio.
Na definição da função, temos vários parâmetros necessários para a execução do script. Muitos desses parâmetros foram adquiridos durante a configuração da conta do Twilio.
Parâmetros:
- account_sid: O SID da conta Twilio.
- auth_token: O Token de autenticação da sua conta Twilio.
- from_whatsapp_number: O número do Twilio habilitado para WhatsApp, formatado com o prefixo "whatsapp:".
- to_whatsapp_number: O número do WhatsApp do destinatário, formatado com o prefixo "whatsapp:".
- message: O texto da mensagem a ser enviado.
requests.post: Envia uma requisição POST para a API do Twilio com os dados da mensagem e as credenciais de autenticação.
response: Captura a resposta da API do Twilio.
status_code: Verifica o código de status da resposta para determinar se a mensagem foi enviada com sucesso (201 indica sucesso).
O trecho final do script forma o código principal, onde a execução ocorrerá. Quando este script for executado, ele fará:
- Ler o texto da mensagem a partir dos argumentos da linha de comando.
- Chamar a função send_whatsapp_message com as credenciais fornecidas, números de telefone e mensagem.
- Exibir uma mensagem de sucesso ou falha com base na resposta da API do Twilio.
# Replace with your actual Twilio credentials and phone numbers account_sid = "**********************" # Your SID auth_token = "***************************" # Your Auth Token from_whatsapp_number = "+14**********" # Your WhatsApp-enabled Twilio number to_whatsapp_number = "+************" # Recipient's WhatsApp number message = sys.argv[1] send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message)
Montando tudo, nosso arquivo final send_whatsapp_message.py será assim:
import sys import requests def send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message): url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json" data = { "From": f"whatsapp:{from_whatsapp_number}", "To": f"whatsapp:{to_whatsapp_number}", "Body": message, } response = requests.post(url, data=data, auth=(account_sid, auth_token)) if response.status_code == 201: print("Message sent successfully") else: print(f"Failed to send message: {response.status_code} - {response.text}") # Replace with your actual Twilio credentials and phone numbers account_sid = "****************" auth_token = "**********************" from_whatsapp_number = "+14***********" to_whatsapp_number = "+***************" message = sys.argv[1] send_whatsapp_message(account_sid, auth_token, from_whatsapp_number, to_whatsapp_number, message)
Podemos prosseguir para testar no prompt de comando para verificar se o script está funcionando. Abra o caminho onde o arquivo send_whatsapp_message.py está armazenado e digite o seguinte comando:
python send_whatsapp_message.py "Mensagem de Teste" Se tudo estiver correto, a mensagem será enviada para o seu número do WhatsApp, e uma mensagem "Mensagem enviada com sucesso" será exibida na janela do prompt de comando. Se ocorrerem erros, será necessário verificar novamente o código e as credenciais, especialmente porque o código fornecido foi depurado e corrigido para funcionar adequadamente. Compartilharei uma captura de tela da minha integração funcionando em algumas seções abaixo.
Modificando o Indicador de Restrição de Tendência para Notificações no WhatsApp
Para completar a integração sem alterar significativamente o código do indicador, decidi me concentrar no ajuste do bloco myAlert para suportar mensagens no WhatsApp. É crucial prestar muita atenção ao inserir corretamente o caminho para o interpretador Python e o script. Estes são componentes-chave da integração ao migrar deste trecho de código. Mantive a maior parte do código de nossa integração anterior com o Telegram inalterada. Além disso, incluí um recurso de inicialização de teste que permite o envio de uma mensagem de boas-vindas na inicialização para verificar a funcionalidade do sistema antes de receber sinais reais.
int OnInit() { // Send test message on launch myAlert("info", "Thank you for subscribing. You shall be receiving Trend Constraint signal alerts via Whatsapp."); return(INIT_SUCCEEDED); }
Incluir isso no OnInit() garantirá que a mensagem seja enviada para os seus números quando você adicionar o indicador a qualquer gráfico.
Abaixo está a parte mais crucial da lógica de integração para o envio de mensagens no WhatsApp. Eu destaquei as seções do código que modifiquei em comparação ao código usado para a integração com o Telegram.
//--- ShellExecuteW declaration ---------------------------------------------- #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import //--- global variables ------------------------------------------------------ datetime last_alert_time; input int alert_cooldown_seconds = 60; // Cooldown period in seconds //--- myAlert function ------------------------------------------------------ void myAlert(string type, string message) { datetime current_time = TimeCurrent(); if (current_time - last_alert_time < alert_cooldown_seconds) { // Skip alert if within cooldown period return; } last_alert_time = current_time; string full_message = type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message; if (type == "print") { Print(message); } else if (type == "error") { Print(type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message); } else if (type == "order") { // Add order alert handling if needed } else if (type == "modify") { // Add modify alert handling if needed } else if (type == "indicator" || type == "info") { if (Audible_Alerts) { Alert(full_message); } if (Push_Notifications) { SendNotification(full_message); } // Send to WhatsApp //Edit to match your actual path, these I gave as an example for my computer string python_path = "C:\\Users\\******\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\******\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py"; string command = python_path + " \"" + script_path + "\" \"" + full_message + "\""; // Debugging: Print the command being executed Print("Executing command to send WhatsApp message: ", command); // Use cmd.exe to execute the command and then wait for 5 seconds string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 1); if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); } } }
Programa Principal Após Ajustes para nos fornecer o Trend Constraint V1.06:
//+------------------------------------------------------------------+ //| Trend Constraint V1.06.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com" #property version "1.06" #property description "A model that seeks to produce sell signals when D1 candle is Bearish only and buy signals when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 6 #property indicator_plots 6 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFF3C00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #property indicator_type3 DRAW_ARROW #property indicator_width3 2 #property indicator_color3 0xE8351A #property indicator_label3 "Buy Reversal" #property indicator_type4 DRAW_ARROW #property indicator_width4 2 #property indicator_color4 0x1A1AE8 #property indicator_label4 "Sell Reversal" #property indicator_type5 DRAW_LINE #property indicator_style5 STYLE_SOLID #property indicator_width5 2 #property indicator_color5 0xFFAA00 #property indicator_label5 "Buy" #property indicator_type6 DRAW_LINE #property indicator_style6 STYLE_SOLID #property indicator_width6 2 #property indicator_color6 0x0000FF #property indicator_label6 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double Buffer3[]; double Buffer4[]; double Buffer5[]; double Buffer6[]; input double Oversold = 30; input double Overbought = 70; input int Slow_MA_period = 200; input int Fast_MA_period = 100; datetime time_alert; //used when sending alert input bool Audible_Alerts = true; input bool Push_Notifications = true; double myPoint; //initialized in OnInit int RSI_handle; double RSI[]; double Open[]; double Close[]; int MA_handle; double MA[]; int MA_handle2; double MA2[]; int MA_handle3; double MA3[]; int MA_handle4; double MA4[]; double Low[]; double High[]; int MA_handle5; double MA5[]; int MA_handle6; double MA6[]; int MA_handle7; double MA7[]; //--- ShellExecuteW declaration ---------------------------------------------- #import "shell32.dll" int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); #import //--- global variables ------------------------------------------------------ datetime last_alert_time; input int alert_cooldown_seconds = 60; // Cooldown period in seconds //--- myAlert function ------------------------------------------------------ void myAlert(string type, string message) { datetime current_time = TimeCurrent(); if (current_time - last_alert_time < alert_cooldown_seconds) { // Skip alert if within cooldown period return; } last_alert_time = current_time; string full_message = type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message; if (type == "print") { Print(message); } else if (type == "error") { Print(type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message); } else if (type == "order") { // Add order alert handling if needed } else if (type == "modify") { // Add modify alert handling if needed } else if (type == "indicator" || type == "info") { if (Audible_Alerts) { Alert(full_message); } if (Push_Notifications) { SendNotification(full_message); } // Send to WhatsApp string python_path = "C:\\Users\\****\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\****\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py"; string command = python_path + " \"" + script_path + "\" \"" + full_message + "\""; // Debugging: Print the command being executed Print("Executing command to send WhatsApp message: ", command); // Use cmd.exe to execute the command and then wait for 5 seconds string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 1); if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); } } } //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); SetIndexBuffer(2, Buffer3); PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(2, PLOT_ARROW, 236); SetIndexBuffer(3, Buffer4); PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(3, PLOT_ARROW, 238); SetIndexBuffer(4, Buffer5); PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); SetIndexBuffer(5, Buffer6); PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); // Send test message on launch myAlert("info", "Thank you for subscribing. You shall be receiving Trend Constraint signal alerts via Whatsapp."); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE); if(RSI_handle < 0) { Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle3 = iMA(NULL, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle3 < 0) { Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle4 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle4 < 0) { Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle5 = iMA(NULL, PERIOD_CURRENT, Fast_MA_period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle5 < 0) { Print("The creation of iMA has failed: MA_handle5=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle6 = iMA(NULL, PERIOD_CURRENT, Slow_MA_period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle6 < 0) { Print("The creation of iMA has failed: MA_handle6=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle7 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle7 < 0) { Print("The creation of iMA has failed: MA_handle7=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); ArraySetAsSeries(Buffer3, true); ArraySetAsSeries(Buffer4, true); ArraySetAsSeries(Buffer5, true); ArraySetAsSeries(Buffer6, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); ArrayInitialize(Buffer3, EMPTY_VALUE); ArrayInitialize(Buffer4, EMPTY_VALUE); ArrayInitialize(Buffer5, EMPTY_VALUE); ArrayInitialize(Buffer6, EMPTY_VALUE); } else limit++; datetime Time[]; datetime TimeShift[]; if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total); ArraySetAsSeries(TimeShift, true); int barshift_M1[]; ArrayResize(barshift_M1, rates_total); int barshift_D1[]; ArrayResize(barshift_D1, rates_total); for(int i = 0; i < rates_total; i++) { barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]); barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]); } if(BarsCalculated(RSI_handle) <= 0) return(0); if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total); ArraySetAsSeries(RSI, true); if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total); ArraySetAsSeries(Open, true); if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(BarsCalculated(MA_handle3) <= 0) return(0); if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total); ArraySetAsSeries(MA3, true); if(BarsCalculated(MA_handle4) <= 0) return(0); if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total); ArraySetAsSeries(MA4, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); if(BarsCalculated(MA_handle5) <= 0) return(0); if(CopyBuffer(MA_handle5, 0, 0, rates_total, MA5) <= 0) return(rates_total); ArraySetAsSeries(MA5, true); if(BarsCalculated(MA_handle6) <= 0) return(0); if(CopyBuffer(MA_handle6, 0, 0, rates_total, MA6) <= 0) return(rates_total); ArraySetAsSeries(MA6, true); if(BarsCalculated(MA_handle7) <= 0) return(0); if(CopyBuffer(MA_handle7, 0, 0, rates_total, MA7) <= 0) return(rates_total); ArraySetAsSeries(MA7, true); if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total); ArraySetAsSeries(Time, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue; if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue; //Indicator Buffer 1 if(RSI[i] < Oversold && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close && MA[i] > MA2[i] //Moving Average > Moving Average && MA3[i] > MA4[i] //Moving Average > Moving Average ) { Buffer1[i] = Low[1+i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open time_alert = Time[1]; } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(RSI[i] > Overbought && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close && MA[i] < MA2[i] //Moving Average < Moving Average && MA3[i] < MA4[i] //Moving Average < Moving Average ) { Buffer2[i] = High[1+i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open time_alert = Time[1]; } else { Buffer2[i] = EMPTY_VALUE; } //Indicator Buffer 3 if(MA5[i] > MA6[i] && MA5[i+1] < MA6[i+1] //Moving Average crosses above Moving Average ) { Buffer3[i] = Low[i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Reversal"); //Alert on next bar open time_alert = Time[1]; } else { Buffer3[i] = EMPTY_VALUE; } //Indicator Buffer 4 if(MA5[i] < MA6[i] && MA5[i+1] > MA6[i+1] //Moving Average crosses below Moving Average ) { Buffer4[i] = High[i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Reversal"); //Alert on next bar open time_alert = Time[1]; } else { Buffer4[i] = EMPTY_VALUE; } //Indicator Buffer 5, Alert muted by turning it into a comment if(MA3[i] > MA7[i] //Moving Average > Moving Average ) { Buffer5[i] = MA3[i]; //Set indicator value at Moving Average //if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open //time_alert = Time[1]; } else { Buffer5[i] = EMPTY_VALUE; } //Indicator Buffer 6, Alert muted by turning it into a comment if(MA3[i] < MA7[i] //Moving Average < Moving Average ) { Buffer6[i] = MA3[i]; //Set indicator value at Moving Average //if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open //time_alert = Time[1]; } else { Buffer6[i] = EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+
Testes e Resultados
Realizamos testes em duas das subseções acima. Nosso projeto está funcionando corretamente no meu ambiente. Incluí algumas capturas de tela dos sinais recebidos abaixo.

O indicador está funcionando bem, desenhando de acordo com o objetivo e enviando sinais para meus canais sociais conforme projetado. Segue anexada uma imagem do gráfico do índice Boom 500 abaixo:

Nosso programa abre uma janela do prompt de comando ao iniciar para exibir os processos em andamento e envia uma nota de abertura. Ele segue o mesmo procedimento ao transmitir sinais ao longo do tempo. No entanto, a janela que aparece pode ser disruptiva ao trabalhar em tarefas, então o programa pode ser codificado para funcionar sem exibir a janela do Prompt de Comando. Neste projeto, optamos por não ocultar a janela para observar os processos em andamento. Para impedir que a janela do Prompt de Comando apareça, você pode incluir a seguinte linha de código...
// execute the command without showing the window string final_command = "/c " + command + " && timeout 5"; int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 0); // Change the last parameter to 0 (SW_HIDE) if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); } else { Print("Successfully executed Python script. Result code: ", result); }
O último parâmetro é chamado de nShowCmd, e controla como a janela da aplicação é exibida. Alterando os parâmetros para 0 (SW_HIDE) em vez de 1 (SW_SHOWNORMAL).
Segurança
A técnica utilizada envolve arquivos DLL, que são considerados uma potencial ameaça. Por meio da minha pesquisa, identifiquei os riscos associados para fins de conscientização abaixo. Certifique-se de proteger suas credenciais para APIs, pois me esforcei para ocultar as minhas em algum ponto deste artigo. Divulgue-as apenas para entidades confiáveis.
Alguns perigos associados a arquivos DLL:
- Malware: Carregar um DLL malicioso pode executar códigos nocivos em seu sistema. Esse é um risco significativo se o DLL for obtido de uma fonte desconhecida ou não confiável.
- Hijacking de DLL: Se um atacante conseguir colocar um DLL malicioso em um local carregado pela aplicação, ele poderá executar códigos arbitrários. Isso é particularmente perigoso se a aplicação for executada com privilégios elevados.
- Falhas e Instabilidade: O uso incorreto de funções de DLL ou a chamada de funções com parâmetros inválidos pode causar falhas na aplicação ou instabilidade do sistema.
- Vazamento de Recursos: O manuseio inadequado de recursos (ex.: memória, handles de arquivo) dentro de funções DLL pode levar a vazamentos, afetando o desempenho do sistema ao longo do tempo.
- Conflitos de Versão: Diferentes versões de um DLL podem ter assinaturas ou comportamentos distintos, levando a problemas de compatibilidade.
- Problemas de Dependência: Gerenciar dependências em múltiplos DLLs e suas versões pode ser complexo e propenso a erros, resultando em erros de execução.
Para combater tais ameaças, é crucial incorporar recursos de segurança ao nosso programa. A linha de código a seguir pode resolver preocupações de segurança se implementada em nosso modelo:
// You can secure the program by adding SecureExecuteCommand(command); below these lines. string python_path = "C:\\Users\\*****\\AppData\\Local\\Programs\\Python\\Python312\\python.exe"; string script_path = "C:\\Users\\*****\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py"; //***** is your computer user name, the rest of the path txt is correct based on the python version being used. string message = "Hello, this is a test message"; string command = python_path + " \"" + script_path + "\" \"" + message + "\""; SecureExecuteCommand(command);
A função SecureExecuteCommand() verifica caracteres inválidos na string de comando, o que pode ajudar a prevenir ataques de injeção de comandos.
Algumas práticas recomendadas para combater os riscos são:
- Use Fontes Confiáveis: Use apenas DLLs de fontes confiáveis e verificadas.
- Assinatura de Código: Certifique-se de que os DLLs sejam assinados por uma autoridade confiável, o que ajuda a verificar sua integridade e origem.
- Privilégio Mínimo: Execute aplicações com o menor privilégio necessário para reduzir o impacto de qualquer possível exploração.
- Valide Entradas: Sempre valide e sanitize os parâmetros de entrada, especialmente ao construir strings de comando.
- Tratamento de Erros: Implemente um tratamento de erros robusto para gerenciar e registrar erros de maneira elegante.
- Atualizações Regulares: Mantenha seu software e bibliotecas atualizados com patches e atualizações de segurança.
- Isolamento: Use sandboxing ou outras técnicas de isolamento para executar operações potencialmente arriscadas em um ambiente restrito.
Conclusão
A integração com WhatsApp foi concluída com sucesso. Nosso modelo agora pode transmitir sinais do MetaTrader 5 para o Telegram e o WhatsApp. É viável consolidar a integração em um único programa e transmitir os sinais em ambas as plataformas simultaneamente. Observei pequenas discrepâncias na entrega de sinais, com notificações push chegando um pouco antes do que as nas plataformas sociais, embora com uma diferença de tempo muito pequena, talvez em torno de 7 segundos. Os sinais do Telegram foram mais rápidos que os do WhatsApp por alguns segundos. No entanto, nosso objetivo principal era garantir a chegada dos sinais, e esse objetivo foi alcançado.
Espero que este artigo tenha lhe trazido algo de valor. Como desenvolvedores, não devemos desistir, mas manter o fluxograma operacional até atingirmos nossos objetivos. Devemos aproveitar o poder de nossa comunidade para aprimorar nossas habilidades em programação de negociação algorítmica. As discussões estão sempre abertas a todos para que ideias possam ser compartilhadas livremente. Em nosso próximo projeto, construiremos sobre nossa base existente para explorar ainda mais. Encontre os arquivos anexos e suas descrições abaixo.
| Anexos: | Descrição |
|---|---|
| send_whatsapp_message.py | Responsável pela comunicação do MetaTrader 5 com o Twilio e, em seguida, com o WhatsApp. |
| Trend Constraint V1.06.mq5 | WhatsApp integrado, mas precisa que você atualize as credenciais e diretórios de caminho para funcionar no seu computador. |
| Secure Command.mq5 | Modificado para ocultar a janela do Prompt de Comando e proteger o programa contra ataques externos. |
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14969
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Reimaginando Estratégias Clássicas em Python: MA Crossovers
Data Science e Machine Learning (Parte 25): Previsão de Séries Temporais de Forex Usando uma Rede Neural Recorrente (RNN)
Ferramentas econométricas para previsão de volatilidade: Modelo GARCH
Redes neurais em trading: Representação linear por partes de séries temporais
- 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