Рыночные секреты Ларри Уильямса (Часть 13): Автоматизация разворотных паттернов Hidden Smash Day
Введение
В книге "Долгосрочные секреты краткосрочной торговли" Ларри Уильямс представляет Hidden Smash Day как более сдержанную, более "внутреннюю" версию классического Smash Day. На графике это выглядит просто: бар не обязательно пробивает очевидный предыдущий максимум или минимум, но намекает на истощение, потому что рынок не способен развить движение после теста уровня на следующей сессии. Сетап намеренно неочевиден, и Уильямс ясно подчеркивает ключевой момент: бар Hidden Smash Day сам по себе не является входом в сделку — торговый сигнал возникает только после подтверждения на следующей сессии, когда цена пробивает скрытый уровень.
Именно из-за этой тонкости паттерн часто вызывает затруднения при ручной торговле. Как только вы пытаетесь отрабатывать его вручную, это быстро превращается в спор о трактовке правил: где именно начинается "нижняя/верхняя часть диапазона", что считать подтверждением, должен ли стоп опираться на структуру бара Smash Day или расширяться вместе с волатильностью, и как избежать наложения позиций, когда сигналы идут группами.
Если вы подходите к работе Уильямса как алготрейдер или разработчик, вам нужна не интерпретация, а формальные правила: одинаковые условия для всех инструментов, неизменная логика подтверждения на следующей сессии и управление риском, которое можно воспроизвести в тестере стратегий. Цель этой статьи — перевести Hidden Smash Day в однозначные правила и реализовать их в MQL5 так, чтобы сигнал, вход, SL/TP и размер позиции рассчитывались автоматически и выполнялись одинаково при каждом запуске — без пространства для субъективной интерпретации.
Понимание скрытых разворотных паттернов Smash Day
Hidden Smash Day определяется положением цены закрытия внутри собственного диапазона бара в сочетании со сравнением с закрытием предыдущей сессии.
Для бычьего сетапа Hidden Smash Day нужны четыре условия:
- Бар должен закрыться выше предыдущего бара.
- Диапазон бара измеряется от его собственного максимума до его собственного минимума.
- Цена закрытия должна находиться в нижних двадцати пяти процентах этого диапазона.
- При необходимости можно потребовать, чтобы закрытие оставалось ниже открытия бара для более строгой фильтрации.

Такая структура отражает закрытие в плюс, которое при этом оказывается слабым внутри собственного диапазона, указывая на внутреннее ослабление импульса несмотря на закрытие в плюс.
Медвежий Hidden Smash Day строится по обратной логике:
- Бар должен закрыться ниже предыдущего бара.
- Его диапазон определяется собственным максимумом и минимумом.
- Цена закрытия должна находиться в верхних двадцати пяти процентах этого диапазона.
- При необходимости можно потребовать, чтобы закрытие оставалось выше открытия.

