Разработка инструментария для анализа Price Action (Часть 28): Инструмент для торговли пробоя диапазона открытия
Содержание
- Введение
- Диапазон открытия
- Обзор стратегии
- Разбор компонентов советника
- Тестирование на исторических данных и результаты
- Заключение
Введение
6 мая 2010 года фондовые рынки США пережили печально известный "Flash Crash" – стремительный обвал, при котором крупный алгоритмический ордер на продажу фьючерсов E-Mini S&P 500 спровоцировал волну высокочастотных ликвидаций и обрушил индекс Dow почти на 1000 пунктов всего за несколько минут, после чего последовало столь же стремительное восстановление. Этот драматичный эпизод выявил критическую уязвимость: реакция на неподтвержденный пробой, каким бы убедительным он ни казался, может поставить трейдера в сложное положение, если ликвидность исчезнет, а рынок резко развернется обратно.
Пробой происходит, когда цена уверенно выходит за четко определенную границу, например за максимум или минимум начального интервала сессии, сигнализируя о том, что спрос или предложение взяли верх над противоположной стороной. Умение распознавать настоящие пробои крайне важно, поскольку они часто знаменуют начало устойчивых трендов, тогда как ложные пробои при преждевременном входе нередко приводят к убыткам из-за резких обратных движений.
Стратегия пробоя диапазона открытия (Opening Range Breakout, ORB) решает эту задачу так: сначала она фиксирует верхнюю и нижнюю границы начального интервала, который может быть задан любой длительности, а затем отмечает этот диапазон на графике прямоугольником. Эти границы служат и визуальными ориентирами, и точными уровнями входа. Только когда цена выходит за пределы прямоугольника, затем возвращается к этой границе и снова пробивает ее, стратегия подтверждает вход, отфильтровывая шум и выделяя движения, подтвержденные реальным рыночным импульсом.
В этой статье вы познакомитесь с профессиональной реализацией ORB в виде советника на MQL5, которая включает:
- инкапсулированный модуль диапазона, который отслеживает и отображает максимум и минимум открытия, не загромождая основной цикл;
- стоп-лосс и тейк-профит с поправкой на волатильность через повторно используемый модуль ATR;
- логику подтверждения ретеста, которая отличает реальные пробои от кратковременных всплесков;
- визуализацию на графике с динамическими метками панели и графическими объектами;
- четкую машину состояний в OnTick(), которая управляет каждым этапом и корректно сбрасывается при закрытии сессии.
Диапазон открытия
Диапазон открытия определяется уровнями максимума и минимума, формируемыми в течение первых минут торговой сессии, чаще всего в первые 15 или 30 минут. Этот период отражает немедленную реакцию рынка на ночные новости, экономические данные и активность институциональных участников; обычно ему сопутствуют высокие объемы и повышенная волатильность. Трейдеры используют границы диапазона как опорные точки; пробой вверх или вниз может указывать на возможный импульс в соответствующем направлении. Эти уровни помогают планировать сделки с заранее определенными точками входа, стоп-лоссами и целями, что делает диапазон открытия практичным инструментом для раннего выявления тренда и построения структурированных внутридневных стратегий.
Понимание диапазона открытия и умение эффективно торговать его дают несколько преимуществ на внутридневных рынках:
| Преимущество | Описание |
|---|---|
| Раннее выявление тренда | Пробой диапазона первых 15-30 минут указывает на возможный импульс и помогает трейдеру действовать в направлении внутридневного движения. |
| Четкие правила торговли | При четко заданных границах максимума и минимума вы получаете объективные точки входа и уровни стопов, что уменьшает необходимость действовать наугад. |
| Встроенное управление рисками | Стопы можно размещать чуть внутри противоположной границы, заранее определяя соотношение риск/прибыль. |
| Экономия времени и системность | Если торговля ограничена утренним окном, времени перед экраном требуется меньше, а саму стратегию проще применять изо дня в день. |
| Применимость на разных рынках | Подходит для акций, форекса, фьючерсов и разных таймфреймов, повышая гибкость трейдера. |
| Преимущество высокой волатильности | Позволяет использовать преимущества ликвидности и узких спредов, характерных для начала сессии. |
| Гибкость стратегии | Поддерживает тактики пробоя, разворота и скальпинга в рамках единого подхода. |
Мы используем два основных метода для расчета диапазона открытия.
Метод 1. Двухсвечной диапазон
Этот подход использует всего два бара. Сначала возьмите последнюю свечу предыдущей сессии: ее максимум и минимум задают крайние уровни завершения предыдущей сессии. Затем возьмите свечу открытия текущей сессии: ее максимум и минимум отражают начальный всплеск торгов. Диапазон открытия – это просто расстояние между самым высоким максимумом и самым низким минимумом этих двух баров. Этот компактный расчет сразу дает представление о начальном импульсе и помогает определить потенциальные уровни пробоя на текущую сессию.

