
Crypto Market Making Strategy: Dynamically Adjusting Quotes Using Order Book Imbalance
Learn how quantitative traders use order book imbalance (OBI) to adjust crypto market-making quotes with Python, manage volatility and inventory, and reduce adverse-selection risk.
For quantitative traders, market making is a pricing problem that changes with market conditions. Quotes that are too wide may miss profitable fills, while quotes that are too aggressive can expose a strategy to adverse selection — getting filled just before the market moves against the position.
In cryptocurrency markets, where trading continues around the clock, order book liquidity can change rapidly. Order Book Imbalance (OBI) offers a way to measure the distribution of visible liquidity and use it to adjust quotes systematically.
This guide explains how to calculate OBI, translate it into dynamic quotes, and process real-time crypto order book data with Python.
Why Order Book Imbalance Matters in Crypto Market Making
A conventional market-making strategy places bid and ask quotes around a reference price. However, the same midpoint can represent different trading conditions depending on the available liquidity on each side.
For example, a relatively large bid-side volume may indicate stronger displayed buying interest. Conversely, heavier ask-side volume may suggest greater selling-side liquidity.
OBI measures this imbalance across selected order book levels. It does not predict price direction with certainty, but it gives quantitative traders an additional signal for adjusting their quoting behavior.
Calculating Order Book Imbalance
A common multi-level OBI formula is:
[
OBI=\frac{V_{bid}-V_{ask}}{V_{bid}+V_{ask}}
]
Here, (V_{bid}) is the total bid volume across the selected levels, and (V_{ask}) is the corresponding ask volume.
The resulting value ranges from -1 to +1 when total volume is positive.
| OBI value | Interpretation | Potential quoting response |
|---|---|---|
| Above zero | More displayed bid volume | Shift the quote center upward |
| Below zero | More displayed ask volume | Shift the quote center downward |
| Near zero | Relatively balanced volume | Keep the center closer to the midpoint |
For instance, if the selected bid levels contain 800 units and the ask levels contain 400 units, OBI is approximately 0.33.
This indicates an imbalance in displayed liquidity, not confirmed buying pressure. Limit orders can be cancelled or replenished, so OBI should be treated as one signal among several rather than a standalone trading rule.
Turning OBI into Dynamic Quotes
A static market-making model places quotes around the midpoint:
[
Mid=\frac{BestBid+BestAsk}{2}
]To incorporate OBI, the strategy can shift the quote center:
[
Center=Mid+\kappa \times OBI
]The bid and ask quotes then become:
[
Bid=Center-h
][
Ask=Center+h
]Here, (h) is the desired half-spread, while (\kappa) controls how strongly OBI affects the quote center. Because OBI is dimensionless, (\kappa) must be expressed in price units.
When OBI is positive, both quotes move upward. When it is negative, both move downward. This changes the reference price without necessarily changing the spread itself.
In a live strategy, the half-spread and adjustment coefficient should account for transaction costs, inventory exposure, volatility, tick size, and execution risk. Their values need to be calibrated through testing rather than assumed to work across all market conditions.
Processing Real-Time Order Book Data with Python
To calculate multi-level OBI, a strategy needs bid and ask prices and volumes, not only the latest trade price.
AllTick provides a WebSocket interface for real-time order book updates. Its depth subscription documentation describes the subscription protocol and the bids and asks fields used below.
The following example subscribes to five BTCUSDT order book levels, calculates OBI, and prints illustrative quote adjustments. It does not submit trading orders.
import json
import os
import time
import uuid
import threading
from urllib.parse import quote
import websocket
API_KEY = os.environ.get("ALLTICK_API_KEY")
if not API_KEY:
raise RuntimeError("Set the ALLTICK_API_KEY environment variable")
WS_URL = (
"wss://quote.alltick.co/quote-b-ws-api?token="
+ quote(API_KEY, safe="")
)
QUOTE_SHIFT_FACTOR = 0.25
def send_heartbeat(ws):
while ws.sock and ws.sock.connected:
time.sleep(10)
if not ws.sock or not ws.sock.connected:
break
try:
ws.send(json.dumps({
"cmd_id": 22000,
"seq_id": int(time.time()),
"trace": str(uuid.uuid4()),
"data": {}
}))
except Exception:
break
def on_open(ws):
ws.send(json.dumps({
"cmd_id": 22002,
"seq_id": int(time.time()),
"trace": str(uuid.uuid4()),
"data": {
"symbol_list": [
{"code": "BTCUSDT", "depth_level": 5}
]
}
}))
threading.Thread(
target=send_heartbeat, args=(ws,), daemon=True
).start()
def on_message(ws, message):
try:
packet = json.loads(message)
except json.JSONDecodeError:
return
if packet.get("cmd_id") != 22999:
return
book = packet.get("data") or {}
bids = book.get("bids") or []
asks = book.get("asks") or []
if not bids or not asks:
return
try:
bid_vol = sum(float(x.get("volume") or 0) for x in bids)
ask_vol = sum(float(x.get("volume") or 0) for x in asks)
best_bid = float(bids[0]["price"])
best_ask = float(asks[0]["price"])
except (TypeError, ValueError, KeyError):
return
total_vol = bid_vol + ask_vol
if total_vol <= 0 or best_ask <= best_bid:
return
obi = (bid_vol - ask_vol) / total_vol
mid = (best_bid + best_ask) / 2
spread = best_ask - best_bid
shift = QUOTE_SHIFT_FACTOR * spread * obi
model_bid = mid - spread / 2 + shift
model_ask = mid + spread / 2 + shift
print(
f"{book.get('code')} OBI={obi:.3f} "
f"bid={model_bid:.2f} ask={model_ask:.2f}"
)
def start():
while True:
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
on_error=lambda ws, err: print(f"WebSocket error: {err}"),
)
ws.run_forever()
time.sleep(3)
if __name__ == "__main__":
start()The example uses the current best bid-ask spread to demonstrate quote shifting. The adjustment factor is illustrative, not a validated trading parameter. Production systems need additional handling for order placement, reconnection state, stale data, price precision, inventory limits, and exchange-specific execution rules.
Controlling Adverse Selection with Volatility and Inventory
OBI alone can generate noisy signals. A large displayed order may disappear before execution, while sudden volatility can make an otherwise reasonable quote outdated.
A more robust crypto market making strategy combines three controls:
- Volatility filtering: Widen the spread or reduce quote sensitivity when short-term volatility rises.
- Inventory management: Adjust the quote center when accumulated positions create excessive directional exposure.
- Signal persistence: Check whether an imbalance persists across multiple updates instead of reacting to every snapshot.
These controls address different risks. Volatility filtering responds to changing market conditions, inventory management limits position concentration, and signal persistence reduces sensitivity to transient order book changes.
Testing the Strategy Before Deployment
A positive OBI reading does not automatically imply that raising quotes improves profitability. Quantitative traders should test whether the signal provides useful information about subsequent price changes and execution outcomes.
Record the order book timestamp, selected bid and ask levels, calculated OBI, generated quotes, and subsequent mid-price movements. Evaluate fill rates, adverse price movement after fills, transaction costs, inventory exposure, and net performance under different volatility conditions.
One important data limitation is that AllTick's documented WebSocket depth subscription provides real-time order book updates, not historical order book data. Traders who need reproducible historical OBI backtests should archive the depth stream themselves and preserve timestamps and data-quality checks.
For live data integration, review the AllTick Crypto API and confirm that the required instrument and depth are available for your account.
A practical market-making strategy does not treat order book imbalance as a guaranteed forecast. It uses OBI to adjust the quote center, combines it with volatility and inventory controls, and relies on measured execution results to determine whether the adjustment adds value.