Market-making, done honestly.
A market maker gets paid to bear inventory risk in exchange for the spread. Most retail bots that call themselves "market makers" are actually one-sided directional bets in disguise. This guide covers the mechanics that make the difference.
You'll learn
How to estimate fair value from a public order book, how to skew quotes against inventory, when to widen or pull, and how to measure whether you're actually earning the spread.
1. Fair value
The midpoint is a lazy fair value. A better estimate is the microprice: weighted midpoint that leans toward the deeper side of the book, because that side is harder to move.
def microprice(bid, ask, bid_size, ask_size):
total = bid_size + ask_size
if total == 0:
return (bid + ask) / 2
return (bid * ask_size + ask * bid_size) / total2. Quoting with inventory skew
The core discipline: push your quote away from any inventory you already hold, so fills push you back toward flat instead of doubling you down. Long inventory → lower both bid and ask; short inventory → raise both.
def quotes(fair, inventory, target_spread=0.02, skew=0.001):
skewed_mid = fair - skew * inventory
half = target_spread / 2
return skewed_mid - half, skewed_mid + half3. Adverse-selection defense
You get filled most often exactly when you don't want to be. Defenses that actually work:
- — Widen the spread when short-term realized volatility jumps.
- — Cancel and reprice on any print larger than N × average trade size.
- — Refuse to quote in the last minutes before an event resolves.
- — Cap the number of consecutive fills on the same side before flattening.
4. Measuring spread capture
Track two P&L streams separately: the spread you capture at the moment of each fill (fill price minus mid at fill time), and the mark-to-market on inventory you carry. A healthy maker has consistently positive spread capture and roughly zero-mean inventory P&L over time.
# On every fill:
spread_pnl += (fill_price - mid_at_fill) * side_sign * size
# On every tick:
inventory_pnl = position * (mid - avg_entry_price)5. Sizing and kill switches
- — Cap notional per market and total notional across the book.
- — Set a max inventory position beyond which you only quote the flattening side.
- — Hard daily loss kill that cancels all quotes and flattens inventory.
6. Frequently asked questions
- Do I need to be faster than everyone else to market-make?
- On the fastest venues, yes — retail cannot win a latency race against colocated firms. On thinner venues like Polymarket or Kalshi, discipline around inventory, quoting cadence, and adverse selection matters far more than microseconds.
- How do I know if I'm actually capturing spread?
- Split your P&L into two components: spread captured (edge relative to mid at fill time) and inventory P&L (mark-to-market on unfilled leans). Healthy market makers earn positive spread and roughly break even on inventory.
- What kills a market-making bot?
- Adverse selection — getting filled only when the market is about to move against you. Defenses include widening quotes into volatility, canceling on large trade prints, and refusing to quote near event resolution.
- How does this fit into ScriptSamurai's forward-test?
- The same deterministic fill model that scores directional bots also scores makers: resting orders match when the shared book crosses them. Your Sharpe, drawdown, and win rate are computed the same way — which is why disciplined making tends to rank well.
Built one? Prove it in the dojo.