English Русский Español Deutsch 日本語 Português
preview
构建K线图趋势约束模型(第六部分):一体化集成

构建K线图趋势约束模型(第六部分):一体化集成

MetaTrader 5交易系统 |
377 2
Clemence Benjamin
Clemence Benjamin
  1. 概述
  2. 主要集成部分
  3. 整合集成逻辑
  4. 评论功能
  5. 测试评论功能效果
  6. 结论


概述

我们的信号系统在其发展的各个阶段始终表现出卓越的性能。当前的目标是将现有的程序整合成一个统一的信号系统。请记住,趋势约束指标的前两个版本在第五部分中各有其特定的集成版本。此次整合旨在充分利用程序的强大功能,让计算机以惊人的速度执行复杂且重复的任务,从而大大减轻人为的工作量。

鉴于我们有两个逻辑相似但功能不同的程序,集成过程不仅仅是简单地复制粘贴源代码。相反,我们将策略性地保留两个程序中具有一致效果的某些元素,以确保具备最优功能。我将这一过程称为“合并”,它需要仔细地考虑和精确地操作。

在本文中,我们将分解MQL5代码中发生整合的部分,并探讨在合并过程中始终保持全局性的关键代码行。当合并多个代码片段以创建一个连贯且高效的程序时,这种细致入微的方法是必不可少的。

第5部分及其子部分中,我们总结出两个主要的集成方案:

  1. Telegram与MetaTrader 5集成用于通知。
  2. WhatsApp与MetaTrader 5集成以用于通知。

一个挑战是,我们的集成在命令提示符窗口中执行任务时,会将窗口隐藏以避免干扰电脑屏幕上的其他进程。因此,无法确认信号是否已成功发送到目标平台。我们希望我们的系统能够在图表窗口中为每次成功广播的信号添加注释,或者至少将其打印在平台日志中。

让我们进一步深入探讨,并在本文的下一部分中提出更多见解以供探讨。


我们的主要集成部分