В обоих случаях сам бар Smash Day является только сетапом. Он не запускает сделку. Подтверждение требуется на следующем завершенном баре.
В этой реализации подтверждение происходит только тогда, когда подтверждающий бар закрывается за экстремумом бара Smash Day. Для сигнала на покупку требуется полное закрытие бара выше максимума бара Smash Day. Для сигнала на продажу требуется полное закрытие бара ниже минимума бара Smash Day.
Это правило подтверждения по цене закрытия последовательно используется во всей статье и в советнике.
Преобразование Hidden Smash Day в практические торговые правила
Перед автоматизацией нужно было определить, как торговать по паттернам Hidden Smash Day контролируемо и воспроизводимо. Цель этого советника — не торговать каждый возможный сигнал, а придать идее Ларри Уильямса структуру, сохранив гибкость в руках трейдера.
Первое проектное правило касается момента принятия решений. Вся логика обнаружения паттерна и исполнения сделок оценивается только на открытии нового бара. Это гарантирует, что бары Hidden Smash Day полностью сформированы, а бары подтверждения завершили свою сессию. Так мы избегаем действий на основе неполной ценовой информации и остаемся ближе к тому, как паттерн определен в исходной работе.
Второе правило — подтверждение до входа. Hidden Smash Day никогда не торгуется сам по себе. В этой реализации подтверждение требует полного закрытия бара за экстремумом бара Smash Day. Для сетапа на покупку следующая сессия должна закрыться выше максимума скрытого бара Smash Day. Для сетапа на продажу следующая сессия должна закрыться ниже его минимума. Все оценки выполняются только на открытии нового бара, чтобы и бар Smash Day, и подтверждающий бар были полностью завершены до рассмотрения сделки.
Важное проектное решение в этом советнике — явный контроль направления торговли. Система поддерживает три отдельных режима работы. Ее можно ограничить только длинными сделками, только короткими сделками или разрешить оба направления. Эта возможность намеренно вынесена во входные параметры, потому что паттерны Hidden Smash Day не одинаково хорошо работают во всех рыночных условиях. В одних рынках или периодах преобладают сетапы на покупку, в других надежнее оказываются сетапы на продажу. Благодаря контролю направления советник становится инструментом для исследования и проверки, а не жестким черным ящиком.
Управление риском рассматривается как ключевой компонент, а не как второстепенная деталь. Стоп-лосс может рассчитываться двумя способами. Первый вариант размещает стоп-лосс на структурном уровне Hidden Smash Day, используя максимум или минимум паттерна. Второй вариант учитывает рыночную волатильность через заданный пользователем множитель Average True Range. Такой двойной подход позволяет системе адаптироваться и к ценовой структуре, и к меняющимся условиям волатильности.
Размер позиции также гибок по замыслу. Советник поддерживает ручной размер лота для трейдеров, предпочитающих фиксированный размер позиции, а также автоматический расчет позиции на основе процента от баланса счета. Когда включен автоматический расчет, каждая сделка рискует стабильной долей капитала независимо от символа или волатильности, что помогает поддерживать более устойчивые долгосрочные результаты.
Еще одно важное правило — правило единственной открытой позиции. Советник никогда не открывает больше одной сделки одновременно. Перед размещением нового ордера он всегда проверяет наличие открытых позиций. Это предотвращает перекрывающиеся сделки, упрощает контроль риска и делает анализ результатов в тестировании намного яснее.
В совокупности эти правила определяют, как паттерны Hidden Smash Day превращаются в дисциплинированную торговую систему. Каждое решение отражает исходный замысел Ларри Уильямса и добавляет структуру, необходимую для автоматизации, тестирования и долгосрочной оценки.
Поток исполнения стратегии Hidden Smash Day
Если открылся новый бар Обновить значения ATR Если открытых позиций нет Проверить наличие бычьего сетапа Hidden Smash Day (бар сетапа — индекс 2) Если сетап действителен Проверить, закрылся ли подтверждающий бар выше максимума бара сетапа Если подтверждение получено Рассчитать стоп-лосс Рассчитать тейк-профит Рассчитать размер позиции Открыть ордер на покупку Проверить наличие медвежьего сетапа Hidden Smash Day (бар сетапа — индекс 2) Если сетап действителен Проверить, закрылся ли подтверждающий бар ниже минимума бара сетапа Если подтверждение получено Рассчитать стоп-лосс Рассчитать тейк-профит Рассчитать размер позиции Открыть ордер на продажу
- Сетап и подтверждение разделены.
- Используются только завершенные бары.
- Стоп-лосс и тейк-профит определяются до исполнения.
- Риск рассчитывается до отправки ордера.
- Одновременно может существовать только одна сделка.
После определения такой структуры код становится прямым выражением этих шагов.
Создание советника Hidden Smash Day
Этот раздел открывает практическую фазу реализации. Здесь мы начинаем пошагово собирать советник Hidden Smash Day, сначала сосредоточившись на структуре и только затем добавляя торговую логику. На этом этапе цель еще не в торговле, а в создании чистой и надежной основы, которая сможет поддерживать более сложное поведение по мере развития проекта.
Перед дальнейшей работой важно уточнить несколько предварительных требований. В этом разделе предполагается знакомство с языком MQL5 и его базовым синтаксисом, включая переменные, функции, перечисления и стандартные библиотеки. Также ожидается опыт работы с терминалом MetaTrader 5, особенно навигация по графикам, подключение советников и запуск тестов. Наконец, требуется базовая уверенность в MetaEditor: создание исходных файлов, компиляция кода и просмотр сообщений компилятора.
Чтобы стимулировать активное обучение, завершенный исходный файл советника прикреплен к статье под именем lwHiddenSmashDayExpert.mq5. Если держать этот файл открытым в отдельной вкладке по ходу руководства, будет проще сравнивать код при добавлении новых компонентов.
С учетом этого контекста мы начинаем с создания нового пустого файла советника в MetaEditor и вставки начального шаблонного кода, показанного ниже.
//+------------------------------------------------------------------+ //| lwHiddenSmashDayExpert.mq5 | //| Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian | //| https://www.mql5.com/en/users/chachaian | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian" #property link "https://www.mql5.com/en/users/chachaian" #property version "1.00" //+------------------------------------------------------------------+ //| Standard Libraries | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //| Defines how stop loss levels are determined for smash day trades | //+------------------------------------------------------------------+ enum ENUM_STOP_LOSS_MODE { SL_ATR_BASED, SL_SMASH_BAR_STRUCTURE }; //+------------------------------------------------------------------+ //| Defines the trade direction | //+------------------------------------------------------------------+ enum ENUM_TRADE_DIRECTION { TRADE_LONG, TRADE_SHORT, TRADE_BOTH }; enum ENUM_LOT_SIZE_INPUT_MODE { MODE_MANUAL, MODE_AUTO }; //+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input ulong magicNumber = 254700680002; input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; input group "ATR configuration parameters" input int32_t atrPeriod = 14; input double atrMultiplier = 2.0; input group "Trade and Risk Management" input ENUM_STOP_LOSS_MODE smashStopLossMode = SL_SMASH_BAR_STRUCTURE; input double rewardRiskRatio = 3.0; input ENUM_TRADE_DIRECTION direction = TRADE_LONG; input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode = MODE_AUTO; input double riskPerTradePercent = 1.0; input double positionSize = 0.1; //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ //--- Create a CTrade object to handle trading operations CTrade Trade; //--- To hep track current market prices for Buying (Ask) and Selling (Bid) double askPrice; double bidPrice; //--- To store current time datetime currentTime; //--- To help track new bar open datetime lastBarOpenTime; //--- ATR Values int atrHandle; double atrValues []; //--- Protective stops double stopLossLevel; double takeProfitLevel; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- Assign a unique magic number to identify trades opened by this EA Trade.SetExpertMagicNumber(magicNumber); //--- Initialize global variables lastBarOpenTime = 0; //--- Initialize the ATR indicator atrHandle = iATR(_Symbol, timeframe, atrPeriod); if(atrHandle == INVALID_HANDLE){ Print("Error while initializing the ATR indicator ", GetLastError()); return(INIT_FAILED); } //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar) ArraySetAsSeries(atrValues, true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- Notify why the program stopped running Print("Program terminated! Reason code: ", reason); //--- Release ATR if(atrHandle != INVALID_HANDLE){ if(IndicatorRelease(atrHandle)){ Print("The computer memory tracking ATR has been freed."); } } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- Retrieve current market prices for trade execution askPrice = SymbolInfoDouble (_Symbol, SYMBOL_ASK); bidPrice = SymbolInfoDouble (_Symbol, SYMBOL_BID); currentTime = TimeCurrent(); } //+------------------------------------------------------------------+
Этот код пока не открывает сделок. Вместо этого он задает структуру, параметры конфигурации и основные сервисы, на которые советник будет опираться позже.
Заголовок файла и идентификация
//+------------------------------------------------------------------+ //| lwHiddenSmashDayExpert.mq5 | //| Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian | //| https://www.mql5.com/en/users/chachaian | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, MetaQuotes Ltd. Developer is Chacha Ian" #property link "https://www.mql5.com/en/users/chachaian" #property version "1.00"
Начальный раздел определяет идентичность советника. В нем указаны имя файла, принадлежность и информация о версии. Хотя эта часть напрямую не влияет на торговую логику, она играет важную роль в организации кода, ясности авторства и долгосрочном сопровождении. Раннее определение этих свойств помогает сделать будущие редакции отслеживаемыми и профессиональными.
Подключение торговой библиотеки
Следующий шаг — подключение стандартной торговой библиотеки.
//+------------------------------------------------------------------+ //| Standard Libraries | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh>
Эта библиотека предоставляет доступ к классу CTrade, который позже используется для исполнения ордеров на покупку и продажу. Опора на этот стандартный интерфейс делает исполнение ордеров безопаснее, понятнее и более согласованным с внутренней обработкой торговых операций в MetaTrader.
На этом этапе мы только подключаем библиотеку. Непосредственное исполнение ордеров будет добавлено позже, когда будет готова логика сигналов.
Перечисления, задающие поведение
Перед определением входных параметров или логики мы вводим набор перечислений.
//+------------------------------------------------------------------+ //| Defines how stop loss levels are determined for smash day trades | //+------------------------------------------------------------------+ enum ENUM_STOP_LOSS_MODE { SL_ATR_BASED, SL_SMASH_BAR_STRUCTURE }; //+------------------------------------------------------------------+ //| Defines the trade direction | //+------------------------------------------------------------------+ enum ENUM_TRADE_DIRECTION { TRADE_LONG, TRADE_SHORT, TRADE_BOTH }; //+------------------------------------------------------------------+ //| To track lot size input mode | //+------------------------------------------------------------------+ enum ENUM_LOT_SIZE_INPUT_MODE { MODE_MANUAL, MODE_AUTO };
Эти перечисления формализуют ключевые проектные решения и делают поведение советника явным и настраиваемым.
Первое перечисление определяет, как рассчитываются уровни стоп-лосса. Один режим стопа основан на рыночной волатильности через ATR, а другой привязывает стопы к структуре самого скрытого бара Smash Day. Это разделение намеренное и отражает два разных подхода к контролю риска.
Второе перечисление определяет направление торговли. Советник можно ограничить только длинными сделками, только короткими сделками или разрешить торговлю в обоих направлениях. Это важная проектная возможность, поскольку паттерны Hidden Smash Day не всегда симметрично работают в разных рыночных условиях.
Последнее перечисление управляет способом задания размера лота. Размер сделок можно задавать вручную или рассчитывать автоматически на основе риска по счету. Это различие позволяет советнику работать и как инструмент исполнения с фиксированным объемом, и как исследовательская система с нормированным риском.
Определяя эти варианты как перечисления, мы избегаем неоднозначных булевых флагов и делаем конфигурацию советника проще для чтения и понимания.
Конфигурация входных параметров
После определения перечислений переходим к входным параметрам. Они сгруппированы логически, чтобы панель настроек оставалась читаемой и интуитивной.
//+------------------------------------------------------------------+ //| User input variables | //+------------------------------------------------------------------+ input group "Information" input ulong magicNumber = 254700680002; input ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT; input group "ATR configuration parameters" input int32_t atrPeriod = 14; input double atrMultiplier = 2.0; input group "Trade and Risk Management" input ENUM_STOP_LOSS_MODE smashStopLossMode = SL_SMASH_BAR_STRUCTURE; input double rewardRiskRatio = 3.0; input ENUM_TRADE_DIRECTION direction = TRADE_LONG; input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode = MODE_AUTO; input double riskPerTradePercent = 1.0; input double positionSize = 0.1;
Группа Information содержит magic number и таймфрейм. Magic number гарантирует, что позиции, открытые этим советником, всегда можно идентифицировать и управлять ими независимо от других систем.
Группа конфигурации ATR задает период и множитель, используемые для стоп-лоссов на основе ATR. Эти значения определяют, как волатильность переводится в защитную дистанцию.
Группа Trade and Risk Management объединяет самые важные элементы управления поведением системы. Здесь задаются режим стоп-лосса, соотношение прибыли и риска, направление торговли, режим расчета лота и параметры риска. Каждый из этих входных параметров напрямую влияет на размер, защиту и фильтрацию сделок.
На этом этапе эти параметры объявлены, но еще не используются. Их задача — направлять будущую логику, а не немедленно исполнять сделки.
Глобальное состояние и рыночный контекст
После входных параметров мы объявляем глобальные переменные. Они позволяют разным частям советника аккуратно обмениваться состоянием.
//+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ //--- Create a CTrade object to handle trading operations CTrade Trade; //--- To hep track current market prices for Buying (Ask) and Selling (Bid) double askPrice; double bidPrice; //--- To store current time datetime currentTime; //--- To help track new bar open datetime lastBarOpenTime; //--- ATR Values int atrHandle; double atrValues []; //--- Protective stops double stopLossLevel; double takeProfitLevel;
Объект CTrade создается для последующего исполнения ордеров. Рыночные цены, такие как Ask и Bid, хранятся глобально, чтобы их можно было последовательно использовать в разных функциях. Текущее серверное время отслеживается для логики синхронизации.
Для поддержки решений на основе баров зарезервирована переменная, которая отслеживает время открытия последнего бара. Это обеспечивает точное обнаружение новых торговых сессий, что важно для анализа дневных паттернов.
Также объявляются переменные, связанные с ATR. Хэндл индикатора соединяет советник с индикатором ATR, а массив хранит последние значения ATR. Позже эти значения будут использоваться для расчета стоп-лоссов на основе волатильности.
Наконец, определяются заполнители для уровней стоп-лосса и тейк-профита. Эти переменные будут заполняться только после появления корректных торговых сигналов.
Логика инициализации советника
Функция инициализации подготавливает советник к работе.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ //--- Assign a unique magic number to identify trades opened by this EA Trade.SetExpertMagicNumber(magicNumber); //--- Initialize global variables lastBarOpenTime = 0; //--- Initialize the ATR indicator atrHandle = iATR(_Symbol, timeframe, atrPeriod); if(atrHandle == INVALID_HANDLE){ Print("Error while initializing the ATR indicator ", GetLastError()); return(INIT_FAILED); } //--- Treat the following arrays as timeseries (index 0 becomes the most recent bar) ArraySetAsSeries(atrValues, true); return(INIT_SUCCEEDED); }
Сначала торговому объекту назначается magic number. Это гарантирует, что все сделки, открытые этим советником, будут корректно помечены.
Затем инициализируется переменная отслеживания баров. Установка ее в ноль гарантирует корректную обработку первого обнаруженного изменения бара.
После этого инициализируется индикатор ATR с использованием настроенного таймфрейма и периода. Если этот шаг завершается ошибкой, советник сразу останавливается, поскольку значения ATR нужны для одного из поддерживаемых режимов стоп-лосса.
Наконец, массив значений ATR настраивается как временной ряд. Благодаря этому самое новое значение ATR всегда доступно по индексу ноль, что упрощает будущие расчеты.
В конце инициализации советник полностью подготовлен, но еще не активен для торговли.
Деинициализация и очистка ресурсов
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- Notify why the program stopped running Print("Program terminated! Reason code: ", reason); //--- Release ATR if(atrHandle != INVALID_HANDLE){ if(IndicatorRelease(atrHandle)){ Print("The computer memory tracking ATR has been freed."); } } }
Когда советник удаляется или терминал завершает работу, вызывается функция деинициализации.
Здесь в журнал записывается сообщение о причине остановки, а хэндл индикатора ATR освобождается. Освобождение хэндлов индикаторов важно для предотвращения утечек памяти и чистого завершения работы, особенно при многократном тестировании.
Функция OnTick как заготовка
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- Retrieve current market prices for trade execution askPrice = SymbolInfoDouble (_Symbol, SYMBOL_ASK); bidPrice = SymbolInfoDouble (_Symbol, SYMBOL_BID); currentTime = TimeCurrent(); }
На этом раннем этапе функция тика выполняет только базовые задачи. Она обновляет рыночные цены и записывает текущее серверное время.
Торговые решения пока не принимаются. Это сделано намеренно. Функция тика остается минимальной до тех пор, пока не определены вся логика обнаружения и управления риском. Такой подход предотвращает преждевременную сложность и сохраняет фокус каждого этапа разработки.
Закладка основы
На этом этапе советник не торгует. Так и задумано.
То, что мы построили к этому моменту, — устойчивый каркас. Он определяет параметры конфигурации, задает рыночный контекст, подготавливает доступ к индикатору и обеспечивает чистый запуск и остановку. Каждый добавленный здесь элемент существует для поддержки последующей логики.
На следующих шагах мы начнем добавлять обнаружение паттернов, подтверждение сигналов и правила исполнения. Поскольку основа уже готова, эти добавления аккуратно и предсказуемо встроятся в существующую структуру.
Именно такой размеренный темп позволяет советнику оставаться читаемым, тестируемым и расширяемым по мере роста сложности.
Когда основа готова, мы начинаем собирать торговую логику по частям. Каждое добавление имеет четкую цель и поддерживает решения, принятые ранее на этапе проектирования. В этом разделе важна не скорость, а ясность. Мы вводим по одному компоненту, объясняем его роль и показываем, как он вписывается в общую структуру советника.
Обнаружение начала новой торговой сессии
Паттерны Hidden Smash Day оцениваются на завершенных барах. Поэтому все торговые решения в этом советнике принимаются на открытии нового бара. Для поддержки такого поведения сначала определим небольшую служебную функцию, которая сообщает, когда на выбранном таймфрейме сформировался новый бар.
//+------------------------------------------------------------------+ //| Function to check if there's a new bar on a given chart timeframe| //+------------------------------------------------------------------+ bool IsNewBar(string symbol, ENUM_TIMEFRAMES tf, datetime &lastTm){ datetime currentTm = iTime(symbol, tf, 0); if(currentTm != lastTm){ lastTm = currentTm; return true; } return false; }
Эту функцию нужно добавить в служебный раздел кода. Она сравнивает время открытия самого нового бара с ранее сохраненной меткой времени. Когда значение меняется, значит сформировался новый бар. Затем метка времени обновляется по ссылке, что позволяет функции стабильно работать на разных тиках. Для поддержки этой логики нужна глобальная переменная, в которой хранится последнее известное время открытия бара.
//--- To help track new bar open datetime lastBarOpenTime;
Эта переменная инициализируется при запуске советника, чтобы обеспечить чистое отслеживание состояния.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- Initialize global variables lastBarOpenTime = 0; }
С этого момента у советника есть надежный способ выполнять логику только один раз на бар.
Обновление значений ATR для управления риском
Один из режимов стоп-лосса, поддерживаемых этим советником, использует Average True Range. Чтобы значения ATR оставались актуальными, мы определяем функцию, которая обновляет буфер ATR при формировании нового бара.
//+------------------------------------------------------------------+ //| To update ATR values | //+------------------------------------------------------------------+ void UpdateATRValues(){ //--- Get some ATR Values int numberOfCopiedATRValues = CopyBuffer(atrHandle, 0, 0, 5, atrValues); if(numberOfCopiedATRValues == -1){ Print("Error while copying ATR values: ", GetLastError()); } }
Эту функцию следует разместить рядом с другими служебными функциями. Она загружает последние значения ATR в массив временного ряда, где индекс 0 всегда представляет самое новое значение. Такая организация делает логику расчета стоп-лосса простой и читаемой.
Внутри OnTick значения ATR обновляются сразу после обнаружения нового бара.
//+------------------------------------------------------------------+ //| Returns true if the bar at index forms a Hidden Smash Day Buy Bar | //| Logic aligned with indicator implementation | //+------------------------------------------------------------------+ bool IsHiddenSmashDayBuyBar(string symbol, ENUM_TIMEFRAMES tf, int index, double closePercentThreshold = 25.0, bool allowBullishClose = true, bool allowBearishClose = true){ //--- We need at least one previous bar if(index < 1){ return false; } double high = iHigh(symbol, tf, index); double low = iLow(symbol, tf, index); double open = iOpen(symbol, tf, index); double close = iClose(symbol, tf, index); double prevClose = iClose(symbol, tf, index + 1); double range = high - low; if(range <= 0.0) return false; //--- 1. Must close higher than previous bar if(close <= prevClose) return false; //--- 2. Close must be in lower portion of its own range double closePositionPercent = ((close - low) / range) * 100.0; if(closePositionPercent > closePercentThreshold) return false; //--- 3. Optional candle direction filter if(close > open && !allowBullishClose) return false; if(close < open && !allowBearishClose) return false; return true; }
Эта функция проверяет, находится ли цена закрытия в нижней части диапазона бара, заданной процентным порогом. Дополнительные параметры позволяют гибко разрешать бычьи или медвежьи закрытия, отражая наблюдение Ларри Уильямса о том, что оба случая могут быть корректными.
Для обнаружения медвежьих баров Hidden Smash Day определяется зеркальная функция.
//+--------------------------------------------------------------------+ //| Returns true if the bar at index forms a Hidden Smash Day Sell Bar | //| Logic aligned with indicator implementation | //+--------------------------------------------------------------------+ bool IsHiddenSmashDaySellBar(string symbol, ENUM_TIMEFRAMES tf, int index, double closePercentThreshold = 25.0, bool allowBullishClose = true, bool allowBearishClose = true){ //--- We need at least one previous bar if(index < 1){ return false; } double high = iHigh(symbol, tf, index); double low = iLow(symbol, tf, index); double open = iOpen(symbol, tf, index); double close = iClose(symbol, tf, index); double prevClose = iClose(symbol, tf, index + 1); double range = high - low; if(range <= 0.0) return false; //--- 1. Must close lower than previous bar if(close >= prevClose) return false; //--- 2. Close must be in upper portion of its own range double closePositionPercent = ((high - close) / range) * 100.0; if(closePositionPercent > closePercentThreshold) return false; //--- 3. Optional candle direction filter if(close > open && !allowBullishClose) return false; if(close < open && !allowBearishClose) return false; return true; }
Эти две функции формируют основу обнаружения паттернов. На этом этапе торговые сигналы еще не генерируются. Мы только выявляем бары-кандидаты.
Подтверждение корректных торговых сигналов
Hidden Smash Day становится пригодным к торговле только после подтверждения. Ларри Уильямс указывает, что подтверждение происходит, когда следующая сессия закрывается за экстремумом бара Smash Day. Чтобы формализовать это правило, мы определяем функцию подтверждения для бычьих сетапов.
//+------------------------------------------------------------------+ //| Confirms a Hidden Smash Day Buy signal using a confirming bar | //+------------------------------------------------------------------+ bool IsHiddenSmashDayBuySignal(int confirmingBarIndex){ int smashBarIndex = confirmingBarIndex + 1; //--- Verify smash bar exists and is valid if(!IsHiddenSmashDayBuyBar(_Symbol, timeframe, smashBarIndex)) return false; //--- Confirmation requires a close above the smash bar high if(iClose(_Symbol, timeframe, confirmingBarIndex) > iHigh (_Symbol, timeframe, smashBarIndex)){ return true; } return false; }
Логика проверяет, что существует корректный скрытый бар Smash Day и что следующий бар закрывается выше его максимума.
Зеркальная функция подтверждает медвежьи сигналы.
//+------------------------------------------------------------------+ //| Confirms a Hidden Smash Day Sell signal using a confirming bar | //+------------------------------------------------------------------+ bool IsHiddenSmashDaySellSignal(int confirmingBarIndex){ int smashBarIndex = confirmingBarIndex + 1; //--- Verify smash bar exists and is valid if(!IsHiddenSmashDaySellBar(_Symbol, timeframe, smashBarIndex)) return false; //--- Confirmation requires a close below the smash bar low if(iClose(_Symbol, timeframe, confirmingBarIndex) < iLow (_Symbol, timeframe, smashBarIndex)){ return true; } return false; }
На этом этапе советник уже может объективно выявлять корректные торговые сигналы.
Правило одной позиции за раз
Чтобы держать риск под контролем, а логику — предсказуемой, советник спроектирован так, чтобы удерживать только одну открытую позицию в любой момент времени. Это правило реализуют две вспомогательные функции.
//+------------------------------------------------------------------+ //| To verify whether this EA currently has an active buy position. | | //+------------------------------------------------------------------+ bool IsThereAnActiveBuyPosition(ulong magic){ for(int i = PositionsTotal() - 1; i >= 0; i--){ ulong ticket = PositionGetTicket(i); if(ticket == 0){ Print("Error while fetching position ticket ", _LastError); continue; }else{ if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){ return true; } } } return false; } //+------------------------------------------------------------------+ //| To verify whether this EA currently has an active sell position. | | //+------------------------------------------------------------------+ bool IsThereAnActiveSellPosition(ulong magic){ for(int i = PositionsTotal() - 1; i >= 0; i--){ ulong ticket = PositionGetTicket(i); if(ticket == 0){ Print("Error while fetching position ticket ", _LastError); continue; }else{ if(PositionGetInteger(POSITION_MAGIC) == magic && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){ return true; } } } return false; }
Эти функции просматривают все открытые позиции и возвращают true, если сделка с magic number этого советника уже активна. Перед открытием любой новой позиции выполняются обе проверки.
Расчет уровней стоп-лосса и тейк-профита
После обнаружения корректного сигнала необходимо рассчитать защитные уровни. Функция стоп-лосса поддерживает два режима: на основе ATR и на основе структуры бара Smash Day.
//+------------------------------------------------------------------+ //| Computes the stop loss level based on direction and SL mode | //+------------------------------------------------------------------+ double ComputeStopLossLevel(ENUM_TRADE_DIRECTION tDirection, ENUM_STOP_LOSS_MODE slMode, int smashBarIndex) { double slLevel = 0.0; //--- ATR based stop loss if(slMode == SL_ATR_BASED) { double atrValue = atrValues[0] * atrMultiplier; if(tDirection == TRADE_LONG) slLevel = askPrice - atrValue; else slLevel = bidPrice + atrValue; } //--- Smash bar structure based stop loss else if(slMode == SL_SMASH_BAR_STRUCTURE) { if(tDirection == TRADE_LONG) slLevel = iLow(_Symbol, timeframe, smashBarIndex); else slLevel = iHigh(_Symbol, timeframe, smashBarIndex); } return NormalizeDouble(slLevel, Digits()); }
В режиме ATR стоп-лосс размещается на расстоянии от цены входа, равном кратному текущего ATR. В структурном режиме стоп-лосс размещается на максимуме или минимуме самого бара Smash Day. Такая гибкость позволяет тестировать разные подходы к риску без изменения кода.
Уровень тейк-профита проецируется с использованием фиксированного соотношения прибыли и риска.
//+------------------------------------------------------------------+ //| Computes the take profit level using risk reward ratio | //+------------------------------------------------------------------+ double ComputeTakeProfitLevel(ENUM_TRADE_DIRECTION tDirection, double stopLoss) { double entryPrice; double riskDistance; double takeProfit; if(tDirection == TRADE_LONG) { entryPrice = askPrice; riskDistance = entryPrice - stopLossLevel; takeProfit = entryPrice + (riskDistance * rewardRiskRatio); } else { entryPrice = bidPrice; riskDistance = stopLossLevel - entryPrice; takeProfit = entryPrice - (riskDistance * rewardRiskRatio); } return NormalizeDouble(takeProfit, Digits()); }
Привязывая тейк-профит напрямую к риску, советник поддерживает последовательную логику размера позиции и математического ожидания.
Исполнение сделок
Вспомогательная функция определяется для расчета автоматического размера позиции.
//+------------------------------------------------------------------+ //| Calculates position size using OrderCalcProfit for accuracy | //+------------------------------------------------------------------+ double CalculatePositionSizeByRisk(ENUM_ORDER_TYPE orderType, double entryPrice, double stopLossPrice){ //--- Amount willing to risk double amountAtRisk = (riskPerTradePercent / 100.0) * AccountInfoDouble(ACCOUNT_BALANCE); //--- Calculate loss for 1 lot double lossPerLot = 0.0; if(!OrderCalcProfit(orderType, _Symbol, 1.0, // 1 lot entryPrice, stopLossPrice, lossPerLot)) { Print("OrderCalcProfit failed: ", GetLastError()); return 0.0; } // Loss will be negative for losing scenario lossPerLot = MathAbs(lossPerLot); if(lossPerLot <= 0.0) return 0.0; //--- Raw volume double volume = amountAtRisk / lossPerLot; //--- Apply broker constraints double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); // Normalize to step volume = MathFloor(volume / lotStep) * lotStep; if(volume < minLot) volume = minLot; if(volume > maxLot) volume = maxLot; return NormalizeDouble(volume, 2); }
Две простые функции-обертки отвечают за исполнение сделок.
//+------------------------------------------------------------------+ //| Calculates position size using OrderCalcProfit for accuracy | //+------------------------------------------------------------------+ double CalculatePositionSizeByRisk(ENUM_ORDER_TYPE orderType, double entryPrice, double stopLossPrice){ //--- Amount willing to risk double amountAtRisk = (riskPerTradePercent / 100.0) * AccountInfoDouble(ACCOUNT_BALANCE); //--- Calculate loss for 1 lot double lossPerLot = 0.0; if(!OrderCalcProfit(orderType, _Symbol, 1.0, // 1 lot entryPrice, stopLossPrice, lossPerLot)) { Print("OrderCalcProfit failed: ", GetLastError()); return 0.0; } // Loss will be negative for losing scenario lossPerLot = MathAbs(lossPerLot); if(lossPerLot <= 0.0) return 0.0; //--- Raw volume double volume = amountAtRisk / lossPerLot; //--- Apply broker constraints double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); // Normalize to step volume = MathFloor(volume / lotStep) * lotStep; if(volume < minLot) volume = minLot; if(volume > maxLot) volume = maxLot; return NormalizeDouble(volume, 2); } //+------------------------------------------------------------------+ //| Function to open a market buy position | //+------------------------------------------------------------------+ bool OpenBuy(double entryPrice, double stopLoss, double takeProfit, double lotSize){ if(lotSizeMode == MODE_AUTO){ lotSize = CalculatePositionSizeByRisk(ORDER_TYPE_BUY, entryPrice, stopLoss); } if(!Trade.Buy(lotSize, _Symbol, entryPrice, stopLoss, takeProfit)){ Print("Error while executing a market buy order: ", GetLastError()); Print(Trade.ResultRetcode()); Print(Trade.ResultComment()); return false; } return true; } //+------------------------------------------------------------------+ //| Function to open a market sell position | //+------------------------------------------------------------------+ bool OpenSell(double entryPrice, double stopLoss, double takeProfit, double lotSize){ if(lotSizeMode == MODE_AUTO){ lotSize = CalculatePositionSizeByRisk(ORDER_TYPE_SELL, entryPrice, stopLoss); } if(!Trade.Sell(lotSize, _Symbol, entryPrice, stopLoss, takeProfit)){ Print("Error while executing a market sell order: ", GetLastError()); Print(Trade.ResultRetcode()); Print(Trade.ResultComment()); return false; } return true; }
Если включен автоматический расчет лота, размер лота вычисляется на основе заданного процента риска. В противном случае используется ручной размер позиции. Эти функции отделяют исполнение сделок от логики сигналов, повышая читаемость и удобство сопровождения.
Сведение всего вместе в OnTick
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ //--- Retrieve current market prices for trade execution askPrice = SymbolInfoDouble (_Symbol, SYMBOL_ASK); bidPrice = SymbolInfoDouble (_Symbol, SYMBOL_BID); currentTime = TimeCurrent(); //--- Execute on new bar open if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){ //--- Update ATR Values UpdateATRValues(); if(IsHiddenSmashDayBuySignal(1)) { Print("New Bar!!!"); stopLossLevel = ComputeStopLossLevel(TRADE_LONG, smashStopLossMode, 2); takeProfitLevel = ComputeTakeProfitLevel(TRADE_LONG, stopLossLevel); if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ if(direction == TRADE_LONG || direction == TRADE_BOTH){ OpenBuy(askPrice, stopLossLevel, takeProfitLevel, positionSize); } } } if(IsHiddenSmashDaySellSignal(1)){ Print("New Bar!!!"); stopLossLevel = ComputeStopLossLevel(TRADE_SHORT, smashStopLossMode, 2); takeProfitLevel = ComputeTakeProfitLevel(TRADE_SHORT, stopLossLevel); if(!IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){ if(direction == TRADE_SHORT || direction == TRADE_BOTH){ OpenSell(bidPrice, stopLossLevel, takeProfitLevel, positionSize); } } } } }
Все компоненты соединяются внутри функции OnTick. На каждом новом баре советник:
- обновляет значения ATR
- проверяет подтвержденные сигналы на покупку или продажу
- проверяет отсутствие активной позиции
- применяет фильтр направления торговли
- рассчитывает стоп-лосс и тейк-профит
- исполняет сделку
Такой структурированный поток гарантирует, что сделки открываются только при совпадении всех условий, а каждое решение принимается на основе полной ценовой информации.
Подготовка графика для наглядного тестирования
На этом этапе логика советника завершена. Перед переходом к фазе тестирования нужен еще один практический шаг. Необходимо убедиться, что визуальная среда, используемая при тестировании, чистая и читаемая.
Тестирование стратегии — это не только цифры эффективности. Это еще и наблюдение. Мы хотим ясно видеть движение цены, структуру свечей и размещение сделок без визуального шума. Стандартные настройки графика часто перегружены и могут скрывать важные детали, особенно при просмотре входов и выходов бар за баром.
Для этого мы определяем небольшую служебную функцию, единственная задача которой — настроить внешний вид графика.
//+------------------------------------------------------------------+ //| This function configures the chart's appearance. | //+------------------------------------------------------------------+ bool ConfigureChartAppearance() { if(!ChartSetInteger(0, CHART_COLOR_BACKGROUND, clrWhite)){ Print("Error while setting chart background, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_SHOW_GRID, false)){ Print("Error while setting chart grid, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_MODE, CHART_CANDLES)){ Print("Error while setting chart mode, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_FOREGROUND, clrBlack)){ Print("Error while setting chart foreground, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrSeaGreen)){ Print("Error while setting bullish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrBlack)){ Print("Error while setting bearish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CHART_UP, clrSeaGreen)){ Print("Error while setting bearish candles color, ", GetLastError()); return false; } if(!ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrBlack)){ Print("Error while setting bearish candles color, ", GetLastError()); return false; } return true; }
Эту функцию следует добавить ближе к концу исходного файла, рядом с другими служебными помощниками. Она применяет контрастную тему с белым фоном и хорошо различимыми бычьими и медвежьими свечами. Линии сетки отключаются для снижения шума, а график явно переводится в свечной режим. Каждая настройка проверяется, и любая ошибка сразу выводится в журнал. Такой подход гарантирует, что при визуальном разборе сделок ценовая структура и точки исполнения легко интерпретируются.
После определения функции последний шаг — вызвать ее во время инициализации советника. Это гарантирует, что график будет настроен один раз до начала любой торговой логики.
Внутри функции OnInit мы добавляем следующий блок.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... //--- To configure the chart's appearance if(!ConfigureChartAppearance()){ Print("Error while configuring chart appearance", GetLastError()); return INIT_FAILED; } return(INIT_SUCCEEDED); }
Размещая этот вызов в OnInit, мы гарантируем, что визуальная среда готова до начала тестирования или живого исполнения. Если настройка графика по какой-либо причине завершается ошибкой, советник сразу останавливается, а не работает в непредусмотренном состоянии.
После этого финального шага советник не только логически завершен, но и правильно подготовлен к анализу и тестированию. Логика принятия решений и визуальная обратная связь теперь работают вместе, что особенно важно при оценке стратегии на основе паттерна, такого как Hidden Smash Day.
На этом этапе советник полностью функционален. Полная реализация предоставлена в прикрепленном файле lwHiddenSmashDayExpert.mq5, что позволяет читателям изучать, тестировать и расширять логику без копирования больших блоков кода из статьи.
Такой структурированный подход отражает философию работы Ларри Уильямса: четкие правила, дисциплинированное исполнение и уважение к рыночной структуре. Когда основная логика готова, следующий шаг — протестировать и оценить, как эти скрытые паттерны ведут себя на разных рынках и в разных условиях.
Тестирование советника Hidden Smash Day
После завершения разработки следующий шаг — проверить, что советник ведет себя именно так, как задумано. Это включает два этапа. Сначала визуальная проверка на графиках в реальном времени подтверждает, что система правильно определяет скрытые бары Smash Day и открывает позиции в соответствии с заданными правилами. Затем историческое тестирование позволяет оценить стратегию в контролируемых условиях.
Визуальная проверка на графике
Первый шаг — убедиться, что советник точно определяет паттерны Hidden Smash Day и исполняет сделки только после надлежащего подтверждения.
На этом этапе представлены два скриншота. Один показывает активную длинную позицию.

