◆ New — Strategy Validator, Code Fixer & Prop Compliance Checker are live. Try one free →
Home / Learn / MetaTrader OrderSend Errors Explained: 130, 131, 134, 4109 and Friends
MetaTrader

MetaTrader OrderSend Errors Explained: 130, 131, 134, 4109 and Friends

OrderSend error 130 (invalid stops) and its siblings — 131, 134, 4109, requotes and context-busy errors — all trace back to a small set of broker-side constraints: stop level distance, lot step and limits, margin, and trading permissions. This guide gives the error table with root causes and the defensive MQL4 patterns (with MQL5 retcode equivalents) that prevent each one before the order is ever sent. Educational material only, not financial advice: these patterns make order code robust, they do not make any strategy profitable, and trading carries a real risk of loss.

Why am I getting OrderSend error 130 (invalid stops) in MetaTrader?

Error 130 (ERR_INVALID_STOPS) means your stop-loss or take-profit violates the broker's placement rules: it is too close to the current market price (inside the symbol's minimum stop distance), on the wrong side of the price, or not normalized to the symbol's tick size. The broker publishes the minimum distance as the stop levelMarketInfo(Symbol(), MODE_STOPLEVEL) in MQL4, SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) in MQL5 — expressed in points, and any SL/TP inside that distance is rejected wholesale.

The detail that catches most people is which price the distance is measured from. For a buy, you enter at Ask but exit at Bid, so SL and TP validity is checked against Bid: the SL must sit at least the stop level below Bid and the TP at least the stop level above it. For a sell, mirror everything against Ask. Code that measures a buy's stop distance from Ask can pass on a tight-spread symbol and fail with 130 the moment the spread widens — which is why 130 so often appears 'randomly' around news.

Two related constraints hide behind the same error family. The freeze level (MODE_FREEZELEVEL) defines a band around the current price inside which existing orders' stops cannot be modified — relevant to trailing-stop code that inches the stop toward price. And some brokers enforce a stop level of 0 in the specification while still rejecting stops inside the current spread.

Everything in this guide is educational only, not financial advice. Defensive order code prevents rejected trades; it says nothing about whether the trades are worth taking, and trading carries a real risk of loss.

The error table: codes, causes, and MQL5 equivalents

The recurring OrderSend failures, their root causes, and the MQL5 trade-server retcodes that correspond to them:

| MQL4 code | Name | Root cause | MQL5 retcode | |---|---|---|---| | 129 | ERR_INVALID_PRICE | Price not normalized to Digits, or stale after a fast move | 10015 | | 130 | ERR_INVALID_STOPS | SL/TP inside stop level, wrong side, or unnormalized | 10016 | | 131 | ERR_INVALID_TRADE_VOLUME | Lot below MINLOT, above MAXLOT, or off the LOTSTEP grid | 10014 | | 133 | ERR_TRADE_DISABLED | Trading disabled for the account or symbol | 10017/10018 | | 134 | ERR_NOT_ENOUGH_MONEY | Insufficient free margin for the requested volume | 10019 | | 136 | ERR_OFF_QUOTES | No prices available at the requested level | 10021 | | 138 | ERR_REQUOTE | Price moved before the dealer processed the request | 10004 | | 146 | ERR_TRADE_CONTEXT_BUSY | Another EA/script occupies MT4's single trade thread | n/a (MT5 is multi-threaded) | | 4109 | ERR_TRADE_NOT_ALLOWED | AutoTrading off, or the EA's 'Allow live trading' box unchecked | 10027 (terminal), 10026 (server) | | 4110/4111 | longs/shorts not allowed | EA property restricts direction | — |

Three reading notes. First, the 129/130/131 cluster is your code's fault and is fully preventable with the normalization patterns below. Second, 136/138/146 are environmental — they demand retry logic, not fixes. Third, the 4xxx codes are client-terminal errors: the request never reached the broker, so no amount of price normalization helps; the fix is configuration (4109) or logic (4110/4111). Distinguishing the three families is the fastest route to a diagnosis.

Fixing 130: defensive stop placement

The cure for 130 is to compute the broker's minimum distance at send time, clamp your desired stops against it, measure from the correct side, and normalize everything to Digits. A complete MQL4 helper:

4
// Educational only — validate before trading; not financial advice.
bool BuyWithSafeStops(double lots, double slPoints, double tpPoints)
  {
   RefreshRates();
   double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;

   // Never place stops inside the broker's minimum distance.
   double slDist = MathMax(slPoints * Point, stopLevel);
   double tpDist = MathMax(tpPoints * Point, stopLevel);

   // Buy exits at Bid, so SL/TP are measured against Bid.
   double sl = NormalizeDouble(Bid - slDist, Digits);
   double tp = NormalizeDouble(Bid + tpDist, Digits);

   int ticket = OrderSend(Symbol(), OP_BUY, lots,
                          NormalizeDouble(Ask, Digits), 3,
                          sl, tp, "safe buy", 0, 0, clrNONE);
   if(ticket < 0)
      Print("OrderSend failed, error ", GetLastError());
   return(ticket >= 0);
  }