Сначала вычислите точный момент начала вашей торговой сессии, например 09:30 по локальному времени сервера. Это можно либо жестко задать в коде, либо вычислить через SymbolInfoSessionTrade.
// Example: use SymbolInfoSessionTrade to get today's session start MqlDateTime nowStruct; TimeToStruct(TimeCurrent(), nowStruct); datetime from, to; SymbolInfoSessionTrade(_Symbol, (ENUM_DAY_OF_WEEK)nowStruct.day_of_week, SessionIndex, from, to); // 'from' now holds seconds since midnight; convert to full datetime: datetime todayStart = (TimeCurrent() - TimeCurrent()%86400) + from;
Найдите индекс самого первого бара M1 на момент todayStart или сразу после него, затем возьмите следующий по индексу бар (index+1) как последний бар вчерашней сессии.
// Find bar numbers int firstBarToday = iBarShift(_Symbol, PERIOD_M1, todayStart, false); int lastBarYesterday = firstBarToday + 1;Используйте встроенные функции работы с временными рядами, чтобы получить максимум и минимум для каждого индекса бара.
double highYesterday = iHigh(_Symbol, PERIOD_M1, lastBarYesterday); double lowYesterday = iLow (_Symbol, PERIOD_M1, lastBarYesterday); double highToday = iHigh(_Symbol, PERIOD_M1, firstBarToday); double lowToday = iLow (_Symbol, PERIOD_M1, firstBarToday);Возьмите максимум из двух максимумов и минимум из двух минимумов, чтобы сформировать диапазон открытия, а затем рассчитайте его размер.
double openingHigh = MathMax(highYesterday, highToday); double openingLow = MathMin (lowYesterday, lowToday); double openingSize = openingHigh - openingLow; PrintFormat("Opening Range → High: %.5f Low: %.5f Size: %.5f", openingHigh, openingLow, openingSize);
Метод 2
Вместо опоры на конкретные свечи этот подход определяет диапазон открытия по максимальной и минимальной ценам, достигнутым в первые минуты после открытия рынка. Отслеживая эти ранние экстремумы, вы в реальном времени фиксируете первоначальные настроения рынка и импульс дня. Эти уровни максимума и минимума диапазона открытия затем служат порогами пробоя; как только цена выходит за их пределы, это указывает на возможный тренд до конца сессии.

