English Deutsch
preview
MQL5取引ツール(第3回):戦略的取引のための多時間軸スキャナーダッシュボードの構築

MQL5取引ツール(第3回):戦略的取引のための多時間軸スキャナーダッシュボードの構築

MetaTrader 5トレーディング |
114 0
Allan Munene Mutiiria
Allan Munene Mutiiria

はじめに

前回の記事(第2回)では、MetaQuotes Language 5 (MQL5)で取引アシスタントツールを強化し、インタラクティブ性向上のための動的なビジュアルフィードバックを追加しました。今回は、戦略的な意思決定のためにリアルタイムの取引シグナルを提供する多時間軸スキャナーダッシュボードの構築に焦点を当てます。インジケーター駆動のシグナルとクローズボタンを備えたグリッドベースのインターフェースを紹介し、以下のサブトピックを通じてこれらの進展を解説します。

  1. スキャナーダッシュボードの計画
  2. MQL5での実装
  3. バックテスト
  4. 結論

これらのセクションにより、直感的で強力な取引ダッシュボードの作成に向けたガイドとなります。


スキャナーダッシュボードの計画

戦略的な意思決定を支援するため、明確でリアルタイムの取引シグナルを提供する多時間軸スキャナーダッシュボードの作成を目指します。このダッシュボードは、複数の時間軸にわたる買いシグナルと売りシグナルをグリッドレイアウトで表示し、チャートを切り替えることなく市場状況を迅速に把握できるように設計されます。また、クローズボタンを設置し、パネルの簡単な閉鎖を可能にすることで、取引ニーズに応じて柔軟でクリーンなユーザー体験を提供します。

主要なインジケーターとして、相対力指数(RSI: Relative Strength Index)、ストキャスティクス(STOCH)、コモディティチャンネル指数(CCI)、平均方向性指数(ADX: Average Directional Index)、オーサムオシレーター(AO: Awesome Oscillator)を用いたシグナルを組み込みます。これらは、カスタマイズ可能な強度の閾値に基づき、潜在的な取引機会を特定することを目的としています。ただし、使用するインジケーターやプライスアクションデータの選択はユーザー次第です。この構成により、複数の時間軸にわたるトレンドや反転を把握し、短期戦略および長期戦略の両方をサポートします。私たちの目標は、ユーザーフレンドリーでありながら実用的な洞察を提供する、効率的で直感的なツールを作ることです。将来的には、自動アラートや追加インジケーターの導入など、さらなる拡張も見据えています。以下は、私たちが目指すイメージの可視化です。

実施計画


MQL5での実装

MQL5でプログラムを作成するには、まずプログラムのメタデータを定義し、その後、ダッシュボードのオブジェクトを参照しやすく管理するためのオブジェクト名定数をいくつか定義する必要があります。

//+------------------------------------------------------------------+
//|                             TimeframeScanner Dashboard EA.mq5    |
//|                           Copyright 2025, Allan Munene Mutiiria. |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Allan Munene Mutiiria."
#property link      "https://t.me/Forex_Algo_Trader"
#property version   "1.00"

// Define identifiers and properties for UI elements
#define MAIN_PANEL              "PANEL_MAIN"                     //--- Main panel rectangle identifier
#define HEADER_PANEL            "PANEL_HEADER"                   //--- Header panel rectangle identifier
#define HEADER_PANEL_ICON       "PANEL_HEADER_ICON"              //--- Header icon label identifier
#define HEADER_PANEL_TEXT       "PANEL_HEADER_TEXT"              //--- Header title label identifier
#define CLOSE_BUTTON            "BUTTON_CLOSE"                   //--- Close button identifier
#define SYMBOL_RECTANGLE        "SYMBOL_HEADER"                  //--- Symbol rectangle identifier
#define SYMBOL_TEXT             "SYMBOL_TEXT"                    //--- Symbol text label identifier
#define TIMEFRAME_RECTANGLE     "TIMEFRAME_"                     //--- Timeframe rectangle prefix
#define TIMEFRAME_TEXT          "TIMEFRAME_TEXT_"                //--- Timeframe text label prefix
#define HEADER_RECTANGLE        "HEADER_"                        //--- Header rectangle prefix
#define HEADER_TEXT             "HEADER_TEXT_"                   //--- Header text label prefix
#define RSI_RECTANGLE           "RSI_"                           //--- RSI rectangle prefix
#define RSI_TEXT                "RSI_TEXT_"                      //--- RSI text label prefix
#define STOCH_RECTANGLE         "STOCH_"                         //--- Stochastic rectangle prefix
#define STOCH_TEXT              "STOCH_TEXT_"                    //--- Stochastic text label prefix
#define CCI_RECTANGLE           "CCI_"                           //--- CCI rectangle prefix
#define CCI_TEXT                "CCI_TEXT_"                      //--- CCI text label prefix
#define ADX_RECTANGLE           "ADX_"                           //--- ADX rectangle prefix
#define ADX_TEXT                "ADX_TEXT_"                      //--- ADX text label prefix
#define AO_RECTANGLE            "AO_"                            //--- AO rectangle prefix
#define AO_TEXT                 "AO_TEXT_"                       //--- AO text label prefix
#define BUY_RECTANGLE           "BUY_"                           //--- Buy rectangle prefix
#define BUY_TEXT                "BUY_TEXT_"                      //--- Buy text label prefix
#define SELL_RECTANGLE          "SELL_"                          //--- Sell rectangle prefix
#define SELL_TEXT               "SELL_TEXT_"                     //--- Sell text label prefix
#define WIDTH_TIMEFRAME         90                               //--- Width of timeframe and symbol rectangles
#define WIDTH_INDICATOR         70                               //--- Width of indicator rectangles
#define WIDTH_SIGNAL            90                               //--- Width of BUY/SELL signal rectangles
#define HEIGHT_RECTANGLE        25                               //--- Height of all rectangles
#define COLOR_WHITE             clrWhite                         //--- White color for text and backgrounds
#define COLOR_BLACK             clrBlack                         //--- Black color for borders and text
#define COLOR_LIGHT_GRAY        C'230,230,230'                   //--- Light gray color for signal backgrounds
#define COLOR_DARK_GRAY         C'105,105,105'                   //--- Dark gray color for indicator backgrounds

