English Deutsch 日本語
preview
Рыночные секреты Ларри Уильямса (Часть 4): Автоматизация краткосрочных свинговых максимумов и минимумов в MQL5

Рыночные секреты Ларри Уильямса (Часть 4): Автоматизация краткосрочных свинговых максимумов и минимумов в MQL5

MetaTrader 5Трейдинг |
40 2
Chacha Ian Maroa
Chacha Ian Maroa

Введение

Если смотреть на рынок свеча за свечой, он часто кажется хаотичным. Цена движется вверх, затем вниз, затем вбок, и многие трейдеры не понимают, есть ли у этих движений какая-либо структура. Однако задолго до того, как алгоритмическая торговля стала популярной, Ларри Уильямс предложил иной взгляд. В книге Долгосрочные секреты краткосрочной торговли Ларри Уильямс утверждал, что ценовое движение не является полностью случайным, а определенные краткосрочные свинговые паттерны повторяются достаточно часто, чтобы давать измеримое преимущество. Эти идеи основывались на наблюдениях, статистике и десятилетиях реального рыночного опыта.

В предыдущей части этой серии мы протестировали несколько идей Ларри Уильямса с помощью кода и реальных исторических данных. Один результат выделился особенно явно. После формирования краткосрочного свингового минимума рынки демонстрировали сильную и устойчиво бычью реакцию. Такое поведение проявлялось на разных классах активов и временных интервалах, что указывает на неслучайность паттерна. Эти выводы естественным образом подводят к важному вопросу: если такое поведение можно измерить и подтвердить, можно ли также автоматизировать его и протестировать как полноценную торговую систему?

Здесь мы переходим к следующему этапу — от анализа к реализации, создавая полностью автоматизированного советника на MQL5, который торгует по краткосрочным свинговым минимумам и максимумам Ларри Уильямса. Цель состоит не в оптимизации и не в подгонке под исторические данные, а в структуре и ясности. Переводя четко определенную концепцию анализа ценового движения в точные правила и код, мы создаем инструмент, который позволяет трейдерам самостоятельно тестировать, проверять и улучшать эти идеи. К концу статьи у читателя будет практический каркас для превращения наблюдаемого рыночного поведения в систематический и проверяемый торговый подход.


Определение и выявление краткосрочных свинговых точек Ларри Уильямса

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

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

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

Краткосрочный минимум

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

Краткосрочный максимум

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

Обратите внимание на рисунок 3, где потенциальный свинговый минимум признается недействительным из-за внешнего бара (outside bar).

Внешний бар

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

Аналогично, на рисунке 4 показано влияние внутренних баров (inside bars).

Внутренний бар

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

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

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


Общая архитектура советника

Хорошо спроектированную систему легче тестировать, расширять и применять с уверенностью. В этом разделе мы обозначим ключевые принципы проектирования, на которых строится наш советник для торговли краткосрочными свинговыми минимумами и максимумами Ларри Уильямса.

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

Управление направлением торговли

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

Размер позиции и контроль риска

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

Логика выхода из сделки

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

Размещение защитного стопа

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

Модульная архитектура

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

Дополнительные проектные соображения

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

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


Пошаговое написание советника

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

Прежде чем продолжить, стоит отметить несколько моментов. В этой статье предполагается, что читатель уже имеет практические знания языка программирования MQL5. Вы должны уверенно читать и писать советники без необходимости объяснять базовый синтаксис. Также предполагается знакомство с MetaTrader 5 и MetaEditor 5, включая создание новых файлов советников, компиляцию программ MQL5, прикрепление их к графикам и чтение сообщений компилятора. Также ожидается базовый опыт работы с тестером стратегий, поскольку этот советник предназначен для тестирования и оценки в разных рыночных условиях.

Чтобы облегчить обучение, к статье приложен полный исходный файл с именем lwShortTermStructureExpert.mq5. В нем находится готовая версия советника, который мы собираемся построить. Рекомендую скачать его и держать открытым для справки. Вы сможете сравнивать его со своей реализацией всякий раз, когда что-то покажется непонятным. Лучший способ учиться программированию — писать код самостоятельно, часто компилировать его и наблюдать, как реагирует платформа.

