English Deutsch 日本語
preview
Разработка инструментария для анализа Price Action (Часть 45): Создание динамической панели для анализа уровней в MQL5

Разработка инструментария для анализа Price Action (Часть 45): Создание динамической панели для анализа уровней в MQL5

MetaTrader 5Примеры |
267 0
Christian Benjamin
Christian Benjamin

Содержание



Введение

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

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

В этой статье мы развиваем эту идею дальше и представляем советник Price Level Testing EA – автоматизированный аналитический инструмент, который позволяет тестировать любой ценовой уровень по запросу и сразу получать объективную обратную связь о том, как цена реагировала на него на протяжении сотен и тысяч предыдущих баров. По сути это ваша личная "лаборатория Price Action". Вы задаете уровень, советник проводит тестирование на исторических данных, и в результате программа выдает эмпирическую картину касаний, отскоков и пробоев, которые в прошлом формировали эту зону.



Почему важна статистическая проверка

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

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

Без тестирования на исторических данных нарисованный вручную уровень остается лишь мнением. Советник Price Level Testing EA дает то, чего здесь не хватает, – доказательства. Он превращает визуальные впечатления в измеримые данные:

  • Когда этот уровень действительно выступал барьером?
  • Как часто цена просто проходила через него?
  • С какой стороны – сверху или снизу – цена подходила к нему чаще?  

Две ключевые проблемы, которые решает советник

Проблема 1 – Догадки при оценке силы уровня

Похоже на сильное сопротивление... по крайней мере, мне так кажется.

  • Типичная ситуация у трейдера:

Вы видите, как EURUSD дважды отскакивает от зоны 1.2000 в течение нескольких недель. Все выглядит убедительно – длинные верхние тени, сильные продажи, четко читаемый паттерн. Вы отмечаете 1.2000 как сильное сопротивление и планируете следующие сделки с учетом этого уровня. Через несколько недель цена снова начинает медленно подниматься к 1.2000. Вы начинаете сомневаться:  "Удержится ли уровень на этот раз? Действительно ли 1.2000 настолько силен, или в прошлый раз мне просто повезло, что цена развернулась именно там?

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

Как советник решает эту проблему:

Введите 1.2000 в поле на информационной панели и нажмите Analyze. Через несколько секунд советник просканирует историю и покажет:

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

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

Проблема 2 – Ошибочная оценка направления рынка и надежности пробоя

"Цена только что пробила уровень – это настоящий пробой или просто рыночный шум?"

  • Типичная ситуация:

Представьте, что XAUUSD (золото) торгуется в районе 1950.00. Выше этого уровня формируется резкая свеча; на рынке нарастает ажиотаж – "бычий пробой!" – и трейдеры активно входят в рынок. Через два часа свеча резко разворачивается, цена снова уходит ниже 1950, и повсюду срабатывают стоп-лоссы. Был ли это настоящий импульс или ложный пробой, типичный для волатильного золота?

Если бы вы заранее проверили, как статистически вел себя уровень 1950, у вас уже был бы ответ.

Как советник решает эту проблему:

Введите 1950.00, нажмите Analyze, и инструмент мгновенно соберет историческую статистику:

  • сколько бычьих пробоев выше 1950 переходили в дальнейший рост;
  • сколько ложных пробоев быстро заканчивались разворотом;
  • сколько раз уровень 1950 выступал магнитом (цена часто взаимодействовала с ним), а сколько – барьером (цена резко от него отскакивала).

Имея эти метрики, вы сразу видите, чаще ли 1950 притягивает цену или отталкивает ее. Это превращает неопределенность в измеримую вероятностную оценку – именно такое понимание системно помогает и дисциплинированным трейдерам, и алгоритмическим системам.

Пример: Ручной анализ уровня 1.34244 (GBP/USD H1, с апреля по октябрь 2025 года)

В течение показанного ниже периода советник Price Level Testing EA зафиксировал несколько взаимодействий цены с уровнем 1.34244 на графике GBP/USD H1. Цена несколько раз подходила к уровню и касалась его в пределах заданного допуска, однако подтвержденного пробоя выше порога не происходило. После каждой такой попытки следовал разворот вниз, что указывает на устойчивую защиту этой зоны со стороны продавцов.  

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

