Edgoro
Trade server return code 10029 · MQL5

MT5 error 10029 Order or position frozen: fix

What retcode 10029 (frozen) means in MetaTrader 5: the freeze level, SYMBOL_TRADE_FREEZE_LEVEL, and how to check it before modifying stops or orders in MQL5.

Trade server return code · MqlTradeResult.retcode
10029 TRADE_RETCODE_FROZEN
“Order or position frozen”
Experts tab · line printed by CTrade (example values)
CTrade::OrderSend: modify position #123456789 EURUSD (sl: 1.08440, tp: 1.08900) [frozen]

What it means

The server refused to modify an order or a position because the market is too close to it. Each symbol can have a freeze level: a distance from the current price inside which pending orders and the stops of open positions can't be changed.

Usual causes

  • A trailing stop near the market. The position's current stop (or target) is within the freeze level of the price, so it can't be moved.
  • A pending order about to trigger. Its price is within the freeze level of the market, so it can't be modified.
  • No freeze check at all. The code checks the stops level but not SYMBOL_TRADE_FREEZE_LEVEL.

The rules from MetaQuotes' checklist, with F the freeze distance (SYMBOL_TRADE_FREEZE_LEVEL × _Point):

What you modifyAllowed only if
Buy positionTP − Bid ≥ F and Bid − SL ≥ F
Sell positionAsk − TP ≥ F and SL − Ask ≥ F
Buy limitAsk − order price ≥ F
Buy stopOrder price − Ask ≥ F
Sell limitOrder price − Bid ≥ F
Sell stopBid − order price ≥ F

A freeze level of 0 means no freeze zone.

How to detect it

  • trade.ResultRetcode() (or result.retcode) is 10029; the Experts tab shows the modify request followed by [frozen].
  • Read SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL) and log it with the Bid, Ask, stop and target when a modification fails.

Broken code

This EA compiles. When the Bid comes within the freeze level of the current stop or target, the modification fails with 10029.

MQL5
#include <Trade/Trade.mqh>

input int InpTrailPoints = 100; // Trailing distance, points

CTrade trade;

void OnTick()
  {
   if(!PositionSelect(_Symbol) || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY)
      return;
   double bid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double oldSl = PositionGetDouble(POSITION_SL);
   double newSl = NormalizeDouble(bid - InpTrailPoints * _Point, _Digits);
   // Checks that the stop improves, but not whether the position is frozen
   if(newSl > oldSl)
      trade.PositionModify(_Symbol, newSl, PositionGetDouble(POSITION_TP));
  }

Fixed code

The same program with the check that prevents the error. It compiles in MetaEditor with 0 errors and 0 warnings.

MQL5
#include <Trade/Trade.mqh>

input int InpTrailPoints = 100; // Trailing distance, points

CTrade trade;

// True if a buy position's stop and target may be modified now (freeze level rules)
bool BuyStopsModifiable(const double sl, const double tp, const double bid)
  {
   double freeze = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL) * _Point;
   if(freeze <= 0.0)
      return true;
   if(sl != 0.0 && bid - sl < freeze)
      return false;
   if(tp != 0.0 && tp - bid < freeze)
      return false;
   return true;
  }

void OnTick()
  {
   if(!PositionSelect(_Symbol) || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY)
      return;
   double bid     = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double oldSl   = PositionGetDouble(POSITION_SL);
   double tp      = PositionGetDouble(POSITION_TP);
   double newSl   = NormalizeDouble(bid - InpTrailPoints * _Point, _Digits);
   double minDist = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
   if(newSl <= oldSl || bid - newSl < minDist)
      return;
   // Inside the freeze zone nothing can be changed: wait for the price to move away
   if(!BuyStopsModifiable(oldSl, tp, bid))
      return;
   if(!trade.PositionModify(_Symbol, newSl, tp))
      PrintFormat("Modify failed: retcode %u (%s)", trade.ResultRetcode(), trade.ResultRetcodeDescription());
  }

Why the fix works

Before sending, the EA applies the freeze rule for a buy position to the levels the position has now: when the Bid is within the freeze distance of the current stop or target, it waits for a later tick instead of sending a request the server will refuse. The new stop must also stay beyond the stops level, or the server answers with 10016. For sell positions, use the Ask and the mirrored conditions in the table.

Questions

What is the freeze level in MT5?

A distance in points, set by the broker per symbol (SYMBOL_TRADE_FREEZE_LEVEL), inside which pending orders and the stop-loss and take-profit of open positions can't be modified. 0 means there's no freeze zone.

What's the difference between the freeze level and the stops level?

The stops level is the minimum distance for new stops and pending orders. The freeze level forbids changing existing orders and stops that are already close to the price. A trailing stop has to respect both.

What was 10029 called in MT4?

MQL4's error 145, ERR_TRADE_MODIFY_DENIED: modification denied because the order is too close to the market.

The programs on this page are minimal examples written to show the error and its fix, not trading systems. Some of them send orders when they run: try them on a demo account. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.

Working code that avoids it

All MQL5 examples

Rather not write the error handling yourself?

Edgoro's MT5 EA generator writes complete MQL5 Expert Advisors from plain English and compiles each one in MetaEditor before you get it. A clean build proves the code compiles, not that a strategy works: test it on a demo account.