English Deutsch 日本語
preview
От новичка до эксперта: Создание анимированного советника для новостей в MQL5 (X) — Представление графика с несколькими символами для торговли на новостях

От новичка до эксперта: Создание анимированного советника для новостей в MQL5 (X) — Представление графика с несколькими символами для торговли на новостях

MetaTrader 5Примеры |
359 0
Clemence Benjamin
Clemence Benjamin

Содержание:


Введение

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

Однако проблема осталась: хотя трейдеры могли управлять выбранными парами, они по-прежнему не могли напрямую обращаться к графическим интерфейсам для этих пар и, следовательно, не имели возможности удобно просматривать их цену для анализа. Чтобы решить эту проблему, сегодня мы совершенствуем нашу торговлю по нескольким символам, разработав специальный класс для визуализации нескольких графиков, который легко управляется на графике и интегрируется как часть более широкого набора функций советника News Headline EA.

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

Самая ранняя версия советника News Headline EA была ориентирована на воспроизведение запланированных календарных событий в четко определенных полосах на графике, распределенных по важности. Концепция “полос” быстро расширилась: мы интегрировали API новостной ленты от Alpha Vantage, добавили локально размещенные аналитические данные от моделей ИИ и создали полосы для встроенных аналитических данных на основе индикаторов. Основываясь на этом, мы внедрили функции автоматической торговли на новостях, включая специализированный функционал для торговли NFP (Данные о занятости в несельскохозяйственном секторе) в сочетании с интегрированием кнопок ручной торговли.

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

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


Стратегия реализации

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

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

Для такой сложной программы, как News Headline EA, я придерживаюсь последовательного рабочего процесса:

  1. Начните с разработки отдельной мини-программы, предназначенной для тестирования новой функции.
  2. Как только функция станет доступной и стабильной, приступайте к интеграции в основной советник.

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

Сегодня нашей задачей по разработке является создание класса CChartMiniTiles, который будет обрабатывать отображение диаграмм нескольких символов в рамках одной диаграммы, каждая из которых имеет настраиваемые размеры. Затем мы реализуем этот класс в фиктивном советнике (MiniChartsEA) для проверки концепции. После подтверждения этот класс будет интегрирован в советник News Headline EA и адаптирован для обеспечения бесперебойной работы.

Наконец, обратите внимание, что такие имена, как CChartMiniTiles и MiniChartsEA, являются просто заполнителями, которые я выбрал для этого пошагового руководства — вы можете использовать разные имена, если понимаете, как работает программа.

В следующих 4 подразделах мы сосредоточимся на реализации:

  1. Заголовок ChartMiniTiles
  2. Пример советника (MiniChartsEA) для тестирования заголовка
  3. Первоначальное тестирование
  4. Интеграция ChartsMiniTiles в советник News Headline EA

1.0 Заголовок ChartMiniTiles

Этот заголовочный файл определяет класс CChartMiniTiles, многоразовую утилиту, предназначенную для отображения нескольких мини-графиков и управления ими в рамках одного графика на MetaTrader 5. Цель этого класса - упростить интеграцию многосимвольных графиков в более крупные проекты, такие как советник News Headline EA, сохраняя при этом модульность кода и удобство сопровождения.

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

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

1.1. Обзор и назначение класса

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

//+------------------------------------------------------------------+
//| ChartMiniTilesClass.mqh                                          |
//| Class wrapper for ChartMiniTiles functionality                   |
//| - CChartMiniTiles class                                           |
//| - bottom-anchored mini-chart tiles using OBJ_CHART                |
//| - broker-adaptive symbol lookup, toggle button, responsive layout |
//| - supports top-reserved area to avoid overlapping top UI     |
//+------------------------------------------------------------------+
#ifndef __CHART_MINI_TILES_CLASS_MQH__
#define __CHART_MINI_TILES_CLASS_MQH__

//--- compile-time defaults (macros are safe in MQL5)
#define CMT_DEFAULT_WIDTH       120
#define CMT_DEFAULT_HEIGHT      112    // quadrupled default
#define CMT_DEFAULT_X_OFFSET    10
#define CMT_DEFAULT_Y_OFFSET    40     // bottom offset from bottom
#define CMT_DEFAULT_SPACING     6
#define CMT_DEFAULT_PERIOD      PERIOD_M1
#define CMT_DEFAULT_CHART_SCALE 2

// toggle button defaults
#define CMT_TOG_X               8
#define CMT_TOG_Y               6
#define CMT_TOG_W               72
#define CMT_TOG_H               20
#define CMT_TOG_NAME            "CMT_ToggleButton"

1.2. Конструктор и Деструктор

Конструктор инициализирует класс в известном безопасном состоянии, используя значения по умолчанию во время компиляции. Он подготавливает внутренние массивы, размеры и смещения мозаичных фрагментов по умолчанию, а также настройки кнопок переключения и устанавливает значение m_top_reserved равным нулю (зарезервированная по умолчанию область отсутствует). Деструктор вызывает Delete(), чтобы гарантировать, что любые созданные классом объекты будут удалены, когда экземпляр выйдет за пределы области видимости. Такая детерминированная настройка и демонтаж предотвращают появление оставшихся объектов на диаграмме и уменьшают проблемы с отладкой.

