English Deutsch
preview
MQL5経済指標カレンダーを使った取引(第2回):ニュースダッシュボードパネルの作成

MQL5経済指標カレンダーを使った取引(第2回):ニュースダッシュボードパネルの作成

MetaTrader 5トレーディング | 31 3月 2025, 08:03
90 0
Allan Munene Mutiiria
Allan Munene Mutiiria

はじめに

この記事では、MetaQuotes Language 5(MQL5)経済指標カレンダーに関する第1回で、経済ニュースイベントを取得し分析するための関数を習得した内容を基に進めます。今回は、トレーダーがリアルタイムで重要な経済データにアクセスできる便利なインターフェースを提供するニュースダッシュボードパネルを作成することで、次のステップに進みます。このダッシュボードは、市場の動きに影響を与える可能性のある関連ニュースイベントを強調表示することで、意思決定プロセスを効率化するのに役立ちます。取り上げるトピックは次の通りです。

  1. ダッシュボードパネルの設計
  2. MQL5でのパネル設定
  3. 結論

これらのコンポーネントを通じて、MQL5の経済ニュースをリアルタイムで監視するための効果的なツールを提供し、取引体験を向上させることを目指します。


ダッシュボードパネルの設計

ダッシュボードパネルの設計は、MQL5経済指標カレンダーを使用して経済ニュースイベントを監視するための効果的なツールを作成する上で非常に重要なステップです。私たちの目標は、重要な情報を明確かつ簡潔に提供する、ユーザーフレンドリーで視覚的に魅力的なインターフェイスを作成することです。適切に構成されたダッシュボードは、経済イベントが取引戦略に与える影響を迅速に評価できるようにします。

ダッシュボードパネルを設計する際には、まず表示する必要のある主要なコンポーネントを特定する必要があります。これらのコンポーネントには通常、イベント名、スケジュールされた時間、影響を受ける通貨、重要度レベル、イベントの簡単な説明が含まれます。使いやすさを向上させるため、この情報は表形式で整理し、各行が異なる経済イベントを示します。重要度レベルに応じて対照的な色を使い、影響の大きいイベントを素早く識別できるようにして、表を読みやすくする予定です。

パネルをさらに魅力的にするため、境界線、背景、フォントなどの視覚的要素を選び、すっきりとしたプロフェッショナルな外観を作成します。このレイアウトにより、ナビゲーションが容易になり、過剰な詳細で圧倒されることなく、必要な情報をすばやく見つけることができます。デザインを直感的でシンプルに保つことで、トレーダーはダッシュボードパネルに表示された経済イベントに基づいて、情報に基づいた意思決定に集中できるようになります。パネルは前述のように配置され、以下に示すコンポーネントが含まれます。

パネルコンポーネント

目的を明確に理解した上で、自動化プロセスに取り掛かりましょう。前回の記事では、経済ニュースイベントを効果的に取得し、分析するためにMQL5経済指標カレンダーの機能を習得することに焦点を当てました。まだご覧になっていない場合は、その内容を参照して、ニュースダッシュボードパネルの作成を進める際に十分な準備ができるようにしてください。それでは始めましょう。


MQL5でのパネル設定

このセクションでは、MQL5を使用して必要なパネル要素を作成し、ダッシュボードパネルを設定することに焦点を当てます。まず、必要な3つの要素(長方形ラベル、ボタン、テキストラベル)用の関数を作成する必要があります。このアプローチは、類似の機能を作成する際に同じ関数を再利用できるため、新しいオブジェクトごとにプロセス全体を繰り返す必要がなくなり、非常に有益です。こうすることで、時間とスペースを節約し、プロセスを迅速かつ簡単にし、コードスニペットを簡潔に保つことができます。

長方形のラベルを作成するには、10個の引数またはパラメータを取る関数を作成します。この関数は、長方形の位置、サイズ、色、スタイルなどのプロパティを定義し、ダッシュボードのデザイン要件に応じてラベルの外観をカスタマイズできるようにします。

//+------------------------------------------------------------------+
//|     Function to create rectangle label                           |
//+------------------------------------------------------------------+

bool createRecLabel(string objName, int xD, int yD, int xS, int yS,
                    color clrBg, int widthBorder, color clrBorder = clrNONE,
                    ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) {

...
}

関数のシグネチャがすべてを物語っています。これはcreateRecLabelという名前のブール関数で、成功した場合と失敗した場合に、それぞれtrueかfalseの2つのブール型フラグを返すという意味です。そのパラメータを簡単に理解するために、以下にその概要を個別に説明しましょう。

  • objName: 矩形ラベルオブジェクトの一意な名前を表します。作成されるグラフィカル要素の識別子となります。
  • xD、yD:長方形ラベルが配置される角からのX距離とY距離を決定します。チャートに対する矩形の左上隅を定義する座標だと考えてください。
  • xS、yS: 矩形の幅と高さを指定します。「xS」の値は長方形の水平方向の幅を決定し、「yS」は長方形の垂直方向の高さを制御します。

