English Deutsch 日本語
preview
От новичка до эксперта: Анимированный советник News Headline с использованием MQL5 (XI) - Корреляция при торговле на новостях

От новичка до эксперта: Анимированный советник News Headline с использованием MQL5 (XI) - Корреляция при торговле на новостях

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

Содержание:


Введение

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

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

Именно здесь концепция корреляции приобретает решающее значение. Оценивая взаимосвязи между парами, трейдеры могут совершенствовать свои стратегии, избегать чрезмерного риска и даже применять такие методы, как стратегия "лидер–последователь" ("догоняющий"), когда движение одного инструмента помогает предсказать движение другого.

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



Изучение финансовой корреляции

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

Что касается советника News Headline EA, то понимание корреляции превращает его из простого исполнителя сделок в сложного стратегического менеджера.

Коэффициент корреляции: Ключевой показатель

Взаимосвязь выражается коэффициентом корреляции, который колеблется от -1 до +1.

  • +1 (Идеальная положительная корреляция): Две пары движутся в идеальном ритме. Если пара A повышается на 1%, то пара B повышается на 1%. Если пара A падает, то и пара B падает одинаково. (например, два почти идентичных ETF, отслеживающих один и тот же индекс).
  • 0 (Корреляция отсутствует): Между движениями этих двух пар нет заметной взаимосвязи. Они абсолютно независимы.
  • -1 (Идеальная отрицательная корреляция): Эти две пары движутся совершенно противоположно. Если пара A растет на 1%, пара B падает на 1%. (например, классическое хеджирование, такое как акция и опцион "пут" на эту акцию).

На самом деле большинство корреляций находятся где-то между этими крайними значениями (например, +0,85, -0,30).

Почему корреляция нестатична и зависит от контекста

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

Зависимость от таймфрейма: Корреляция между EUR/USD и GBP/USD на 1-минутном графике во время выхода новостей может сильно отличаться от их корреляции на дневном графике. Ваш советник должен рассчитать корреляцию за короткий, релевантный период ретроспективы (например, 15-30 минут) для торговли на новостях.

  1. Изменение режима: Крупные экономические сдвиги (например, изменение политики центрального банка) могут изменить давние корреляции.
  2. Напряжённость рыночной конъюнктуры: Во время "бегства в безопасное место" или паники на рынке (например, во время кризиса 2008 года) корреляции могут неожиданно сойтись до +1 или -1. Диверсификация терпит неудачу, потому что все движется вместе — либо вверх, либо вниз. Это идеальный тест для управления рисками вашего советника.

Расчет корреляции для советника News Headline EA

Наиболее распространенным методом является определение коэффициента корреляции Пирсона. Наш советник рассчитал бы его автоматически на основе процентной доходности или изменения цен на два актива (A и B) за определенное количество периодов (N).

Его формула:

Calculating Correlation

Где:

  • 𝑟_A = доходность актива A
  • 𝑟_B = доходность актива B
  • Cov(𝑟_A.r_B) = ковариация между двумя сериями доходов  
  • 𝜎_A = стандартное отклонение доходности актива А
  • 𝜎_B = стандартное отклонение доходности актива B

Практическая реализация:

  • Данные: У нашего советника уже есть ценовые данные по всем выбранным парам.
  • Функция: Закодируем функцию, которая возвращает коэффициент.
  • Ретроспективный анализ: Для торговли на новостях периоды будут небольшими (например, 50-100 баров на 1-минутном или 5-минутном графике).


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

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

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

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

Шаг 1: Расширение CTradingButtons для корреляции

1.1. Конструктивные особенности и назначение

Начинаем с небольшого набора параметров по умолчанию во время компиляции, которые управляют вычислениями корреляции: длина окна (сколько выборок возврата мы используем), максимальный лаг (на сколько баров мы сдвигаем одну серию относительно другой, чтобы найти соотношение опережения и запаздывания) и пороговое значение, определяющее, считается ли корреляция достаточно сильной, чтобы отметить её как “коррелированная”. Эти простые константы упрощают настройку кода в зависимости от скорости отклика и чувствительности к шуму (короткие окна реагируют быстрее, но более шумные; длинные окна работают более плавно).

// ---------------- Correlation defaults & utilities (merged) -------
#define CORR_WINDOW    40     // samples used for correlation window (returns)
#define CORR_MAX_LAG    3     // maximum lag (in bars) to test for cross-correlation
#define CORR_THRESHOLD 0.60   // threshold for "correlated" marker

