Свинговые экстремумы и откаты в MQL5 (Часть 1): Разработка мультитаймфреймового индикатора
Содержание
- Введение
- Обзор автоматизации
- Начало работы
- Результаты тестирования на исторических данных
- Заключение
Введение
Ранее мы разработали индикатор свинговых экстремумов и откатов (Swing Extremes and the Pullback Indicator) путем систематического выявления свинговых максимумов и минимумов в ценовом движении младшего таймфрейма (LTF). Подход был сосредоточен на выявлении и разметке краткосрочных структурных сдвигов — более высоких максимумов, более низких минимумов, откатов и пауз в импульсном движении — для определения возможных разворотов до того, как они станут очевидными на старших таймфреймах. Сочетание логики обнаружения свингов с правилами подтверждения откатов позволило создать систему, преобразующую необработанную волатильность младшего таймфрейма (LTF) в структурированную и понятную модель поведения рынка.
Следующий этап — полная автоматизация индикатора путем встраивания структурной логики непосредственно в код. Для этого необходимо алгоритмически определять подтвержденные свинговые точки, фильтровать шум, подтверждать откаты с помощью формальных условий и динамически обновлять структуру в реальном времени. Благодаря автоматизации система непрерывно анализирует и интерпретирует рыночную структуру младшего таймфрейма (LTF) без ручного вмешательства, обеспечивая объективное, последовательное и более оперативное выявление разворотов и повышая точность исполнения сделок и эффективность принятия решений.
Обзор автоматизации
С точки зрения автоматизации экстремальное медвежье движение преобразуется в точную модель исполнения сделок на основе правил. Когда цена резко опускается ниже последнего минимума LTF и график обновляется, система проверяет, находятся ли LTF_LastHigh и LTF_LastLow выше текущей рыночной цены. Это подтверждает структурное смещение ниже недавнего диапазона. После выполнения этих условий логика интерпретирует движение как истощение, а не продолжение, и автоматически исполняет сделку на покупку. Затем система использует LTF_LastHigh как уровень тейк-профита, рассчитывая на возврат цены к предыдущей структуре по модели возврата к среднему. Это полностью исключает субъективный фактор: сделка открывается строго при структурном дисбалансе и достижении заранее заданных пороговых значений, что обеспечивает последовательное исполнение при статистическом перерастяжении медвежьего движения.

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

