Разработка динамического мультивалютного советника (Часть 5): Скальпинг и свинг-трейдинг
Содержание
Введение
Выбрать подходящий стиль торговли для разных рыночных условий часто бывает непросто. На быстро движущемся рынке свинг-стратегии могут оказаться слишком медленными, а в волатильные сессии скальперские сделки с близкими целями могут быстро закрываться по стоп-лоссу. Это создает дилемму: трейдер либо упускает краткосрочные возможности с высокой вероятностью, либо начинает переторговывать в условиях, не подходящих для выбранной стратегии. В результате прибыль становится нестабильной, а системы, которые хорошо работают на одном активе или таймфрейме, часто дают сбой при переносе на другие.
Эту проблему можно решить, разработав динамический мультивалютный советник, который объединяет режимы скальпинга и свинг-трейдинга в рамках единой системы. Благодаря возможности переключать эти режимы вручную или автоматически на основе волатильности и структуры рынка советник может динамически адаптировать торговую логику, уровни стопов и временные горизонты. Это позволяет системе сохранять прибыльность в разных условиях, сочетая быструю внутридневную прибыль с более длительными и качественными свинг-сетапами.
Обзор системы
Скальпинг – это торговый подход, ориентированный на извлечение выгоды из очень небольших ценовых движений на коротких таймфреймах, часто от нескольких секунд до нескольких минут. Трейдеры, использующие этот стиль, открывают и закрывают множество позиций в течение дня, стремясь зарабатывать на микроколебаниях цены, а не на крупных направленных движениях. Такой подход требует точности, быстрого исполнения и строгой дисциплины, так как спреды, проскальзывание и издержки на сделки могут быстро съедать прибыль. Скальперы в основном работают на младших таймфреймах, таких как M1 и M5, используя технические индикаторы вроде скользящих средних, всплесков объема и осцилляторов импульса, чтобы с высокой точностью определять точки входа и выхода.

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