//+------------------------------------------------------------------+
//| CChartMiniTiles class declaration                                |
//+------------------------------------------------------------------+
class CChartMiniTiles
  {
public:
                     CChartMiniTiles(void);
                    ~CChartMiniTiles(void);

   bool              Init(const string majorSymbols,
                          const int width = -1,
                          const int height = -1,
                          const int xOffset = -1,
                          const int yOffset = -1,        // bottom offset (pixels from bottom)
                          const int spacing = -1,
                          const int period = -1,
                          const bool dateScale = true,
                          const bool priceScale = false,
                          const int chartScale = -1);

   void              UpdateLayout(void);
   void              Delete(void);

   bool              HandleEvent(const int id,const string sparam); // forward OnChartEvent
   void              SetToggleButtonPos(const int x,const int y);
   void              SetTilesVisible(const bool visible);
   void              Toggle(void);

   // NEW: reserve top area height (pixels from top) that tiles must NOT cover
   void              SetTopReservedHeight(const int pixels);

private:
   // state
   string            m_object_names[];   // object names created
   string            m_symbols[];        // resolved broker symbols
   int               m_count;

   int               m_width;
   int               m_height;
   int               m_xoffset;
   int               m_yoffset;         // bottom offset
   int               m_spacing;
   int               m_period;
   bool              m_date_scale;
   bool              m_price_scale;
   int               m_chart_scale;
   bool              m_visible;

   int               m_tog_x;
   int               m_tog_y;
   int               m_tog_w;
   int               m_tog_h;
   string            m_tog_name;

   // NEW
   int               m_top_reserved;    // pixels from top that must be left free for other UI

private:
   // helpers
   string            MakeObjectName(const string base);
   string            TrimString(const string s);
   string            FindBrokerSymbol(const string baseSymbol);
   int               ComputeBaseYFromTop(void);

   void              CreateToggleButton(void);
   void              DeleteToggleButton(void);
   void              CollapseAll(void);
  };

//+------------------------------------------------------------------+
//| Constructor / Destructor                                         |
//+------------------------------------------------------------------+
CChartMiniTiles::CChartMiniTiles(void)
  {
   m_count       = 0;
   ArrayResize(m_object_names,0);
   ArrayResize(m_symbols,0);

   m_width       = CMT_DEFAULT_WIDTH;
   m_height      = CMT_DEFAULT_HEIGHT;
   m_xoffset     = CMT_DEFAULT_X_OFFSET;
   m_yoffset     = CMT_DEFAULT_Y_OFFSET;
   m_spacing     = CMT_DEFAULT_SPACING;
   m_period      = CMT_DEFAULT_PERIOD;
   m_date_scale  = false;
   m_price_scale = false;
   m_chart_scale = CMT_DEFAULT_CHART_SCALE;
   m_visible     = true;

   m_tog_x = CMT_TOG_X;
   m_tog_y = CMT_TOG_Y;
   m_tog_w = CMT_TOG_W;
   m_tog_h = CMT_TOG_H;
   m_tog_name = CMT_TOG_NAME;

   m_top_reserved = 0; // default: no reserved area
  }

CChartMiniTiles::~CChartMiniTiles(void)
  {
   Delete();
  }

1.3. Вспомогательные методы

Эти специализированные вспомогательные функции нормализуют входные данные и скрывают причуды брокера, что упрощает работу с остальными частями класса. MakeObjectName преобразует строки в безопасные имена объектов (заменяя пробелы и специальные символы). Строка TrimString удаляет начальные и конечные пробелы, включая символы табуляции и новые строки. FindBrokerSymbol пытается выполнить точный SymbolSelect и, если это не удается, выполняет поиск без учета регистра по списку символов брокера, чтобы найти соответствие - это важно для переносимости между брокерами, которые добавляют суффиксы или используют разные соглашения об именовании. ComputeBaseYFromTop определяет вертикальную базовую линию для привязанных снизу мозаичных фрагментов, защищая при этом от недопустимых значений высоты диаграммы.

//+------------------------------------------------------------------+
//| Helpers implementation                                           |
//+------------------------------------------------------------------+
string CChartMiniTiles::MakeObjectName(const string base)
  {
   string name = base;
   StringReplace(name, " ", "_");
   StringReplace(name, ".", "_");
   StringReplace(name, ":", "_");
   StringReplace(name, "/", "_");
   StringReplace(name, "\\", "_");
   return(name);
  }

string CChartMiniTiles::TrimString(const string s)
  {
   if(s == NULL) return("");
   int len = StringLen(s);
   if(len == 0) return("");
   int left = 0;
   int right = len - 1;
   while(left <= right)
     {
      int ch = StringGetCharacter(s, left);
      if(ch == 32 || ch == 9 || ch == 10 || ch == 13) left++;
      else break;
     }
   while(right >= left)
     {
      int ch = StringGetCharacter(s, right);
      if(ch == 32 || ch == 9 || ch == 10 || ch == 13) right--;
      else break;
     }
   if(left > right) return("");
   return StringSubstr(s, left, right - left + 1);
  }

string CChartMiniTiles::FindBrokerSymbol(const string baseSymbol)
  {
   if(StringLen(baseSymbol) == 0) return("");
   if(SymbolSelect(baseSymbol, true))
      return(baseSymbol);

   string baseUpper = baseSymbol; StringToUpper(baseUpper);

   int total = SymbolsTotal(true);
   for(int i = 0; i < total; i++)
     {
      string s = SymbolName(i, true);
      if(StringLen(s) == 0) continue;
      string sUpper = s; StringToUpper(sUpper);
      if(StringFind(sUpper, baseUpper) >= 0)
         return(s);
     }
   return("");
  }

int CChartMiniTiles::ComputeBaseYFromTop(void)
  {
   int chartTotalHeight = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
   if(chartTotalHeight <= 0) chartTotalHeight = 600;
   int base_y_from_top = chartTotalHeight - m_yoffset - m_height;
   if(base_y_from_top < 0) base_y_from_top = 0;
   if(base_y_from_top + m_height > chartTotalHeight) base_y_from_top = MathMax(0, chartTotalHeight - m_height);
   return base_y_from_top;
  }

1.4. Управление с помощью кнопки переключения

Интерактивное управление осуществляется с помощью кнопки-переключателя. CreateToggleButton гарантирует, что кнопочный объект существует (создает его, если он отсутствует), и устанавливает визуальные свойства: положение, размер, шрифт, цвет фона, цвет текста, возможность выбора и текст о начальном состоянии, определяемый параметром m_visible. DeleteToggleButton чисто удаляет её. CollapseAll - это упрощенный метод скрытия, который эффективно скрывает фрагменты, перемещая их за пределы экрана и устанавливая их размеры равными нулю, а не удаляя их. Это позволяет сохранить состояние для быстрого повторного отображения и избежать затрат на воссоздание объектов.

