Как работает трейлинг-стоп для сетки ордеров в MetaTrader 5 (MQL5)
Трейлинг-стоп — это мощный инструмент для управления торговыми позициями, который позволяет фиксировать прибыль, автоматически корректируя стоп-лосс при движении цены в вашу пользу. В этой статье мы разберем, как работает код MQL5 для трейлинг-стопа, применяемого к сетке ордеров (Buy и Sell) на хеджинговом счете в MetaTrader 5 (MT5). Код предназначен для автоматизации управления сеткой, чтобы вы могли выводить убыточные позиции в плюс или минимизировать потери.
Что делает код?
Этот код реализует трейлинг-стоп для сетки ордеров (Buy и Sell) на одном финансовом инструменте. Вот его основные функции:
-
Расчет «нулевой» цены сетки:
-
Определяет средневзвешенную цену всех открытых позиций (Buy и Sell), при которой суммарный профит сетки равен нулю.
-
Это точка, от которой начинается отсчет профитной зоны.
-
-
Активация трейлинг-стопа:
-
Трейлинг-стоп включается, когда цена (Bid для Buy, Ask для Sell) проходит в профитную сторону на заданное количество пунктов (startTral, по умолчанию 50 пунктов) от нулевой цены.
-
-
Управление стоп-лоссами:
-
Для позиций Buy: Стоп-лосс устанавливается ниже текущей цены Bid на заданное расстояние (trailingStop, по умолчанию 30 пунктов).
-
Для позиций Sell: Стоп-лосс устанавливается выше текущей цены Ask на то же расстояние.
-
Стоп-лосс обновляется только при движении цены в профитную сторону на минимальный шаг (trailingStep, по умолчанию 10 пунктов), чтобы избежать лишних модификаций.
-
-
Автоматизация:
-
Код работает в реальном времени, проверяя условия на каждом тике (изменении цены) и корректируя стоп-лоссы всех позиций в сетке.
-
Этот подход позволяет «запереть» прибыль сетки, даже если рынок движется в сложных условиях, и помогает управлять убыточными позициями, выводя их в плюс при благоприятном движении цены.
Как работает код?
Код написан на языке MQL5 и предназначен для хеджингового счета, где можно одновременно держать позиции Buy и Sell по одному инструменту. Давайте разберем его структуру и ключевые компоненты:
1. Параметры настройки ️
Код использует три настраиваемых параметра:
-
startTral (по умолчанию 50 пунктов): Расстояние от нулевой цены, при котором активируется трейлинг-стоп.
-
trailingStop (по умолчанию 30 пунктов): Расстояние стоп-лосса от текущей рыночной цены.
-
trailingStep (по умолчанию 10 пунктов): Минимальный шаг изменения стоп-лосса, чтобы избежать частых модификаций.
Эти параметры можно настроить при запуске советника в MT5, чтобы адаптировать стратегию под ваш стиль торговли.
2. Функция CalculateZeroPrice
Эта функция вычисляет «нулевую» цену сетки ордеров:
-
Перебирает все открытые позиции по заданному символу (например, EURUSD).
-
Собирает данные об объемах и ценах открытия для позиций Buy и Sell.
-
Рассчитывает средневзвешенную цену с учетом объемов:
zeroPrice = (sumPriceVolumeBuy + sumPriceVolumeSell) / (totalVolumeBuy + totalVolumeSell)
-
Возвращает цену, при которой суммарный профит сетки равен нулю.
Если позиций нет, функция возвращает 0, и трейлинг-стоп не активируется.
3. Функция TrailingStopGrid ⚙️
Это основная функция, которая реализует логику трейлинг-стопа:
-
Проверяет, находится ли сетка в профитной зоне:
-
Суммирует текущий профит всех позиций.
-
Сравнивает текущие цены (Bid для Buy, Ask для Sell) с нулевой ценой, чтобы определить, превышен ли порог startTral.
-
-
Если сетка в прибыли, для каждой позиции:
-
Для Buy: Устанавливает стоп-лосс ниже Bid на trailingStop пунктов, если новый стоп-лосс лучше текущего и цена прошла trailingStep.
-
Для Sell: Устанавливает стоп-лосс выше Ask на trailingStop пунктов по аналогичной логике.
-
-
Использует класс CTrade из библиотеки MQL5 для безопасной модификации позиций.
4. Обработка на каждом тике (OnTick) ⏰
Функция TrailingStopGrid вызывается на каждом тике (изменении цены), чтобы:
-
Постоянно отслеживать рыночные цены.
-
Обновлять стоп-лоссы, если выполняются условия трейлинга.
-
Выводить в журнал информацию об обновлении стоп-лоссов для контроля.
Пример работы
Допустим, у вас есть сетка из двух позиций по EURUSD:
-
Buy: 1 лот по 1.1000.
-
Sell: 1 лот по 1.1020.
-
Нулевая цена: Средневзвешенная цена = (1.1000 + 1.1020) / 2 = 1.1010.
-
Активация: Если Bid поднимается выше 1.1060 (1.1010 + 50 пунктов) или Ask падает ниже 1.0960 (1.1010 — 50 пунктов), трейлинг-стоп включается.
-
Трейлинг:
-
Для Buy: Если Bid = 1.1080, стоп-лосс устанавливается на 1.1050 (Bid — 30 пунктов).
-
Для Sell: Если Ask = 1.0940, стоп-лосс устанавливается на 1.0970 (Ask + 30 пунктов).
-
-
Обновление: Стоп-лоссы корректируются, только если цена проходит trailingStep (10 пунктов) в профитную сторону.
Если рынок продолжает двигаться в вашу пользу, стоп-лоссы «подтягиваются», фиксируя прибыль. Если цена достигает стоп-лосса, позиции закрываются с минимальной прибылью или нулевым убытком.
Риски и рекомендации ⚠️
-
Риск проскальзывания: В условиях высокой волатильности стоп-лоссы могут исполняться с отклонением от заданной цены.
-
Размер депозита: Убедитесь, что у вас достаточно средств для поддержки сетки ордеров, особенно если она большая.
-
Оптимизация параметров: Подберите значения startTral, trailingStop и trailingStep под ваш инструмент и стратегию. Например, для волатильных пар (GBPUSD) могут понадобиться большие значения.
-
Логи: Код выводит информацию об обновлении стоп-лоссов в журнал MT5 — проверяйте его для контроля.
Преимущества подхода
-
Автоматизация: Код работает без вашего участия, экономя время и исключая эмоции.
-
Гибкость: Подходит для любых сеток ордеров (хеджирование, усреднение, сеточные стратегии).
-
Управление рисками: Помогает фиксировать прибыль и минимизировать убытки, даже если рынок движется против вас.
Заключение
Этот трейлинг-стоп для MQL5 — мощный инструмент для трейдеров, работающих с сетками ордеров в MT5. Он автоматически определяет нулевую цену, активирует трейлинг в профитной зоне и корректирует стоп-лоссы, защищая вашу прибыль. Попробуйте его на демо-счете, настройте под свои нужды и начните торговать эффективнее!
#include
//+------------------------------------------------------------------+
//| Параметры функции |
//+------------------------------------------------------------------+
input int startTral = 50; // Пункты для начала трейлинга от нулевой цены
input int trailingStop = 30; // Расстояние трейлинг-стопа в пунктах
input int trailingStep = 10; // Шаг трейлинга в пунктах
CTrade trade;
//+------------------------------------------------------------------+
//| Функция расчета нулевой цены сетки ордеров |
//+------------------------------------------------------------------+
double CalculateZeroPrice(string symbol) {
double totalVolumeBuy = 0, totalVolumeSell = 0;
double sumPriceVolumeBuy = 0, sumPriceVolumeSell = 0;
double totalProfit = 0;
// Перебираем все позиции по символу
for(int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket)) {
if(PositionGetString(POSITION_SYMBOL) == symbol) {
double volume = PositionGetDouble(POSITION_VOLUME);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
totalVolumeBuy += volume;
sumPriceVolumeBuy += openPrice * volume;
} else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
totalVolumeSell += volume;
sumPriceVolumeSell += openPrice * volume;
}
totalProfit += PositionGetDouble(POSITION_PROFIT);
}
}
}
// Если нет позиций, возвращаем 0
if(totalVolumeBuy + totalVolumeSell == 0) return 0;
// Рассчитываем средневзвешенную цену
double zeroPrice = (sumPriceVolumeBuy + sumPriceVolumeSell) / (totalVolumeBuy + totalVolumeSell);
return NormalizeDouble(zeroPrice, _Digits);
}
//+------------------------------------------------------------------+
//| Функция трейлинг-стопа для сетки ордеров |
//+------------------------------------------------------------------+
void TrailingStopGrid(string symbol, int startTralPoints, int trailingStopPoints, int trailingStepPoints) {
double zeroPrice = CalculateZeroPrice(symbol);
if(zeroPrice == 0) return; // Нет позиций для обработки
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
// Проверяем, находится ли цена в профитной зоне
double currentProfit = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == symbol) {
currentProfit += PositionGetDouble(POSITION_PROFIT);
}
}
bool isProfitZone = false;
if(currentProfit > 0) {
if(bid > zeroPrice + startTralPoints * point || ask < zeroPrice - startTralPoints * point) {
isProfitZone = true;
}
}
// Если цена в профитной зоне, применяем трейлинг-стоп
if(isProfitZone) {
for(int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == symbol) {
double currentSL = PositionGetDouble(POSITION_SL);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
long posType = PositionGetInteger(POSITION_TYPE);
double newSL = 0;
if(posType == POSITION_TYPE_BUY) {
// Для Buy: SL ниже текущей цены Bid
newSL = NormalizeDouble(bid - trailingStopPoints * point, _Digits);
if(currentSL == 0 || (newSL > currentSL && bid >= currentSL + trailingStepPoints * point)) {
trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
Print("Buy Position ", ticket, ": SL updated to ", newSL);
}
} else if(posType == POSITION_TYPE_SELL) {
// Для Sell: SL выше текущей цены Ask
newSL = NormalizeDouble(ask + trailingStopPoints * point, _Digits);
if(currentSL == 0 || (newSL < currentSL && ask <= currentSL - trailingStepPoints * point)) {
trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
Print("Sell Position ", ticket, ": SL updated to ", newSL);
}
}
}
}
}
}