Problem Description
Solution
To manage existing trades in MQL4, you primarily use two functions: OrderModify() to change parameters like Stop Loss (SL) or Take Profit (TP), and OrderClose() to exit a market position.
Here is a detailed guide and the necessary code to perform both actions safely.
1. Modifying the Stop Loss
To change the Stop Loss, you must select the order using OrderSelect(), retrieve its current parameters (Open Price and Take Profit), and then pass the new Stop Loss value to OrderModify().
Key Considerations:
- Normalization: Prices must be normalized to the chart's digits using
NormalizeDouble()to avoid Error 129 (Invalid Price). - Freeze Level: Ensure the new SL is not too close to the current price (inside the FreezeLevel).
//+------------------------------------------------------------------+
//| Function to Modify Stop Loss of a specific ticket |
//+------------------------------------------------------------------+
void ModifyTradeSL(int ticket, double newStopLoss)
{
// 1. Select the order by ticket number
if(OrderSelect(ticket, SELECT_BY_TICKET))
{
// 2. Normalize the new Stop Loss price to match server digits
double normalizedSL = NormalizeDouble(newStopLoss, Digits);
// 3. Retrieve existing parameters that we do not want to change
double openPrice = OrderOpenPrice();
double takeProfit = OrderTakeProfit();
datetime expiration = OrderExpiration(); // Only relevant for pending orders
// 4. Send the modification request
// Note: We pass the existing openPrice and takeProfit to keep them unchanged
bool res = OrderModify(ticket, openPrice, normalizedSL, takeProfit, expiration, clrBlue);
if(!res)
{
Print("Error modifying order #", ticket, ". Error code: ", GetLastError());
}
else
{
Print("Order #", ticket, " Stop Loss modified successfully to ", normalizedSL);
}
}
else
{
Print("Failed to select order #", ticket, ". Error code: ", GetLastError());
}
}
2. Closing a Trade
To close a trade, you use OrderClose(). You must determine the correct closing price based on the order type:
- Buy Orders (OP_BUY): Close at
Bidprice. - Sell Orders (OP_SELL): Close at
Askprice.
//+------------------------------------------------------------------+
//| Function to Close a specific ticket completely |
//+------------------------------------------------------------------+
void CloseTrade(int ticket, int slippage = 3)
{
// 1. Select the order
if(OrderSelect(ticket, SELECT_BY_TICKET))
{
// 2. Check if the order is actually open (Market order)
// Pending orders (OP_BUYLIMIT, etc.) use OrderDelete(), not OrderClose()
int type = OrderType();
if(type > 1) // 0=OP_BUY, 1=OP_SELL. Anything higher is a pending order.
{
Print("Order #", ticket, " is a pending order. Use OrderDelete instead.");
return;
}
// 3. Determine the correct closing price and color
double closePrice = 0.0;
color arrowColor = clrNONE;
RefreshRates(); // Ensure we have the latest Bid/Ask
if(type == OP_BUY)
{
closePrice = Bid;
arrowColor = clrRed;
}
else if(type == OP_SELL)
{
closePrice = Ask;
arrowColor = clrBlue;
}
// 4. Send the close request
// We use OrderLots() to close the entire volume.
bool res = OrderClose(ticket, OrderLots(), closePrice, slippage, arrowColor);
if(!res)
{
Print("Error closing order #", ticket, ". Error code: ", GetLastError());
}
else
{
Print("Order #", ticket, " closed successfully.");
}
}
else
{
Print("Failed to select order #", ticket, ". Error code: ", GetLastError());
}
}
3. Implementation Example
Here is how you would use these functions inside an Expert Advisor (e.g., in the OnTick function). This example loops through open orders, finds a Buy order, moves the SL to Break Even, and then closes it.
void OnTick()
{
// Loop through all open orders
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// Filter by Symbol and Magic Number (optional but recommended)
if(OrderSymbol() == Symbol())
{
int ticket = OrderTicket();
double openPrice = OrderOpenPrice();
double currentSL = OrderStopLoss();
// --- EXAMPLE 1: MODIFY SL ---
// If it's a BUY order and price moved 50 points in profit, move SL to Break Even
if(OrderType() == OP_BUY)
{
if(Bid > openPrice + 50 * Point && currentSL < openPrice)
{
// Move SL to Open Price
ModifyTradeSL(ticket, openPrice);
}
}
// --- EXAMPLE 2: CLOSE TRADE ---
// If it's a SELL order and price moved 100 points against us (emergency close)
if(OrderType() == OP_SELL)
{
if(Ask > openPrice + 100 * Point)
{
CloseTrade(ticket);
}
}
}
}
}
}
Q&A: Common Issues with Order Management
Q: Why do I get Error 130 (ERR_INVALID_STOPS) when modifying Stop Loss?
A: This usually happens if the new Stop Loss is too close to the current market price. You must check the MODE_STOPLEVEL using MarketInfo(Symbol(), MODE_STOPLEVEL). The new SL must be at least that many points away from the current Bid/Ask.
Q: Can I close only half of my trade?
A: Yes. In the OrderClose() function, instead of passing OrderLots(), you can pass a specific volume (e.g., 0.5). This is called a partial close. The remaining volume will stay open with a new ticket number.
Q: Do I need to use OrderModify for Pending Orders?
A: Yes, OrderModify is used to change the Open Price, Stop Loss, Take Profit, or Expiration of pending orders. However, to remove a pending order entirely, you must use OrderDelete(), not OrderClose().
Q: Why is RefreshRates() important before closing?
A: MQL4 stores a local copy of prices. If your code executes complex logic that takes time, the prices (Bid/Ask) might become stale. Calling RefreshRates() updates these variables to the very latest server prices, reducing the chance of "Off Quotes" or slippage errors.