1.2. Получение рядов доходности (как мы преобразуем цены в сопоставимые данные)

Корреляция рассчитывается на основе "доходности" (относительных изменений цен), а не исходных цен, чтобы избежать влияния уровней и придать формуле Пирсона смысл для инструментов с разным масштабом цен. Функция FetchReturns копирует последние цены закрытия для запрашиваемого инструмента и таймфрейма, преобразуя их в простой процент доходности. 

Где:

  • R_t это доход в момент времени t
  • 𝑃_t это текущая цена закрытия
  • 𝑃_t−1 это предыдущая цена закрытия
  • Δ𝑃_𝑡 = 𝑃_𝑡 − 𝑃_𝑡−1 , и возвращает массив самых последних возвращаемых доходов (самые последние - сначала). Она также резервирует дополнительные бары для тестирования лага. Если данных недостаточно, происходит корректный сбой.

// Fetch recent returns for `symbol` on timeframe `tf`.
// Returns number of return samples placed into `ret[]` (most recent first).
int FetchReturns(const string symbol, const ENUM_TIMEFRAMES tf, const int samples, const int maxLag, double &ret[])
{
   if(StringLen(symbol) == 0 || samples <= 0) return 0;
   int need = samples + MathMax(0, maxLag) + 5;
   if(need <= 1) return 0;

   double closes[];
   ArrayResize(closes, need);
   int copied = CopyClose(symbol, tf, 0, need, closes);
   if(copied <= 1) return 0;

   int available = copied - 1; // returns available
   int use = MathMin(samples, available - MathMax(0, maxLag));
   if(use <= 0) return 0;

   ArrayResize(ret, use);
   for(int i = 0; i < use; i++)
   {
      double older = closes[i+1];
      double newer = closes[i];
      if(older == 0.0) ret[i] = 0.0;
      else ret[i] = (newer - older) / older;
   }
   return use;
}

1.3. Вычисление корреляции Пирсона по двум массивам дохода (математическое объяснение)

Как только у нас будут два выровненных массива дохода длиной n, мы вычислим коэффициент корреляции Пирсона r. Знакомая формула такова

Где:

  • r - коэффициент корреляции Пирсона (единичное число от -1 до +1, измеряющее линейную связь).
  • x_i - это i-е наблюдение серии x (в нашем советнике это i-е значение для символа X, например, a[i]).
  • y_i - это i-е наблюдение серии y (i-е значение для символа Y, например, b[i]).
  • x (бар x) - это среднее значение ряда x: x = (1/n) Σ x_i
  • y (бар y) - это среднее значение ряда y: ȳ = (1/n) Σ y_i

Эта функция реализует это численно: она вычисляет средние значения, затем ковариацию и дисперсии и, наконец, делит на квадратный корень из произведения дисперсий. Она возвращает 0 для вырожденных случаев. Поскольку ранее мы вычисляли доходность в виде простых процентных изменений, результат не зависит от масштаба (сопоставим по инструментам).
// Compute Pearson correlation from two return arrays of length n
double ComputePearsonFromReturns(const double &a[], const double &b[], const int n)
{
   if(n <= 1) return 0.0;
   double meanA = 0.0, meanB = 0.0;
   for(int i = 0; i < n; i++) { meanA += a[i]; meanB += b[i]; }
   meanA /= n; meanB /= n;

   double cov = 0.0, varA = 0.0, varB = 0.0;
   for(int i = 0; i < n; i++)
   {
      double da = a[i] - meanA;
      double db = b[i] - meanB;
      cov += da * db;
      varA += da * da;
      varB += db * db;
   }

   if(varA <= 0.0 || varB <= 0.0) return 0.0;
   double r = cov / MathSqrt(varA * varB);
   if(r > 1.0) r = 1.0;
   if(r < -1.0) r = -1.0;
   return r;
}

1.4. Поиск максимальной взаимной корреляции между лагами (определение лидера/последователя)

