MT5 Error 10016 (Invalid Stops): Causes and Fixes in MQL5 OrderSend
Short answer: Error 10016 in MetaTrader 5 is TRADE_RETCODE_INVALID_STOPS — the broker rejected your Stop Loss or Take Profit because they violate server rules (distance, direction, or precision). Fix it by reading SYMBOL_TRADE_STOPS_LEVEL, placing SL/TP on the correct side of price for Buy/Sell, using NormalizeDouble, and calling OrderCheck() before OrderSend().
If you searched MT5 error 10016, invalid stops MQL5, or OrderSend failed 10016, this page is the fix map — aligned with the official trade return codes, not forum guesses.
Related guides: Common MQL5 EA Errors · Can ChatGPT Write an MT5 EA? · EA Risk Management · Build Your First EA
What Is MT5 Error 10016?
After OrderSend(), check MqlTradeResult retcode. When it equals 10016, the constant is TRADE_RETCODE_INVALID_STOPS.
Official wording from MetaQuotes: "Invalid stops in the request."
That means the prices you sent for SL and/or TP are not acceptable to the trade server for this symbol at this moment — not that your EA logic is "wrong," but that the request broke broker constraints.
Symptoms:
- Journal line:
failed market buy … [invalid stops]or retcode 10016 - OrderSend returns
truebutretcode != TRADE_RETCODE_DONE(always readretcode) - Works on one broker symbol suffix, fails on another (
EURUSDvsEURUSD.pro)
Error 10016 vs Old Error 130 (MT4)
| MT4 habit | MT5 correct check | |
|---|---|---|
| Typical number | 130 (ERR_INVALID_STOPS) in older examples | 10016 in MqlTradeResult.retcode |
| Where to read | GetLastError() after OrderSend | result.retcode after OrderSend |
| AI risk | ChatGPT still outputs MT4 patterns | Demand "MQL5 only, check result.retcode" |
When auditing code, search for 130 and replace with handling of 10016 on MqlTradeResult. Our ChatGPT MQL5 guide covers this mix-up.
SYMBOL_TRADE_STOPS_LEVEL Explained
Brokers require a minimum distance (in points) between the current price and any pending SL/TP attached to a market order.
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double minDist = stopLevel * point; // price distance, not pips
Per SymbolInfoInteger documentation, SYMBOL_TRADE_STOPS_LEVEL is the minimum distance for stop orders.
Also check freeze level: SYMBOL_TRADE_FREEZE_LEVEL — while price is within freeze distance, modifying SL/TP can fail. Relevant for EAs that trail stops every tick.
Practical tip: Add 1–3 points buffer above stopLevel on live accounts; spreads widen at news.
Correct SL and TP Placement (Buy and Sell)
Wrong side is the #2 cause after distance.
| Action | Stop loss | Take profit |
|---|---|---|
| Buy (ASK) | Below entry | Above entry |
| Sell (BID) | Above entry | Below entry |
For Buy, use ASK as reference when setting SL/TP on market buy; for Sell, BID. Mixing Bid/Ask causes subtle 10016 on some servers.
Digits matter: NormalizeDouble(price, (int)SymbolInfoInteger(sym, SYMBOL_DIGITS)).
Fix Invalid Stops in MQL5 Code
Adjust SL/TP to minimum distance
void AdjustStopsForBroker(const string sym, ENUM_ORDER_TYPE type,
double price, double &sl, double &tp)
{
int digits = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
int stopLevel = (int)SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
if(stopLevel <= 0) stopLevel = 10;
double point = SymbolInfoDouble(sym, SYMBOL_POINT);
double minDist = (stopLevel + 2) * point; // +2 point buffer
if(type == ORDER_TYPE_BUY)
{
if(sl > 0 && price - sl < minDist)
sl = NormalizeDouble(price - minDist, digits);
if(tp > 0 && tp - price < minDist)
tp = NormalizeDouble(price + minDist, digits);
if(sl > 0 && sl >= price) sl = NormalizeDouble(price - minDist, digits);
if(tp > 0 && tp <= price) tp = NormalizeDouble(price + minDist, digits);
}
else if(type == ORDER_TYPE_SELL)
{
if(sl > 0 && sl - price < minDist)
sl = NormalizeDouble(price + minDist, digits);
if(tp > 0 && price - tp < minDist)
tp = NormalizeDouble(price - minDist, digits);
if(sl > 0 && sl <= price) sl = NormalizeDouble(price + minDist, digits);
if(tp > 0 && tp >= price) tp = NormalizeDouble(price - minDist, digits);
}
}
Call AdjustStopsForBroker immediately before building MqlTradeRequest.
Alternative: send without SL/TP, manage in code
Set request.sl = 0 and request.tp = 0 on OrderSend, then modify with OrderSend TRADE_ACTION_SLTP once price has moved, or exit with a market close. Used by some scalping EAs — see scalping EA guide.
Use OrderCheck() Before OrderSend()
MetaQuotes recommends validation first. From OrderSend: "It is recommended to check the request before sending it to a trade server… use the OrderCheck() function."
MqlTradeRequest request = {};
MqlTradeCheckResult check = {};
// ... fill request ...
if(!OrderCheck(request, check))
{
Print("OrderCheck failed, retcode=", check.retcode,
" balance=", check.balance, " margin=", check.margin);
return;
}
if(check.retcode == TRADE_RETCODE_INVALID_STOPS)
Print("Would fail with 10016 — fix SL/TP before sending");
if(!OrderSend(request, result))
Print("OrderSend error ", GetLastError());
else if(result.retcode != TRADE_RETCODE_DONE)
Print("Server retcode=", result.retcode, " ", result.comment);
Log result.comment — it often says invalid stops in plain language for the Journal.
Backtest vs Live: Why 10016 Only on Real
| Environment | Typical behavior |
|---|---|
| Strategy Tester | Fixed spread; may not enforce stops level like live |
| Demo live | Closer to real server rules — use for SL/TP validation |
| Live | Strict SYMBOL_TRADE_STOPS_LEVEL, freeze, symbol suffix |
Community tests of AI-generated EAs often pass backtest then hit 10016 on the first live order — because stops level was never coded.
Checklist before live:
- Same symbol name/suffix as production
- Print
SYMBOL_TRADE_STOPS_LEVELonce in OnInit - Demo trade with smallest lot
- Read deploy guide logging section
Next Steps
- All major codes: Common MQL5 EA Errors
- AI drafts missing stops: ChatGPT MQL5 EA Guide
- SL distance from ATR: EA Risk Management
- First working EA: Build Your First EA
- Prop firm guards: Prop Firm EA Rules
References: enum_trade_return_codes — TRADE_RETCODE_INVALID_STOPS, SymbolInfoInteger, OrderSend, OrderCheck, NormalizeDouble, MQL5 — ChatGPT EA test (2026).