Сначала вычислите точный момент начала текущей торговой сессии, например 09:30. Мы используем SymbolInfoSessionTrade, чтобы получить значение в секундах из поля "from" и преобразовать его в полноценный тип datetime.
// Calculate the session’s opening datetime MqlDateTime nowStruct; TimeToStruct(TimeCurrent(), nowStruct); datetime fromSec, toSec; SymbolInfoSessionTrade(_Symbol, (ENUM_DAY_OF_WEEK)nowStruct.day_of_week, SessionIndex, fromSec, toSec); // Build a full datetime from today’s midnight plus the session offset datetime sessionStart = (TimeCurrent() - TimeCurrent() % 86400) + fromSec;
Затем пройдите по каждому минутному бару в пределах первых RangeMinutes после sessionStart, отслеживая самый высокий максимум и самый низкий минимум из всех, появившихся с момента начала сессии.
double orHigh = -DBL_MAX; double orLow = DBL_MAX; // Find the bar index at or just after sessionStart int startIdx = iBarShift(_Symbol, TF, sessionStart, false); // Loop through the first RangeMinutes bars (M1 timeframe) for(int i = startIdx; i >= startIdx - (RangeMinutes - 1); i--) { if(i < 0) break; // safety check double h = iHigh(_Symbol, TF, i); double l = iLow (_Symbol, TF, i); orHigh = MathMax(orHigh, h); orLow = MathMin(orLow, l); }
В итоге вы получаете значения orHigh и orLow. После этого можно вычислить размер диапазона и сравнить текущую цену (Bid) с этими уровнями, чтобы генерировать сигналы.
double openingSize = orHigh - orLow; PrintFormat("Opening Range (Method 2): High=%.5f Low=%.5f Size=%.5f", orHigh, orLow, openingSize); // Breakout detection double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(bid > orHigh) Alert("Breakout Long at price " + DoubleToString(bid, _Digits)); else if(bid < orLow) Alert("Breakout Short at price " + DoubleToString(bid, _Digits));
Обзор стратегии
Этот советник автоматизирует стратегию пробоя диапазона открытия, сначала определяя верхнюю и нижнюю границы начального периода торговой сессии. В начале каждой сессии он фиксирует цену открытия, а затем в течение следующих RangeMinutes, например 15 минут, непрерывно обновляет наибольший максимум и наименьший минимум. Когда это окно закрывается, советник рисует на графике горизонтальные линии и прямоугольник, чтобы визуально обозначить область диапазона, в пределах которой формировалась начальная волатильность. Фильтр ATR с настраиваемыми периодом и множителем гарантирует, что торговые сигналы будут срабатывать только тогда, когда волатильность достигнет значимого уровня.
После того как диапазон определен, советник отслеживает двухэтапный пробой: сначала цена должна закрыться за пределами диапазона, затем вернуться к его границе и снова закрыться за ней (это и есть ретест). Когда происходит подтверждение ретеста, советник рисует стрелку вверх или вниз на баре входа, вычисляет уровни стоп-лосса и тейк-профита на основе ATR и отправляет алерты о сигнале – на экране, по электронной почте и/или через push-уведомления. На панели на графике постоянно обновляются текущее состояние советника, значение ATR и ширина диапазона, а при начале следующей сессии или в полночь все корректно сбрасывается.
Этот советник автоматизирует стратегию пробоя диапазона открытия, сначала определяя верхнюю и нижнюю границы начального периода торговой сессии. В начале каждой сессии он фиксирует цену открытия, а затем в течение следующих RangeMinutes, например 15 минут, непрерывно обновляет наибольший максимум и наименьший минимум. Когда это окно закрывается, советник рисует на графике горизонтальные линии и прямоугольник, чтобы визуально обозначить область диапазона, в пределах которой формировалась начальная волатильность. Фильтр ATR с настраиваемыми периодом и множителем гарантирует, что торговые сигналы будут срабатывать только тогда, когда волатильность достигнет значимого уровня.
После того как диапазон определен, советник отслеживает двухэтапный пробой: сначала цена должна закрыться за пределами диапазона, затем вернуться к его границе и снова закрыться за ней (это и есть ретест). Когда происходит подтверждение ретеста, советник рисует стрелку вверх или вниз на баре входа, вычисляет уровни стоп-лосса и тейк-профита на основе ATR и отправляет алерты о сигнале – на экране, по электронной почте и/или через push-уведомления. На панели на графике постоянно обновляются текущее состояние советника, значение ATR и ширина диапазона, а при начале следующей сессии или в полночь все корректно сбрасывается.
Разбор компонентов советника
1. Заголовок файла и свойства
В верхней части файла мы задаем сведения об авторском праве, ссылку и версию с помощью директивы #property. Это не просто формальность: директива #property strict заставляет компилятор применять современные правила MQL5, такие как запрет неявных приведений типов и обязательность прототипов функций, что помогает выявлять тонкие ошибки еще на этапе компиляции. Задав #property link, мы позволяем любому, кто откроет советник в MetaEditor, перейти на наш профиль в сообществе MQL5, что помогает поддерживать контроль версий и явно обозначает авторство. Вы также можете использовать #property description, чтобы добавить собственные пояснения, которые будут отображаться в окне свойств советника; это упрощает пользователям задачу описания своих настроек без добавления дополнительного кода графического интерфейса.
//+------------------------------------------------------------------+ //| ORB Breakout EA| //| Copyright 2025, MetaQuotes Ltd.| //| https://www.mql5.com/ru/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/ru/users/lynnchris" #property version "1.0" #property description "Opening‑Range Breakout with ATR confirmation" #property strict
2. Входные параметры
Мы группируем настраиваемые пользователем параметры под понятными комментариями: индекс сессии и длину диапазона, настройки фильтра ATR, коды и цвета стрелок, а также переключатели оповещений. В языке MQL5 входные переменные автоматически появляются в окне свойств советника с корректными типами, а перечисления, например ENUM_TIMEFRAMES для таймфреймов, отображаются как выпадающие списки – без необходимости писать собственный GUI. Обратите внимание: выбрав входной параметр int ArrowUpCode, мы даем пользователю возможность выбрать код любого символа из шрифта Wingdings, но если бы нам понадобился фиксированный список, мы могли бы определить собственное перечисление ArrowSymbol { UP=233, DOWN=234 }, чтобы ограничить выбор уже на этапе компиляции. Входные параметры также поддерживают readonly, если вы хотите запретить их изменение в процессе работы советника.
//--- session & range input int SessionIndex = 0; // 0 = first session input int RangeMinutes = 15; // minutes to capture range //--- ATR filter input ENUM_TIMEFRAMES TF = PERIOD_M1; // ATR timeframe input int ATRPeriod = 14; // ATR look‑back input double ATRMultiplier = 1.5; // ATR * multiplier //--- arrows & alerts input int ArrowUpCode = 233; // wingdings ↑ input int ArrowDnCode = 234; // wingdings ↓ input color ArrowUpColor = clrLime; // long arrow input color ArrowDnColor = clrRed; // short arrow input bool SendEmailAlert = false; // email on signal input bool PushNotify = false; // push on signal input string EmailSubject = "ORB Signal"; // mail subject
3. Класс RangeCapture
Инкапсуляция логики диапазона открытия в отдельном классе CRangeCapture позволяет не перегружать основной OnTick() и подчеркивает объектно-ориентированную структуру кода MQL5. Мы сохраняем время начала, а также изменяющиеся значения максимума и минимума, используя методы Init(), Update() и IsDefined(). Помните, что классы в MQL5 не инициализируются автоматически, поэтому явные вызовы Init() обязательны. Кроме того, храня hi и lo как double, мы используем 64-битную точность чисел с плавающей запятой в MQL5, что критически важно для котировок на Forex. В дальнейшем этот класс можно было бы расширить так, чтобы он записывал максимум и минимум каждого тика во внутренний буфер. Это хорошо показывает, как классы могут развиваться, сохраняя исходный интерфейс.
class CRangeCapture { private: datetime startTime; double hi, lo; public: void Init(datetime t, double price) { startTime = t; hi = lo = price; } void Update(double price, datetime now) { if(now < startTime + RangeMinutes*60) { hi = MathMax(hi, price); lo = MathMin(lo, price); } } bool IsDefined(datetime now) const { return(now >= startTime + RangeMinutes*60); } double High() const { return hi; } double Low() const { return lo; } }; static CRangeCapture g_range;
4. Класс ATRModule
Здесь мы оборачиваем хэндл стандартного индикатора ATR (iATR) в класс CATRModule. В Init() мы создаем хэндл и проверяем его на INVALID_HANDLE, чтобы защититься от проблем, связанных с символом или таймфреймом. Метод Value() вызывает CopyBuffer всего один раз на тик, что гораздо эффективнее, чем многократно вызывать iATR внутри OnTick(). Кэшируя хэндл, мы избегаем утечек памяти и минимизируем нагрузку на ресурсы. Когда в Release() вызывается IndicatorRelease(), этот хэндл освобождается. Без этого во вкладке "Индикаторы" терминала со временем может накопиться большой список, а работа терминала может замедлиться. Этот паттерн легко масштабируется, если вы обернете дополнительные индикаторы, такие как EMA и полосы Боллинджера, в отдельные модули.
class CATRModule { private: int handle; public: bool Init() { handle = iATR(_Symbol, TF, ATRPeriod); return(handle != INVALID_HANDLE); } double Value() const { double buf[]; if(handle != INVALID_HANDLE && CopyBuffer(handle, 0, 0, 1, buf) == 1) return buf[0] * ATRMultiplier; return 0.0; } void Release() { if(handle != INVALID_HANDLE) IndicatorRelease(handle); } }; static CATRModule g_atr;
5. Класс логики ретеста
Класс CRetestSignal реализует паттерн "пробой, ретест, повторный пробой" с помощью трех простых булевых флагов. Переменные breakLong, breakShort и retested остаются внутренними, а наружу выносятся только методы Reset(), OnBreak() и CheckRetest(). Так мы скрываем детали реализации от OnTick(), поэтому внимание читателя смещается с "как" на "что". Обратите внимание, что последний бар MqlRates передается по ссылке, что снижает затраты ресурсов на копирование. Если в будущем понадобится поддержка нескольких таймфреймов, CheckRetest() можно расширить так, чтобы он принимал массив MqlRates или параметр таймфрейма. Это хорошо показывает, насколько гибкой может быть перегрузка методов в MQL5.
class CRetestSignal { private: bool breakLong, breakShort, retested; public: void Reset() { breakLong = breakShort = retested = false; } void OnBreak(double close, double h, double l) { breakLong = (close > h); breakShort = (close < l); retested = false; } bool CheckRetest(const MqlRates &r, bool &isLong) { if(breakLong) { if(!retested && r.low <= g_range.High()) { retested = true; isLong = true; return false; } if(retested && r.close > g_range.High()) { isLong = true; return true; } } else if(breakShort) { if(!retested && r.high >= g_range.Low()) { retested = true; isLong = false; return false; } if(retested && r.close < g_range.Low()) { isLong = false; return true; } } return false; } }; static CRetestSignal g_retest;
6. Панель на графике
Чтобы давать обратную связь в реальном времени, CDashboard создает простой объект OBJ_LABEL в левом верхнем углу. Здесь видно, как Init(), Update() и Delete() управляют жизненным циклом этой метки. Тот же паттерн работает и для OBJ_TEXT, OBJ_RECTANGLE и любых других типов объектов. Метка обновляется на каждом тике, но поскольку повторное присвоение одного и того же текста не требует больших ресурсов, производительность остается высокой. Если потребуется дополнительная оптимизация, можно кэшировать последнюю строку и вызывать ObjectSetString() только тогда, когда эта строка действительно меняется. Это хороший пример того, как небольшие улучшения в управлении объектами дают прирост производительности в советниках, обрабатывающих большое количество тиков.
class CDashboard { private: string name; public: void Init() { name = "ORB_Info"; if(ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 30); } } void Update(const string &txt) { ObjectSetString(0, name, OBJPROP_TEXT, txt); } void Delete() { if(ObjectFind(0, name) >= 0) ObjectDelete(0, name); } }; static CDashboard g_dash;
7. Торговый интерфейс и уведомления
Хотя в этом примере мы не отправляем ордера, здесь все же объявлен объект static CTrade trade, чтобы показать, как позже можно будет интегрировать реальные сделки. Но важнее то, что при подтвержденном сигнале мы рисуем стрелку (OBJ_ARROW), используя выбранные пользователем коды и цвета Wingdings, а затем вызываем Alert(), SendNotification() и SendMail(). Эта триада демонстрирует встроенную в MQL5 систему событий и уведомлений – без каких-либо внешних библиотек. При желании сюда можно добавить PlaySound() или EventChartCustom() для веб-хуков, показывая читателю, насколько широк набор встроенных каналов связи.
static CTrade trade; // ... inside your retest-confirmation block: string msg = StringFormat("%s Signal @%.5f SL=%.5f TP=%.5f", isLong ? "LONG" : "SHORT", r[0].close, sl, tp); Alert(msg); if(PushNotify) SendNotification(msg); if(SendEmailAlert) SendMail(EmailSubject, msg); // draw arrow on chart: string arrowName = "ORB_Arrow_" + IntegerToString((int)r[0].time); ObjectCreate(0, arrowName, OBJ_ARROW, 0, r[0].time, isLong ? r[0].low - 5 * _Point : r[0].high + 5 * _Point); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, isLong ? ArrowUpCode : ArrowDnCode); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, isLong ? ArrowUpColor : ArrowDnColor);
8. OnInit() и OnDeinit()
В OnInit() мы инициализируем модуль ATR и панель. Если что-то идет не так, возвращается INIT_FAILED. Такой паттерн не позволяет советнику запускаться в частично нерабочем состоянии. В OnDeinit() мы корректно освобождаем хэндл ATR и удаляем все графические объекты, чтобы при перезагрузке или удалении советника не оставалось осиротевших индикаторов и объектов. Эта практика критически важна для рабочего кода: каждому хэндлу iXXX должен соответствовать вызов IndicatorRelease(), а каждому ObjectCreate() – либо ObjectDelete() в OnDeinit(), либо условная логика в процедуре сброса.
int OnInit() { if(!g_atr.Init()) return INIT_FAILED; g_dash.Init(); return INIT_SUCCEEDED; } void OnDeinit(const int reason) { g_atr.Release(); ObjectDelete(0, "ORB_High"); ObjectDelete(0, "ORB_Low"); ObjectDelete(0, "ORB_Range"); g_dash.Delete(); }
9. Машина состояний в OnTick()
Сердце советника – функция OnTick(). Мы используем static bool inited и static int state, поэтому их значения сохраняются между вызовами. Именно так в MQL5 реализуется память на уровне советника без глобальных переменных и внешнего хранилища. Сначала мы вычисляем время начала сессии и выполняем сброс один раз в день – это типичный паттерн для внутридневной логики. Затем переключатель switch(state) последовательно проводит нас через четыре этапа: Capture ("захват"), Break ("пробой"), Retest ("ретест") и Done ("готово"). Поскольку MQL5 не поддерживает передачу управления в стиле сопрограмм (через yield), машина состояний является стандартным способом разбить многошаговую стратегию на обработку по одному тику. Кроме того, такой подход делает каждую ветку небольшой и удобной для тестирования.
void OnTick() { static bool inited = false; static int state = 0; static datetime sessionStart; if(!inited) { // compute sessionStart, init g_range & g_retest, Alert inited = true; state = 0; } // fetch latest MqlRates r[0] and bid/ask switch(state) { case 0: // Capture g_range.Update(bid, TimeCurrent()); if(g_range.IsDefined(TimeCurrent())) state = 1; break; case 1: // Break if(r[0].close > g_range.High() || r[0].close < g_range.Low()) { g_retest.OnBreak(r[0].close, g_range.High(), g_range.Low()); state = 2; } break; case 2: // Retest { bool isLong; if(g_retest.CheckRetest(r[0], isLong)) state = 3; } break; case 3: // Done break; } }
10. Сброс в полночь
Наконец, мы сравниваем today = now - now%86400 со статической переменной datetime lastDay. Как только дата меняется, мы удаляем старые объекты и сбрасываем флаги – без неуклюжих хаков в духе "if hour==0". Этот паттерн подходит для любого советника с дневной логикой: работы с нулевыми барами, расчета дневных точек разворота, отчетов в конце дня и т.д. Если приучать читателя к такому приему, это помогает избегать тонких ошибок на единицу при переходе через полночь и во время сезонного перевода часов.
// at the end of OnTick(): static datetime lastDay = 0; datetime today = TimeCurrent() - TimeCurrent() % 86400; if(today != lastDay) { lastDay = today; inited = false; state = 0; ObjectDelete(0, "ORB_High"); ObjectDelete(0, "ORB_Low"); ObjectDelete(0, "ORB_Range"); }
Тестирование на исторических данных и результаты
Тестирование на исторических данных – это запуск вашей торговой стратегии, реализованной в советнике, на исторических рыночных данных, чтобы увидеть, как она повела бы себя в прошлом. Это позволяет:
- проверить, дают ли ваши правила разумные результаты;
- измерить ключевые метрики, такие как процент выигрышных сделок, просадка и коэффициент прибыльности;
- оптимизировать входные параметры, например длину диапазона и множитель ATR, чтобы найти сочетания, которые исторически работали лучше всего.
В MetaTrader 5 тестер стратегий подает каждый исторический тик в OnTick(), поэтому:
- OnInit() настраивает все – хэндл ATR, графические объекты и начальное состояние;
- OnTick() управляет построением диапазона, логикой пробоя и ретеста, отрисовкой стрелок, алертами и обновлением панели на каждом смоделированном тике;
- OnDeinit() выполняет очистку после теста.
Другими словами, тестер использует тот же кодовый путь, что и на реальном графике.

Анимированный GIF выше показывает работу советника Opening Range Breakout на графике EURUSD M15 во время бэктеста. В основной области графика виден затененный прямоугольник, обозначающий диапазон открытия и ограниченный двумя горизонтальными линиями на максимуме и минимуме этого начального интервала. Такое визуальное оформление сразу показывает, где советник ожидает значимого движения цены.
Каждая зеленая стрелка на графике обозначает подтвержденный вход в длинную позицию. Логика "пробой → ретест → повторный пробой" в советнике гарантирует, что цена сначала должна пробить верхнюю границу, затем вернуться к ней и только после этого снова закрыться выше нее, прежде чем появится стрелка. Такое двухэтапное подтверждение отфильтровывает ложные пробои и подает сигнал только при наличии реального импульса.
Панель Journal под графиком фиксирует каждое критически важное событие: начало сессии, определение диапазона, обнаружение пробоя и финальный сигнал с точными значениями входа, стоп-лосса и тейк-профита. Эти записи в логе отражают внутренние переходы состояний советника и прозрачно показывают, как и когда принимаются решения.
Этот пример показывает, как стратегия ORB использует волатильность начала сессии, подтверждает истинные пробои и генерирует воспроизводимые сигналы на таймфрейме EURUSD M15.

Я также протестировал этот советник на AUD/USD на таймфрейме M5, чтобы получить более наглядную картину внутридневного движения цены. См. диаграмму выше.
Заключение
Разработанный нами на языке MQL5 советник Opening Range Breakout превращает простую идею ценового коридора начала сессии в дисциплинированную автоматизированную стратегию. Разделив на модули каждый компонент – захват диапазона, стопы на основе волатильности, проверку ретеста и обратную связь на графике, – мы получили кодовую базу, которую легко поддерживать и которая достаточно быстра для реального применения.
Этот подход решает две ключевые внутридневные задачи: помогает отличать настоящий импульс от кратковременных всплесков и подбирать размер риска в соответствии с рыночными условиями в реальном времени. Последовательность подтверждения "пробой → ретест → повторный пробой" отсекает ложные движения, а уровни стоп-лосса и тейк-профита, рассчитанные на основе ATR, динамически адаптируются к меняющейся волатильности. За счет этого советник выдает последовательные и убедительные сигналы – именно те входы, которые лучше выдерживают турбулентный рынок и позволяют использовать реальные движения цены.
Теперь пришло время адаптировать его под себя. Скомпилируйте советник в MetaEditor, протестируйте его на разных символах и сессиях и поэкспериментируйте с параметрами, такими как длительность диапазона и множитель ATR. Понаблюдайте, как на графике оживают прямоугольник, линии и стрелки, и следите за записями в Journal, чтобы видеть, как разворачивается каждое решение. Имея в распоряжении эту ORB-схему, вы сможете превращать колебания в начале каждого дня в воспроизводимые и более уверенные сделки. Желаю вам более точных входов и более продуманного управления рисками.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/18486
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Статистический арбитраж на основе коинтегрированных акций (Часть 3): Настройка базы данных
От начального до среднего уровня: Объекты (II)
Создание самооптимизирующихся советников на MQL5 (Часть 13): Введение в теорию управления с использованием факторизации матриц
Торговые инструменты на MQL5 (Часть 20): Построение графиков на Canvas с использованием статистической корреляции и регрессионного анализа
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования