English Русский 中文 Español Deutsch 日本語
preview
Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 6): Integração Completa

Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 6): Integração Completa

MetaTrader 5Sistemas de negociação | 14 fevereiro 2025, 10:05
136 0
Clemence Benjamin
Clemence Benjamin
  1. Introdução
  2. Principais Seções de Integração
  3. Combinando a Lógica de Integração
  4. A Função de Comentário
  5. Testando os Efeitos da Função de Comentário
  6. Conclusão


Introdução

Nosso sistema de sinais tem demonstrado consistentemente um desempenho excepcional em cada estágio de seu desenvolvimento. O objetivo atual é fundir os programas existentes em um único sistema de sinal unificado. Lembre-se de que as duas versões anteriores do indicador de Restrição de Tendência tinham suas integrações específicas na Parte 5. Esta consolidação visa aproveitar todo o potencial da programação, reduzindo significativamente o trabalho humano ao permitir que computadores executem tarefas complexas e repetitivas com velocidades incríveis.

Dado que temos dois programas com lógica semelhante, mas com recursos distintos, o processo de integração envolve mais do que simplesmente copiar e colar o código-fonte. Em vez disso, reteremos estrategicamente certos elementos que têm efeitos consistentes em ambos os programas, garantindo a funcionalidade ideal. Este processo, que eu chamo de fusão, requer consideração cuidadosa e precisão.

Neste artigo, dividiremos as seções de código MQL5 onde ocorre a integração e discutiremos as linhas principais que permanecem globais ao longo do processo de fusão. Essa abordagem meticulosa é essencial ao combinar vários trechos de código para criar um programa coeso e eficiente.

Na Parte 5 e suas subseções, tivemos duas principais integrações para resumir:

  1. Integração do Telegram com MetaTrader 5 para notificações.
  2. Integração do WhatsApp com MetaTrader 5 para notificações.

Um desafio é que nossa integração realiza tarefas no Prompt de Comando com a janela oculta para evitar interferências em outros processos na tela do computador. Como resultado, não há confirmação se os sinais foram enviados com sucesso para as plataformas de destino. Queremos que nosso sistema comente na janela do gráfico a cada transmissão bem-sucedida de sinal ou, pelo menos, registre essa informação no diário da plataforma.

Vamos nos aprofundar e discutir mais detalhes nas próximas seções deste artigo.


Nossas principais seções de integração

Extraí os principais pontos de interesse do código especificamente para a discussão deste artigo. Para discussões mais detalhadas, consulte novamente a Parte 5. Aqui estão os programas que estamos comparando para facilitar o processo de fusão. Analise cada programa e compare suas semelhanças e diferenças. Essa comparação nos ajudará a identificar as áreas principais onde a integração é necessária, garantindo uma fusão eficiente e sem problemas.

  • Integração do Telegram: 

/--- ShellExecuteW declaration ----------------------------------------------
#import "shell32.dll"
int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
#import

//--- functions for telegram integration -----------------------------------------------
datetime last_alert_time;
input int alert_cooldown_seconds = 60; // Cooldown period in seconds

