English Deutsch
preview
Candlestick Trend Constraintモデルの構築(第6回):オールインワン統合

Candlestick Trend Constraintモデルの構築(第6回):オールインワン統合

MetaTrader 5トレーディングシステム | 3 9月 2024, 11:35
30 0
Clemence Benjamin
Clemence Benjamin
  1. はじめに
  2. 主な統合セクション
  3. 統合ロジックの組み合わせ
  4. Comment関数
  5. Comment関数の効果を検証する
  6. 結論


はじめに

私たちのシグナルシステムは、開発の各段階を通じて一貫して優れた性能を発揮してきました。現在の目標は、既存のプログラムを統合し、統一されたシグナルシステムを構築することです。Trend Constraint指標の前の2つのバージョンでは、それぞれ第5回で特定の統合をおこなったことを思い出してください。この統合は、複雑な反復作業を驚異的なスピードでコンピュータに実行させることで、人間の作業負荷を大幅に軽減するプログラミングの力をフルに活用することを目的としています。

ロジックは似ているが機能は異なる2つのプログラムがあることを考えると、統合プロセスでただソースコードをコピーしてペーストするだけでは不十分です。その代わり、両プログラムで一貫した効果を発揮する特定の要素を戦略的に残し、最適な機能性を確保します。このプロセスを「結合」と呼びますが、これは慎重な検討と正確さを求められる作業です。

この記事では、統合がおこなわれるMQL5のコードセクションを分解し、統合プロセス全体でグローバルに機能する重要なコード行について解説します。複数のコードスニペットを組み合わせて、まとまりのある効率的なプログラムを作るには、綿密なアプローチが欠かせません。

第5回とそのサブセクションから、私たちは2つの主要な統合をまとめました。

  1. TelegramをMetaTrader 5に統合し、通知をおこなう。
  2. WhatsAppをMetaTrader 5 に統合し、通知をおこなう。

1つの課題は、統合が他のプロセスの邪魔にならないように、ウィンドウを非表示にしてコマンドプロンプトでタスクを実行することです。その結果、シグナルがターゲットプラットフォームに正常に送信されたかどうかの確認はできません。シグナルブロードキャストが成功するたびに、チャートウィンドウにコメントを表示するか、少なくともプラットフォーム操作ログに表示します。

この記事の次のセクションで、さらに深く掘り下げて考察してみましょう。


主な統合セクション