//+------------------------------------------------------------------+
//| Toggle button helpers                                            |
//+------------------------------------------------------------------+
void CChartMiniTiles::CreateToggleButton(void)
  {
   if(ObjectFind(ChartID(), m_tog_name) == -1)
      ObjectCreate(ChartID(), m_tog_name, OBJ_BUTTON, 0, 0, 0, 0, 0);

   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XSIZE, m_tog_w);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YSIZE, m_tog_h);

   ObjectSetString(ChartID(), m_tog_name, OBJPROP_FONT, "Arial");
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_FONTSIZE, 10);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_BGCOLOR, clrDarkSlateGray);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_SELECTABLE, 1);
   ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, m_visible ? 1 : 0);
   ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, m_visible ? "Tiles: ON" : "Tiles: OFF");
  }

void CChartMiniTiles::DeleteToggleButton(void)
  {
   if(ObjectFind(ChartID(), m_tog_name) >= 0)
      ObjectDelete(ChartID(), m_tog_name);
  }

void CChartMiniTiles::CollapseAll(void)
  {
   for(int i = 0; i < ArraySize(m_object_names); i++)
     {
      string name = m_object_names[i];
      if(StringLen(name) == 0) continue;
      if(ObjectFind(ChartID(), name) == -1) continue;
      ObjectSetInteger(ChartID(), name, OBJPROP_XDISTANCE, -1);
      ObjectSetInteger(ChartID(), name, OBJPROP_YDISTANCE, -1);
      ObjectSetInteger(ChartID(), name, OBJPROP_XSIZE, 0);
      ObjectSetInteger(ChartID(), name, OBJPROP_YSIZE, 0);
     }
  }

1.5. Инициализация мини-диаграмм

Init - это основная процедура настройки: сначала она очищает любое предыдущее состояние, применяет переданные параметры, возвращаясь к значениям по умолчанию, анализирует список разделенных запятыми majorSymbols, обрезает и преобразует каждый из них в определенный брокером символ с помощью FindBrokerSymbol и создает массив m_symbols. Вычисляет ограничения компоновки на основе ширины диаграммы и размеров мозаики, а затем устанавливает ограничение по рядам, чтобы избежать вторжения в m_top_reserved (зарезервированную верхнюю область). Для каждого разрешенного символа создает OBJ_CHART, задаёт свойства (символ, период, расстояния, размеры, масштаб даты/цены и масштаб графика) и сохраняет имя созданного объекта для последующего обновления или удаления. После создания она исполняет кнопку переключения, соблюдает флажок начальной видимости, перерисовывает диаграмму и возвращает успешное значение. Этот метод включает ведение лога для определения разрешения символов и созданных объектов, чтобы поведение во время выполнения было прозрачным.

//+------------------------------------------------------------------+
//| NEW: set top reserved height (pixels from top)                   |
//+------------------------------------------------------------------+
void CChartMiniTiles::SetTopReservedHeight(const int pixels)
  {
   m_top_reserved = MathMax(0, pixels);
  }

