مدل محدودیت روند کندل | کلید شناسایی فرصتهای معاملاتی
سیستم سیگنال ما در هر مرحله از توسعه، عملکرد استثنایی از خود نشان داده است. هدف فعلی، ادغام برنامههای موجود در یک سیستم سیگنال واحد و یکپارچه است. به یاد داشته باشید که دو نسخه قبلی اندیکاتور Trend Constraint هر کدام در قسمت ۵ دارای ادغامهای خاص خود بودند. این یکپارچهسازی بهدنبال استفاده کامل از قدرت برنامهنویسی است، که بار کاری انسانی را بهطور قابل توجهی کاهش میدهد، زیرا کامپیوترها میتوانند وظایف پیچیده و تکراری را با سرعت بالا اجرا کنند.
با توجه به اینکه دو برنامه داریم که منطق مشابهی دارند اما ویژگیهای متمایزی را ارائه میدهند، فرآیند ادغام شامل کپی و چسباندن ساده کد منبع نیست. بلکه، ما بهطور استراتژیک برخی از عناصر را که در هر دو برنامه تأثیرات یکسانی دارند، حفظ میکنیم تا عملکرد بهینهسازی شود. این فرآیند که من آن را “ادغام” مینامم، نیازمند دقت و توجه ویژهای است.
در این مقاله، بخشهای کد MQL5 را که در آن ادغام انجام میشود، بررسی کرده و خطوط کلیدی را که در طول فرآیند ادغام جهانی باقی میمانند، مورد بحث قرار خواهیم داد. این رویکرد دقیق، هنگام ترکیب چندین قطعه کد برای ایجاد یک برنامه منسجم و کارآمد، ضروری است.
یکی از چالشها این است که ادغام ما وظایف را در Command Prompt انجام میدهد در حالی که پنجره مخفی است تا از تداخل با سایر فرآیندهای صفحه کامپیوتر جلوگیری شود. در نتیجه، هیچ تأییدی برای اینکه آیا سیگنالها با موفقیت به پلتفرمهای هدف ارسال شدهاند یا خیر وجود ندارد. ما میخواهیم سیستم ما در پنجره نمودار برای هر سیگنال موفق که ارسال میشود یک نظر (Comment) درج کند یا حداقل آن را در ژورنال پلتفرم چاپ کند.
بیایید به جزئیات بیشتری بپردازیم و بینشهای بیشتری را در بخشهای بعدی این مقاله مورد بحث قرار دهیم.
بخشهای اصلی ادغام ما
من نکات اصلی مرتبط با این مقاله را از کد استخراج کردهام. برای بحثهای دقیقتر، لطفاً به قسمت ۵ بازگردید. در اینجا برنامههایی که برای تسهیل فرآیند ادغام با هم مقایسه میکنیم، ارائه شدهاند. هر برنامه را با دقت بررسی کرده و شباهتها و تفاوتهای آنها را مقایسه کنید. این مقایسه به ما کمک میکند تا بخشهای کلیدی را که نیاز به ادغام دارند شناسایی کرده و اطمینان حاصل کنیم که ادغام بهصورت یکپارچه و کارآمد انجام شود.
ادغام تلگرام:
--- 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); } } }
ادغام واتساپ :
//--- 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); } } }
این بخش تابع ShellExecuteW را از کتابخانه shell32.dll ویندوز وارد میکند. ShellExecuteW یک تابع API ویندوز است که عملی را بر روی یک فایل مشخص انجام میدهد. با وارد کردن این تابع، کد MQL5 میتواند دستورات یا اسکریپتهای خارجی، مانند اسکریپتهای پایتون برای ارسال پیامها از طریق واتساپ و تلگرام، را اجرا کند.
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 به منظور ارسال هشدارها بر اساس نوع و پیام ارائهشده طراحی شده است. این تابع دوره خنکسازی را مدیریت کرده، پیام هشدار را تشکیل میدهد و آن را به هر دو پلتفرم WhatsApp و Telegram با استفاده از اسکریپتهای خارجی Python ارسال میکند. این بخش بزرگترین قسمت کد است، همانطور که میتوانید ببینید.
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
متن هایلایت شده پاسخ مثبت از خط فرمان را نشان میدهد که تأیید میکند اسکریپتهای ما به درستی کار میکنند. بسیار مهم است که مسیر فایل را به درستی در برنامه اصلی اضافه کنیم.
از طرف دیگر، ما همچنین سیگنالها را در پلتفرمهای اجتماعی خود دریافت میکنیم. در تصویر زیر، در سمت چپ، یک پیام آزمایشی تلگرام از خط فرمان نمایش داده شده و در سمت راست، یک پیام آزمایشی واتساپ از خط فرمان وجود دارد. اکنون ما مطمئن هستیم که برنامه ما به خوبی کار میکند و میتوانیم به برنامه اصلی خود ادامه دهیم.
در تصویر بالا، اتصال sandbox که توسط API تویلیو برای ادغام واتساپ فراهم شده است، در مدت 72 ساعت منقضی میشود. مهم است که با ارسال یک پیام منحصر به فرد دوباره متصل شویم تا برای دریافت پیامهای API دوباره اضافه شویم. در این مورد، پیام برای دوباره متصل شدن “join so-cave” است. برای به دست آوردن یک سرویس بدون انقضا، میتوانید یک شماره تویلیو خریداری کنید.
بیایید به ادغام همه چیز در یک برنامه با استفاده از منطق شاخص Trend Constraint ادامه دهیم. این ما را به نسخه 1.07 از Trend Constraint پیش میبرد:
//+------------------------------------------------------------------+ //| 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 بهروزرسانی کردیم. پس از کامپایل برنامه، هیچ خطایی مشاهده نکردیم و برنامه ما اکنون بهخوبی در متاتریدر 5 کار میکند. در زیر تصاویری از پیامهای آزمایشی که هنگام راهاندازی اندیکاتور در MT5 ارسال شده است، آورده شده است: در سمت چپ، اعلانهای فشاری (Push Notifications) در نسخه اندروید متاتریدر 5، در وسط یک اعلان آزمایشی تلگرام و در سمت راست یک پیام آزمایشی واتساپ قرار دارد.
تابع Comment
تابع Comment در MQL5 یک تابع داخلی است که برای نمایش پیامهای متنی سفارشی بهطور مستقیم بر روی نمودار استفاده میشود. این تابع به ما کمک میکند تا بازخورد بصری در زمان واقعی ارائه دهیم و پیامهایی را نمایش دهیم که میتوانند در طول اجرای یک اندیکاتور یا اکسپرت مشاور بهطور مداوم بهروزرسانی شوند. در این حالت، هدف ما استفاده از این تابع برای دستیابی به اهداف زیر است:
- اطلاعرسانی به کاربر از راهاندازی موفقیتآمیز اندیکاتور.
- تأیید ارسال موفقیتآمیز پیامهای هشدار.
- هشدار به کاربر در صورت بروز خطا در ارسال پیامهای هشدار.
ما در سه بخش از کد، این ویژگی را پیادهسازی خواهیم کرد.
int OnInit() { // Initialization code here Comment("Indicator successfully launched."); return INIT_SUCCEEDED; }
هدف از کد فوق، اطلاعرسانی به ما در مورد راهاندازی موفقیتآمیز اندیکاتور است. پس از راهاندازی موفق اندیکاتور، تابع Comment پیام “اندیکاتور با موفقیت راهاندازی شد” را روی نمودار نمایش میدهد. این پیام بازخورد فوری ارائه میدهد که نشان میدهد اندیکاتور فعال و در حال اجرا است.
if (result > 32) { Print("Successfully executed Python script. Result code: ", result); Comment("Success message sent: " + message); }
این بخش برای اطلاعرسانی به ما در مورد ارسال موفقیتآمیز پیام هشدار است. هنگامی که یک پیام هشدار با موفقیت از طریق تابع myAlert ارسال میشود، این تابع پیامی با متن “پیام با موفقیت ارسال شد [پیام]” را روی نمودار نمایش میدهد، که [پیام] محتوای واقعی هشدار است. این پیام به ما تأیید میدهد که هشدار بهدرستی ارسال شده است.
if (result <= 32) { int error_code = GetLastError(); Print("Failed to execute Python script. Error code: ", error_code); Comment("Failed to send 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); } //+------------------------------------------------------------------+
آزمایش تأثیرات تابع Comment
پیادهسازی تابع Comment در MQL5 راهی ساده برای افزایش تعامل و اطلاعاتگذاری در نمودارهای معاملاتی است. با یکپارچهسازی این تابع، میتوانید به تریدرها بهروزرسانیهای اساسی و بههنگام را مستقیماً روی نمودارهایشان ارائه دهید، که تجربه معاملاتی کلی آنها را بهبود میبخشد. این تابع امکان نمایش دادههای پویا، مانند قیمتهای جاری، مقادیر اندیکاتور و پیامهای سفارشی، بهصورت واضح و مختصر را فراهم میکند. در نتیجه، تریدرها میتوانند تصمیمات بهتری بگیرند بدون اینکه نیاز به جابهجایی بین چندین پنجره یا ابزار خارجی داشته باشند.
سادگی استفاده و انعطافپذیری تابع Comment، آن را به ابزاری ارزشمند برای توسعه الگوریتمهای معاملاتی کاربرپسند و کارآمد تبدیل میکند. با یکپارچهسازی اطلاعات بههنگام و خاص به زمینه بهطور مستقیم در رابط معاملاتی، این تابع آگاهی از وضعیت را افزایش داده و روند معامله را تسهیل میکند، که به تجربه کاربری مؤثرتر و رضایتبخشتری منجر میشود. در اینجا تصویری از راهاندازی موفق Trend Constraint V1.07 را مشاهده میکنید:
دانلود فایل اکسپرت فوق
نتیجهگیری
در مسیر توسعه نرمافزار، نوآوری معمولاً از یکپارچگی بیدردسر راهحلهای موجود بهمنظور ایجاد برنامههای جامعتر و دارای ویژگیهای بیشتر به وجود میآید. این مقاله به بررسی فرآیند ادغام دو برنامه به یک واحد یکپارچه پرداخت و قدرت ترکیب قابلیتها را برای افزایش عملکرد کلی و تجربه کاربری نشان داد.
ما با درک عملکردهای اصلی دو برنامه جداگانه شروع کردیم، که هرکدام دارای نقاط قوت منحصر به فردی بودند. با تحلیل دقیق پایگاههای کد آنها و شناسایی نقاط همافزایی، موفق شدیم آنها را به یک برنامه یکپارچه ادغام کنیم. این ادغام نهتنها عملیات را سادهتر کرد بلکه همچنین از تکرار و احتمال تعارضات کاست و زمینه را برای اجرای کارآمدتر فراهم آورد.
علاوه بر این، گنجاندن تابع Comment در برنامه MQL5 بُعد جدیدی به برنامه ترکیبی ما افزود. با بهرهگیری از سیستم هشدار قدرتمند MQL5، ویژگیای را پیادهسازی کردیم که امکان ارسال اعلانهای بههنگام از طریق کانالهای مختلف، از جمله WhatsApp و Telegram را فراهم میآورد. این بهبود اطمینان میدهد که کاربران همواره از رویدادهای حیاتی مطلع هستند و این امر به بهبود واکنشپذیری و تصمیمگیری کمک میکند.
در ادامه، امکانات برای بهبودها و شخصیسازیهای بیشتر همچنان فراوان است و دعوت به نوآوری و بهبود مستمر میکند. با ساخت بر اساس فناوریهای موجود و یکپارچهسازی هوشمند ویژگیهای جدید، میتوانیم ابزارهای قدرتمندی ایجاد کنیم که بهرهوری را افزایش دهند، تعامل کاربر را بهبود بخشند و در نهایت به نتایج بهتری منجر شوند.
نظرات کاربران