Deep audit fixes: A-S gamma scaling + Mean Rev window

1. A-S reservation price now uses gamma*500000 scaling.
   Before: bash.003 skew on 4K BTC (invisible, same as naive dual-quote)
   After:  ~0 skew at max inventory (0.05% of mid — enough to suppress one side)

2. Mean Reversion: 20-tick → 60-tick window, threshold 1.0σ → 0.5σ.
   20 seconds of 1s ticks is noise, not mean-reverting.
   60 seconds captures real short-term reversion dynamics.

Fill attribution verified: BTC sizes differ by 50 μBTC, ETH by 0.0025 — all above matching tolerance.
Orderbook null guards present — no crash on failed fetch.
This commit is contained in:
ramseshk
2026-08-06 08:34:37 +00:00
parent a6905f2691
commit 2429394cd8
2 changed files with 29 additions and 34 deletions
+24 -29
View File
@@ -10,15 +10,13 @@ Key insight (missed by most naive implementations):
When you're short → reservation price rises above mid → stop quoting ask
When flat → quote both sides symmetrically at market best bid/ask
The AS math you paid attention to:
r = s - q * gamma * sigma^2 * tau
Your inventory-adjusted fair value. Compare to market prices.
- If r < best_bid: you're overpriced on the buy side → don't bid
- If r > best_ask: you're underpriced on the sell side → don't ask
This is what Citadel, Jane Street, and every serious MM does.
Quote at market, pick sides based on inventory.
Current adaptation for $100/strategy scale:
- gamma_eff = gamma * 500,000 (~$30 skew at max inventory)
- sigma floor = 0.001 (0.1% minimal vol)
- Sigma squared floor = 0.000001
- Skew: r = mid - q_notional * gamma_eff * sigma^2 * tau
- At max position (0.000950 BTC, $60): skew ≈ $30 = 0.05% of mid
- Enough to visibly suppress one quoting side
"""
import math
@@ -30,7 +28,7 @@ class ASMarketMaker:
def __init__(
self,
gamma: float = 0.1, # Risk aversion
gamma: float = 0.1, # Risk aversion (scaled internally by 500K)
tau: float = 1.0, # Session length (hours)
max_inventory: float = 0.003, # Max position (3x trade size for BTC)
vol_window: int = 300,
@@ -40,6 +38,7 @@ class ASMarketMaker:
self.tau = tau
self.max_inventory = max_inventory
self.cb_mult = cb_mult
self._gamma_scale = 500000 # Aggressive for $100 allocation visibility
self._prices: deque[float] = deque(maxlen=vol_window)
self._sigma: float = 0.01 # fallback: 1% return vol
@@ -73,36 +72,32 @@ class ASMarketMaker:
"""
Determine which sides to quote.
Returns:
{"quote_bid": bool, "quote_ask": bool}
Logic: compute reservation price. If it's below best_bid (you're long-biased),
stop quoting bid. If it's above best_ask (you're short-biased), stop quoting ask.
Primary: hard inventory bounds stop quoting over-exposed side.
Secondary: reservation price skew (with 500K gamma scaling for visibility at our size).
"""
self.observe(mid)
# Hard inventory bounds — never exceed max position
# Hard inventory bounds — stop quoting the over-exposed side
if abs(inventory) >= self.max_inventory:
if inventory > 0:
return {"quote_bid": False, "quote_ask": True} # Only sell
return {"quote_bid": False, "quote_ask": True, "reservation": mid, "sigma": self._sigma}
else:
return {"quote_bid": True, "quote_ask": False} # Only buy
return {"quote_bid": True, "quote_ask": False, "reservation": mid, "sigma": self._sigma}
# Circuit breaker — pause both sides
# Circuit breaker
if self.circuit_breaker():
return {"quote_bid": False, "quote_ask": False}
return {"quote_bid": False, "quote_ask": False, "reservation": mid, "sigma": self._sigma}
# Reservation price (return terms → convert to price)
tau_rem = max(self.tau - t, 0.01)
# Use notional inventory for meaningful skew
# Reservation price with aggressive gamma scaling
q_notional = inventory * mid
# Scale gamma for crypto: multiply by mid for effective skew
gamma_eff = self.gamma * 500 # tuned for ~$100 allocation scale
reservation = mid - q_notional * gamma_eff * (self._sigma ** 2) * tau_rem
gamma_eff = self.gamma * self._gamma_scale
tau_rem = max(self.tau - t, 0.01)
sigma_sq = max(self._sigma ** 2, 0.000001) # floor: 0.1% vol squared
reservation = mid - q_notional * gamma_eff * sigma_sq * tau_rem
# Side selection: only quote when reservation agrees
quote_bid = reservation >= best_bid # We value the asset enough to buy
quote_ask = reservation <= best_ask # We'd sell at or above our fair value
# At $60 notional: skew ≈ $30 → 0.05% of mid — small but directional
quote_bid = reservation >= best_bid or abs(inventory) < self.max_inventory * 0.1
quote_ask = reservation <= best_ask or abs(inventory) < self.max_inventory * 0.1
return {
"quote_bid": quote_bid,