Skip to main content
A production market maker on OCX is defined less by its pricing and more by how it behaves when things go wrong — a lost feed, a disconnect, a runaway inventory. This page collects the operational patterns that keep a quoting bot safe.

Inventory and risk

Every fill moves your inventory. Read it from the fill stream (futures) and your positions (options), and let it drive your next ladder.
As you accumulate a long position, lower both sides of your ladder slightly so you are more likely to sell and less likely to buy more (and vice versa when short). This mean-reverts inventory toward flat without crossing the spread.
Reduce quoted quantity — or widen — as your position approaches your own risk limit, so you stop adding to a one-sided book.
Tag exit-only orders reduceOnly so they can only shrink a position. On futures, POST {API_BASE}/fut/positions/close flattens a position fully or partially.
OCX enforces portfolio margin server-side: every order passes a margin check before acceptance, and a rejected order returns INSUFFICIENT_MARGIN — handle it, don’t retry blindly. Watch NLV and margin in GET {API_BASE}/portfolio/balances and de-risk proactively. Accounts whose requirement exceeds their NLV are reduced by the exchange, and accounts at the liquidation floor are liquidated — see Margin & liquidations.
A margin rejection is a business answer, not a transport failure. Distinguish it from network and 5xx errors in your client — a margin reject is a signal to de-risk, not to reconnect.

Kill switch

Pull all your orders the moment your bot can no longer be sure they reflect a live price — feed loss, an unhandled error, or shutdown. Futures and options orders are cancelled separately, so call both:
1

Detect the trigger

Your reference feed goes stale, the fill stream stops heartbeating, a place or replace call errors repeatedly, or you receive SIGTERM.
2

Cancel everything immediately

Fire both cancel-alls before doing anything else, so no stale order can be hit while you are blind.
3

Stand down until healthy

Do not re-quote until your feed is fresh and your streams are reconnected and re-snapshotted.
Never leave resting orders behind a dead price feed. If your fair value goes stale and you keep quoting off it, you will be adversely selected. Option quotes are not post-only, so a stale quote can also cross the book and trade as a taker.
A quotes/bulk call with cancelAll (the default) already replaces your prior option ladder in that market, so your steady-state option loop is self-cleaning — the standalone cancel-alls are for the abort path.

Reconnect and heartbeat

SSE streams are long-lived. Build your client to survive drops without leaving orphaned orders.
On connect you get a full snapshot; thereafter fold in delta events (or, on the book and board streams, replace your copy with each full update).
GET /fut/stream/user carries an eventSeq that increases by exactly one per event. If it jumps, close and reconnect — you will get a fresh snapshot to re-sync from. Other streams’ sequence numbers are not contiguous; rely on reconnect-on-drop there.
Idle streams send comment heartbeats — : heartbeat on the futures account stream (after 5s idle), :heartbeat on the futures book stream (after 15s idle), and :keepalive on the balances stream (every 15s). If expected heartbeats stop arriving, treat the connection as dead and reconnect.
On any disconnect, reconnect with exponential backoff and jitter. Re-snapshot before trusting local state, and resume quoting only once state is consistent.

Idempotency and identifiers

clientOrderId

Attach a clientOrderId to each order or quote level. A retried request with the same id and parameters returns the original result instead of placing a duplicate.

quoteId

Tag each quoting cycle with a quoteId to group a batch of quotes.

Rate limits

The gateway allows 600 requests per minute per client on most endpoints and returns x-ratelimit-* headers; futures market data and futures streams are not rate-limited at the gateway. The engines also limit order placement per account (RATE_LIMITED). Back off on 429 and on RATE_LIMITED rather than retrying tightly. See Errors & rate limits.

Session hygiene

Sign each bot in with its own wallet so its positions, margin, and kill switch are isolated from your other accounts.
Sessions last 7 days. Sign in again ahead of expiry, and handle 401 by re-authenticating, then re-snapshotting.
The session token can trade the account. Keep it in a secret store, never in code or logs, and revoke it with POST {API_BASE}/auth/logout if it leaks.

A resilient maker loop

1

Start up

Sign in, load the market lists, contract terms, and fee schedules, connect the futures account stream, and re-snapshot state.
2

Each cycle

Compute fair value → (optionally) preview → quotes/bulk per option market; amend or re-place post-only orders per futures market.
3

On fill

Update inventory from the position delta (futures) or a positions read (options), then skew or shrink and re-quote.
4

On trouble

Stale feed, disconnect, repeated errors, or shutdown → both cancel-alls, back off, reconnect, re-snapshot, and only then resume.