Complete guide for professional market makers — Market-Making Program, colocation setup, available endpoints, quoting strategy, and safety mechanisms.
The Market-Making Program provides dedicated infrastructure for professional liquidity providers — including fee rebates, colocation access, and a curated endpoint set optimized for low-latency quoting. The guide covers program enrollment, colocation setup, available endpoints, quoting strategy, and production safety mechanisms.
The Market-Making Program offers tiered fee rebates based on 30-day rolling trading volume.Fee tier structure:
Tier
Maker Fee
Taker Fee
Requirement
Base rate
0.1%
0.1%
Default for all users
VIP best tier
-0.001%
0.03%
Volume-based VIP progression
MM Program best tier
-0.012%
0.020%
$100M+ spot volume per 30 days
Negative maker fees represent rebates — the exchange pays the market maker for each maker order filled.Futures market making has separate entry requirements and rebate tiers:
Tier
Maker Fee
Taker Fee
Requirement
Futures MM best tier
-0.020%
0.032%
≥2% of total WhiteBIT Futures maker volume per 30 days (min $30M)
For current tier breakpoints across all volume levels, see the Market-Making Program page.Worked example — MM Program best tier (-0.012% maker):
Maker fill of $100,000 on BTC_USDT:Rebate = $100,000 × 0.00012 = $12.00 received per fillAt $100M monthly maker volume: ~$12,000/month in rebates
Colocation provides low-latency API access from AWS infrastructure co-located with the WhiteBIT matching engine.Regions:
Region
Location
Europe (Primary)
Frankfurt
Asia
Tokyo
The account manager provides the specific AWS region, availability zone, and connection endpoints during onboarding.Performance: 3-5 milliseconds latency from colocation infrastructure.EC2 sizing recommendations:
Network: up to 10Gbit bandwidth
CPU: minimum 4 vCPU cores
Low-performance VPS instances result in higher latency
Both REST API and WebSocket connections are available via colocation.Contact the designated account manager for connection details including base URLs and availability zone placement.
Colocation endpoints are a SUBSET of the full WhiteBIT API. Only the 33 endpoints listed below are available via colocation infrastructure. All other API endpoints must be accessed through the standard public API.
See the Colocation page for additional infrastructure details.
The colocation infrastructure exposes 33 endpoints organized into three categories: spot trading (15), collateral trading for both Margin and Futures (14), and utility (4).
Collateral / Margin and Futures trading (14 endpoints)
Endpoint
Description
POST /api/v4/collateral-account/balance
Collateral account balance
POST /api/v4/collateral-account/balance-summary
Collateral balance summary
POST /api/v4/collateral-account/summary
Collateral account summary
POST /api/v4/collateral-account/leverage
Set leverage
POST /api/v4/collateral-account/positions/open
Open positions
POST /api/v4/collateral-account/positions/history
Position history
POST /api/v4/collateral-account/funding-history
Funding history
POST /api/v4/oco-orders
OCO orders
POST /api/v4/order/collateral/limit
Collateral limit order
POST /api/v4/order/collateral/market
Collateral market order
POST /api/v4/order/collateral/stop-limit
Collateral stop-limit order
POST /api/v4/order/collateral/trigger-market
Collateral trigger-market order
POST /api/v4/order/collateral/oco
Collateral OCO order
POST /api/v4/order/collateral/bulk
Collateral bulk orders
API naming convention: WhiteBIT’s API uses “collateral” endpoints for both Margin and Futures trading. The market pair determines the product: spot pairs (e.g., BTC_USDT) for Margin, perpetual pairs (e.g., BTC_PERP) for Futures. All endpoints under /api/v4/order/collateral/ and /api/v4/collateral-account/ serve both products.
Professional quoting on WhiteBIT combines bulk limit orders for position management with real-time market data for price discovery.Bulk limit orders:POST /api/v4/order/bulk — place up to 20 limit orders in a single API call. Each order item can set rpi: true to enable Retail Price Improvement mode — post-only by design, not visible in public depth feeds, and incompatible with ioc. See the API Reference.Real-time orderbook: Subscribe to the depth WebSocket channel for real-time orderbook updates. See the WebSocket Quickstart.Order modify:POST /api/v4/order/modify — change an existing order’s price, amount, or activation price. The matching engine internally cancels the original order and creates a replacement with a new orderId, so modify does NOT preserve queue priority. Use clientOrderId as the stable identifier across modifications. Identify the target by orderId OR clientOrderId — never both. See the API Reference.Kill-switch (circuit breaker):POST /api/v4/order/kill-switch — set a timeout after which all active orders are automatically canceled. Essential safety mechanism for market-making operations. See the API Reference.
Configuration: set the timeout period; the timer resets on each API call to the kill-switch endpoint
Scope: pass the optional types array ("spot", "margin", "futures") to restrict the breaker to a subset of order types — useful when running spot market-making alongside futures positions you do not want to kill
Check status: POST /api/v4/order/kill-switch/status — see the API Reference
Self-Trade Prevention: Market makers providing two-sided quotes (bid + ask) must understand STP behavior to avoid self-trades. When a new order would match against an existing order from the same account, the STP mechanism cancels the new order, the existing order, both, or neither — depending on the stp mode passed at order placement. The default mode (no) allows self-trades, which is usually not what a two-sided quoter wants. See Self-Trade Prevention for the available modes.
curl
Python
# Place a bulk order (up to 20 limit orders). Each order item carries its# own "market" field — there is no top-level market parameter.curl -X POST "https://whitebit.com/api/v4/order/bulk" \ -H "Content-Type: application/json" \ -H "X-TXC-APIKEY: YOUR_API_KEY" \ -H "X-TXC-PAYLOAD: YOUR_PAYLOAD" \ -H "X-TXC-SIGNATURE: YOUR_SIGNATURE" \ -d '{ "orders": [ {"market": "BTC_USDT", "side": "buy", "amount": "0.01", "price": "60000", "clientOrderId": "quote-bid-1"}, {"market": "BTC_USDT", "side": "buy", "amount": "0.01", "price": "59900", "clientOrderId": "quote-bid-2"}, {"market": "BTC_USDT", "side": "sell", "amount": "0.01", "price": "60200", "clientOrderId": "quote-ask-1"}, {"market": "BTC_USDT", "side": "sell", "amount": "0.01", "price": "60300", "clientOrderId": "quote-ask-2"} ], "request": "/api/v4/order/bulk", "nonce": "YOUR_NONCE" }'# Requote the top bid by clientOrderId. The response carries a new orderId;# the clientOrderId is preserved so local tracking survives the modify.curl -X POST "https://whitebit.com/api/v4/order/modify" \ -H "Content-Type: application/json" \ -H "X-TXC-APIKEY: YOUR_API_KEY" \ -H "X-TXC-PAYLOAD: YOUR_PAYLOAD" \ -H "X-TXC-SIGNATURE: YOUR_SIGNATURE" \ -d '{ "market": "BTC_USDT", "clientOrderId": "quote-bid-1", "price": "60050", "request": "/api/v4/order/modify", "nonce": "YOUR_NONCE" }'# Set a kill-switch with 60-second timeout. The timeout field is a string.curl -X POST "https://whitebit.com/api/v4/order/kill-switch" \ -H "Content-Type: application/json" \ -H "X-TXC-APIKEY: YOUR_API_KEY" \ -H "X-TXC-PAYLOAD: YOUR_PAYLOAD" \ -H "X-TXC-SIGNATURE: YOUR_SIGNATURE" \ -d '{ "market": "BTC_USDT", "timeout": "60", "request": "/api/v4/order/kill-switch", "nonce": "YOUR_NONCE" }'
import hashlibimport hmacimport jsonimport timeimport base64import requestsAPI_KEY = "YOUR_API_KEY"API_SECRET = "YOUR_SECRET"BASE_URL = "https://whitebit.com"def send_request(endpoint, payload): payload["request"] = endpoint payload["nonce"] = str(int(time.time() * 1000)) body = json.dumps(payload) encoded = base64.b64encode(body.encode()).decode() signature = hmac.new( API_SECRET.encode(), encoded.encode(), hashlib.sha512 ).hexdigest() headers = { "Content-Type": "application/json", "X-TXC-APIKEY": API_KEY, "X-TXC-PAYLOAD": encoded, "X-TXC-SIGNATURE": signature, } return requests.post(f"{BASE_URL}{endpoint}", headers=headers, data=body)# Place a bulk order. Each order item carries its own "market" field —# there is no top-level market parameter. The response is a list of# {"result": {...}, "error": {...}} pairs — check each item individually# since per-order failures do not fail the HTTP request.response = send_request("/api/v4/order/bulk", { "orders": [ {"market": "BTC_USDT", "side": "buy", "amount": "0.01", "price": "60000", "clientOrderId": "quote-bid-1"}, {"market": "BTC_USDT", "side": "buy", "amount": "0.01", "price": "59900", "clientOrderId": "quote-bid-2"}, {"market": "BTC_USDT", "side": "sell", "amount": "0.01", "price": "60200", "clientOrderId": "quote-ask-1"}, {"market": "BTC_USDT", "side": "sell", "amount": "0.01", "price": "60300", "clientOrderId": "quote-ask-2"}, ],})print(response.json())# Requote the top bid by clientOrderId. Response carries a new orderId;# clientOrderId is preserved so local tracking survives the modify.response = send_request("/api/v4/order/modify", { "market": "BTC_USDT", "clientOrderId": "quote-bid-1", "price": "60050",})print(response.json())# Set a kill-switch with 60-second timeout. The timeout field is a string.response = send_request("/api/v4/order/kill-switch", { "market": "BTC_USDT", "timeout": "60",})print(response.json())
The market-making loop runs on real-time WebSocket data, not REST polling. Quote inputs arrive on depth (deep book) or bookTicker (top of book); inventory state arrives on balanceSpot; fill confirmations arrive on deals (executions) and ordersPending (state transitions including partial fills and cancels). Wire those four channels together to close the loop: market data drives the quote, REST order/bulk or order/modify places it, ordersPending confirms the state transition, deals confirms the fill, balanceSpot confirms the inventory delta, and the loop recomputes.The protocol primitives — connect, ping/pong, authorize, exponential-backoff reconnection, and the query-then-subscribe recovery pattern — are covered end-to-end in the WebSocket Quickstart. This section maps MM data needs to the right pieces of that material rather than duplicating it.
Channel
Tells you
Recovery model
Where to learn the protocol
depth
Full orderbook (1/5/10/20/30/50/100 levels per market)
Snapshot on subscribe, then incremental updates with update_id for gap detection
Canonical subscribe set (spot MM). Send these messages after the authorize handshake — the three private subscriptions will be rejected on an unauthenticated socket. For multi-symbol MM, repeat each *_subscribe per market or use the multiple-subscription flag where supported (see the depth subscribe parameters).
Note the asymmetry: ordersPending_subscribe takes a flat array of markets, deals_subscribe takes a single-element array containing the array of markets. The full schema lives in asyncapi/private/deals.yaml (rendered as the Deals channel page).For the full reconnect-with-fresh-token + auto-resubscribe pattern that wraps these subscriptions in production, see WS Quickstart — Reconnection and state recovery and the worked grid-bot example in the Bot Guide.
Production market-making systems require careful architecture around account structure, connectivity, and rate management.Sub-accounts for strategy separation: Use sub-accounts to isolate different trading strategies or pair groups. Each sub-account has independent balances and can have dedicated API keys. Transfers between sub-accounts are fee-free.WebSocket connection management:
Authenticate after connecting: fetch a token via POST /api/v4/profile/websocket_token (rate limit: 10 requests per 60 seconds — cache the token across reconnects within its lifetime), then send {"id": N, "method": "authorize", "params": ["<token>", "public"]} on the socket. On {"result": {"status": "success"}}, subscribe to private channels such as balanceSpot, ordersPending, and deals
Implement automatic reconnection with exponential backoff
Re-subscribe to all channels after reconnection
Use the ping/pong mechanism to detect stale connections
After reconnecting, reconcile local state: call POST /api/v4/orders for the current active set and POST /api/v4/trade-account/executed-history for fills since the last-seen ID. Do not assume in-memory state survived the disconnect
Market-making operations require continuous monitoring and automated safety mechanisms.Kill-switch configuration: Set the kill-switch timeout as the first action after connecting. Configure the timeout based on the maximum acceptable unmonitored period for the system. Reset the timer with each regular API call to the kill-switch endpoint. If the system crashes or loses connectivity, the kill-switch cancels all orders after the timeout expires.Emergency cancel:POST /api/v4/order/cancel/all — cancel every open order synchronously. Use the optional market field to scope to a single pair and the type array to scope to "spot", "margin", or "futures"; omit both to cancel everything on the account. This is the “big red button” for live traders; the kill-switch is the deadman timer for when you are not there. See the API Reference.
# Uses send_request helper from the Quoting strategy example above.response = send_request("/api/v4/order/cancel/all", { "market": "BTC_USDT", "type": ["spot"],})print(response.json())
Balance monitoring: Use the WebSocket balanceSpot channel for real-time balance updates, or poll POST /api/v4/trade-account/balance for periodic checks. Monitor for unexpected balance changes.Fee tracking: Use POST /api/v4/market/fee to pull the account’s global maker and taker fees plus any per-pair custom fees — the market request parameter is currently ignored, so the endpoint returns fees for all markets regardless. Filter the per-pair custom_fee map client-side. Fee tiers are based on 30-day rolling volume — monitor tier changes as volume accumulates. Look up tier breakpoints on the VIP program page or the trading fees page.Self-Trade Prevention: Understand the STP mode active on the account. Two-sided quoters hit STP frequently when bid and ask orders overlap. See Self-Trade Prevention for the available modes and behavior.