English Deutsch 日本語
preview
От новичка до эксперта: Индикатор силы уровней поддержки и сопротивления (SRSI)

От новичка до эксперта: Индикатор силы уровней поддержки и сопротивления (SRSI)

MetaTrader 5Примеры |
805 6
Clemence Benjamin
Clemence Benjamin

Разделы


Введение

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

Кто-то может спросить, зачем нужна автоматизация. Хотя люди преуспевают в решении сложных творческих задач и адаптации к новым ситуациям, нам часто трудно обеспечить последовательность и обрабатывать большие объемы данных. Исследование Марка Анджело Д. Джулиана (Mark Angelo D. Julian), Данило Б. Вилларино (Danilo B. Villarino) и Кристин Т. Соберано (Kristine T. Soberano), опубликованное 7 июля 2024 года в статье «Человеческий мозг против компьютера: кто умнее?» ("The Human Brain Versus Computer: Which is Smarter?"), подчеркивает этот момент. Их исследование показывает, что, хотя люди и преуспевают в понимании контекста, компьютеры значительно превосходят их в скорости обработки, точности данных и выполнении повторяющихся вычислений. Этот контраст стимулирует нашу постоянную разработку алгоритмов для торговли и анализа данных.


Обзор обсуждения

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

Хотя на рынке уже доступно несколько инструментов — как бесплатных, так и платных, — сегодня мы исследуем уникальный подход. В ходе этой сессии мы не только обсудим конечный продукт, но и поделимся навыками программирования на языке MQL5, необходимыми для создания собственного пользовательского решения. Ниже приводится краткое описание преимуществ разрабатываемого нами индикатора силы уровней поддержки и сопротивления (SRSI):

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

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

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


Свидетельство современного характера рынка 

Моя платформа MetaTrader 5 подключена к брокерскому ресурсу Deriv.com, что обеспечивает мне доступ к широкому спектру торговых пар. В зависимости от типа аккаунта я могу торговать волатильными парами, валютными парами, фондовыми парами и многим другим. На представленном изображении продемонстрирован широкий выбор дополнительных пар, доступных для торговли. Для настоящего исследования с целью проведения анализа нами выбраны несколько пар из этой коллекции.

Чтобы просмотреть предлагаемые вашим брокером пары и добавить их в свой список обзор рынка, просто нажмите CTRL + U на клавиатуре или щелкните по красному округлому значку (как показано на рисунке ниже), чтобы открыть окно "Символы» (Symbols). Затем дважды щелкните нужную пару, чтобы автоматически добавить ее в свой список.

Символы

DerivSVG Символы MetaTrader 5

Синтетические пары

Я начал свой анализ с синтетической пары в соответствии с индексами волатильности — индекса волатильности 75 (1s) — на недельном таймфрейме. Когда эта пара была представлена примерно в 2020 году, она изначально была дорогой, но вскоре пережила продолжительный обвал, сформировав сильный нисходящий тренд на несколько недель. Трейдеры, в этот период игравшие на понижение пары, вероятно, получили значительную прибыль. Однако основное внимание я уделяю структуре рынка, особенно за последние три года.

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

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

Volatility 75(1s) index

Индекс волатильности 75 (1s)

Фондовая пара

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

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

     US Tech 100Weekly

Индекс US Tech 100 Weekly

Валютная пара

Недельный график EUR/USD показывает небольшую фазу импульса, за которой последовал продолжительный период колебаний. Такое поведение очевидно на старшем таймфрейме и распространяется также на младшие таймфреймы. Ключевым моментом здесь является привязанное к диапазону движение цены, подчеркивающее, как рынок тратит значительную часть времени на консолидацию, а не на движение в тренде. Изображение ниже служит доказательством такого длительного поведения рынка в определенном диапазоне.

EURUSDWeekly

Еженедельный анализ EURUSD

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

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

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


Реализация на MQL5 для разработки SRSI 

Определение уровней поддержки и сопротивления

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

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

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

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


Разработка и реализация алгоритма

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

  1. Определяем экстремальные поворотные моменты: Это значимые максимумы (сопротивление) или минимумы (поддержка), где цена меняет направление.
  2. Находим другие точки тестирования: Ищем дополнительные ценовые уровни, где цена равна или находится в пределах 5 пипсов от крайней точки разворота, подтверждая ее значимость.
  3. Формируем зоны отскока: Создаём прямоугольные зоны, охватывающие крайние поворотные точки и их контрольные точки, при этом зона расширяется вокруг этих точек касания.
  4. Настроим размеры зоны:

  • Высота: Вертикальный размер прямоугольника зоны (в пипсах) должен быть регулируемым.
  • Ширина: Горизонтальный размер зоны (в барах японских свечей справа) должен быть регулируемым.

