Problem Description
Solution
To modify the Stop Loss (SL) or Take Profit (TP) of all open trades in MQL4, you need to iterate through the order pool, select each order, calculate the new price levels, and send a modification request to the server.
Here is a complete, robust script that demonstrates how to loop through all open positions for the current symbol and apply new SL/TP levels based on points.
MQL4 Script: Modify All Open Trades
//+------------------------------------------------------------------+
//| ModifyAllTrades.mq4 |
//| Copyright 2023, Quantitative AI Assistant |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI Assistant"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#property script_show_inputs
//--- Input Parameters
input int InpStopLossPoints = 50; // Stop Loss in Points (0 to disable)
input int InpTakeProfitPoints = 100; // Take Profit in Points (0 to disable)
input int InpMagicNumber = 0; // Magic Number (0 for manual trades)
input bool InpAllSymbols = false; // Modify trades for all symbols?
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
// Adjust points for 3/5 digit brokers
double pnt = Point;
if(Digits == 3 || Digits == 5) pnt *= 10;
int total = OrdersTotal();
// Iterate backwards to handle potential index shifts safely
for(int i = total - 1; i >= 0; i--)
{
// 1. Select the order
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
Print("Failed to select order index: ", i, ". Error: ", GetLastError());
continue;
}
// 2. Filter by Symbol (unless AllSymbols is true)
if(!InpAllSymbols && OrderSymbol() != Symbol()) continue;
// 3. Filter by Magic Number (optional, remove if modifying all)
if(InpMagicNumber != 0 && OrderMagicNumber() != InpMagicNumber) continue;
// 4. Filter by Order Type (Only Buy and Sell, ignore pending orders)
if(OrderType() > OP_SELL) continue;
// Variables for calculation
double openPrice = OrderOpenPrice();
double newSL = 0;
double newTP = 0;
double currentSL = OrderStopLoss();
double currentTP = OrderTakeProfit();
// 5. Calculate new prices based on direction
if(OrderType() == OP_BUY)
{
if(InpStopLossPoints > 0) newSL = NormalizeDouble(openPrice - (InpStopLossPoints * pnt), Digits);
else newSL = currentSL; // Keep existing if input is 0
if(InpTakeProfitPoints > 0) newTP = NormalizeDouble(openPrice + (InpTakeProfitPoints * pnt), Digits);
else newTP = currentTP; // Keep existing if input is 0
}
else if(OrderType() == OP_SELL)
{
if(InpStopLossPoints > 0) newSL = NormalizeDouble(openPrice + (InpStopLossPoints * pnt), Digits);
else newSL = currentSL;
if(InpTakeProfitPoints > 0) newTP = NormalizeDouble(openPrice - (InpTakeProfitPoints * pnt), Digits);
else newTP = currentTP;
}
// 6. Check if modification is actually required to avoid Error 1 (ERR_NO_RESULT)
// We compare doubles using a small epsilon or simply check inequality after normalization
if(MathAbs(newSL - currentSL) < Point && MathAbs(newTP - currentTP) < Point)
{
Print("Order #", OrderTicket(), " already has these levels. Skipping.");
continue;
}
// 7. Send Modification Request
bool res = OrderModify(
OrderTicket(), // Ticket
OrderOpenPrice(), // Open Price (Must be the original open price)
newSL, // New Stop Loss
newTP, // New Take Profit
0, // Expiration (0 for market orders)
clrNONE // Arrow Color
);
if(!res)
{
Print("Error modifying order #", OrderTicket(), ". Error code: ", GetLastError());
}
else
{
Print("Successfully modified order #", OrderTicket());
}
}
}
Key Logic Explanation
-
OrdersTotal()& Loop Direction:
We useOrdersTotal()to get the count of open and pending orders. We loop fromOrdersTotal() - 1down to0. WhileOrderModifydoesn't remove orders from the list, iterating backwards is a best practice in MQL4 to ensure stability if you later decide to close orders within the same loop. -
OrderSelect(..., MODE_TRADES):
This selects orders from the "Trade" tab (active positions and pending orders). Do not useMODE_HISTORYhere, as that accesses closed trades. -
Filters:
- Symbol:
OrderSymbol() == Symbol()ensures you only modify trades for the chart the script is running on. - Type:
OrderType() <= OP_SELLensures we only modify active Buy (0) and Sell (1) positions, ignoring pending orders (Limit/Stop).
- Symbol:
-
NormalizeDouble():
This is critical. Prices calculated mathematically (e.g.,1.12345 + 0.00100) can result in floating-point artifacts (e.g.,1.1244500000001). Sending un-normalized prices toOrderModifyoften results in Error 129 (Invalid Price). Always normalize toDigits. -
Error 1 Prevention:
If you try to modify an order with the exact same SL and TP it already has, the server returns Error 1 (ERR_NO_RESULT). The code checksMathAbs(newSL - currentSL) < Pointto ensure values have actually changed before calling the server.
Common Error Codes
- 129 (ERR_INVALID_PRICE): Usually caused by failing to use
NormalizeDouble. - 130 (ERR_INVALID_STOPS): The SL or TP is too close to the current market price. You must check
MarketInfo(Symbol(), MODE_STOPLEVEL)if you are setting tight stops. - 4108 (ERR_INVALID_TICKET): The order closed before the script could modify it, or
OrderSelectfailed.
Q&A
Q: Can I use this code to modify Pending Orders (Limit/Stop) as well?
A: Yes, but you need to remove the check if(OrderType() > OP_SELL) continue;. Also, note that for pending orders, the OrderOpenPrice() parameter in OrderModify allows you to change the entry price, whereas for open market orders, that parameter must remain the current open price.
Q: How do I set the SL to the exact Open Price (Break Even)?
A: In the calculation section, instead of adding/subtracting points, simply set newSL = OrderOpenPrice().
Q: Why does the script use OrderOpenPrice() in OrderModify?
A: The OrderModify function signature requires the Open Price as the second parameter. For active market orders, you cannot change the open price, but you must still pass the original value. Passing 0 or the current Bid/Ask will result in an error.