С 30 сентября по 9 октября 2025 года рынок несколько сессий торговался выше области 1.34244 и использовал ее как промежуточную поддержку.  Цена неоднократно ретестировала эту область сверху и сначала удерживалась над ней, демонстрируя краткосрочную устойчивость. Однако по мере развития этого участка давление покупателей слабело, и затем произошел уверенный пробой ниже 1.34244.  Свечи начали закрываться ниже уровня, после чего последовало явное продолжение вниз.  Это подтвердило, что поддержка была сломлена и затем сменила роль: когда цена позднее попыталась ретестировать уровень, он уже выступал новой зоной сопротивления.

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

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


От интуиции к подтвержденным данным

У каждого трейдера со временем появляется интуиция относительно уровней, которые, как кажется, притягивают цену или отталкивают ее. Такие представления основаны на опыте, но одной интуиции часто недостаточно для подтверждения. Советник Price Level Testing EA переводит эту интуицию в формализованный вид.  Он превращает впечатление трейдера – "этот уровень важен" – в проверяемые количественные данные.

На первый взгляд советник кажется обманчиво простым. Вы вводите ценовой уровень, нажимаете Analyze, и программа просматривает недавнюю историю. За этой простотой стоит полноценный аналитический механизм, который измеряет, как цена взаимодействовала с уровнем на протяжении сотен баров. Через несколько секунд программа выдает четыре конкретных результата:

  • количество бычьих и медвежьих касаний – как часто цена тестировала уровень с каждой стороны;
  • количество подтвержденных пробоев – сколько раз цена уверенно проходила через уровень;
  • вероятности, отражающие направление этих событий;
  • сводная оценка направленности, по которой уровень классифицируется как Support, Resistance или Neutral.

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

Объективная классификация событий

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

1. Определение касания

Касание – это контролируемая проверка уровня: цена подходит к нему, касается его, но не закрывается далеко за его пределами. Чтобы отфильтровать случайный ценовой шум, советник задает допустимый допуск TouchPips в пипсах вокруг выбранного уровня. Если для какого-либо бара

High ≥ Level − (TouchPips × pip)  AND  Low ≤ Level + (TouchPips × pip)

программа регистрирует такой бар как касание. Затем направление определяется по цене закрытия:

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

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

2. Подтверждение пробоя

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

Бычий пробой: предыдущий бар закрылся ниже уровня, а текущий – достаточно выше него (более чем на BreakPips пипсов).

PrevClose<LevelANDClose>Level+(BreakPips×pip)

Медвежий пробой: предыдущий бар закрылся выше уровня, а текущий – достаточно ниже него (более чем на BreakPips пипсов).

PrevClose>LevelANDClose<Level−(BreakPips×pip)

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

От количественных показателей к эмпирическим вероятностям

После проверки всех баров в BarsToCheck советник сводит результат к четырем базовым счетчикам:

Тип событияБычьеМедвежье
Касаниеbull_touch
bear_touch
Пробойbull_break
bear_break

Эти подсчеты преобразуются в эмпирические вероятности – прямое отражение частоты событий в выбранной исторической выборке.

Эмпирические вероятности:

  • Вероятность бычьего касания

  • Вероятность медвежьего касания


Это не прогнозы и не теоретические значения; это фактическое поведение рынка в выбранном окне анализа.

Наконец, определяется общая направленность уровня:

  • Если доминируют и вероятность бычьего касания, и вероятность бычьего пробоя, уровень в основном выступал как Support (Bullish).
  • Если доминируют оба медвежьих показателя, уровень выступал как Resistance (Bearish).
  • Если ни одна сторона не дает убедительного сигнала, уровень считается нейтральным (Neutral).

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



Реализация на MQL5

1. Начинаем с метаданных и входных параметров