この記事の考察のために、コードから特に注目すべき点を抜粋しました。より詳細な議論については、第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);
        }
    }
}

    統合ロジックの組み合わせ

    2つのコードスニペットを使用してWhatsAppTelegramの両方を統合するプログラムを作成するには、それぞれのスニペットのロジックを1つのまとまった関数にまとめます。計画はこうです。 

    1. グローバル変数と宣言を組み合わせる:宣言とグローバル変数を統合します。
    2. myAlert関数を結合する:myAlert関数を拡張し、WhatsAppとTelegramの両方にメッセージを送信できるようにします。
    3. コマンド実行ロジックを調整する:両方のコマンド(WhatsAppとTelegram)が同じ関数内で実行されるようにします。
    4. クールダウン期間を確保する:アラートが頻繁に送信されないようにするロジックは維持します。

    どちらのスニペットにもShellExecuteWの宣言と、クールダウン期間を管理する変数が含まれていましたが、冗長性を避けるため、これらの宣言とグローバル変数はコードの先頭で統合されました。myAlert関数はWhatsAppTelegramの両方の通知ロジックを含むように拡張され、メッセージが頻繁に送信されないようにするアラートクールダウンロジックを備えています。要約すると、WhatsAppではPython実行ファイルとWhatsAppスクリプトのパスが定義され、WhatsAppメッセージ送信スクリプトを実行するためのコマンド文字列が作成されます。このコマンドはShellExecuteWを使用して実行され、エラーがあればログに記録されます。同様に、Telegramについては、Python実行ファイルとTelegramスクリプトへのパスが定義され、Telegramメッセージ送信スクリプトを実行するためのコマンド文字列が構築され、ShellExecuteWを使用してコマンドが実行され、エラーがあればログに記録するための結果確認がおこなわれます。

    これが結合したプログラムです。

    //--- ShellExecuteW declaration ----------------------------------------------
    #import "shell32.dll"
    int ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
    #import
    
    //--- global variables ------------------------------------------------------
    datetime last_alert_time;
    input int alert_cooldown_seconds = 60; // Cooldown period in seconds
    
    //--- myAlert function ------------------------------------------------------
    void myAlert(string type, string message) {
        datetime current_time = TimeCurrent();
        if (current_time - last_alert_time < alert_cooldown_seconds) {
            // Skip alert if within cooldown period
            return;
        }
    
        last_alert_time = current_time;
        string full_message = type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message;
        if (type == "print") {
            Print(message);
        } else if (type == "error") {
            Print(type + " | Trend Constraint V1.06 @ " + Symbol() + "," + IntegerToString(Period()) + " | " + message);
        } else if (type == "order") {
            // Add order alert handling if needed
        } else if (type == "modify") {
            // Add modify alert handling if needed
        } else if (type == "indicator" || type == "info") {
            if (Audible_Alerts) {
                Alert(full_message);
            }
            if (Push_Notifications) {
                SendNotification(full_message);
            }
    
            // Send to WhatsApp
            string python_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
            string whatsapp_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_whatsapp_message.py";
            string whatsapp_command = python_path + " \"" + whatsapp_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for WhatsApp
            Print("Executing command to send WhatsApp message: ", whatsapp_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_whatsapp_command = "/c " + whatsapp_command + " && timeout 5";
            int whatsapp_result = ShellExecuteW(0, "open", "cmd.exe", final_whatsapp_command, NULL, 1);
            if (whatsapp_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute WhatsApp Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed WhatsApp Python script. Result code: ", whatsapp_result);
            }
    
            // Send to Telegram
            string telegram_script_path = "C:\\Users\\Your_Computer_Name\\AppData\\Local\\Programs\\Python\\Python312\\Scripts\\send_telegram_message.py";
            string telegram_command = python_path + " \"" + telegram_script_path + "\" \"" + full_message + "\"";
            
            // Debugging: Print the command being executed for Telegram
            Print("Executing command to send Telegram message: ", telegram_command);
    
            // Use cmd.exe to execute the command and then wait for 5 seconds
            string final_telegram_command = "/c " + telegram_command + " && timeout 5";
            int telegram_result = ShellExecuteW(0, "open", "cmd.exe", final_telegram_command, NULL, 1);
            if (telegram_result <= 32) {
                int error_code = GetLastError();
                Print("Failed to execute Telegram Python script. Error code: ", error_code);
            } else {
                Print("Successfully executed Telegram Python script. Result code: ", telegram_result);
            }
        }
    }
    
    

    この段階で、コードをセクションに分け、それぞれの機能を説明します。

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

    このセクションでは、shell32.dll Windowsライブラリから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;
    
    • このセクションは、現在時刻から前回の警告時刻を引いた値がクールダウン時間未満かどうかを確認します。trueの場合、アラートの送信をスキップします。これにより、短期間に頻繁にアラートが鳴るのを防ぐことができます。

    スクリプトが機能していることを確認するために、コマンドプロンプトで以下の結果を得ます。

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

    ハイライトされたテキストは、コマンドプロンプトからの肯定的な応答で、スクリプトが問題なく動作していることが確認されます。メインプログラムでファイルパスを正しく追加することが非常に重要です。

    その一方で、ソーシャルプラットフォーム上でもシグナルを受け取ります。下の左側はコマンドプロンプトからのTelegramのテストメッセージ、右側はコマンドプロンプトからのWhatsAppのテストメッセージです。これでプログラムが正常に動作していることが確認できたので、メインプログラムに進むことができます。

    Telegramスクリプトテスト Whatsappスクリプトテスト

    上の図では、WhatsApp統合のためにTwilio APIが提供するサンドボックス接続は72時間以内に期限切れとなります。APIメッセージを受信するために、ユニークなメッセージを送信して再接続することが重要です。この場合、再接続のためのメッセージは「join so-cave」となります。 期限切れのないサービスを取得するには、Twilio番号を購入します。

    それでは、Trend Constraint指標のロジックを使用して、すべてを1つのプログラムに統合しましょう。これでTrend ConstraintV1.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 Androidモバイルのプッシュ通知、中央はTelegramのテスト通知、右はWhatsAppのテストメッセージです。

    アンドロイドのMetaTrade 5プッシュ通知 Telegram、Trend ConstraintV1.07テスト Whatsapp, Trend Constraint V1.07テスト



    Comment関数

    MQL5のComment関数は、カスタムテキストメッセージをチャート上に直接表示するために使用される組み込み関数です。この関数は、指標やEAの実行中に継続的に更新されるメッセージを表示することで、リアルタイムの視覚的なフィードバックを提供するのに役立ちます。この場合、私たちの目的はそれを使用して次のことを達成することです。

    • 指標が正常に起動したことをユーザーに通知する
    • アラートメッセージが正常に送信されたことを確認する
    • アラートメッセージの送信に失敗した場合、ユーザーにアラートを出す

    この機能を組み込むために、コード内の3つのエリアをターゲットにします。

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

    上記のコードスニペットの目的は、指標が正常に起動したことを通知することです。指標の初期化に成功すると、コメント関数はチャート上に「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 ConstraintV1.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関数の効果を検証する

    MQL5でComment関数を実装することは、取引チャートのインタラクティブ性と形成性を高める簡単な方法です。この機能を統合することで、トレーダーに必要不可欠なリアルタイムの最新情報をチャート上で直接提供することができ、トレーダーの全体的な取引体験を向上させることができます。この関数により、現在価格、指標値、カスタムメッセージなどのダイナミックデータを分かりやすく表示することができます。その結果、トレーダーは複数のウィンドウや外部ツールを切り替えることなく、より多くの情報に基づいた意思決定をおこなうことができます。

    Comment関数は、その使いやすさと柔軟性により、ユーザーフレンドリーで効率的な取引アルゴリズムの開発において、非常に有用なツールとなっています。リアルタイムで状況に応じた情報を取引インターフェイスに直接組み込むことで、この関数は状況認識を高め、取引プロセスを合理化し、より効果的で満足度の高いユーザー体験に貢献します。以下は、Trend ConstraintV1.07が正常に起動したことを示す画像です。

     



    結論

    ソフトウェア開発の過程では、革新はしばしば既存のソリューションをシームレスに統合し、より堅牢で機能豊富なアプリケーションを作り上げることで実現されます。 この記事では、2つのプログラムを1つの統合されたユニットにまとめるプロセスを探り、全体的なパフォーマンスとユーザー体験を向上させるために、機能を組み合わせることの効果を示しました。

    まず、個別に強みを持つ2つのプログラムの中核機能を理解することから始めました。両者のコードベースを注意深く分析し、相乗効果を発揮する部分を特定したことで、これらのプログラムを統合し、より一体感のあるシステムを構築することができました。この結合により、業務の効率化が進み、重複や潜在的な競合が減少し、より効率的な実行が可能となりました。

    さらに、MQL5プログラムにComment関数を組み込むことで、アプリケーションに新たな価値を追加しました。MQL5の堅牢なアラートシステムを活用することで、WhatsAppやTelegramなど、さまざまなチャネルを通じてリアルタイムの通知を実現しました。この機能強化により、ユーザーは常に重要なイベントを把握できるため、迅速な対応と意思決定が可能になります。

     今後も、さらなる強化やカスタマイズの可能性は広がっており、継続的な改善と革新が求められます。既存のテクノロジーを基盤に、新しい機能を慎重に統合することで、効率性とユーザーエンゲージメントを高め、最終的にはより優れた成果をもたらす強力なツールを創り出すことができるでしょう。

    以下の添付ファイルを参照してください。ご意見やコメントをお待ちしています。

    添付ファイル 詳細
    Trend Constraint V1.07.mq5 2つのプラットフォームを1つのプログラムに統合
    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

    EAのサンプル EAのサンプル
    一般的なMACDを使ったEAを例として、MQL4開発の原則を紹介します。
    初心者のためのMQL5によるSP500取引戦略 初心者のためのMQL5によるSP500取引戦略
    MQL5を活用してS&P500指数を正確に予測する方法をご紹介します。古典的なテクニカル分析とアルゴリズム、そして長年の経験に裏打ちされた原理を組み合わせることで、安定性を高め、確かな市場洞察力を得られます。
    エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
    この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
    スマートマネーコンセプト(BOS)とRSI指標をEAに統合する方法 スマートマネーコンセプト(BOS)とRSI指標をEAに統合する方法
    市場構造に基づいた情報に基づく自動売買の意思決定を可能にするためには、スマートマネーコンセプト(Break Of Structure: BOS)とRSI指標の組み合わせが有効です。