Как правило, мы настраиваем нашу программу на сканирование определенного количества свечей, определяя условия, которые соответствуют нашим критериям, и рисуя соответствующие фигуры, линии и метки. Мы также предоставим возможности ввода для управления различными функциями программы. Для оповещений мы реализуем push-уведомления и оповещения на терминале, отправляя их периодически в течение настраиваемого 4-часового интервала. В отличие от других индикаторов, уровни поддержки и сопротивления не требуют постоянного мониторинга, поэтому такой подход обеспечивает своевременные уведомления без лишних оповещений. Ниже я пошагово объясню детали, приведя фрагменты кода.

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

//+------------------------------------------------------------------+
//|                                                        _SRSI.mq5 |
//|                                   Copyright 2025, Metaquotes Ltd |
//|                                            https://www.mql5.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Metaquotes Ltd"
#property link      "https://www.mql5.com/"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

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

Шаг 1: Пользовательская настройка свойств индикатора

Для начала настроим свойства индикатора, чтобы персонализировать его и соответствовать требованиям MetaTrader 5. Мы обновляем информацию об авторских правах и ссылках, чтобы она отражала нашу собственную информацию. Добавляем настройку для более строгой проверки ошибок, чтобы таким образом выявлять ошибки во время разработки. Индикатор настроен на отображение в главном окне графика. Поскольку для MetaTrader 5 требуется по крайней мере один буфер, определяем один скрытый «фиктивный» буфер, поскольку наш индикатор будет использовать пользовательские объекты (линии и прямоугольники), а не графически представленные данные буфера.

#property copyright "Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"
#property strict          // Enforces stricter error checking
#property indicator_chart_window
#property indicator_buffers 1  // MT5 requires at least one buffer
#property indicator_plots 1    // Ties to the buffer (even if unused for plotting)

Шаг 2: Добавление пользовательских входных данных

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

input int InpLookBack = 1000;        // Number of bars to analyze
input double InpTestProximity = 0.0007; // Price range for tests (e.g., 7 pips)
input int InpMinTests = 3;           // Minimum tests for strong levels
input bool InpShowRectangles = true; // Show zones as rectangles

Шаг 3: Создание фиктивного (думми) буфера

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

double DummyBuffer[];

Его использование:

int OnInit()
{
   SetIndexBuffer(0, DummyBuffer, INDICATOR_DATA);   // Bind buffer to index 0
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE); // Hide it from the chart
   return(INIT_SUCCEEDED);
}

Шаг 4: Определение структур данных

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

enum ENUM_LEVEL_TYPE {
   LEVEL_STRONG_SUPPORT,      // Strong support level
   LEVEL_STRONG_RESISTANCE,   // Strong resistance level
   LEVEL_WEAK_SUPPORT,        // Weak support level
   LEVEL_WEAK_RESISTANCE      // Weak resistance level
};

struct PriceLevel {
   double price;           // Price value of the level
   int test_count;         // Number of times price tested it
   ENUM_LEVEL_TYPE type;   // Strong or weak, support or resistance
   datetime time;          // Time the level was identified
};

struct Zone {
   double top;             // Top price of the zone
   double bottom;          // Bottom price of the zone
   datetime start_time;    // When the zone starts
   datetime end_time;      // When the zone ends (current time)
};

PriceLevel StrongLevels[];    // Array for strong levels
PriceLevel WeakLevels[];      // Array for weak levels
Zone Zones[];                 // Array for strong level zones
datetime LastAlertTime = 0;   // Tracks the last alert time

Шаг 5: Обнаружение точек колебания

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

bool IsSwingHigh(int index, const double &high[])
{
   int window = 5;  // Check 5 bars on each side
   for (int i = 1; i <= window; i++) {
      if (index - i < 0 || index + i >= ArraySize(high)) return false; // Out of bounds
      if (high[index] <= high[index - i] || high[index] <= high[index + i]) return false; // Not a peak
   }
   return true;
}

