Order management is the core of any Expert Advisor. This guide covers everything you need to place, modify, and close trades in MQL5.
Understanding MQL5 Trade Structures
MqlTradeRequest
The request structure contains order details:
MqlTradeRequest request;
request.action = TRADE_ACTION_DEAL; // Action type
request.symbol = _Symbol; // Trading symbol
request.volume = 0.1; // Lot size
request.type = ORDER_TYPE_BUY; // Order type
request.price = Ask; // Entry price
request.sl = 0; // Stop loss
request.tp = 0; // Take profit
request.deviation = 10; // Slippage
request.magic = 12345; // Magic number
request.comment = "My trade"; // Comment
MqlTradeResult
The result structure returns execution details:
MqlTradeResult result;
// After OrderSend:
result.retcode; // Return code (10009 = success)
result.order; // Order ticket
result.deal; // Deal ticket
result.price; // Execution price
result.volume; // Executed volume
Placing Market Orders
Buy Market Order
bool PlaceBuyOrder(double lots, double sl, double tp)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lots;
request.type = ORDER_TYPE_BUY;
request.price = ask;
request.sl = sl;
request.tp = tp;
request.deviation = 10;
request.magic = MagicNumber;
request.comment = "Buy Order";
if(!OrderSend(request, result))
{
Print("OrderSend failed: ", GetLastError());
return false;
}
if(result.retcode != TRADE_RETCODE_DONE)
{
Print("Trade failed. Retcode: ", result.retcode);
return false;
}
Print("Buy order placed. Ticket: ", result.order);
return true;
}
Sell Market Order
bool PlaceSellOrder(double lots, double sl, double tp)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lots;
request.type = ORDER_TYPE_SELL;
request.price = bid;
request.sl = sl;
request.tp = tp;
request.deviation = 10;
request.magic = MagicNumber;
request.comment = "Sell Order";
if(!OrderSend(request, result))
{
Print("OrderSend failed: ", GetLastError());
return false;
}
if(result.retcode != TRADE_RETCODE_DONE)
{
Print("Trade failed. Retcode: ", result.retcode);
return false;
}
Print("Sell order placed. Ticket: ", result.order);
return true;
}
Placing Pending Orders
Buy Stop Order
Opens buy when price rises to specified level:
bool PlaceBuyStop(double price, double lots, double sl, double tp)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = lots;
request.type = ORDER_TYPE_BUY_STOP;
request.price = price;
request.sl = sl;
request.tp = tp;
request.magic = MagicNumber;
request.comment = "Buy Stop";
return OrderSend(request, result);
}
Buy Limit Order
Opens buy when price falls to specified level:
bool PlaceBuyLimit(double price, double lots, double sl, double tp)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = lots;
request.type = ORDER_TYPE_BUY_LIMIT;
request.price = price;
request.sl = sl;
request.tp = tp;
request.magic = MagicNumber;
request.comment = "Buy Limit";
return OrderSend(request, result);
}
Sell Stop and Sell Limit
Same pattern with ORDER_TYPE_SELL_STOP and ORDER_TYPE_SELL_LIMIT.
Modifying Positions
Modify Stop Loss and Take Profit
bool ModifyPosition(ulong ticket, double newSL, double newTP)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = _Symbol;
request.sl = newSL;
request.tp = newTP;
if(!OrderSend(request, result))
{
Print("Modify failed: ", GetLastError());
return false;
}
if(result.retcode != TRADE_RETCODE_DONE)
{
Print("Modify failed. Retcode: ", result.retcode);
return false;
}
Print("Position modified. New SL: ", newSL, " TP: ", newTP);
return true;
}
Trailing Stop Implementation
void TrailingStop(int trailPoints)
{
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
double positionSL = PositionGetDouble(POSITION_SL);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
long posType = PositionGetInteger(POSITION_TYPE);
if(posType == POSITION_TYPE_BUY)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double newSL = bid - trailPoints * point;
if(newSL > positionSL && newSL > openPrice)
{
ModifyPosition(ticket, newSL, PositionGetDouble(POSITION_TP));
}
}
else if(posType == POSITION_TYPE_SELL)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double newSL = ask + trailPoints * point;
if(newSL < positionSL || positionSL == 0)
{
if(newSL < openPrice)
{
ModifyPosition(ticket, newSL, PositionGetDouble(POSITION_TP));
}
}
}
}
}
Closing Positions
Close Single Position
bool ClosePosition(ulong ticket)
{
if(!PositionSelectByTicket(ticket))
{
Print("Position not found: ", ticket);
return false;
}
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = PositionGetString(POSITION_SYMBOL);
request.volume = PositionGetDouble(POSITION_VOLUME);
request.deviation = 10;
request.magic = MagicNumber;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(request.symbol, SYMBOL_BID);
}
else
{
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(request.symbol, SYMBOL_ASK);
}
if(!OrderSend(request, result))
{
Print("Close failed: ", GetLastError());
return false;
}
Print("Position closed: ", ticket);
return true;
}
Close All Positions
void CloseAllPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket > 0)
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
ClosePosition(ticket);
}
}
}
}
Partial Close
bool PartialClose(ulong ticket, double volumeToClose)
{
if(!PositionSelectByTicket(ticket))
return false;
double currentVolume = PositionGetDouble(POSITION_VOLUME);
if(volumeToClose > currentVolume)
volumeToClose = currentVolume;
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = PositionGetString(POSITION_SYMBOL);
request.volume = volumeToClose; // Partial volume
request.deviation = 10;
request.magic = MagicNumber;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(request.symbol, SYMBOL_BID);
}
else
{
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(request.symbol, SYMBOL_ASK);
}
return OrderSend(request, result);
}
Position Information
Get Position Details
void PrintPositionInfo(ulong ticket)
{
if(!PositionSelectByTicket(ticket))
{
Print("Position not found");
return;
}
Print("=== Position Info ===");
Print("Ticket: ", ticket);
Print("Symbol: ", PositionGetString(POSITION_SYMBOL));
Print("Type: ", PositionGetInteger(POSITION_TYPE) == 0 ? "Buy" : "Sell");
Print("Volume: ", PositionGetDouble(POSITION_VOLUME));
Print("Open Price: ", PositionGetDouble(POSITION_PRICE_OPEN));
Print("Current Price: ", PositionGetDouble(POSITION_PRICE_CURRENT));
Print("SL: ", PositionGetDouble(POSITION_SL));
Print("TP: ", PositionGetDouble(POSITION_TP));
Print("Profit: ", PositionGetDouble(POSITION_PROFIT));
Print("Magic: ", PositionGetInteger(POSITION_MAGIC));
}
Count Positions
int CountPositions(ENUM_POSITION_TYPE type = -1)
{
int count = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
if(type == -1 || PositionGetInteger(POSITION_TYPE) == type)
count++;
}
return count;
}
// Usage
int buyCount = CountPositions(POSITION_TYPE_BUY);
int sellCount = CountPositions(POSITION_TYPE_SELL);
int totalCount = CountPositions();
Error Handling
Common Return Codes
| Code | Meaning | Action |
|---|---|---|
| 10009 | TRADE_RETCODE_DONE | Success |
| 10013 | TRADE_RETCODE_INVALID | Invalid request |
| 10014 | TRADE_RETCODE_INVALID_VOLUME | Bad lot size |
| 10015 | TRADE_RETCODE_INVALID_PRICE | Bad price |
| 10016 | TRADE_RETCODE_INVALID_STOPS | Invalid SL/TP |
| 10019 | TRADE_RETCODE_NO_MONEY | Insufficient margin |
Error Handler Function
void HandleTradeError(uint retcode)
{
switch(retcode)
{
case TRADE_RETCODE_DONE:
Print("Trade executed successfully");
break;
case TRADE_RETCODE_INVALID_VOLUME:
Print("ERROR: Invalid lot size");
break;
case TRADE_RETCODE_INVALID_PRICE:
Print("ERROR: Invalid price");
break;
case TRADE_RETCODE_INVALID_STOPS:
Print("ERROR: Invalid SL/TP levels");
break;
case TRADE_RETCODE_NO_MONEY:
Print("ERROR: Not enough margin");
break;
default:
Print("ERROR: Trade failed with code ", retcode);
}
}
Key Takeaways
- Use MqlTradeRequest and MqlTradeResult for all orders
- TRADE_ACTION_DEAL for market orders
- TRADE_ACTION_PENDING for pending orders
- TRADE_ACTION_SLTP to modify SL/TP
- Always check return codes
- Use Magic Number to identify your trades
- Loop backwards when closing multiple positions
What's Next?
Learn about MQL5 risk management functions to protect your capital.
This article is for educational purposes only and does not constitute financial advice.