Основное усовершенствование заключается в поиске наиболее сильной корреляции между текущим инструментом графика и каждым потенциальным инструментом с учетом небольших задержек. Для каждого кандидата мы сдвигаем один ряд доходности по отношению к другому через лаги от −maxLag до +maxLag и вычисляем корреляцию Пирсона r для каждого сдвига. Сохраняем значение r с максимальным абсолютным значением (peakCorr) и соответствующим лагом. Положительный лаг указывает на то, что кандидат отстает от текущего символа; отрицательный лаг указывает на то, что кандидат лидирует по текущему символу. Именно так советник может порекомендовать лидера. Функция возвращает значения peakCorr и lagAtPeak, или false, если данных недостаточно.
// Compute cross-correlation peak and lag between currSym and otherSym.
// Outputs peakCorr and lagAtPeak (int).
bool ComputeCrossCorrPeak(const string currSym, const string otherSym, const ENUM_TIMEFRAMES tf, const int window, const int maxLag, double &peakCorr, int &lagAtPeak)
{
   if(StringLen(currSym) == 0 || StringLen(otherSym) == 0 || window <= 1) return(false);

   double rCurr[], rOther[];
   int nCurr = FetchReturns(currSym, tf, window, maxLag, rCurr);
   int nOther = FetchReturns(otherSym, tf, window, maxLag, rOther);
   if(nCurr == 0 || nOther == 0) return(false);

   int available = MathMin(nCurr, nOther);
   if(available < window) return(false);

   bool found = false;
   peakCorr = 0.0;
   lagAtPeak = 0;

   for(int lag = -maxLag; lag <= maxLag; lag++)
   {
      int startCurr = 0;
      int startOther = lag;
      if(startOther < 0) { startCurr = -startOther; startOther = 0; }

      int maxSamples = available - MathMax(startCurr, startOther);
      if(maxSamples < window) continue;

      double a[], b[];
      ArrayResize(a, window);
      ArrayResize(b, window);
      for(int i = 0; i < window; i++)
      {
         a[i] = rCurr[startCurr + i];
         b[i] = rOther[startOther + i];
      }

      double r = ComputePearsonFromReturns(a, b, window);

      if(!found || MathAbs(r) > MathAbs(peakCorr))
      {
         peakCorr = r;
         lagAtPeak = lag;
         found = true;
      }
   }

   return(found);
}

1.5. Маркеры рендеринга — функции painter (визуальная обратная связь)

