Blog / Fix MT5 errors · Trade errors · MQL5 · MQL4
Requotes, Off Quotes and Invalid Price: Handling Trade Server Errors
Understand MT5 requotes, off quotes and invalid price errors, their causes, and practical MQL5 solutions for more reliable EA execution.
· 7 min read
Your Expert Advisor identifies a trading opportunity and submits an order, but the trade server rejects it because the requested price has changed, no usable quote is available, or the submitted price is invalid.
These problems commonly appear as requotes, off quotes, or invalid price errors.
They require different solutions. Refreshing a quote may help with a temporary price change, but it will not correct an invalid price calculation. Repeatedly submitting the same request can also create unnecessary delays or duplicate exposure.
In MT5, you can identify the underlying problem through trade server return codes and handle it with fresh market data, valid price calculations, and controlled retries.
1. Understand the Three Execution Problems
Although these errors involve price or execution, they do not mean the same thing.
Requotes (10004)
A requote occurs when the requested price is no longer available and the broker returns a new price instead.
For example, your EA attempts to buy EURUSD at 1.08500, but the market moves before the request is processed. Under an execution model that supports requoting, the broker may return a different available price.
The MT5 return code is:
TRADE_RETCODE_REQUOTE // 10004What to do: Retrieve the latest quote, check whether the trading signal is still valid, and submit another request only if the strategy still permits entry.
Off quotes (10021)
Off quotes means the trade server has no usable quote with which to process the request.
Possible causes include:
- A temporary interruption in price updates.
- Low liquidity or unavailable market prices.
- A market session or quoting interruption.
- A problem with the broker's price feed or connection.
The MT5 return code is:
TRADE_RETCODE_PRICE_OFF // 10021What to do: Check whether a valid tick is available. If not, wait for a usable quote instead of repeatedly submitting the same order.
Invalid price (10015)
An invalid price error means the price supplied in the trade request is unacceptable.
Common causes include:
- Using an outdated price.
- Calculating a price incorrectly.
- Supplying a price that does not align with the instrument's tick size.
- Using a price that does not satisfy the requirements of the order type or execution mode.
The MT5 return code is:
TRADE_RETCODE_INVALID_PRICE // 10015What to do: Inspect the price calculation and request parameters. Refreshing the quote alone will not fix an incorrectly calculated or formatted price.
2. Identify the Exact MT5 Return Code
Before changing your EA's execution logic, identify the response returned by the trade server.
These are the main price-related codes:
| Return code | MQL5 constant | Meaning |
|---|---|---|
| 10004 | TRADE_RETCODE_REQUOTE |
Requote |
| 10015 | TRADE_RETCODE_INVALID_PRICE |
Invalid requested price |
| 10020 | TRADE_RETCODE_PRICE_CHANGED |
Price changed |
| 10021 | TRADE_RETCODE_PRICE_OFF |
No usable quote available |
When using the MQL5 CTrade class, retrieve the server response with ResultRetcode() and ResultRetcodeDescription().
uint retcode = trade.ResultRetcode();
Print("Trade server response: ", retcode);
Print("Description: ",
trade.ResultRetcodeDescription());Do not rely exclusively on GetLastError() to diagnose these trade rejections. The terminal's last-error value and the trade server's return code provide different information.
3. Fix Invalid Prices by Retrieving Fresh Quotes
A common EA mistake is calculating an entry price and using it later without checking whether the market has moved.
Use SymbolInfoTick() to retrieve the latest available market data before preparing a trade request.
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick))
{
Print("Unable to retrieve market prices. Error: ",
GetLastError());
return;
}
if(tick.bid <= 0 || tick.ask <= 0)
{
Print("Invalid Bid or Ask quote.");
return;
}
double current_bid = tick.bid;
double current_ask = tick.ask;
Print("Current Bid: ", current_bid);
Print("Current Ask: ", current_ask);For a market Buy, the Ask is generally the relevant entry-side quote. For a market Sell, it is the Bid.
The exact price requirements still depend on the order type and execution mode. For example, pending orders require an explicitly calculated entry price, while a market order submitted through CTrade::Buy() with a price of 0.0 uses the current market Ask.
Check the instrument's tick size
Correct decimal precision does not necessarily mean that a price is valid.
For example, an instrument may allow price changes only in increments of 0.25. A calculated price of 100.13 has two decimal places, but it does not align with that tick size.
Retrieve the permitted increment with SYMBOL_TRADE_TICK_SIZE:
double tick_size = 0.0;
if(!SymbolInfoDouble(_Symbol,
SYMBOL_TRADE_TICK_SIZE,
tick_size) ||
tick_size <= 0)
{
Print("Unable to retrieve a valid tick size.");
return;
}
Print("Symbol tick size: ", tick_size);When calculating pending-order prices or stop levels, align the price with the permitted tick increment and then apply the symbol's required decimal precision.
Do not assume that NormalizeDouble() alone guarantees tick-size alignment. The appropriate rounding direction also depends on whether the price is an entry, stop-loss, or take-profit level.
4. Handle Requotes and Price Changes Safely
A requote or price-changed response does not automatically mean that the EA's trading strategy is incorrect. The market may simply have moved between price calculation and order processing.
Set an acceptable price deviation
The MQL5 CTrade class provides SetDeviationInPoints() to configure the allowed price deviation for applicable execution modes.
#include <Trade/Trade.mqh>
CTrade trade;
int OnInit()
{
trade.SetDeviationInPoints(20);
return INIT_SUCCEEDED;
}The value is expressed in points, not pips.
This setting does not guarantee execution at a particular price. Its effect depends on the symbol's execution mode and the broker's execution rules. In particular, do not assume it provides the same price protection under Market Execution as it does under other execution modes.
Use controlled retries
If a request fails because of a temporary price change or unavailable quote, the EA can retrieve fresh market data and consider another attempt.
The retry should be limited to specific temporary responses. Invalid prices, invalid volume, insufficient margin, and other request errors require separate corrections.
The following example demonstrates a bounded retry for a market Buy:
#include <Trade/Trade.mqh>
CTrade trade;
bool OpenBuyWithRetry(const double volume,
const string symbol,
const int max_attempts = 3)
{
if(volume <= 0 || max_attempts < 1)
return false;
trade.SetDeviationInPoints(20);
for(int attempt = 1;
attempt <= max_attempts;
attempt++)
{
MqlTick tick;
if(!SymbolInfoTick(symbol, tick) ||
tick.bid <= 0 ||
tick.ask <= 0)
{
Print("No valid market quote available.");
return false;
}
bool sent = trade.Buy(
volume,
symbol,
0.0,
0.0,
0.0,
"EA Buy"
);
uint retcode = trade.ResultRetcode();
if(sent && retcode == TRADE_RETCODE_DONE)
{
Print("Buy executed. Deal: ",
trade.ResultDeal());
return true;
}
if(sent && retcode == TRADE_RETCODE_DONE_PARTIAL)
{
Print("Buy partially executed. Filled volume: ",
trade.ResultVolume());
return true;
}
if(sent && retcode == TRADE_RETCODE_PLACED)
{
Print("Order placed. Verify its execution status.");
return true;
}
Print("Attempt ", attempt,
" failed. Retcode: ", retcode,
" - ", trade.ResultRetcodeDescription());
if(retcode != TRADE_RETCODE_REQUOTE &&
retcode != TRADE_RETCODE_PRICE_CHANGED &&
retcode != TRADE_RETCODE_PRICE_OFF)
{
return false;
}
if(attempt < max_attempts)
Sleep(250);
}
Print("Maximum retry attempts reached.");
return false;
}The example:
- Checks that the requested volume and retry limit are valid.
- Retrieves a current tick before each attempt.
- Submits a market Buy using the current market price.
- Checks the server's return code.
- Retries only after a requote, price change, or unavailable quote.
- Stops after the configured number of attempts.
A full execution, partial execution, and placed order are not identical outcomes. The example returns after each accepted outcome to prevent another Buy from being submitted unnecessarily. Your EA should still track the resulting deal, order, or position and handle any unfilled volume according to its strategy.
Production note: Sleep() is included to keep the example simple. Avoid blocking OnTick() with delays in a production EA. A timer or event-driven retry mechanism is generally more suitable. Also, an EA should recheck its entry conditions before retrying; a previously valid trading signal may no longer be valid after the delay.
5. How MQL4 Handles These Errors
MT4 uses different error identifiers for similar execution problems.
| MQL4 error | Constant | Meaning |
|---|---|---|
| 129 | ERR_INVALID_PRICE |
Invalid price |
| 135 | ERR_PRICE_CHANGED |
Price changed |
| 136 | ERR_OFF_QUOTES |
No quotes available |
| 138 | ERR_REQUOTE |
Requote |
Retrieve the error after a failed OrderSend() call with GetLastError():
int ticket = OrderSend(
Symbol(),
OP_BUY,
0.01,
Ask,
3,
0,
0,
"EA Buy",
10001,
0,
clrBlue
);
if(ticket < 0)
{
int error = GetLastError();
Print("OrderSend failed. Error: ", error);
}Before another attempt, refresh the available price data:
RefreshRates();
double current_ask = Ask;
double current_bid = Bid;Refreshing rates does not guarantee that the next request will succeed. Validate the new price and check the returned error before retrying.
When porting an EA from MT4 to MT5, remember that MQL4 error numbers and MT5 trade server return codes are different. They should not be treated as interchangeable.
6. When Should an EA Retry a Failed Trade?
Not every rejected request should trigger another order submission.
Use the returned code to decide what needs to happen:
| Server response | Appropriate action |
|---|---|
| Requote (10004) | Retrieve the new quote and retry only if the signal remains valid. |
| Price changed (10020) | Refresh the quote and recalculate the request if necessary. |
| Off quotes (10021) | Wait for a usable quote before considering another attempt. |
| Invalid price (10015) | Correct the price calculation, tick alignment, or request parameters. |
There is also an important risk when a request's outcome is uncertain. Before resubmitting, check the account's orders, deals, and positions to determine whether the original request was executed or partially executed.
Otherwise, the EA may submit another order and create duplicate exposure.
The objective is not to force every trade through. It is to identify why the request failed and respond without violating the strategy's entry conditions or risk limits.
Conclusion
MT5 requotes, off quotes, and invalid price errors describe different execution problems.
- Requote (10004): The requested price is no longer available under an execution model that supports requoting.
- Off quotes (10021): No usable quote is available to process the request.
- Invalid price (10015): The submitted price or request parameters are unacceptable.
To handle them correctly, retrieve fresh ticks, validate prices against the instrument's tick size, inspect the trade server's return code, and retry only when the failure is temporary and the original trading conditions remain valid.
If your EA keeps running into execution errors and you can't find the cause in its order-submission logic, try PositionAlpha's Fix an EA: you paste or upload the EA and describe the problem. The AI returns the complete updated .mq4 or .mq5 file and explains the problems it found and each change it made. Compile the result in MetaEditor and test it in the Strategy Tester and on a demo account before you rely on it.
Build a bot from your idea
Describe your trading idea and the AI writes MT4 or MT5 code for you to review and test, with a plain-English explanation and setup steps. Your first bot is free.