Для начала откройте MetaEditor 5 и создайте новый пустой файл советника. Назовите его lwShortTermStructureExpert.mq5. После создания файла вставьте приведенный ниже исходный код в редактор и скомпилируйте его.

//+------------------------------------------------------------------+
//|                                   lwShortTermStructureExpert.mq5 |
//|          Copyright 2025, MetaQuotes Ltd. Developer is Chacha Ian |
//|                          https://www.mql5.com/en/users/chachaian |
//+------------------------------------------------------------------+

#property copyright   "Copyright 2025, MetaQuotes Ltd. Developer is Chacha Ian"
#property link        "https://www.mql5.com/en/users/chachaian"
#property version     "1.00"
#property description "This Expert Advisor automates Larry Williams’ short-term swing high and swing low trading methodology."
#property description "Trades are executed based on validated short-term swing formations derived from market structure."
#property description "The EA supports both time-based exits (single-bar holding) and risk-reward–based take-profit models."

//+------------------------------------------------------------------+
//| Standard Libraries                                               |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| User input variables                                             |
//+------------------------------------------------------------------+
input group "Information"
input ulong           magicNumber           = 254700680002;                 
input ENUM_TIMEFRAMES timeframe             = PERIOD_CURRENT;

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
//--- Create a CTrade object to handle trading operations

CTrade Trade;

//--- Bid and Ask
double   askPrice;
double   bidPrice;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //---  Assign a unique magic number to identify trades opened by this EA
   Trade.SetExpertMagicNumber(magicNumber);

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){

   //--- Notify why the program stopped running
   Print("Program terminated! Reason code: ", reason);

}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   //--- Retrieve current market prices for trade execution
   askPrice      = SymbolInfoDouble (_Symbol, SYMBOL_ASK);
   bidPrice      = SymbolInfoDouble (_Symbol, SYMBOL_BID);
   
}

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
{

   //--- To handle trade transaction events

}
  
//+------------------------------------------------------------------+

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

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

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

Раздел глобальных переменных хранит объекты и значения, к которым нужен доступ во всем советнике. Здесь мы создаем объект CTrade , который будет выполнять все торговые операции. Также мы объявляем переменные для хранения текущих цен bid и ask, которые необходимы при открытии сделок.
Функция инициализации вызывается один раз при запуске советника. Ее основная роль здесь — назначить торговому объекту уникальный идентификатор советника (magic number). Это позволяет советнику корректно определять и управлять только собственными позициями.

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

Функция тика — это место, где советник реагирует на рыночную активность. На этом этапе она только получает текущие цены bid и ask . В следующих разделах эта функция будет содержать основную логику обнаружения краткосрочных свинговых структур и открытия сделок.
Наконец, функция торговой транзакции добавлена как заготовка. Она позволяет советнику реагировать на торговые события, такие как исполнение ордера или закрытие позиции. Позже мы используем ее для более точного мониторинга и управления поведением сделок.

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

Логика обнаружения сигналов

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

В этом советнике мы намеренно избегаем вызова пользовательского индикатора. Вместо этого мы выявляем краткосрочные свинговые формации Ларри Уильямса непосредственно по ценовым данным. Такое проектное решение делает советник легким, более удобным для распространения и полностью самодостаточным — все, что требуется для определения паттерна, находится внутри самого советника.

Обнаружение сигналов в правильный момент

Краткосрочные свинги Ларри Уильямса — это трехбарные структуры. Чтобы надежно их обнаруживать, необходимо дождаться полного закрытия всех требуемых баров. Поэтому обнаружение сигналов выполняется только при открытии нового бара.

Когда появляется новый бар, он занимает индекс ноль в ценовом ряду. Три завершенных бара непосредственно перед ним имеют индексы 1, 2 и 3. Именно эти бары могут сформировать корректную краткосрочную свинговую формацию.

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

//--- UTILITY FUNCTIONS
//+------------------------------------------------------------------+
//| 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;
   
}

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

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