Другой показывает активную короткую позицию, открытую советником.

В примере длинной сделки скрытый бар Smash Day закрывается в нижней части собственного диапазона и при этом закрывается выше закрытия предыдущего бара. Это удовлетворяет структурному требованию бычьего Hidden Smash Day. Затем следующий бар закрывается выше максимума этого бара Smash Day, подтверждая разворот. После завершения подтверждающего бара советник открывает длинную позицию на открытии нового бара.
Пример короткой сделки повторяет ту же логику зеркально. Скрытый бар Smash Day закрывается в верхней части своего диапазона и при этом закрывается ниже закрытия предыдущего бара. Это формирует медвежий скрытый сетап Smash Day. Затем следующая сессия закрывается ниже минимума бара Smash Day, подтверждая сигнал. На открытии следующего бара советник открывает короткую позицию.
Эти примеры подтверждают, что система правильно применяет правила, установленные ранее в статье. Сетап-бар определяется корректно, подтверждение требуется от завершенного бара, а сделки исполняются только после выполнения условий сигнала.
Тестирование на исторических данных
После подтверждения корректного поведения торговой логики на графике следующий шаг — оценить систему на исторических данных.
Исторический бэктест был проведен на золоте XAUUSD на дневном таймфрейме. Период тестирования начался 1 января 2025 года и продолжался до 28 февраля 2026 года, охватив чуть больше одного года рыночной активности.
Во время этого теста советник был настроен так, чтобы разрешать как сетапы Hidden Smash Day на покупку, так и на продажу. Был включен автоматический расчет размера позиции, при котором каждая сделка рисковала одним процентом баланса счета.
Чтобы сделать результаты полностью воспроизводимыми, к статье прикреплены два вспомогательных файла. Первый файл с именем configurations.ini содержит настройки среды тестера стратегий. Второй файл называется parameters.set и содержит точные входные параметры, использованные во время теста.
Результаты бэктеста