bool IsSwingLow(int index, const double &low[])
{
   int window = 5;  // Check 5 bars on each side
   for (int i = 1; i <= window; i++) {
      if (index - i < 0 || index + i >= ArraySize(low)) return false; // Out of bounds
      if (low[index] >= low[index - i] || low[index] >= low[index + i]) return false; // Not a trough
   }
   return true;

Шаг 6: Подсчет ценовых тестов

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

int CountLevelTests(double price, int start_index, const double &high[], const double &low[])
{
   int tests = 0;
   for (int i = start_index + 1; i < ArraySize(high); i++) {
      if (MathAbs(high[i] - price) <= InpTestProximity || MathAbs(low[i] - price) <= InpTestProximity) {
         tests++;
      }
   }
   return tests;

Шаг 7: Уровни обработки

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

void ProcessLevel(int index, double price, bool is_high, const double &high[], const double &low[], const datetime &time[])
{
   PriceLevel level;
   level.price = price;
   level.test_count = CountLevelTests(price, index, high, low);
   level.time = time[index];
   
   if (is_high) {
      level.type = (level.test_count >= InpMinTests) ? LEVEL_STRONG_RESISTANCE : LEVEL_WEAK_RESISTANCE;
   } else {
      level.type = (level.test_count >= InpMinTests) ? LEVEL_STRONG_SUPPORT : LEVEL_WEAK_SUPPORT;
   }
   
   if (level.test_count >= InpMinTests) {
      ArrayResize(StrongLevels, ArraySize(StrongLevels) + 1);
      StrongLevels[ArraySize(StrongLevels) - 1] = level;
      Zone zone;
      zone.start_time = time[index];
      zone.end_time = TimeCurrent();
      zone.top = price + InpTestProximity;
      zone.bottom = price - InpTestProximity;
      ArrayResize(Zones, ArraySize(Zones) + 1);
      Zones[ArraySize(Zones) - 1] = zone;
   } else {
      ArrayResize(WeakLevels, ArraySize(WeakLevels) + 1);
      WeakLevels[ArraySize(WeakLevels) - 1] = level;
   }

Шаг 8: Нанесение на диаграмму

Для отображения уровней мы используем две функции отрисовки. Одна рисует сильные уровни серым прямоугольником (если включено) для зоны и сплошной линией — синей для поддержки, красной для сопротивления — плюс метка («SS» или «SR»). Другая отображает слабые уровни пунктирной линией — светло-голубой для поддержки, розовой для сопротивления — и меткой («WS» или «WR»). Каждому объекту присваивается уникальное имя в зависимости от его времени, что обеспечивает надлежащее управление на диаграмме.

void RenderZone(const Zone &zone, const PriceLevel &level)
{
   string name = "Zone_" + TimeToString(zone.start_time);
   if (InpShowRectangles) {
      ObjectCreate(0, name, OBJ_RECTANGLE, 0, zone.start_time, zone.top, zone.end_time, zone.bottom);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clrLightGray);
      ObjectSetInteger(0, name, OBJPROP_FILL, true);
   }
   
   string line_name = "Line_" + TimeToString(level.time);
   ObjectCreate(0, line_name, OBJ_HLINE, 0, 0, level.price);
   ObjectSetInteger(0, line_name, OBJPROP_COLOR, (level.type == LEVEL_STRONG_SUPPORT) ? clrBlue : clrRed);
   ObjectSetString(0, line_name, OBJPROP_TEXT, (level.type == LEVEL_STRONG_SUPPORT) ? "SS" : "SR");
}

void RenderWeakLine(const PriceLevel &level)
{
   string name = "WeakLine_" + TimeToString(level.time);
   ObjectCreate(0, name, OBJ_HLINE, 0, 0, level.price);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
   ObjectSetInteger(0, name, OBJPROP_COLOR, (level.type == LEVEL_WEAK_SUPPORT) ? clrLightBlue : clrPink);
   ObjectSetString(0, name, OBJPROP_TEXT, (level.type == LEVEL_WEAK_SUPPORT) ? "WS" : "WR");

Шаг 9: Отправка оповещений

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

void SendPeriodicAlert(double current_price)
{
   if (TimeCurrent() - LastAlertTime < 3600) return; // Wait 1 hour between alerts
   if (ArraySize(StrongLevels) == 0) return;         // No strong levels, no alert
   
   PriceLevel latest = StrongLevels[ArraySize(StrongLevels) - 1];
   string message = "SRZones Alert: Strong " + 
                    ((latest.type == LEVEL_STRONG_SUPPORT) ? "Support" : "Resistance") + 
                    " at " + DoubleToString(latest.price, 5) + 
                    ", Current Price: " + DoubleToString(current_price, 5);
   Alert(message);
   LastAlertTime = TimeCurrent();
}

Шаг 10: Очистка старых рисунков

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

void ClearDisplayObjects()
{
   ObjectsDeleteAll(0, "Zone_");       // Delete all zones
   ObjectsDeleteAll(0, "Line_");       // Delete strong lines
   ObjectsDeleteAll(0, "WeakLine_");   // Delete weak lines
}

Шаг 11: Запуск логики в OnCalculate

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

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   if (prev_calculated == 0 || rates_total > prev_calculated) { // Full recalc on start or new bar
      ClearDisplayObjects();
      ArrayResize(StrongLevels, 0);
      ArrayResize(WeakLevels, 0);
      ArrayResize(Zones, 0);
      
      int start = MathMax(5, rates_total - InpLookBack); // Start within lookback period
      for (int i = start; i < rates_total - 5; i++) {    // Leave room for swing checks
         if (IsSwingHigh(i, high)) ProcessLevel(i, high[i], true, high, low, time);
         if (IsSwingLow(i, low)) ProcessLevel(i, low[i], false, high, low, time);
      }
      
      for (int i = 0; i < ArraySize(StrongLevels); i++) {
         RenderZone(Zones[i], StrongLevels[i]);
      }
      for (int i = 0; i < ArraySize(WeakLevels); i++) {
         RenderWeakLine(WeakLevels[i]);
      }
      
      SendPeriodicAlert(close[rates_total - 1]);
   }
   return(rates_total); // Tell MT5 how many bars were processed
}

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


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

Первым шагом было запустить индикатор и добавить его на диаграмму с настройками по умолчанию, используя EURUSD в качестве референса. Для корректного отображения индикатора на других валютных парах могут потребоваться первоначальные настройки, в частности, значение пипса. Например, при тестировании индекса волатильности 75 (1s) никаких зон не появлялось, пока я не настроил значение пипса на 70.

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

Adding SRSI to chart

Добавление индикатора силы уровней поддержки и сопротивления (SRSI) на диаграмму.

Customizing the SRSI

Пользовательская настройка параметров SRSI

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

2025.03.10 07:44:42.548 _SRSI (EURUSD,M15)      Alert: Key Level: SR at 1.08715 | Current Price: 1.09021
2025.03.10 07:54:04.239 _SRSI (EURUSD,M15)      Alert: Key Level: SR at 1.08715 | Current Price: 1.09033
2025.03.10 07:55:04.965 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09044
2025.03.10 09:25:13.506 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09210
2025.03.10 11:26:46.761 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09192

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

Alerts

Окно оповещений терминала: работа индикатора SRSI


Заключение 

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

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

Надеюсь, эта дискуссия оказалась для вас содержательной. До новых встреч — счастливого программирования и успешной торговли, коллеги-разработчики!


Приложение (исходный файл SRSI) 

Файл Описание
_SRSI.mq5 Индикатор силы уровней поддержки и сопротивления, который динамически рисует регулируемые прямоугольные зоны, четко обозначая сильную поддержку (SS) и сильное сопротивление (SR). Кроме того, он рисует пунктирные линии, указывающие на более слабые уровни поддержки (WS) и сопротивления (WR) для лучшей визуализации.

К содержанию

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

Прикрепленные файлы |
_SRSI.mq5 (29.97 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (6)
Clemence Benjamin
Clemence Benjamin | 20 мар. 2025 в 18:13
Darz #:
Мне очень понравилась ваша статья, я попробовал ее на FX парах, которые, кажется, хорошо работают... Как насчет индексов, таких как US30? Какие настройки вы рекомендуете? Я пробовал установить текстовую близость на 0.035 и результаты кажутся забавными.
Привет, @Darz, мой хороший друг. Спасибо за ваш ответ!
Я заметил, что для US Tech и других синтетических пар требуется гораздо большее значение близости из-за их более высокой стоимости пункта. Мне пришлось установить значение 10, прежде чем на US Tech начали появляться зоны сопротивления - см. изображение ниже.
Я рекомендую поэкспериментировать с этим значением, пока вы не найдете оптимальную настройку для ваших конкретных пар.

Спасибо!


Anil Varma
Anil Varma | 21 мар. 2025 в 08:53
Clemence Benjamin #:
Привет, @Darz, мой хороший друг. Спасибо за твой ответ!
Я заметил, что для US Tech и других синтетических пар требуется гораздо большее значение приближения из-за их более высокой стоимости пункта. Мне пришлось установить значение 10, прежде чем на US Tech начали появляться зоны сопротивления - см. изображение ниже.
Я рекомендую поэкспериментировать с этим значением, пока вы не найдете оптимальную настройку для ваших конкретных пар.

Спасибо!


Здравствуйте, друг

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

Я попробовал 21-периодный ATR-мультипликатор, как показано ниже:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1)); // (n*getATR(index) заменен на ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1)); // (n*getATR(index) заменен на ...InpMinWeakDistance;

Это помогло мне получить SRZones для пар EURUSD и XAUUSD с довольно большой разницей в значениях 1.08000 - 3000.00.

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

Clemence Benjamin
Clemence Benjamin | 25 мар. 2025 в 22:09
Anil Varma #:

Здравствуй, друг

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

Я попробовал 21-периодный ATR, как показано ниже:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1)); // (n*getATR(index) заменен на ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1))); // (n*getATR(index) заменен на ...InpMinWeakDistance;