Чтобы это работало, мы также определяем глобальную переменную datetime. Она хранит временную метку последнего обработанного бара и позволяет советнику сохранять состояние между тиками.

//--- To help track new bar open
datetime lastBarOpenTime;

После объявления переменной мы задаем ее начальное значение внутри функции OnInit как показано ниже.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Initialize global variables
   lastBarOpenTime       = 0;

   return(INIT_SUCCEEDED);
}

Обнаружение краткосрочного свингового минимума

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

//+------------------------------------------------------------------+
//| Detects a Larry Williams short-term low on the last three bars   |
//| Bar index 2 must be a swing low with higher lows on both sides   |
//| Bar 2 must NOT be an outside bar                                 |
//| Bar 1 must NOT be an inside bar                                  |
//+------------------------------------------------------------------+
bool IsLarryWilliamsShortTermLow(string symbol, ENUM_TIMEFRAMES tf){

   //--- Price data for the three bars
   double high1 = iHigh(symbol, tf, 1);
   double low1  = iLow (symbol, tf, 1);

   double high2 = iHigh(symbol, tf, 2);
   double low2  = iLow (symbol, tf, 2);

   double high3 = iHigh(symbol, tf, 3);
   double low3  = iLow (symbol, tf, 3);

   //--- Condition 1: Bar 2 must be a swing low
   bool isSwingLow =
      (low2 < low1) &&
      (low2 < low3);

   if(!isSwingLow){
      return false;
   }
      
   //--- Condition 2: Bar 2 must NOT be an outside bar relative to bar 3
   bool isOutsideBar =
      (high2 > high3) &&
      (low2  < low3);

   if(isOutsideBar){
      return false;
   }

   //--- Condition 3: Bar 1 must NOT be an inside bar relative to bar 2
   bool isInsideBar =
      (high1 < high2) &&
      (low1  > low2);

   if(isInsideBar){
      return false;
   }

   //--- All conditions satisfied
   lwShortTermSwingLevel = NormalizeDouble(low2, Digits());
   return true;
}

Функция, обнаруживающая краткосрочный минимум Ларри Уильямса, начинает с получения цен high и low для баров 1, 2 и 3. Бар два является средним баром и кандидатом на свинговый бар.

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

Второе условие отфильтровывает внешние бары. Бар два не должен полностью поглощать бар три. Внешние бары часто искажают структуру, поэтому они исключаются, чтобы паттерн оставался чистым и последовательным.

Третье условие проверяет бар один. Он не должен быть внутренним баром относительно бара два. Внутренние бары отражают сжатие и неопределенность, чего Ларри Уильямс явно избегает при определении корректных свинговых точек.

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

Обнаружение краткосрочного свингового максимума

Логика обнаружения краткосрочного свингового максимума является обратной логике свингового минимума.

//+------------------------------------------------------------------+
//| Detects a Larry Williams short-term high on the last three bars  |
//| Bar index 2 must be a swing high with lower highs on both sides  |
//| Bar 2 must NOT be an outside bar                                 |
//| Bar 1 must NOT be an inside bar                                  |
//+------------------------------------------------------------------+
bool IsLarryWilliamsShortTermHigh(string symbol, ENUM_TIMEFRAMES tf){

   //--- Price data for the three bars
   double high1 = iHigh(symbol, tf, 1);
   double low1  = iLow (symbol, tf, 1);

   double high2 = iHigh(symbol, tf, 2);
   double low2  = iLow (symbol, tf, 2);

   double high3 = iHigh(symbol, tf, 3);
   double low3  = iLow (symbol, tf, 3);

   //--- Condition 1: Bar 2 must be a swing high
   bool isSwingHigh =
      (high2 > high1) &&
      (high2 > high3);

   if(!isSwingHigh){
      return false;
   }
      
   //--- Condition 2: Bar 2 must NOT be an outside bar relative to bar 3
   bool isOutsideBar =
      (high2 > high3) &&
      (low2  < low3);

   if(isOutsideBar){
      return false;
   }

   //--- Condition 3: Bar 1 must NOT be an inside bar relative to bar 2
   bool isInsideBar =
      (high1 < high2) &&
      (low1  > low2);

   if(isInsideBar){
      return false;
   }

   //--- All conditions satisfied
   lwShortTermSwingLevel = NormalizeDouble(high2, Digits());
   return true;
}

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

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

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

