English Deutsch 日本語
preview
Разработка инструментария для анализа движения цен (Часть 8): Панель метрик

Разработка инструментария для анализа движения цен (Часть 8): Панель метрик

MetaTrader 5Трейдинг |
77 0
Christian Benjamin
Christian Benjamin

Содержание



Введение

На ранних этапах нашей серии мы опубликовали статью под названием "Советник Analytics Master", в которой рассматривались методы извлечения и визуализации рыночных показателей предыдущего дня. Эта основополагающая работа подготовила почву для разработки более сложных инструментов. Мы рады представить вам советник Metrics Board — инновационное и высококачественное решение, которое кардинально меняет подход к анализу рынка в MetaTrader 5. Этот инструмент функционирует как интегрированное приложение, предлагая оптимизированный и простой интерфейс, оснащенный специальными кнопками для расширенного анализа, включая:

  • High/Low Analysis (анализ максимумов/минимумов) - легко определяйте критические уровни цен для оценки рыночных трендов и выявления потенциальных разворотов.
  • Volume Analysis (анализ объемов) - анализируйте торговые объемы для оценки активности рынка и условий ликвидности.
  • Trend Analysis (анализ трендов) - оценивайте направление и устойчивость с помощью точных показателей.
  • Volatility Analysis (анализ волатильности) - количественная оценка рыночных колебаний для разработки стратегий, адаптированных к различным торговым условиям.
  • Moving Average Analysis (анализ скользящей средней) - отслеживайте динамические ценовые тренды для более четкого понимания поведения рынка.
  • Support/Resistance (анализ поддержки/сопротивления) - определяйте ключевые ценовые уровни для оптимизации стратегий входа, выхода и управления рисками.

Каждая кнопка обеспечивает доставку данных в реальном времени простым нажатием, мгновенно преобразуя сложные рыночные данные в полезную информацию. Советник Metrics Board основан на передовых алгоритмах, обеспечивающих высокую скорость и точность вычислений, отвечающих потребностям профессиональных трейдеров. Используя этот инструмент, трейдеры могут преобразовывать сложные рыночные данные в простые и практичные решения. Советник служит ключевым ресурсом для тех, кто стремится усовершенствовать свои торговые стратегии.


Обзор системы

В этом разделе я представлю краткий обзор логики системы. Подробное объяснение шагов представлено в разделе "Разбор и реализация кода". Необходимые шаги:

  • Настройка класса: Класс создает диалоговое окно с кнопками для различной аналитики.
  • Обработка событий: Нажатия кнопок запускают соответствующие методы анализа.
  • Анализ и отображение: Рыночные данные обрабатываются и отображаются на панели.
  • Закрытие: Кнопка Close (закрыть) позволяет пользователю закрыть панель метрик.
Вышеописанные шаги описывают этапы, которые наш советник должен пройти для достижения ожидаемых результатов. Каждый этап тщательно продуман для обеспечения точного исполнения и охватывает все: от анализа рынка до выработки практических идей. Соблюдая эти этапы, советник обеспечивает бесперебойный и эффективный процесс. Давайте также обратимся к диаграмме ниже для визуального представления всего процесса.


Логика советника

Рис 1. Логика советника


Код MQL5

//+------------------------------------------------------------------+
//|                                                Metrics Board.mql5|
//|                                Copyright 2025, Christian Benjamin|
//|                                              https://www.mql5.com|
//+------------------------------------------------------------------+
#property copyright "2025, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/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/en/users/lynnchris"
#property version   "1.0"
#property strict
В блоке комментариев описывается цель скрипта и указываются авторы, что важно для определения авторства и обеспечения правильной атрибуции для будущих пользователей. Директивы #property служат для определения различных характеристик скрипта, таких как информация об авторских правах, ссылка на автора или документацию, номер версии и установка строгого режима, который помогает выявлять потенциальные проблемы во время компиляции.
  • Подключение необходимых библиотек

Далее мы подключаем библиотеки, необходимые для нашего приложения. Эти библиотеки предоставляют предопределенные функции, упрощающие кодирование.

#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 используются для создания и управления компонентами пользовательского интерфейса панели метрик.

  • Определение класса
После включения библиотеки мы определяем основной класс панели. Класс CMetricsBoard наследует от CAppDialog, что позволяет нам использовать функционал диалога. Мы объявляем несколько приватных переменных-членов, в основном кнопки и панели, которые будут использоваться для взаимодействия с приложением. Каждая кнопка соответствует функции анализа, а результаты будут отображены на панели 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 необходим для работы диалогового окна.

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 для дальнейшей обработки.

  • Аналитические операции

Следующие методы реализуют различные типы анализа рынка, которые может выполнять наша панель метрик. Например, 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);
}

В этом методе мы используем встроенные функции для извлечения самых высоких и самых низких цен за последний час. В случае успеха результаты отображаются на подписи. В противном случае выводится сообщение об ошибке.

Аналогичная логика применяется к другим функциям анализа, таким как 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. В случае успеха приступаем к запуску. Ошибки регистрируются соответствующим образом, а функция указывает на успех или неудачу.

Деинициализация обеспечивает корректное высвобождение ресурсов при удалении советника.

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

  • Обработка событий графика