В начале скрипта задаем метаданные советника. Сюда входят название советника ("Price Level Testing EA"), сведения об авторских правах и ссылка на профиль автора в MQL5. Эти строки не влияют на работу советника, но помогают идентифицировать его, а также его автора. Затем с помощью директивы #property задаем номер версии, ссылку на авторские права и строгий режим компиляции. Строгий режим помогает писать более безопасный и надежный код, потому что включает строгую проверку типов.

#property copyright "https://www.mql5.com/ru/users/lynnchris"
#property version   "1.0"
#property strict

input int    BarsToCheck = 500;
input double TouchPips   = 10;
input double BreakPips   = 20;
input color  TextColor   = clrYellow;

Далее определяем входные параметры, чтобы пользователь мог настроить поведение советника. Мы задаем, сколько исторических баров нужно анализировать (BarsToCheck), насколько близко цена должна подойти к уровню, чтобы это считалось "касанием" (TouchPips), и насколько далеко она должна выйти за уровень, чтобы это считалось "пробоем" (BreakPips). Также пользователь может выбрать цвет текста вывода (TextColor). Эти входные параметры делают анализ гибче и позволяют адаптировать работу советника к разным символам, таймфреймам и торговым стратегиям.

2. Константы интерфейса и структура размещения элементов

Далее задаем несколько констант с помощью директив #define. Эти константы помогают управлять элементами интерфейса, которые позже будут выведены на график. Присваивая каждому объекту уникальное имя или префикс – например, EDIT_NAME для текстового поля, BTN_NAME для кнопки анализа и MARK_PREFIX для маркеров, – мы можем легко ссылаться на эти объекты и управлять ими во всем скрипте. Это особенно полезно, когда объекты нужно динамически обновлять или удалять.

#define EDIT_NAME    "UI_EDIT_LEVEL"
#define BTN_NAME     "UI_BTN_ANALYZE"
#define BOX_NAME     "UI_BOX"
#define HDR_NAME     "UI_HDR"
#define INSTR_NAME   "UI_INSTR"
#define MARK_PREFIX  "AN_"
#define LINE_PREFIX  "UI_LINE_"

#define UI_CORNER    CORNER_LEFT_UPPER
int ui_base_x = 6;
int ui_base_y = 18;
int ui_row_spacing = 17;
int ui_font_size = 9;

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

3. Создание интерфейса в OnInit()

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

SafeDeleteObj(EDIT_NAME);
ObjectCreate(0, EDIT_NAME, OBJ_EDIT, 0, 0, 0);
ObjectSetInteger(0, EDIT_NAME, OBJPROP_CORNER, UI_CORNER);
ObjectSetInteger(0, EDIT_NAME, OBJPROP_XDISTANCE, ui_base_x);
ObjectSetInteger(0, EDIT_NAME, OBJPROP_YDISTANCE, ui_base_y);
ObjectSetInteger(0, EDIT_NAME, OBJPROP_XSIZE, 100);
ObjectSetInteger(0, EDIT_NAME, OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, EDIT_NAME, OBJPROP_COLOR, clrLime);
ObjectSetInteger(0, EDIT_NAME, OBJPROP_FONTSIZE, ui_font_size);
ObjectSetString(0, EDIT_NAME, OBJPROP_TEXT, "1.2000");

Затем рядом с полем ввода размещаем кнопку "Analyze". Клик по этой кнопке запускает анализ. Положение кнопки задаем с помощью ранее определенных констант размещения, чтобы выровнять ее с полем ввода. Затем добавляем метку-подсказку с текстом "Press Analyze" и размещаем ее сразу справа от кнопки. Наконец, добавляем заголовок "Touch & Breakout Stats", чтобы сразу обозначить назначение всего интерфейса. К моменту завершения OnInit() интерфейс уже собран: он прост, интерактивен и позволяет начать анализ за несколько кликов.

4. Очистка с помощью OnDeinit()

После настройки интерфейса нужно предусмотреть и очистку. Функция OnDeinit() вызывается при удалении советника с графика или его повторной загрузке. На этом этапе удаляются все объекты, созданные советником, чтобы график оставался чистым и не захламленным. Для этого вызываем DeletePrefixObjects() с нужными префиксами и удаляем все маркеры и метки, созданные во время анализа.