Отслеживание последнего свингового уровня

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

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

//--- Stores the price level of the most recently detected Larry Williams' short-term swing high or low
double lwShortTermSwingLevel;

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

После объявления переменной мы задаем ее начальное значение внутри функции OnInit как показано ниже.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   ...
   
   //--- Initialize global variables
   
   ...
   
   lwShortTermSwingLevel = DBL_MAX;

   return(INIT_SUCCEEDED);
}

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

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

Торговая логика и открытие ордеров

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

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

Контроль направления торговли

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

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

//--- CUSTOM ENUMERATIONS
enum ENUM_TRADE_DIRECTION  
{ 
   ONLY_LONG, 
   ONLY_SHORT, 
   TRADE_BOTH 
};

Затем мы предоставляем этот выбор пользователю в виде входного параметра.

input group "Trade And Risk Management"
input ENUM_TRADE_DIRECTION direction        = TRADE_BOTH;

Во время работы советник проверяет эту настройку перед открытием любого ордера. Сигналы, не соответствующие выбранному направлению, полностью игнорируются. 

Режимы определения размера лота

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

enum ENUM_LOT_SIZE_INPUT_MODE 
{ 
   MODE_MANUAL, 
   MODE_AUTO 
};

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

Оба режима вынесены во входные параметры.

input ENUM_LOT_SIZE_INPUT_MODE lotSizeMode  = MODE_AUTO;
input double riskPerTradePercent            = 1.0;
input double positionSize                   = 0.01;

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

Режимы фиксации прибыли и контроль риск/прибыль

Следующий уровень гибкости — логика выхода из сделки. На основе предыдущих экспериментов мы знаем, что краткосрочные свинговые паттерны часто дают направленное движение в пределах следующего бара. Однако некоторые трейдеры предпочитают структурированные целевые уровни прибыли.

Чтобы поддержать оба подхода, мы определяем перечисление режимов тейк-профита.

enum ENUM_TAKE_PROFIT_MODE
{
   TP_HOLD_ONE_BAR,
   TP_FIXED_RRR_1_ONE,
   TP_FIXED_RRR_1_ONEptFIVE,
   TP_FIXED_RRR_1_TWO,
   TP_FIXED_RRR_1_THREE
};

Первый вариант закрывает сделки ровно через один бар. В этом режиме тейк-профит не устанавливается. Выход из сделок выполняется по времени, а не по цене.

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

Один входной параметр позволяет пользователю выбрать желаемый стиль выхода. Советник автоматически адаптирует свое поведение в соответствии с этим выбором.

input ENUM_TAKE_PROFIT_MODE takeProfitMode  = TP_HOLD_ONE_BAR;

Ограничение одной сделкой за раз

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

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

//+------------------------------------------------------------------+
//| 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;
}

Эти функции просматривают все открытые позиции и ищут позицию, которая соответствует magic number советника и требуемому типу сделки.

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

Функции проверки позиции buy или sell имеют одинаковую структуру. Как только читатель понимает одну из них, другая становится сразу понятной.

Закрытие сделок, удерживаемых один бар

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

//+------------------------------------------------------------------+
//| To close all positions with a specified magic number             |   
//+------------------------------------------------------------------+
void ClosePositionsByMagic(ulong magic) {
    
    for (int i = PositionsTotal() - 1; i >= 0; i--) {
        ulong ticket = PositionGetTicket(i);
        if (PositionSelectByTicket(ticket)) {
            if (PositionGetInteger(POSITION_MAGIC) == magic) {
                ulong positionType = PositionGetInteger(POSITION_TYPE);
                double volume = PositionGetDouble(POSITION_VOLUME);
                if (positionType == POSITION_TYPE_BUY) {
                    Trade.PositionClose(ticket);
                } else if (positionType == POSITION_TYPE_SELL) {
                    Trade.PositionClose(ticket);
                }
            }
        }
    }    
}

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

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