Это помогло мне получить SRZones для пар EURUSD и XAUUSD с довольно большой разницей в значениях 1.08000 - 3000.00.

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

Привет, мой хороший друг @Anil Varma.

Спасибо, что поделились этим уникальным подходом! Я обязательно попробую.

Evgeny Fedorenko
Evgeny Fedorenko | 9 июн. 2025 в 14:44
Anil Varma #:

Здравствуй, друг

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

Я попробовал 21-периодный ATR, как показано ниже:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1)); // (n*getATR(index) заменен на ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1))); // (n*getATR(index) заменен на ...InpMinWeakDistance;

Это помогло мне получить SRZones для пар EURUSD и XAUUSD с довольно большой разницей в значениях 1.08000 - 3000.00.

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

Здравствуйте
Не могли бы вы поделиться своей версией индикатора ATR?
Anil Varma
Anil Varma | 18 июн. 2025 в 10:25
Evgeny Fedorenko #:
Здравствуйте
Не могли бы вы поделиться своей версией индикатора ATR?

Здравствуйте @Evgeny Fedorenko

Во-первых, извините, что отвечаю слишком поздно, на самом деле я отвлекся на курс Quant Financial Modeling.

Во-вторых, я не создавал никакого индикатора для себя, просто попробовал код индикатора Клеменса Бенджамина с твиком, предложенным в моем посте.

