От новичка до эксперта: Автоматизация распознавания геометрических паттернов внутри базовых свечей зон ликвидности в MQL5
У вас уже есть надежный индикатор зон ликвидности, который отображает прямоугольники зон предложения и спроса на старших таймфреймах. Однако этот индикатор не может заглянуть внутрь базовой свечи. Чтобы понять, сформировалась ли зона из восходящего треугольника, прямоугольника, двойной вершины или другого паттерна, необходимо вручную рассмотреть каждую зону в увеличенном масштабе на младшем таймфрейме. Такая ручная проверка занимает много времени, субъективна и дает непоследовательные результаты. В результате вы пропускаете зоны, противоречите собственным прежним оценкам и упускаете скрытую геометрию, которая отличает сильные зоны от слабых.
В статье представлен модуль автоматического распознавания геометрии, который легко интегрируется с уже используемым индикатором зон. Он мгновенно классифицирует внутреннюю структуру каждой базовой свечи — восходящий треугольник, нисходящий треугольник, прямоугольник, M, W или неопределенная структура — и отображает результат на графике, заменяя догадки воспроизводимым анализом.
Содержание
Введение
Каждый трейдер, который ориентируется на зоны ликвидности, знаком с этим чувством. Вы часами просматриваете графики старших таймфреймов и выделяете прямоугольниками зоны спроса и предложения. Затем вы подробно рассматриваете каждую базовую свечу на младшем таймфрейме, чтобы определить, содержит ли она восходящий треугольник, нисходящий треугольник, прямоугольник, двойную вершину или двойное дно. Этот процесс выполняется вручную, субъективен и занимает слишком много времени. Разные трейдеры часто по-разному классифицируют одну и ту же фигуру. Вы пропускаете зоны, потому что их анализ занимает слишком много времени. И что хуже всего, у вас нет системного способа определить, какие зоны, скорее всего, удержат цену, а какие будут пробиты.
Основная причина — не в самом обнаружении зон. Многие индикаторы уже выявляют зоны ликвидности по соотношению размеров свечей старшего таймфрейма. Недостающий элемент — внутренняя геометрия базовой свечи: паттерн, который показывает, шло ли на рынке активное накопление (треугольник) или цена просто двигалась вбок (прямоугольник). Без этой информации все зоны выглядят одинаково, и вам приходится гадать.
Мы восполним этот пробел. В статье представлен настраиваемый модуль распознавания геометрии. Он анализирует бары младшего таймфрейма внутри каждой базовой свечи, классифицирует паттерн (восходящий, нисходящий или симметричный треугольник, прямоугольник, M, W либо неопределенная структура) и отображает результат на графике. Кроме того, алерты и записи журнала дополняются новой информацией. К концу статьи вы перейдете от ручной проверки к мгновенному и воспроизводимому распознаванию геометрии.
Знакомство с концепцией
Рассмотрим реальную последовательность событий, представленную на рис. 1. На графике установлен таймфрейм M5, а для обнаружения зон ликвидности используется старший таймфрейм H1. Это означает, что каждая часовая базовая свеча содержит ровно 12 пятиминутных баров — такой детализации достаточно для анализа значимой внутренней структуры. Первая заметная фигура — нисходящий треугольник (горизонтальная поддержка и снижающееся сопротивление). Вместо пробоя вниз цена вышла из фигуры вверх, сформировав зону спроса. Позже эта зона спроса стала отправной точкой разворота. После этого сформировалась прямоугольная консолидация — узкий горизонтальный диапазон с неоднократными касаниями обеих границ. Прямоугольник послужил трамплином для импульсного движения, которое протестировало ранее сформированную зону спроса.
Чуть правее на том же графике мы видим двойную вершину (обозначенную цифрами 1 и 2). Сформировались два отчетливых пика почти одинаковой высоты с выраженной впадиной между ними. После второго пика цена пробила линию шеи вниз, сформировав подтвержденную зону предложения. Эта зона предложения привела к сильной распродаже. Позже цена вернулась к зоне предложения — классический ретест. На этот раз отбой от зоны был резким и уверенным: цена сформировала перевернутую V (быстрый выброс вверх с немедленным сильным падением). Перевернутая V подтверждает, что зона предложения по-прежнему активна, а продавцы защищают этот уровень. Такую реакцию сложно выявить без анализа внутренней геометрии базовой свечи, сформировавшей зону предложения.
На рис. 2 тот же нисходящий треугольник показан крупным планом, на этот раз на графике M1. Вся формация занимает один час (60 минутных баров). Обратите внимание: линия сопротивления направлена вверх, а поддержка остается горизонтальной. Это классический бычий паттерн, пробой которого сформировал зону спроса, показанную на рис. 1. Именно возможность распознавать эту фигуру на нескольких таймфреймах и обеспечивает наш автоматический детектор геометрии.

Рис. 1. Ручной анализ геометрии базовой свечи зоны старшего таймфрейма на младшем таймфрейме