//+------------------------------------------------------------------+
//| Init: create mini tiles                                           |
//+------------------------------------------------------------------+
bool CChartMiniTiles::Init(const string majorSymbols,
                           const int width,
                           const int height,
                           const int xOffset,
                           const int yOffset,
                           const int spacing,
                           const int period,
                           const bool dateScale,
                           const bool priceScale,
                           const int chartScale)
  {
   Delete();

   m_width       = (width  <= 0) ? CMT_DEFAULT_WIDTH  : width;
   m_height      = (height <= 0) ? CMT_DEFAULT_HEIGHT : height;
   m_xoffset     = (xOffset <= 0) ? CMT_DEFAULT_X_OFFSET : xOffset;
   m_yoffset     = (yOffset <= 0) ? CMT_DEFAULT_Y_OFFSET : yOffset;
   m_spacing     = (spacing <= 0) ? CMT_DEFAULT_SPACING : spacing;
   m_period      = (period <= 0) ? CMT_DEFAULT_PERIOD : period;
   m_date_scale  = dateScale;
   m_price_scale = priceScale;
   m_chart_scale = (chartScale <= 0) ? CMT_DEFAULT_CHART_SCALE : chartScale;

   ArrayFree(m_object_names);
   ArrayFree(m_symbols);
   m_count = 0;

   string raw[]; StringSplit(majorSymbols, ',', raw);
   int rawCount = ArraySize(raw);
   if(rawCount == 0) return(false);

   for(int i = 0; i < rawCount; i++)
     {
      string base = TrimString(raw[i]);
      if(StringLen(base) == 0) continue;
      string resolved = FindBrokerSymbol(base);
      if(resolved == "")
        {
         PrintFormat("CMT: symbol not found on this broker: %s", base);
         continue;
        }
      int n = ArraySize(m_symbols);
      ArrayResize(m_symbols, n + 1);
      m_symbols[n] = resolved;
     }

   m_count = ArraySize(m_symbols);
   PrintFormat("CMT: %d symbols resolved for mini-tiles.", m_count);
   for(int i=0;i<m_count;i++) PrintFormat("CMT: symbol[%d] = %s", i, m_symbols[i]);

   if(m_count == 0) return(false);

   ArrayResize(m_object_names, m_count);
   for(int i = 0; i < m_count; i++) m_object_names[i] = "";

   int base_y_from_top = ComputeBaseYFromTop();

   int chartW = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   if(chartW <= 0) chartW = 800;
   int columns = MathMax(1, chartW / (m_width + m_spacing));

   // --- NEW: limit rows to avoid top reserved region
   int rows = (m_count + columns - 1) / columns;
   int availableAbove = MathMax(0, base_y_from_top - m_top_reserved);
   int maxRowsAllowed = 1 + (availableAbove / (m_height + m_spacing)); // bottom row + how many rows can fit above
   if(maxRowsAllowed < 1) maxRowsAllowed = 1;
   if(rows > maxRowsAllowed)
     {
      // increase columns to fit within allowed rows
      columns = (m_count + maxRowsAllowed - 1) / maxRowsAllowed;
      if(columns < 1) columns = 1;
      rows = (m_count + columns - 1) / columns;
     }
   // ---

   int createdCount = 0;
   for(int i = 0; i < m_count; i++)
     {
      string sym = m_symbols[i];
      string objName = MakeObjectName("CMT_" + sym + "_" + IntegerToString(i));
      m_object_names[i] = objName;

      int col = i % columns;
      int row = i / columns;

      int xdist = m_xoffset + col * (m_width + m_spacing);
      int ydist = base_y_from_top - row * (m_height + m_spacing);
      if(ydist < 0) ydist = 0;

      bool created = ObjectCreate(ChartID(), objName, OBJ_CHART, 0, 0, 0, 0, 0);
      if(!created)
        {
         PrintFormat("CMT: failed to create OBJ_CHART for %s (obj=%s)", sym, objName);
         m_object_names[i] = "";
         continue;
        }

      ObjectSetString(ChartID(), objName, OBJPROP_SYMBOL, sym);
      ObjectSetInteger(ChartID(), objName, OBJPROP_PERIOD, m_period);
      ObjectSetInteger(ChartID(), objName, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(ChartID(), objName, OBJPROP_YDISTANCE, ydist);
      ObjectSetInteger(ChartID(), objName, OBJPROP_XSIZE, m_width);
      ObjectSetInteger(ChartID(), objName, OBJPROP_YSIZE, m_height);
      ObjectSetInteger(ChartID(), objName, OBJPROP_DATE_SCALE, (int)m_date_scale);
      ObjectSetInteger(ChartID(), objName, OBJPROP_PRICE_SCALE, (int)m_price_scale);
      ObjectSetInteger(ChartID(), objName, OBJPROP_SELECTABLE, 1);
      ObjectSetInteger(ChartID(), objName, OBJPROP_CHART_SCALE, m_chart_scale);

      createdCount++;
     }

   PrintFormat("CMT: created %d / %d mini-chart objects.", createdCount, m_count);

   CreateToggleButton();

   if(!m_visible)
     SetTilesVisible(false);

   ChartRedraw();
   return(true);
  }

1.6. Обновления компоновки

UpdateLayout пересчитывает позиции и размеры при изменении геометрии или видимости диаграммы. Сначала она обрабатывает скрытое состояние, сворачивая фрагменты и устанавливая переключатель в положение “ВЫКЛ”. Когда становится видимой, пересчитывает столбцы по ширине диаграммы, применяет ограничение верхнего зарезервированного пространства (чтобы ряды никогда не пересекались с зарезервированным пространством) и обновляет каждый OBJ_CHART соответствующими OBJPROP_XDISTANCE, OBJPROP_YDISTANCE, размерами и масштабом диаграммы. Наконец, она обновляет состояние кнопки переключения на “ВКЛ” и вызывает ChartRedraw(), чтобы обновить пользовательский интерфейс. Этот метод предназначен для вызова всякий раз, когда изменяется размер графика или когда советник хочет обновить компоновку.

//+------------------------------------------------------------------+
//| UpdateLayout - reposition tiles (respects m_visible and top reserved)|
//+------------------------------------------------------------------+
void CChartMiniTiles::UpdateLayout(void)
  {
   if(!m_visible)
     {
      CollapseAll();
      if(ObjectFind(ChartID(), m_tog_name) >= 0)
        {
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, 0);
         ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, "Tiles: OFF");
        }
      ChartRedraw();
      return;
     }

   if(m_count == 0) return;

   int chartW = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   if(chartW <= 0) chartW = 800;
   int chartTotalHeight = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
   if(chartTotalHeight <= 0) chartTotalHeight = 600;

   int columns = MathMax(1, chartW / (m_width + m_spacing));

   int base_y_from_top = ComputeBaseYFromTop();

   // --- NEW: ensure rows don't surpass top-reserved area
   int rows = (m_count + columns - 1) / columns;
   int availableAbove = MathMax(0, base_y_from_top - m_top_reserved);
   int maxRowsAllowed = 1 + (availableAbove / (m_height + m_spacing));
   if(maxRowsAllowed < 1) maxRowsAllowed = 1;
   if(rows > maxRowsAllowed)
     {
      columns = (m_count + maxRowsAllowed - 1) / maxRowsAllowed;
      if(columns < 1) columns = 1;
      rows = (m_count + columns - 1) / columns;
     }
   // ---

   for(int i = 0; i < m_count; i++)
     {
      string name = m_object_names[i];
      if(StringLen(name) == 0) continue;
      if(ObjectFind(ChartID(), name) == -1) continue;

      int col = i % columns;
      int row = i / columns;
      int xdist = m_xoffset + col * (m_width + m_spacing);
      int ydist = base_y_from_top - row * (m_height + m_spacing);
      if(ydist < 0) ydist = 0;

      ObjectSetInteger(ChartID(), name, OBJPROP_XDISTANCE, xdist);
      ObjectSetInteger(ChartID(), name, OBJPROP_YDISTANCE, ydist);
      ObjectSetInteger(ChartID(), name, OBJPROP_XSIZE, m_width);
      ObjectSetInteger(ChartID(), name, OBJPROP_YSIZE, m_height);
      ObjectSetInteger(ChartID(), name, OBJPROP_CHART_SCALE, m_chart_scale);
     }

   if(ObjectFind(ChartID(), m_tog_name) >= 0)
     {
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, 1);
      ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, "Tiles: ON");
     }

   ChartRedraw();
  }

1.7. Видимость и переключение

Этот небольшой набор методов управляет видимым состоянием мозаики. SetTilesVisible обновляет флаг m_visible и либо перемещает мозаики, либо сворачивает их в зависимости от нового состояния; она также обновляет состояние и текст кнопки переключения. Toggle - это удобная оболочка, которая изменяет видимость и вызывает SetTilesVisible. SetToggleButtonPos позволяет динамически изменять положение кнопки переключения; если кнопка уже существует, она обновляет OBJPROP_XDISTANCE и OBJPROP_YDISTANCE. Эти методы являются программными и точками входа пользовательского интерфейса для отображения, скрытия и изменения положения элементов управления мозаикой.