Чтобы отобразить результаты корреляции, не загромождая существующие метки символов, вы добавили минимум маркеров: компактную метку с цветной точкой и числовым значением корреляции. DrawCorrelationMarker создает график OBJ_LABEL с заданными координатами, устанавливает цвет на зеленый (коррелированный) или красный (некоррелированный) и записывает короткий текст типа "● 0.72". Это позволяет сохранить пользовательский интерфейс компактным и удобочитаемым. Аналогичная небольшая функция DrawRecommendation записывает предложение "Рекомендуемый лидер"; DrawCorrelationTitle помещает статический заголовок "Корреляция" над областью маркера. Эти три функции являются простыми обертками для управления объектами, которые обеспечивают согласованность рисования и централизуют выбор z-порядка и шрифта.
// Draw a small correlation marker near (x,y) — dot + numeric value only (no symbol text).
void DrawCorrelationMarker(const string objName, const int x, const int y, const double corr, const bool correlated)
{
   if(StringLen(objName) == 0) return;
   long chart = ChartID();
   if(ObjectFind(chart, objName) == -1)
      ObjectCreate(chart, objName, OBJ_LABEL, 0, 0, 0);

   ObjectSetInteger(chart, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(chart, objName, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(chart, objName, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(chart, objName, OBJPROP_FONTSIZE, 10);
   int col = correlated ? clrLime : clrRed;
   ObjectSetInteger(chart, objName, OBJPROP_COLOR, col);
   ObjectSetInteger(chart, objName, OBJPROP_SELECTABLE, 0);
   ObjectSetInteger(chart, objName, OBJPROP_ZORDER, 20);

   // Show a small dot and the numeric correlation (2 decimals). Example: "● 0.72"
   string text = StringFormat("● %.2f", corr);
   ObjectSetString(chart, objName, OBJPROP_TEXT, text);
}

// Draw recommendation label (top-left of panel area)
void DrawRecommendation(const string objName, const int x, const int y, const string text)
{
   if(StringLen(objName) == 0) return;
   long chart = ChartID();
   if(ObjectFind(chart, objName) == -1)
      ObjectCreate(chart, objName, OBJ_LABEL, 0, 0, 0);

   ObjectSetInteger(chart, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(chart, objName, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(chart, objName, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(chart, objName, OBJPROP_FONTSIZE, 10);
   ObjectSetInteger(chart, objName, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(chart, objName, OBJPROP_SELECTABLE, 0);
   ObjectSetInteger(chart, objName, OBJPROP_ZORDER, 21);
   ObjectSetString(chart, objName, OBJPROP_TEXT, text);
}

// Draw static "Correlation" title above correlation area
void DrawCorrelationTitle(const string objName, const int x, const int y)
{
   if(StringLen(objName) == 0) return;
   long chart = ChartID();
   if(ObjectFind(chart, objName) == -1)
      ObjectCreate(chart, objName, OBJ_LABEL, 0, 0, 0);

   ObjectSetInteger(chart, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(chart, objName, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(chart, objName, OBJPROP_YDISTANCE, y);
   ObjectSetInteger(chart, objName, OBJPROP_FONTSIZE, 11);
   ObjectSetInteger(chart, objName, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(chart, objName, OBJPROP_SELECTABLE, 0);
   ObjectSetInteger(chart, objName, OBJPROP_ZORDER, 22);
   ObjectSetString(chart, objName, OBJPROP_TEXT, "Correlation");
}

1.6. Где настройки корреляции и состояние пользовательского интерфейса находятся внутри класса trading-button

Для аккуратной интеграции параметры корреляции и координаты для каждого флажка сохраняются как элементы класса CTradingButtons. Конструктор устанавливает разумные значения по умолчанию, поэтому советник может просто создать торговую панель и получить готовую корреляцию. Ключевыми элементами являются m_corr_window, m_corr_maxlag, m_corr_threshold, смещения по вертикали/горизонтали (чтобы можно было перемещать точки) и массивы m_check_x/m_check_y, которые запоминают положение флажков в пикселях. Это локализованное состояние упрощает UpdateCorrelationMarkersInternal и позволяет избежать дисперсии состояния корреляции по всему советнику.
      // initialize correlation defaults here (cannot initialize at declaration)
      m_corr_marker_prefix = "CorrMarker_";
      m_corr_rec_name      = "Corr_Recommendation";
      m_corr_title_name    = "Corr_Title";
      m_corr_tf            = PERIOD_M1;
      m_corr_window        = CORR_WINDOW;
      m_corr_maxlag        = CORR_MAX_LAG;
      m_corr_threshold     = CORR_THRESHOLD;

      // vertical offsets (push correlation UI down a bit)
      m_corr_rec_y_offset    = 24; // recommendation label y-distance in pixels (tweak)
      m_corr_marker_v_offset = 8;  // marker offset relative to checkbox top (tweak)

      // horizontal offset default (shift markers slightly right)
      m_corr_marker_h_offset = 6;  // default shift to the right by 6 pixels (tweak as needed)

      ArrayResize(m_check_x, 0);
      ArrayResize(m_check_y, 0);

1.7. Открытый контроль: предоставьте советнику доступ к настройкам времени выполнения

Два небольших метода позволяют советнику настраивать корреляцию во время выполнения: SetCorrelationParams для изменения таймфрейма/окна/максимального лага/порогового значения и SetCorrelationMarkerHorizontalOffset, чтобы пользователь советника мог изменять положение маркеров для разных размеров экрана или ширины флажка. Оба вызывают (или будут вызывать) внутреннюю процедуру обновления, чтобы немедленно перерисовать маркеры. Такое разделение упрощает настройки пользовательского интерфейса.
   // Configure correlation evaluation (optional runtime tuning)
   void SetCorrelationParams(const int timeframe, const int window, const int maxlag, const double threshold)
   {
      m_corr_tf = timeframe;
      m_corr_window = MathMax(1, window);
      m_corr_maxlag = MathMax(0, maxlag);
      m_corr_threshold = MathMax(0.0, MathMin(1.0, threshold));
      PrintFormat("SetCorrelationParams: tf=%d window=%d maxlag=%d thresh=%.2f", m_corr_tf, m_corr_window, m_corr_maxlag, m_corr_threshold);
   }

   // Exposed update so EA can refresh markers (public wrapper)
   void UpdateCorrelationMarkers()
   {
      UpdateCorrelationMarkersInternal();
   }

   // Public setter for horizontal offset of correlation markers
   void SetCorrelationMarkerHorizontalOffset(const int px)
   {
      m_corr_marker_h_offset = px;
      UpdateCorrelationMarkersInternal();
   }

1.8. Отрисовка по каждому флажку: DrawCorrelationForIndex (где каждый маркер вычисляется и наносится)

Для каждой найденной пары вычисляем пик корреляции с текущим инструментом на графике и решаем, соответствует ли он пороговому значению. Координаты считываются из сохраненных значений m_check_x/m_check_y (полученных при создании флажков или путем запроса объекта checkbox), затем помещаем точку и цифровой текст в это положение пикселя (с настраиваемыми смещениями по горизонтали и вертикали). Функция вызывает ComputeCrossCorrPeak и DrawCorrelationMarker, разделяя обязанности.
   void DrawCorrelationForIndex(const int idx)
   {
      if(idx < 0 || idx >= ArraySize(availablePairs)) return;
      string sym = availablePairs[idx];
      if(StringLen(sym) == 0) return;
      if(idx >= ArraySize(m_check_x) || idx >= ArraySize(m_check_y)) return;

      int x = m_check_x[idx];
      int y = m_check_y[idx];
      if(x < 0 || y < 0) return;

      // move marker slightly to the right with configurable horizontal offset
      int markerX = MathMax(2, x - 18 + m_corr_marker_h_offset);
      int markerY = y + m_corr_marker_v_offset; // configurable vertical offset

      double peakCorr = 0.0;
      int lag = 0;
      bool ok = ComputeCrossCorrPeak(Symbol(), sym, (ENUM_TIMEFRAMES)m_corr_tf, m_corr_window, m_corr_maxlag, peakCorr, lag);
      if(!ok) peakCorr = 0.0;
      bool correlated = (MathAbs(peakCorr) >= m_corr_threshold);

      string objName = m_corr_marker_prefix + sym;
      DrawCorrelationMarker(objName, markerX, markerY, peakCorr, correlated);
   }

1.9. Организация функционирования: UpdateCorrelationMarkersInternal (выбор лидера + перерисовка)

Это центральная функция, которая выполняет перебор по разрешенным парам, гарантирует, что у нас есть пиксельные координаты для флажков, рисует каждый маркер, а затем вычисляет наилучшего кандидата в лидеры, выбирая символ с наибольшей абсолютной корреляцией пиков, который также указывает на лидерство с отрицательным лагом (вы можете настроить свое правило лидера). Функция записывает короткую, понятную для пользователя строку “Recommended leader: … r=lag=…” с помощью DrawRecommendation и рисует заголовок "Correlation" над областью. Это функция, которую вы вызываете всякий раз, когда меняются флажки или компоновка экрана. 

   void UpdateCorrelationMarkersInternal()
   {
      int n = ArraySize(availablePairs);
      if(n == 0) return;

      for(int i = 0; i < n; i++)
      {
         if(StringLen(availablePairs[i]) == 0) continue;

         if(i >= ArraySize(m_check_x) || i >= ArraySize(m_check_y) || m_check_x[i] < 0 || m_check_y[i] < 0)
         {
            string chkName = "Chk_" + availablePairs[i];
            if(ObjectFind(ChartID(), chkName) >= 0)
            {
               int y = (int)ObjectGetInteger(ChartID(), chkName, OBJPROP_YDISTANCE);
               int x = (int)ObjectGetInteger(ChartID(), chkName, OBJPROP_XDISTANCE);
               if(ArraySize(m_check_x) < n) ArrayResize(m_check_x, n);
               if(ArraySize(m_check_y) < n) ArrayResize(m_check_y, n);
               m_check_x[i] = x;
               m_check_y[i] = y;
            }
            else
               continue;
         }

         DrawCorrelationForIndex(i);
      }

      double bestCorr = 0.0;
      string bestSym = "";
      int bestLag = 0;
      for(int j = 0; j < n; j++)
      {
         if(StringLen(availablePairs[j]) == 0) continue;
         double p = 0.0; int l = 0;
         bool ok = ComputeCrossCorrPeak(Symbol(), availablePairs[j], (ENUM_TIMEFRAMES)m_corr_tf, m_corr_window, m_corr_maxlag, p, l);
         if(!ok) continue;
         if(l < 0 && MathAbs(p) > MathAbs(bestCorr))
         {
            bestCorr = p;
            bestSym = availablePairs[j];
            bestLag = l;
         }
      }

      int recX = checkStartX;
      int recY = m_corr_rec_y_offset; // configurable vertical offset for recommendation
      string recText;
      if(bestSym != "")
         recText = StringFormat("Recommended leader: %s  r=%.2f lag=%d", bestSym, bestCorr, bestLag);
      else
         recText = "No clear leader detected";

      // Draw title above the recommendation/markers area
      DrawCorrelationTitle(m_corr_title_name, recX, MathMax(2, recY - 18));
      DrawRecommendation(m_corr_rec_name, recX, recY, recText);
   }

1.10. Очистка: DeleteCorrelationMarkers (аккуратное удаление объектов)

Когда заголовок/пользовательский интерфейс удаляется (Deinit), мы удаляем все объекты корреляционной метки вместе с заголовком и рекомендательной меткой, чтобы график вернулся к своему состоянию до появления советника. Это предотвращает появление ненужных меток при удалении советника или панели кнопок.
   void DeleteCorrelationMarkers()
   {
      for(int i = 0; i < ArraySize(availablePairs); i++)
      {
         if(StringLen(availablePairs[i]) == 0) continue;
         string obj = m_corr_marker_prefix + availablePairs[i];
         if(ObjectFind(ChartID(), obj) >= 0) ObjectDelete(ChartID(), obj);
      }
      if(ObjectFind(ChartID(), m_corr_rec_name) >= 0) ObjectDelete(ChartID(), m_corr_rec_name);
      if(ObjectFind(ChartID(), m_corr_title_name) >= 0) ObjectDelete(ChartID(), m_corr_title_name);
   }

Где и когда запускается пользовательский интерфейс корреляции (точки интеграции)

Чтобы синхронизировать расположение флажков и взаимодействие с пользователем, вызываем UpdateCorrelationMarkersInternal после создания флажков (чтобы были установлены начальные маркеры) и снова, когда флажок переключается с помощью HandleChartEvent. Вот два узла вызова (CreatePairCheckboxes завершается вызовом UpdateCorrelationMarkersInternal; HandleChartEvent вызывает UpdateCorrelationMarkersInternal при изменении флажка).
      // end of CreatePairCheckboxes()
      // inside HandleChartEvent() when checkbox clicked:
      UpdateCorrelationMarkersInternal();

Шаг 2: Интеграция Correlation в советник

2.1. Заголовок включает в себя — сделать доступным корреляционный API.

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

#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/)

2.2. Пользовательские данные для корреляции — предоставляют трейдеру возможность настройки.

Укажите временные рамки, окно, максимальный лаг и пороговое значение, чтобы пользователи могли настроить, насколько чувствительным / стабильным должно быть обнаружение корреляции. Они считываются в OnInit() и передаются в заголовок.

// Correlation tuning exposed to EA
input group "Correlation (TradingButtons)"
input int CorrTimeframe = PERIOD_M1;
input int CorrWindow = 40;
input int CorrMaxLag = 3;
input double CorrThreshold = 0.60;

2.3. Создать парный пользовательский интерфейс (флажки) — точки привязки для корреляционных маркеров

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

// Create pair checkboxes aligned below the canvas lanes:
int checkboxY = InpTopOffset + (InpSeparateLanes ? 8 : 28) * lineH + 6; // same as before
buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);

2.4. Передайте параметры корреляции и принудительно выполните начальный рисунок

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

// Set correlation params in TradingButtons
buttonsEA.SetCorrelationParams(CorrTimeframe, CorrWindow, CorrMaxLag, CorrThreshold);

// Force initial correlation markers
buttonsEA.UpdateCorrelationMarkers();

2.5. Перенаправление событий и обработка изменений в компоновке

Перенаправляйте события графика в заголовок, чтобы там обрабатывались щелчки флажков и взаимодействия с пользовательским интерфейсом. Также реагируйте на изменения компоновки графика (CHARTEVENT_CHART_CHANGE), меняя местами как mini-tiles, так и маркеры корреляции, чтобы сохранить позиции корректными.

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   // Let the tiles class handle object clicks (toggle button). If handled, stop processing.
   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();
      buttonsEA.UpdateCorrelationMarkers();
   }
}

2.6. Обновление по таймеру — поддержание актуальности корреляционных маркеров

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

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

// Keep correlation markers fresh — call the header's public updater
buttonsEA.UpdateCorrelationMarkers();

2.7. Очистка—деинициализация заголовка удаляет объекты корреляции

Когда советник остановится, вызовите функцию Deinit/cleanup заголовка, чтобы из заголовка можно было удалить все объекты корреляционных маркеров, рекомендательную метку и название. На уровне советника вы вызываете buttonsEA.Deinit(). Внутренне заголовок должен удалять каждый маркер — пример функции очистки заголовка:

void OnDeinit(const int reason)
{
   EventKillTimer();
   buttonsEA.Deinit();

   // ... other UI destruction ...

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


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

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

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

Testing Correlation in News Headline EA

Рисунок 1: Тестирование корреляции на GPBAUD с помощью обновленного советника News Headline EA

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


Заключение

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

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

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

Using Correlation to filter pairs for trading.

Рисунок 2: Использование корреляции для принятия решения, какими парами торговать одновременно.

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


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

Урок Описание:
Целенаправленная интеграция Корреляцию следует рассматривать как информирующую о торговых решениях функцию, а не как самостоятельный сигнал. Интеграция корреляции в пользовательский интерфейс и рабочий процесс (флажки, маркеры, рекомендации) позволяет использовать статистическую информацию при торговле несколькими инструментами, ориентируясь на новости.
Работа с доходностью, а не с сырыми ценами Вычисляет корреляцию доходности от периода к периоду (относительные изменения цен), чтобы сравнение между инструментами проводилось без масштабирования. Использование доходности позволяет избежать эффекта уровня и делает корреляцию Пирсона значимой для инструментов с разными ценовыми диапазонами.
Реализация корреляции Пирсона Применяет коэффициент Пирсона с осторожностью: вычисляет среднее значение, ковариацию (сумму парных отклонений) и нормализуйте по произведению стандартных отклонений. Следит за нулевой дисперсией, чтобы избежать ошибок при делении на ноль.
Компромисс длины окна Сознательно выбирает длину окна корреляции: короткие окна реагируют быстро, но с шумом; длинные окна работают плавнее, но медленнее. Указывает окно в качестве параметра времени выполнения, чтобы пользователи могли настраивать скорость отклика и стабильность.
Определение лага и соотношения лидер–последователь Тестирует небольшие положительные и отрицательные лаги при вычислении взаимной корреляции, чтобы определить ведущие инструменты. Отставание от максимальной абсолютной корреляции указывает на то, опережает ли другая пара текущий график или отстает от него, что позволяет рекомендовать лидера.
Пороговое значение для принятия решений Применяет настраиваемое пороговое значение, чтобы решить, когда помечать пару как “коррелируемую”. Это предотвращает чрезмерную маркировку и позволяет трейдерам контролировать чувствительность (типичные пороговые значения варьируются от 0,5 до 0,8 в зависимости от допуска ложных положительных срабатываний).
Компактная, ненавязчивая визуализация Отображает корреляцию в виде маленькой цветной точки плюс числовое значение рядом с существующими метками инструментов и добавьте краткое название, например “Correlation”. Компактные маркеры передают информацию, не загромождая график и не препятствуя элементам управления торговлей.
Маркеры привязки к элементам пользовательского интерфейса Располагает маркеры корреляции относительно существующих привязок пользовательского интерфейса (например, флажков инструментов), чтобы маркеры оставались выровненными при изменении размеров графика и панели. Обновляет позиции всякий раз, когда происходят изменения в компоновке.
Использует корреляцию для уменьшения воздействия Использует корреляцию для отсеивания избыточных пар при открытии многопарных позиций. Исключает совершение однонаправленных сделок по сильно коррелированным парам, чтобы снизить совокупный риск во время важных событий.
Открытая настройка времени выполнения Делает таймфрейм, окно, максимальный лаг и пороговое значение доступными в качестве входных данных. Возможность трейдерам настраивать их во время выполнения повышает гибкость и помогает адаптировать алгоритм к различным рыночным режимам и предпочтениям пользователей.
Обновление и производительность по таймеру Повторно вычисляет и перерисовывает корреляционные маркеры по управляемому таймеру, чтобы поддерживать текущие значения при ограничении использования центрального процессора и API. Балансирует частоту обновления с затратами на вычисления, чтобы пользовательский интерфейс был своевременным, но не требовал больших ресурсов.
Корректно обрабатывает отсутствующие или искаженные данные Выявляет недостаточную историю или ряды с нулевой дисперсией и пропускает или помечает такие пары консервативно. Возврат безопасных настроек по умолчанию вместо сбоев обеспечивает надежность советника во всех брокерских компаниях и списках инструментов.
Очистка объектов при деинициализации Удаляет все маркеры корреляции, названия и рекомендательные метки во время Deinit, чтобы избежать появления ненужных объектов на графике. Надлежащая очистка обеспечивает аккуратный график после удаления или перезагрузки советника.
Модульный и основанный на заголовках дизайн Инкапсулирует логику корреляции и отрисовку внутри многоразового заголовка / класса (например, расширяя утилиту trading-button). Это позволяет сфокусировать код советника, упростить тестирование и обеспечивает повторное использование его в разных проектах.
Предпочтение тестирования живых графиков в отношении функций в режиме реального времени Тестирует корреляцию и взаимодействие пользовательского интерфейса на живом графике, а не в тестере стратегий, поскольку корреляция зависит от динамики тиков в реальном времени и интерактивного размещения пользовательского интерфейса, которые тестировщик не может полностью воспроизвести.

Вложения

В таблице ниже перечислены исходные файлы, которые были обновлены для добавления возможности корреляции. В каждом ряду указано имя файла, текущая версия файла (если применимо) и краткое описание того, что изменилось — с акцентом на расчеты корреляции, обновления маркеров/пользовательского интерфейса, общедоступные API-хуки и точки интеграции с основным советником.
Имя файла Версия Описание
TradingButtons.mqh 1.01  Заголовок торгового интерфейса расширен за счет включения утилит корреляции. Добавляет расчеты взаимной корреляции по методу Пирсона и с лагом, настраиваемые параметры (таймфрейм, окно, максимальный лаг, пороговое значение) и эффективные обновления по таймеру.

Визуальные изменения включают в себя компактные маркеры корреляции (цветная точка + числовое значение), заголовок “Correlation” над блоком, корректировку размещения (сдвинут немного ниже и смещен вправо), а также удаление повторяющегося текста символов, чтобы рядом с существующими метками отображались только точки и значения.

Предоставляет общедоступные функции API для советника: SetCorrelationParams, UpdateCorrelationMarkers, CreatePairCheckboxes, HandleChartEvent и Deinit (cleanup). Обрабатывает вырожденные данные и очищает все созданные объекты при деинициализации.
NewsHeadlineEA.mq5 1.15 Основной советник, объединяющий календарь, новости, аналитику с помощью ИИ, пользовательский интерфейс TradingButtons и тайлы мини-графиков. Обновлено для передачи входных данных о корреляции в заголовок TradingButtons, вызова UpdateCorrelationMarkers при инициализации, таймера и событий изменения графика, а также позиционирования пользовательского интерфейса корреляции, чтобы избежать дублирования с элементами управления торговлей и CTM.

Также интегрирует ChartMiniTiles для многосимвольных мини-графиков и резервирует верхнюю область для торгового пользовательского интерфейса. Обеспечивает плавную очистку корреляционных маркеров и тацлов CTM при deinit.
ChartMiniTiles.mqh 1.0 Многоразовый класс тайлов мини-графиков для встраивания графиков с несколькими инструментами в основной график. 

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

Прикрепленные файлы |
TradingButtons.mqh (94.86 KB)
NewsHeadlineEA.mq5 (70.54 KB)
ChartMiniTiles.mqh (38.65 KB)
Нейросети в трейдинге: Модели многократного уточнения прогнозов (RAFT) Нейросети в трейдинге: Модели многократного уточнения прогнозов (RAFT)
Фреймворк RAFT предлагает принципиально иной подход к прогнозированию динамики рынка — не как разовый снимок, а как итеративное уточнение состояния в реальном времени. Он одновременно учитывает локальные и глобальные изменения, сохраняя высокую точность даже при сложных ценовых структурах.
Таблицы в парадигме MVC на MQL5: настраиваемые и сортируемые столбцы таблицы Таблицы в парадигме MVC на MQL5: настраиваемые и сортируемые столбцы таблицы
В статье сделаем изменяемую ширину столбцов таблицы при помощи курсора мышки, сортировку таблицы по данным столбцов, и добавим новый класс для упрощенного создания таблиц на основании любых наборов данных.
Алгоритм кристаллической структуры — Crystal Structure Algorithm (CryStAl) Алгоритм кристаллической структуры — Crystal Structure Algorithm (CryStAl)
В статье представлены две версии Алгоритма кристаллической структуры, оригинальная и модифицированная. Алгоритм Crystal Structure Algorithm (CryStAl), опубликованный в 2021 году и вдохновленный физикой кристаллических структур, позиционировался как parameter-free метаэвристика для глобальной оптимизации. Однако тестирование выявило критическую проблему алгоритма. Представлена также модифицированная версия CryStAlm, которая исправляет ключевые недостатки оригинала.
Нейросети в трейдинге: Адаптивное восприятие рыночной динамики (Окончание) Нейросети в трейдинге: Адаптивное восприятие рыночной динамики (Окончание)
В статье продолжается работа над реализацией подходов фреймворка STE-FlowNet, который сочетает многопоточную обработку с рекуррентными структурами для точного анализа сложных данных. Проведенные тесты подтвердили его стабильность и гибкость в разных сценариях. Архитектура ускоряет вычисления и позволяет глубже моделировать зависимости во временных рядах. Такой подход открывает новые возможности для практического применения в трейдинге и аналитике.