Наконец, мы определяем функцию OnChartEvent для управления событиями, связанными с графиками. Это позволяет интегрировать взаимодействие пользователя непосредственно в функционал приложения. Метод фиксирует события диаграммы и передает их в метод ChartEvent нашего экземпляра CMetricsBoard.

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 библиотека include позволяет интегрировать внешний код, функции или классы в программу, расширяя ее функциональность и позволяя повторно использовать код из различных источников. Включая библиотеку, вы получаете доступ к функциям, классам или переменным, определенным в ней, что делает их доступными для использования в вашем скрипте, советнике или индикаторе. Большинство библиотек в MQL5 являются встроенными и предоставляют готовые решения для распространенных задач, таких как торговые функции, технические индикаторы и многое другое.


Результаты

После успешной компиляции советника вы можете перейти в MetaTrader 5 и прикрепить советник к графику. Давайте рассмотрим результаты, полученные в ходе тестирования.

Результаты

Рис. 3. Результаты

В соответствии с представленным выше графиком очевидно, что советник Metrics Board обеспечивает оптимальную функциональность, эффективно реагируя на каждое нажатие кнопки. Советник предоставляет необходимые показатели в реальном времени, улучшая взаимодействие с пользователем и производительность.

  • Журналирование

Мы также можем просмотреть вкладку "Эксперты" в MetaTrader 5, чтобы проследить взаимодействие между нажатыми кнопками и событиями на графике. Поскольку наш советник включает в себя встроенную функцию журналирования, он будет фиксировать эти взаимодействия. Давайте посмотрим, какая информация была зафиксирована. 

Записи на вкладке "Эксперты"

Рис 4. Записи на вкладке "Эксперты"


Заключение

Советник Metrics Board имеет динамичный и удобный интерфейс панели, встроенный непосредственно в MetaTrader 5, включая функцию рисования объектов. Благодаря плавной интеграции создается впечатление работы с собственными элементами управления MetaTrader 5. На мой взгляд, это знаменует собой значительный прогресс в области торговых инструментов, обеспечивая функциональность и простоту использования, превосходящие возможности некоторых аналитических скриптов, разработанных мной ранее. Позволяя пользователям сосредоточиться на определенной информации одним нажатием кнопки, приложение гарантирует отображение только необходимых данных, оптимизируя процесс анализа. Хотя предыдущие скрипты эффективно выполняли свои задачи, советник выводит анализ рынка на более высокий уровень эффективности и доступности.

Ключевые особенности советника включают в себя:

Свойство Польза
High/Low Analysis Быстро определяет значимые уровни рынка.
Volume Tracking Предоставляет актуальные данные об объеме торгов для лучшего понимания ситуации на рынке.
Trend Identification Упрощает процесс распознавания текущих рыночных тенденций.
Support/Resistance Точно определяет ключевые ценовые зоны для стратегической торговли.

Этот инструмент позволяет трейдерам эффективно анализировать рынки и делать более обоснованный выбор. Его простой дизайн упрощает сложную аналитику, позволяя пользователям сосредоточиться на совершенствовании своих стратегий. Возможности сервиса могут быть расширены за счет добавления новых функций и дальнейшего улучшения интерфейса.

Дата Название инструмента  Описание Версия  Обновления  Примечания
01/10/24 Chart Projector Скрипт для наложения эффекта призрака на движение цены за предыдущий день. 1.0 Первоначальная версия Первый инструмент в Lynnchris Tools Chest
18/11/24 Analytical Comment Предоставляет информацию за предыдущий день в табличном формате, а также прогнозирует будущее направление рынка. 1.0 Первоначальная версия Второй инструмент в Lynnchris Tools Chest
27/11/24 Analytics Master Регулярное обновление рыночных показателей каждые два часа  1.01 Вторая версия Третий инструмент в Lynnchris Tools Chest
02/12/24 Analytics Forecaster  Регулярное обновление рыночных показателей каждые два часа с интеграцией с Telegram 1.1 Третья версия Инструмент номер 4
09/12/24 Volatility Navigator Советник анализирует рыночные условия с помощью полос Боллинджера, RSI и ATR. 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  Панель с кнопкfvb для анализа  1.0  Первоначальная версия Инструмент номер 8 

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16584

Прикрепленные файлы |
Metrics_Board.mq5 (15.92 KB)
Анализ стратегий внутридневной торговли на основе прорывов диапазона открытия Анализ стратегий внутридневной торговли на основе прорывов диапазона открытия
Стратегии прорыва диапазона открытия (Opening Range Breakout, ORB) основаны на идее о том, что начальный торговый диапазон, установленный вскоре после открытия рынка, отражает значимые уровни цен, когда покупатели и продавцы договариваются о стоимости. Выявляя прорывы определенного диапазона вверх или вниз, трейдеры могут извлекать выгоду из моментума, который часто возникает, когда направление рынка становится более отчетливым. В этой статье рассмотрим три стратегии ORB, адаптированные из материалов компании Concretum Group.
Модификация Алгоритма оптимизации динго — Dingo Optimization Algorithm M (DOAm) Модификация Алгоритма оптимизации динго — Dingo Optimization Algorithm M (DOAm)
Представленная в статье авторская модификация алгоритма динго высоко подняла планку для поиска лучшего из лучших алгоритма оптимизации. Возможны ли еще более высокие результаты?
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Автоматизация торговых стратегий на MQL5 (Часть 3): система Zone Recovery RSI для динамического управления торговлей Автоматизация торговых стратегий на MQL5 (Часть 3): система Zone Recovery RSI для динамического управления торговлей
В этой статье мы создадим систему Zone Recovery RSI EA на языке MQL5, используя сигналы RSI для запуска сделок и стратегию восстановления для управления убытками. Мы реализуем класс ZoneRecovery для автоматизации входа в сделку, логики восстановления и управления позициями. В заключение статьи приводятся результаты бэктестинга для оптимизации производительности и повышения эффективности советника.