距離とサイズ

  • clrBg: 長方形ラベルの背景色を表します。チャートの背景とのコントラストがよい色、または他の要素を引き立てる色を選択します。
  • widthBorder: 矩形を囲む境界線の幅を定義します。境界線が必要な場合は正の値を設定し、境界線がない場合はゼロを使用します。
  • clrBorder: 境界線の色を指定するオプションのパラメータです。境界線が必要な場合は、色を指定します(例:境界線の色なしの場合は「clrNONE」)。
  • borderType: 矩形の枠の種類を指定します。オプションには、flat、raised、その他のスタイルがあります。単純なフラットな境界線の場合は、BORDER_FLATを使用します。
  • borderStyle: flat境界線を選択した場合、このパラメータで線のスタイル(実線、破線など)を決定します。連続線の場合はSTYLE_SOLIDを使用します。

関数のシグネチャで、いくつかの引数がすでに何らかの値で初期化されていることに気づいたはずです。初期化値は、そのパラメータが関数呼び出し中に無視された場合に割り当てられるデフォルト値を表します。例えば、デフォルトの境界線カラーはnoneです。つまり、関数呼び出し時にカラー値が指定されなければ、矩形ラベルの境界線にはカラーが適用されません。 

中括弧({})で囲まれた関数本体の中で、オブジェクト生成プロシージャを定義します。

// Create a rectangle label object
if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
  Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError);
  return (false); // Return false if object creation fails
}

まず、if文を使用してオブジェクトが作成されていないかどうかをチェックします。 6つの引数を取るブール値のObjectCreate関数が使用されます。この関数は、指定された名前、型、初期座標を持つオブジェクトを、指定されたチャートサブウィンドウに作成します。まず、チャートウィンドウを指定します。0は、オブジェクトがメインウィンドウ上に作成されることを意味します。次に、オブジェクト名を指定します。これは、特定のオブジェクトに一意に割り当てられる名前です。作成するオブジェクトのタイプはOBJ_RECTANGLE_LABEL型であり、カスタムグラフィカルインターフェイスを作成および設計するためのオブジェクトを表します。次に、現在のサブウィンドウを0として、サブウィンドウを指定します。最後に、時間と価格の値は、チャートに付けるのではなく、チャートウィンドウの座標に付けるので、ゼロとして提供します。ピクセルはマッピングの設定に使用されます。

オブジェクトの作成に失敗した場合、最終的にObjectCreate関数はfalseを返します。明らかに続行する意味がないので、エラーを返します。この場合、エラーコードの横にエラーを操作ログに出力し、falseを返すことでエラーを通知します。そのため、最新のエラーを取得するには、前のエラーをクリアする必要があります。これは、オブジェクト作成ロジックの直前に、MQL5内蔵関数であるResetLastError関数を呼び出すことで実現します。

ResetLastError(); // Reset any previous error codes

この関数の目的は、エラーが発生した最後の操作のエラーコードを格納する定義済み変数_LastErrorの値を0に設定することです。これを呼び出すことで、次の操作に進む前に、以前のエラーコードがクリアされていることを確認します。このステップは、以前のエラー状態に干渉されることなく、新しいエラーを独立して処理することを可能にするため、不可欠です。

この時点まで戻らなければ、オブジェクトを作成したことになるので、オブジェクトのプロパティ更新を続けることができます。内蔵関数ObjectSet...のセットは、対応するオブジェクトプロパティの値を設定します。オブジェクトプロパティは、datetime型、integer型、color型、boolean型、character型のいずれかでなければなりません。

// Set properties for the rectangle label
ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle
ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle
ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color
ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type
ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat)
ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat)
ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat)
ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object
ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable
ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

最初の特性ロジックに集中しましょう。

ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner

ここでは、組み込みのObjectSetInteger関数を使用し、それぞれパラメータを渡します。パラメータは以下の通りです。

  • Chartid: チャートの識別子です。0は現在のチャート(チャートID)を指します。このチャート内のオブジェクトのプロパティを調整しています。
  • Name: objNameは、矩形ラベルオブジェクトに割り当てられた固有の名前を表します。
  • Propertyid: これはオブジェクトプロパティのIDであり、その値はENUM_OBJECT_PROPERTY_INTEGER列挙体のいずれかの値になります。OBJPROP_XDISTANCEは、X距離プロパティを変更することを指定します。
  • Propertyvalue: プロパティの値です。xDに代入される値は、矩形ラベルの左上隅がチャートの左端から水平方向にどのくらい右(負の場合は左)に位置するかを決定します。

同様に、他のプロパティも同じ形式で設定します。OBJPROP_YDISTANCEは、長方形ラベルのY距離プロパティを構成します。yD値は、矩形ラベルの左上隅がチャートの上端から垂直方向にどのくらい離れているかを決定します。言い換えれば、チャート領域内でのラベルの垂直配置を制御します。これは隅からのY距離を設定します。OBJPROP_XSIZEとOBJPROP_YSIZEはそれぞれ矩形の幅と高さを設定します。 

