
构建K线图趋势约束模型(第六部分):一体化集成
概述
我们的信号系统在其发展的各个阶段始终表现出卓越的性能。当前的目标是将现有的程序整合成一个统一的信号系统。请记住,趋势约束指标的前两个版本在第五部分中各有其特定的集成版本。此次整合旨在充分利用程序的强大功能,让计算机以惊人的速度执行复杂且重复的任务,从而大大减轻人为的工作量。
鉴于我们有两个逻辑相似但功能不同的程序,集成过程不仅仅是简单地复制粘贴源代码。相反,我们将策略性地保留两个程序中具有一致效果的某些元素,以确保具备最优功能。我将这一过程称为“合并”,它需要仔细地考虑和精确地操作。
在本文中,我们将分解MQL5代码中发生整合的部分,并探讨在合并过程中始终保持全局性的关键代码行。当合并多个代码片段以创建一个连贯且高效的程序时,这种细致入微的方法是必不可少的。
从第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); } } }
整合集成逻辑
为了使用提供的两个代码段创建一个同时集成WhatsApp和Telegram的单一程序,我们将把每个代码段中的逻辑整合成一个连贯的函数。计划如下:
- 整合全局变量和声明:我们将合并声明和全局变量。
- 合并myAlert函数:我们将扩展myAlert函数,用以处理向WhatsApp和Telegram发送消息。
- 调整命令执行逻辑:我们将确保两个命令(WhatsApp和Telegram)在同一个函数内被执行。
- 确保冷却期持续:我们将保留确保警报不会过于频繁发送的逻辑。
为了整合声明和全局变量,两个代码段中的ShellExecuteW声明和冷却期变量被统一放在代码的顶部,以避免冗余。myAlert函数被扩展以包含WhatsApp和Telegram通知的逻辑,同时警报冷却逻辑确保消息不会发送得太频繁。总结来说,对于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测试消息。我们现在可以确定程序运行正常,可以继续进行我们的主程序了。
在上图中,由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测试消息。
评论功能
在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
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。



可以更简单、更通用。大世界的普遍做法不是重新发明轮子,而是使用数据收集器/路由器
例如,通过 Socket() 或 WebRequest() 将指标和事件发送到 telegrafhttps://www.influxdata.com/time-series-platform/telegraf/。
它将处理所有(任何)收件人。
代码更少,运行更稳定。
--
telegraf 是作为一个例子列出的,每个人都可以免费使用。还有其他商业和开源的选择
可以更简单、更通用。大世界的普遍做法不是重新发明轮子,而是使用数据收集器/路由器
例如,通过 Socket() 或 WebRequest() 将指标和事件发送到 telegrafhttps://www.influxdata.com/time-series-platform/telegraf/。
它将处理所有(任何)收件人。
代码更少,运行更稳定。
--
telegraf 是作为一个例子列出的,每个人都可以免费使用。还有其他商业和开源软件
感谢您的分享。我会看看服务器是如何工作的。