Введение: Зачем нужны виртуальные Stop Loss и Take Profit?
В мире алгоритмической торговли на платформе MetaTrader 4 (MQL4) трейдеры и разработчики советников (Expert Advisors, EA) постоянно ищут способы улучшить свои стратегии и защитить капитал. Стандартные уровни Stop Loss (SL) и Take Profit (TP), устанавливаемые непосредственно у брокера, имеют свои преимущества, но также и недостатки. Одним из таких недостатков является их видимость для брокера, что в некоторых случаях может приводить к нежелательным манипуляциям или «охоте за стопами».
Виртуальные Stop Loss и Take Profit — это решение, при котором уровни SL и TP не отправляются брокеру, а отслеживаются непосредственно советником в памяти терминала. Когда цена достигает заданного виртуального уровня, советник самостоятельно закрывает позицию по рыночной цене. Это дает ряд преимуществ:
- Невидимость для брокера: Ваши защитные уровни остаются скрытыми, что потенциально снижает риск манипуляций.
- Гибкость: Вы можете реализовать более сложные логики закрытия позиций, которые невозможно задать стандартными SL/TP (например, трейлинг-стоп на основе индикатора, частичное закрытие, или закрытие по времени).
- Обход минимальных ограничений: Некоторые брокеры устанавливают минимальное расстояние для SL/TP. Виртуальные уровни позволяют обойти эти ограничения.
В этой статье мы подробно рассмотрим, как реализовать базовую функциональность виртуальных SL/TP в вашем советнике на MQL4.
Исходный код
Ниже представлен пример кода советника на MQL4, который реализует виртуальные Stop Loss и Take Profit для всех ордеров, открытых этим же советником (имеющих соответствующий магический номер) и относящихся к текущему символу.
//--- Глобальные переменные для виртуальных уровней SL/TP
extern int VirtualStopLossPips = 50; // Виртуальный Stop Loss в стандартных пунктах (например, 50 пунктов)
extern int VirtualTakeProfitPips = 100; // Виртуальный Take Profit в стандартных пунктах
extern int MagicNumber = 12345; // Уникальный идентификатор для ордеров данного советника
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Вызываем функцию для проверки виртуальных уровней на каждом тике
CheckVirtualLevels();
}
//+------------------------------------------------------------------+
//| Функция для проверки и управления виртуальными SL/TP |
//+------------------------------------------------------------------+
void CheckVirtualLevels()
{
// Определяем корректное значение одного пункта для текущего символа.
// Это важно для правильного расчета на 4-х и 5-значных брокерах.
// Например, для EURUSD на 5-значном брокере Point = 0.00001, а стандартный пункт = 0.0001.
double pip_value = (Digits == 5 || Digits == 3) ? 10 * Point : Point;
// Итерируем по всем открытым ордерам
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
// Выбираем ордер для работы
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// Проверяем, что ордер принадлежит нашему советнику (по MagicNumber)
// и относится к текущему торговому символу
if (OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
double currentPrice;
double virtualSLPrice;
double virtualTPPrice;
// Расчет виртуальных цен SL/TP в зависимости от типа ордера
if (OrderType() == OP_BUY)
{
currentPrice = Bid; // Для ордеров BUY используем цену Bid для закрытия
virtualSLPrice = OrderOpenPrice() - VirtualStopLossPips * pip_value;
virtualTPPrice = OrderOpenPrice() + VirtualTakeProfitPips * pip_value;
// Проверка виртуального Stop Loss для ордера BUY
if (currentPrice <= virtualSLPrice)
{
Print("Виртуальный Stop Loss сработал для ордера BUY #", OrderTicket(), ". Закрытие по цене ", currentPrice);
OrderClose(OrderTicket(), OrderLots(), currentPrice, 3, Red); // Закрываем ордер
continue; // Переходим к следующему ордеру
}
// Проверка виртуального Take Profit для ордера BUY
if (currentPrice >= virtualTPPrice)
{
Print("Виртуальный Take Profit сработал для ордера BUY #", OrderTicket(), ". Закрытие по цене ", currentPrice);
OrderClose(OrderTicket(), OrderLots(), currentPrice, 3, Blue); // Закрываем ордер
continue; // Переходим к следующему ордеру
}
}
else if (OrderType() == OP_SELL)
{
currentPrice = Ask; // Для ордеров SELL используем цену Ask для закрытия
virtualSLPrice = OrderOpenPrice() + VirtualStopLossPips * pip_value;
virtualTPPrice = OrderOpenPrice() - VirtualTakeProfitPips * pip_value;
// Проверка виртуального Stop Loss для ордера SELL
if (currentPrice >= virtualSLPrice)
{
Print("Виртуальный Stop Loss сработал для ордера SELL #", OrderTicket(), ". Закрытие по цене ", currentPrice);
OrderClose(OrderTicket(), OrderLots(), currentPrice, 3, Red); // Закрываем ордер
continue; // Переходим к следующему ордеру
}
// Проверка виртуального Take Profit для ордера SELL
if (currentPrice <= virtualTPPrice)
{
Print("Виртуальный Take Profit сработал для ордера SELL #", OrderTicket(), ". Закрытие по цене ", currentPrice);
OrderClose(OrderTicket(), OrderLots(), currentPrice, 3, Blue); // Закрываем ордер
continue; // Переходим к следующему ордеру
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Пример функции для открытия тестового ордера (для демонстрации) |
//| В реальном советнике логика открытия ордеров будет сложнее. |
//+------------------------------------------------------------------+
void OnStart() // Можно использовать OnStart для однократного открытия или OnTick с условием
{
// Этот блок кода закомментирован, так как он предназначен только для тестирования.
// В реальном советнике вы будете открывать ордера согласно вашей торговой стратегии.
// Для проверки виртуальных SL/TP вы можете открыть ордер вручную или раскомментировать
// и адаптировать этот блок.
/*
if (OrdersTotal() == 0) // Открыть ордер только если нет других ордеров
{
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "Test Order", MagicNumber, 0, Green);
if (ticket > 0)
{
Print("Тестовый ордер BUY открыт успешно: #", ticket);
}
else
{
Print("Не удалось открыть тестовый ордер BUY. Ошибка: ", GetLastError());
}
}
*/
}
Разбор параметров
VirtualStopLossPips: Целочисленное значение, определяющее расстояние виртуального Stop Loss от цены открытия ордера в стандартных пунктах (pips). Например, значение 50 означает 50 пунктов.VirtualTakeProfitPips: Целочисленное значение, определяющее расстояние виртуального Take Profit от цены открытия ордера в стандартных пунктах (pips). Например, значение 100 означает 100 пунктов.MagicNumber: Уникальный целочисленный идентификатор, который присваивается ордерам, открытым данным советником. Это позволяет советнику управлять только «своими» ордерами, игнорируя ордера, открытые вручную или другими советниками.
Как запустить
Чтобы использовать представленный код в вашем торговом терминале MetaTrader 4, выполните следующие шаги:
- Создайте новый советник: Откройте MetaEditor (нажмите F4 в MT4), затем выберите ‘Файл’ -> ‘Создать’ -> ‘Советник (шаблон)’. Дайте ему любое имя, например,
VirtualSLTP_EA. - Вставьте код: Удалите весь сгенерированный код в новом файле и вставьте код, представленный выше.
- Скомпилируйте: Нажмите кнопку ‘Компилировать’ (или F7). Убедитесь, что нет ошибок.
- Прикрепите к графику: Перетащите скомпилированный советник (
VirtualSLTP_EA.ex4) из окна ‘Навигатор’ в MT4 на график нужной валютной пары. - Настройте параметры: В окне настроек советника (вкладка ‘Входные параметры’) установите желаемые значения для
VirtualStopLossPips,VirtualTakeProfitPipsиMagicNumber. Убедитесь, что на вкладке ‘Общие’ установлен флажок ‘Разрешить автоматическую торговлю’. - Откройте тестовый ордер: Для проверки работы виртуальных уровней откройте ордер вручную на том же графике, где установлен советник. Важно, чтобы при открытии ордера вы указали тот же
MagicNumber, что и в настройках советника (это можно сделать через скрипт или модифицировав код советника для открытия тестового ордера). Если вы не укажетеMagicNumber, советник не будет управлять этим ордером. В качестве альтернативы, вы можете раскомментировать и адаптировать блок кода в функцииOnStart()для автоматического открытия тестового ордера. - Наблюдайте: Следите за ценой. Когда она достигнет одного из виртуальных уровней, советник автоматически закроет позицию, и в журнале экспертов (вкладка ‘Эксперты’ в окне ‘Терминал’) появится соответствующее сообщение.
Важные соображения и дальнейшие улучшения
Реализация виртуальных SL/TP, как показано выше, является базовой. Для использования в реальной торговле необходимо учесть несколько моментов и рассмотреть возможные улучшения:
- Проскальзывание (Slippage): Закрытие ордера по рынку всегда подвержено проскальзыванию, особенно на волатильных рынках. Указанный в
OrderClose()параметрslippage(в нашем примере 3 пункта) помогает контролировать это, но не гарантирует точное закрытие по виртуальной цене. - Задержки (Latency): Скорость исполнения кода советника и связь с сервером брокера могут влиять на точность срабатывания виртуальных уровней.
- Обработка ошибок: В реальном советнике необходимо добавить более надежную обработку ошибок для функций
OrderClose(), чтобы убедиться, что ордер действительно закрыт, и предпринять повторные попытки в случае неудачи. - Частичное закрытие: Вы можете модифицировать логику для частичного закрытия позиций при достижении определенных виртуальных уровней, а не полного закрытия.
- Трейлинг-стоп: Виртуальные уровни идеально подходят для реализации сложных трейлинг-стопов, которые могут быть основаны не только на цене, но и на показаниях индикаторов. Например, вы можете использовать данные индикаторов с других таймфреймов, как описано в нашей статье Как считывать данные индикатора с другого таймфрейма (iCustom MTF) без перерисовки в MQL4, для динамического изменения виртуального SL.
- Управление капиталом: Интеграция виртуальных уровней с продвинутыми системами управления капиталом, такими как динамический мартингейл, может значительно повысить эффективность стратегии. Подробнее об этом можно узнать в статье Динамический Мартингейл с учетом корреляции пар в MQL4.
- Продвинутые стратегии: Виртуальные SL/TP являются фундаментом для создания более сложных торговых систем, включая те, что используют машинное обучение и нейронные сети для прогнозирования, как это описано в руководстве Нейросетевой предиктор на ALGLIB в MQL5: Руководство.
Реализация виртуальных Stop Loss и Take Profit — это мощный инструмент в арсенале Quant Developer, позволяющий создавать более гибкие, устойчивые и скрытые от брокера торговые стратегии.