オブジェクトを配置するには、OBJPROP_CORNERプロパティを使用して、チャートウィンドウ上でオブジェクトを配置するコーナーを決定します。

ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner

プロパティは4種類しかありません。

  • CORNER_LEFT_UPPER: 座標の中心はチャートの左上隅
  • CORNER_LEFT_LOWER: 座標の中心はチャートの左下隅
  • CORNER_RIGHT_LOWER: 座標の中心はチャートの右下隅
  • CORNER_RIGHT_UPPER: 座標の中心はチャートの右上隅

図で表現するとこうなります。

コーナー

その他の特性は単純明快です。わかりやすいようにコメントをつけました。次に、ChartRedraw関数を使用してチャートを再描画するだけで、価格クオートやチャートイベントの変更を待たずに、変更が自動的に有効になります。

ChartRedraw(0); // Redraw the chart

最後に、オブジェクトプロパティの作成と更新が成功したことを示すtrueを返します。

return (true); // Return true if object creation and property settings are successful

チャートウィンドウ上に矩形オブジェクトを作成する関数コードの全容は以下の通りです。

bool createRecLabel(string objName, int xD, int yD, int xS, int yS,
                    color clrBg, int widthBorder, color clrBorder = clrNONE,
                    ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) {
    ResetLastError(); // Reset any previous error codes
    
    // Create a rectangle label object
    if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
        Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError);
        return (false); // Return false if object creation fails
    }
    
    // Set properties for the rectangle label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type
    ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected
    
    ChartRedraw(0); // Redraw the chart
    
    return (true); // Return true if object creation and property settings are successful
}

ボタンオブジェクトを作成するには、同じ関数を使用します。カスタムボタン関数を作成するコードは以下の通りです。

//+------------------------------------------------------------------+
//|     Function to create button                                    |
//+------------------------------------------------------------------+