Надеюсь, это вам поможет.

Разработка инструментария для анализа движения цен (Часть 4): Советник Analytics Forecaster Разработка инструментария для анализа движения цен (Часть 4): Советник Analytics Forecaster
Мы выходим за рамки простого просмотра проанализированных показателей на графиках и переходим к более широкой перспективе, которая включает интеграцию с Telegram. Это позволит отправлять важные результаты непосредственно на мобильное устройство через Telegram.
WebSocket для MetaTrader 5 — Асинхронные клиентские соединения с помощью Windows API WebSocket для MetaTrader 5 — Асинхронные клиентские соединения с помощью Windows API
В данной статье подробно описывается разработка пользовательской динамически подключаемой библиотеки, предназначенной для упрощения асинхронных клиентских соединений по протоколу WebSocket для программ MetaTrader.
Нейросети в трейдинге: Сквозная многомерная модель прогнозирования временных рядов (Окончание) Нейросети в трейдинге: Сквозная многомерная модель прогнозирования временных рядов (Окончание)
Представляем вашему вниманию заключительную часть цикла, посвящённого GinAR — нейросетевому фреймворку для прогнозирования временных рядов. В этой статье мы анализируем результаты тестирования модели на новых данных и оцениваем её устойчивость в условиях реального рынка.
Трейдинг с экономическим календарем MQL5 (Часть 4): Обновление новостей в панели управления в реальном времени Трейдинг с экономическим календарем MQL5 (Часть 4): Обновление новостей в панели управления в реальном времени
В этой статье мы расширим возможности нашей панели экономического календаря, внедрив обновления новостей в реальном времени для поддержания актуальности рыночной информации. Мы интегрируем методы извлечения данных в реальном времени в MQL5 для непрерывного обновления событий на панели управления и повышения отзывчивости интерфейса. Это обновление обеспечивает нам доступ к последним экономическим новостям непосредственно с панели управления, оптимизируя торговые решения на основе самых свежих данных.