Why an MT5 Trade Can Fail Even When Your API Request Is Correct
Market closed, invalid volume, invalid stops, no margin, wrong symbol: five reasons a broker refuses a valid MT5 order, and how to read and prevent each.
In short
- A well-formed request can still be refused by the broker, because the broker applies its own rules to every order.
- The five common causes: the market is closed, the volume breaks the symbol's rules, the stops are invalid, there is not enough margin, or the symbol is named differently at this broker.
- Read the result, not just the status. fxapis returns ORDER_REJECTED with the broker's reason, its MT5 return code, and whether retrying can help.
- Most rejections can be prevented by checking market hours, the symbol's volume rules and the margin before you send.
On this page
Your request is valid JSON, your key is right, the account is online — and the order is still refused. The API accepted your request; the broker declined the trade. Brokers check every order against their own rules, and those rules can say no to a request that is perfectly formed.
Reading the result first
With fxapis, a broker refusal comes back as 422 ORDER_REJECTED, with the reason and a retryable flag:
{
"error": {
"code": "ORDER_REJECTED",
"message": "The broker rejected the order: No money",
"details": [{ "orderId": "…", "state": "rejected", "retryable": false }]
}
}
GET /v1/orders/{id} shows the broker's own MT5 return code — 10019 here — exactly as the broker sent it. Nothing executed. The fix depends on the cause.
The five common causes
1. The market is closed
Return code 10018. Forex closes at the weekend, gold takes a daily break, indices follow their exchange's hours — and each broker sets its own hours for each symbol.
Prevent it: check the account's market hours before sending. GET /v1/accounts/{id}/sessions?instrument=XAUUSD returns openNow and nextOpen, read from that broker.
2. The volume breaks the symbol's rules
Return code 10014. Each symbol has a minimum volume, a maximum, and a step. 0.015 lots is invalid where the step is 0.01; 0.01 is invalid where the minimum is 0.1.
Prevent it: read the rules from the account's broker — GET /v1/accounts/{id}/symbols?search=EURUSD returns volumeMin, volumeStep and volumeMax — and round sizes to the step before sending. Send volumes as strings, "0.10", so nothing is rounded on the way.
3. The stops are invalid
Return code 10016. A buy's stop loss must be below the price and its take profit above it (a sell's, the reverse), and brokers often require a minimum distance from the price.
Prevent it: stops are absolute prices, not distances in pips — compute them from the current price, and keep them outside the broker's minimum distance. fxapis refuses a stop on the obviously wrong side before anything is sent.
4. Not enough margin
Return code 10019. The account cannot fund the position at its leverage — common when one signal is sized the same on accounts with very different balances.
Prevent it: POST /v1/accounts/{id}/calculate with "kind": "margin" returns the margin an order needs without opening anything. On multi-account orders, size each account to its balance with weights.
5. The symbol is named differently
Gold is XAUUSD at one broker, XAUUSD.a or GOLD at another. Sending another broker's name fails before it can trade.
Prevent it: send instrument instead of symbol — "instrument": "XAUUSD" — and fxapis trades each account's own symbol for it. If a broker has no match, or two plausible ones, the order is refused before anything is sent, with INSTRUMENT_NOT_OFFERED or INSTRUMENT_AMBIGUOUS.
The cheat sheet
| Cause | MT5 code | Retry as is? | Prevent it with |
|---|---|---|---|
| Market closed | 10018 | No | GET …/sessions |
| Invalid volume | 10014 | No | GET …/symbols volume rules |
| Invalid stops | 10016 | No | Stops from the current price |
| Not enough money | 10019 | No | POST …/calculate |
| Symbol mismatch | — | No | instrument instead of symbol |
| Requote, price moved, no quotes | 10004, 10020, 10021 | As a new order | Check the new price first |
Not every failure is a rejection
Two other failures look similar and mean something else:
SEND_FAILED(503) — the order provably never reached the broker. Safe to resend, with the same idempotency key.ORDER_UNRESOLVED(503) — nobody knows yet whether it executed. Do not resend. Poll the order; fxapis confirms it against the broker's records.
Next steps
- The three failures — rejected, never sent, and unknown, in full.
- Every error code, with whether to retry.
- Instruments and symbols — one name for each market, at every broker.
- The MT5 API — accounts, orders and history, with a recorded result for every trade.