bool createButton(string objName, int xD, int yD, int xS, int yS,
                  string txt = "", color clrTxt = clrBlack, int fontSize = 12,
                  color clrBg = clrNONE, color clrBorder = clrNONE,
                  string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the button object
    if (!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the button! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the button
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the button
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the button
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the button
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Button state (not pressed)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the button
    ChartRedraw(0);

    return (true); // Button creation successful
}

コードの違いは、矩形オブジェクトはその中にテキストを取ることができませんでしたが、ボタンは、それが必要とされる場合に備えて、ボタンの機能を説明するテキストを含んでいるということです。したがって、入力パラメータには、テキストプロパティ、ここではテキスト値、色、フォントサイズ、フォント名を考慮します。ボタンの境界線タイプは静的なので、そのプロパティを取り除き、境界線の色だけを保持します。 

作成するオブジェクトタイプはOBJ_BUTTONであり、ボタングラフィカルオブジェクトを作成することを意味します。そのアンカーポイントはピクセル単位で設定されます。境界線プロパティは、境界線カラーとして残し、残りをテキスト入力プロパティに置き換えます。

最後に、テキストラベルである最後の要素の機能が必要です。テキストラベルは背景オブジェクトを必要としないので、その実装は他の関数に比べて非常に簡単です。必要なのはテキストだけなので、テキストプロパティに集中します。コードは以下の通りです。

//+------------------------------------------------------------------+
//|     Function to create text label                                |
//+------------------------------------------------------------------+

bool createLabel(string objName, int xD, int yD,
                 string txt, color clrTxt = clrBlack, int fontSize = 12,
                 string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the label object
    if (!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the label! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the label
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Label state (not active)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the label
    ChartRedraw(0);

    return (true); // Label creation successful
}

このコード構造でボタンの機能と大きく異なるのは、オブジェクトのサイズと境界線のプロパティです。関数のシグネチャで、オブジェクトのサイズと境界線のプロパティを取り除きます。オブジェクトタイプをOBJ_LABELとして定義し、定義されたラベル座標に従ってチャートウィンドウにラベルを描画することを示します。最後に、sizeとborderのパラメータを取り除きます。簡単なことです。

グラフィカルユーザーインターフェイス(GUI)を作成するために必要な関数が揃ったので、それらを使用してパネルを作成しましょう。オブジェクトの名前が必要になりますが、オブジェクト名の相互作用を簡単に管理するには、マクロを定義する方がずっと簡単です。 

#define MAIN_REC "MAIN_REC"

#defineキーワードを使用して、値MAIN_RECを持つMAIN_RECという名前のマクロを定義し、レベルを作成するたびに名前を繰り返し再入力する代わりに、メイン長方形のベース名を簡単に保存します。これにより、時間が大幅に節約され、名前を間違って指定する可能性が減ります。基本的に、マクロはコンパイル時のテキスト置換に使用されます。

私たちのコードは、初期化インスタンスでパネルを作成したいので、EAの初期化セクションに大きく依存します。したがって、OnInitイベントハンドラにはコード構造の大部分が格納されます。 

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

int OnInit(){

   ...
   
   return(INIT_SUCCEEDED);
}

OnInit関数は、必要に応じて必要な初期化を実行するためにエキスパート初期化インスタンスで呼び出されるイベントハンドラです。 

次に、矩形ラベルを作成する関数を呼び出し、その名前とパラメータを入力します。

//--- Create main rectangle label for the dashboard panel
createRecLabel(MAIN_REC,50,50,740,410,clrSeaGreen,1);

ここでは、マクロの定義と同じように、矩形名をMAIN_RECとします。チャートウィンドウの左上隅からのx軸(時間と日付のスケール)に沿った距離は50ピクセルで、y軸(価格のスケール)に沿った距離も50ピクセルです。幅は740ピクセル、高さは410ピクセルです。背景色を濃い黄緑、境界線の幅を1、残りのパラメータをデフォルトに選択します。ピクセルをおおよその範囲にするためには、チャートを0にスケールダウンし、2つのクロスヘア座標間のバーの数を水平スケール上のピクセル数に等しくします。例を挙げれば、こういうことです。

クロスヘア

他のパラメータは省略されており、デフォルト値が自動的に適用されることを意味します。つまり、境界線の種類はフラットになり、線のスタイルは連続した実線になります。コンパイルすると、これが現在の状況です。

メインパネル

サブフレームを作成するには、それぞれのマクロを再度明示的に宣言します。

#define SUB_REC1 "SUB_REC1"
#define SUB_REC2 "SUB_REC2"

次に、同じ関数を呼び出してサブフレームを作成します。フレームをベースパネルのフレーム内に配置したいので、わずかに異なる色を使用する必要があります。これを実現するために、白と緑の色と3ピクセルと5ピクセルの余白を使用しました。

//--- Create sub-rectangle labels within the main panel for different sections
createRecLabel(SUB_REC1,50+3,50+30,740-3-3,410-30-3,clrWhite,1);
createRecLabel(SUB_REC2,50+3+5,50+30+50+27,740-3-3-5-5,410-30-3-50-27-10,clrGreen,1);

ここでは、メインダッシュボードパネル内にSUB_REC1とSUB_REC2という2つの追加サブセクションを設定して、コンテンツを視覚的に整理および分離できるようにします。createRecLabel関数を使用して、メインの長方形MAIN_RECの左端と右端から3ピクセル、上端から30ピクセルのオフセットを追加してSUB_REC1を配置します。これにより、メインパネル内にフレームセクションが効果的に作成されます。縮小された余白内に収まるように幅を「740-3-3」に定義し、上下にスペースを残してメインの長方形内にきちんと収まるように高さを「410-30-3」に定義します。このサブセクションは白色に設定されており、メインパネルの海の緑色と対照的なニュートラルな背景を確立して、視覚的な明瞭性を高めます。

次に、createRecLabelを使用して、SUB_REC1内に追加セクションSUB_REC2を追加し、整理された階層化されたレイアウトのために細かいオフセットで配置します。これを実現するために、開始X座標を「50+3+5」に設定し、それをSUB_REC1内にさらに配置して、このサブセクション内の別個の領域として視覚的に定義します。メイン長方形と最初のサブ長方形の両方の垂直オフセットを考慮して、Y座標を「50+30+50+27」に設定します。幅「740-3-3-5-5」はSUB_REC2を残りの水平スペース内に正確に収め、高さ「410-30-3-50-27-10」はバランスのとれた分離された領域を可能にします。SUB_REC2を緑に設定すると、強いコントラストが追加され、重要なデータが表示される領域であることが示されます。この長方形の慎重な階層化は、ダッシュボードの構造化された視覚的にナビゲート可能なパネルを確立するために不可欠です。コンパイルすると、次のような結果が得られます。

パネルフレーム

ここまでで、パネルのフレーム、余白、境界の設定は完了です。次に、他のパネルユーティリティ、そのプロパティ、および効果を追加します。まず始めに、パネルにタイトルをつけましょう。

#define HEADER_LABEL "HEADER_LABEL"

//---

//--- Create the header label with text "MQL5 Economic Calendar"
createLabel(HEADER_LABEL,50+3+5,50+5,"MQL5 Economic Calendar",clrWhite,15);

ここでは、コード全体でこの特定のラベルの一貫性と参照の容易さを保つために、ラベル識別子HEADER_LABELを値HEADER_LABELで定義します。このラベルはダッシュボードパネルのヘッダーとして機能し、「MQL5 Economic Calendar」というタイトルを目立つように表示します。

次に、createLabel関数を使用して、指定した位置にヘッダーラベルを作成します。X座標を「50+3+5」に設定し、メインパネルの端より少し右に配置して、SUB_REC1の長方形内に揃い、余白と重ならないようにしています。Y座標「50+5」は、メインの長方形の上端から数ピクセル下に配置され、読みやすさが確保されます。視認性を高めるために、テキストの色を白、フォントサイズを15に設定し、ダッシュボードの目的を示す太字で目立つヘッダーを作成します。このヘッダーはダッシュボードのビジュアルデザインを固定し、その目的をユーザーに即座に伝えます。これがその結果です。

タイトル

うまくいきました。次に、パネルヘッダーの作成に進みます。このため、最も簡単な方法を使用します。つまり、ヘッダータイトルを定義し、それを配列に配置し、ループを使用してそれらを1行だけにあるため動的に配置します。ただし、個々のヘッダーの長さによってボタンの幅が異なるため、ボタンのサイズも別々に定義する必要があります。以下は、これを達成するために使用するロジックです。

string array_calendar[] = {"Date","Time","Cur.","Imp.","Event","Actual","Forecast","Previous"};
int buttons[] = {80,50,50,40,281,60,70,70};

ダッシュボード内のボタンのラベルと寸法を整理するために、2つの配列を定義します。最初の配列array_calendarには、表示する各列ヘッダーの文字列が含まれており、情報の種類を指定します。これらは、「Date」、「Time」、「Cur.」(通貨)、「Imp.」(影響/重要度)、「Event」、「Actual」、「Forecast」、「Previous」です。各文字列はデータカテゴリのラベルを表し、ダッシュボードの各セクションに何が表示されるかを理解するのに役立ちます。

2番目の配列buttonsには、array_calendar内のそれぞれの列に関連付けられた各ボタンの幅(ピクセル単位)を表す整数が含まれています。これらの幅は各データ型に合わせて調整され、レイアウトが整列され、視覚的に整理された状態が維持されます。たとえば、Date列の80ピクセルは長い日付形式に対応しますが、Time列とCur列には50ピクセルなどの狭い幅が設定され、必要なスペースが少なくなります。これらの配列を組み合わせることで、ダッシュボードの列ヘッダーとボタンの作成が効率化され、さらなるユーザーインターフェイス(UI)要素のための構造化された基盤が設定されます。ここから、ループを使用してヘッダーを動的に作成できます。

#define ARRAY_CALENDAR "ARRAY_CALENDAR"

//---

//--- Initialize starting x-coordinate for button positioning
int startX = 59;
   
//--- Loop through the array_calendar elements to create buttons
for (int i=0; i<ArraySize(array_calendar); i++){
   //--- Create each button for calendar categories
   createButton(ARRAY_CALENDAR+IntegerToString(i),startX,132,buttons[i],25,array_calendar[i],clrWhite,13,clrGreen,clrNONE,"Calibri Bold");
   startX += buttons[i]+3; //--- Update x-coordinate for the next button
}

ここでは、array_calendar要素に基づいてボタンを初期化して配置し、ダッシュボードパネルの各カテゴリにラベルを付けます。まず、カレンダーボタンシリーズの識別子「ARRAY_CALENDAR」を定義します。次に、最初のボタンをパネル上に水平に配置するために、初期x座標としてstartXを59に設定します。

次に、forループを使用してarray_calendar内の各項目を反復処理し、ボタンを作成します。各反復ごとに、createButton関数を呼び出し、ARRAY_CALENDARにループインデックスを追加して、各ボタンの一意のIDを渡します。これにより、すべてのボタンIDが一意になり、「Date」、「Time」、「Cur」などのカテゴリを参照できるようになります。startX位置を指定し、buttonsの値を使用して各ボタンの幅を定義し、それぞれのデータカテゴリとの配置を確保します。各ボタンには、フォントの色(白)、フォントサイズ(13)、背景色(ボタンの場合は緑、境界線の場合はなし)などのスタイルプロパティも設定され、CalibriBoldフォントで設定されます。各ボタンを作成した後、現在のボタンの幅に3ピクセルの余白を加えてstartXを調整し、次の反復でボタンの間隔を均一にします。コンパイルすると、次の出力が得られます。

ヘッダー

ヘッダーを作成したら、時間、特定されたニュースイベントの数、影響レベルを表示するための他のサブセクションを作成する必要があります。まず、本連載の前回の記事からニュースイベントを取得することから始めます。

//--- Declare variables for tracking news events and status
int totalNews = 0;
bool isNews = false;
MqlCalendarValue values[]; //--- Array to store calendar values

//--- Define start and end time for calendar event retrieval
datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_H12);
datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_H12);