Рис. 2. Расширяющаяся бычья структура на M1 (нисходящий треугольник)
Критерии распознавания наиболее распространенных геометрических фигур при анализе рынка
Детектор геометрии использует следующие объективные правила, основанные на описанных выше наблюдениях при ручном анализе:
- восходящий треугольник — свинговые максимумы остаются на одном уровне (в пределах допуска), а свинговые минимумы растут;
- нисходящий треугольник (зеркальный вариант восходящего треугольника) — свинговые минимумы остаются на одном уровне, а свинговые максимумы снижаются;
- симметричный треугольник — наклон линии свинговых максимумов отрицательный, а линии свинговых минимумов — положительный (линии сходятся);
- прямоугольник — цена остается в горизонтальном диапазоне и касается каждой из его границ как минимум дважды;
- M (двойная вершина) — два свинговых максимума близкой высоты со значимым минимумом между ними;
- W (двойное дно) — два свинговых минимума близкой глубины со значимым максимумом между ними;
- перевернутая V (резкий отбой) — быстрый выброс цены к границе зоны с немедленным сильным разворотом; хотя детектор не выделяет ее как самостоятельный паттерн, такая реакция служит подтверждением, которое отражается в дополненных алертах.
Все допуски настраиваются, поэтому вы можете регулировать чувствительность для разных символов и таймфреймов. Детектор работает как на пятиминутных (12 баров в час), так и на минутных (60 баров в час) графиках. Вам нужно лишь настроить расстояние для поиска свингов и минимальное количество баров.
Реализация
Мы будем пошагово создавать модуль распознавания геометрии. Сначала мы создаем отдельный заголовочный файл с классом CGeometryDetector в специально отведенной подпапке (например, MQL5/Include/GeometryTools/GeometryDetection.mqh). Затем мы интегрируем его в основной индикатор реакции на зоны ликвидности.
Разработка заголовочного файла — GeometryDetection.mqh (в подпапке GeometryTools).
Этот заголовочный файл инкапсулирует всю логику распознавания паттернов. Отделяя его от основного индикатора и размещая в подпапке MQL5/Include/, мы не загромождаем стандартный каталог терминала, поддерживаем порядок в файлах пользователя и обеспечиваем возможность повторного использования кода. Каждый метод распознавания можно настроить, поэтому алгоритм допускает тонкую настройку без изменения основного индикатора. Отдельный заголовочный файл также сокращает время компиляции и позволяет независимо тестировать механизм распознавания геометрии — это критически важно при последующем расширении набора паттернов.
Шаг 1. Определите класс и настраиваемые параметры
Первый шаг — создать класс, содержащий всю логику распознавания. Мы делаем его настраиваемым: пользователь может регулировать допуски для треугольников и прямоугольников, глубину паттернов M/W, расстояние для поиска свингов и минимальное количество баров. Это позволяет одному и тому же детектору работать с разными символами и таймфреймами без перекомпиляции. Эти настройки хранятся в закрытых полях класса. Обратите внимание: каждый допуск задается относительной долей, а не фиксированным количеством пипсов. Благодаря этому детектор не зависит от символа и адаптируется к любому масштабу цен.
//+------------------------------------------------------------------+ //| Configurable geometry detection class for market patterns | //| | //+------------------------------------------------------------------+ class CGeometryDetector { private: double m_triangle_tolerance; // tolerance for flat lines double m_rectangle_tolerance; // tolerance for rectangle range double m_mw_depth_factor; // minimum depth for M/W patterns int m_swing_distance; // swing detection distance int m_min_bars; // minimum bars required // ... (rest of class)
Шаг 2. Реализуйте вспомогательную функцию для добавления элементов в динамические массивы
В языке MQL5 нет встроенной функции ArrayAdd. Мы создаем шаблонную вспомогательную функцию, которая изменяет размер массива и добавляет значение в его конец. Эта функция многократно используется при сборе свинговых точек и значений паттернов. Шаблон позволяет одной и той же вспомогательной функции работать с целочисленными индексами, значениями типа double и другими нужными типами данных. Без этого код был бы перегружен повторяющимися вызовами ArrayResize.
//+------------------------------------------------------------------+ //| Adds value to dynamic array | //+------------------------------------------------------------------+ template<typename T> void ArrayAdd(T &arr[], T value) { int size = ArraySize(arr); ArrayResize(arr, size + 1); arr[size] = value; }
Шаг 3. Выявляйте свинговые максимумы и минимумы с учетом минимального расстояния
Свинговая точка — это бар, максимум (или минимум) которого выше (или ниже) соответствующих значений у заданного количества соседних баров с обеих сторон. Параметр m_swing_distance задает количество проверяемых баров с каждой стороны. Без этого фильтра каждое незначительное колебание считалось бы свингом, что приводило бы к ложному распознаванию паттернов. Этот метод перебирает ценовой массив и возвращает только индексы свинговых максимумов и минимумов, соответствующих заданным условиям. Они служат основой для дальнейшего распознавания паттернов. При выборе расстояния для поиска свингов нужен компромисс: значение 1 делает детектор крайне чувствительным к шуму, а значение 3 или 4 требует более крупных и значимых свингов. Это сокращает число ложных срабатываний, но может приводить к пропуску паттернов в узких консолидациях. Значение по умолчанию 2 обеспечивает баланс, подходящий для большинства внутридневных таймфреймов.
//+------------------------------------------------------------------+ //| Finds swing highs and lows | //+------------------------------------------------------------------+ void FindSwings(const double &highs[], const double &lows[], const int total, int &swing_high_idx[], int &swing_low_idx[]) { ArrayResize(swing_high_idx, 0); ArrayResize(swing_low_idx, 0); for(int i = m_swing_distance; i < total - m_swing_distance; i++) { bool is_high = true; bool is_low = true; for(int j = 1; j <= m_swing_distance; j++) { if(highs[i] <= highs[i-j] || highs[i] <= highs[i+j]) is_high = false; if(lows[i] >= lows[i-j] || lows[i] >= lows[i+j]) is_low = false; } if(is_high) ArrayAdd(swing_high_idx, i); if(is_low) ArrayAdd(swing_low_idx, i); } }
Шаг 4. Рассчитайте наклон линейной регрессии для симметричных треугольников
Для распознавания симметричных треугольников необходимо определить, снижаются ли максимумы и растут ли минимумы. Простой расчет наклона (методом наименьших квадратов) по значениям свингов позволяет определить направление каждой трендовой линии. Этот подход надежнее, чем сравнение только первой и последней свинговых точек, поскольку он учитывает всю последовательность свингов. Отрицательный наклон линии максимумов и положительный наклон линии минимумов подтверждают сужение диапазона — характерный признак симметричного треугольника.
//+------------------------------------------------------------------+ //| Calculates linear regression slope | //+------------------------------------------------------------------+ double Slope(const double &values[], const int start, const int count) { if(count < 2) return(0); double sum_x=0, sum_y=0, sum_xy=0, sum_x2=0; for(int i=0; i<count; i++) { double x=i, y=values[start+i]; sum_x+=x; sum_y+=y; sum_xy+=x*y; sum_x2+=x*x; } double denom = count*sum_x2 - sum_x*sum_x; if(denom==0) return(0); return((count*sum_xy - sum_x*sum_y)/denom); }
Шаг 5. Проверьте, находятся ли значения на одном уровне в пределах допуска
У треугольников одна сторона должна быть плоской (горизонтальной). Эта вспомогательная функция вычисляет среднее, а затем проверяет, не превышает ли отклонение каждого значения от него заданный процент. Допуск задается долей (например, 0,005 = 0,5%), что позволяет учитывать уровень цены и обходиться без жестко заданных значений в пипсах. Почему именно относительный допуск? Ведь отклонение в пять пипсов по EURUSD может быть приемлемым, а такое же абсолютное отклонение по GBPJPY — незначительным. Подход на основе процентов обеспечивает согласованную работу алгоритма на всех инструментах.
//+------------------------------------------------------------------+ //| Checks if values are flat within tolerance | //+------------------------------------------------------------------+ bool IsFlat(const double &values[], const double tolerance) { int size = ArraySize(values); if(size < 2) return(true); double avg = 0; for(int i=0; i<size; i++) avg += values[i]; avg /= size; for(int i=0; i<size; i++) if(MathAbs(values[i]-avg) > avg*tolerance) return(false); return(true); }
Шаг 6. Выявите восходящий треугольник
Для восходящего треугольника максимумы должны находиться на одном уровне (в пределах допуска), а минимумы — расти (каждый последующий свинговый минимум выше предыдущего). Метод извлекает значения свинговых точек и выполняет эти проверки. Это бычий паттерн; при возвращении цены зона часто служит сильной поддержкой. Ошибочная классификация прямоугольника как восходящего треугольника может привести к преждевременному открытию длинных позиций — поэтому проверка горизонтальности выполняется строго.
//+------------------------------------------------------------------+ //| Detects ascending triangle pattern | //+------------------------------------------------------------------+ bool IsAscendingTriangle(const double &highs[], const double &lows[], const int total) { if(total < m_min_bars) return(false); int swing_highs[], swing_lows[]; FindSwings(highs,lows,total,swing_highs,swing_lows); if(ArraySize(swing_highs)<2 || ArraySize(swing_lows)<2) return(false); double high_vals[], low_vals[]; for(int i=0; i<ArraySize(swing_highs); i++) ArrayAdd(high_vals, highs[swing_highs[i]]); for(int i=0; i<ArraySize(swing_lows); i++) ArrayAdd(low_vals, lows[swing_lows[i]]); if(!IsFlat(high_vals, m_triangle_tolerance)) return(false); for(int i=1; i<ArraySize(low_vals); i++) if(low_vals[i] <= low_vals[i-1]) return(false); return(true); }
Шаг 7. Выявите нисходящий треугольник
Нисходящий треугольник — противоположный паттерн: минимумы находятся на одном уровне, а максимумы снижаются. Логика зеркально повторяет проверку восходящего треугольника, но горизонтальность проверяется по минимумам, а каждый свинговый максимум должен быть ниже предыдущего. Это медвежий паттерн, который при возвращении цены часто выступает сопротивлением. Тот же параметр допуска применяется симметрично.
//+------------------------------------------------------------------+ //| Detects descending triangle pattern | //+------------------------------------------------------------------+ bool IsDescendingTriangle(const double &highs[], const double &lows[], const int total) { if(total < m_min_bars) return(false); int swing_highs[], swing_lows[]; FindSwings(highs,lows,total,swing_highs,swing_lows); if(ArraySize(swing_highs)<2 || ArraySize(swing_lows)<2) return(false); double high_vals[], low_vals[]; for(int i=0; i<ArraySize(swing_highs); i++) ArrayAdd(high_vals, highs[swing_highs[i]]); for(int i=0; i<ArraySize(swing_lows); i++) ArrayAdd(low_vals, lows[swing_lows[i]]); if(!IsFlat(low_vals, m_triangle_tolerance)) return(false); for(int i=1; i<ArraySize(high_vals); i++) if(high_vals[i] >= high_vals[i-1]) return(false); return(true); }
Шаг 8. Выявите симметричный треугольник по наклонам линий
Симметричный треугольник характеризуется снижающимися максимумами (отрицательный наклон) и растущими минимумами (положительный наклон). Мы вычисляем наклоны линейной регрессии отдельно по свинговым максимумам и минимумам и проверяем их знаки. Этот паттерн указывает на неопределенность и допускает пробой в любом направлении, но сама зона по-прежнему служит пулом ликвидности. Расчет наклона предпочтительнее простой проверки того, что последний свинговый максимум ниже первого: он отражает общее сужение диапазона даже при неравномерной последовательности отдельных свингов.
//+------------------------------------------------------------------+ //| Detects symmetrical triangle pattern | //+------------------------------------------------------------------+ bool IsSymmetricalTriangle(const double &highs[], const double &lows[], const int total) { if(total < m_min_bars) return(false); int swing_highs[], swing_lows[]; FindSwings(highs,lows,total,swing_highs,swing_lows); if(ArraySize(swing_highs)<2 || ArraySize(swing_lows)<2) return(false); double high_vals[], low_vals[]; for(int i=0; i<ArraySize(swing_highs); i++) ArrayAdd(high_vals, highs[swing_highs[i]]); for(int i=0; i<ArraySize(swing_lows); i++) ArrayAdd(low_vals, lows[swing_lows[i]]); double high_slope = Slope(high_vals, 0, ArraySize(high_vals)); double low_slope = Slope(low_vals, 0, ArraySize(low_vals)); return(high_slope < 0 && low_slope > 0); }
Шаг 9. Выявите прямоугольную консолидацию
Прямоугольник выявляется, когда цена остается в узком горизонтальном диапазоне. Мы проверяем три условия: все бары находятся в общем диапазоне между максимумом и минимумом с учетом допуска, диапазон не слишком широк, а верхнего и нижнего уровней цена касается как минимум по два раза. Прямоугольники нейтральны: они указывают на равновесие, поэтому сформированные на их основе зоны считаются более слабыми. Требование двух касаний не позволяет принять простой диапазон из двух баров за прямоугольник; для полноценной консолидации нужны неоднократные проверки обеих границ.
//+------------------------------------------------------------------+ //| Detects rectangle consolidation pattern | //+------------------------------------------------------------------+ bool IsRectangle(const double &highs[], const double &lows[], const int total) { if(total < m_min_bars) return(false); double max_high = highs[ArrayMaximum(highs)]; double min_low = lows[ArrayMinimum(lows)]; double avg_price = (max_high+min_low)/2; double tolerance = avg_price * m_rectangle_tolerance; for(int i=0; i<total; i++) if(highs[i]>max_high+tolerance || lows[i]<min_low-tolerance) return(false); double range = max_high - min_low; if(range > avg_price*0.02) return(false); int high_touches=0, low_touches=0; double touch_tol = avg_price*0.001; for(int i=0; i<total; i++) { if(highs[i] >= max_high - touch_tol) high_touches++; if(lows[i] <= min_low + touch_tol) low_touches++; } if(high_touches<2 || low_touches<2) return(false); return(true); }
Шаг 10. Выявите паттерн M (двойная вершина)
Паттерн M состоит из двух свинговых максимумов близкой высоты с выраженным минимумом между ними. Мы берем первый и последний свинговые максимумы, проверяем, укладывается ли разница между ними в допуск, а затем проверяем, достаточно ли глубоко расположен минимум между вершинами относительно их средней высоты. Этот паттерн сигнализирует о возможном развороте и часто служит признаком распределения. Коэффициент глубины не позволяет принимать незначительные колебания за значимую двойную вершину.
//+------------------------------------------------------------------+ //| Detects M (double top) pattern | //+------------------------------------------------------------------+ bool IsM(const double &highs[], const double &lows[], const int total) { if(total < m_min_bars) return(false); int swing_highs[], swing_lows[]; FindSwings(highs,lows,total,swing_highs,swing_lows); if(ArraySize(swing_highs)<2) return(false); int idx1 = swing_highs[0]; int idx2 = swing_highs[ArraySize(swing_highs)-1]; if(idx2-idx1 < m_swing_distance*2) return(false); double min_low = DBL_MAX; for(int i=idx1; i<=idx2; i++) if(lows[i] < min_low) min_low = lows[i]; double avg_peak = (highs[idx1]+highs[idx2])/2; double tolerance = avg_peak * m_triangle_tolerance; if(MathAbs(highs[idx1]-highs[idx2]) > tolerance) return(false); double height = avg_peak - min_low; if(height < avg_peak * m_mw_depth_factor) return(false); return(true); }
Шаг 11. Выявите паттерн W (двойное дно)
Паттерн W — обратный вариант M: два свинговых минимума близкой глубины с вершиной между ними. Мы используем ту же логику, но анализируем свинговые минимумы и проверяем высоту наибольшего максимума между ними. Этот паттерн указывает на накопление и часто приводит к бычьим разворотам. Как и для паттерна M, коэффициент глубины обеспечивает выделение только значимых двойных доньев.
//+------------------------------------------------------------------+ //| Detects W (double bottom) pattern | //+------------------------------------------------------------------+ bool IsW(const double &highs[], const double &lows[], const int total) { if(total < m_min_bars) return(false); int swing_highs[], swing_lows[]; FindSwings(highs,lows,total,swing_highs,swing_lows); if(ArraySize(swing_lows)<2) return(false); int idx1 = swing_lows[0]; int idx2 = swing_lows[ArraySize(swing_lows)-1]; if(idx2-idx1 < m_swing_distance*2) return(false); double max_high = 0; for(int i=idx1; i<=idx2; i++) if(highs[i] > max_high) max_high = highs[i]; double avg_valley = (lows[idx1]+lows[idx2])/2; double tolerance = avg_valley * m_triangle_tolerance; if(MathAbs(lows[idx1]-lows[idx2]) > tolerance) return(false); double height = max_high - avg_valley; if(height < avg_valley * m_mw_depth_factor) return(false); return(true); }
Шаг 12. Основная функция распознавания, возвращающая название паттерна
Публичный метод DetectInternalBaseShape выполняет проверки в порядке специфичности паттернов (сначала треугольники, затем прямоугольники, затем M/W). Если баров недостаточно или ни один паттерн не подходит, метод возвращает "undefined". Благодаря этому метки получают только четкие и надежно распознанные геометрические структуры; система не присваивает категорию принудительно, если паттерн неоднозначен. Порядок важен: при узком диапазоне треугольник может соответствовать и критериям прямоугольника, но треугольники более специфичны и должны иметь приоритет.
//+------------------------------------------------------------------+ //| Detects internal base shape and returns string | //+------------------------------------------------------------------+ string DetectInternalBaseShape(const double &highs[], const double &lows[], const int total) { if(total < m_min_bars) return("undefined (too few bars)"); if(IsAscendingTriangle(highs,lows,total)) return("ascending triangle"); if(IsDescendingTriangle(highs,lows,total)) return("descending triangle"); if(IsSymmetricalTriangle(highs,lows,total)) return("symmetrical triangle"); if(IsRectangle(highs,lows,total)) return("rectangle"); if(IsM(highs,lows,total)) return("M"); if(IsW(highs,lows,total)) return("W"); return("undefined"); }
Интеграция в основную программу — LiquidityZoneReaction.mq5
Теперь, когда класс детектора геометрии готов, нам нужно подключить его к существующему индикатору зон ликвидности. Интеграция требует добавления всего нескольких строчек кода, но значительно повышает полезность индикатора. Основной индикатор уже обнаруживает зоны по соотношению размеров свечей старшего таймфрейма. После создания каждой зоны мы добавляем вызов детектора геометрии и передаем ему бары младшего таймфрейма, попадающие во временной интервал базовой свечи.
Шаг 1. Подключите заголовочный файл детектора геометрии и создайте экземпляр
В начале основного файла индикатора добавьте директиву include с путем к подпапке. Затем объявите глобальный экземпляр CGeometryDetector. Благодаря этому детектор доступен во всем коде индикатора. Глобальный экземпляр позволяет избежать неэффективной повторной инициализации объекта при каждом обновлении зоны.
//+------------------------------------------------------------------+ //| LiquidityZoneReaction.mq5 | //| Copyright 2025, Clemence Benjamin | //| https://www.mql5.com/ru/users/billionaire2024/seller | //+------------------------------------------------------------------+ #include <GeometryTools/GeometryDetection.mqh> //--- Geometry detector instance CGeometryDetector geoDetector;
Шаг 2. Добавьте входные параметры для распознавания геометрии
Мы добавляем входные параметры для проверки горизонтальности стороны треугольника, допуска прямоугольника, глубины M/W, расстояния для поиска свингов и минимального количества баров. Они отображаются в окне свойств индикатора, что позволяет трейдерам оптимизировать распознавание для конкретного рынка без перекомпиляции. Настройки по умолчанию тщательно подобраны для типичных валютных пар, однако пользователям, торгующим криптовалютами или индексами, может потребоваться их скорректировать.
input double Geo_TriangleTolerance = 0.005; // Triangle flatness tolerance (0.005 = 0.5%) input double Geo_RectangleTolerance = 0.01; // Rectangle range tolerance (1%) input double Geo_MWDepthFactor = 0.005; // M/W pattern depth factor (0.5%) input int Geo_SwingDistance = 2; // Bars between swing points input int Geo_MinBars = 6; // Minimum bars inside base candle
Шаг 3. Настройте детектор в обработчике событий OnInit()
В обработчике событий OnInit() вызовите метод Configure() детектора, передав ему заданные пользователем значения входных параметров. Так настройки передаются экземпляру детектора до начала обработки зон. Размещение этого кода в OnInit гарантирует готовность детектора до первого обновления зоны.
//--- Configure geometry detector
geoDetector.Configure(Geo_TriangleTolerance, Geo_RectangleTolerance,
Geo_MWDepthFactor, Geo_SwingDistance, Geo_MinBars);Шаг 4. Вспомогательная функция для получения баров в пределах временного интервала
Функция GetBarsInInterval() копирует максимумы, минимумы, цены закрытия и временные метки для заданных начального и конечного значений типа datetime. Она использует iBarShift для определения индексов баров, а затем считывает ценовые данные. Это необходимо для получения именно тех баров младшего таймфрейма, которые попадают во временной интервал базовой свечи. Функция возвращает false, если баров недостаточно (менее 3), чтобы детектор геометрии не запускался при нехватке данных.
//+------------------------------------------------------------------+ //| Copies bars inside a time interval on current timeframe | //+------------------------------------------------------------------+ bool GetBarsInInterval(datetime start, datetime end, double &highs[], double &lows[], double &closes[], datetime ×[]) { int start_idx = iBarShift(Symbol(), PERIOD_CURRENT, start); int end_idx = iBarShift(Symbol(), PERIOD_CURRENT, end); if(start_idx < 0 || end_idx < 0) return(false); int total = MathAbs(start_idx - end_idx) + 1; if(total < 3) return(false); ArrayResize(highs, total); ArrayResize(lows, total); ArrayResize(closes, total); ArrayResize(times, total); for(int i = 0; i < total; i++) { int idx = start_idx + i; highs[i] = iHigh(Symbol(), PERIOD_CURRENT, idx); lows[i] = iLow(Symbol(), PERIOD_CURRENT, idx); closes[i] = iClose(Symbol(), PERIOD_CURRENT, idx); times[i] = iTime(Symbol(), PERIOD_CURRENT, idx); } return(true); }
Шаг 5. Вызовите детектор геометрии при создании зоны
В UpdateZones() после заполнения структуры зоны вычислите время окончания базовой свечи, получите бары младшего таймфрейма и вызовите geoDetector.DetectInternalBaseShape(). Возвращаемая строка с названием паттерна сохраняется в z.shape и затем отображается на графике. Обратите внимание: если бары не найдены, зона помечается как "undefined (no bars)", чтобы отличить отсутствие данных от ситуации, когда паттерн не удалось определить.
datetime base_end = z.start_time + htfPeriodSeconds; if(GetBarsInInterval(z.start_time, base_end, highs_in, lows_in, closes_in, times_in)) z.shape = geoDetector.DetectInternalBaseShape(highs_in, lows_in, ArraySize(highs_in)); else z.shape = "undefined (no bars)";
Шаг 6. Определите паттерн формирования зоны (треугольник старшего таймфрейма)
Функция DetectTriangleOrigin() анализирует бары старшего таймфрейма вокруг базовой и импульсной свечей. Она проверяет, сформировалась ли сама зона из восходящего или нисходящего треугольника, добавляя еще один слой оценки силы зоны. Эта оценка не зависит от внутренней геометрии: у зоны может быть сильный паттерн формирования (треугольник), но слабая внутренняя консолидация (прямоугольник). Общая оценка таких зон все равно обозначается как "weak", поскольку одной силы паттерна формирования недостаточно для гарантированной реакции.
z.origin_shape = DetectTriangleOrigin(htf_high, htf_low, htf_time, base_idx, impulse_idx, true);
Шаг 7. Отобразите метки паттернов на графике
Функция DrawZone() изменена так, чтобы принимать строки с названиями внутреннего паттерна и паттерна формирования зоны. Она создает текстовые объекты внутри прямоугольника и над ним. Название внутреннего паттерна отображается белым цветом по центру зоны. Название паттерна формирования зоны отображается желтым цветом над ней; если это треугольник, добавляется метка "STRONG". Текстовые объекты получают уникальные имена на основе времени начала зоны, чтобы избежать конфликтов при ее перерисовке.
//--- Internal shape label (inside rectangle) if(shape != "none" && shape != "" && StringFind(shape, "undefined") == -1) { string txt_shape = "Shape_" + IntegerToString(start_time); if(ObjectFind(0, txt_shape) < 0) { double y_pos = (price_top + price_bottom) / 2; if(ObjectCreate(0, txt_shape, OBJ_TEXT, 0, start_time, y_pos)) { ObjectSetString(0, txt_shape, OBJPROP_TEXT, shape); ObjectSetInteger(0, txt_shape, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, txt_shape, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, txt_shape, OBJPROP_BACK, false); } } }
Шаг 8. Дополните алерты и записи журнала сведениями о геометрии
При появлении сигнала разворота в алерте и журнале указываются внутренний паттерн и паттерн формирования зоны. Это позволяет сразу понять причину сигнала, не покидая график и не открывая свойства индикатора. Со временем вы начнете замечать, какие сочетания паттернов (например, восходящий треугольник внутри базовой свечи + восходящий треугольник при формировании зоны) дают наиболее надежные реакции.
//--- Build alert message with geometry details string msg = StringFormat("DEMAND ZONE BUY | %s %s | Internal: %s | Origin: %s", Symbol(), EnumToString(_Period), zones[z].shape, zones[z].origin_shape); //--- Alert popup if(TimeArray[signal_bar] != lastAlertTime) { Alert(msg); lastAlertTime = TimeArray[signal_bar]; } //--- Journal entry Print(msg);
Полный исходный код индикатора приведен в приложениях. Скомпилируйте код и добавьте полученный индикатор на график, чтобы увидеть метки геометрических фигур. Каждая зона ликвидности теперь раскрывает свою внутреннюю структуру, а каждый алерт содержит сведения о геометрии, необходимые для принятия торговых решений с высокой вероятностью успеха.
Тестирование и результаты
Чтобы протестировать распознавание геометрии, добавьте индикатор на любой график и задайте для обнаружения зон старший таймфрейм (например, H1). Затем установите для текущего графика младший таймфрейм (например, M5). Индикатор отобразит каждую зону ликвидности прямоугольником. Внутри каждого прямоугольника вы увидите метку внутреннего паттерна. Над прямоугольником вы увидите оценку силы паттерна формирования зоны (STRONG или WEAK).
Для быстрой проверки используйте Тестер стратегий в визуальном режиме. Запустите индикатор на исторических данных и проследите за появлением паттернов. Вы также можете наблюдать за работой индикатора в реальном времени на демо-счете. Отрегулируйте входные параметры — Geo_TriangleTolerance, Geo_RectangleTolerance, Geo_MWDepthFactor, Geo_SwingDistance и Geo_MinBars, — чтобы точно настроить распознавание под свой стиль торговли.
В наших тестах при допусках по умолчанию детектор правильно распознавал треугольники примерно в 70% зон, проверенных вручную. Прямоугольники чаще всего становились резервным вариантом классификации. Паттерны M и W появлялись реже, что ожидаемо: паттерны двойной вершины и двойного дна внутри одной базовой свечи менее распространены. Уменьшив значение Geo_MWDepthFactor до 0,002, мы смогли выявить менее глубокие паттерны.