void OnDeinit(const int reason)
{
   DeletePrefixObjects(MARK_PREFIX);
   DeletePrefixObjects(LINE_PREFIX);
   SafeDeleteObj(EDIT_NAME);
   SafeDeleteObj(BTN_NAME);
   SafeDeleteObj(BOX_NAME);
   SafeDeleteObj(HDR_NAME);
   SafeDeleteObj(INSTR_NAME);
}

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

5. Обработка действий пользователя в OnChartEvent()

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

void OnChartEvent(const int id,const long &l,const double &d,const string &s)
{
   if(id==CHARTEVENT_OBJECT_CLICK && s==BTN_NAME)
   {
      string textlevel = ObjectGetString(0, EDIT_NAME, OBJPROP_TEXT);
      double level = StringToDouble(textlevel);
      if(level <= 0)
      {
         Alert("Enter numeric level");
         return;
      }
      DeletePrefixObjects(MARK_PREFIX);
      DeletePrefixObjects(LINE_PREFIX);
      RunAnalysis(level);
   }
}

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

6. Подготовка к анализу в RunAnalysis()

Внутри функции RunAnalysis() сначала подготавливаем все нужные переменные и пороговые значения. На основе количества знаков текущего символа рассчитываем значение пипса, чтобы точно задать пороги для "касания" и "пробоя". Затем определяем, сколько баров можно безопасно проанализировать, чтобы не выйти за пределы доступной истории.

double point = SymbolInfoDouble(_Symbol,SYMBOL_POINT);
double pip   = (SymbolInfoInteger(_Symbol,SYMBOL_DIGITS) > 3 ? 0.0001 : 0.01);
double touch_th = TouchPips * pip;
double break_th = BreakPips * pip;

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

7. Поиск событий в исторических барах

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

for(int i=0; i<bars_to_check; i++)
{
   double hi = iHigh(_Symbol,_Period,i);
   double lo = iLow(_Symbol,_Period,i);
   double cl = iClose(_Symbol,_Period,i);
   double prev = iClose(_Symbol,_Period,i+1);
   datetime t = iTime(_Symbol,_Period,i);

   if(hi >= level - touch_th && lo <= level + touch_th)
   {
      if(cl < level)
         bull_touch++, DrawMarker(MARK_PREFIX+"T_BU_"+string(i), t, level + 5*point, clrLime, 241);
      else if(cl > level)
         bear_touch++, DrawMarker(MARK_PREFIX+"T_BE_"+string(i), t, level - 5*point, clrRed, 242);
   }

   if(prev < level && cl > level + break_th)
      bull_break++, DrawMarker(MARK_PREFIX+"B_BU_"+string(i), t, cl + 10*point, clrLime, 217);
   if(prev > level && cl < level - break_th)
      bear_break++, DrawMarker(MARK_PREFIX+"B_BE_"+string(i), t, cl - 10*point, clrRed, 218);
}

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

8. Расчет статистики и определение общей направленности

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

double tot_touch = (double)(bull_touch + bear_touch);
double tot_break = (double)(bull_break + bear_break);
double pBT = (tot_touch > 0.0 ? 100.0 * bull_touch / tot_touch : 0.0);
double pRT = (tot_touch > 0.0 ? 100.0 * bear_touch / tot_touch : 0.0);
double pBB = (tot_break > 0.0 ? 100.0 * bull_break / tot_break : 0.0);
double pRB = (tot_break > 0.0 ? 100.0 * bear_break / tot_break : 0.0);

string bias = "Neutral";
if(pBT > pRT && pBB > pRB)
   bias = "Support (Bullish)";
else if(pRT > pBT && pRB > pBB)
   bias = "Resistance (Bearish)";

По преобладанию бычьей или медвежьей активности определяется общая направленность. Если доминируют бычьи касания и пробои, уровень получает метку "Support (Bullish)". Если доминируют медвежьи события, уровень получает метку "Resistance (Bearish)". Если явного преобладания нет, уровень классифицируется как "Neutral". Так трейдер может быстро понять, будет ли уровень, скорее, выступать поддержкой или сопротивлением.

