# 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.

Published 2026-10-16 by fxapis. Canonical: https://fxapis.com/blog/why-mt5-trades-fail

## 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.

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:

```json
{
  "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](https://docs.fxapis.com/trading#the-three-failures) — rejected, never sent, and unknown, in full.
- [Every error code](https://docs.fxapis.com/errors), with whether to retry.
- [Instruments and symbols](https://docs.fxapis.com/instruments) — one name for each market, at every broker.
- [The MT5 API](https://fxapis.com/mt5-api) — accounts, orders and history, with a recorded result for every trade.

## Questions

### What does MT5 error 10019 mean?

10019 is TRADE_RETCODE_NO_MONEY: there is not enough free margin on the account to open the order. Reduce the volume or check the margin first; retrying the same order collects the same rejection.

### What does MT5 error 10014 invalid volume mean?

The volume breaks the symbol's rules at that broker: below its minimum, above its maximum, or not a multiple of its volume step. Each broker sets these per symbol.

### What does MT5 error 10016 invalid stops mean?

The stop loss or take profit is on the wrong side of the price, or closer to it than the broker allows.

### Should I retry a rejected MT5 order?

Only when the rejection is transient, such as a requote or a moved price; fxapis marks those retryable. Send it as a new order with a new idempotency key, after looking at the new price. Other rejections will repeat until you change the order.