//--- Set a specific country code filter (e.g., "US" for USD)
string country_code = "US";
string currency_base = SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE);

//--- Retrieve historical calendar values within the specified time range
int allValues = CalendarValueHistory(values,startTime,endTime,NULL,NULL);

//--- Print the total number of values retrieved and the array size
Print("TOTAL VALUES = ",allValues," || Array size = ",ArraySize(values));

これにより、MQL5経済指標カレンダーから取得した履歴イベント値が提供され、それらを単に印刷するだけでなく、ダッシュボードに表示できるようになります。私たちが適用するロジックは次のとおりです。

#define TIME_LABEL "TIME_LABEL"

//---

//--- Create label displaying server time and total number of news events found
createLabel(TIME_LABEL,70,85,"Server Time: "+TimeToString(TimeCurrent(),
           TIME_DATE|TIME_SECONDS)+"   |||   Total News: "+
           IntegerToString(allValues),clrBlack,14,"Times new roman bold");

ここでは、取得されたニュースイベントの合計数とともに現在のサーバー時間を表示するラベルを作成します。まず、ダッシュボードパネル内でこのラベルを一意に参照するための識別子「TIME_LABEL」を定義します。

次に、createLabel関数を呼び出してラベル自体を生成します。座標70と85を指定してラベルの位置を指定します。これにより、パネル上でラベルが表示される場所が決まります。ラベルのテキストは、TimeToString関数を使用して動的に構築されます。この関数は、TimeCurrent関数によって取得された現在のサーバー時間を日付と秒の形式でフォーマットします。このフォーマットされた時間を文字列「|||TotalNews:」と連結し、ニュースイベントの数を含む変数allValuesをIntegerToString関数を使用して文字列に変換します。これにより、サーバー時間と見つかったニュースイベントの合計数の両方を示す包括的なラベルが作成されます。ラベルの色は黒、フォントサイズは14で、視認性を高めるために「TimesNewRoman太字」フォントを使用しています。同じロジックを使用して、影響ラベルも作成します。