まず、#defineディレクティブを使用して、多時間軸スキャナーダッシュボードのユーザーインターフェースのフレームワークを構築します。メインパネルとヘッダーパネルの矩形にはMAIN_PANELやHEADER_PANEL、ヘッダのアイコン、タイトル、クローズボタンにはHEADER_PANEL_ICON、HEADER_PANEL_TEXT、CLOSE_BUTTONといった定数を作成します。

次に、ダッシュボードのグリッド構造用の識別子を定義します。銘柄にはSYMBOL_RECTANGLEとSYMBOL_TEXT、時間軸の行にはTIMEFRAME_RECTANGLEとTIMEFRAME_TEXTというプレフィックスを使用します。列ヘッダーにはHEADER_RECTANGLEとHEADER_TEXT、インジケーターやシグナルセルにはRSI_RECTANGLE、STOCH_RECTANGLE、BUY_RECTANGLEと対応するRSI_TEXT、STOCH_TEXT、BUY_TEXTといったプレフィックスを使います。

サイズはWIDTH_TIMEFRAME(90ピクセル)、WIDTH_INDICATOR(70ピクセル)、WIDTH_SIGNAL(90ピクセル)、HEIGHT_RECTANGLE(25ピクセル)で設定します。色は、テキストや枠線にCOLOR_WHITEとCOLOR_BLACK、シグナル背景にCOLOR_LIGHT_GRAY (C'230,230,230')、インジケーター背景にCOLOR_DARK_GRAY (C'105,105,105')を使用し、均一で見やすいレイアウトを確保します。さらに、プログラム全体で使用するいくつかのグローバル変数を定義する必要があります。

bool panel_is_visible = true;                                    //--- Flag to control panel visibility

// Define the timeframes to be used
ENUM_TIMEFRAMES timeframes_array[] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M20, PERIOD_M30, 
                                      PERIOD_H1, PERIOD_H2, PERIOD_H3, PERIOD_H4, PERIOD_H8, 
                                      PERIOD_H12, PERIOD_D1, PERIOD_W1}; //--- Array of timeframes for scanning

// Global variables for indicator values
double rsi_values[];                                             //--- Array to store RSI values
double stochastic_values[];                                      //--- Array to store Stochastic signal line values
double cci_values[];                                             //--- Array to store CCI values
double adx_values[];                                             //--- Array to store ADX values
double ao_values[];                                              //--- Array to store AO values

ここでは、ブール型変数panel_is_visibleを宣言し、trueに設定します。この変数はダッシュボードがチャート上に表示されるかどうかを決定します。このフラグにより、データ更新が不要な場合などにダッシュボードの表示を切り替えることができます。次に、ENUM_TIMEFRAMES型を使用して配列timeframes_arrayを定義し、PERIOD_M1(1分)からPERIOD_W1(週足)までの期間を列挙します。この配列はダッシュボードが分析する時間軸を指定し、複数の時間軸にわたる市場シグナルを構造的にスキャンできるようにします。不要な場合や変更したい場合は、列挙型を修正してください。

インジケーターのデータを格納するために、double型の配列rsi_values、stochastic_values、cci_values、adx_values、ao_valuesを作成します。これらの配列はそれぞれ相対力指数(RSI)、ストキャス(STOCH)、コモディティチャンネル指数(CCI)、平均方向性指数(ADX)、オーサムオシレーター(AO)の計算値を保持し、各時間軸に対する取引シグナルを効率的に処理・表示できるようにします。次に、取得したチャート銘柄の方向や切り捨てを判定するために使用するヘルパー関数を定義できます。

//+------------------------------------------------------------------+
//| Truncate timeframe enum to display string                        |
//+------------------------------------------------------------------+
string truncate_timeframe_name(int timeframe_index)              //--- Function to format timeframe name
{
   string timeframe_string = StringSubstr(EnumToString(timeframes_array[timeframe_index]), 7); //--- Extract timeframe name
   return timeframe_string;                                      //--- Return formatted name
}

//+------------------------------------------------------------------+
//| Calculate signal strength for buy/sell                           |
//+------------------------------------------------------------------+
string calculate_signal_strength(double rsi, double stochastic, double cci, double adx, double ao, bool is_buy) //--- Function to compute signal strength
{
   int signal_strength = 0;                                      //--- Initialize signal strength counter
   
   if(is_buy && rsi < 40) signal_strength++;                     //--- Increment for buy if RSI is oversold
   else if(!is_buy && rsi > 60) signal_strength++;               //--- Increment for sell if RSI is overbought
   
   if(is_buy && stochastic < 40) signal_strength++;              //--- Increment for buy if Stochastic is oversold
   else if(!is_buy && stochastic > 60) signal_strength++;        //--- Increment for sell if Stochastic is overbought
   
   if(is_buy && cci < -70) signal_strength++;                    //--- Increment for buy if CCI is oversold
   else if(!is_buy && cci > 70) signal_strength++;               //--- Increment for sell if CCI is overbought
   
   if(adx > 40) signal_strength++;                               //--- Increment if ADX indicates strong trend
   
   if(is_buy && ao > 0) signal_strength++;                       //--- Increment for buy if AO is positive
   else if(!is_buy && ao < 0) signal_strength++;                 //--- Increment for sell if AO is negative
   
   if(signal_strength >= 3) return is_buy ? "Strong Buy" : "Strong Sell"; //--- Return strong signal if 3+ conditions met
   if(signal_strength >= 2) return is_buy ? "Buy" : "Sell";      //--- Return regular signal if 2 conditions met
   return "Neutral";                                             //--- Return neutral if insufficient conditions
}

ここでは、truncate_timeframe_name関数を定義します。この関数は整数型パラメータtimeframe_indexを受け取り、表示用に時間軸の名前を整形します。内部では、EnumToString関数をtimeframes_array[timeframe_index]に適用した結果から、StringSubstr関数を使って位置7からの部分文字列を抽出し、timeframe_stringに格納します。そしてtimeframe_stringを返すことで、ユーザーに読みやすい時間軸名を提供します。

