Back to MetaTrader 5 MQL5 for CFD Traders
Part 3

Placing and Managing Orders

MqlTradeRequest by hand: filling modes, deviation, retcodes, and closing what you opened.

Intermediate12 min readBeginner → AdvancedLesson 11 / 17
Try it in MetaEditor
Raw OrderSend with a filling-mode fallback chain

Save as MQL5/Experts/Lesson11RawOrder.mq5. DEMO ONLY. It builds the request manually, tries FOK then IOC then RETURN, and prints the full result — the same logic CTrade hides.

//+------------------------------------------------------------------+
//| Lesson 11 - Raw OrderSend, filling modes, retcodes               |
//| WARNING: sends real market orders. Use a DEMO account.           |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version   "1.00"
#property strict

input double Lots        = 0.10;
input int    StopPoints  = 200;
input int    Deviation   = 10;
input ulong  MagicNumber = 11111111;

datetime lastBarTime = 0;

int OnInit()
{
   Print("Filling mode supported by ", _Symbol, ": ",
         EnumToString((ENUM_ORDER_TYPE_FILLING)SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE)));
   return(INIT_SUCCEEDED);
}

void OnTick()
{
   datetime t = iTime(_Symbol, _Period, 0);
   if(t == lastBarTime) return;
   lastBarTime = t;

   if(PositionSelect(_Symbol))
   {
      Print("Position already open - skipping.");
      return;
   }

   OpenBuy(Lots, StopPoints);
}

//+------------------------------------------------------------------+
//| Market buy built by hand, with a filling-mode fallback chain     |
//+------------------------------------------------------------------+
void OpenBuy(const double lots, const double stopPoints)
{
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double sl  = NormalizeDouble(ask - stopPoints * _Point, _Digits);

   MqlTradeRequest req = {};
   MqlTradeResult  res = {};

   req.action    = TRADE_ACTION_DEAL;
   req.symbol    = _Symbol;
   req.volume    = NormalizeDouble(lots, 2);
   req.type      = ORDER_TYPE_BUY;
   req.price     = ask;
   req.sl        = sl;
   req.deviation = Deviation;
   req.magic     = MagicNumber;
   req.comment   = "lesson11";

   // Ask the symbol first; fall back through the rest if the server refuses.
   long supported = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);

   ENUM_ORDER_TYPE_FILLING modes[3];
   if((supported & SYMBOL_FILLING_FOK) != 0)
      { modes[0] = ORDER_FILLING_FOK;    modes[1] = ORDER_FILLING_IOC;    modes[2] = ORDER_FILLING_RETURN; }
   else if((supported & SYMBOL_FILLING_IOC) != 0)
      { modes[0] = ORDER_FILLING_IOC;    modes[1] = ORDER_FILLING_RETURN; modes[2] = ORDER_FILLING_FOK;    }
   else
      { modes[0] = ORDER_FILLING_RETURN; modes[1] = ORDER_FILLING_FOK;    modes[2] = ORDER_FILLING_IOC;    }

   for(int i = 0; i < 3; i++)
   {
      req.type_filling = modes[i];
      ResetLastError();

      if(!OrderSend(req, res))
      {
         Print("OrderSend failed with ", EnumToString(modes[i]),
               ". GetLastError=", GetLastError());
         continue;
      }

      Print("Sent with ", EnumToString(modes[i]),
            " -> retcode=", res.retcode,
            "  deal=", res.deal,
            "  volume=", DoubleToString(res.volume, 2),
            "  price=", DoubleToString(res.price, _Digits));

      if(res.retcode == TRADE_RETCODE_DONE || res.retcode == TRADE_RETCODE_PLACED)
      {
         Print("SUCCESS: order accepted.");
         return;
      }

      // Retcode-specific hints - do not blindly retry these.
      if(res.retcode == TRADE_RETCODE_INVALID_STOPS)
      {
         Print("Invalid stops: your SL/TP is too close. Broker minimum is ",
               SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL), " points.");
         return;
      }
      if(res.retcode == TRADE_RETCODE_NO_MONEY)
      {
         Print("Not enough margin. Free margin: ",
               DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_FREE), 2));
         return;
      }
      Print("Rejected with retcode ", res.retcode, " - check the retcode table.");
      return;
   }
}
To run it
  1. 1. Open MetaEditor from MT5 (press F4), and pick the folder this program belongs in — Experts, Indicators, or Scripts.
  2. 2. Create a new file, paste this over it, then press F7 to compile. Fix anything the Errors tab reports.
  3. 3. Back in MT5, drag it onto a chart — or open the Strategy Tester if it is an Expert Advisor.

Under CTrade: the raw request

CTrade is convenient, but you should see the machinery once. Every order is a MqlTradeRequest struct passed to OrderSend, which fills a MqlTradeResult.

Fields that matter

  • actionTRADE_ACTION_DEAL (market), TRADE_ACTION_PENDING, TRADE_ACTION_SLTP, TRADE_ACTION_MODIFY, TRADE_ACTION_REMOVE.
  • typeORDER_TYPE_BUY, ORDER_TYPE_SELL, plus the pending variants.
  • volume — normalised to the symbol's step.
  • price — ask for buys, bid for sells. For market orders you may pass 0 and let the server fill it.
  • sl / tp — absolute prices, normalised to digits.
  • deviation — slippage tolerance in points.
  • type_fillingORDER_FILLING_FOK, ORDER_FILLING_IOC, or ORDER_FILLING_RETURN.
  • magic, comment — your identity and a note for the log.

Filling mode is the classic rejection

Send the wrong type_filling and you get unsupported filling mode — usually on exactly the broker you most want to trade with. Do not hardcode it. Query SYMBOL_FILLING_MODE, or let CTrade::SetTypeFillingBySymbol() do it. This lesson shows the manual fallback chain so you can see what that helper is doing.

Retcodes are your error messages

TRADE_RETCODE_DONE means filled. TRADE_RETCODE_PLACED means a pending order was accepted. Anything else is a specific, documented failure: requote, invalid stops, no money, market closed, disabled trading. Print the code and look it up — do not just retry blindly, because retrying a rejection caused by a too-tight stop will fail forever.

Closing and modifying

Use TRADE_ACTION_REMOVE for pending orders and CTrade::PositionClose for open positions. On hedging accounts you close a specific ticket; on netting accounts you close the symbol's single net position.

What you just did

Lesson 11 of 17 in MetaTrader 5 MQL5 for CFD Traders. When you have run the examples or read the section, tick it off and move to the next lesson.