Field guide for brokers & developers
Troubleshooting trading platforms: a field guide for brokers and developers
Rejected orders, dropped FIX sessions, price spikes, laggy terminals, balances that don't match. How to find out which part of the chain failed — and what usually fixes it.
How to debug a trading platform
Every trade crosses the same chain: client app → gateway or API → trading server → bridge → liquidity provider, and back. Most incidents are one broken link in that chain, so the fastest diagnosis follows a single order through every hop.
- Pick one failing order and collect its identifiers at every hop: terminal request ID, platform order and deal tickets, bridge order ID, and the FIX ClOrdID (11).
- Line up timestamps in UTC. Platform journals, bridge logs, and FIX logs often use different time zones — misaligned clocks send you to the wrong hop.
- Find the first hop where the order looks wrong. A rejection code, a missing message, or a gap longer than your normal latency marks the failing link.
- Reproduce it on staging with the same group, symbol, volume, and filling mode before changing anything in production.
- Fix it with a test or a monitor, so the same failure is caught automatically next time.
MT5 trade return codes and what usually causes them
When MetaTrader 5 refuses a trade request it answers with a numeric return code. The names below are MetaQuotes' own; the causes are what we most often find behind them on broker servers.
| Code | Constant | Meaning | Usual cause and fix |
|---|---|---|---|
| 10004 | TRADE_ | Requote | Price moved beyond the allowed deviation before execution. Review the group's deviation settings and the symbol's execution mode. |
| 10006 | TRADE_ | Request rejected | Refused by the dealer, a server plugin, or the bridge. The reason is in the plugin or bridge log, not the terminal. |
| 10012 | TRADE_ | Request canceled by timeout | No answer from the execution side in time — often a slow or disconnected bridge or liquidity provider session. |
| 10013 | TRADE_ | Invalid request | Malformed request from an app or EA. Validate every field against the symbol specification before sending. |
| 10014 | TRADE_ | Invalid volume in the request | Volume outside the symbol's minimum, maximum, or step. Round to the volume step before sending. |
| 10015 | TRADE_ | Invalid price in the request | Stale or wrong-side price for the order type — common when an app sends a cached quote. |
| 10016 | TRADE_ | Invalid stops in the request | Stop-loss or take-profit inside the symbol's stops level. Respect the stops and freeze levels. |
| 10018 | TRADE_ | Market is closed | Outside the symbol's trading session — check session settings, holidays, and server time zone. |
| 10019 | TRADE_ | There is not enough money to complete the request | Insufficient free margin — or margin settings for the group that differ from what the client sees. |
| 10021 | TRADE_ | There are no quotes to process the request | The symbol has no live quotes: a stale feed, a broken symbol mapping, or a feed that failed over incompletely. |
| 10024 | TRADE_ | Too frequent requests | An app or EA flooding the server. Throttle requests on the client and apply limits in the gateway. |
| 10027 | TRADE_ | Autotrading disabled by client terminal | An expert advisor tried to trade with algo trading switched off in the client terminal. |
| 10030 | TRADE_ | Invalid order filling type | The request's filling policy (FOK, IOC, or Return) is not allowed for the symbol. Read the symbol's allowed filling modes and send one of them. |
| 10031 | TRADE_ | No connection with the trade server | The terminal or gateway lost its connection — check network paths, access-server load, and reconnect logic. |
FIX session failures with liquidity providers
Bridges talk to liquidity providers over FIX, usually FIX 4.4. When a session misbehaves, the FIX messages themselves say why — as long as they are logged in full.
| Symptom | What to look for | Usual fix |
|---|---|---|
| Logon refused | A Logout (35=5) in reply to Logon (35=A), often with a reason in Text (58) | Check SenderCompID (49), TargetCompID (56), credentials, and whether your IP is allow-listed by the provider. |
| Disconnects every few minutes | Missed Heartbeats (35=0) or an unanswered TestRequest (35=1) | Match HeartBtInt (108) with the provider and make sure a busy thread never delays heartbeat replies. |
| "MsgSeqNum too low" or a resend storm | Sequence numbers (34) out of step after a restart; ResendRequest (35=2) | Persist sequence numbers across restarts; answer resend requests with SequenceReset-GapFill (35=4) for admin messages. |
| Orders rejected by the provider | ExecutionReport (35=8) with OrdStatus (39) = 8 (Rejected) | Read OrdRejReason (103) and Text (58): symbol mapping, volume limits, and credit limits are the common causes. |
| Messages rejected at session level | Reject (35=3) with RefTagID (371) and SessionRejectReason (373) | A malformed or unexpected field. Compare your message with the provider's FIX specification, tag by tag. |
| Messages refused as unsupported | BusinessMessageReject (35=j) | The provider doesn't support that message type — check which order types and messages the spec allows. |
Sources: FIX Trading Community
Price spikes and stale quotes
A spike that reaches a client's chart can trigger stop-outs and complaints within seconds. The causes are almost always upstream of the platform:
- One provider sends an off-market quote and the aggregator passes it through unfiltered.
- Symbol mapping is wrong — digits, contract size, or quote currency differ between the provider and the platform symbol.
- Failover is slow or partial, so a symbol keeps its last price long after the feed died.
What fixes it: filter each tick against the median of your other providers, reject ticks that jump more than a set multiple of the normal spread, give every symbol a stale-quote timeout, and store raw ticks so any disputed price can be replayed. Our liquidity bridge work builds these filters in.
Terminal lag and WebSocket disconnects
Web and mobile terminals usually slow down during news, exactly when clients are watching. The causes are well known:
- Rendering every tick. Coalesce updates and repaint at most once per animation frame.
- Unbounded queues. Without backpressure, a slow client builds a backlog and falls further behind; drop superseded quotes instead of queuing them.
- Idle connections closed by proxies. Send WebSocket ping/pong keep-alives shorter than the shortest proxy timeout.
- Reconnect storms. After an outage every client reconnects at once — use exponential backoff with jitter.
- Gaps after reconnect. Resync with a snapshot of positions and quotes, then resume deltas, so the terminal never shows stale state.
We build these into every custom trading terminal and trading app.
MT5 Manager API connection drops
CRMs, risk dashboards, and reporting jobs connect to MetaTrader 5 through the Manager API. When they lose data, it is usually one of these:
- Short-lived connections. Run the manager connection as one long-lived service that reconnects with backoff, not a new connection per request.
- Polling instead of pumping. Use the API's pumping mode for real-time updates rather than repeatedly requesting full data.
- Outdated libraries. Keep Manager API libraries current with your server build. MetaQuotes retires old versions — since July 2025, terminals older than MT5 build 4755 can no longer connect to broker servers.
- Access restrictions. Manager accounts are often limited by IP address and permissions; a new server or a missing right looks like a connection failure.
More in our MT5 plugin and Manager API service.
When balances don't match between CRM and platform
A deposit counted twice or a missing commission turns into a client complaint or an audit finding. The usual causes:
- Retries without idempotency. A timed-out deposit call is retried and applied twice. Give every balance operation an external ID and refuse duplicates.
- Different day cut-offs. CRM, payment provider, and platform close the day in different time zones.
- Swaps, commissions, and adjustments booked in one system only — for example, manual corrections made directly on the trading server.
A daily automated reconciliation between platform, CRM, and payment providers — with a ledger behind the CRM — catches differences the same day. It is part of every forex CRM we build.
What to collect before you escalate
- Exact time of the problem In UTC, with the server time zone noted.
- Identifiers Order and deal tickets, bridge order IDs, FIX ClOrdID (11).
- Scope Client group, symbol, volume, order type, and filling mode.
- Evidence Platform journal lines, plugin and bridge logs, raw FIX messages.
- What changed Recent server builds, plugin releases, group or symbol settings.
Stuck on a live issue? Our trading platform debugging service starts with exactly this evidence.
FAQ
What does MT5 error 10030 (invalid order filling type) mean?
MetaTrader 5 return code 10030, TRADE_RETCODE_INVALID_FILL, means the order's filling policy — Fill or Kill, Immediate or Cancel, or Return — is not allowed for that symbol. The fix is to read the symbol's allowed filling modes and send one of them; brokers can also review which filling modes the symbol and its execution mode permit.
Why does MT5 reject orders with return code 10006?
Return code 10006, TRADE_RETCODE_REJECT, means the request was rejected on the execution side — by the dealer, a server plugin, or the liquidity bridge. The terminal only shows the code; the actual reason is in the plugin or bridge logs, so start there with the order's ticket and timestamp.
How do you fix FIX sequence number errors with a liquidity provider?
Sequence number errors happen when MsgSeqNum (tag 34) gets out of step, usually after one side restarts without persisting its counters. Persist sequence numbers across restarts, answer ResendRequest (35=2) messages correctly, use SequenceReset-GapFill (35=4) for administrative messages, and agree a reset procedure with the provider for daily session starts.
Why does a web trading terminal lag during news?
Usually because it tries to render every price tick and queues updates without limit. Coalescing ticks to one repaint per animation frame, dropping superseded quotes instead of queuing them, and resyncing from a snapshot after reconnects keep a terminal responsive during high-volatility news.