//+------------------------------------------------------------------+
//| Set visibility programmatically                                  |
//+------------------------------------------------------------------+
void CChartMiniTiles::SetTilesVisible(const bool visible)
  {
   m_visible = visible;
   if(m_count == 0)
     {
      if(ObjectFind(ChartID(), m_tog_name) >= 0)
        {
         ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, m_visible ? 1 : 0);
         ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, m_visible ? "Tiles: ON" : "Tiles: OFF");
         ChartRedraw();
        }
      return;
     }

   if(m_visible)
     UpdateLayout();
   else
     {
      CollapseAll();
      ChartRedraw();
     }

   if(ObjectFind(ChartID(), m_tog_name) >= 0)
     {
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_STATE, m_visible ? 1 : 0);
      ObjectSetString(ChartID(), m_tog_name, OBJPROP_TEXT, m_visible ? "Tiles: ON" : "Tiles: OFF");
     }
  }

//+------------------------------------------------------------------+
//| Toggle                                                           |
//+------------------------------------------------------------------+
void CChartMiniTiles::Toggle(void)
  {
   SetTilesVisible(!m_visible);
  }

//+------------------------------------------------------------------+
//| Set toggle position                                               |
//+------------------------------------------------------------------+
void CChartMiniTiles::SetToggleButtonPos(const int x,const int y)
  {
   m_tog_x = x;
   m_tog_y = y;
   if(ObjectFind(ChartID(), m_tog_name) >= 0)
     {
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_XDISTANCE, m_tog_x);
      ObjectSetInteger(ChartID(), m_tog_name, OBJPROP_YDISTANCE, m_tog_y);
     }
  }

1.8. Очистка и обработка событий

Наконец, Delete выполняет тщательную очистку: она перебирает массив имен объектов и удаляет каждую созданную OBJ_CHART, удаляет кнопку переключения, освобождает массивы с помощью ArrayFree, сбрасывает m_count и перерисовывает диаграмму. HandleEvent - это метод переадресации событий, предназначенный для вызова из OnChartEvent советника; она выполняет фильтрацию по CHARTEVENT_OBJECT_CLICK и по названию кнопки переключения — если переключатель был нажат, она вызывает Toggle() и возвращает значение true, указывающее на то, что событие было обработано. Это упрощает интеграцию с советником: пересылка событий и вызов Init/Delete в OnInit/OnDeinit.

//+------------------------------------------------------------------+
//| Delete all objects                                                |
//+------------------------------------------------------------------+
void CChartMiniTiles::Delete(void)
  {
   for(int i = 0; i < ArraySize(m_object_names); i++)
     {
      string name = m_object_names[i];
      if(StringLen(name) == 0) continue;
      if(ObjectFind(ChartID(), name) >= 0) ObjectDelete(ChartID(), name);
     }
   DeleteToggleButton();
   ArrayFree(m_object_names);
   ArrayFree(m_symbols);
   m_count = 0;
   ChartRedraw();
  }

//+------------------------------------------------------------------+
//| HandleEvent - forward OnChartEvent to class (returns true if handled)|
//+------------------------------------------------------------------+
bool CChartMiniTiles::HandleEvent(const int id,const string sparam)
  {
   if(id != CHARTEVENT_OBJECT_CLICK) return(false);
   if(StringLen(sparam) == 0) return(false);
   if(sparam == m_tog_name)
     {
      Toggle();
      return(true);
     }
   return(false);
  }

//+------------------------------------------------------------------+
#endif // __CHART_MINI_TILES_CLASS_MQH__

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

2.0 Пример советника (MiniChartsEA) для тестирования заголовка

2.1. Обзор и назначение советника

Данный советник является испытательным полигоном для класса CChartMiniTiles. Он создает экземпляр класса, инициализирует мини-диаграммы для нескольких символов и проверяет функциональность переключения, изменения размера и обновления перед интеграцией в более крупные проекты.

//+------------------------------------------------------------------+
//|                                                  MiniChartsEA.mq5|
//|          Dummy EA to test CChartMiniTiles (ChartMiniTilesClass)  |
//+------------------------------------------------------------------+
#property copyright "2025"
#property link      "https://www.mql5.com/ru/users/billionaire2024/seller"
#property version   "1.00"
#property description "Mini-charts EA using CChartMiniTiles class"

// --- Include the class header
#include <ChartMiniTiles.mqh>

2.2. Входные данные и глобальные переменные

В настоящем разделе определяются параметры и переменные состояния, которые управляют мини-диаграммами (список символов, размеры, поведение при обновлении).

//--- Inputs
input string MajorSymbols      = "EURUSD,GBPUSD,USDJPY,USDCHF,USDCAD,AUDUSD,NZDUSD"; 
input int    BarsWidth         = 20;   // bars used to estimate tile pixel width
input int    TileHeightPx      = 112;  // tile height in pixels
input int    HorizontalSpacing = 6;    // spacing between tiles
input int    UpdateInterval    = 1000; // ms timer update interval
input int    XOffset           = 10;   // left margin in pixels
input int    BottomOffset      = 40;   // distance from bottom in pixels
input int    ToggleButtonX     = 8;    // toggle button X
input int    ToggleButtonY     = 6;    // toggle button Y
input bool   DateScale         = false;// show date scale
input bool   PriceScale        = false;// show price scale
input int    ChartScale        = 2;    // chart zoom level

//--- object instance of our class
CChartMiniTiles tiles;

//--- internal state
int pixelWidth = 120;

2.3. Вспомогательные методы

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

//+------------------------------------------------------------------+
//| Helper: estimate pixel width from BarsWidth                      |
//+------------------------------------------------------------------+
int CalculateChartWidthFromBars(int barsWidth)
{
   int mainChartWidth = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   int visibleBars    = (int)ChartGetInteger(0, CHART_VISIBLE_BARS);

   if(visibleBars <= 0 || mainChartWidth <= 0)
      return MathMax(80, BarsWidth * 6); // fallback

   return MathMax(80, barsWidth * mainChartWidth / visibleBars);
}

2.4. Управление с помощью кнопки переключения

Обрабатывается объектом tiles (CChartMiniTiles). Сам советник устанавливает только начальное положение кнопки переключения.

// Inside OnInit we call:
tiles.SetToggleButtonPos(ToggleButtonX, ToggleButtonY);