| Аспект | Скальпинг | Свинг-трейдинг |
|---|---|---|
| Длительность сделки | От секунд до минут | От часов до дней (иногда недель) |
| Частота сделок | От десятков до сотен в день | От 1 до 10 сделок в неделю (в среднем) |
| Цель | Извлечение прибыли из небольших частых ценовых движений (50-100 пипсов или $0.50-$1 на металлах) | Извлечение прибыли из более крупных рыночных свингов (сотни пипсов) |
| Затраты времени | Интенсивный режим, много времени у экрана | Умеренные, с акцентом на анализ |
| Рыночный контекст | Лучше всего работает на рынках с высокой волатильностью и высокой ликвидностью (например, XAUUSD и основных валютных парах). | Лучше всего работает на трендовых рынках или при расширении диапазона. |
| Стоп-лосс / тейк-профит | Очень узкий SL (50-150 пипсов) / небольшой TP (40-100 пипсов) | Более широкий SL (200+ пипсов) / более крупный TP (1000+ пипсов) |
| Размер позиции | Обычно больше, так как цели небольшие | Обычно меньше, так как целевые уровни дальше |
Приступим
//+------------------------------------------------------------------+ //| Scalps and Swings.mq5 | //| GIT under Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com/ru/users/johnhlomohang/ | //+------------------------------------------------------------------+ #property copyright "GIT under Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/ru/users/johnhlomohang/" #property version "1.00" #property description "Dual-mode EA for Scalping and Swing Trading" #include <Trade/Trade.mqh>
Как обычно, мы начинаем с импорта важнейшей торговой библиотеки, необходимой для того, чтобы наш советник исполнял ордера и управлял позициями.
//+------------------------------------------------------------------+ //| Input Parameters | //+------------------------------------------------------------------+ enum ENUM_MODE { MODE_SCALP, // Scalping MODE_SWING // Swing Trading }; input ENUM_MODE TradeMode = MODE_SCALP; // Trading Mode input string TradePairs = "XAUUSD,BTCUSD,US100,GBPUSD"; // Trading Pairs (comma separated) input bool UseATR = false; // Use ATR for SL/TP // Scalping Parameters input double LotSize_Scalp = 0.1; // Scalp Lot Size input int StopLoss_Scalp = 50; // Scalp Stop Loss (pips) input int TakeProfit_Scalp = 30; // Scalp Take Profit (pips) input int ScalpTrailingStop = 15; // Scalp Trailing Stop (pips) input ENUM_TIMEFRAMES ScalpTimeframe = PERIOD_M5; // Scalping Timeframe input int Scalp_EMA_Fast = 5; // Scalp Fast EMA input int Scalp_EMA_Slow = 20; // Scalp Slow EMA input int Scalp_RSI_Period = 14; // Scalp RSI Period input int Scalp_RSI_Overbought = 55; // Scalp RSI Overbought input int Scalp_RSI_Oversold = 45; // Scalp RSI Oversold // Swing Trading Parameters input double LotSize_Swing = 0.1; // Swing Lot Size input int StopLoss_Swing = 200; // Swing Stop Loss (pips) input int TakeProfit_Swing = 400; // Swing Take Profit (pips) input int SwingTrailingStop = 100; // Swing Trailing Stop (pips) input ENUM_TIMEFRAMES SwingTimeframe = PERIOD_H4; // Swing Timeframe input int Swing_Lookback = 20; // Swing Lookback Period input double Fib_Level = 0.618; // Fibonacci Retracement Level input bool UseHigherTFConfirmation = true; // Use D1 Confirmation input ENUM_TIMEFRAMES HigherTF = PERIOD_D1; // Higher Timeframe // Risk Management input int MaxOpenPositions = 4; // Max Open Positions per Pair input int MagicNumber = 12345; // Magic Number input int Slippage = 3; // Slippage (points)
Начнем с определения входных параметров многорежимной торговой системы, поддерживающей и скальпинг, и свинг-трейдинг. В первом блоке задается перечисление ENUM_MODE, которое позволяет пользователю выбирать между MODE_SCALP и MODE_SWING. Этот параметр определяет поведение советника: будет ли он торговать краткосрочные внутридневные движения или более длительные рыночные движения. Входной параметр TradePairs позволяет задать несколько инструментов, например XAUUSD, BTCUSD, US100 и GBPUSD, а опция UseATR позволяет использовать адаптивные уровни стоп-лосса и тейк-профита на основе волатильности, а не фиксированных значений в пипсах.
Параметры скальпинга определяют, как советник ведет себя в быстрых, высокочастотных условиях. К ним относятся меньшие расстояния Stop Loss и Take Profit, более короткий таймфрейм, например M5, и более быстрые индикаторы, такие как EMA с периодами 5 и 20 в сочетании с RSI с периодом 14. Пороги RSI намеренно сделаны узкими (55 и 45), чтобы выявлять небольшие изменения импульса. Значение трейлинг-стопа меньше, что делает сделки более чувствительными к внутридневной волатильности. Эти настройки обеспечивают быстрые торговые циклы, позволяя отрабатывать небольшие ценовые колебания без излишнего влияния длительного рыночного шума.
Напротив, параметры свинг-трейдинга настроены на более масштабные движения рынка. Советник использует более широкие уровни стоп-лосса и тейк-профита, чтобы учитывать волатильность старшего таймфрейма и продолжение тренда. Период анализа в 20 баров и уровень коррекции Фибоначчи (0.618) помогают выявлять ключевые коррекционные зоны для возможных разворотов. Подтверждение на старшем таймфрейме, обычно D1, добавляет дополнительную проверку тренда, помогая избегать сделок против тренда. Наконец, входные параметры управления рисками, такие как MaxOpenPositions, MagicNumber и Slippage, обеспечивают надежный контроль над объемом торговли, идентификацией сделок и точностью исполнения ордеров, благодаря чему советник работает стабильно и безопасно на всех парах и в любых условиях.
//+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ string SymbolList[]; int TotalPairs; datetime LastTickTime = 0; color TextColor = clrWhite; CTrade trade; int handleEmaFast_Scalp, handleEmaSlow_Scalp, handleRsi_Scalp; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize trade object trade.SetExpertMagicNumber(MagicNumber); trade.SetDeviationInPoints(Slippage); // Split trading pairs SplitString(TradePairs, ",", SymbolList); TotalPairs = ArraySize(SymbolList); // Validate symbols for(int i = 0; i < TotalPairs; i++) { if(!SymbolInfoInteger(SymbolList[i], SYMBOL_TRADE_MODE)) { Print("Error: Symbol ", SymbolList[i], " is not available for trading"); return(INIT_FAILED); } } // Create indicator handles for scalping mode handleEmaFast_Scalp = iMA(NULL, ScalpTimeframe, Scalp_EMA_Fast, 0, MODE_EMA, PRICE_CLOSE); if(handleEmaFast_Scalp == INVALID_HANDLE) { Print("Failed to create handle for fast EMA (Scalp)"); return(INIT_FAILED); } handleEmaSlow_Scalp = iMA(NULL, ScalpTimeframe, Scalp_EMA_Slow, 0, MODE_EMA, PRICE_CLOSE); if(handleEmaSlow_Scalp == INVALID_HANDLE) { Print("Failed to create handle for slow EMA (Scalp)"); return(INIT_FAILED); } handleRsi_Scalp = iRSI(NULL, ScalpTimeframe, Scalp_RSI_Period, PRICE_CLOSE); if(handleRsi_Scalp == INVALID_HANDLE) { Print("Failed to create handle for RSI (Scalp)"); return(INIT_FAILED); } Print("EA initialized successfully with ", TotalPairs, " pairs"); Print("Trading Mode: ", EnumToString(TradeMode)); return(INIT_SUCCEEDED); }
Затем определяются глобальные переменные и процедура инициализации советника. В глобальных переменных задаются ключевые компоненты: список торговых символов, общее число пар и экземпляр класса CTrade для исполнения сделок. Дополнительные переменные включают хэндлы индикаторов для режима скальпинга – быстрой EMA, медленной EMA и RSI, которые позже будут использоваться для получения данных в реальном времени при генерации сигналов. Переменная LastTickTime повышает эффективность обработки тиков, а TextColor задает цвет по умолчанию для текстовых элементов графика, используемых при визуализации или логировании.
В функции OnInit() советник начинает с настройки торговой среды. В объекте CTrade задаются уникальное магическое число и допустимое проскальзывание для последовательного управления ордерами. Входная строка TradePairs разбивается на массив с помощью пользовательской функции SplitString(), определяющей, с какими символами будет работать советник. Каждый символ проверяется, чтобы убедиться, что он доступен для торговли, прежде чем продолжится работа. Затем функция создает хэндлы индикаторов для быстрой и медленной EMA, а также RSI для режима скальпинга. Каждый хэндл проверяется на корректность, чтобы советник не запускался с некорректными ссылками на индикаторы. После успешного прохождения всех проверок выводятся сообщения об успешной инициализации, в которых указаны количество активных пар и выбранный торговый режим, что подтверждает полную готовность советника к работе.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Comment(""); // Clear chart comment } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Avoid multiple processing in the same tick if(LastTickTime == iTime(_Symbol, _Period, 0)) return; LastTickTime = iTime(_Symbol, _Period, 0); // Process each trading pair for(int i = 0; i < TotalPairs; i++) { string symbol = SymbolList[i]; if(TradeMode == MODE_SCALP) { ScalpModeHandler(symbol); if(IsNewBar(symbol, ScalpTimeframe)) { ExecuteScalpTrade(symbol); } ManageScalpTrades(symbol); } else if(TradeMode == MODE_SWING) { if(SwingSignal(symbol)) { if(IsNewBar(symbol, SwingTimeframe)) { ExecuteSwingTrade(symbol); } } ManageSwingTrades(symbol); } } // Update dashboard UpdateDashboard(); } //+------------------------------------------------------------------+ //| Check if new bar formed | //+------------------------------------------------------------------+ bool IsNewBar(string symbol, ENUM_TIMEFRAMES timeframe) { static datetime lastBarTime = 0; datetime currentBarTime = iTime(symbol, timeframe, 0); if(currentBarTime != lastBarTime) { lastBarTime = currentBarTime; return true; } return false; }
Как известно, функция OnTick() является основным циклом выполнения советника и запускается каждый раз при поступлении нового тика. Сначала функция проверяет, совпадает ли время текущего тика со временем последнего обработанного тика, чтобы избежать избыточных операций в рамках одного тика. Затем советник перебирает все торговые пары, заданные в SymbolList, и в зависимости от выбранного TradeMode динамически применяет логику скальпинга или свинг-трейдинга. В режиме скальпинга функция вызывает ScalpModeHandler() для оценки сигналов, выполняет сделки на новых барах и управляет существующими позициями скальпинга. В режиме свинг-трейдинга функция выявляет корректные свинг-сигналы, открывает соответствующие сделки и сопровождает текущие позиции с помощью ManageSwingTrades(). Наконец, функция обновляет панель на экране, чтобы в реальном времени показывать данные по сделкам и результатам работы, благодаря чему советник эффективно и гибко работает по всем активным парам.
//+------------------------------------------------------------------+ //| Scalping Signal Function | //+------------------------------------------------------------------+ void ScalpModeHandler(string symbol) { // Define arrays to hold indicator values double emaFastArr[2], emaSlowArr[2], rsiArr[2]; // Copy values: current and previous if(CopyBuffer(handleEmaFast_Scalp, 0, 0, 2, emaFastArr) < 2) return; if(CopyBuffer(handleEmaSlow_Scalp, 0, 0, 2, emaSlowArr) < 2) return; if(CopyBuffer(handleRsi_Scalp, 0, 0, 2, rsiArr) < 2) return; // Assign named values double emaFastCurr = emaFastArr[0]; double emaFastPrev = emaFastArr[1]; double emaSlowCurr = emaSlowArr[0]; double emaSlowPrev = emaSlowArr[1]; double rsiCurr = rsiArr[0]; // Validate (avoid zero or invalid) if(emaFastCurr == 0 || emaSlowCurr == 0 || rsiCurr == 0) return; // Check open positions for this symbol if(CountOpenPositions(symbol) >= MaxOpenPositions) return; // BUY signal condition if(emaFastCurr > emaSlowCurr && emaFastPrev <= emaSlowPrev && rsiCurr > Scalp_RSI_Overbought) { ExecuteAdaptiveTrade(ORDER_TYPE_BUY, symbol, LotSize_Scalp); Print("Scalp BUY Signal executed for ", symbol); } // SELL signal condition else if(emaFastCurr < emaSlowCurr && emaFastPrev >= emaSlowPrev && rsiCurr < Scalp_RSI_Oversold) { ExecuteAdaptiveTrade(ORDER_TYPE_SELL, symbol, LotSize_Scalp); Print("Scalp SELL Signal executed for ", symbol); } } //+------------------------------------------------------------------+ //| Swing Trading Signal Function | //+------------------------------------------------------------------+ bool SwingSignal(string symbol) { int swingHighBar = iHighest(symbol, SwingTimeframe, MODE_HIGH, Swing_Lookback, 1); int swingLowBar = iLowest(symbol, SwingTimeframe, MODE_LOW, Swing_Lookback, 1); if(swingHighBar == -1 || swingLowBar == -1) return false; double swingHigh = iHigh(symbol, SwingTimeframe, swingHighBar); double swingLow = iLow(symbol, SwingTimeframe, swingLowBar); double currentClose = iClose(symbol, SwingTimeframe, 0); double range = swingHigh - swingLow; if(range == 0) return false; double fib618_Up = swingHigh - Fib_Level * range; double fib618_Down = swingLow + Fib_Level * range; bool higherTFBullish = true; bool higherTFBearish = true; if(UseHigherTFConfirmation) { int handleEMA = iMA(symbol, HigherTF, 20, 0, MODE_EMA, PRICE_CLOSE); if(handleEMA == INVALID_HANDLE) return false; double emaVal[1]; if(CopyBuffer(handleEMA, 0, 0, 1, emaVal) < 1) return false; double htEMA20 = emaVal[0]; double htClose = iClose(symbol, HigherTF, 0); higherTFBullish = htClose > htEMA20; higherTFBearish = htClose < htEMA20; } // --- Buy Signal if(currentClose <= fib618_Down && currentClose > swingLow && higherTFBullish) return true; // --- Sell Signal if(currentClose >= fib618_Up && currentClose < swingHigh && higherTFBearish) return true; return false; }
Функция ScalpModeHandler() отвечает за формирование и исполнение краткосрочных торговых сигналов в режиме скальпинга. Она получает последние и предыдущие значения быстрой EMA, медленной EMA и RSI с помощью CopyBuffer() из заранее инициализированных хэндлов индикаторов. Эти значения используются для выявления пересечений и состояний импульса, которые лежат в основе сигналов для скальперских сделок. В частности, сигнал на покупку возникает, когда быстрая EMA пересекает медленную EMA снизу вверх, а RSI превышает порог перекупленности, что указывает на восходящий импульс. Напротив, сигнал на продажу возникает, когда быстрая EMA пересекает медленную EMA сверху вниз, а RSI опускается ниже порога перепроданности, что указывает на нисходящий импульс. Перед выполнением любой сделки функция проверяет корректность данных индикаторов и следит за тем, чтобы по символу не было превышено максимальное число открытых позиций, поддерживая тем самым эффективное и контролируемое управление сделками.
Функция SwingSignal() работает на старших таймфреймах и позволяет выявлять потенциальные более широкие рыночные развороты или продолжения тренда. Она определяет последние свинг-максимум и свинг-минимум в пределах заданного периода анализа, рассчитывает торговый диапазон и уровни коррекции Фибоначчи, чтобы найти потенциальные зоны реакции цены. Используя эту информацию, функция проверяет, находится ли текущая рыночная цена вблизи ключевых уровней коррекции, которые указывают на возможность разворота. Если включено подтверждение на старшем таймфрейме, дополнительный EMA-фильтр следит за тем, чтобы сделки открывались только по направлению преобладающего тренда на старшем таймфрейме. Затем функция возвращает булев сигнал (true или false) в зависимости от того, обнаружен ли корректный сетап на покупку или продажу. Такое разделение краткосрочной логики (скальпинг) и долгосрочной логики (свинг-трейдинг) позволяет советнику точно и динамично адаптировать стратегию к различным рыночным условиям.
//+------------------------------------------------------------------+ //| Execute Scalp Trade | //+------------------------------------------------------------------+ void ExecuteScalpTrade(string symbol) { if(CountOpenPositions(symbol) >= MaxOpenPositions) return; int handleEmaFast = iMA(symbol, ScalpTimeframe, Scalp_EMA_Fast, 0, MODE_EMA, PRICE_CLOSE); int handleEmaSlow = iMA(symbol, ScalpTimeframe, Scalp_EMA_Slow, 0, MODE_EMA, PRICE_CLOSE); int handleRSI = iRSI(symbol, ScalpTimeframe, Scalp_RSI_Period, PRICE_CLOSE); double emaFast[1], emaSlow[1], rsi[1]; if(CopyBuffer(handleEmaFast, 0, 0, 1, emaFast) < 1) return; if(CopyBuffer(handleEmaSlow, 0, 0, 1, emaSlow) < 1) return; if(CopyBuffer(handleRSI, 0, 0, 1, rsi) < 1) return; double emaF = emaFast[0]; double emaS = emaSlow[0]; double rsiV = rsi[0]; if(emaF > emaS && rsiV > Scalp_RSI_Overbought) ExecuteTrade(ORDER_TYPE_BUY, symbol, LotSize_Scalp, StopLoss_Scalp, TakeProfit_Scalp); else if(emaF < emaS && rsiV < Scalp_RSI_Oversold) ExecuteTrade(ORDER_TYPE_SELL, symbol, LotSize_Scalp, StopLoss_Scalp, TakeProfit_Scalp); } //+------------------------------------------------------------------+ //| Execute Swing Trade | //+------------------------------------------------------------------+ void ExecuteSwingTrade(string symbol) { if(CountOpenPositions(symbol) >= MaxOpenPositions) return; // Determine trade direction (simplified logic) int swingHighBar = iHighest(symbol, SwingTimeframe, MODE_HIGH, Swing_Lookback, 1); int swingLowBar = iLowest(symbol, SwingTimeframe, MODE_LOW, Swing_Lookback, 1); if(swingHighBar != -1 && swingLowBar != -1) { double swingHigh = iHigh(symbol, SwingTimeframe, swingHighBar); double swingLow = iLow(symbol, SwingTimeframe, swingLowBar); double currentClose = iClose(symbol, SwingTimeframe, 0); double range = swingHigh - swingLow; double fib618_Down = swingLow + Fib_Level * range; double fib618_Up = swingHigh - Fib_Level * range; if(currentClose <= fib618_Down && currentClose > swingLow) { ExecuteTrade(ORDER_TYPE_BUY, symbol, LotSize_Swing, StopLoss_Swing, TakeProfit_Swing); } else if(currentClose >= fib618_Up && currentClose < swingHigh) { ExecuteTrade(ORDER_TYPE_SELL, symbol, LotSize_Swing, StopLoss_Swing, TakeProfit_Swing); } } } //+------------------------------------------------------------------+ //| Execute trade with dynamic stop/TP adaption per symbol | //+------------------------------------------------------------------+ void ExecuteTrade(ENUM_ORDER_TYPE tradeType, string symbol, double lotSize, int stopLossPips, int takeProfitPips) { //--- Symbol info double point = SymbolInfoDouble(symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double price = (tradeType == ORDER_TYPE_BUY) ? ask : bid; //--- Detect pip size automatically (handles forex, gold, crypto, indices) double pipSize; if(StringFind(symbol, "JPY") != -1) // JPY pairs (2/3 digits) pipSize = (digits == 3) ? point * 10 : point; else if(StringFind(symbol, "XAU") != -1 || StringFind(symbol, "GOLD") != -1) // Metals pipSize = 0.10; else if(StringFind(symbol, "BTC") != -1 || StringFind(symbol, "ETH") != -1) // Cryptos pipSize = point * 100.0; else if(StringFind(symbol, "US") != -1 && digits <= 2) // Indices pipSize = point; else pipSize = (digits == 3 || digits == 5) ? point * 10 : point; // Default Forex //--- Convert SL/TP from pips to price distances double sl_distance = stopLossPips * pipSize; double tp_distance = takeProfitPips * pipSize; //--- Determine broker minimum stop levels double minStopPoints = 0.0; if(SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) > 0) minStopPoints = SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL); else if(SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) > 0) minStopPoints = SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL); else minStopPoints = 30; // fallback default (points) double minStop = minStopPoints * point; //--- Ensure SL/TP distances are greater than min stop level if(sl_distance < minStop) sl_distance = minStop; if(tp_distance < minStop) tp_distance = minStop; //--- Calculate final SL/TP prices double sl = (tradeType == ORDER_TYPE_BUY) ? price - sl_distance : price + sl_distance; double tp = (tradeType == ORDER_TYPE_BUY) ? price + tp_distance : price - tp_distance; //--- Normalize prices sl = NormalizeDouble(sl, digits); tp = NormalizeDouble(tp, digits); price = NormalizeDouble(price, digits); //--- Safety validation (correct SL/TP relation) if((tradeType == ORDER_TYPE_BUY && (sl >= price || tp <= price)) || (tradeType == ORDER_TYPE_SELL && (sl <= price || tp >= price))) { Print("Invalid SL/TP detected for ", symbol, " — auto-adjusting..."); if(tradeType == ORDER_TYPE_BUY) { sl = NormalizeDouble(price - minStop, digits); tp = NormalizeDouble(price + minStop * 2, digits); } else { sl = NormalizeDouble(price + minStop, digits); tp = NormalizeDouble(price - minStop * 2, digits); } } //--- Try executing trade if(trade.PositionOpen(symbol, tradeType, lotSize, price, sl, tp, "Adaptive Multi-Pair EA")) { PrintFormat("%s opened on %s | Lot: %.2f | SL: %.5f | TP: %.5f | TickValue: %.2f", EnumToString(tradeType), symbol, lotSize, sl, tp, tickValue); } else { int err = GetLastError(); PrintFormat("Failed to open %s on %s | Error %d: %s", EnumToString(tradeType), symbol, err, err); ResetLastError(); } }Функции ExecuteScalpTrade() и ExecuteSwingTrade() задают две разные логики исполнения: одну для краткосрочных точных входов, другую – для свинг-сетапов на старших таймфреймах. Логика скальперских сделок ориентирована на быстрые входы в условиях сильного импульса и использует быструю и медленную EMA вместе с порогами RSI для выявления краткосрочных трендов. Сделки выполняются сразу после пересечения быстрой и медленной EMA, когда RSI достигает зоны перекупленности или перепроданности, что позволяет быстро отрабатывать волатильные движения. В свою очередь, функция свинг-трейдинга выявляет более крупные рыночные структуры, анализируя недавние максимумы и минимумы свинга, а затем рассчитывает уровни коррекции Фибоначчи, чтобы найти оптимальные зоны входа на откате. Это позволяет советнику отрабатывать среднесрочные развороты и продолжения в рамках более широких трендов.
Функция ExecuteTrade() выступает основным механизмом исполнения и адаптируется к различным рыночным инструментам, рассчитывая размер пипса, проверяя ограничения брокера и нормализуя цены для безопасного размещения сделок. Она динамически корректирует уровни стоп-лосса и тейк-профита с учетом характеристик символа – будь то Forex, золото, криптовалюта или индексы, – чтобы каждая сделка соблюдала минимальные уровни стопов брокера при сохранении логичных расстояний SL/TP. Вместе эти три функции образуют надежную систему исполнения, которая интеллектуально адаптируется как к быстрым, так и к более медленным рыночным условиям, обеспечивая точность, безопасность и согласованность в разных классах активов.
//+------------------------------------------------------------------+ //| Execute trade with adaptive SL/TP by symbol type | //+------------------------------------------------------------------+ void ExecuteAdaptiveTrade(ENUM_ORDER_TYPE type, string symbol, double lotSize) { double point = SymbolInfoDouble(symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double price = (type == ORDER_TYPE_BUY) ? ask : bid; //--- Determine adaptive pip scale per asset double pipScale; if(StringFind(symbol, "XAU") != -1 || StringFind(symbol, "GOLD") != -1) pipScale = 1.0; // Gold → 1 dollar movement = 1 pip else if(StringFind(symbol, "BTC") != -1) pipScale = 50.0; // Crypto → 50-point unit for volatility else if(StringFind(symbol, "US") != -1 && digits <= 2) pipScale = 10.0; // Indices (US100, US30) else if(StringFind(symbol, "JPY") != -1) pipScale = 0.1; // Yen pairs else pipScale = 0.0001; // Standard Forex ENUM_TIMEFRAMES tf = ScalpTimeframe; //--- Calculate SL/TP dynamically double atr = iATR(symbol, tf, 14); if(atr <= 0) atr = pipScale * 30; // Fallback default double slDistance = atr * 1.5; // SL = 1.5x ATR double tpDistance = atr * 3.0; // TP = 3x ATR //--- Validate broker min stop distance double minStop = 0; if(SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) > 0) minStop = SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) * point; else if(SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) > 0) minStop = SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) * point; else minStop = atr * 0.5; if(slDistance < minStop) slDistance = minStop; if(tpDistance < minStop) tpDistance = minStop * 2; //--- Final price calculation double sl = (type == ORDER_TYPE_BUY) ? price - slDistance : price + slDistance; double tp = (type == ORDER_TYPE_BUY) ? price + tpDistance : price - tpDistance; sl = NormalizeDouble(sl, digits); tp = NormalizeDouble(tp, digits); //--- Trade execution if(trade.PositionOpen(symbol, type, lotSize, price, sl, tp, "Scalp-Mode")) { PrintFormat("%s %s | Lot: %.2f | SL: %.5f | TP: %.5f | ATR: %.5f", EnumToString(type), symbol, lotSize, sl, tp, atr); } else { int err = GetLastError(); PrintFormat("Trade failed on %s | Error %d: %s", symbol, err, GetLastError()); ResetLastError(); } } //+------------------------------------------------------------------+ //| Dashboard Functions | //+------------------------------------------------------------------+ void UpdateDashboard() { string dashboardText = ""; string newLine = "\n"; dashboardText += "=== MULTI-PAIR TRADING EA ===" + newLine; dashboardText += "Trading Mode: " + EnumToString(TradeMode) + newLine; dashboardText += "Active Pairs: " + IntegerToString(TotalPairs) + newLine; dashboardText += "Account Balance: " + DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE), 2) + newLine; dashboardText += "=================================" + newLine; // Show status for each pair for(int i = 0; i < TotalPairs; i++) { string symbol = SymbolList[i]; int positions = CountOpenPositions(symbol); dashboardText += symbol + ":" + newLine; dashboardText += " Positions: " + IntegerToString(positions) + newLine; // Add signal status with detailed info if(TradeMode == MODE_SCALP) { //bool signal = ScalpModeHandler(symbol); double emaFast = iMA(symbol, ScalpTimeframe, Scalp_EMA_Fast, 0, MODE_EMA, PRICE_CLOSE); double emaSlow = iMA(symbol, ScalpTimeframe, Scalp_EMA_Slow, 0, MODE_EMA, PRICE_CLOSE); double rsi = iRSI(symbol, ScalpTimeframe, Scalp_RSI_Period, PRICE_CLOSE); //dashboardText += " Scalp Signal: " + (signal ? "ACTIVE" : "INACTIVE") + newLine; dashboardText += " EMA Fast: " + DoubleToString(emaFast, 5) + newLine; dashboardText += " EMA Slow: " + DoubleToString(emaSlow, 5) + newLine; dashboardText += " RSI: " + DoubleToString(rsi, 1) + newLine; } else { bool signal = SwingSignal(symbol); dashboardText += " Swing Signal: " + (signal ? "ACTIVE" : "INACTIVE") + newLine; } dashboardText += newLine; } Comment(dashboardText); } //+------------------------------------------------------------------+
Функция ExecuteAdaptiveTrade() вводит интеллектуальный механизм исполнения сделок, который динамически корректирует расстояния стоп-лосса (SL) и тейк-профита (TP) с учетом уникального профиля волатильности каждого актива. Определяя тип инструмента – золото, криптовалюта, индексы, пары с JPY или стандартный Forex, – функция применяет подходящий масштаб пипсов и использует индикатор ATR (Average True Range) для расчета адаптивных уровней SL/TP. Это гарантирует, что границы сделки не окажутся слишком узкими для волатильных рынков и слишком широкими для спокойных, поддерживая баланс между риском и прибылью в реальном времени. Функция также включает защитные механизмы для минимальных стоп-расстояний брокера и механизмы автокоррекции, обеспечивая точное размещение сделок с учетом волатильности в мультиактивной среде.
Функция UpdateDashboard() дополняет адаптивную торговую логику, обеспечивая наглядный мониторинг работы системы в реальном времени. Она отображает активные позиции по каждой торговой паре, ключевые технические метрики (значения EMA, RSI или свинг-сигнал) и общий режим работы советника, позволяя трейдерам прямо с графика визуально отслеживать логику принятия решений и состояние системы. Вместе эти компоненты обеспечивают непрерывную обратную связь – адаптивное исполнение сделок и наглядный мониторинг системы в реальном времени, – позволяя трейдерам уверенно и эффективно управлять несколькими валютными парами и четко понимать поведение системы в разных рыночных условиях.
Результаты тестирования на исторических данных
Параметры скальпинга:| Входная переменная | Параметр |
|---|---|
| Использовать ATR для SL/TP | True |
| Размер лота для скальпинга | 0.35 |
| Стоп-лосс для скальпинга (пипсы) | 950 |
| Тейк-профит для скальпинга (пипсы) | 30 |
| Трейлинг-стоп для скальпинга | 15 |
| Таймфрейм для скальпинга | 3 минуты |
| Быстрая EMA для скальпинга | 20 |
| Медленная EMA для скальпинга | 50 |
| Период RSI для скальпинга | 14 |
| Уровень перекупленности RSI для скальпинга | 55 |
| Уровень перепроданности RSI для скальпинга | 45 |