Рис. 3. Визуализация индикатора с автоматическим распознаванием геометрии и отображением меток на графике
Ниже приведен фрагмент журнала визуализации Тестера стратегий, показывающий, как система обнаруживает и записывает геометрические структуры в реальном времени. Каждая запись фиксирует подтвержденное событие обнаружения и содержит классификацию внутреннего паттерна и соответствующий торговый сигнал.
2026.03.30 08:59:36.456 2020.03.10 03:04:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 08:59:39.538 2020.03.10 04:00:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 08:59:39.538 2020.03.10 04:00:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:00:07.833 2020.03.10 08:09:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:00:07.833 2020.03.10 08:09:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:00:39.817 2020.03.10 12:24:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:00:39.817 2020.03.10 12:24:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:00:45.443 2020.03.10 13:00:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:00:45.443 2020.03.10 13:00:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:01:06.519 2020.03.10 15:27:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:01:06.519 2020.03.10 15:27:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: rectangle | Origin: none 2026.03.30 09:04:42.988 2020.03.12 08:29:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: descending triangle | Origin: none 2026.03.30 09:04:42.988 2020.03.12 08:29:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: descending triangle | Origin: none 2026.03.30 09:04:46.930 2020.03.12 09:03:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: descending triangle | Origin: none 2026.03.30 09:04:46.931 2020.03.12 09:03:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: descending triangle | Origin: none 2026.03.30 09:05:13.649 2020.03.12 12:49:00 Alert: DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: descending triangle | Origin: none 2026.03.30 09:05:13.649 2020.03.12 12:49:00 DEMAND ZONE BUY | EURUSD PERIOD_M5 | Internal: descending triangle | Origin: noneПри работе в реальном времени эти события не только записываются в журнал, но и сразу вызывают алерты, позволяя реагировать по мере формирования структуры, а не постфактум. В каждой записи есть две временные метки:
- первая временная метка (2026.03.30 …) отражает время выполнения в среде тестера;
- вторая временная метка (2020.03.10 / 2020.03.12 …) соответствует времени исторических рыночных данных, на которых была распознана геометрия.
Это разграничение важно: оно подтверждает, что система работает с историческими данными, сохраняя при моделировании оперативность реакции в реальном времени.
Заключение
Мы создали полноценную систему распознавания геометрии, готовую к использованию и напрямую интегрируемую в существующий процесс работы с зонами ликвидности. Больше не требуется длительная ручная проверка каждой базовой свечи с субъективной оценкой ее структуры. Ее заменяет автоматизированный и настраиваемый механизм с воспроизводимыми результатами, который мгновенно обозначает внутреннюю структуру каждой зоны — восходящий треугольник, нисходящий треугольник, прямоугольник, M, W либо неопределенная структура — и оценивает силу паттерна ее формирования.
Теперь в вашем распоряжении три конкретных результата работы:
- полнофункциональный индикатор на языке MQL5, отображающий зоны со сведениями об их геометрии на любом графике и добавляющий информацию о паттернах в алерты и записи журнала;
- пригодный для повторного использования класс детектора геометрии (GeometryDetection.mqh), который можно подключить к другим проектам — от сканеров до советников — без необходимости переписывать код распознавания паттернов;
- понятная и проверяемая система разграничения сильных зон (сформированных из треугольника) и слабых, позволяющая фильтровать сигналы, проверять эффективность паттернов на исторических данных и расширять анализ на разные символы и таймфреймы без дополнительной ручной работы.
Каждая зона ликвидности на вашем графике теперь раскрывает свою внутреннюю историю. Ответ на вопрос "Какой паттерн находится внутри этой базовой свечи?" появляется в момент отображения зоны. Это не просто индикатор, а инструмент поддержки принятия решений, который превращает данные о зонах ликвидности в информацию для практических действий.
На этом путь не заканчивается. В приведенных ниже основных выводах собраны важнейшие идеи рассмотренного кода и концепций. Затем в разделе "Приложения" перечислены два файла, необходимые для начала работы. Предлагаю вам скомпилировать индикатор, добавить его на свои графики и изучить, как детектор геометрии работает с разными символами и таймфреймами. Делитесь своими наблюдениями, вопросами и открытиями в разделе комментариев — ваши отзывы помогают совершенствовать инструмент и углублять наше общее понимание геометрии рынка. Удачного программирования! Следите за обновлениями до следующей публикации.
Основные выводы
| Основные выводы | Описание |
|---|---|
| Внутренняя геометрия имеет значение | Фигура внутри базовой свечи определяет силу зоны ликвидности. Треугольники указывают на накопление, а прямоугольники — на равновесие. |
| Разделение слоев распознавания | Отделяйте обнаружение зон (старший таймфрейм) от анализа геометрии (младший таймфрейм), чтобы код оставался чистым и удобным для сопровождения. |
| Настраиваемые допуски | Рынки различаются. Дайте пользователям возможность настраивать допуски горизонтальности и коэффициенты глубины под выбранные символ и таймфрейм. |
| Обнаружение свинговых точек с учетом расстояния | Использование минимального расстояния в барах снижает шум и улучшает распознавание паттернов. |
| Дополнение алертов и записей журнала | Добавление распознанного паттерна в сигналы помогает трейдерам изучать систему и постепенно проверять ее работу. |
| Относительные допуски лучше фиксированных значений в пипсах | Задание допусков долей цены позволяет детектору работать со всеми символами без повторной калибровки. |
| Порядок распознавания имеет значение | Сначала проверяйте треугольники, затем прямоугольники, а затем паттерны M/W, чтобы избежать ошибочной классификации. |
| Требование минимального количества баров предотвращает ложные срабатывания | Требование не менее 6 баров внутри базовой свечи позволяет избежать ненадежного распознавания паттернов при слишком малом объеме данных. |
| Сила паттерна формирования зоны дополняет контекст | Зона, сформированная из треугольника на старшем таймфрейме, сильнее зоны без такого паттерна формирования независимо от внутренней геометрии. |
| Линейная регрессия улучшает распознавание симметричных треугольников | Расчет наклона по всем свинговым точкам надежнее сравнения только первого и последнего значений. |
| Требование двух касаний для прямоугольников | Требование как минимум двух касаний каждой из границ не позволяет классифицировать небольшие диапазоны как прямоугольники. |
| Коэффициент глубины для паттернов M и W | Минимальный коэффициент глубины позволяет отмечать только значимые двойные вершины и двойные донья, а не незначительные колебания. |
| "undefined" — допустимый результат | Принудительное присвоение метки при отсутствии четкого паттерна приводит к ложной уверенности. Возвращать "undefined" — честно и полезно. |
| Модульная архитектура упрощает тестирование | Выделение детектора геометрии в отдельный заголовочный файл позволяет независимо тестировать его и повторно использовать в других индикаторах или советниках. |
| Наглядное отображение ускоряет обучение | Отображение паттерна непосредственно на графике позволяет трейдеру научиться его распознаванию быстрее, чем при любом самостоятельном анализе. |
Приложения
| Имя файла | Тип | Версия | Описание |
|---|---|---|---|
| GeometryDetection.mqh | Подключаемый файл | 1.00 | Класс настраиваемого детектора геометрии. Содержит всю логику распознавания паттернов: обнаружение свинговых точек, расчет наклона, проверку горизонтальности и классификацию восходящих, нисходящих и симметричных треугольников, прямоугольников, паттернов M и W. Инструкции по использованию: Чтобы сохранить порядок в стандартном каталоге, поместите файл в подпапку MQL5/Include/ по пути MQL5/Include/GeometryTools/GeometryDetection.mqh. Затем подключите его в своем индикаторе или советнике с помощью директивы #include GeometryTools/GeometryDetection.mqh. Отдельная компиляция заголовочного файла не требуется. Все параметры распознавания (допуски, расстояние для поиска свингов, минимальное количество баров) можно настроить с помощью метода Configure(). |
| Liquidity_Zone_Reaction_Indicator.mq5 | Индикатор | 4.00 | Основной индикатор зон ликвидности со встроенным распознаванием геометрии. Расширяет исходную логику обнаружения зон, автоматически анализируя внутреннюю структуру каждой базовой свечи. Он отображает каждую зону спроса или предложения прямоугольником, указывает внутри него внутреннюю геометрию (например, "ascending triangle"), а над ним — силу паттерна формирования зоны (например, "ascending triangle (STRONG)"). Алерты и записи журнала теперь содержат внутренний паттерн и паттерн формирования зоны. Инструкции по использованию: Поместите этот файл в папку MQL5/Indicators/. Перед компиляцией убедитесь, что необходимый заголовочный файл GeometryDetection.mqh находится в нужной подпапке (например, MQL5/Include/GeometryTools/) и что в исходном коде индикатора указана соответствующая директива подключения (например, #include <GeometryTools/GeometryDetection.mqh>). Откройте индикатор в MetaEditor и нажмите "Компилировать" (F7). После успешной компиляции добавьте индикатор на любой график. Индикатор работает на всех таймфреймах и со всеми символами. Входные параметры позволяют точно настроить чувствительность распознавания геометрии без перекомпиляции. |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/21817
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Создание системы торговой аналитики (Часть 2): Как фиксировать закрытые сделки и передавать данные в формате JSON с помощью MQL5
Создание традиционного индикатора Ренко с наложением на график в MQL5
Версионирование параметров советника в MQL5 с помощью файлов
Нейросети в трейдинге: Habi — быстрое принятие решений без сложного планирования
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования