# QFEX — weighted limits and backoff

This file separates documented exchange budgets from configurable client pacing and explains how uncorrelated throttling affects placement outcomes. Official rate-limit documentation was checked on 2026-10-03; live `RateLimited` behavior remains unverified.

## TL;DR

1. The documented ceiling is 12,000 weight units per 60 seconds per user, shared across connections and API keys.
2. General and cancel traffic have separate EMA buckets.
3. A local fuse, pacing rate, burst allowance, and jitter are caller settings.
4. Read messages consume weight too.
5. An uncorrelated throttle error cannot identify which placement was refused.

## 1. Documented budget and weights

The server models weighted traffic as an exponential moving average, rather than a simple count resetting each minute. More sockets or keys do not add budget. The documented general ceiling corresponds to 200 weight units per second sustained; short bursts are subject to the EMA.

| Message | Weight |
|---|---:|
| `add_order`, `cancel_order`, `modify_order` | 1 |
| `get_order`, `cancel_all_orders` | 2 |
| `get_user_orders` | 5 |
| `get_user_trades` | 0.5 |
| `subscribe`, `unsubscribe` | 0.1 |
| Leverage get/levels/set | 0.1 |
| `cancel_stop_order`, `modify_stop_order` | 1 |
| `cancel_on_disconnect` | 0.1 |

Cancel-related traffic has its own bucket. Exact membership and the cancel bucket's separate capacity are not fully stated. A local classifier is an implementation inference, not a demonstrated server partition.

## 2. Throttle outcomes and correlation

Documentation shows a flat `Err` response with `RateLimited`, retry-after text, and an empty `incoming_message`. Without a usable echo it cannot be tied to a request. A placement slot that permits only one unacknowledged `add_order` reduces ambiguity; this is a client design choice.

An echoed throttle on an order proves that attempt was refused before processing only when no acknowledgement or fill evidence conflicts with it. If the server gives no correlation and several requests could be affected, classify the affected placements as unknown and resolve them. Do not silently resend them.

Parse retry hints with seconds or milliseconds; handle invalid or missing hints through caller-selected bounded backoff. Backoff jitter and an EMA fuse below the exchange ceiling are explicit workload policies, not protocol constants.

## 3. REST pacing

The rate page expressly separates HTTP and handshake controls from authenticated WebSocket message limits. No numeric REST ceiling is established here. The REST client requires an explicit pacing choice and treats 429 as a shared pause within the client. Honor `Retry-After`, which may be seconds or an HTTP date.

Do not turn a local no-send result into an exchange rejection. Useful outcome classes are locally blocked/rate-limited, rejected with exchange evidence, accepted, and unknown after a send. Each supports a different next action.

## 4. Restart and shared clients

A process restart does not prove the venue's EMA reset. Budget state must account for other connections using the same user. Prefer fewer complete reads and event-driven updates to repeated expensive order queries. Pacing choices should be based on the actual application, not embedded as universal package defaults.

## Pitfalls

| What breaks | Why | Correct approach |
|---|---|---|
| Extra sockets unexpectedly throttle | User-level shared budget | Account for all connections |
| An unknown write is retried | Empty throttle echo | Resolve the original intent first |
| Reads exhaust the budget | `get_user_orders` costs 5 | Include reads in accounting |
| Cancel capacity is assumed unlimited | Separate does not mean unlimited | Back off the affected bucket |
| REST pacing uses the WS ceiling | Different controls | Configure REST independently |

## Open questions / not verified

- Live throttle envelope, retry units, cancellation-bucket size, and subaccount sharing behavior.
- HTTP and initial-handshake limits.
- The exact server EMA time constant and burst acceptance.

## Sources

[API rate limits](https://docs.qfex.com/websocket/rate) and [Errors](https://docs.qfex.com/websocket/errors) (checked 2026-10-03). Bucket classifiers, placement serialization, and local fuses are toolkit mechanisms; they are not claimed as measured server behavior.

<!-- license-footer -->
_© markpaper authors. Licensed under [CC BY 4.0](LICENSE.md): when publishing or adapting this material, credit “markpaper — QFEX knowledge base” and link to the original and the license._
