A market maker on Kalshi using Black-Scholes binary pricing on a short-dated BTC contract.
Full Code
"""Market maker on Kalshi (paper mode)."""
import math
import horizon as hz
from horizon.context import FeedData
def fair_value(ctx: hz.Context) -> float:
btc_price = ctx.feeds.get("btc", FeedData()).price or 100_000
strike = 100_000
vol = 0.6
tte = 1 / 365 # 1 day to expiry
if tte <= 0:
return 1.0 if btc_price >= strike else 0.0
d2 = (math.log(btc_price / strike) - 0.5 * vol**2 * tte) / (vol * math.sqrt(tte))
return 0.5 * (1 + math.erf(d2 / math.sqrt(2)))
def quoter(ctx: hz.Context, fair: float) -> list[hz.Quote]:
spread = 0.04
return hz.quotes(fair, spread, size=10)
if __name__ == "__main__":
hz.run(
name="kalshi_mm",
exchange=hz.Kalshi(api_key="demo_key"),
markets=["KXBTC-25FEB16"],
feeds={"btc": hz.BinanceWS("btcusdt")},
pipeline=[fair_value, quoter],
risk=hz.Risk(max_position=50),
interval=1.0,
mode="paper",
)
How It Works
- Fair value uses the Black-Scholes binary formula with:
- Strike: $100,000
- Volatility: 60% annualized
- Time to expiry: 1 day (short-dated)
- Underlying: BTC price from Binance WebSocket feed
-
Quoter places a fixed 4-cent spread around the fair value with size 10
-
Risk is capped at 50 contracts per market
Short-Dated vs Long-Dated
For a 1-day contract, the binary option is highly sensitive to the underlying price:
- BTC at 99,000→fairvalue≈0.25(unlikelytohit100k in 1 day)
- BTC at $100,000 → fair value ≈ 0.50 (coin flip)
- BTC at $101,000 → fair value ≈ 0.75 (likely already above)
For longer-dated contracts, increase tte:
tte = 30 / 365 # 30 days → more moderate pricing
Run It
# Paper mode
python examples/kalshi_mm.py
# Live on Kalshi demo
python -m horizon run examples/kalshi_mm.py --mode=live
Use Kalshi’s demo environment for testing: set api_url="https://demo-api.kalshi.co/trade-api/v2" or KALSHI_API_URL env var.