Начало работы
//+------------------------------------------------------------------+ //| Auto Swing Extremes.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include <Trade/Trade.mqh> CTrade trade; //+------------------------------------------------------------------+ //| Input Parameters | //+------------------------------------------------------------------+ input ENUM_TIMEFRAMES HTF = PERIOD_H1; // Higher Timeframe input ENUM_TIMEFRAMES LTF = PERIOD_M5; // Lower Timeframe input int SwingBars = 3; // Bars for swing detection input double RiskPercent = 1.0; // Risk per trade (%) input int Stop_Loss = 2000; // StopLoss input bool Visualize = true; // Show swing points & structure //+------------------------------------------------------------------+ //| Swing Point Structure | //+------------------------------------------------------------------+ struct SwingPoint { datetime time; double price; int type; // 1 = High, -1 = Low int barIndex; void Reset() { time = 0; price = 0.0; type = 0; barIndex = 0; } };
Для начала инициализируется торговая среда: подключается файл <Trade/Trade.mqh> и создается объект CTrade, предоставляющий структурированный способ программного исполнения сделок и управления ими. Затем определяются ключевые входные параметры: старший таймфрейм (HTF) и младший таймфрейм (LTF) для мультитаймфреймового анализа структуры, количество SwingBars для обнаружения подтвержденных свинговых максимумов и минимумов, процент риска по счету на сделку, фиксированное значение стоп-лосса и переключатель визуализации, позволяющий при необходимости отображать структурные элементы на графике. Эти параметры делают систему настраиваемой, позволяя стратегии адаптироваться к различным рыночным условиям, символам и предпочтениям трейдеров без изменения основной логики.
Затем объявляется структура SwingPoint для формального представления рыночной структуры в коде. Эта структура хранит временную метку свинга, ценовой уровень, тип (1 для свингового максимума и -1 для свингового минимума) и индекс соответствующего бара, объединяя все необходимые данные для отслеживания структурных точек разворота. Функция Reset() позволяет безопасно очистить и повторно использовать свинговую точку, сохраняя целостность данных при обновлениях. Организация информации о свингах в структурированном объекте закладывает основу для автоматического обнаружения рыночной структуры.
//+------------------------------------------------------------------+ //| Market Structure States | //+------------------------------------------------------------------+ enum STRUCTURE_STATE { STRUCT_NEUTRAL, STRUCT_BULLISH, STRUCT_BEARISH }; //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ SwingPoint htf_lastHigh, htf_prevHigh; SwingPoint htf_lastLow, htf_prevLow; SwingPoint ltf_lastHigh, ltf_prevHigh; SwingPoint ltf_lastLow, ltf_prevLow; STRUCTURE_STATE htfBias = STRUCT_NEUTRAL; STRUCTURE_STATE ltfStructure = STRUCT_NEUTRAL; datetime lastHtfUpdate = 0; datetime lastLtfUpdate = 0; // Track last traded swing to avoid multiple entries on same swing datetime lastBuySwingTime = 0; datetime lastSellSwingTime = 0; double lastBuySwingPrice = 0; double lastSellSwingPrice = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Validate timeframe combination if(PeriodSeconds(HTF) <= PeriodSeconds(LTF)) { Alert("HTF must be higher than LTF!"); return INIT_PARAMETERS_INCORRECT; } // Initialize swing points htf_lastHigh.Reset(); htf_prevHigh.Reset(); htf_lastLow.Reset(); htf_prevLow.Reset(); ltf_lastHigh.Reset(); ltf_prevHigh.Reset(); ltf_lastLow.Reset(); ltf_prevLow.Reset(); // Initialize trade tracking lastBuySwingTime = 0; lastSellSwingTime = 0; lastBuySwingPrice = 0; lastSellSwingPrice = 0; // Initial structure detection UpdateHTFStructure(); UpdateLTFStructure(); return INIT_SUCCEEDED; }
В этом разделе определяется основа структурной логики, задающая интерпретацию направления рынка стратегией. Перечисление STRUCTURE_STATE определяет три возможных состояния рынка — нейтральное, бычье и медвежье. Это позволяет в любой момент времени четко классифицировать направленность старшего таймфрейма (HTF) и структуру младшего таймфрейма (LTF). Глобальные переменные SwingPoint объявляются для отслеживания последних и предыдущих максимумов и минимумов на старшем таймфрейме (HTF) и младшем таймфрейме (LTF). Это позволяет сравнивать последовательные структурные точки, например более высокие максимумы и более низкие минимумы. Дополнительные переменные состояния, такие как htfBias и ltfStructure, хранят активное структурное направление. Временные метки lastHtfUpdate и lastLtfUpdate обеспечивают обновление структуры только при формировании новых баров, поддерживая эффективность и предотвращая избыточные пересчеты.
В глобальной области видимости также определены защитные механизмы управления торговлей, предотвращающие повторное открытие сделок с одного и того же свингового уровня. Благодаря сохранению значений lastBuySwingTime, lastSellSwingTime и соответствующих им цен система избегает исполнения нескольких сделок по одинаковым структурным сигналам. В функции OnInit() программа сначала проверяет, действительно ли выбранный старший таймфрейм (HTF) выше младшего таймфрейма (LTF), обеспечивая корректную мультитаймфреймовую иерархию. Затем программа сбрасывает все структуры свингов и переменные отслеживания сделок, обеспечивая корректное начальное состояние. Затем программа выполняет начальное сканирование структуры с помощью функций UpdateHTFStructure() и UpdateLTFStructure(), синхронизируя систему с текущими рыночными условиями до начала реальной торговли.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Clean up objects ObjectsDeleteAll(0, "MS_"); ChartRedraw(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { static datetime lastLtfBar = 0; datetime currentLtfBar = iTime(_Symbol, LTF, 0); // Process on new LTF bar if(currentLtfBar != lastLtfBar) { lastLtfBar = currentLtfBar; // Update HTF bias if needed (on new HTF bar) if(TimeCurrent() - lastHtfUpdate >= PeriodSeconds(HTF)) { UpdateHTFStructure(); lastHtfUpdate = TimeCurrent(); } // Store previous LTF structure for comparison STRUCTURE_STATE prevLtfStructure = ltfStructure; // Update LTF structure UpdateLTFStructure(); // Check for structure breaks CheckStructureBreak(); // Try to execute trades if structure changed or conditions met if(ltfStructure != prevLtfStructure || (ltf_lastHigh.price > 0 && ltf_lastLow.price > 0)) { TryExecuteTrade(); } // Update visualization if(Visualize) UpdateVisualization(); } }
Здесь код управляет очисткой ресурсов и ходом выполнения советника в реальном времени. В функции OnDeinit() удаляются все объекты графика с префиксом "MS_", чтобы при отсоединении советника очистить графические элементы, связанные со структурой. Затем выполняется перерисовка графика для визуальной согласованности. В функции OnTick() система выполняет логику только при формировании нового бара младшего таймфрейма (LTF), сравнивая временные метки. Это предотвращает избыточные вычисления на каждом тике. При формировании нового бара система при необходимости обновляет направленность старшего таймфрейма (HTF), обновляет структуру младшего таймфрейма (LTF), проверяет пробои структуры и сравнивает предыдущее и текущее состояния структуры. Если происходит структурный сдвиг или имеются подтвержденные данные о свинговых экстремумах, система пытается исполнить сделку с помощью функции TryExecuteTrade(). Если визуализация включена, система обновляет графические объекты, отображая последнее состояние структуры и обеспечивая синхронизацию логики с визуальной обратной связью.
//+------------------------------------------------------------------+ //| Update Higher Timeframe Structure | //+------------------------------------------------------------------+ void UpdateHTFStructure() { // Get HTF data MqlRates htfRates[]; ArraySetAsSeries(htfRates, true); CopyRates(_Symbol, HTF, 0, 100, htfRates); if(ArraySize(htfRates) < SwingBars * 2 + 1) return; // Detect swing points on HTF for(int i = SwingBars; i < ArraySize(htfRates) - SwingBars; i++) { bool isHigh = true; bool isLow = true; // Check if current bar is swing high for(int j = 1; j <= SwingBars; j++) { if(htfRates[i].high <= htfRates[i-j].high || htfRates[i].high <= htfRates[i+j].high) { isHigh = false; } if(htfRates[i].low >= htfRates[i-j].low || htfRates[i].low >= htfRates[i+j].low) { isLow = false; } } // Update swing highs if(isHigh) { htf_prevHigh = htf_lastHigh; htf_lastHigh.time = htfRates[i].time; htf_lastHigh.price = htfRates[i].high; htf_lastHigh.type = 1; htf_lastHigh.barIndex = i; } // Update swing lows if(isLow) { htf_prevLow = htf_lastLow; htf_lastLow.time = htfRates[i].time; htf_lastLow.price = htfRates[i].low; htf_lastLow.type = -1; htf_lastLow.barIndex = i; } } // Update HTF bias htfBias = DetectStructure(htf_lastHigh, htf_prevHigh, htf_lastLow, htf_prevLow); } //+------------------------------------------------------------------+ //| Update Lower Timeframe Structure | //+------------------------------------------------------------------+ void UpdateLTFStructure() { // Get LTF data MqlRates ltfRates[]; ArraySetAsSeries(ltfRates, true); CopyRates(_Symbol, LTF, 0, 100, ltfRates); if(ArraySize(ltfRates) < SwingBars * 2 + 1) return; // Detect swing points on LTF for(int i = SwingBars; i < ArraySize(ltfRates) - SwingBars; i++) { bool isHigh = true; bool isLow = true; // Check if current bar is swing high for(int j = 1; j <= SwingBars; j++) { if(ltfRates[i].high <= ltfRates[i-j].high || ltfRates[i].high <= ltfRates[i+j].high) { isHigh = false; } if(ltfRates[i].low >= ltfRates[i-j].low || ltfRates[i].low >= ltfRates[i+j].low) { isLow = false; } } // Update swing highs if(isHigh) { ltf_prevHigh = ltf_lastHigh; ltf_lastHigh.time = ltfRates[i].time; ltf_lastHigh.price = ltfRates[i].high; ltf_lastHigh.type = 1; ltf_lastHigh.barIndex = i; } // Update swing lows if(isLow) { ltf_prevLow = ltf_lastLow; ltf_lastLow.time = ltfRates[i].time; ltf_lastLow.price = ltfRates[i].low; ltf_lastLow.type = -1; ltf_lastLow.barIndex = i; } } // Update LTF structure ltfStructure = DetectStructure(ltf_lastHigh, ltf_prevHigh, ltf_lastLow, ltf_prevLow); }
Функция UpdateHTFStructure() анализирует ценовые данные старшего таймфрейма для выявления подтвержденных свинговых максимумов и свинговых минимумов на основе заданного параметра SwingBars. Она получает последние 100 свечей старшего таймфрейма (HTF), проверяет наличие достаточных данных, а затем анализирует каждый подходящий бар, чтобы определить, является ли он структурным экстремумом. Бар классифицируется как свинговый максимум, если его максимум превышает максимумы окружающих баров в заданном диапазоне, и как свинговый минимум, если его минимум ниже минимумов соседних баров. Когда подтверждается новый свинг, предыдущий свинг сохраняется, а последний обновляется с указанием времени, цены, типа и индекса. После обработки всех кандидатов функция определяет общую направленность старшего таймфрейма — бычью, медвежью или нейтральную — сравнивая последние и предыдущие свинговые максимумы и минимумы с помощью DetectStructure().
Функция UpdateLTFStructure() применяет ту же логику на младшем таймфрейме, используя тот же процесс выявления свингов для более детализированных ценовых данных. Она оценивает каждый бар в пределах допустимого диапазона, подтверждает структурные максимумы и минимумы симметричными сравнениями и соответствующим образом обновляет сохраненные переменные свингов LTF. Сохраняя последние и предыдущие свинговые точки, система может определить, формирует ли рынок более высокие максимумы, более низкие минимумы или переходит к структурному сдвигу. На заключительном этапе с помощью DetectStructure() задается обновленное состояние структуры младшего таймфрейма (LTF). Это обеспечивает работу торговой логики и обнаружения разворотов на основе постоянно обновляемой и объективно определенной рыночной структуры обоих таймфреймов.
//+------------------------------------------------------------------+ //| Detect Market Structure | //+------------------------------------------------------------------+ STRUCTURE_STATE DetectStructure(SwingPoint &lastHigh, SwingPoint &prevHigh, SwingPoint &lastLow, SwingPoint &prevLow) { // Need at least two highs and two lows if(lastHigh.price == 0 || prevHigh.price == 0 || lastLow.price == 0 || prevLow.price == 0) return STRUCT_NEUTRAL; bool isHigherHigh = lastHigh.price > prevHigh.price; bool isHigherLow = lastLow.price > prevLow.price; bool isLowerLow = lastLow.price < prevLow.price; bool isLowerHigh = lastHigh.price < prevHigh.price; if(isHigherHigh && isHigherLow) return STRUCT_BULLISH; if(isLowerLow && isLowerHigh) return STRUCT_BEARISH; return STRUCT_NEUTRAL; }Функция DetectStructure() определяет текущую рыночную структуру, сравнивая последние и предыдущие свинговые максимумы и минимумы. Сначала функция проверяет наличие достаточных данных по свингам: необходимы как минимум два подтвержденных свинговых максимума и два подтвержденных свинговых минимума. В противном случае она возвращает нейтральное состояние. Затем функция оценивает развитие структуры: если последний свинговый максимум выше предыдущего и при этом последний свинговый минимум выше предыдущего, рынок классифицируется как бычий. И напротив, если последний свинговый минимум ниже предыдущего и при этом последний свинговый максимум ниже предыдущего, структура считается медвежьей. Если ни одно условие не выполняется полностью, функция по умолчанию устанавливает нейтральное состояние, указывающее на консолидацию или переход структуры.
//+------------------------------------------------------------------+ //| New Sell Condition | //+------------------------------------------------------------------+ bool CheckSellCondition() { // Need valid LTF swing points if(ltf_lastHigh.price == 0 || ltf_lastLow.price == 0) return false; // Get current price double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); // Check if price is above both last high and last low bool priceAboveHigh = currentPrice > ltf_lastHigh.price; bool priceAboveLow = currentPrice > ltf_lastLow.price; // Check if this is a new swing (not already traded) bool isNewSwing = (ltf_lastHigh.time != lastSellSwingTime) || (ltf_lastHigh.price != lastSellSwingPrice); return (priceAboveHigh && priceAboveLow && isNewSwing); } //+------------------------------------------------------------------+ //| New Buy Condition | //+------------------------------------------------------------------+ bool CheckBuyCondition() { // Need valid LTF swing points if(ltf_lastLow.price == 0) return false; // Get current price double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Check if price is below last low bool priceBelowLow = currentPrice < ltf_lastLow.price; // Check if this is a new swing (not already traded) bool isNewSwing = (ltf_lastLow.time != lastBuySwingTime) || (ltf_lastLow.price != lastBuySwingPrice); return (priceBelowLow && isNewSwing); } //+------------------------------------------------------------------+ //| Execute trade | //+------------------------------------------------------------------+ void ExecuteTrade(ENUM_ORDER_TYPE tradeType, string symbol) { // Get current price double price = (tradeType == ORDER_TYPE_BUY) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID); price = NormalizeDouble(price, _Digits); // Calculate stop loss double sl = CalculateSL(tradeType == ORDER_TYPE_BUY); sl = NormalizeDouble(sl, _Digits); // Calculate take profit based on your requirements double tp = 0; if(tradeType == ORDER_TYPE_BUY) { // For Buy: TP at next structure level (last high) tp = (ltf_lastHigh.price > 0) ? ltf_lastHigh.price : price + (MathAbs(price - sl) * 2); } else if(tradeType == ORDER_TYPE_SELL) // ORDER_TYPE_SELL { // For Sell: TP at last low (as requested) tp = (ltf_lastLow.price > 0) ? ltf_lastLow.price : price - (MathAbs(price - sl) * 2); } tp = NormalizeDouble(tp, _Digits); // Ensure TP is valid (not too close to entry) double minDistance = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE) * 10; if(MathAbs(price - tp) < minDistance) { Print("TP too close to entry, adjusting..."); if(tradeType == ORDER_TYPE_BUY) tp = price + (MathAbs(price - sl) * 2); else tp = price - (MathAbs(price - sl) * 2); } // Calculate lot size based on risk double volume = CalculateLotSize(price, sl); // Ensure volume is within valid range double volume_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double volume_min = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double volume_max = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); // Normalize volume to step size volume = floor(volume / volume_step) * volume_step; volume = MathMax(volume, volume_min); volume = MathMin(volume, volume_max); // Prepare trade comment string comment = StringFormat("MS_%s_%s", (tradeType == ORDER_TYPE_BUY) ? "BUY" : "SELL", TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES)); // Execute trade using CTrade bool success = trade.PositionOpen(symbol, tradeType, volume, price, sl, tp, comment); if(success) { // Update swing tracking to avoid multiple entries if(tradeType == ORDER_TYPE_BUY) { lastBuySwingTime = ltf_lastLow.time; lastBuySwingPrice = ltf_lastLow.price; } else { lastSellSwingTime = ltf_lastHigh.time; lastSellSwingPrice = ltf_lastHigh.price; } Print(StringFormat("Trade Opened: %s | Price: %.5f | SL: %.5f | TP: %.5f | Lots: %.2f", (tradeType == ORDER_TYPE_BUY) ? "BUY" : "SELL", price, sl, tp, volume)); } else { Print("Trade failed: ", trade.ResultRetcodeDescription()); } } //+------------------------------------------------------------------+ //| Try Execute Trade | //+------------------------------------------------------------------+ void TryExecuteTrade() { // Check if position already exists if(PositionSelect(_Symbol)) { Print("Position already exists, waiting for closure..."); return; } // For Sell positions: Price above both last high and last low if(CheckSellCondition()) { // Optional: Check HTF bias filter if(htfBias == STRUCT_BEARISH || htfBias == STRUCT_NEUTRAL) { Print("SELL condition met: Price above LTF high and low"); OpenSell(); return; } } // For Buy positions: Price below last low if(CheckBuyCondition()) { // Optional: Check HTF bias filter if(htfBias == STRUCT_BULLISH || htfBias == STRUCT_NEUTRAL) { Print("BUY condition met: Price below LTF low"); OpenBuy(); return; } } }
Функции CheckSellCondition() и CheckBuyCondition() определяют структурные условия открытия сделок на основе смещения младшего таймфрейма (LTF). Для сетапа на продажу система сначала проверяет наличие подтвержденных данных по свингам, а затем определяет, находится ли текущая цена Bid выше последнего свингового максимума и свингового минимума LTF. Это указывает на бычье перерастяжение за пределы недавней структуры. Кроме того, система проверяет, не использовался ли этот свинг уже для сделки, сравнивая сохраненные значения его времени и цены. Это предотвращает повторные входы. Аналогично условие покупки подтверждает, что цена опустилась ниже последнего свингового минимума LTF, сигнализируя о медвежьем истощении. Кроме того, перед возвратом true проверяется актуальность свинга. В совокупности эти условия преобразуют структурные экстремумы в объективные сигналы входа, основанные на правилах, и обеспечивают принцип "одна сделка на один свинг".
Функция ExecuteTrade() отвечает за формирование сделки и управление рисками. Она определяет корректную цену входа (Ask для покупок и Bid для продаж), рассчитывает стоп-лосс отдельной функцией и динамически задает тейк-профит на основе структуры: последний свинговый максимум LTF используется как TP для сделок на покупку, а последний свинговый минимум LTF — как TP для сделок на продажу. Если структурные уровни TP недоступны или находятся слишком близко к цене входа, система по умолчанию использует резервный расчет на основе соотношения риска и вознаграждения. Размер позиции рассчитывается в соответствии с процентом риска по счету, а затем нормализуется с учетом требований брокера к минимальному, максимальному объему и шагу объема. Сделка исполняется с помощью объекта CTrade; при успешном исполнении сохраняются данные соответствующего свинга, чтобы предотвратить повторные входы на одном структурном уровне.
Затем функция TryExecuteTrade() выступает в роли финального механизма принятия решения. Сначала функция проверяет, открыта ли уже позиция по символу, чтобы избежать одновременного открытия нескольких сделок. Если позиция отсутствует, система оценивает условия продажи — цена выше последнего свингового максимума и минимума — и при необходимости фильтрует их с учетом направленности HTF. Сделки разрешаются только при согласованности структуры HTF с сигналом или при ее нейтральности. Если условия выполнены, инициируется ордер на продажу. Затем система оценивает условия покупки — цена ниже последнего свингового минимума, — также при необходимости фильтруя их по направленности HTF, соответствующей бычьей или нейтральной структуре. Этот многоуровневый процесс гарантирует, что сделки исполняются только при согласованности структурного смещения, актуальности свингов и более широкой рыночной направленности, обеспечивая дисциплинированную автоматизацию на основе структуры.
//+------------------------------------------------------------------+ //| Check Structure Break | //+------------------------------------------------------------------+ void CheckStructureBreak() { MqlRates current[]; ArraySetAsSeries(current, true); CopyRates(_Symbol, LTF, 0, 1, current); if(ArraySize(current) < 1) return; // Bullish structure break if(ltfStructure == STRUCT_BULLISH && current[0].close < ltf_lastLow.price) { ResetLTFStructure(); } // Bearish structure break if(ltfStructure == STRUCT_BEARISH && current[0].close > ltf_lastHigh.price) { ResetLTFStructure(); } } //+------------------------------------------------------------------+ //| Reset LTF Structure | //+------------------------------------------------------------------+ void ResetLTFStructure() { ltf_lastHigh.Reset(); ltf_prevHigh.Reset(); ltf_lastLow.Reset(); ltf_prevLow.Reset(); ltfStructure = STRUCT_NEUTRAL; // Also reset trade tracking lastBuySwingTime = 0; lastSellSwingTime = 0; lastBuySwingPrice = 0; lastSellSwingPrice = 0; } //+------------------------------------------------------------------+ //| Update Visualization | //+------------------------------------------------------------------+ void UpdateVisualization() { ObjectsDeleteAll(0, "MS_"); // Draw HTF swing points if(htf_lastHigh.price > 0) DrawSwingPoint(htf_lastHigh, "HTF_High", clrRed, HTF); if(htf_prevHigh.price > 0) DrawSwingPoint(htf_prevHigh, "HTF_PrevHigh", clrRed, HTF); if(htf_lastLow.price > 0) DrawSwingPoint(htf_lastLow, "HTF_Low", clrBlue, HTF); if(htf_prevLow.price > 0) DrawSwingPoint(htf_prevLow, "HTF_PrevLow", clrBlue, HTF); // Draw LTF swing points if(ltf_lastHigh.price > 0) DrawSwingPoint(ltf_lastHigh, "LTF_High", clrOrange, LTF); if(ltf_prevHigh.price > 0) DrawSwingPoint(ltf_prevHigh, "LTF_PrevHigh", clrOrange, LTF); if(ltf_lastLow.price > 0) DrawSwingPoint(ltf_lastLow, "LTF_Low", clrGreen, LTF); if(ltf_prevLow.price > 0) DrawSwingPoint(ltf_prevLow, "LTF_PrevLow", clrGreen, LTF); // Draw current price lines for reference double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK); CreateHorizontalLine("Current_Bid", currentBid, clrYellow, STYLE_DASH); CreateHorizontalLine("Current_Ask", currentAsk, clrYellow, STYLE_DASH); // Draw trade condition zones if(ltf_lastHigh.price > 0) CreateHorizontalLine("Sell_Zone_Min", ltf_lastHigh.price, clrRed, STYLE_SOLID); if(ltf_lastLow.price > 0) { CreateHorizontalLine("Buy_Zone_Max", ltf_lastLow.price, clrBlue, STYLE_SOLID); CreateHorizontalLine("Sell_TP_Level", ltf_lastLow.price, clrGreen, STYLE_DOT); } // Draw structure labels DrawStructureLabels(); }
Здесь код отслеживает целостность рыночной структуры младшего таймфрейма (LTF) и автоматически сбрасывает ее при пробое структуры. Функция CheckStructureBreak() получает последнюю свечу LTF и сравнивает цену ее закрытия с текущими структурными экстремумами. Если рынок находится в бычьей структуре, а цена закрывается ниже последнего свингового минимума, это сигнализирует о пробое вниз и запускает ResetLTFStructure(). Напротив, если рынок находится в медвежьей структуре, а цена закрывается выше последнего свингового максимума, структура также сбрасывается. Функция ResetLTFStructure() очищает все свинговые точки LTF, устанавливает нейтральное состояние структуры и сбрасывает переменные отслеживания сделок. Благодаря этому последующая логика учитывает только новые структурные формирования.
Функция UpdateVisualization() обеспечивает понятное визуальное представление в реальном времени свингов старшего и младшего таймфреймов, текущей цены и ключевых торговых зон. Сначала удаляются все существующие объекты с префиксом MS_, а затем маркерами с цветовой кодировкой отрисовываются все релевантные свинговые точки HTF и LTF. Текущие цены Bid и Ask отображаются желтыми штриховыми линиями, а торговые зоны — уровни покупки, продажи и тейк-профита — отрисовываются сплошными или точечными линиями.
//+------------------------------------------------------------------+ //| Draw Swing Point | //+------------------------------------------------------------------+ void DrawSwingPoint(SwingPoint &sp, string name, color clr, ENUM_TIMEFRAMES tf) { ObjectCreate(0, "MS_" + name, OBJ_ARROW, 0, sp.time, sp.price); ObjectSetInteger(0, "MS_" + name, OBJPROP_ARROWCODE, sp.type == 1 ? 218 : 217); ObjectSetInteger(0, "MS_" + name, OBJPROP_COLOR, clr); ObjectSetInteger(0, "MS_" + name, OBJPROP_WIDTH, 3); ObjectSetString(0, "MS_" + name, OBJPROP_TOOLTIP, StringFormat("%s: %.5f", sp.type == 1 ? "High" : "Low", sp.price)); } //+------------------------------------------------------------------+ //| Draw Structure Labels | //+------------------------------------------------------------------+ void DrawStructureLabels() { string biasText = "HTF Bias: "; switch(htfBias) { case STRUCT_BULLISH: biasText += "BULLISH"; break; case STRUCT_BEARISH: biasText += "BEARISH"; break; default: biasText += "NEUTRAL"; break; } string ltfText = "LTF Structure: "; switch(ltfStructure) { case STRUCT_BULLISH: ltfText += "HH+HL"; break; case STRUCT_BEARISH: ltfText += "LL+LH"; break; default: ltfText += "NEUTRAL"; break; } // Current trade conditions string conditionText = ""; if(CheckBuyCondition()) conditionText = "BUY Condition: ACTIVE (Price < LTF Low)"; else if(CheckSellCondition()) conditionText = "SELL Condition: ACTIVE (Price > LTF High & Low)"; else conditionText = "No Trade Condition Met"; // Create label objects CreateLabel("MS_BiasLabel", biasText, 10, 20, clrDarkOrange); CreateLabel("MS_LTFLabel", ltfText, 10, 40, clrDarkOrange); CreateLabel("MS_ConditionLabel", conditionText, 10, 60, (CheckBuyCondition() || CheckSellCondition()) ? clrLime : clrGray); // Display LTF swing prices if(ltf_lastHigh.price > 0) CreateLabel("MS_LTFHighLabel", StringFormat("LTF High: %.5f", ltf_lastHigh.price), 10, 80, clrOrange); if(ltf_lastLow.price > 0) CreateLabel("MS_LTFLowLabel", StringFormat("LTF Low: %.5f", ltf_lastLow.price), 10, 100, clrGreen); } //+------------------------------------------------------------------+ //| Create Text Label | //+------------------------------------------------------------------+ void CreateLabel(string name, string text, int x, int y, color clr) { ObjectCreate(0, "MS_" + name, OBJ_LABEL, 0, 0, 0); ObjectSetString(0, "MS_" + name, OBJPROP_TEXT, text); ObjectSetInteger(0, "MS_" + name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, "MS_" + name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, "MS_" + name, OBJPROP_COLOR, clr); ObjectSetInteger(0, "MS_" + name, OBJPROP_FONTSIZE, 10); } //+------------------------------------------------------------------+ //| Create Horizontal Line | //+------------------------------------------------------------------+ void CreateHorizontalLine(string name, double price, color clr, ENUM_LINE_STYLE style) { ObjectCreate(0, "MS_" + name, OBJ_HLINE, 0, 0, price); ObjectSetInteger(0, "MS_" + name, OBJPROP_COLOR, clr); ObjectSetInteger(0, "MS_" + name, OBJPROP_STYLE, style); ObjectSetInteger(0, "MS_" + name, OBJPROP_WIDTH, 1); }
В этом разделе кода система обеспечивает полную визуализацию рыночной структуры и торговых условий на графике. Функция DrawSwingPoint() отмечает свинговые максимумы и минимумы стрелками с цветовой кодировкой и добавляет всплывающие подсказки с указанием точной цены и типа — максимум или минимум. Функция DrawStructureLabels() дополняет визуализацию текстовой информацией о направленности HTF, текущей структуре LTF и активных торговых условиях, предоставляя быстрый обзор рыночного контекста. Метки также выделяют цены свингового максимума и минимума LTF, помогая визуализировать потенциальные зоны разворота и поддерживая оперативное принятие решений.
Для поддержки этих визуальных элементов вспомогательные функции CreateLabel() и CreateHorizontalLine() стандартизируют создание текстовых меток и горизонтальных ориентировочных линий. Метки размещаются в заданных экранных координатах с настраиваемыми цветами и размерами шрифта, а горизонтальные линии обозначают ключевые ценовые уровни: текущие цены Bid и Ask, свинговые максимумы и минимумы, а также торговые зоны. В совокупности эти функции преобразуют необработанные структурные данные в понятную и практически применимую визуальную основу, позволяя трейдерам в реальном времени видеть на графике рыночные экстремумы и потенциальные торговые возможности.
Результаты тестирования на исторических данных
Тестирование на исторических данных проводилось на таймфрейме H1 в течение 2 месяцев — с 1 декабря 2025 года по 31 января 2026 года — с настройками по умолчанию: 

Заключение
Подводя итог, индикатор свинговых экстремумов и отката был автоматизирован путем преобразования рыночной структуры младшего и старшего таймфреймов в полностью реализованную в коде систему. Система автоматизации выявляет свинговые максимумы и минимумы на HTF и LTF, непрерывно отслеживает ценовое движение на предмет пробоев структуры и определяет перерастянутые движения, сигнализирующие о возможных разворотах. Были заложены правила исполнения сделок, включая покупку, когда цена опускается ниже последнего свингового минимума LTF, и продажу при движении цены выше последнего свингового максимума и минимума LTF. Уровни тейк-профита определяются по соответствующим свинговым точкам. Кроме того, автоматизированы функции визуализации, позволяющие в реальном времени отображать на графике свинги, торговые зоны и метки рыночной направленности. Это обеспечивает структурированное представление рынка без ручного анализа.
Эта автоматизация упрощает процесс принятия решений, снижая эмоциональную предвзятость и необходимость ручного контроля за счет объективного исполнения сделок на основе структурных экстремумов. Система позволяет трейдерам одновременно отслеживать несколько таймфреймов, заранее выявлять возможные откаты или развороты и исполнять сделки с заранее рассчитанными риском и целями прибыли. Сочетание автоматического исполнения и понятной визуальной обратной связи повышает эффективность, последовательность и понятность торгового процесса, делая торговлю проще, быстрее и дисциплинированнее.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/21330
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Нейроструктурный торговый движок — NSTE (Часть I): Построение мультиаккаунтной системы с учетом ограничений проп-фирм
Нейросети в трейдинге: Управление риском через распределение результатов (AC-SRM)
Разработка индикатора паттерна "Мегафон" на MQL5
Использование Экономического календаря MQL5 для фильтрации новостей (Часть 1): Реализация временных окон до и после новостей в MQL5
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Как получить этот показатель
Ваши советники терпят неудачу из-за логики, лежащей в основе концепции, которую вы реализуете.