English Deutsch
preview
プライスアクション分析ツールキットの開発(第8回):Metrics Board

プライスアクション分析ツールキットの開発(第8回):Metrics Board

MetaTrader 5トレーディング | 2 6月 2025, 09:23
106 0
Christian Benjamin
Christian Benjamin

内容



はじめに

本連載の初期には、「Analytics Master」という記事を公開し、前日の市場指標を取得して視覚化する手法を取り上げました。この基礎的な取り組みが、より高度なツール開発への土台となりました。今回ご紹介するのは、MetaTrader 5上での市場分析を革新する、革新的かつ高品質なソリューション「Metrics Board EA」です。このツールは、MetaTrader 5へシームレスに統合され、直感的でシンプルなインターフェイスに専用の分析ボタンが配置されたアプリケーションとして機能します。以下のような高度な分析をワンクリックで実行可能です。

  • 高値・安値分析:重要な価格帯を瞬時に特定し、市場のトレンドや潜在的な反転ポイントを把握します。
  • ボリューム分析:取引量を可視化し、市場の参加度や流動性の状態を評価します。
  • トレンド分析:正確な数値指標を用いて、価格の方向性とその持続力を判断します。
  • ボラティリティ分析:市場の変動性を定量的に測定し、異なる相場環境に応じた戦略立案を支援します。
  • 移動平均分析:価格の動的な推移を追跡し、市場の全体的な流れを把握します。
  • サポート・レジスタンス分析:エントリーやエグジット、リスク管理において鍵となる価格帯を特定します。

各ボタンをクリックするだけで、リアルタイムのデータが即座に表示され、複雑な市場情報が一瞬で実用的な知見に変わります。Metrics Board EAには高度なアルゴリズムが搭載されており、プロフェッショナルトレーダーの要求に応える高速かつ高精度な演算処理を実現しています。 このツールを活用することで、トレーダーは複雑な市場データをシンプルかつ明確な知見へと変換し、戦略を洗練し、意思決定を迅速化することができます。Metrics Board EAは、取引戦略の精度と効率性を追求するすべてのトレーダーにとって、欠かせないリソースとなるでしょう。


システムの概要

このセクションでは、システムロジックの概要を簡潔に説明します。手順の詳細な解説は「コードの分解と実装」セクションを参照してください。以下の手順に沿ってシステムが動作します。

  • クラスの設定:このクラスは、各種分析用ボタンを備えたダイアログを生成します。
  • イベント処理:各ボタンのクリックにより、それぞれの分析メソッドが実行されます。
  • 分析と表示:市場データが処理され、分析結果がパネルに表示されます。
  • 終了処理:「閉じる」ボタンにより、メトリックボードを閉じることができます。
以上の手順は、EAが期待される成果を達成するために管理する処理フローの概要です。各段階は、市場分析から実用的な知見の生成に至るまで、精密な実行を可能にするように設計されています。これらのプロセスを順を追って実行することで、EAはシームレスかつ効率的な動作を実現します。以下の図では、このプロセス全体の流れを視覚的に確認できます。


EAロジックの概要

図1:EAロジックの概要


MQL5コード

//+------------------------------------------------------------------+
//|                                                Metrics Board.mql5|
//|                                Copyright 2025, Christian Benjamin|
//|                                              https://www.mql5.com|
//+------------------------------------------------------------------+
#property copyright "2025, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/ja/users/lynnchris"
#property version   "1.0"
#property strict

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Label.mqh>
#include <Controls\Panel.mqh>

// Metrics Board Class
class CMetricsBoard : public CAppDialog
  {
private:
   CButton           m_btnClose; // Close Button
   CButton           m_btnHighLowAnalysis;
   CButton           m_btnVolumeAnalysis;
   CButton           m_btnTrendAnalysis;
   CButton           m_btnVolatilityAnalysis;
   CButton           m_btnMovingAverage;
   CButton           m_btnSupportResistance;
   CPanel            m_panelResults;
   CLabel            m_lblResults;

public:
                     CMetricsBoard(void);
                    ~CMetricsBoard(void);
   virtual bool      Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2);
   virtual void      Minimize();
   virtual bool      Run(); // Declaration of Run method
   virtual bool      OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   virtual bool      ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   virtual void      Destroy(const int reason = REASON_PROGRAM); // Override Destroy method