Тест начался с начального баланса счета 10 000 долларов. За период тестирования система получила чистую прибыль 1 371,64 доллара, что соответствует доходности немного выше тринадцати процентов. Доля прибыльных сделок в тесте составила 100%. В этом конкретном периоде выборки сработали только длинные сетапы.
Кривая баланса ниже показывает плавное восходящее движение без резких падений или крупных просадок.

Предопределенные правила стоп-лосса контролировали убытки, а политика одной позиции предотвращала перекрытие экспозиции.
Хотя эти результаты относятся к одной конфигурации и одному рынку, они подтверждают, что советник последовательно исполняет логику Hidden Smash Day и демонстрирует стабильное поведение кривой капитала в протестированных условиях.
Эксперименты со стратегией
Одна из главных целей этого проекта — предоставить структурированный инструмент для исследования и проверки, а не жесткую торговую систему. В советнике вынесено несколько параметров для настройки и экспериментов. Режим направления, метод стоп-лосса, соотношение прибыли и риска, конфигурацию ATR и процент риска можно менять без изменения исходного кода.
Дополнительные тесты на других символах, таймфреймах или комбинациях параметров могут выявить условия, в которых паттерн Hidden Smash Day ведет себя иначе или работает эффективнее. Исследование этих вариантов настоятельно приветствуется. Любые интересные наблюдения или улучшения, найденные при тестировании, можно поделиться в комментариях к статье, чтобы другие участники серии также получили пользу от обсуждения.
После этой статьи вы сможете
- выявлять сетапы Hidden Smash Day с помощью точных структурных правил.
- подтверждать сигналы через закрытие завершенного бара за экстремумом бара Smash Day.
- автоматически исполнять сделки на новых барах без дискреционной интерпретации.
- контролировать риск с помощью структурных стопов или стопов на основе ATR
- последовательно тестировать стратегию в тестере стратегий MetaTrader с воспроизводимыми настройками.
Ограничения системы
Эта реализация сосредоточена только на базовом паттерне Hidden Smash Day и логике его подтверждения. Несколько факторов, способных повлиять на торговые результаты, намеренно исключены.
Советник не применяет фильтры тренда или рыночного режима. Он не учитывает изменения спреда, торговые сессии или новостные события. Обработка гэпов и продвинутые методы управления позицией также находятся за рамками этой реализации.
Эти исключения намеренны. Цель статьи — построить ясную и тестируемую основу, отражающую исходную структуру паттерна. Дополнительные фильтры и расширения можно изучать в будущих экспериментах или следующих частях этой серии.
Заключение
В этой статье разворотный паттерн Hidden Smash Day был формализован в полноценный и тестируемый советник MQL5.
Правила сетапа были определены через измеримые условия, основанные на собственном диапазоне бара и его отношении к предыдущему закрытию. Подтверждение было строго задано как полное закрытие бара за экстремумом бара Smash Day. Торговые решения принимаются только на открытии нового бара, чтобы исключить неоднозначность незавершенного бара.
Управление риском было встроено непосредственно в систему. Стоп-лосс может размещаться структурно на уровне бара Smash Day или рассчитываться с использованием ATR. Прибыль выводится из фиксированного соотношения прибыли и риска. Автоматический расчет размера позиции использует OrderCalcProfit, чтобы обеспечить стабильный денежный риск по разным инструментам.
После изучения этой статьи теперь можно:
- объективно выявлять сетапы Hidden Smash Day.
- применять последовательное правило подтверждения по цене закрытия.
- исполнять сделки только на полностью завершенных барах.
- выбирать между структурными стопами и стопами на основе волатильности.
- контролировать экспозицию через точный процентный риск.
- воспроизводить результаты тестов с помощью предоставленных конфигурационных файлов.
Итоговый результат — готовый к компиляции советник, который реализует паттерн Hidden Smash Day без дискреционной интерпретации. Эту структуру можно тестировать, изменять и расширять, сохраняя исходную систему правил.
Обзор прикрепленных файлов
Чтобы упростить воспроизведение и дальнейшее исследование, к статье прикреплены все использованные и упомянутые файлы. В таблице ниже приведено краткое описание каждого файла и его назначения. Эти вложения позволяют просматривать, тестировать и расширять стратегию без неоднозначности.
| Имя файла | Описание |
|---|---|
| lwHiddenSmashDayExpert.mq5 | Полный исходный код советника, разработанный и объясненный в этой статье. |
| configurations.ini | Конфигурация среды тестера стратегий, использованная во время бэктеста. |
| parameters.set | Набор входных параметров для точного воспроизведения показанных результатов бэктеста. |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/21391
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Разработка инструментария для анализа Price Action (Часть 67): Автоматизация мониторинга уровней поддержки и сопротивления в MQL5
Торговые инструменты на MQL5 (Часть 30): Боковая панель палитры инструментов с архитектурой на основе классов
Автоматизация торговых стратегий с помощью MQL5 (Часть 48): Блоки ордеров, провокация ликвидности, пробой структуры
От начального до среднего уровня: Произвольный доступ (II)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Спасибо за идею и предоставленные коды...
При точно таких же настройках советник совершил 4 сделки на покупку и 2 SL / 2 TP с прибылью 508 долларов США // Думаю, это связано с различиями между брокерами ?!?
Пробовал D1 / H1 / M5 в качестве таймфреймов для советника, но были заключены точно такие же сделки в те же даты с такими же результатами по SL / TP