#define IMPACT_LABEL "IMPACT_LABEL"

//---

//--- Create label for displaying "Impact" category header
createLabel(IMPACT_LABEL,70,105,"Impact: ",clrBlack,14,"Times new roman bold");

コンパイルすると、次のような出力が得られます。

価値と影響のラベル

うまくいきました。次に、それぞれの影響レベルが何であるかをユーザーが理解できるように、それぞれの影響ボタンをそれぞれのラベルと色で表示する必要があります。 

//--- Define labels for impact levels and size of impact display areas
string impact_labels[] = {"None", "Low", "Medium", "High"};
int impact_size = 100;

//--- Loop through impact levels to create buttons for each level
for (int i=0; i<ArraySize(impact_labels); i++){
   color impact_color = clrBlack, label_color = clrBlack; //--- Default colors for label and button

   //--- Assign color based on impact level
   if (impact_labels[i] == "None"){label_color = clrWhite;}
   else if (impact_labels[i] == "Low"){impact_color = clrYellow;}
   else if (impact_labels[i] == "Medium"){impact_color = clrOrange;}
   else if (impact_labels[i] == "High"){impact_color = clrRed;}

   //--- Create button for each impact level
   createButton(IMPACT_LABEL+string(i),140+impact_size*i,105,impact_size,25,impact_labels[i],label_color,12,impact_color,clrBlack);
}

ここでは、経済イベントに関連するさまざまな影響レベルのラベルと、これらの影響指標の表示領域のサイズを定義します。まず、さまざまな影響レベル(None、Low、Medium、High)を表す文字列を含む配列「impact_labels」を宣言します。さらに、各影響レベルに対して作成されるボタンの幅を決定する整数変数impact_sizeを値100で初期化します。

次に、ArraySize関数を使用して影響レベルの合計数を判断しながら、impact_labels配列を反復処理するループに入ります。このループ内では、まず黒色を使用してボタンとラベルのデフォルトの色を設定します。次に、条件文を使用して、現在の影響レベルに基づいて特定の色を割り当てます。影響レベルがNoneの場合、label_colorを白に変更します。レベルがLowの場合は、impact_colorを黄色に設定します。Mediumの場合はimpact_colorをオレンジに割り当て、Highの場合は赤に指定します。最後に、createButton関数を呼び出して、各影響レベルのボタンを生成し、「140+impact_size*i」で計算された動的なx座標を使用して配置し、固定のy座標を105に維持し、それに応じて寸法と色を指定します。これが現在のマイルストーンです。

インパクトボタン

うまくいきました。次に、実際のカレンダーデータをダッシュボードに追加します。ただし、その前に、パネルにデータを配置するだけでなく、よりプロフェッショナルな外観を与えることができるように、2番目のサブフレームを分割する必要があります。次のロジックを通じてそれを実現します。

//--- Limit the total number of values to display
int valuesTotal = (allValues <= 11) ? allValues : 11;

//--- Initialize starting y-coordinate for displaying news data
int startY = 162;

//--- Loop through each calendar value up to the maximum defined total
for (int i = 0; i < valuesTotal; i++){

   //--- Set alternating colors for each data row holder
   color holder_color = (i % 2 == 0) ? C'213,227,207' : clrWhite;

   //--- Create rectangle label for each data row holder
   createRecLabel(DATA_HOLDERS+string(i),62,startY-1,716,26,holder_color,1,clrBlack);

   //--- Increment y-coordinate for the next row of data
   startY += 25;
   Print(startY); //--- Print current y-coordinate for debugging
}

valuesTotal整数変数を定義して、ダッシュボードに表示される値の合計数を制限します。条件(三項)演算子を使用して、allValuesが11以下かどうかを確認し、そうであれば、valuesTotalをallValuesに設定します。そ例外の場合は11に設定します。このアプローチにより、11件を超えるニュースイベントを表示しないようにして、ダッシュボードを整理して管理しやすくすることができます。

