What it means
The price in the request isn't one the server accepts for that order. With pending orders it almost always means the order is on the wrong side of the market, or too close to it.
Usual causes
- A pending order on the wrong side. A buy limit must be below the Ask and a buy stop above it; a sell limit must be above the Bid and a sell stop below it. A buy limit placed at or above the Ask is refused.
- Too close to the market. A pending order closer to the current price than the broker allows. Keep it beyond the symbol's
SYMBOL_TRADE_STOPS_LEVEL. - An unrounded price. A price with more decimals than the symbol's digits, or off the tick size. Round it before sending.
- The market moved past it. The price was valid when computed, but the market crossed it before the request arrived.
How to detect it
result.retcode(ortrade.ResultRetcode()) is10015; the Experts tab shows the order, its price and[invalid price].- Log the Bid, the Ask and the order price together: the wrong side is visible at a glance.
Broken code
This script compiles. The buy limit is above the market, where only a buy stop can go, so the server returns 10015.
#include <Trade/Trade.mqh>
input int InpOffsetPoints = 50; // Distance of the limit order, points
CTrade trade;
void OnStart()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Sign error: a buy limit ABOVE the Ask
double price = ask + InpOffsetPoints * _Point;
trade.BuyLimit(0.10, price);
}Fixed code
The same program with the check that prevents the error. It compiles in MetaEditor with 0 errors and 0 warnings.
#include <Trade/Trade.mqh>
input int InpOffsetPoints = 50; // Distance of the limit order, points
CTrade trade;
// Rounds a price to the symbol's tick size
double RoundToTick(const double price)
{
double tick = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
if(tick <= 0.0)
return NormalizeDouble(price, _Digits);
return NormalizeDouble(MathRound(price / tick) * tick, _Digits);
}
void OnStart()
{
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick))
return;
// A buy limit waits BELOW the Ask, at least the stops level away
double minDist = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
double price = RoundToTick(tick.ask - InpOffsetPoints * _Point);
if(tick.ask - price < minDist)
{
PrintFormat("Skipped: a buy limit must be at least %d points below the Ask", (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL));
return;
}
if(!trade.BuyLimit(0.10, price))
PrintFormat("BuyLimit failed: retcode %u (%s)", trade.ResultRetcode(), trade.ResultRetcodeDescription());
}Why the fix works
The buy limit now sits below the Ask, rounded to the tick size, and the script checks the broker's minimum distance before sending. To buy above the current price, the order type to use is a buy stop, not a buy limit.
Where each pending order goes
| Order | Placed | Measured from |
|---|---|---|
| Buy limit | Below the market | Ask |
| Buy stop | Above the market | Ask |
| Sell limit | Above the market | Bid |
| Sell stop | Below the market | Bid |
Stop-loss and take-profit levels of a pending order are measured from the order's own price; when they're too close, the code is 10016, invalid stops.
Questions
Why is my buy limit rejected with invalid price?
Most often because it's at or above the Ask: a buy limit must wait below the current price. If it's below but very close, it can still be refused; keep it beyond SYMBOL_TRADE_STOPS_LEVEL and round it to the tick size.
What's the difference between 10015 and 10016?
10015 is about the order's price itself. 10016 is about its stop-loss or take-profit levels.
Is MT5 error 10015 the same as MT4 error 129?
Yes. MQL4's error 129 (ERR_INVALID_PRICE) is trade server return code 10015 in MQL5.
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.