2.5. Инициализация мини-диаграмм

На этом этапе создаются все мини-диаграммы с пользовательскими настройками.

//+------------------------------------------------------------------+
//| Expert initialization                                            |
//+------------------------------------------------------------------+
int OnInit()
{
   // compute pixel width from BarsWidth heuristic
   pixelWidth = CalculateChartWidthFromBars(BarsWidth);

   // set toggle button position
   tiles.SetToggleButtonPos(ToggleButtonX, ToggleButtonY);

   // initialize tiles
   bool ok = tiles.Init(MajorSymbols,
                        pixelWidth,
                        TileHeightPx,
                        XOffset,
                        BottomOffset,
                        HorizontalSpacing,
                        PERIOD_M1,
                        DateScale,
                        PriceScale,
                        ChartScale);

   if(!ok)
   {
      Print("MiniChartsEA: tiles.Init() failed. Check Experts log for symbol issues.");
      return(INIT_FAILED);
   }

   // start timer for adaptive updates
   EventSetMillisecondTimer(UpdateInterval);

   Print("MiniChartsEA initialized.");
   return(INIT_SUCCEEDED);
}

2.6. Обновления компоновки

Это гарантирует правильное изменение размера и положения мозаик при изменении графика или с течением времени.

//+------------------------------------------------------------------+
//| Timer: update layout                                             |
//+------------------------------------------------------------------+
void OnTimer()
{
   tiles.UpdateLayout();
}

2.7. Видимость и переключение

Здесь советник передает клики кнопки переключения классу и отслеживает изменения на графике для сохранения выравнивания.

//+------------------------------------------------------------------+
//| Chart events - forward to tiles                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   // Let tiles handle toggle button clicks
   if(tiles.HandleEvent(id, sparam))
      return;

   // If chart resized or layout changed, reflow tiles
   if(id == CHARTEVENT_CHART_CHANGE)
      tiles.UpdateLayout();
}

2.8. Очистка и обработка событий

Это обеспечивает чистое удаление объектов при остановке советника.

//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   EventKillTimer();
   tiles.Delete();
   Print("MiniChartsEA deinitialized.");
}

3.0 Первоначальное тестирование

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

Такая функциональность станет еще более ценной, как только этот класс будет интегрирован в советник News Headline EA, где множество компонентов создадут более сложную графическую среду. Возможность быстрого переключения мини-плиток обеспечит более чистое и удобное рабочее пространство.

Смотрите изображение ниже, на котором показано развертывание и вывод данных MiniChartsEA.

Testing the MiniChatTilesEA

Рисунок 1: Результаты тестирования MiniChartsEA на графике валютной пары EURUSD.

Теперь можем продолжить интеграцию класса CChartMiniTiles в советник News Headline EA. В следующем разделе мы подробно рассмотрим обновленный код, а затем рассмотрим результирующее поведение на графике.

4.0 Интеграция ChartsMiniTiles в советник News Headline EA

4.1. Включаем заголовок ChartMiniTiles — сделаем класс доступным для советника.

Для использования класса mini-tiles необходимо указать его заголовок в верхней части советника. Это переносит объявление класса и его реализацию в модуль компиляции EA, так что вы можете создать экземпляр и вызывать его методы. Размещение include с другими заголовками (TradingButtons, Canvas, Trade) позволяет упорядочить импорт и сигнализирует о зависимости будущим разработчикам. Если файл отсутствует в MQL5/Include/, компилятор пожалуется здесь, так что это самый первый шаг интеграции.

#include <TradingButtons.mqh>
#include <Trade\Trade.mqh>
#include <Canvas\Canvas.mqh>
#include <ChartMiniTiles.mqh>   // <-- CTM class include (make sure this file is in MQL5/Include/)

4.2. Объявим экземпляр CChartMiniTiles — создадим менеджер мозаики советника

Объявление глобальных фрагментов CChartMiniTiles дает всему советнику доступ к единому менеджеру мозаичных шаблонов. Этот экземпляр содержит состояние (созданные имена объектов, список символов, флаг видимости, зарезервированная максимальная высота) и предоставляет методы для инициализации, обновления компоновки, обработки событий и очистки. Объявление его среди других глобальных параметров упрощает управление его жизненным циклом в OnInit / OnTimer / OnChartEvent / OnDeinit.

//+------------------------------------------------------------------+
//| ChartMiniTiles instance (CTM)                                     |
//+------------------------------------------------------------------+
CChartMiniTiles tiles;   // class instance for mini tiles

4.3. Создадим список символов и оценим ширину мозаики в пикселях — подготовим исходные данные CMT

Перед вызовом tiles.Init вам потребуется строка символов, разделенных запятыми, и приемлемая ширина в пикселях для tiles. В данном разделе создаем ctmSymbols из вашего массива majorPairs[] с помощью функции JoinSymbolArray() и вычисляем pixelWidth, используя эвристику "от баров к пикселям", основанную на ширине основного графика и видимых барах. Выполнение этого при инициализации гарантирует, что размеры фрагментов будут адаптированы к текущей компоновке графика, а название брокерского символа будет определено с помощью FindBrokerSymbol внутри класса.

   // Build a comma-separated symbol list from majorPairs[] and initialize CTM.
   string ctmSymbols = JoinSymbolArray(majorPairs);
   // Estimate pixel width from Bars heuristic (simple fallback)
   int mainChartWidth = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   int visibleBars    = (int)ChartGetInteger(0, CHART_VISIBLE_BARS);
   int pixelWidth = 120;
   if(visibleBars > 0 && mainChartWidth > 0)
      pixelWidth = MathMax(80, CTM_TileWidthBars * mainChartWidth / visibleBars);

4.4. Установите переключатель и задайте его положение, чтобы пользовательский интерфейс был доступен.