次に、整数変数startYを値162で初期化します。これは、パネル上にニュースデータを配置するための開始y座標として機能します。次に、0からvaluesTotalまでを反復するループに入り、表示する各カレンダー値を効果的に処理します。このループ内では、現在のインデックス「i」に基づいて交互パターンを使用して各行ホルダーの色を定義します。「i」が偶数の場合、holder_colorを「C'213,227,207'」で表される明るい灰色に設定します。「i」が奇数の場合、白に設定します。色を決定した後、createRecLabel関数を呼び出して、各データ行ホルダーに対して、x軸の62、y軸の「startY-1」の位置、幅716、高さ26、境界線の色が黒の長方形ラベルを生成します。最後に、startYを25増やして次のデータ行のy座標を調整し、各エントリが順番に表示されるようにします。デバッグの目的で、現在のstartY値を出力し、作成される各データ行の垂直位置を追跡できるようにします。これが現在のマイルストーンです。

データ保有者

ホルダーサブフレームの作成中にマクロ変数DATA_HOLDERSを使用したことに気づいたかもしれません。私たちはそれを次のように定義しました。

#define DATA_HOLDERS "DATA_HOLDERS"
#define ARRAY_NEWS "ARRAY_NEWS"

また、列ヘッダーに関するデータホルダー内にマップされるそれぞれのデータの作成を容易にするために、ARRAY_NEWSマクロも定義しました。データを入力するには、選択したホルダーごとに、特定のイベント値のすべてのデータを反復処理し、そのデータを取得して表示する必要があります。したがって、これは最初のループ内で実行され、次のロジックを持つことになります。

//--- Initialize starting x-coordinate for each data entry
int startX = 65;

//--- Loop through calendar data columns
for (int k=0; k<ArraySize(array_calendar); k++){

   MqlCalendarEvent event; //--- Declare event structure
   CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID

   MqlCalendarCountry country; //--- Declare country structure
   CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID

   //--- Print event details for debugging
   Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time);

   //--- Skip event if currency does not match the selected country code
   // if (StringFind(_Symbol,country.currency) < 0) continue;

   //--- Prepare news data array with time, country, and other event details
   string news_data[ArraySize(array_calendar)];
   news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date
   news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time
   news_data[2] = country.currency; //--- Event country currency

   //--- Determine importance color based on event impact
   color importance_color = clrBlack;
   if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
   else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
   else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}

   //--- Set importance symbol for the event
   news_data[3] = ShortToString(0x25CF);

   //--- Set event name in the data array
   news_data[4] = event.name;

   MqlCalendarValue value; //--- Declare calendar value structure
   CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values

   //--- Populate actual, forecast, and previous values in the news data array
   news_data[5] = DoubleToString(value.GetActualValue(),3);
   news_data[6] = DoubleToString(value.GetForecastValue(),3);
   news_data[7] = DoubleToString(value.GetPreviousValue(),3);

   //--- Create label for each news data item
   if (k == 3){
      createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY-(22-12),news_data[k],importance_color,22,"Calibri");
   }
   else {
      createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY,news_data[k],clrBlack,12,"Calibri");
   }

   //--- Increment x-coordinate for the next column
   startX += buttons[k]+3;
}

ここでは、startXという整数変数を値65で初期化します。これは、カレンダーイベントに関連する各データエントリを配置するための開始x座標として機能します。次に、インデックス「k」を使用してarray_calendar内の各列を反復処理するループに入ります。このループ内で、特定のカレンダーイベントの詳細を保持するために使用される、MqlCalendarEvent型の構造体変数「event」を宣言します。CalendarEventById関数を呼び出して、イベントIDをvalues配列から渡し、結果を「event」に保存することで、イベントの詳細を取得します。

次に、カレンダーイベントに関連付けられた国に関する情報を保持するために、MqlCalendarCountry型の別の構造体変数「country」を宣言します。CalendarCountryById関数を使用して、イベントの国IDに基づいてcountryに詳細を入力します。デバッグの目的で、イベント名、重要度レベル(EnumToString関数を使用して文字列に変換)、国名、および「values[i].time」に保存されているイベント時間などの主要なイベントの詳細を出力します。

次に、イベントに関連する情報を格納するために、array_calendarと同じサイズのnews_dataという文字列配列を準備します。news_dataの最初の要素は、イベントの日付に設定され、TIME_DATEフラグを指定したTimeToString関数を使用して文字列としてフォーマットされます。2番目の要素は、TIME_MINUTESフラグを使用してフォーマットされたイベント時間をキャプチャします。3番目の要素には、イベントの国の通貨が格納されます。

次に、イベントの影響レベルに基づいてイベントの重要度色を決定し、変数「importance_color」を黒に初期化します。event.importanceの値を確認し、その値(低、中、高)に基づいて適切な色を割り当てます。低の場合は黄色、中の場合はオレンジ、高の場合は赤です。