我已经从代码中提取了与本文讨论内容最相关的要点。如需更详细地讨论,请重新查阅第5部分。以下是我们为促进合并过程而需要对比的程序。请逐一查看这些程序,并对比它们的相似之处和不同之处。通过这种对比,我们将确定需要集成的关键领域,从而确保合并过程既顺畅又高效。

  • 集成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);
        }
    }
}

  • 集成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);
        }
    }
}

    整合集成逻辑

    为了使用提供的两个代码段创建一个同时集成WhatsAppTelegram的单一程序,我们将把每个代码段中的逻辑整合成一个连贯的函数。计划如下: 

    1. 整合全局变量和声明:我们将合并声明和全局变量。
    2. 合并myAlert函数:我们将扩展myAlert函数,用以处理向WhatsApp和Telegram发送消息。
    3. 调整命令执行逻辑:我们将确保两个命令(WhatsApp和Telegram)在同一个函数内被执行。
    4. 确保冷却期持续:我们将保留确保警报不会过于频繁发送的逻辑。

    为了整合声明和全局变量,两个代码段中的ShellExecuteW声明和冷却期变量被统一放在代码的顶部,以避免冗余。myAlert函数被扩展以包含WhatsAppTelegram通知的逻辑,同时警报冷却逻辑确保消息不会发送得太频繁。总结来说,对于WhatsApp,定义了Python可执行文件和WhatsApp脚本的路径,并构造了一个命令字符串来执行WhatsApp消息发送脚本。该命令使用ShellExecuteW执行,并检查结果以记录任何错误。类似地,对于Telegram,定义了Python可执行文件和Telegram脚本的路径,构造了一个命令字符串来执行Telegram消息发送脚本,并使用ShellExecuteW执行该命令,同时检查结果以记录任何错误。

    以下是合并后的程序:

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

    在此阶段,让我们把代码分成几个部分来解释它们的功能:

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

    这一节从Windows的shell32.dll库中导入了ShellExecuteW函数。ShellExecuteW是Windows API的一个函数,用于对指定的文件执行操作。通过导入这个函数,MQL5代码可以执行外部命令或脚本,例如用于向WhatsApp和Telegram发送消息的Python脚本。

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

    上述代码片段定义了集成算法的全局变量。

    • last_alert_time:一个全局变量,存储上一次发送警报的时间戳。这有助于在警报期间实现冷却期。
    • alert_cooldown_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.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);
            }
        }
    }
    
    

    •  myAlert函数旨在根据提供的类型和消息发送警报。它管理冷却期,构建警报消息,并使用外部Python脚本将消息发送到WhatsApp和Telegram上。如您所见,这是代码中占比最大的部分。
    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;
    
    • 这一节会检查当前时间减去上一次警报时间是否小于冷却期。如果为真,则跳过发送警报。这样可以防止在短时间内频繁发送警报。

    为了确保我们的脚本正常工作,我们通过命令提示符得到了以下结果:

    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

    高亮显示的文本是命令提示符的正面响应,确认我们的脚本运行正常。在主程序中正确地添加文件路径是非常重要的。

    另一方面,我们也在社交平台上收到了信号。下面左侧是一张图片,展示了从命令提示符发送的Telegram测试消息,右侧则是从命令提示符发送的WhatsApp测试消息。我们现在可以确定程序运行正常,可以继续进行我们的主程序了。

    Telegram脚本测试 Whatsapp脚本测试

    在上图中,由Twilio API提供的用于WhatsApp集成的沙盒连接将在72小时内过期。重要的是,您需要通过发送一条独特的信息来重新连接,以便再次接收API消息。在这种情况下,重新连接的信息是“join so-cave”。要获得一个永不过期的服务,您可以购买一个Twilio号码。

    接下来,让我们使用趋势约束指标逻辑将所有内容整合到一个程序中。推出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);
      }
    //+------------------------------------------------------------------+

    如果您仔细观察,会发现我们将指标从V1.06版本更新到了V1.07版本。在编译程序后,我们没有遇到任何错误,并且我们的程序现在已经在MetaTrader 5上平稳运行。以下是在MetaTrader 5(MT5)上启动指标时发送的测试消息的图片:最左边的是MetaTrader 5安卓版手机上的推送通知,中间是Telegram测试通知,右边是WhatsApp测试消息。

    安卓系统的MetaTrade 5推送通知 Telegram, Trend Constraint V1.07测试 Whatsapp, Trend Constraint V1.07测试



    评论功能

    在MQL5中,Comment函数是一个内置函数,用于直接在图表上显示自定义的文本消息。这个函数能够帮助我们在指标或EA运行期间,通过显示可以持续更新的消息来提供实时的视觉反馈。在该案例中,我们的目标是使用它来实现以下功能:

    • 通知用户指标已成功启动。
    • 确认警报消息已成功发送。
    • 向用户发送警报消息失败的警告。

    我们将在代码的以下三个区段中实现这一功能:

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

    上述代码段的目的是通知我们指标已成功启动。在指标成功初始化后,Comment函数会在图表上显示消息“Indicator successfully launched”(指标成功启动)。这就提供了即时反馈,表明指标处于活跃和运行状态。

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

    这是为了告知我们警报消息已成功发送。当使用myAlert函数成功发送警报消息时,该函数会在图表上显示消息“Success message sent [message]”,其中[message]是实际的警报内容。它向我们确认警报已正确发送。

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

    最后,我们也希望能在启动失败时得到通知,提升我们程序的实用性。此段代码用于通知我们发送警报消息失败。如果发送警报消息失败,会在图表上显示消息“Failed to send message [message]”,其中[message]是原本要发送的警报内容。这就提醒我们出现了失败的情况,以便采取纠正措施。

    为了运用Comment函数引入的新功能,我已经将我们的程序升级到Trend Constraint V1.08版本。通过将这个函数策略性地集成到代码的相关部分,我成功地更新了程序,确保了它的平稳运行。下面,您将看到源代码,其中修改过的部分已被高亮显示,以展示所做出的增强。

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



    测试评论功能效果

    在MQL5中实现Comment函数是增强交易图表交互性和信息丰富性的一种直接的方法。通过集成此函数,您可以直接在交易者的图表上提供关键的实时更新,从而提升他们的整体交易体验。此函数能够以清晰简洁的方式显示动态数据,如当前价格、指标值和自定义消息。因此,交易者可以在无需在多个窗口或外部工具之间切换的情况下做出更加明智的决策。

    Comment函数的易用性和灵活性,使其成为开发更友好、更高效的交易算法时不可或缺的工具。通过将实时、特定情境的信息直接融入交易界面,该函数提高了情境感知能力,简化了交易流程,为用户带来了更高效、更满意的体验。通过以下的一张图片,展示了Trend Constraint V1.07的成功启动:

     



    结论

    在软件开发的道路上,创新往往源自于对现有解决方案的无缝整合,从而开发出更加稳健且功能丰富的应用程序。本文探讨了将两个程序合并为一个协调统一的整体的过程,展示了通过整合功能来提升整体性能和用户体验。

    我们首先从理解这两个独立程序的核心功能开始,每个程序都有其独特的优势。通过仔细分析它们的代码库并找出协同点,我们成功地将它们合并为一个完整的程序。这次合并不仅简化了操作,还减少了冗余和潜在的不一致,为其更高效地运行铺平了道路。

    此外,在MQL5程序中整合Comment功能为我们合并应用增添了一个新的维度。通过利用MQL5强大的警报系统,我们实现了一个功能,该功能允许通过包括WhatsApp和Telegram在内的多种渠道发送实时通知。这一增强确保了用户能够随时获知关键事件,从而提高了响应速度和决策能力。

    随着我们的不断前行,进一步改进和订制的可能性依然巨大,这促使我们持续追求进步和创新。通过在现有技术的基础上进行构建并精心整合新功能,我们可以创造出强大的工具,以提高效率、增强用户参与度,并最终获得更好的结果。

    请参阅以下附件。欢迎发表评论和意见。

    附件 说明
    Trend Constraint V1.07.mq5 将两个平台集成到一个程序中。
    Trend Constraint V1.08.mq5
    包含command函数。
    Send_telegram_message.py Telegram消息发送脚本。
    send_whatsapp_message.py WhatsApp消息发送脚本。

    本文由MetaQuotes Ltd译自英文
    原文地址: https://www.mql5.com/en/articles/15143

    最近评论 | 前往讨论 (2)
    Maxim Kuznetsov
    Maxim Kuznetsov | 14 1月 2025 在 16:32

    可以更简单、更通用。大世界的普遍做法不是重新发明轮子,而是使用数据收集器/路由器

    例如,通过 Socket() 或 WebRequest() 将指标和事件发送到 telegrafhttps://www.influxdata.com/time-series-platform/telegraf/。

    它将处理所有(任何)收件人。

    代码更少,运行更稳定。

    --

    telegraf 是作为一个例子列出的,每个人都可以免费使用。还有其他商业和开源的选择

    Clemence Benjamin
    Clemence Benjamin | 29 1月 2025 在 08:28
    Maxim Kuznetsov #:

    可以更简单、更通用。大世界的普遍做法不是重新发明轮子,而是使用数据收集器/路由器

    例如,通过 Socket() 或 WebRequest() 将指标和事件发送到 telegrafhttps://www.influxdata.com/time-series-platform/telegraf/。

    它将处理所有(任何)收件人。

    代码更少,运行更稳定。

    --

    telegraf 是作为一个例子列出的,每个人都可以免费使用。还有其他商业和开源软件

    感谢您的分享。我会看看服务器是如何工作的。

    在 MQL5 中创建每日回撤限制器 EA 在 MQL5 中创建每日回撤限制器 EA
    本文从详细的角度讨论了如何基于交易算法实现 EA 交易系统的创建。这有助于在 MQL5 中实现系统自动化,并控制每日回撤。
    在您的 MQL 项目中使用 JSON 数据 API 在您的 MQL 项目中使用 JSON 数据 API
    想象一下,您可以使用 MetaTrader 中没有的数据,您只能通过价格分析和技术分析从指标中获得数据。现在想象一下,您可以访问数据,这将使你的交易能力更高。如果您通过 API(应用程序编程接口)数据混合其他软件、宏观分析方法和超高级工具的输出,您就可以倍增 MetaTrader 软件的力量。在本文中,我们将教您如何使用 API,并介绍有用和有价值的 API 数据服务。
    神经网络变得简单(第 89 部分):频率增强分解变换器(FEDformer) 神经网络变得简单(第 89 部分):频率增强分解变换器(FEDformer)
    到目前为止,我们研究过的所有模型在分析环境状态时都将其当作时间序列。不过,时间序列也能以频率特征的形式表示。在本文中,我将向您介绍一种算法,即利用时间序列的频率分量来预测未来状态。
    自适应社会行为优化(ASBO):Schwefel函数与Box-Muller方法 自适应社会行为优化(ASBO):Schwefel函数与Box-Muller方法
    本文深入探讨了生物体的社会行为及其对新型数学模型——自适应社会行为优化(ASBO)创建的影响,为我们呈现了一个引人入胜的世界。我们将研究生物社会中观察到的领导、近邻和合作原则如何激发创新优化算法的开发。