Кнопка переключения - это пользовательский элемент управления для отображения / скрытия фрагментов. Намеренно расположив её чуть ниже торговой панели, вы гарантируете, что она не будет перекрывать важные элементы управления пользовательского интерфейса. После вычисления tradingPanelBottomY советник вызывает tiles.SetToggleButtonPos(toggleX, toggleY), чтобы указать классу, где создать кнопку. Это размещение выполняется перед инициализацией фрагментов, чтобы кнопка существовала и соответствовала логике зарезервированной области, приведенной ниже.

   // Place the CTM toggle button JUST BELOW the trading panel bottom
   int toggleX = 8;
   int toggleY = tradingPanelBottomY + 6; // +6 px margin so it doesn't touch trading controls
   tiles.SetToggleButtonPos(toggleX, toggleY);

 4.5. Зарезервируйте верхнюю часть пользовательского интерфейса для элементов управления торговлей — предотвратите их перекрытие.

Чтобы избежать наложения мини-тайлов на торговую панель и кнопку переключения, советник вычисляет значение topReserve и вызывает tiles.SetTopReservedHeight (topReserve). Класс tiles использует это значение, чтобы ограничить количество рядов, которые могут располагаться снизу вверх; это сохраняет верхнюю область для кнопок, холстов или других элементов пользовательского интерфейса. Резервирование верхнего пространства перед вызовом Init гарантирует, что при расчете компоновки оно будет непосредственно учтено.

   // Reserve the area above tiles so the trading UI remains free. We reserve up to the toggle bottom.
   int topReserve = toggleY + CMT_TOG_H + 4; // leave a few px extra
   tiles.SetTopReservedHeight(topReserve);

4.6. Инициализируйте тайлы — создайте объекты OBJ_CHART для каждого символа

Это основной вызов интеграции. Советник преобразует список разрешенных символов, рассчитанную ширину в пикселях, высоту фрагментов, смещения, интервалы, период графика и масштаб в tiles.Init(...). Класс разрешит имена для конкретного брокера, создаст объекты OBJ_CHART, задаст их свойства (символ, период, масштабы, размеры) и создаст кнопку переключения. Советник проверяет возврат логического значения (ctm_ok), чтобы корректно обработать ошибку инициализации (например, если по этому брокеру не были разрешены какие-либо символы).

   // Initialize tiles: (symbols, widthPx, heightPx, xOffset, bottomOffset, spacing, period, dateScale, priceScale, chartScale)
   bool ctm_ok = tiles.Init(ctmSymbols, pixelWidth, CTM_TileHeightPx, CTM_XOffset, CTM_BottomOffset, CTM_Spacing, PERIOD_M1, false, false, CTM_ChartScale);
   if(!ctm_ok)
   {
      Print("CTM: initialization failed (no matching symbols?); tiles disabled.");
   }

4.7. Поддерживайте адаптивность раскладки — вызывайте UpdateLayout при изменении графика или по таймеру

После инициализации советник должен сохранять фрагменты в нужном месте при изменении размера или компоновки графика. Интеграция охватывает три области:

  • Перенаправление событий изменения графика для изменения положения тайлов (таким образом, обрабатываются выполненные пользователем изменения размера или рабочей области).
  • Вызов tiles.UpdateLayout() периодически в цикле OnTimer для обработки динамических смещений пользовательского интерфейса или для восстановления после внешних изменений.
  • Вызов tiles.UpdateLayout() в конце основного цикла обработки OnTimer, чтобы CTM всегда обновлялся после других обновлений пользовательского интерфейса (холсты, новости, аналитические данные ИИ).

Ниже приведены точные фрагменты, используемые в вашем советнике для обработки таких случаев.

Перенаправление OnChartEvent и реакция на изменение графика:

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   // Let CTM handle object clicks first (toggle button)
   if(tiles.HandleEvent(id, sparam))
      return;

   // Forward to the TradingButtons header afterward
   buttonsEA.HandleChartEvent(id, sparam, majorPairs, pairSelected);

   // Also respond to chart change events for CTM layout
   if(id == CHARTEVENT_CHART_CHANGE)
      tiles.UpdateLayout();
}

Обновление End-of-OnTimer (синхронизирует CTM при каждом тике таймера):

   // Keep CTM updated every tick (timer-driven)
   tiles.UpdateLayout();
}

4.8. Очистка при деинициализации — удаление фрагментов и кнопки переключения

Когда советник останавливается или удаляется, он должен удалить все созданные им объекты. Вызов tiles.Delete() удаляет каждый OBJ_CHART и кнопку переключения, освобождает массивы и заново рисует график. Это заключительный шаг интеграции, который предотвращает появление на графике ненужных объектов.

   // delete CTM tiles and toggle button
   tiles.Delete();

Краткий контрольный список интеграции (резюме)

  1. #include <ChartMiniTiles.mqh> в верхней точке.
  2. Объявите фрагменты CChartMiniTiles; глобально.
  3. Создайте ctmSymbols и вычислите pixelWidth перед Init.
  4. Установите положение переключателя с помощью tiles.SetToggleButtonPos(...).
  5. Зарезервируйте верхнюю область пользовательского интерфейса с помощью tiles.SetTopReservedHeight(...).
  6. Инициализируйте с помощью tiles.Init(...) и проверьте return.
  7. Направьте OnChartEvent в tiles.HandleEvent(...) и вызовите tiles.UpdateLayout() после изменения графика и при периодических обновлениях.
  8. Вызовите tiles.Delete() в OnDeinit.


Тестирование и результаты

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

Рисунок 2: Использование советника News Headline EA на графике AUDUSD с мини-фрагментами графика для торговли несколькими символами

Multiple Feature News Headline EA

Рисунок 3: Работа ChartMiniTiles в советнике News Headline EA

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


Заключение

Мы успешно интегрировали класс, который управляет несколькими видами мини-графиков на одном основном графике, используя советник New Headline EA. Такой подход предоставляет трейдерам мощный инструмент для мониторинга и торговли несколькими инструментами одновременно, повышая эффективность, особенно в периоды высокой волатильности, такие как выход важных новостей. Когда открывается несколько позиций по разным парам, этот инструмент позволяет трейдерам управлять ими и отслеживать их из единого интерфейса, обеспечивая быстрый контроль и исполнение сделок.

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

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

Приглашаем вас высказать свои идеи и внести свой вклад в это обсуждение. Ниже прилагается исходный код и изображение, показывающее основной график вместе с настройками ChartMiniTiles.