9. Формирование панели результатов

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

ArrayResize(lines, 7);
lines[0] = StringFormat("Symbol: %s    TF: %s", _Symbol, EnumToString(_Period));
lines[1] = StringFormat("Level: %.*f    Bars Checked: %d", (int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS), level, bars_to_check);
lines[2] = " ";
lines[3] = StringFormat("Touches  ↑ %3d   ↓ %3d    P↑ %4.1f%%   P↓ %4.1f%%", bull_touch, bear_touch, pBT, pRT);
lines[4] = StringFormat("Breaks   ↑ %3d   ↓ %3d    P↑ %4.1f%%   P↓ %4.1f%%", bull_break, bear_break, pBB, pRB);
lines[5] = " ";
lines[6] = StringFormat("Overall Bias: %s", bias);

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

10. Отрисовка результатов на графике

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

ObjectCreate(0, BOX_NAME, OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, BOX_NAME, OBJPROP_XDISTANCE, baseX - 6);
ObjectSetInteger(0, BOX_NAME, OBJPROP_YDISTANCE, baseY - 8);
ObjectSetInteger(0, BOX_NAME, OBJPROP_XSIZE, boxWidth + 12);
ObjectSetInteger(0, BOX_NAME, OBJPROP_YSIZE, boxHeight + 12);
ObjectSetInteger(0, BOX_NAME, OBJPROP_BGCOLOR, clrDarkSlateGray);

for(int i=0; i<7; i++)
{
   string nm = LINE_PREFIX + IntegerToString(i);
   ObjectCreate(0, nm, OBJ_LABEL, 0, 0, 0);
   ObjectSetString(0, nm, OBJPROP_TEXT, lines[i]);
}

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

11. Вывод отчета в терминал

Помимо вывода результатов на график, полный отчет также выводится в терминал через Print(). Так пользователь может просмотреть результаты анализа во вкладках "Эксперты" или "Журнал" в MetaTrader. Кроме того, так сохраняется постоянная запись в журнале, которая удобна для отслеживания, отладки и анализа нескольких уровней во времени. Благодаря и визуальному, и текстовому выводу учитываются разные предпочтения пользователей, а сама информация не теряется.

string report = "";
for(int i=0; i<ArraySize(lines); i++)
{
   report += lines[i];
   if(i < ArraySize(lines)-1) report += "\n";
}
Print(report);

12. Отрисовка маркеров с помощью DrawMarker()

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

void DrawMarker(string name, datetime t, double price, color clr, int arrow)
{
   if(ObjectFind(0, name) >= 0)
      ObjectDelete(0, name);
   ObjectCreate(0, name, OBJ_ARROW, 0, t, price);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_ARROWCODE, arrow);
}

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

13. Безопасное удаление объектов с помощью SafeDeleteObj()

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

void SafeDeleteObj(string name)
{
   if(ObjectFind(0, name) >= 0)
      ObjectDelete(0, name);
}

14. Удаление объектов по префиксу с помощью DeletePrefixObjects()

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

void DeletePrefixObjects(string prefix)
{
   int total = ObjectsTotal(0);
   for(int i = total - 1; i >= 0; i--)
   {
      string nm = ObjectName(0, i);
      if(StringFind(nm, prefix) == 0)
         ObjectDelete(0, nm);
   }
}



Результаты

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

1. Введите в поле ввода точное числовое значение цены, например:

  • 1.2000 для EURUSD;
  • 1950.25 для золота;
  • 80.50 для индекса.

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

2. Затем нажмите Analyze.

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

3. Что вы увидите на информационной панели:

  • общее количество касаний;
  • общее количество пробоев;
  • распределение по направлению (вверх/вниз);
  • общая направленность.

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

  • Тестирование на паре EURUSD с периодом H1