private:
   bool              CreateButtons(void);
   bool              CreateResultsPanel(void);
   void              OnClickButtonClose(); // New close button handler
   void              PerformHighLowAnalysis(void);
   void              PerformVolumeAnalysis(void);
   void              PerformTrendAnalysis(void);
   void              PerformVolatilityAnalysis(void);
   void              PerformMovingAverageAnalysis(void);
   void              PerformSupportResistanceAnalysis(void);
   double            CalculateMovingAverage(int period);
  };

CMetricsBoard::CMetricsBoard(void) {}

CMetricsBoard::~CMetricsBoard(void) {}

// Override Destroy method
void CMetricsBoard::Destroy(const int reason)
  {
// Call base class Destroy method to release resources
   CAppDialog::Destroy(reason);
  }

//+------------------------------------------------------------------+
//| Create a control dialog                                          |
//+------------------------------------------------------------------+
bool CMetricsBoard::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
  {
   if(!CAppDialog::Create(chart, name, subwin, x1, y1, x2, y2))
     {
      Print("Failed to create CAppDialog instance.");
      return false; // Failed to create the dialog
     }

   if(!CreateResultsPanel())
     {
      Print("Failed to create results panel.");
      return false; // Failed to create the results panel
     }

   if(!CreateButtons())
     {
      Print("Failed to create buttons.");
      return false; // Failed to create buttons
     }

   Show(); // Show the dialog after creation
   return true; // Successfully created the dialog
  }

//+------------------------------------------------------------------+
//| Minimize the control window                                      |
//+------------------------------------------------------------------+
void CMetricsBoard::Minimize()
  {
   CAppDialog::Minimize();
  }

//+------------------------------------------------------------------+
//| Run the control.                                                 |
//+------------------------------------------------------------------+
bool CMetricsBoard::Run()
  {
// Assuming Run makes the dialog functional
   if(!Show())
     {
      Print("Failed to show the control.");
      return false; // Could not show the control
     }
// Additional initialization or starting logic can be added here
   return true; // Successfully run the control
  }

//+------------------------------------------------------------------+
//| Create the results panel                                         |
//+------------------------------------------------------------------+
bool CMetricsBoard::CreateResultsPanel(void)
  {
   if(!m_panelResults.Create(0, "ResultsPanel", 0, 10, 10, 330, 60))
      return false;

   m_panelResults.Color(clrLightGray);
   Add(m_panelResults);

   if(!m_lblResults.Create(0, "ResultsLabel", 0, 15, 15, 315, 30))
      return false;

   m_lblResults.Text("Results will be displayed here.");
   m_lblResults.Color(clrBlack);
   m_lblResults.FontSize(12);
   Add(m_lblResults);

   return true;
  }

//+------------------------------------------------------------------+
//| Create buttons for the panel                                     |
//+------------------------------------------------------------------+
bool CMetricsBoard::CreateButtons(void)
  {
   int x = 20;
   int y = 80;
   int buttonWidth = 300;
   int buttonHeight = 30;
   int spacing = 15;

// Create Close Button
   if(!m_btnClose.Create(0, "CloseButton", 0, x, y, x + buttonWidth, y + buttonHeight))
      return false;

   m_btnClose.Text("Close Panel");
   Add(m_btnClose);
   y += buttonHeight + spacing;

   struct ButtonData
     {
      CButton        *button;
      string         name;
      string         text;
     };

   ButtonData buttons[] =
     {
        {&m_btnHighLowAnalysis, "HighLowButton", "High/Low Analysis"},
        {&m_btnVolumeAnalysis, "VolumeButton", "Volume Analysis"},
        {&m_btnTrendAnalysis, "TrendButton", "Trend Analysis"},
        {&m_btnVolatilityAnalysis, "VolatilityButton", "Volatility Analysis"},
        {&m_btnMovingAverage, "MovingAverageButton", "Moving Average"},
        {&m_btnSupportResistance, "SupportResistanceButton", "Support/Resistance"}
     };

   for(int i = 0; i < ArraySize(buttons); i++)
     {
      if(!buttons[i].button.Create(0, buttons[i].name, 0, x, y, x + buttonWidth, y + buttonHeight))
         return false;

      buttons[i].button.Text(buttons[i].text);
      Add(buttons[i].button);
      y += buttonHeight + spacing;
     }

   return true;
  }