Основные уроки

Основной урокОписание:
Управление несколькими инструментамиТрейдеры могут эффективно выбирать и отслеживать несколько торговых пар, не переключаясь между графиками.
Специальный класс для работы с несколькими графикамиИспользование отдельного класса для управления несколькими мини-графиками упрощает интеграцию и поддерживает модульный код.
Автономное тестирование перед интеграциейРазработка и проверка функции в отдельном тестовом советнике обеспечивает стабильность перед объединением с основным советником.
Настраиваемые компоновки мини-диаграммРазмер мини-диаграмм можно изменять и упорядочивать их в соответствии с предпочтениями пользователя, что улучшает видимость и рабочий процесс.
Визуализация нескольких инструментов в реальном времениОтображение нескольких инструментов на одном графике позволяет трейдерам быстрее реагировать на изменчивые рыночные условия.
Модульное программированиеРазделение функциональности на заголовки и классы повышает удобство обслуживания и повторного использования в разных проектах.
Поэтапная разработка функцийПостепенное добавление новых функций сокращает количество ошибок и обеспечивает плавную интеграцию с существующими системами.
Обработка событий в мини-диаграммахКаждая мини-диаграмма может реагировать на действия пользователя, обеспечивая интерактивный и динамический анализ.
Интеграция с основным советникомПосле тестирования класс mini chart объединяется с основным советником, чтобы обеспечить бесперебойную торговлю несколькими инструментами.
Повторно используемые служебные классыТакие классы, как CChartMiniTiles, служат модульными инструментами, которые могут быть адаптированы для других проектов и советников.
Эффективные методы ведения рабочего процессаИспользование структурированного рабочего процесса — создание прототипов, тестирование, интеграция — повышает скорость разработки и уменьшает количество ошибок.
Быстрая поддержка принятия решенийМини-диаграммы дают трейдерам консолидированное представление о нескольких рынках, помогая принимать более быстрые торговые решения.
Динамическое управление объектамиКод демонстрирует, как динамически создавать, обновлять и уничтожать объекты диаграммы для каждого мини-графика, что важно для масштабируемого дизайна советника.
Эффективное использование памятиУправляя мини-графиками как отдельными объектами и обновляя только видимые элементы, советник оптимизирует использование памяти и процессора.
Плавное распространение событийКласс mini chart показывает, как обрабатывать события диаграммы иерархическим образом, гарантируя, что события достигают нужного экземпляра диаграммы без конфликтов.


Вложения

Имя файлаВерсияОписание
ChartMiniTiles.mqh1.0Определяет класс CChartMiniTiles, отвечающий за управление и отображение нескольких видов мини-диаграмм в рамках одной основной диаграммы. Обеспечивает модульную многосимвольную визуализацию и возможности взаимодействия.
MiniChartsEA.mq51.0Фиктивный советник, созданный для самостоятельного тестирования класса CChartMiniTiles перед интеграцией в основной советник News Headline EA. Проверяет компоновку, изменение размера и обработку событий мини-диаграмм.
NewsHeadlineEA.mq51.14Основной советник, который объединяет в себе множество функций: визуализацию новостной ленты, автоматическую торговлю на основе событий календаря и торговлю несколькими символами с использованием мини-диаграмм.
TradingButtons.mqh1.0Предоставляет кнопки управления для совершения сделок, выбора пар и управления ордерами непосредственно с графика. Поддерживает быструю торговлю несколькими символами в советнике.
terminal64_Dp0JGQhX5.pngотсутствуетШирокий скриншот графика терминала, иллюстрирующий функцию ChartMiniTiles советника News Headline EA, демонстрирующую торговлю несколькими символами, мониторинг в режиме реального времени и быстрый визуальный анализ.

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

Прикрепленные файлы |
ChartMiniTiles.mqh (38.64 KB)
MiniChartsEA.mq5 (9.85 KB)
NewsHeadlineEA.mq5 (68.81 KB)
TradingButtons.mqh (38.59 KB)
Нейросети в трейдинге: Адаптивное восприятие рыночной динамики (Окончание) Нейросети в трейдинге: Адаптивное восприятие рыночной динамики (Окончание)
В статье продолжается работа над реализацией подходов фреймворка STE-FlowNet, который сочетает многопоточную обработку с рекуррентными структурами для точного анализа сложных данных. Проведенные тесты подтвердили его стабильность и гибкость в разных сценариях. Архитектура ускоряет вычисления и позволяет глубже моделировать зависимости во временных рядах. Такой подход открывает новые возможности для практического применения в трейдинге и аналитике.
Осваиваем JSON: Разработка пользовательского JSON-ридера с нуля на MQL5 Осваиваем JSON: Разработка пользовательского JSON-ридера с нуля на MQL5
В статье приведено пошаговое руководство по созданию пользовательского парсера JSON на языке MQL5, включающего обработку объектов и массивов, проверку ошибок и сериализацию. Вы сможет объединить торговую логику и структурированные данные с помощью гибкого решения для обработки JSON в MetaTrader 5.
Таблицы в парадигме MVC на MQL5: настраиваемые и сортируемые столбцы таблицы Таблицы в парадигме MVC на MQL5: настраиваемые и сортируемые столбцы таблицы
В статье сделаем изменяемую ширину столбцов таблицы при помощи курсора мышки, сортировку таблицы по данным столбцов, и добавим новый класс для упрощенного создания таблиц на основании любых наборов данных.
Самоорганизующиеся карты Кохонена в советнике MQL5 Самоорганизующиеся карты Кохонена в советнике MQL5
Самоорганизующиеся карты Кохонена превращают хаос рыночных данных в упорядоченную двумерную карту, где похожие паттерны группируются вместе. Эта статья показывает полную реализацию SOM в торговом советнике MQL5 с четырехстами нейронами и непрерывным обучением. Разбираем алгоритм поиска Best Matching Unit, обновление весов с гауссовой функцией соседства, интеграцию с квантовыми эффектами и создание торговых сигналов. Код открыт, математика понятна, результаты проверяемы.