次に、calculate_signal_strength関数を作成し、インジケーター値に基づいて買いまたは売りのシグナルを判定します。整数型のsignal_strengthを0で初期化し、条件が一致した回数をカウントします。相対力指数(RSI)では、is_buyがtrueかつrsiが40未満(売られ過ぎ)である場合、またはis_buyがfalseかつrsiが60を超える(買われ過ぎ)場合にsignal_strengthを増加させます。同様にストキャスティクス(40未満または60超)、CCI(-70未満または70超)、AO(買いは正、売りは負)を確認し、条件を満たすたびにsignal_strengthを増加させます。

さらに平均方向性指数(ADX)も評価し、adxが40を超える場合は買い・売りいずれのシナリオでも強いトレンドと判断してsignal_strengthを増加させます。signal_strengthが3以上の場合、is_buyがtrueなら「Strong Buy」、falseなら「Strong Sell」を返します。2の場合はBuyまたはSell、1以下の場合はNeutralを返すことで、ダッシュボード用に明確なシグナル分類を可能にします。最後に、オブジェクトを作成するために使用する関数を定義できる状態になります。

//+------------------------------------------------------------------+
//| Create a rectangle for the UI                                    |
//+------------------------------------------------------------------+
bool create_rectangle(string object_name, int x_distance, int y_distance, int x_size, int y_size, 
                      color background_color, color border_color = COLOR_BLACK) //--- Function to create a rectangle
{
   ResetLastError();                                                            //--- Reset error code
   if(!ObjectCreate(0, object_name, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {            //--- Create rectangle object
      Print(__FUNCTION__, ": failed to create Rectangle: ERR Code: ", GetLastError()); //--- Log creation failure
      return(false);                                                            //--- Return failure
   }
   ObjectSetInteger(0, object_name, OBJPROP_XDISTANCE, x_distance);             //--- Set x position
   ObjectSetInteger(0, object_name, OBJPROP_YDISTANCE, y_distance);             //--- Set y position
   ObjectSetInteger(0, object_name, OBJPROP_XSIZE, x_size);                     //--- Set width
   ObjectSetInteger(0, object_name, OBJPROP_YSIZE, y_size);                     //--- Set height
   ObjectSetInteger(0, object_name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);        //--- Set corner to top-right
   ObjectSetInteger(0, object_name, OBJPROP_BGCOLOR, background_color);         //--- Set background color
   ObjectSetInteger(0, object_name, OBJPROP_BORDER_COLOR, border_color);        //--- Set border color
   ObjectSetInteger(0, object_name, OBJPROP_BORDER_TYPE, BORDER_FLAT);          //--- Set flat border style
   ObjectSetInteger(0, object_name, OBJPROP_BACK, false);                       //--- Set to foreground
   
   ChartRedraw(0);                                                              //--- Redraw chart
   return(true);                                                                //--- Return success
}

//+------------------------------------------------------------------+
//| Create a text label for the UI                                   |
//+------------------------------------------------------------------+
bool create_label(string object_name, string text, int x_distance, int y_distance, int font_size = 12, 
                  color text_color = COLOR_BLACK, string font = "Arial Rounded MT Bold") //--- Function to create a label
{
   ResetLastError();                                                               //--- Reset error code
   if(!ObjectCreate(0, object_name, OBJ_LABEL, 0, 0, 0)) {                         //--- Create label object
      Print(__FUNCTION__, ": failed to create Label: ERR Code: ", GetLastError()); //--- Log creation failure
      return(false);                                                               //--- Return failure
   }
   ObjectSetInteger(0, object_name, OBJPROP_XDISTANCE, x_distance);                //--- Set x position
   ObjectSetInteger(0, object_name, OBJPROP_YDISTANCE, y_distance);                //--- Set y position
   ObjectSetInteger(0, object_name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);           //--- Set corner to top-right
   ObjectSetString(0, object_name, OBJPROP_TEXT, text);                            //--- Set label text
   ObjectSetString(0, object_name, OBJPROP_FONT, font);                            //--- Set font
   ObjectSetInteger(0, object_name, OBJPROP_FONTSIZE, font_size);                  //--- Set font size
   ObjectSetInteger(0, object_name, OBJPROP_COLOR, text_color);                    //--- Set text color
   ObjectSetInteger(0, object_name, OBJPROP_ANCHOR, ANCHOR_CENTER);                //--- Center text
   
   ChartRedraw(0);                                                                 //--- Redraw chart
   return(true);                                                                   //--- Return success
}

オブジェクトの作成を可能にするために、create_rectangle関数を定義します。この関数はobject_name、x_distance、y_distance、x_size、y_size、background_color、border_colorのパラメータを受け取ります。まずResetLastError関数を使用し、ObjectCreate関数でOBJ_RECTANGLE_LABELを作成します。作成に失敗した場合はPrint関数でエラーをログに出力し、falseを返します。

次にObjectSetInteger関数を使用して、位置、サイズ、CORNER_RIGHT_UPPER、background_color、border_color、BORDER_FLATなどの矩形プロパティを設定し、前景に表示されるようにします。ChartRedraw関数を呼び出し、trueを返します。テキスト用には、create_label関数を定義します。パラメータはobject_name、text、x_distance、y_distance、font_size、text_color、fontです。

ResetLastError関数を使用し、ObjectCreate関数でOBJ_LABELを作成します。作成に失敗した場合はエラーをログに出力します。ObjectSetInteger関数で位置、サイズ、色、ANCHOR_CENTERを設定し、ObjectSetString関数でtextとfontを設定します。ChartRedraw関数を呼び出し、trueを返します。これらの関数を用意することで、OnInitイベントハンドラ内で初期パネルオブジェクトを作成し、作業の出発点を整えることができます。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()                                                                             //--- Initialize EA
{
   create_rectangle(MAIN_PANEL, 632, 40, 617, 374, C'30,30,30', BORDER_FLAT);            //--- Create main panel background
   create_rectangle(HEADER_PANEL, 632, 40, 617, 27, C'60,60,60', BORDER_FLAT);           //--- Create header panel background
   create_label(HEADER_PANEL_ICON, CharToString(91), 620, 54, 18, clrAqua, "Wingdings"); //--- Create header icon
   create_label(HEADER_PANEL_TEXT, "TimeframeScanner", 527, 52, 13, COLOR_WHITE);        //--- Create header title
   create_label(CLOSE_BUTTON, CharToString('r'), 32, 54, 18, clrYellow, "Webdings");     //--- Create close button

   // Create header rectangle and label
   create_rectangle(SYMBOL_RECTANGLE, 630, 75, WIDTH_TIMEFRAME, HEIGHT_RECTANGLE, clrGray); //--- Create symbol rectangle
   create_label(SYMBOL_TEXT, _Symbol, 585, 85, 11, COLOR_WHITE); //--- Create symbol label
   
   // Create summary and indicator headers (rectangles and labels)
   string header_names[] = {"BUY", "SELL", "RSI", "STOCH", "CCI", "ADX", "AO"};            //--- Define header titles
   for(int header_index = 0; header_index < ArraySize(header_names); header_index++) {     //--- Loop through headers
      int x_offset = (630 - WIDTH_TIMEFRAME) - (header_index < 2 ? header_index * WIDTH_SIGNAL : 2 * WIDTH_SIGNAL + (header_index - 2) * WIDTH_INDICATOR) + (1 + header_index); //--- Calculate x position
      int width = (header_index < 2 ? WIDTH_SIGNAL : WIDTH_INDICATOR);                     //--- Set width based on header type
      create_rectangle(HEADER_RECTANGLE + IntegerToString(header_index), x_offset, 75, width, HEIGHT_RECTANGLE, clrGray);             //--- Create header rectangle
      create_label(HEADER_TEXT + IntegerToString(header_index), header_names[header_index], x_offset - width/2, 85, 11, COLOR_WHITE); //--- Create header label
   }
   
   // Create timeframe rectangles and labels, and summary/indicator cells
   for(int timeframe_index = 0; timeframe_index < ArraySize(timeframes_array); timeframe_index++) {            //--- Loop through timeframes
      // Highlight current timeframe
      color timeframe_background = (timeframes_array[timeframe_index] == _Period) ? clrLimeGreen : clrGray;    //--- Set background color for current timeframe
      color timeframe_text_color = (timeframes_array[timeframe_index] == _Period) ? COLOR_BLACK : COLOR_WHITE; //--- Set text color for current timeframe
      
      create_rectangle(TIMEFRAME_RECTANGLE + IntegerToString(timeframe_index), 630, (75 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), WIDTH_TIMEFRAME, HEIGHT_RECTANGLE, timeframe_background);   //--- Create timeframe rectangle
      create_label(TIMEFRAME_TEXT + IntegerToString(timeframe_index), truncate_timeframe_name(timeframe_index), 585, (85 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), 11, timeframe_text_color); //--- Create timeframe label
                  
      // Create summary and indicator cells
      for(int header_index = 0; header_index < ArraySize(header_names); header_index++) { //--- Loop through headers for cells
         string cell_rectangle_name, cell_text_name;                                      //--- Declare cell name and label variables
         color cell_background = (header_index < 2) ? COLOR_LIGHT_GRAY : COLOR_BLACK;     //--- Set cell background color
         switch(header_index) {                                   //--- Select cell type
            case 0: cell_rectangle_name = BUY_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = BUY_TEXT + IntegerToString(timeframe_index); break;     //--- Buy cell
            case 1: cell_rectangle_name = SELL_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = SELL_TEXT + IntegerToString(timeframe_index); break;   //--- Sell cell
            case 2: cell_rectangle_name = RSI_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = RSI_TEXT + IntegerToString(timeframe_index); break;     //--- RSI cell
            case 3: cell_rectangle_name = STOCH_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = STOCH_TEXT + IntegerToString(timeframe_index); break; //--- Stochastic cell
            case 4: cell_rectangle_name = CCI_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = CCI_TEXT + IntegerToString(timeframe_index); break;     //--- CCI cell
            case 5: cell_rectangle_name = ADX_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = ADX_TEXT + IntegerToString(timeframe_index); break;     //--- ADX cell
            case 6: cell_rectangle_name = AO_RECTANGLE + IntegerToString(timeframe_index); cell_text_name = AO_TEXT + IntegerToString(timeframe_index); break;       //--- AO cell
         }
         int x_offset = (630 - WIDTH_TIMEFRAME) - (header_index < 2 ? header_index * WIDTH_SIGNAL : 2 * WIDTH_SIGNAL + (header_index - 2) * WIDTH_INDICATOR) + (1 + header_index);        //--- Calculate x position
         int width = (header_index < 2 ? WIDTH_SIGNAL : WIDTH_INDICATOR); //--- Set width based on cell type
         create_rectangle(cell_rectangle_name, x_offset, (75 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), width, HEIGHT_RECTANGLE, cell_background); //--- Create cell rectangle
         create_label(cell_text_name, "-/-", x_offset - width/2, (85 + HEIGHT_RECTANGLE) + timeframe_index * HEIGHT_RECTANGLE - (1 + timeframe_index), 10, COLOR_WHITE);                  //--- Create cell label
      }
   }
   
   // Initialize indicator arrays
   ArraySetAsSeries(rsi_values, true);                       //--- Set RSI array as timeseries
   ArraySetAsSeries(stochastic_values, true);                //--- Set Stochastic array as timeseries
   ArraySetAsSeries(cci_values, true);                       //--- Set CCI array as timeseries
   ArraySetAsSeries(adx_values, true);                       //--- Set ADX array as timeseries
   ArraySetAsSeries(ao_values, true);                        //--- Set AO array as timeseries
    
   return(INIT_SUCCEEDED);                                   //--- Return initialization success
}

OnInitイベントハンドラ内で、多時間軸スキャナーダッシュボードのユーザーインターフェースを初期化します。まずcreate_rectangle関数を使用して、MAIN_PANELを位置(632,40)、サイズ617x374ピクセル、色C'30,30,30'で描画し、同じ位置に高さ27ピクセル、色C'60,60,60'でHEADER_PANELを描画します。次にcreate_label関数を使用して、HEADER_PANEL_ICONをWingdings文字で位置(620,54)に追加します。MQL5のデフォルト文字を使用し、CharToString関数で文字コードを文字列に変換します。ここでは文字コード91を使用していますが、任意の文字を使用できます。

MQL5 WINGDINGS

その後、HEADER_PANEL_TEXTを「TimeframeScanner」として位置(527,52)に作成し、CLOSE_BUTTONを位置(32,54)に作成します。この場合は別のフォントを使用し、文字「r」を文字列としてマッピングします。使用可能なフォントシンボルの可視化も参考にできます。

シンボルフォント

次に銘柄表示を設定します。create_rectangle関数でSYMBOL_RECTANGLEを位置(630,75)、サイズWIDTH_TIMEFRAME×HEIGHT_RECTANGLE、色グレーで作成し、create_label関数でSYMBOL_TEXTを位置(585,85)に現在の銘柄として配置します。ヘッダについては、header_names配列に「BUY」や「RSI」といったタイトルを定義し、ループでy=75にHEADER_RECTANGLEを作成、xオフセットはWIDTH_SIGNALやWIDTH_INDICATORに基づき、y=85にHEADER_TEXTラベルをcreate_label関数で配置します。

時間軸のグリッドはtimeframes_arrayをループして作成します。create_rectangle関数でTIMEFRAME_RECTANGLEをx=630、yオフセットは75+HEIGHT_RECTANGLE-(1+timeframe_index)として、色timeframe_backgroundで描画します。create_label関数でTIMEFRAME_TEXTをtruncate_timeframe_name関数から取得した名前で配置します。セルについては、BUY_RECTANGLE、RSI_RECTANGLEなどをループでcreate_rectangle関数で作成し、色cell_backgroundを設定、さらにcreate_label関数で「-/-」ラベルを追加します。インジケーター配列(rsi_valuesなど)はArraySetAsSeries関数を使用して時系列データとして設定します。INIT_SUCCEEDEDを返すことで初期化が成功したことを確認し、ダッシュボードのレイアウトとデータ構造を確立します。コンパイルすると、次の結果が得られます。

静的ダッシュボード

画像からわかるように、ダッシュボードは準備完了です。あとはインジケーター値を追加して分析に使用するだけです。分析用の関数はすでに用意されているため、データを取得するだけで済みます。そのために、すべての動的更新ロジックを処理する関数を作成します。

//+------------------------------------------------------------------+
//| Update indicator values                                          |
//+------------------------------------------------------------------+
void updateIndicators()                                                                               //--- Update dashboard indicators
{
   for(int timeframe_index = 0; timeframe_index < ArraySize(timeframes_array); timeframe_index++) {   //--- Loop through timeframes
      // Initialize indicator handles
      int rsi_indicator_handle = iRSI(_Symbol, timeframes_array[timeframe_index], 14, PRICE_CLOSE);   //--- Create RSI handle
      int stochastic_indicator_handle = iStochastic(_Symbol, timeframes_array[timeframe_index], 14, 3, 3, MODE_SMA, STO_LOWHIGH); //--- Create Stochastic handle
      int cci_indicator_handle = iCCI(_Symbol, timeframes_array[timeframe_index], 20, PRICE_TYPICAL); //--- Create CCI handle
      int adx_indicator_handle = iADX(_Symbol, timeframes_array[timeframe_index], 14);                //--- Create ADX handle
      int ao_indicator_handle = iAO(_Symbol, timeframes_array[timeframe_index]);                      //--- Create AO handle
      
      // Check for valid handles
      if(rsi_indicator_handle == INVALID_HANDLE || stochastic_indicator_handle == INVALID_HANDLE || 
         cci_indicator_handle == INVALID_HANDLE || adx_indicator_handle == INVALID_HANDLE || 
         ao_indicator_handle == INVALID_HANDLE) {                                                             //--- Check if any handle is invalid
         Print("Failed to create indicator handle for timeframe ", truncate_timeframe_name(timeframe_index)); //--- Log failure
         continue;                                                                                            //--- Skip to next timeframe
      }
      
      // Copy indicator values
      if(CopyBuffer(rsi_indicator_handle, 0, 0, 1, rsi_values) <= 0 ||                            //--- Copy RSI value
         CopyBuffer(stochastic_indicator_handle, 1, 0, 1, stochastic_values) <= 0 ||              //--- Copy Stochastic signal line value
         CopyBuffer(cci_indicator_handle, 0, 0, 1, cci_values) <= 0 ||                            //--- Copy CCI value
         CopyBuffer(adx_indicator_handle, 0, 0, 1, adx_values) <= 0 ||                            //--- Copy ADX value
         CopyBuffer(ao_indicator_handle, 0, 0, 1, ao_values) <= 0) {                              //--- Copy AO value
         Print("Failed to copy buffer for timeframe ", truncate_timeframe_name(timeframe_index)); //--- Log copy failure
         continue;                                                                                //--- Skip to next timeframe
      }
      
      // Update RSI
      color rsi_text_color = (rsi_values[0] < 30) ? clrBlue : (rsi_values[0] > 70) ? clrRed : COLOR_WHITE;         //--- Set RSI text color
      update_label(RSI_TEXT + IntegerToString(timeframe_index), DoubleToString(rsi_values[0], 2), rsi_text_color); //--- Update RSI label
      
      // Update Stochastic (Signal Line only)
      color stochastic_text_color = (stochastic_values[0] < 20) ? clrBlue : (stochastic_values[0] > 80) ? clrRed : COLOR_WHITE;    //--- Set Stochastic text color
      update_label(STOCH_TEXT + IntegerToString(timeframe_index), DoubleToString(stochastic_values[0], 2), stochastic_text_color); //--- Update Stochastic label
      
      // Update CCI
      color cci_text_color = (cci_values[0] < -100) ? clrBlue : (cci_values[0] > 100) ? clrRed : COLOR_WHITE;      //--- Set CCI text color
      update_label(CCI_TEXT + IntegerToString(timeframe_index), DoubleToString(cci_values[0], 2), cci_text_color); //--- Update CCI label
      
      // Update ADX
      color adx_text_color = (adx_values[0] > 25) ? clrBlue : COLOR_WHITE;                                         //--- Set ADX text color
      update_label(ADX_TEXT + IntegerToString(timeframe_index), DoubleToString(adx_values[0], 2), adx_text_color); //--- Update ADX label
      
      // Update AO
      color ao_text_color = (ao_values[0] > 0) ? clrGreen : (ao_values[0] < 0) ? clrRed : COLOR_WHITE;          //--- Set AO text color
      update_label(AO_TEXT + IntegerToString(timeframe_index), DoubleToString(ao_values[0], 2), ao_text_color); //--- Update AO label
      
      // Update Buy/Sell signals
      string buy_signal = calculate_signal_strength(rsi_values[0], stochastic_values[0], cci_values[0], 
                                                   adx_values[0], ao_values[0], true);                          //--- Calculate buy signal
      string sell_signal = calculate_signal_strength(rsi_values[0], stochastic_values[0], cci_values[0], 
                                                    adx_values[0], ao_values[0], false);                        //--- Calculate sell signal
      
      color buy_text_color = (buy_signal == "Strong Buy") ? COLOR_WHITE : COLOR_WHITE;                          //--- Set buy text color
      color buy_background = (buy_signal == "Strong Buy") ? clrGreen : 
                            (buy_signal == "Buy") ? clrSeaGreen : COLOR_DARK_GRAY;                              //--- Set buy background color
      update_rectangle(BUY_RECTANGLE + IntegerToString(timeframe_index), buy_background);                       //--- Update buy rectangle
      update_label(BUY_TEXT + IntegerToString(timeframe_index), buy_signal, buy_text_color);                    //--- Update buy label
      
      color sell_text_color = (sell_signal == "Strong Sell") ? COLOR_WHITE : COLOR_WHITE;                       //--- Set sell text color
      color sell_background = (sell_signal == "Strong Sell") ? clrRed : 
                             (sell_signal == "Sell") ? clrSalmon : COLOR_DARK_GRAY;                             //--- Set sell background color
      update_rectangle(SELL_RECTANGLE + IntegerToString(timeframe_index), sell_background);                     //--- Update sell rectangle
      update_label(SELL_TEXT + IntegerToString(timeframe_index), sell_signal, sell_text_color);                 //--- Update sell label
      
      // Release indicator handles
      IndicatorRelease(rsi_indicator_handle);                   //--- Release RSI handle
      IndicatorRelease(stochastic_indicator_handle);            //--- Release Stochastic handle
      IndicatorRelease(cci_indicator_handle);                   //--- Release CCI handle
      IndicatorRelease(adx_indicator_handle);                   //--- Release ADX handle
      IndicatorRelease(ao_indicator_handle);                    //--- Release AO handle
   }
}

ダッシュボードの値更新を容易に管理するために、updateIndicators関数を実装し、インジケーター値とシグナルを更新します。timeframes_arrayをtimeframe_indexでループし、各時間軸を処理します。iRSI、iStochastic、iCCI、iADX、iAO関数を使用して、現在の銘柄と時間軸に対応するインジケーターハンドル(例:rsi_indicator_handle)を作成し、14期間のRSIや20期間のCCIなどのパラメータを設定します。インジケーターの設定値はすべてカスタマイズ可能であり、デフォルト値に制限される必要はありません。

次に、rsi_indicator_handleのような任意のハンドルがINVALID_HANDLEに等しい場合、作成に失敗したことを意味します。この場合はPrint関数を使用して、truncate_timeframe_name関数の出力とともにエラーをログに出力し、次の時間軸に進みます。CopyBuffer関数を使用して最新値をrsi_valuesなどの配列に取得し、失敗した場合はエラーをログに残して処理を継続します。インジケーターの表示はupdate_label関数を使って更新します。たとえば、rsi_text_colorはrsi_values[0]に基づいて設定し、30未満なら青、70を超えたら赤、それ以外はCOLOR_WHITEとし、DoubleToString関数で整形した値をRSI_TEXTに反映します。同様の処理をstochastic_values、cci_values、adx_values、ao_valuesにも適用し、色のロジック(例:ao_valuesが正なら緑)を組み込みます。

次に、calculate_signal_strength関数を使用し、rsi_values[0]などを渡してbuy_signalとsell_signalを算出します。buy_backgroundは「Strong Buy」なら緑などの色を設定し、update_rectangle関数でBUY_RECTANGLEを更新、update_label関数でBUY_TEXTを更新します。sell_backgroundとSELL_TEXTについても同様に処理します。最後に、IndicatorRelease関数を使用してrsi_indicator_handleなどのハンドルを解放し、効率的なリソース管理をおこないます。使用したヘルパー関数は以下のように定義されています。

//+------------------------------------------------------------------+
//| Update rectangle background color                                |
//+------------------------------------------------------------------+
bool update_rectangle(string object_name, color background_color)//--- Function to update rectangle color
{
   int found = ObjectFind(0, object_name);                       //--- Find rectangle object
   if(found < 0) {                                               //--- Check if object not found
      ResetLastError();                                          //--- Reset error code
      Print("UNABLE TO FIND THE RECTANGLE: ", object_name, ". ERR Code: ", GetLastError()); //--- Log error
      return(false);                                             //--- Return failure
   }
   ObjectSetInteger(0, object_name, OBJPROP_BGCOLOR, background_color); //--- Set background color
   
   ChartRedraw(0);                                               //--- Redraw chart
   return(true);                                                 //--- Return success
}

//+------------------------------------------------------------------+
//| Update label text and color                                      |
//+------------------------------------------------------------------+
bool update_label(string object_name, string text, color text_color) //--- Function to update label
{
   int found = ObjectFind(0, object_name);                       //--- Find label object
   if(found < 0) {                                               //--- Check if object not found
      ResetLastError();                                          //--- Reset error code
      Print("UNABLE TO FIND THE LABEL: ", object_name, ". ERR Code: ", GetLastError()); //--- Log error
      return(false);                                             //--- Return failure
   }
   ObjectSetString(0, object_name, OBJPROP_TEXT, text);          //--- Set label text
   ObjectSetInteger(0, object_name, OBJPROP_COLOR, text_color);  //--- Set text color
   
   ChartRedraw(0);                                               //--- Redraw chart
   return(true);                                                 //--- Return success
}

update_rectangle関数を定義します。この関数はobject_nameとbackground_colorをパラメータとして受け取り、矩形の外観を変更します。ObjectFind関数を使用して矩形を検索し、結果をfoundに格納します。foundが0未満の場合、そのオブジェクトが存在しないことを意味するため、ResetLastError関数を使用し、Print関数とGetLastErrorでエラーをログに出力し、falseを返します。矩形の背景はObjectSetInteger関数を使用してOBJPROP_BGCOLORをbackground_colorに設定して更新します。ChartRedraw関数でチャートを再描画し、成功時にはtrueを返します。テキスト更新用にはupdate_label関数を定義します。この関数はobject_name、text、text_colorをパラメータとして受け取ります。

ObjectFind関数でラベルの存在を確認し、foundが負の場合はResetLastError関数を使用し、Print関数でエラーをログに出力してfalseを返します。ObjectSetString関数でOBJPROP_TEXTをtextに設定し、ObjectSetInteger関数でOBJPROP_COLORをtext_colorに設定します。ChartRedraw関数を使用してチャートを更新し、trueを返すことで、ラベルの動的更新を可能にします。これでティックごとにupdate関数を呼び出し、ダッシュボードを更新できるようになります。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()                                                    //--- Handle tick events
{
   if (panel_is_visible) {                                       //--- Check if panel is visible
      updateIndicators();                                        //--- Update indicators
   }
}

ここでは、OnTickイベントハンドラ内で、パネルが表示されている場合にupdateIndicators関数を呼び出して更新を適用します。最後に、不要になった際には作成したオブジェクトを削除し、それらをチャートから取り除く必要があります。

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)                                  //--- Deinitialize EA
{
   ObjectDelete(0, MAIN_PANEL);                                  //--- Delete main panel
   ObjectDelete(0, HEADER_PANEL);                                //--- Delete header panel
   ObjectDelete(0, HEADER_PANEL_ICON);                           //--- Delete header icon
   ObjectDelete(0, HEADER_PANEL_TEXT);                           //--- Delete header title
   ObjectDelete(0, CLOSE_BUTTON);                                //--- Delete close button

   ObjectsDeleteAll(0, SYMBOL_RECTANGLE);                        //--- Delete all symbol rectangles
   ObjectsDeleteAll(0, SYMBOL_TEXT);                             //--- Delete all symbol labels
   ObjectsDeleteAll(0, TIMEFRAME_RECTANGLE);                     //--- Delete all timeframe rectangles
   ObjectsDeleteAll(0, TIMEFRAME_TEXT);                          //--- Delete all timeframe labels
   ObjectsDeleteAll(0, HEADER_RECTANGLE);                        //--- Delete all header rectangles
   ObjectsDeleteAll(0, HEADER_TEXT);                             //--- Delete all header labels
   ObjectsDeleteAll(0, RSI_RECTANGLE);                           //--- Delete all RSI rectangles
   ObjectsDeleteAll(0, RSI_TEXT);                                //--- Delete all RSI labels
   ObjectsDeleteAll(0, STOCH_RECTANGLE);                         //--- Delete all Stochastic rectangles
   ObjectsDeleteAll(0, STOCH_TEXT);                              //--- Delete all Stochastic labels
   ObjectsDeleteAll(0, CCI_RECTANGLE);                           //--- Delete all CCI rectangles
   ObjectsDeleteAll(0, CCI_TEXT);                                //--- Delete all CCI labels
   ObjectsDeleteAll(0, ADX_RECTANGLE);                           //--- Delete all ADX rectangles
   ObjectsDeleteAll(0, ADX_TEXT);                                //--- Delete all ADX labels
   ObjectsDeleteAll(0, AO_RECTANGLE);                            //--- Delete all AO rectangles
   ObjectsDeleteAll(0, AO_TEXT);                                 //--- Delete all AO labels
   ObjectsDeleteAll(0, BUY_RECTANGLE);                           //--- Delete all buy rectangles
   ObjectsDeleteAll(0, BUY_TEXT);                                //--- Delete all buy labels
   ObjectsDeleteAll(0, SELL_RECTANGLE);                          //--- Delete all sell rectangles
   ObjectsDeleteAll(0, SELL_TEXT);                               //--- Delete all sell labels
   
   ChartRedraw(0);                                               //--- Redraw chart
}

最後に、OnDeinit関数を使用してクリーンアップ処理を実装します。この関数はエキスパートアドバイザー(EA)が削除されたときに実行されます。まずObjectDelete関数を使用して、MAIN_PANELの矩形をはじめ、HEADER_PANEL、HEADER_PANEL_ICON、HEADER_PANEL_TEXT、CLOSE_BUTTONを順に削除し、メインパネルとヘッダのコンポーネントをチャートから確実に消去します。

次にObjectsDeleteAll関数を使用して、すべてのダッシュボードオブジェクトを体系的に削除します。SYMBOL_RECTANGLEとSYMBOL_TEXT、TIMEFRAME_RECTANGLEとTIMEFRAME_TEXT、HEADER_RECTANGLEとHEADER_TEXTに関連する矩形やラベルを削除し、銘柄、時間軸、ヘッダ表示をクリアします。さらに、RSI_RECTANGLE、STOCH_RECTANGLE、CCI_RECTANGLE、ADX_RECTANGLE、AO_RECTANGLEなどのインジケーター関連オブジェクトと、それぞれのRSI_TEXTなどのテキストラベルも削除します。

最後にObjectsDeleteAll関数を使用して、BUY_RECTANGLEとSELL_RECTANGLEオブジェクト、さらにBUY_TEXTとSELL_TEXTラベルを削除し、シグナル関連の要素をすべて取り除きます。ChartRedraw関数を使用してチャートを再描画し、初期化解除後にクリーンな表示状態を確保します。最後に、キャンセルボタンを処理する必要があります。クリックされた際にダッシュボードを閉じ、以後の更新を無効にするようにします。

//+------------------------------------------------------------------+
//| Expert chart event handler                                       |
//+------------------------------------------------------------------+
void OnChartEvent(const int       event_id,                      //--- Event ID
                  const long&     long_param,                    //--- Long parameter
                  const double&   double_param,                  //--- Double parameter
                  const string&   string_param)                  //--- String parameter
{
   if (event_id == CHARTEVENT_OBJECT_CLICK) {                    //--- Check for object click event
      if (string_param == CLOSE_BUTTON) {                        //--- Check if close button clicked
         Print("Closing the panel now");                         //--- Log panel closure
         PlaySound("alert.wav");                                 //--- Play alert sound
         panel_is_visible = false;                               //--- Hide panel
         
         ObjectDelete(0, MAIN_PANEL);                            //--- Delete main panel
         ObjectDelete(0, HEADER_PANEL);                          //--- Delete header panel
         ObjectDelete(0, HEADER_PANEL_ICON);                     //--- Delete header icon
         ObjectDelete(0, HEADER_PANEL_TEXT);                     //--- Delete header title
         ObjectDelete(0, CLOSE_BUTTON);                          //--- Delete close button
      
         ObjectsDeleteAll(0, SYMBOL_RECTANGLE);                  //--- Delete all symbol rectangles
         ObjectsDeleteAll(0, SYMBOL_TEXT);                       //--- Delete all symbol labels
         ObjectsDeleteAll(0, TIMEFRAME_RECTANGLE);               //--- Delete all timeframe rectangles
         ObjectsDeleteAll(0, TIMEFRAME_TEXT);                    //--- Delete all timeframe labels
         ObjectsDeleteAll(0, HEADER_RECTANGLE);                  //--- Delete all header rectangles
         ObjectsDeleteAll(0, HEADER_TEXT);                       //--- Delete all header labels
         ObjectsDeleteAll(0, RSI_RECTANGLE);                     //--- Delete all RSI rectangles
         ObjectsDeleteAll(0, RSI_TEXT);                          //--- Delete all RSI labels
         ObjectsDeleteAll(0, STOCH_RECTANGLE);                   //--- Delete all Stochastic rectangles
         ObjectsDeleteAll(0, STOCH_TEXT);                        //--- Delete all Stochastic labels
         ObjectsDeleteAll(0, CCI_RECTANGLE);                     //--- Delete all CCI rectangles
         ObjectsDeleteAll(0, CCI_TEXT);                          //--- Delete all CCI labels
         ObjectsDeleteAll(0, ADX_RECTANGLE);                     //--- Delete all ADX rectangles
         ObjectsDeleteAll(0, ADX_TEXT);                          //--- Delete all ADX labels
         ObjectsDeleteAll(0, AO_RECTANGLE);                      //--- Delete all AO rectangles
         ObjectsDeleteAll(0, AO_TEXT);                           //--- Delete all AO labels
         ObjectsDeleteAll(0, BUY_RECTANGLE);                     //--- Delete all buy rectangles
         ObjectsDeleteAll(0, BUY_TEXT);                          //--- Delete all buy labels
         ObjectsDeleteAll(0, SELL_RECTANGLE);                    //--- Delete all sell rectangles
         ObjectsDeleteAll(0, SELL_TEXT);                         //--- Delete all sell labels
         
         ChartRedraw(0);                                         //--- Redraw chart
      }
   }
}

OnChartEventイベントハンドラ内では、イベントIDがCHARTEVENT_OBJECT_CLICKで、クリックされたオブジェクトがキャンセルボタンである場合に処理を行います。まずPlaySound関数を使用してアラート音を鳴らし、パネルが無効化されることをユーザーに通知します。その後、パネルの表示を無効にし、OnDeinitで使用したのと同じロジックを用いてチャートをクリアし、ダッシュボードを削除します。コンパイルすると、次の結果が得られます。

更新されたダッシュボード

画像から、インジケーターのデータと売買方向が反映されたダッシュボードが更新されていることが確認できます。残されているのはプロジェクトの実用性をテストすることであり、それは次のセクションで扱います。


バックテスト

テストをおこない、その結果を1枚のGraphics Interchange Format (GIF)ビットマップ画像形式でまとめた可視化を以下に示します。

テストGIF


結論

結論として、MQL5を用いて多時間軸スキャナーダッシュボードを開発しました。構造化されたグリッドレイアウト、リアルタイムのインジケーターシグナル、インタラクティブなクローズボタンを統合することで、戦略的な取引判断の精度を向上させています。これらの機能の設計および実装を示し、堅牢な初期化処理と動的な更新機能を通じて、その有効性を確認しました。このダッシュボードは個々のニーズに応じてカスタマイズ可能であり、複数の時間軸にわたる市場シグナルの監視および迅速な対応能力を大幅に向上させます。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/18319

添付されたファイル |
MQL5入門(第17回):トレンド反転のためのエキスパートアドバイザーの構築 MQL5入門(第17回):トレンド反転のためのエキスパートアドバイザーの構築
この記事では、トレンドラインのブレイクアウトや反転を利用したチャートパターン認識に基づいて取引をおこなうMQL5のエキスパートアドバイザー(EA)の構築方法を初心者向けに解説します。トレンドラインの値を動的に取得し、プライスアクションと比較する方法を学ぶことで、読者は上昇・下降トレンドライン、チャネル、ウェッジ、トライアングルなどのチャートパターンを識別し取引できるEAを開発できるようになります。
プライスアクション分析ツールキットの開発(第25回):Dual EMA Fractal Breaker プライスアクション分析ツールキットの開発(第25回):Dual EMA Fractal Breaker
プライスアクションは、利益を生む取引機会を特定するための基本的なアプローチです。しかし、価格の動きやパターンを手動で監視することは、非常に手間がかかり、時間も消費します。そこで、本記事では、プライスアクションを自動的に分析し、潜在的な取引機会が検出されるたびにタイムリーなシグナルを提供するツールを開発する取り組みを紹介します。特に、フラクタルのブレイクアウトとEMA 14、EMA 200を組み合わせて信頼性の高い取引シグナルを生成する堅牢なツールを紹介し、トレーダーがより自信を持って意思決定できるよう支援します。
プライスアクション分析ツールキットの開発(第26回):Pin Bar, Engulfing Patterns and RSI Divergence (Multi-Pattern) Tool プライスアクション分析ツールキットの開発(第26回):Pin Bar, Engulfing Patterns and RSI Divergence (Multi-Pattern) Tool
実践的なプライスアクションツールの開発を目的として、本記事ではピンバーと包み足を検出するEAの作成について解説します。各シグナルを生成する前に、RSIのダイバージェンスを確認のトリガーとして使用します。
ログレコードをマスターする(第7回):チャートにログを表示する方法 ログレコードをマスターする(第7回):チャートにログを表示する方法
MetaTraderのチャート上に、フレームやタイトル、自動スクロール機能を備えたログ表示エリアを構築し、整理された形でログを確認する方法を解説します。本記事では、MQL5を用いてビジュアルログシステムを実装する手順を紹介します。これにより、ロボットの動作をリアルタイムで効率的に監視することが可能になります。