Magic Number. Позволяет задать новые уровни SL/TP в пунктах относительно цены открытия ордера, с учетом минимального отступа брокера.Введение
В активном трейдинге, особенно при использовании нескольких экспертных советников или ручной торговле с большим количеством позиций, возникает необходимость оперативно управлять параметрами ордеров. Ручное изменение уровней Stop Loss (SL) и Take Profit (TP) для десятков или сотен ордеров может быть крайне трудоемким и неэффективным. Именно для таких сценариев мы, как Senior Quant Developers, разработали специализированный MQL5 скрипт.
Этот скрипт позволяет массово изменить SL и TP для всех открытых ордеров, которые имеют определенный Magic Number, на текущем торговом символе. Это особенно полезно, когда вы хотите быстро адаптировать стратегию управления рисками или прибылью для группы ордеров, запущенных одним экспертом или по одной торговой идее. Например, если вы используете несколько стратегий, каждая из которых имеет свой Magic Number, вы можете легко управлять ими по отдельности. Если вас интересуют другие аспекты автоматизации, рекомендуем ознакомиться с нашим скриптом для сбора статистики проскальзываний Market ордеров.
Исходный код
Представленный ниже MQL5 скрипт предназначен для выполнения массовых операций по изменению SL и TP. Он тщательно проверяет все открытые позиции, фильтрует их по заданному Magic Number и символу, а затем корректирует уровни SL/TP, учитывая при этом минимальные требования брокера к отступам (TradeStopLevel). Скрипт также включает функцию подтверждения, чтобы избежать случайных изменений.
//+------------------------------------------------------------------+
//| MassModifySLTPbyMagicNumber.mq5|
//| Copyright 2023, FinFluct|
//| https://finfluct.com|
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, FinFluct"
#property link "https://finfluct.com"
#property version "1.00"
#property description "Скрипт для массового изменения уровней Stop Loss и Take Profit"
#property description "у всех открытых ордеров по одному Magic Number."
#property script_show_inputs
//--- Входные параметры
input long MagicNumberToModify = 12345; // Magic Number ордеров для изменения
input int NewStopLossPips = 50; // Новый Stop Loss в пунктах (0 - не изменять)
input int NewTakeProfitPips = 100; // Новый Take Profit в пунктах (0 - не изменять)
input bool ConfirmModification = true; // Подтверждение перед изменением
//--- Глобальные переменные для работы с символом
MQL_SYMBOL_INFO _SymbolInfo;
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
// Получаем информацию о текущем символе
if (!SymbolInfoGet(_Symbol, _SymbolInfo))
{
Print("Ошибка получения информации о символе ", _Symbol, ": ", GetLastError());
return;
}
// Проверка на нулевые значения SL/TP, если оба 0, то нет смысла запускать
if (NewStopLossPips == 0 && NewTakeProfitPips == 0)
{
Print("Оба значения Stop Loss и Take Profit равны 0. Изменения не требуются.");
return;
}
// Подтверждение действия
if (ConfirmModification)
{
string message = "Вы уверены, что хотите изменить SL/TP для всех ордеров с Magic Number " +
(string)MagicNumberToModify + " на символе " + _Symbol + "?\n\n";
if (NewStopLossPips > 0) message += "Новый SL: " + (string)NewStopLossPips + " пунктов\n";
else message += "SL останется без изменений\n";
if (NewTakeProfitPips > 0) message += "Новый TP: " + (string)NewTakeProfitPips + " пунктов";
else message += "TP останется без изменений";
if (MessageBox(message, "Подтверждение массового изменения SL/TP", MB_YESNO | MB_ICONQUESTION) == IDNO)
{
Print("Действие отменено пользователем.");
return;
}
}
int modifiedCount = 0;
int totalPositions = PositionsTotal();
if (totalPositions == 0)
{
Print("Открытых позиций не найдено.");
return;
}
Print("Начинаем проверку ", totalPositions, " открытых позиций на символе ", _Symbol, "...");
// Итерируем по всем открытым позициям
for (int i = totalPositions - 1; i >= 0; i--)
{
string symbol = PositionGetSymbol(i);
if (symbol == _Symbol) // Работаем только с позициями по текущему символу
{
long magic = PositionGetInteger(POSITION_MAGIC);
if (magic == MagicNumberToModify)
{
ulong ticket = PositionGetTicket(i);
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double newSL = currentSL; // Инициализируем текущими значениями
double newTP = currentTP; // Инициализируем текущими значениями
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Расчет нового Stop Loss
if (NewStopLossPips > 0)
{
// 1 стандартный пункт (pip) = 10 * _SymbolInfo.Point для большинства инструментов (например, EURUSD 5-знак)
double slPriceOffset = NewStopLossPips * _SymbolInfo.Point * 10;
if (type == POSITION_TYPE_BUY)
{
newSL = NormalizeDouble(openPrice - slPriceOffset, _SymbolInfo.Digits);
}
else if (type == POSITION_TYPE_SELL)
{
newSL = NormalizeDouble(openPrice + slPriceOffset, _SymbolInfo.Digits);
}
}
// Расчет нового Take Profit
if (NewTakeProfitPips > 0)
{
double tpPriceOffset = NewTakeProfitPips * _SymbolInfo.Point * 10;
if (type == POSITION_TYPE_BUY)
{
newTP = NormalizeDouble(openPrice + tpPriceOffset, _SymbolInfo.Digits);
}
else if (type == POSITION_TYPE_SELL)
{
newTP = NormalizeDouble(openPrice - tpPriceOffset, _SymbolInfo.Digits);
}
}
// Проверка на минимальный отступ от текущей цены (TradeStopLevel)
// TradeStopLevel возвращается в пунктах (points), поэтому умножаем на _SymbolInfo.Point
double minDistance = _SymbolInfo.TradeStopLevel * _SymbolInfo.Point;
// Корректировка SL, если он слишком близко к текущей цене
if (newSL != 0) // Если SL установлен
{
if (type == POSITION_TYPE_BUY)
{
if (newSL > currentAsk - minDistance)
{
newSL = NormalizeDouble(currentAsk - minDistance, _SymbolInfo.Digits);
Print("Внимание: SL для BUY ордера #", ticket, " скорректирован до ", newSL, " из-за TradeStopLevel.");
}
}
else if (type == POSITION_TYPE_SELL)
{
if (newSL < currentBid + minDistance)
{
newSL = NormalizeDouble(currentBid + minDistance, _SymbolInfo.Digits);
Print("Внимание: SL для SELL ордера #", ticket, " скорректирован до ", newSL, " из-за TradeStopLevel.");
}
}
}
// Корректировка TP, если он слишком близко к текущей цене
if (newTP != 0) // Если TP установлен
{
if (type == POSITION_TYPE_BUY)
{
if (newTP < currentAsk + minDistance)
{
newTP = NormalizeDouble(currentAsk + minDistance, _SymbolInfo.Digits);
Print("Внимание: TP для BUY ордера #", ticket, " скорректирован до ", newTP, " из-за TradeStopLevel.");
}
}
else if (type == POSITION_TYPE_SELL)
{
if (newTP > currentBid - minDistance)
{
newTP = NormalizeDouble(currentBid - minDistance, _SymbolInfo.Digits);
Print("Внимание: TP для SELL ордера #", ticket, " скорректирован до ", newTP, " из-за TradeStopLevel.");
}
}
}
// Проверка, нужно ли вообще что-то менять
// Сравниваем с точностью до Digits, чтобы избежать проблем с плавающей точкой
if (NormalizeDouble(newSL, _SymbolInfo.Digits) == NormalizeDouble(currentSL, _SymbolInfo.Digits) &&
NormalizeDouble(newTP, _SymbolInfo.Digits) == NormalizeDouble(currentTP, _SymbolInfo.Digits))
{
Print("Ордер #", ticket, " (Magic: ", magic, ") - SL/TP уже соответствуют заданным значениям. Пропускаем.");
continue;
}
// Отправка запроса на изменение
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.sl = newSL;
request.tp = newTP;
request.deviation = 0; // Отклонение не требуется для SL/TP
if (!OrderSend(request, result))
{
Print("Ошибка отправки запроса на изменение ордера #", ticket, ": ", GetLastError());
}
else
{
if (result.retcode == TRADE_RETCODE_DONE)
{
Print("Успешно изменен ордер #", ticket, " (Magic: ", magic, "). Новый SL: ", newSL, ", Новый TP: ", newTP);
modifiedCount++;
}
else
{
Print("Не удалось изменить ордер #", ticket, " (Magic: ", magic, "). Код ошибки: ", result.retcode, ". Описание: ", result.comment);
}
}
}
}
}
if (modifiedCount > 0)
{
Print("Массовое изменение SL/TP завершено. Изменено ордеров: ", modifiedCount);
}
else
{
Print("Не найдено ордеров с Magic Number ", MagicNumberToModify, " на символе ", _Symbol, " для изменения SL/TP.");
}
}
Разбор параметров
Скрипт имеет несколько входных параметров, которые позволяют гибко настроить его поведение:
MagicNumberToModify:Уникальный идентификатор (Magic Number) ордеров, для которых будут изменяться уровни SL/TP. Скрипт будет обрабатывать только те открытые позиции на текущем символе, чей
Magic Numberсовпадает с этим значением.NewStopLossPips:Новое значение Stop Loss в пунктах. Это расстояние будет отсчитываться от цены открытия ордера. Если установить значение
0, Stop Loss для ордеров с указаннымMagic Numberизменяться не будет (сохранится текущее значение).NewTakeProfitPips:Новое значение Take Profit в пунктах. Это расстояние также будет отсчитываться от цены открытия ордера. Если установить значение
0, Take Profit для ордеров с указаннымMagic Numberизменяться не будет (сохранится текущее значение).ConfirmModification:Булевый параметр, который включает или отключает запрос подтверждения перед выполнением массового изменения. Рекомендуется оставлять
trueдля предотвращения случайных действий, особенно на реальном счете.
Как запустить
Для использования скрипта выполните следующие шаги:
-
Откройте MetaEditor: В MetaTrader 5 нажмите
F4или выберитеСервис -> Редактор MetaQuotes Language. -
Создайте новый скрипт: В MetaEditor выберите
Файл -> Создать -> Скрипт. Назовите его, например,MassModifySLTPbyMagicNumber.mq5. -
Вставьте код: Скопируйте предоставленный выше исходный код и вставьте его в окно нового скрипта, заменив стандартный шаблон.
-
Скомпилируйте скрипт: Нажмите
F7или кнопкуКомпилироватьна панели инструментов. Убедитесь, что в окнеОшибкинет сообщений об ошибках. -
Перейдите в MetaTrader 5: Откройте терминал MetaTrader 5.
-
Найдите скрипт: В окне
Навигатор(обычно слева) разверните разделСкриптыи найдитеMassModifySLTPbyMagicNumber. -
Прикрепите к графику: Перетащите скрипт на график того торгового символа, для которого вы хотите изменить ордера (например, EURUSD). Важно: скрипт будет работать только с ордерами на том символе, к графику которого он прикреплен.
-
Настройте параметры: Появится окно с входными параметрами. Укажите желаемый
Magic NumberToModify, а такжеNewStopLossPipsиNewTakeProfitPips. Если вы хотите, чтобы SL или TP не изменялись, оставьте соответствующее значение0. Убедитесь, чтоConfirmModificationустановлен вtrueдля безопасности. -
Разрешите автоматическую торговлю: На вкладке
Общиеустановите флажокРазрешить автоматическую торговлю. -
Запустите скрипт: Нажмите
ОК. ЕслиConfirmModificationвключен, появится диалоговое окно с запросом подтверждения. После подтверждения скрипт выполнит изменения. -
Проверьте результат: Откройте вкладку
Экспертыв окнеТерминал(Ctrl+T), чтобы увидеть логи работы скрипта и подтверждение изменений. Также проверьте свои открытые позиции.
Заключение
Этот скрипт является мощным инструментом для эффективного управления рисками и прибылью в вашей торговой стратегии. Он позволяет быстро реагировать на изменения рынка, корректируя параметры множества ордеров одновременно, что значительно экономит время и снижает вероятность ошибок по сравнению с ручным методом. Подобные инструменты автоматизации, как и скрипт для массового закрытия убыточных позиций, являются неотъемлемой частью арсенала современного трейдера.
Для тех, кто стремится к более глубокой оптимизации торговых стратегий, мы также рекомендуем изучить методы автоматического управления объемами ордеров, например, с помощью автоматического выравнивания объемов ордеров по Келли (Lot Sizing), что позволит вам еще точнее контролировать риски и максимизировать потенциальную прибыль.