Параметры свинг-трейдинга:
| Входная переменная | Параметр |
|---|---|
| Размер лота для свинг-трейдинга | 0.45 |
| Стоп-лосс для свинг-трейдинга (пипсы) | 200 |
| Тейк-профит для свинг-трейдинга (пипсы) | 1800 |
| Трейлинг-стоп для свинг-трейдинга (пипсы) | 100 |
| Таймфрейм для свинг-трейдинга | 4 часа |
| Окно проверки для свинг-трейдинга | 20 |
| Уровень коррекции Фибоначчи | 0.618 |
| Использовать подтверждение на D1 | true |
| Старший таймфрейм | D1 |


Заключение
Подводя итог, мы разработали динамический мультивалютный советник, способный переключаться между подходами скальпинга и свинг-трейдинга и адаптироваться к различным типам активов, таким как золото, Forex, криптовалюты и индексы. Система объединяет такие технические модели, как пересечения EMA, фильтры RSI, уровни коррекции Фибоначчи и показатели волатильности на основе ATR, чтобы интеллектуально определять направление сделки и логику управления позицией. Благодаря адаптивным уровням SL/TP и надежной мультивалютной структуре советник обеспечивает оптимальный контроль риска, эффективное исполнение и последовательное применение логики в разных рыночных условиях – будь то краткосрочный скальпинг или более долгосрочные свинг-сетапы.
В итоге эта архитектура дает трейдерам универсальное и автоматизированное торговое решение, которое динамически подстраивается под рыночную волатильность, характеристики символов и торговые цели. Это позволяет использовать один советник, который объединяет и агрессивный скальпинг, и более терпеливые свинг-стратегии, сводя ручное вмешательство к минимуму. Такая единая архитектура повышает точность исполнения и качество управления рисками, а также дает более глубокий уровень адаптации к рынку – ключевое преимущество для трейдеров, которым важны стабильность и масштабируемость в разных классах активов.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/19989
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Рекуррентный количественный анализ (RQA) в MQL5: Разработка полноценной библиотеки для анализа
Разработка инструментария для анализа Price Action (Часть 50): Создание модуля согласования сигналов RVGI, CCI и SMA на MQL5
Архитектура машинного обучения для MetaTrader 5 (Часть 14): Моделирование транзакционных издержек для разметки методом тройного барьера в MQL5
Фундаментальные предобученные модели в трейдинге: прогнозирование временных рядов с TimesFM 2.5 от Google в MetaTrader 5
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Я считаю, что в изображении скальпинга допущена простая опечатка:
Скачал, но обратный тест не прошел. Его не происходит.
Пожалуйста, обратите внимание на символы ввода. Они должны совпадать с символами ваших брокеров, например, "EURUSD.m" имеет суффикс ".m", при этом, если символы ваших брокеров имеют суффикс или префикс, пожалуйста, введите их во входной символ.
Здравствуйте ,
Я запустил в демо Mt5, но обратный тест не удался. его не происходит. есть ли проблемы в советнике?
Этот советник просто великолепен!!! Я использую его, и результаты прекрасны!!! Продолжайте делать то, что вы делаете, и спасибо, что поделились. Один вопрос!!! На какой паре проводится обратный тест?
Привет, спасибо за ваш отзыв.
Бэк-тест проводится на стандартных настройках входного символа:
"XAUUSD,BTCUSD,US100,GBPUSD"