Открытие позиции Buy

Когда все вспомогательные компоненты готовы, мы можем открывать сделки.

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

//+------------------------------------------------------------------+
//| Function to open a market long position                          |
//+------------------------------------------------------------------+
bool OpenBuy(double entryPrice, double lotSize){
   
   double stopLevel      = lwShortTermSwingLevel;
   double stopDistance   = entryPrice - stopLevel;
   double contractSize   = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   if(takeProfitMode == TP_HOLD_ONE_BAR){
   
      if(lotSizeMode == MODE_AUTO){
         double amountAtRisk = (riskPerTradePercent / 100.0) *  accountBalance;
         lotSize             = amountAtRisk / (contractSize * stopDistance);
         lotSize             = NormalizeDouble(lotSize, 2);
      }
      
      if(!Trade.Buy(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }   
   
   }
   
   else{
   
      double rewardValue              = 1.0;
      
      switch(takeProfitMode){
         case TP_FIXED_RRR_1_ONE: 
            rewardValue = 1.0;
            break;
         case TP_FIXED_RRR_1_ONEptFIVE:
            rewardValue = 1.5;
            break;
         case TP_FIXED_RRR_1_TWO: 
            rewardValue = 2.0;
            break;
         case TP_FIXED_RRR_1_THREE: 
            rewardValue = 3.0;
            break;
         default:
            rewardValue = 1.0;
            break;
      }
      
      double targetLevel = NormalizeDouble(entryPrice + stopDistance * rewardValue ,Digits());
      if(!Trade.Buy(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel, targetLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }   
   }

   return true;
}

Она использует последний обнаруженный свинговый уровень как защитный стоп. Расстояние между ценой входа и этим стопом определяет риск сделки.

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

Затем функция проверяет выбранный режим тейк-профита. Если сделку нужно удерживать один бар, устанавливается только стоп-лосс. Если выбран фиксированный режим прибыли, уровень тейк-профита рассчитывается на основе выбранного соотношения риск/прибыль.

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

Открытие короткой позиции

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

//+------------------------------------------------------------------+
//| Function to open a market short position                         |
//+------------------------------------------------------------------+
bool OpenSel(double entryPrice, double lotSize){

   double stopLevel      = lwShortTermSwingLevel;
   double stopDistance   = stopLevel - entryPrice;
   double contractSize   = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   if(takeProfitMode == TP_HOLD_ONE_BAR){
      if(lotSizeMode == MODE_AUTO){
         double amountAtRisk = (riskPerTradePercent / 100.0) *  accountBalance;
         lotSize             = amountAtRisk / (contractSize * stopDistance);
         lotSize             = NormalizeDouble(lotSize, 2);
      }
      
      if(!Trade.Sell(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      }      
   }
   
   else{
   
      double rewardValue              = 1.0;
      
      switch(takeProfitMode){
         case TP_FIXED_RRR_1_ONE: 
            rewardValue = 1.0;
            break;
         case TP_FIXED_RRR_1_ONEptFIVE:
            rewardValue = 1.5;
            break;
         case TP_FIXED_RRR_1_TWO: 
            rewardValue = 2.0;
            break;
         case TP_FIXED_RRR_1_THREE: 
            rewardValue = 3.0;
            break;
         default:
            rewardValue = 1.0;
            break;
      }
      
      double targetLevel = NormalizeDouble(entryPrice - stopDistance * rewardValue ,Digits());
      if(!Trade.Sell(NormalizeDouble(lotSize, 2), _Symbol, entryPrice, stopLevel, targetLevel)){
         Print("Error while executing a market buy order: ", GetLastError());
         Print(Trade.ResultRetcode());
         Print(Trade.ResultComment());
         return false;
      } 
   
   }   

   return true;
}

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

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

Объединение всего в OnTick

На этом этапе мы уже построили все основные части советника. Мы умеем обнаруживать корректные краткосрочные свинговые сигналы, рассчитывать риск, открывать сделки и управлять ими. Осталось соединить эти части так, чтобы советник в реальном времени вел себя именно так, как задумано.

Финальная интеграция выполняется внутри функции OnTick .

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   ...
   
   //--- Run this block only when a new bar is detected on the selected timeframe
   if(IsNewBar(_Symbol, timeframe, lastBarOpenTime)){
      
      if(takeProfitMode == TP_HOLD_ONE_BAR){
      
         //--- Close any existing buy positions for this EA before opening a new one
         if(IsThereAnActiveBuyPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(100);
         }
         
         if(IsThereAnActiveSellPosition(magicNumber)){
            ClosePositionsByMagic(magicNumber);
            Sleep(100);
         }      
      
      }
      
      //---  Enter a buy position when a Larry Williams-defined short-term low swing pattern is detected
      if(direction == ONLY_LONG || direction == TRADE_BOTH){

         if(IsLarryWilliamsShortTermLow(_Symbol, timeframe) && !IsThereAnActiveBuyPosition(magicNumber) && !IsThereAnActiveSellPosition(magicNumber)){
            OpenBuy(askPrice, positionSize);
         }

      }

      //---  Enter a short position when a Larry Williams-defined short-term high swing pattern is detected
      if(direction == ONLY_SHORT || direction == TRADE_BOTH){

         if(IsLarryWilliamsShortTermHigh(_Symbol, timeframe) && !IsThereAnActiveSellPosition(magicNumber) && !IsThereAnActiveBuyPosition(magicNumber)){
            OpenSel(bidPrice, positionSize);
         }
      }           
   }
}

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

Почему мы торгуем только на новом баре

Первое и самое важное решение внутри OnTick заключается в том, что вся логика выполняется только при обнаружении нового бара на выбранном таймфрейме.

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

Это также сохраняет эффективность советника. Вместо оценки условий на каждом тике советник принимает решения один раз на бар — именно это и требуется для стратегии такого типа.

Управление сделками на один бар

Когда режим тейк-профита установлен на удержание в течение 1 бара, управление сделкой становится основанным на времени, а не на цене.

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

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

Оценка сигналов на покупку

После очистки сделок советник переходит к оценке сигналов.

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

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

Оценка сигналов на продажу

Логика сделок sell имеет ту же структуру.

Если короткие сделки разрешены, советник ищет корректный паттерн краткосрочного максимума Ларри Уильямса. Перед продолжением он снова подтверждает, что активной позиции нет.

Когда условия выполнены, открывается позиция sell с использованием тех же правил управления риском и открытия сделок, но в противоположном направлении. Поскольку логика buy и sell спроектирована как зеркальное отражение, поведение остается последовательным и предсказуемым.

Суть процесса

Сила этой структуры заключается в ее простоте.

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

Теперь советник ведет себя как дисциплинированный трейдер. Он терпеливо ждет, действует только на подтвержденной структуре, соблюдает правила риска и никогда не переторговывает.

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

Функция ConfigureChartAppearance выполняет эту задачу.

//+------------------------------------------------------------------+
//| 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);
}

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

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


Проверка советника на практике

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

Для этого исследования мы провели бэктесты за период с 1 января 2024 года по 30 ноября 2025 года. На момент написания статьи это охватывает примерно двадцать три месяца рыночных данных. Все тесты проводились только на дневном таймфрейме.

Советник был протестирован на четырех инструментах, представляющих разные типы рынков: товарный актив, индекс, криптовалюта и основная валютная пара Forex. Для обеспечения справедливости и повторяемости во всех тестах использовались одинаковые конфигурация и входные параметры. Они приложены к этой статье как configurations.ini и parameters.set, что позволяет воспроизвести те же результаты на собственной платформе.

Каждый тест начинался с начального баланса $10 000.

Золото

Золото показало наилучший результат среди всех протестированных инструментов. За период тестирования советник получил общую чистую прибыль $9 123,25 при доле прибыльных сделок 55%.

Gold Equity Curve

Gold Tester Report

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

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

S&P 500

S&P 500 показал скромные, но стабильные результаты. Общая чистая прибыль за период составила 158 долларов, а доля прибыльных сделок — 42,11%.

Equity Curve S&P 500

Test Report S&P 500

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

Скриншот кривой средств и подробный отчет тестирования предоставлены для визуального подтверждения этого поведения. 

Биткоин

На Биткоине советник показал уверенный результат за период тестирования. При начальном балансе 10 000 долларов система достигла общей чистой прибыли 4 572,63 доллара при доле прибыльных сделок 42,42%.

Bitcoin Equity Curve

Bitcoin Tester Report

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

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

Британский фунт

Британский фунт зафиксировал чистый убыток 279 долларов при том же начальном балансе 10 000 долларов и доле прибыльных сделок 19,05%.

GBPUSD Equity Curve

GBPUSD Tester Report

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

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

Итоги тестирования

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

Именно здесь ценными становятся ваши собственные эксперименты. Загрузив предоставленные файлы configurations.ini и parameters.set вы можете повторить эти тесты, настроить отдельные входные параметры и наблюдать, как меняется результативность на разных рынках и таймфреймах.

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


Заключение

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

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

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

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

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


Имя файла Описание
1. lwShortTermStructureExpert.mq5 Основной исходный код советника, подробно рассмотренный в этой статье, содержащий реализацию логики краткосрочной структуры
2. configurations.ini Конфигурационный файл, содержащий глобальные настройки среды, необходимые для тестирования советника
3. parameters.set Стандартизированный файл входных параметров, позволяющий быстро загрузить пользовательские настройки, использовавшиеся при бэктестировании.

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

Прикрепленные файлы |
configurations.ini (1.18 KB)
parameters.set (1.06 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
Arun Kumar
Arun Kumar | 30 янв. 2026 в 08:44
Здравствуйте,

Заказ на покупку не принимается, у нас возникла проблема: 30.01.2026 14:06:59.971 lwShortTermStructureExpert (XAUUSDm,M1) Ошибка при выполнении рыночного ордера на покупку: 0

Chacha Ian Maroa
Chacha Ian Maroa | 30 янв. 2026 в 08:50
Arun Kumar XAUUSDm,M1) Ошибка при выполнении рыночного ордера на покупку: 0

Спасибо, я это проверю.
Архитектура прибыльной торговли с усиленной многоуровневой защитой счёта Архитектура прибыльной торговли с усиленной многоуровневой защитой счёта
В этом материале мы представляем структурированную многоуровневую систему защиты, нацеленную на достижение амбициозных показателей прибыли при одновременном снижении риска катастрофических потерь. Основное внимание уделяется сочетанию агрессивной торговой логики с защитными механизмами на каждом этапе торгового процесса. Идея состоит в том, чтобы создать советника, который ведёт себя как «хищник, осознающий риск»: способен находить торговые возможности с высоким потенциалом, но всегда имеет несколько защитных слоёв, не позволяющих системе «ослепнуть» при внезапном рыночном стрессе.
Рыночные секреты Ларри Уильямса (Часть 3): Проверка неслучайного поведения рынка средствами MQL5 Рыночные секреты Ларри Уильямса (Часть 3): Проверка неслучайного поведения рынка средствами MQL5
Исследуйте, действительно ли финансовые рынки случайны, воспроизводя эксперименты Ларри Уильямса по поведению рынка с помощью MQL5. В этой статье показано, как простые тесты на основе поведения цены могут выявлять статистические перекосы в поведении рынка с помощью советника (Expert Advisor, EA).
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Моделирование рынка: Position View (III) Моделирование рынка: Position View (III)
В предыдущих статьях мы упоминали, что иногда нам необходимо задать значение для свойства ZOrder. Но почему? Причина в том, что многие коды, добавляющие объекты на график, просто не используют или, точнее, не определяют значение для этого свойства. Дело в том, что я здесь не для того, чтобы говорить, что должен или не должен делать каждый программист, или как он должен или не должен писать свой код. Я здесь для того, чтобы показать вам, уважаемый читатель, и всем, кто действительно хочет понять внутреннее устройство процессов, что именно происходит за кулисами.