また、news_dataの4番目の要素を、イベントの重要度を表すシンボルに設定し、ShortToString(0x25CF)を使用して塗りつぶされた円を作成します。5番目の要素には、event.nameから取得したイベント名が割り当てられます。

イベントの実際の値、予測値、および以前の値を取得するには、MqlCalendarValue型の「value」と呼ばれる別の構造体変数を宣言し、CalendarValueById関数を使用して、「values[i].id」に格納されているイベントのIDに基づいてこの構造体に値を入力します。news_dataの6番目、7番目、8番目の要素には、それぞれ実際の値、予測値、前回の値がDoubleToString関数を使用して小数点以下3桁にフォーマットされて入力されます。

最後に、createLabel関数を使用して、各ニュースデータ項目のラベルを作成します。kが3に等しい場合は重要度カラーを適用し、それ以外の場合はデフォルトで黒色になります。各ラベルのx座標はstartXによって決定され、buttons配列のボタン幅を追加することで増分され、各データ列が正しく配置されて明確に表示されるようになります。コンパイルすると、次のような出力が得られます。

塗りつぶされたパネル

うまくいきました。ニュースデータをチャート上に表示して簡単に参照できるMQL5経済指標カレンダーダッシュボードを作成しました。現在のマイルストーンに関しては、すべてのデータを取得するだけです。次回以降では、フィルターを統合し、リアルタイムのデータ更新を統合し、ニュースデータを取引目的で使用することで、パネルを改善します。


結論

結論として、重要な経済イベントをユーザーフレンドリーな形式で表示するインタラクティブなダッシュボードパネルを構築することで、MQL5経済指標カレンダーの基礎を築くことに成功しました。カレンダーデータの取得、重要度に基づいたイベントの視覚的分類、直感的なラベル付けなどの機能を実装することで、市場の重要な動きについて常に情報を得ることができます。この初期設定は、ユーザーエクスペリエンスを向上させるだけでなく、ダッシュボードを次のレベルに進化させるための強固な基盤も提供します。

次回以降では、ニュースフィルタなどの追加機能を統合し、MQL5における戦略に最も関連性の高い情報に焦点を当てられるようにします。また、最新の経済データが利用可能になるとすぐにパネルに反映されるよう、リアルタイム更新を実装します。さらに、パネルをレスポンシブにして、さまざまな画面サイズやユーザー操作にシームレスに適応できるようにすることにも重点を置きます。最終的には、このデータを活用して情報に基づいた取引の意思決定を促進し、市場のボラティリティを活用したいトレーダーにとって経済指標カレンダーを強力なツールに変えることを目指しています。ご期待ください。

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

添付されたファイル |
PythonからMQL5へ:量子に着想を得た取引システムへの旅 PythonからMQL5へ:量子に着想を得た取引システムへの旅
この記事では、量子に着想を得た取引システムの開発について検討し、Pythonプロトタイプから実際の取引のためのMQL5実装への移行について説明します。このシステムは、量子シミュレーターを使用した従来のコンピューター上で実行されますが、重ね合わせや量子もつれなどの量子コンピューティングの原理を使用して市場の状態を分析します。主な機能には、8つの市場状態を同時に分析する3量子ビットシステム、24時間のルックバック期間、および市場分析用の7つのテクニカル指標が含まれます。精度率は控えめに思えるかもしれませんが、適切なリスク管理戦略と組み合わせると大きな優位性が得られます。
MQL5における段階的特徴量選択 MQL5における段階的特徴量選択
この記事では、MQL5で実装された段階的特徴量選択の修正バージョンを紹介します。このアプローチは、Timothy Masters著の「Modern Data Mining Algorithms in C++ and CUDA C」で概説されている手法に基づいています。
知っておくべきMQL5ウィザードのテクニック(第48回):ビル・ウィリアムズのアリゲーター 知っておくべきMQL5ウィザードのテクニック(第48回):ビル・ウィリアムズのアリゲーター
ビル・ウィリアムズが考案したアリゲーターインジケーターは、明確なシグナルを生成し、他のインジケーターと組み合わせて使用されることが多い、多機能なトレンド識別インジケーターです。MQL5ウィザードのクラスとアセンブリを活用することで、パターンベースでさまざまなシグナルをテストできるため、このインジケーターも検討対象となります。
古典的な戦略を再構築する(第11回):移動平均クロスオーバー(II) 古典的な戦略を再構築する(第11回):移動平均クロスオーバー(II)
移動平均とストキャスティクスオシレーターは、トレンドに従う取引シグナルを生成するために使用できます。ただし、これらのシグナルは価格変動が発生した後にのみ観察されます。AIを使用することで、テクニカルインジケーターに内在するこの遅れを効果的に克服できます。この記事では、既存の取引戦略を改善できるような、完全に自律的なAI搭載のエキスパートアドバイザー(EA)を作成する方法を説明します。最も古い取引戦略であっても、改善することは可能です。