TradingTeaching Press · Dubai, UAE Trading is high-risk. Check local laws, your residency rules and your finances. Risk warning
🤖 Trading Automation

MQL5 Order Management: Place, Modify, and Close Trades

Master order management in MQL5. Learn to place market orders, pending orders, modify positions, and close trades programmatically.

6 min read TradingTeaching Team

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.

Risk warning. This is education only, not financial, investment, tax or legal advice, and not a recommendation to buy or sell anything. Trading forex, CFDs, stocks, commodities, futures, options and crypto is high-risk; with leverage you can lose more than you deposit, and most retail traders lose money. Before you trade or invest in any form, check the local laws where you are and the rules of your country of residence, and consider your own financial situation; if in doubt, ask a licensed adviser. Past and tested results, and all examples, are for illustration only and do not guarantee future results.

Get the strategy right before you automate it

An automated system is only as good as the rules behind it. The book series covers building and testing those rules before a line of code is written.

Explore the books