Анимация выше показывает, как работает советник Price Level Testing EA. В этой демонстрации в поле ввода интерфейса советника на графике вручную вводится конкретный ценовой уровень. После клика по кнопке "Analyze" сразу запускается процедура тестирования уровня. Через мгновение выбранный уровень оценивается на исторических данных, а результаты автоматически выводятся на информационную панель. Одновременно на графике появляются стрелки, отмечающие каждое касание (реакцию цены у уровня) и каждый пробой (уверенное движение через него). Эти визуальные маркеры позволяют пользователю проверить каждое статистическое событие непосредственно по самому ценовому движению.

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


Заключение

Советник Price Level Testing EA устраняет разрыв между визуальной интуицией и количественной проверкой, превращая искусство распознавания уровней в процесс, основанный на эмпирическом тестировании.  

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

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

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

Историческое поведение несет информацию

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

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

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

Прикрепленные файлы |
Архитектура машинного обучения для MetaTrader 5 (Часть 8): Байесовская оптимизация гиперпараметров с Purged Cross-Validation и ранним отсечением испытаний Архитектура машинного обучения для MetaTrader 5 (Часть 8): Байесовская оптимизация гиперпараметров с Purged Cross-Validation и ранним отсечением испытаний
GridSearchCV и RandomizedSearchCV имеют фундаментальное ограничение в финансовом ML: каждое испытание независимо, поэтому качество поиска не улучшается с ростом вычислительного бюджета. В этой статье Optuna — с использованием Tree-structured Parzen Estimator — интегрируется с кросс-валидацией PurgedKFold, ранней остановкой HyperbandPruner и соглашением о двух типах весов, которое разделяет веса обучения и веса оценки. В результате получается система из пяти компонентов: целевая функция с отсечением на уровне фолдов, слой преобразования/подстановки параметров, совместно оптимизирующий схему взвешивания и гиперпараметры модели, финансово откалиброванное отсечение, возобновляемый оркестратор на базе SQLite и конвертер в формат scikit-learn cv_results_. В статье также проводится четкое разграничение — на основе Тимоти Мастерса — между статистическими целями, где направленный поиск полезен, и финансовыми целями, где он вреден.
От "лучшего прохода" к устойчивым решениям: исследование поверхности оптимизации в MetaTrader 5 От "лучшего прохода" к устойчивым решениям: исследование поверхности оптимизации в MetaTrader 5
В статье рассмотрен инженерный подход к оптимизации советника в MetaTrader 5: от сбора пользовательских метрик через Optimization Frames до анализа поверхности параметров. На простой событийной EMA/RSI‑модели показаны экспорт в CSV, сглаживание и оценка локальной стабильности в Python. Цель — находить устойчивые области конфигураций и подтверждать их форвард‑оптимизацией для надёжного внедрения.
Автоматизация торговых стратегий в MQL5 (Часть 29): Создание системы торговли по гармоническому паттерну "Гартли" на основе Price Action Автоматизация торговых стратегий в MQL5 (Часть 29): Создание системы торговли по гармоническому паттерну "Гартли" на основе Price Action
В этой статье мы разрабатываем систему распознавания гармонических паттернов "Гартли" (Gartley) на языке MQL5, которая определяет бычьи и медвежьи гармонические паттерны "Гартли" с использованием точек разворота и уровней Фибоначчи, запуская сделки с точными уровнями входа, стоп-лосса и тейк-профита. Мы также улучшим визуальное представление паттерна с помощью графических объектов — треугольников, линий тренда и меток, которые чётко отображают структуру паттерна XABCD.
Алгоритм оптимизации Архимеда — Archimedes Optimization Algorithm (AOA) Алгоритм оптимизации Архимеда — Archimedes Optimization Algorithm (AOA)
В статье рассматривается алгоритм оптимизации Архимеда — метаэвристика, в которой агент представлен физическим объектом с плотностью, объёмом и ускорением, а сам поиск переосмыслен как стремление погружённых в жидкость тел к равновесию. Баланс между разведкой и эксплуатацией здесь не задаётся внешним расписанием, а вытекает из физики затихающей турбулентности. Реализуем алгоритм на MQL5, прогоняем на стандартном стенде и разбираем, где такая идея работает.