Inventory Risk in Market Making
Inventory risk is the directional exposure a market maker accumulates when fills are one-sided — you keep buying as price falls, or selling as price rises, and the spread you earned does not cover the mark-to-market loss. Every market making strategy is a tradeoff between spread capture (good) and inventory accumulation (bad). This article decomposes market-making P&L, introduces the Avellaneda-Stoikov framework, and covers the practical controls that keep inventory from becoming a directional bet you did not intend.
P&L decomposition
A market maker's daily P&L splits into four components:
P&L = spread_capture + inventory_pnl + fees_rebates + adverse_selection_cost
| Component | Source | Sign |
|---|---|---|
| Spread capture | Buy bid, sell ask, repeat | Positive (intended edge) |
| Inventory P&L | Mark-to-market on net position | Positive or negative |
| Fees/rebates | Exchange maker rebates, taker fees | Usually positive for makers |
| Adverse selection | Informed traders pick you off | Negative |
The failure mode: spread capture looks steady at +$500/day while inventory P&L bleeds -$2000 on a trend day. Net loss. The maker was providing liquidity to informed flow without adjusting quotes — classic adverse selection.
Why inventory accumulates
Fills are not independent. In a downtrend:
- Your bid gets hit (you buy) repeatedly
- Your ask does not get lifted (you do not sell)
- Net inventory grows long as price falls
- Spread earned per round-trip < loss per unit of inventory
This is passive exposure to informed order flow. The market is telling you something through which side fills, and if you ignore it, you are running a losing directional strategy disguised as market making.
Correlation between fill side and subsequent return is the empirical test:
import pandas as pd
import numpy as np
def adverse_selection_cost(fills: pd.DataFrame) -> float:
"""Avg return after fill × fill direction. Positive = you are being picked off."""
# fill_side: +1 for buy, -1 for sell
# ret_1m: return in next 1 minute after fill
picked_off = (fills['fill_side'] * fills['ret_1m']).mean()
return picked_off # positive → adverse selection against you
If this metric is consistently positive, your quotes are too tight or too slow to adjust.
Avellaneda-Stoikov framework
The standard model (Avellaneda & Stoikov, 2008) optimizes quotes around a reservation price that skews away from accumulated inventory:
reservation_price = mid - q × γ × σ² × (T - t)
| Symbol | Meaning |
|---|---|
| q | Current inventory (positive = long) |
| γ | Risk aversion parameter |
| σ | Volatility |
| T - t | Time remaining in session |
Quotes are placed around the reservation price, not the mid:
bid = reservation_price - δ/2
ask = reservation_price + δ/2
When long (q > 0), reservation price drops below mid → bid moves down, ask moves down → harder to buy more, easier to sell. This is inventory skew.
def avellaneda_quotes(mid: float, inventory: float, gamma: float,
sigma: float, time_left: float,
k: float = 1.5) -> tuple[float, float]:
"""Simplified AS optimal quotes."""
reservation = mid - inventory * gamma * sigma**2 * time_left
# Optimal half-spread (simplified)
delta = gamma * sigma**2 * time_left + (2 / gamma) * np.log(1 + gamma / k)
return reservation - delta / 2, reservation + delta / 2
# Long inventory → lower quotes → encourage selling
bid, ask = avellaneda_quotes(mid=100, inventory=500, gamma=0.1,
sigma=0.02, time_left=0.5)
γ controls aggressiveness of skew: high γ → flatten inventory fast (wider spread, more skew); low γ → tolerate inventory for more spread capture.
Practical inventory controls
Beyond AS, production market makers use layered controls:
Hard limits
if |inventory| > max_inv: pull all quotes on accumulating side
Simple, effective, stops the bleeding. Cost: you earn no spread while flat on one side.
Soft skew (linear)
Shift quotes proportionally to inventory without full AS optimization:
bid -= skew_factor × inventory
ask -= skew_factor × inventory
Easier to tune than γ, σ, k. Start here before full AS.
Time-based flattening
As session end approaches, increase γ (or skew_factor) to reach zero inventory. Overnight inventory carries gap risk — most equity MMs flatten into close.
Vol-adjusted spreads
Widen spread when σ rises; inventory losses scale with σ² in the AS model. Connect to GARCH or realized vol estimates.
Toxicity detection
If order flow imbalance is strongly negative, pull bids before they fill. This is adverse-selection-aware quoting — halfway between market making and HFT alpha.
Inventory in crypto market making
Crypto adds:
- 24/7 exposure — no session end to flatten; inventory can accumulate for days
- Funding payments — perp inventory earns/pays funding,
changing the carry of holding inventory
- Fragmented liquidity — inventory on one exchange is not fungible instantly;
transfer risk during rebalancing
- Liquidation cascades — inventory accumulates into a squeeze; gap risk is extreme
Crypto MMs often hedge inventory with perp positions on another venue — converting inventory risk into basis/funding risk, which may be cheaper to manage.
Measuring market-making edge
Track daily:
| Metric | Healthy range | Red flag |
|---|---|---|
| Spread capture / volume | Stable bps per share | Declining trend |
| Inventory P&L / spread capture | < 0.5x | > 1x (inventory dominates) |
| Adverse selection (post-fill return) | Near 0 | Consistently positive |
| Fill rate imbalance | ~50/50 buy/sell | > 60/40 one side |
| Inventory half-life | < 30 min (intraday MM) | > 2 hours |
If inventory half-life exceeds your horizon, you are not market making — you are directional with extra steps.
Connection to capacity and execution
Inventory risk scales with strategy capacity: larger quotes → more inventory per fill → more skew needed → wider effective spread → less competitive. The optimal size balances spread revenue against inventory variance.
For execution (not pure MM), Almgren-Chriss is the analogous framework: trade off speed (inventory reduction) against impact.
Key takeaways
- Market-making P&L = spread + inventory + rebates - adverse selection
- Inventory accumulates one-sided in trends; skew quotes to flatten
- Avellaneda-Stoikov: reservation price shifts with inventory × γ × σ²
- Hard limits, soft skew, and toxicity detection are production essentials
- Track inventory half-life — if it is too long, you are running a directional book