//+------------------------------------------------------------------+
//| Handle events for button clicks                                  |
//+------------------------------------------------------------------+
bool CMetricsBoard::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      Print("Event ID: ", id, ", Event parameter (sparam): ", sparam);

      if(sparam == "CloseButton") // Handle close button click
        {
         OnClickButtonClose(); // Call to new close button handler
         return true; // Event processed
        }
      else
         if(sparam == "HighLowButton")
           {
            Print("High/Low Analysis Button Clicked");
            m_lblResults.Text("Performing High/Low Analysis...");
            PerformHighLowAnalysis();
            return true; // Event processed
           }
         else
            if(sparam == "VolumeButton")
              {
               Print("Volume Analysis Button Clicked");
               m_lblResults.Text("Performing Volume Analysis...");
               PerformVolumeAnalysis();
               return true; // Event processed
              }
            else
               if(sparam == "TrendButton")
                 {
                  Print("Trend Analysis Button Clicked");
                  m_lblResults.Text("Performing Trend Analysis...");
                  PerformTrendAnalysis();
                  return true; // Event processed
                 }
               else
                  if(sparam == "VolatilityButton")
                    {
                     Print("Volatility Analysis Button Clicked");
                     m_lblResults.Text("Performing Volatility Analysis...");
                     PerformVolatilityAnalysis();
                     return true; // Event processed
                    }
                  else
                     if(sparam == "MovingAverageButton")
                       {
                        Print("Moving Average Analysis Button Clicked");
                        m_lblResults.Text("Calculating Moving Average...");
                        PerformMovingAverageAnalysis();
                        return true; // Event processed
                       }
                     else
                        if(sparam == "SupportResistanceButton")
                          {
                           Print("Support/Resistance Analysis Button Clicked");
                           m_lblResults.Text("Calculating Support/Resistance...");
                           PerformSupportResistanceAnalysis();
                           return true; // Event processed
                          }
     }

   return false; // If we reach here, the event was not processed
  }

//+------------------------------------------------------------------+
//| Handle chart events                                              |
//+------------------------------------------------------------------+
bool CMetricsBoard::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   Print("ChartEvent ID: ", id, ", lparam: ", lparam, ", dparam: ", dparam, ", sparam: ", sparam);

   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      return OnEvent(id, lparam, dparam, sparam);
     }

   return false;
  }