void myAlert(string type, string message) {
    datetime current_time = TimeCurrent();
    if (current_time - last_alert_time < alert_cooldown_seconds) {
        // Skip alert if within cooldown period
        return;
    }

    last_alert_time = current_time;
    string full_message = type + " | Trend Constraint V1.05 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message;
    if (type == "print") {
        Print(message);
    } else if (type == "error") {
        Print(type + " | Trend Constraint V1.05 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message);
    } else if (type == "order") {
        // Add order alert handling if needed
    } else if (type == "modify") {
        // Add modify alert handling if needed
    } else if (type == "indicator") {
        if (Audible_Alerts) {
            Alert(full_message);
        }
        if (Push_Notifications) {
            SendNotification(full_message);
        }

        // Send to Telegram
        string python_path = "C:\\Users\\your_computer_name\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
        string script_path = "C:\\Users\\your_computer_name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
        string command = python_path + " \"" + script_path + "\" \"" + full_message + "\"";
        
        // Debugging: Print the command being executed
        Print("Executing command to send Telegram message: ", command);

        // Use cmd.exe to execute the command and then wait for 5 seconds
        string final_command = "/c " + command + " && timeout 5";
        int result = ShellExecuteW(0, "open", "cmd.exe", final_command, NULL, 1);
        if (result <= 32) {
            int error_code = GetLastError();
            Print("Failed to execute Python script. Error code: ", error_code);
        } else {
            Print("Successfully executed Python script. Result code: ", result);
        }
    }
}

  • Integração do WhatsApp:

//--- 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\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
        string script_path = "C:\\Users\\Your_Computer_Name\\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);
        }
    }
}

    Combinando a Lógica de Integração

    Para criar um único programa que integre tanto o WhatsApp quanto o Telegram usando os dois trechos de código fornecidos, combinaremos a lógica de cada trecho em uma função coesa. Plano: 

    1. Combinar Variáveis e Declarações Globais: Consolidaremos as declarações e variáveis globais.
    2. Fundir a Função myAlert: Expandiremos a função myAlert para enviar mensagens tanto para WhatsApp quanto para Telegram.
    3. Ajustar a Lógica de Execução de Comandos: Garantiremos que ambos os comandos (WhatsApp e Telegram) sejam executados na mesma função.
    4. Manter o Período de Resfriamento: Preservaremos a lógica que impede o envio excessivo de alertas em um curto intervalo de tempo.

    Para combinar declarações e variáveis globais, ambos os trechos continham a declaração ShellExecuteW e uma variável de período de resfriamento, que são unificadas no topo do código para evitar redundância. A função myAlert é expandida para incluir a lógica de envio de notificações tanto para WhatsApp quanto para Telegram, com uma verificação de resultado para registrar erros. Resumo: Para o WhatsApp, o caminho para o executável do Python e o script de mensagens do WhatsApp são definidos, e uma string de comando é construída para executar o script. Esse comando é executado usando a função ShellExecuteW, com uma verificação de resultado para registrar possíveis erros. De forma semelhante, para o Telegram, define-se o caminho do executável Python e o script correspondente. Em seguida, uma string de comando é montada para executar o script de envio de mensagens, e o comando é executado utilizando ShellExecuteW, também com uma verificação de resultado para registro de erros.

    Aqui está o programa combinado:

    //--- 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\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
            string whatsapp_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py";
            string whatsapp_command = python_path + " \"" + whatsapp_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for WhatsApp
            Print("Executing command to send WhatsApp message: ", whatsapp_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_whatsapp_command = "/c " + whatsapp_command + " && timeout 5";
            int whatsapp_result = ShellExecuteW(0, "open", "cmd.exe", final_whatsapp_command, NULL, 1);
            if (whatsapp_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute WhatsApp Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed WhatsApp Python script. Result code: ", whatsapp_result);
            }
    
            // Send to Telegram
            string telegram_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
            string telegram_command = python_path + " \"" + telegram_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for Telegram
            Print("Executing command to send Telegram message: ", telegram_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_telegram_command = "/c " + telegram_command + " && timeout 5";
            int telegram_result = ShellExecuteW(0, "open", "cmd.exe", final_telegram_command, NULL, 1);
            if (telegram_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute Telegram Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed Telegram Python script. Result code: ", telegram_result);
            }
        }
    }
    
    

    Nesta etapa, vamos dividir o código em seções para explicar suas funcionalidades:

    #import "shell32.dll"
    int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
    #import
    

    Esta seção importa a função ShellExecuteW da biblioteca shell32.dll do Windows. ShellExecuteW é uma função da API do Windows que executa uma operação em um arquivo especificado. Ao importar essa função, o código MQL5 pode executar comandos ou scripts externos, como scripts Python para o envio de mensagens via WhatsApp e Telegram.

    datetime last_alert_time;
    input int alert_cooldown_seconds = 60; // Cooldown period in seconds
    

    O trecho de código acima define as Variáveis Globais do algoritmo de integração.

    • last_alert_time: Uma variável global que armazena o timestamp do último alerta enviado. Isso ajuda a implementar um período de espera entre os alertas.
    • alert_cooldown_seconds: Uma variável de entrada (configurável pelo usuário) que especifica o período de espera em segundos. Isso determina a frequência com que os alertas podem ser enviados para evitar spam.

    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\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
            string whatsapp_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py";
            string whatsapp_command = python_path + " \"" + whatsapp_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for WhatsApp
            Print("Executing command to send WhatsApp message: ", whatsapp_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_whatsapp_command = "/c " + whatsapp_command + " && timeout 5";
            int whatsapp_result = ShellExecuteW(0, "open", "cmd.exe", final_whatsapp_command, NULL, 1);
            if (whatsapp_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute WhatsApp Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed WhatsApp Python script. Result code: ", whatsapp_result);
            }
    
            // Send to Telegram
            string telegram_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
            string telegram_command = python_path + " \"" + telegram_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for Telegram
            Print("Executing command to send Telegram message: ", telegram_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_telegram_command = "/c " + telegram_command + " && timeout 5";
            int telegram_result = ShellExecuteW(0, "open", "cmd.exe", final_telegram_command, NULL, 1);
            if (telegram_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute Telegram Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed Telegram Python script. Result code: ", telegram_result);
            }
        }
    }
    
    

    •  A função myAlert foi projetada para enviar alertas com base no tipo e na mensagem fornecidos. Ela gerencia o período de espera, constrói a mensagem de alerta e a envia tanto para o WhatsApp quanto para o Telegram usando scripts Python externos. Essa é a maior seção do código, como você pode ver.
    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;
    
    • Esta seção verifica se o tempo atual menos o tempo do último alerta é menor que o período de espera. Se for verdadeiro, ele pula o envio do alerta. Isso evita alertas frequentes em um curto período de tempo.

    Para garantir que nossos scripts estão funcionando, obtemos os seguintes resultados no Prompt de Comando:

    C:\Users\Your_Computer_Name\AppData\Local\Programs\Python\Python312\Scripts>python send_telegram_message.py "Trend Constraint V1.07 testing"
    Message sent successfully!
    
    C:\Users\Your_Computer_Name\AppData\Local\Programs\Python\Python312\Scripts>python send_whatsapp_message.py "Trend Constraint V1.07 testing"
    Message sent successfully

    O texto destacado é a resposta positiva do Prompt de Comando, confirmando que nossos scripts estão funcionando corretamente. É muito importante adicionar corretamente o caminho do arquivo no programa principal.

    Por outro lado, também recebemos os sinais em nossas plataformas sociais. Abaixo, à esquerda, há uma imagem mostrando uma mensagem de teste do Telegram a partir do Prompt de Comando, e à direita, uma mensagem de teste do WhatsApp a partir do Prompt de Comando. Agora temos certeza de que nosso programa está funcionando corretamente e podemos prosseguir para o programa principal.

    Teste do script do Telegram Teste do script do WhatsApp

    Na ilustração acima, a conexão sandbox fornecida pela API do Twilio para integração com o WhatsApp expira em 72 horas. É importante reconectar enviando uma mensagem única para ser readicionado e continuar recebendo mensagens da API. Neste caso, a mensagem para se reconectar é "join so-cave". Para adquirir um serviço sem expiração, você pode comprar um número do Twilio.

    Vamos prosseguir e integrar tudo em um único programa usando a lógica do indicador Trend Constraint. Isso nos leva ao Trend Constraint V1.07:

    //+------------------------------------------------------------------+
    //|                                       Trend Constraint V1.07.mq5 |
    //|                                Copyright 2024, Clemence Benjamin |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    
    #property copyright "Copyright 2024, Clemence Benjamin"
    #property link      "https://www.mql5.com"
    #property version   "1.07"
    #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.07 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message;
        if (type == "print") {
            Print(message);
        } else if (type == "error") {
            Print(type + " | Trend Constraint V1.07 @ " + 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 //Replace your_computer_name with the your actual computer name. //Make sure the path to your python and scripts is correct.
            string python_path = "C:\\Users\\Your_Computer\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
            string whatsapp_script_path = "C:\\Users\\Your_computer_name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py";
            string whatsapp_command = python_path + " \"" + whatsapp_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for WhatsApp
            Print("Executing command to send WhatsApp message: ", whatsapp_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_whatsapp_command = "/c " + whatsapp_command + " && timeout 5";
            int whatsapp_result = ShellExecuteW(0, "open", "cmd.exe", final_whatsapp_command, NULL, 1);
            if (whatsapp_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute WhatsApp Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed WhatsApp Python script. Result code: ", whatsapp_result);
            }
    
            // Send to Telegram
            string telegram_script_path = "C:\\Users\\protech\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
            string telegram_command = python_path + " \"" + telegram_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for Telegram
            Print("Executing command to send Telegram message: ", telegram_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_telegram_command = "/c " + telegram_command + " && timeout 5";
            int telegram_result = ShellExecuteW(0, "open", "cmd.exe", final_telegram_command, NULL, 1);
            if (telegram_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute Telegram Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed Telegram Python script. Result code: ", telegram_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);
      }
    //+------------------------------------------------------------------+

    Se você observou com atenção, atualizamos o indicador da versão V1.06 para V1.07. Após compilar o programa, não encontramos erros, e agora nosso programa está operando sem problemas no MetaTrader 5. Abaixo estão imagens das mensagens de teste enviadas ao iniciar o indicador no MT5: à esquerda estão as Notificações Push no MetaTrader 5 para Android, no centro uma notificação de teste do Telegram, e à direita uma mensagem de teste do WhatsApp.

    Notificação push do MetaTrader 5 no Android Teste do Telegram, Trend Constraint V1.07 Teste do WhatsApp, Trend Constraint V1.07



    A Função de Comentário

    A função Comment no MQL5 é uma função integrada usada para exibir mensagens de texto personalizadas diretamente no gráfico. Essa função nos ajuda a fornecer feedback visual em tempo real, exibindo mensagens que podem ser continuamente atualizadas durante a execução de um indicador ou de um Expert Advisor. Neste caso, nosso objetivo é usá-la para alcançar o seguinte:

    • Notificar o usuário sobre o lançamento bem-sucedido do indicador.
    • Confirmar o envio bem-sucedido das mensagens de alerta.
    • Alertar o usuário sobre falhas no envio das mensagens de alerta.

    Vamos direcionar três áreas do código para incorporar esse recurso:

    int OnInit() {
        // Initialization code here
        Comment("Indicator successfully launched.");
        return INIT_SUCCEEDED;
    }
        
    

    O propósito do trecho de código acima é nos notificar de que o indicador foi lançado com sucesso. Após a inicialização bem-sucedida do indicador, a função Comment exibe a mensagem "Indicador lançado com sucesso" no gráfico. Isso fornece um feedback imediato de que o indicador está ativo e em execução.

    if (result > 32) {
        Print("Successfully executed Python script. Result code: ", result);
        Comment("Success message sent: " + message);
    }
    

    Isso serve para nos informar que uma mensagem de alerta foi enviada com sucesso. Quando uma mensagem de alerta é enviada corretamente usando a função myAlert, a função exibe a mensagem "Mensagem enviada com sucesso [mensagem]" no gráfico, onde [mensagem] é o conteúdo real do alerta. Isso nos fornece uma confirmação de que o alerta foi despachado corretamente.

    if (result <= 32) {
        int error_code = GetLastError();
        Print("Failed to execute Python script. Error code: ", error_code);
        Comment("Failed to send message: " + message);
    }
    

    Por fim, também queremos ser informados sobre uma falha no envio do alerta, o que aprimora a funcionalidade do nosso programa. Este trecho de código nos notifica sobre uma falha no envio de uma mensagem de alerta. Se houver falha no envio da mensagem, ele exibe a mensagem "Falha ao enviar mensagem [mensagem]" no gráfico, onde [mensagem] é o conteúdo do alerta pretendido. Isso nos alerta sobre a falha, permitindo que sejam tomadas ações corretivas.

    Para aproveitar as novas capacidades introduzidas pela função Comment, atualizei nosso programa para Trend Constraint V1.08. Ao integrar estrategicamente essa função nas seções relevantes do código, atualizei com sucesso o programa, garantindo sua operação sem problemas. Abaixo, você encontrará o código-fonte com as seções modificadas destacadas, mostrando as melhorias realizadas.

    //+------------------------------------------------------------------+
    //|                                       Trend Constraint V1.08.mq5 |
    //|                                Copyright 2024, Clemence Benjamin |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    
    #property indicator_chart_window
    #property copyright "Copyright 2024, Clemence Benjamin"
    #property link      "https://www.mql5.com"
    #property version   "1.08"
    #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.08 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message;
        
        string comment = "Alert triggered by Trend Constraint V1.08 | Symbol: " + Symbol() + " | Period: " + IntegerToString(Period()) + " | Message: " + message;
    
        if (type == "print") {
            Print(message);
        } else if (type == "error") {
            Print(type + " | Trend Constraint V1.08 @ " + 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\\protech\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
            string whatsapp_script_path = "C:\\Users\\protech\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py";
            string whatsapp_command = python_path + " \"" + whatsapp_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for WhatsApp
            Print("Executing command to send WhatsApp message: ", whatsapp_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_whatsapp_command = "/c " + whatsapp_command + " && timeout 5";
            int whatsapp_result = ShellExecuteW(0, "open", "cmd.exe", final_whatsapp_command, NULL, 0);
            if (whatsapp_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute WhatsApp Python script. Error code: ", error_code);
                Comment("Failed to send message: " + message);
            } else {
                Print("Successfully executed WhatsApp Python script. Result code: ", whatsapp_result);
                Comment("Success message sent: " + message);
            }
    
            // Send to Telegram
            string telegram_script_path = "C:\\Users\\protech\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
            string telegram_command = python_path + " \"" + telegram_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for Telegram
            Print("Executing command to send Telegram message: ", telegram_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_telegram_command = "/c " + telegram_command + " && timeout 5";
            int telegram_result = ShellExecuteW(0, "open", "cmd.exe", final_telegram_command, NULL, 0);
            if (telegram_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute Telegram Python script. Error code: ", error_code);
                Comment("Failed to send message: " + message);
            } else {
                Print("Successfully executed Telegram Python script. Result code: ", telegram_result);
                Comment("Success message sent: " + message);
            }
        }
    }
    
    
    //+------------------------------------------------------------------+
    //| 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);
         }
       Comment("Indicator successfully launched.");
       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);
      }
    //+------------------------------------------------------------------+



    Testando os Efeitos da Função de Comentário

    Implementar a função Comment no MQL5 é uma maneira direta de aprimorar a interatividade e a formatação dos gráficos de negociação. Ao integrar essa função, é possível fornecer aos traders atualizações essenciais em tempo real diretamente nos gráficos, melhorando sua experiência geral de negociação. Essa função permite a exibição de dados dinâmicos, como preços atuais, valores de indicadores e mensagens personalizadas, de forma clara e concisa. Como resultado, os traders podem tomar decisões mais informadas sem precisar alternar entre várias janelas ou ferramentas externas.

    A facilidade de uso e a flexibilidade da função Comment fazem dela uma ferramenta inestimável para o desenvolvimento de algoritmos de negociação mais eficientes e amigáveis ao usuário. Ao incorporar informações contextuais e em tempo real diretamente na interface de negociação, essa função melhora a consciência situacional e simplifica o processo de negociação, contribuindo para uma experiência mais eficaz e satisfatória. Aqui está uma imagem mostrando o lançamento bem-sucedido do Trend Constraint V1.07:

     



    Conclusão

    Na jornada do desenvolvimento de software, a inovação muitas vezes surge da integração harmoniosa de soluções existentes para criar aplicativos mais robustos e repletos de recursos. Este artigo explorou o processo de fusão de dois programas em uma única unidade coesa, demonstrando o poder da combinação de funcionalidades para aprimorar o desempenho geral e a experiência do usuário.

    Começamos entendendo as funcionalidades principais dos dois programas separados, cada um com suas próprias vantagens. Ao analisar cuidadosamente seus códigos e identificar pontos de sinergia, conseguimos mesclá-los em um único programa. Essa fusão não apenas otimizou as operações, mas também reduziu a redundância e os possíveis conflitos, abrindo caminho para uma execução mais eficiente.

    Além disso, a incorporação da função Comment no programa MQL5 adicionou uma nova dimensão à nossa aplicação combinada. Aproveitando o sistema de alertas robusto do MQL5, implementamos um recurso que permite notificações em tempo real por meio de diversos canais, incluindo WhatsApp e Telegram. Essa melhoria garante que os usuários estejam sempre informados sobre eventos críticos, aprimorando a capacidade de resposta e a tomada de decisões.

    À medida que avançamos, as possibilidades de aprimoramentos e personalizações adicionais continuam vastas, convidando à inovação e à melhoria contínua. Ao construir sobre tecnologias existentes e integrar novos recursos de forma cuidadosa, podemos criar ferramentas poderosas que aumentam a eficiência, aprimoram o envolvimento do usuário e, por fim, levam a melhores resultados.

    Veja os arquivos anexos abaixo. Comentários e opiniões são sempre bem-vindos.

    Anexos: Descrição
    Trend Constraint V1.05.mq5 Integração de duas plataformas em um único programa.
    Trend Constraint V1.05.mq5
    Incorporação da função de comando.
    Send_telegram_message.py Script para envio de mensagens no Telegram.
    send_whatsapp_message.py Script para envio de mensagens no WhatsApp.

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

    Otimização por Quimiotaxia Bacteriana (BCO) Otimização por Quimiotaxia Bacteriana (BCO)
    Este artigo apresenta a versão original do algoritmo de otimização por quimiotaxia bacteriana (Bacterial Chemotaxis Optimization, BCO) e sua variante modificada. Examinaremos detalhadamente todas as diferenças, com foco especial na nova versão BCOm, que simplifica o mecanismo de movimento das bactérias, reduz a dependência do histórico de mudanças de posição e emprega operações matemáticas mais simples em comparação com a versão original, que possui um alto custo computacional. Além disso, serão realizados testes e apresentadas conclusões.
    Redes neurais em trading: Análise de nuvem de pontos (PointNet) Redes neurais em trading: Análise de nuvem de pontos (PointNet)
    A análise direta da nuvem de pontos permite evitar um aumento excessivo no volume de dados e aprimorar a eficiência dos modelos em tarefas de classificação e segmentação. Abordagens deste tipo demonstram um bom desempenho e resistência a perturbações nos dados brutos.
    Combine Estratégias de Análise Fundamental e Técnica no MQL5 Para Iniciantes Combine Estratégias de Análise Fundamental e Técnica no MQL5 Para Iniciantes
    Neste artigo, discutiremos como integrar princípios de seguimento de tendência e análise fundamental em um único Expert Advisor para construir uma estratégia mais robusta. Este artigo demonstrará como qualquer pessoa pode facilmente começar a construir algoritmos de trading personalizados usando MQL5.
    Busca com restrições — Tabu Search (TS) Busca com restrições — Tabu Search (TS)
    O artigo analisa o algoritmo de busca tabu, um dos primeiros e mais conhecidos métodos meta-heurísticos. Exploraremos detalhadamente como o algoritmo funciona, desde a escolha da solução inicial até a exploração das soluções vizinhas, com foco no uso da lista tabu. O artigo cobre os aspectos-chave do algoritmo e suas particularidades.