The load-bearing lines: RefreshRates() re-reads Bid/Ask so a stale price does not produce 129 or 130 after a fast move; MathMax(..., stopLevel) guarantees the distance is legal even if the caller asked for something tighter; the buy's stops are anchored to Bid; and every price passed to OrderSend() goes through NormalizeDouble(..., Digits), because a price like 1.234567891 on a 5-digit symbol is itself grounds for rejection.

For a sell, mirror against Ask: sl = NormalizeDouble(Ask + slDist, Digits) and tp = NormalizeDouble(Ask - tpDist, Digits). Inverted-mirror bugs in the short-side arithmetic are among the most common defects found when EAs are audited — the long side gets tested, the short side gets assumed.

An alternative that sidesteps 130 entirely on ECN-style accounts (some of which reject any SL/TP attached at open): send the order naked, then set stops with OrderModify() — still respecting stop level and freeze level.

Fixing 131 and 134: lot normalization and margin checks

Error 131 (ERR_INVALID_TRADE_VOLUME) fires when the requested lot size is not something the broker accepts: below the minimum, above the maximum, or not a multiple of the lot step. It is endemic in EAs that compute position size from risk — a calculation like risk / (slPoints * tickValue) produces values like 0.0837, and no broker trades that. Snap the result onto the legal grid before sending:

4
// Educational only — validate before trading; not financial advice.
double NormalizeLots(double lots)
  {
   double step = MarketInfo(Symbol(), MODE_LOTSTEP);
   double minL = MarketInfo(Symbol(), MODE_MINLOT);
   double maxL = MarketInfo(Symbol(), MODE_MAXLOT);
   lots = MathFloor(lots / step) * step;   // snap DOWN to the step grid
   return(NormalizeDouble(MathMax(minL, MathMin(maxL, lots)), 2));
  }

Rounding down (MathFloor) matters: rounding to nearest can round a risk-based size up, quietly taking more risk than the input asked for. One honest caveat — clamping up to minL also increases risk beyond what was requested; if the computed size is below the minimum lot, the more defensible behaviour for risk-sized code is to skip the trade rather than inflate it.

Error 134 (ERR_NOT_ENOUGH_MONEY) means the account's free margin cannot support the volume. Check before sending rather than harvesting the rejection:

4
// Educational only — validate before trading; not financial advice.
bool MarginOk(double lots)
  {
   double freeAfter = AccountFreeMarginCheck(Symbol(), OP_BUY, lots);
   return(freeAfter > 0 && GetLastError() != 134);
  }

AccountFreeMarginCheck() returns what free margin would remain after the trade; a non-positive result (or error 134) means the send would fail. In MQL5 the equivalent is OrderCalcMargin() compared against AccountInfoDouble(ACCOUNT_MARGIN_FREE). Recurring 134s in a backtest are also a signal worth hearing: the sizing logic is writing cheques the account cannot cash, which is a risk-model bug, not a broker inconvenience.

Fixing 4109, handling requotes, and a robust send wrapper

Error 4109 (ERR_TRADE_NOT_ALLOWED) is pure configuration: the terminal's AutoTrading button is off, or the EA's own 'Allow live trading' box (Common tab of its properties) is unchecked. The request never leaves the terminal. Detect it explicitly so users get an actionable message instead of a silent failure:

4
// Educational only — validate before trading; not financial advice.
if(!IsTradeAllowed())
  {
   Print("Trading disabled: enable AutoTrading and the EA's 'Allow live trading' option.");
   return;
  }

The MQL5 equivalents are retcode 10027 (AutoTrading disabled in the terminal) and 10026 (disabled server-side), plus TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) and MQLInfoInteger(MQL_TRADE_ALLOWED) for pre-flight checks. Related MQL4 test-time codes 4110/4111 mean the EA's properties forbid longs or shorts respectively.

The environmental errors — 138 requotes, 136 off-quotes, 146 trade-context-busy — deserve a bounded retry loop rather than a fix. The shape that works: attempt the send; on 146, wait briefly (Sleep(100)) for the trade thread; on 136/138, call RefreshRates() and rebuild the request from fresh prices; retry at most three or four times with short pauses; log GetLastError() on every failure and give up loudly rather than looping forever. Unbounded retry loops are how EAs machine-gun a dealer during a news spike.

Two final disciplines. Log every rejection with the error code, requested prices, and current Bid/Ask — 130-class bugs are trivial to diagnose with that context and nearly impossible without it. And test the failure paths deliberately: the strategy tester never requotes you, so code that has only ever run in the tester has never executed its own error handling. Educational only, not financial advice — robust order plumbing prevents rejected and mangled orders, it does not make the underlying strategy profitable, and trading carries a real risk of loss.

Key takeaways

Educational only — not financial advice. Trading involves substantial risk of loss.

Catch the bug that compiles.Run auditGet Pro