//+------------------------------------------------------------------+
//| Analysis operations                                              |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformHighLowAnalysis(void)
  {
   double high = iHigh(Symbol(), PERIOD_H1, 0);
   double low = iLow(Symbol(), PERIOD_H1, 0);

   Print("Retrieved High: ", high, ", Low: ", low);

   if(high == 0 || low == 0)
     {
      m_lblResults.Text("Failed to retrieve high/low values.");
      return;
     }

   string result = StringFormat("High: %.5f, Low: %.5f", high, low);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformVolumeAnalysis(void)
  {
   double volume = iVolume(Symbol(), PERIOD_H1, 0);
   Print("Retrieved Volume: ", volume);

   if(volume < 0)
     {
      m_lblResults.Text("Failed to retrieve volume.");
      return;
     }

   string result = StringFormat("Volume (Last Hour): %.1f", volume);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformTrendAnalysis(void)
  {
   double ma = CalculateMovingAverage(14);
   Print("Calculated 14-period MA: ", ma);

   if(ma <= 0)
     {
      m_lblResults.Text("Not enough data for moving average calculation.");
      return;
     }

   string result = StringFormat("14-period MA: %.5f", ma);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformVolatilityAnalysis(void)
  {
   int atr_period = 14;
   int atr_handle = iATR(Symbol(), PERIOD_H1, atr_period);

   if(atr_handle == INVALID_HANDLE)
     {
      m_lblResults.Text("Failed to get ATR handle.");
      return;
     }

   double atr_value[];
   if(CopyBuffer(atr_handle, 0, 0, 1, atr_value) < 0)
     {
      m_lblResults.Text("Failed to copy ATR value.");
      IndicatorRelease(atr_handle);
      return;
     }

   string result = StringFormat("ATR (14): %.5f", atr_value[0]);
   m_lblResults.Text(result);
   IndicatorRelease(atr_handle);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformMovingAverageAnalysis(void)
  {
   double ma = CalculateMovingAverage(50);
   Print("Calculated 50-period MA: ", ma);

   if(ma <= 0)
     {
      m_lblResults.Text("Not enough data for moving average calculation.");
      return;
     }

   string result = StringFormat("50-period MA: %.5f", ma);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformSupportResistanceAnalysis(void)
  {
   double support = iLow(Symbol(), PERIOD_H1, 1);
   double resistance = iHigh(Symbol(), PERIOD_H1, 1);
   Print("Retrieved Support: ", support, ", Resistance: ", resistance);

   if(support == 0 || resistance == 0)
     {
      m_lblResults.Text("Failed to retrieve support/resistance levels.");
      return;
     }

   string result = StringFormat("Support: %.5f, Resistance: %.5f", support, resistance);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//| Calculate moving average                                         |
//+------------------------------------------------------------------+
double CMetricsBoard::CalculateMovingAverage(int period)
  {
   if(period <= 0)
      return 0;

   double sum = 0.0;
   int bars = Bars(Symbol(), PERIOD_H1);

   if(bars < period)
     {
      return 0;
     }

   for(int i = 0; i < period; i++)
     {
      sum += iClose(Symbol(), PERIOD_H1, i);
     }
   return sum / period;
  }

// Implementation of OnClickButtonClose
void CMetricsBoard::OnClickButtonClose()
  {
   Print("Close button clicked. Closing the Metrics Board...");
   Destroy();  // This method destroys the panel
  }

CMetricsBoard ExtDialog;

//+------------------------------------------------------------------+
//| Initialize the application                                       |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(!ExtDialog.Create(0, "Metrics Board", 0, 10, 10, 350, 500))
     {
      Print("Failed to create Metrics Board.");
      return INIT_FAILED;
     }

   if(!ExtDialog.Run()) // Call Run to make the dialog functional
     {
      Print("Failed to run Metrics Board.");
      return INIT_FAILED; // Call to Run failed
     }

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Deinitialize the application                                     |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ExtDialog.Destroy(reason); // Properly call Destroy method
  }

//+------------------------------------------------------------------+
//| Handle chart events                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   ExtDialog.ChartEvent(id, lparam, dparam, sparam);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+


コードの分解と実装

  • ヘッダーとメタデータ
コードの最初の部分は、ヘッダーとメタデータのセクションです。このセクションでは、著作権の詳細、リンク、バージョン管理、厳密なコンパイルルールなど、スクリプトに関する基本情報を提供します。
//+------------------------------------------------------------------+
//|                                                Metrics Board.mql5|
//|                                Copyright 2025, Christian Benjamin|
//|                                              https://www.mql5.com|
//+------------------------------------------------------------------+
#property copyright "2025, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/ja/users/lynnchris"
#property version   "1.0"
#property strict
コメントブロックは、このスクリプトの目的を明示し、著作権表示やクレジットを記載するためのものであり、将来の利用者にとって作者を特定し、適切な帰属を保証する上で重要です。#propertyディレクティブは、スクリプトのさまざまな属性を定義するために使用されます。これには、著作権情報、作者やドキュメントへのリンク、バージョン番号、そしてコンパイル時の潜在的な問題を検出するためのstrictモードの設定が含まれます。
  • 必要なライブラリをインクルードする

次に、アプリケーションに必要なライブラリをインクルードします。これらのライブラリは、コーディングを簡素化する定義済みの機能を提供します。

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Label.mqh>
#include <Controls\Panel.mqh>

ここでは、取引操作およびユーザーインターフェイス制御に関連するライブラリをインポートしています。たとえば、Trade.mqhは取引関数の実行に不可欠なライブラリであり、Dialog.mqh、Button.mqh、Label.mqh、Panel.mqhは、Metrics Boardのユーザーインターフェイス構成要素を作成・管理するために使用されます。

  • クラス定義
ライブラリのインクルードに続いて、Metrics Boardの主要クラスを定義します。  CMetricsBoardクラスはCAppDialogを継承しており、ダイアログ機能を利用できるようになっています。このクラス内では、アプリケーションとのやり取りに使用される複数のprivateメンバー変数(主にボタンやパネル)を宣言します。各ボタンはそれぞれ特定の分析機能に対応しており、その結果はm_panelResultsというパネルに表示されます。

class CMetricsBoard : public CAppDialog
{
private:
   CButton           m_btnClose; 
   CButton           m_btnHighLowAnalysis;
   CButton           m_btnVolumeAnalysis;
   CButton           m_btnTrendAnalysis;
   CButton           m_btnVolatilityAnalysis;
   CButton           m_btnMovingAverage;
   CButton           m_btnSupportResistance;
   CPanel            m_panelResults;
   CLabel            m_lblResults;

このクラスにはコンストラクタとデストラクタも含まれています。

public:
                     CMetricsBoard(void);
                    ~CMetricsBoard(void);

CMetricsBoard::CMetricsBoard(void) {}

CMetricsBoard::~CMetricsBoard(void) {}

コンストラクタはクラスの初期化をおこない、デストラクタは(この場合は空ですが)CMetricsBoardのインスタンスが破棄される際に必要なクリーンアップ処理がおこなわれるよう定義されています。これは、リソースを効率的に管理する上で重要です。

  • ダイアログの作成

Createメソッドは、コントロールダイアログ全体を構築する役割を担います。このメソッドでは、まず基底クラス(CAppDialog::Create)を呼び出してダイアログの作成を試みます。もし作成に失敗した場合は、エラーログを出力し、falseを返します。続いて、結果表示用のパネルおよび各種ボタンを作成し、それぞれの処理が正常におこなわれたかを確認します。最後に、すべての手順が成功した場合は、ダイアログを表示し、trueを返します。

bool CMetricsBoard::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
{
   if(!CAppDialog::Create(chart, name, subwin, x1, y1, x2, y2))
   {
      Print("Failed to create CAppDialog instance.");
      return false; 
   }

   if(!CreateResultsPanel())
   {
      Print("Failed to create results panel.");
      return false; 
   }

   if(!CreateButtons())
   {
      Print("Failed to create buttons.");
      return false; 
   }

   Show(); 
   return true; 
}

ここで、Runダイアログが表示されます。Runメソッドは、このダイアログを機能させるために不可欠な役割を果たします。

bool CMetricsBoard::Run()
{
   if(!Show())
   {
      Print("Failed to show the control.");
      return false; 
   }
   return true; 
}

ここでは、Showメソッドを使用してダイアログを表示します。ダイアログの表示に失敗した場合は、エラーメッセージが出力され、falseが返されます。

  • 結果パネルの作成

CreateResultsPanelメソッドは、分析結果を表示するパネルを構築します。 まず結果パネルを作成し、色やサイズなどのプロパティを設定します。続いて、このパネルをダイアログに追加します。さらに、パネル内に結果表示用のラベルを作成し、その外観をカスタマイズしたうえでパネルに追加します。このメソッドは、すべてが正常に作成された場合にtrueを返します。

bool CMetricsBoard::CreateResultsPanel(void)
{
   if(!m_panelResults.Create(0, "ResultsPanel", 0, 10, 10, 330, 60))
      return false;

   m_panelResults.Color(clrLightGray);
   Add(m_panelResults);

   if(!m_lblResults.Create(0, "ResultsLabel", 0, 15, 15, 315, 30))
      return false;

   m_lblResults.Text("Results will be displayed here.");
   m_lblResults.Color(clrBlack);
   m_lblResults.FontSize(12);
   Add(m_lblResults);

   return true;
}

  • ボタンの作成

CreateButtonsメソッドは、ダイアログ内のインタラクティブなボタンを初期化する役割を担います。

bool CMetricsBoard::CreateButtons(void)
{
   int x = 20;
   int y = 80;
   int buttonWidth = 300;
   int buttonHeight = 30;
   int spacing = 15;

   if(!m_btnClose.Create(0, "CloseButton", 0, x, y, x + buttonWidth, y + buttonHeight))
      return false;

   m_btnClose.Text("Close Panel");
   Add(m_btnClose);
   y += buttonHeight + spacing;

   struct ButtonData
   {
      CButton        *button;
      string         name;
      string         text;
   };

   ButtonData buttons[] =
   {
      {&m_btnHighLowAnalysis, "HighLowButton", "High/Low Analysis"},
      {&m_btnVolumeAnalysis, "VolumeButton", "Volume Analysis"},
      {&m_btnTrendAnalysis, "TrendButton", "Trend Analysis"},
      {&m_btnVolatilityAnalysis, "VolatilityButton", "Volatility Analysis"},
      {&m_btnMovingAverage, "MovingAverageButton", "Moving Average"},
      {&m_btnSupportResistance, "SupportResistanceButton", "Support/Resistance"}
   };

   for(int i = 0; i < ArraySize(buttons); i++)
   {
      if(!buttons[i].button.Create(0, buttons[i].name, 0, x, y, x + buttonWidth, y + buttonHeight))
         return false;

      buttons[i].button.Text(buttons[i].text);
      Add(buttons[i].button);
      y += buttonHeight + spacing;
   }

   return true;
}

この実装では、ボタンの初期座標、サイズ、間隔を定義します。まず、パネルを閉じるためのボタンを作成し、ダイアログに追加します。次に、ButtonData構造体の配列を用いてボタンの定義を効率的にループ処理します。各ボタンには対応するテキストが設定され、ダイアログに追加されます。すべてのボタンが正常に作成された場合に、メソッドはtrueを返して終了します。

  • イベントの処理

1.  ボタンクリック

OnEventメソッドは、ボタンクリックなどのユーザー操作によって発生するイベントを処理します。

bool CMetricsBoard::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      Print("Event ID: ", id, ", Event parameter (sparam): ", sparam);

      if(sparam == "CloseButton") 
      {
         OnClickButtonClose(); 
         return true; 
      }
      // ... Handling for other button clicks
   }

   return false; 
}

イベントが発生した際、まずそれがボタンクリックイベントであるかを確認します。デバッグ目的でイベントの詳細を出力し、特定のボタンがクリックされた場合には対応する処理関数を呼び出します。もしクリックされたボタンが閉じるボタンであれば、OnClickButtonCloseメソッドを実行します。

2. チャートイベント

ChartEventメソッドは同様の役割を持ちますが、チャートに関連するイベントを対象としています。

bool CMetricsBoard::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   Print("ChartEvent ID: ", id, ", lparam: ", lparam, ", dparam: ", dparam, ", sparam: ", sparam);

   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      return OnEvent(id, lparam, dparam, sparam);
   }

   return false;
}

このメソッドはチャート上のオブジェクトへのクリックを検知し、そのイベントをOnEventメソッドに渡してさらに処理をおこないます。

  • 分析操作

以下のメソッドは、Metrics Boardが実行できるさまざまな市場分析の種類を実装しています。たとえば、PerformHighLowAnalysisメソッドは、指定された期間の高値と安値を取得します。

void CMetricsBoard::PerformHighLowAnalysis(void)
{
   double high = iHigh(Symbol(), PERIOD_H1, 0);
   double low = iLow(Symbol(), PERIOD_H1, 0);

   Print("Retrieved High: ", high, ", Low: ", low);

   if(high == 0 || low == 0)
   {
      m_lblResults.Text("Failed to retrieve high/low values.");
      return;
   }

   string result = StringFormat("High: %.5f, Low: %.5f", high, low);
   m_lblResults.Text(result);
}

このメソッドでは、組み込み関数を使って直近1時間の最高値と最安値を取得します。取得に成功した場合は、その結果をラベルに表示し、失敗した場合はエラーメッセージを表示します。

同様のロジックが、PerformVolumeAnalysis、PerformTrendAnalysis、PerformVolatilityAnalysis、PerformMovingAverageAnalysis、PerformSupportResistanceAnalysisといった他の分析関数にも適用されます。各メソッドは、分析タイプに固有のデータを取得し、それに応じてユーザーインターフェイスを更新します。

  • 移動平均を計算する

ユーティリティメソッドの一つに、指定された期間の移動平均を計算するCalculateMovingAverageがあります。 このメソッドは、指定期間の終値を合計し、その期間数で割ることで平均値を算出します。計算をおこなう前に、入力値の妥当性や十分なデータがあるかどうかを確認します。

double CMetricsBoard::CalculateMovingAverage(int period)
{
   if(period <= 0)
      return 0;

   double sum = 0.0;
   int bars = Bars(Symbol(), PERIOD_H1);

   if(bars < period)
   {
      return 0;
   }

   for(int i = 0; i < period; i++)
   {
      sum += iClose(Symbol(), PERIOD_H1, i);
   }
   return sum / period;
}
  • グローバルインスタンスと初期化

CMetricsBoardクラスのインスタンスがグローバルに生成され、その後、アプリケーションの初期化および終了処理がおこなわれます。

CMetricsBoard ExtDialog;

int OnInit()
{
   if(!ExtDialog.Create(0, "Metrics Board", 0, 10, 10, 350, 500))
   {
      Print("Failed to create Metrics Board.");
      return INIT_FAILED;
   }

   if(!ExtDialog.Run())
   {
      Print("Failed to run Metrics Board.");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

OnInit関数では、Createメソッドを呼び出してMetrics Boardを初期化します。初期化に成功した場合は、続けてRunメソッドを実行します。エラーが発生した場合はログに記録され、関数は成功・失敗の状態を返します。

終了処理では、EAが削除された際にリソースが正しく解放されるようにします。

void OnDeinit(const int reason)
{
   ExtDialog.Destroy(reason); // Properly call Destroy method
}

  • チャートイベント処理

最後に、チャート関連のイベントを管理するためにOnChartEvent関数を定義します。これにより、ユーザーの操作がアプリケーションの機能に直接統合されます。  このメソッドはチャートイベントを検知し、それをCMetricsBoardインスタンスのChartEventメソッドに渡します。

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   ExtDialog.ChartEvent(id, lparam, dparam, sparam);
}


ライブラリをインクルードする

前のセクションで紹介したライブラリを含めずにコードをコンパイルすると、エラーが発生する可能性があります。これを解決するには、MetaEditorを開き、ナビゲータパネルに移動してください。下にスクロールして「Include」セクションを探すと、必要なライブラリにアクセスできます。該当するサブフォルダを開き、関連ファイルを選んで個別にコンパイルします。また、スクリプトの先頭で#includeディレクティブを使って、コード内でライブラリが正しく参照されていることを必ず確認してください。この手順により、すべての依存関係が正しく読み込まれ、コンパイルエラーを防ぐことができます。以下のGIFは、MetaEditorでライブラリにアクセスして組み込む方法を示しています。

ライブラリをインクルードする

図2:ライブラリをインクルードする

MQL5では、インクルードライブラリを使うことで、外部のコードや関数、クラスをプログラムに統合でき、機能を拡張するとともに、さまざまなソースからのコードを再利用できます。ライブラリを組み込むことで、その中で定義されている関数やクラス、変数にアクセス可能となり、スクリプト、エキスパートアドバイザー(EA)、インジケーターなどで利用できるようになります。MQL5のライブラリの多くは組み込み済みで、取引機能やテクニカル指標など、一般的なタスクにすぐに使える便利なソリューションを提供しています。


結果

EAのコンパイルに成功したら、MetaTrader 5を開いてチャートにEAを適用できます。テスト時に得られた結果を確認してみましょう。

結果

図3:結果

上記の図から、Metrics Board EAは各ボタン操作に的確に反応し、最適な機能を提供していることが明らかです。この機能により、EAは必要な指標をリアルタイムで提供し、ユーザーの操作性とパフォーマンスを向上させます。

  • EAログ

また、MetaTrader 5のExpertsログを確認することで、押されたボタンとチャート上のイベントの連携を観察できます。本EAにはログ機能が組み込まれているため、これらの操作が記録されています。ログに記録された情報を見て、内容を分析してみましょう。 

EAログ

図4:EAログ


結論

Metrics Board EAは、MetaTrader 5内に直接組み込まれ、描画オブジェクト機能を活用した動的かつユーザーフレンドリーなパネルインターフェイスを備えています。スムーズな統合により、まるでMetaTrader 5のネイティブコントロールを操作しているかのような使い心地を実現し、組み込みアプリケーションに匹敵する操作体験を提供します。私の見解では、本ツールは取引ツールの大きな飛躍を示しており、以前に開発したいくつかの分析スクリプトを凌駕する機能性と使いやすさを兼ね備えています。ユーザーはボタンを一度クリックするだけで必要な情報に絞って表示できるため、分析プロセスが大幅に効率化されます。過去のスクリプトも目的を十分に果たしていましたが、Metrics Board EAは市場分析の効率性とアクセシビリティをさらに一段階引き上げる存在です。

Metrics Board EAの主な機能は次のとおりです。

機能 利点
高値・安値分析 素早く重要な市場レベルを特定し、トレーダーを支援します。
ボリュームトラッキング 最新の取引量情報を提供し、市場状況の把握をサポートします。
トレンドの特定 現在の市場トレンドの把握を簡素化します。
サポート・レジスタンスレベル 戦略的な取引のための重要な価格帯を正確に特定します。

このツールはトレーダーが市場を効果的に分析し、より良い判断を下す力を与えます。シンプルな設計により複雑な分析を簡素化し、ユーザーが戦略の改善に集中できるようにします。今後は、新機能の追加やインターフェイスのさらなる改良によって、さらなる機能拡張の可能性があります。

日付 ツール名  詳細 バージョン  アップデート  備考
01/10/24 ChartProjector 前日のプライスアクションをゴースト効果でオーバーレイするスクリプト 1.0 初回リリース Lynnchris Tool Chestの最初のツール
18/11/24 Analytical Comment 前日の情報を表形式で提供し、市場の将来の方向性を予測する 1.0 初回リリース Lynnchris Tool Chestの2番目のツール
27/11/24 Analytics Master 2時間ごとに市場指標を定期的に更新  1.01 v.2 Lynnchris Tool Chestの3番目のツール
02/12/24 Analytics Forecaster  Telegram統合により、2時間ごとに市場指標を定期的に更新 1.1 v.3 ツール番号4
09/12/24 Volatility Navigator ボリンジャーバンド、RSI、ATR指標を使用して市場の状況を分析するEA 1.0 初回リリース ツール番号5
19/12/24 Mean Reversion Signal Reaper  平均回帰戦略を用いて市場を分析し、シグナルを提供する  1.0  初回リリース  ツール番号6 
9/01/2025  Signal Pulse  多時間枠分析ツール 1.0  初回リリース  ツール番号7 
17/01/2025  Metrics Board  分析用のボタン付きパネル  1.0  初回リリース ツール番号8 

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

添付されたファイル |
Metrics_Board.mq5 (15.92 KB)
MQL5取引ツールキット(第7回):直近でキャンセルされた予約注文に関する関数で履歴管理EX5ライブラリを拡張 MQL5取引ツールキット(第7回):直近でキャンセルされた予約注文に関する関数で履歴管理EX5ライブラリを拡張
直近でキャンセルされた予約注文を処理する関数に焦点を当て、History Manager EX5ライブラリの最終モジュールの作成を完了する方法を学習します。これにより、MQL5を使用してキャンセルされた予約注文に関連する重要な詳細を効率的に取得して保存するためのツールが提供されます。
MQL5入門(第11回):MQL5の組み込みインジケーターの操作に関する初心者向けガイド(II) MQL5入門(第11回):MQL5の組み込みインジケーターの操作に関する初心者向けガイド(II)
RSI、MA、ストキャスティクスなどの複数のインジケーターを使用してMQL5でエキスパートアドバイザー(EA)を開発し、隠れた強気および弱気のダイバージェンスを検出する方法を学びます。教育目的で、詳細な例および完全にコメントされたソースコードを用いて、効果的なリスク管理を実装し、取引を自動化する方法をご紹介します。
プライスアクション分析ツールキットの開発(第9回):External Flow プライスアクション分析ツールキットの開発(第9回):External Flow
本稿では、高度な分析手法として外部ライブラリを活用する、新たなアプローチを紹介します。pandasのようなライブラリは、複雑なデータを処理・解釈するための強力なツールを提供し、トレーダーが市場の動向についてより深い洞察を得られるようにします。このようなテクノロジーを統合することで、生のデータと実用的な戦略との間にあるギャップを埋めることができます。この革新的なアプローチの基盤を築き、テクノロジーと取引の専門知識を融合させる可能性を引き出すために、ぜひご一緒に取り組んでいきましょう。
MQL5とPythonを使用したブローカーAPIとエキスパートアドバイザーの統合 MQL5とPythonを使用したブローカーAPIとエキスパートアドバイザーの統合
この記事では、Pythonと連携したMQL5の実装について解説し、ブローカー関連の操作を自動化する方法を紹介します。VPS上にホストされて継続的に稼働するエキスパートアドバイザー(EA)が、あなたに代わって取引を実行すると想像してください。ある時点で、EAによる資金管理機能が非常に重要になります。具体的には、取引口座への残高補充や出金などの操作を含みます。本稿では、これらの機能の利点と実際の実装例を紹介し、資金管理を取引戦略にシームレスに統合する方法をお伝えします。どうぞご期待ください。