4f66ef36a9
New live/ sub-modules for production-ready market making:
live/filters/toxicity.py (ToxicityFilter):
VPIN-based pre-trade filter. Accumulates buy/sell volume, computes
VPIN via microstructure module, produces quoting decision:
- allow_quoting: bool
- size_multiplier: 0.0–1.0 (graduated reduction approaching alarm)
- granular thresholds (threshold vs alarm) with smooth reduction
live/treasury.py (Treasury):
Central capital/risk management — single source of truth:
- Position tracking per coin (opening, closing, average entry)
- Realized + unrealized PnL computation
- Pre-trade constraint checks (inventory limits, fee estimates)
- Circuit breaker (drawdown, trade count, toxic fill rate, API errors)
- Liquidation distance monitoring
- Automatic cooldown reset after trip expiry
live/makers/hl_btc_eth.py:
HlMaker — per-coin market maker integrating:
- AvellanedaStoikovMaker (Phase 3) for optimal quotes
- ToxicityFilter for pre-trade gating
- Treasury for position/risk checks
HlMakerPool — manages multiple HlMaker instances with shared treasury
and coordinated observe_all()/quote_all()
live/monitors/cross_venue.py (CrossVenueMonitor):
Cross-exchange lead-lag detection via cross-correlation at multiple
lags. Spot premium (basis proxy) computation. Multi-venue summary.
live/monitors/funding_basis.py (FundingBasisMonitor):
Funding regime classification, momentum detection, carry PnL
estimation, basis spread analysis. Uses microstructure/funding.py.
live/monitors/liq_risk.py (LiquidationRiskOverlay):
Per-position liquidation distance monitoring with tiered warnings
(safe/warning/danger/critical). Recommended position reduction.
38 tests across 4 files (all pass):
test_live_filters.py (5)
test_live_maker.py (9)
test_live_monitors.py (11)
test_live_treasury.py (13)
Total test suite: 172 tests, all passing.
87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
"""
|
|
Tests for live/makers/hl_btc_eth.py — HL maker strategy.
|
|
"""
|
|
from live.treasury import Treasury
|
|
from live.makers.hl_btc_eth import HlMaker, HlMakerPool
|
|
|
|
|
|
class TestHlMaker:
|
|
def test_initial_quote_returns_none(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
maker = HlMaker("BTC", treasury=t)
|
|
assert maker.quote() is None # no mid price yet
|
|
|
|
def test_quote_after_observe(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
maker = HlMaker("BTC", treasury=t, base_size=0.001)
|
|
maker.observe(50000.0)
|
|
maker.update_book(49999.0, 50001.0)
|
|
q = maker.quote()
|
|
assert q is not None
|
|
assert q.bid < 50000.0 < q.ask
|
|
assert q.bid_size > 0
|
|
assert q.ask_size > 0
|
|
|
|
def test_quote_blocked_by_halte(self):
|
|
t = Treasury(initial_equity=10000.0, max_drawdown_pct=-1.0)
|
|
t._realized_pnl = -5000.0
|
|
t._fees_paid = 0
|
|
t._check_breakers()
|
|
maker = HlMaker("BTC", treasury=t)
|
|
maker.observe(50000.0)
|
|
assert maker.quote() is None
|
|
|
|
def test_should_skip_at_max_inventory(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
maker = HlMaker("BTC", treasury=t, max_inventory=0.001)
|
|
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
|
|
maker.observe(50000.0)
|
|
assert maker.should_skip()
|
|
|
|
def test_record_fill_updates_treasury(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
maker = HlMaker("BTC", treasury=t)
|
|
maker.observe(50000.0)
|
|
maker.record_fill("buy", 0.001, 50000.0, 10.0)
|
|
assert t.position("BTC") == 0.001
|
|
|
|
def test_quote_never_crosses_book(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
maker = HlMaker("BTC", treasury=t, base_size=0.001, gamma=0.5)
|
|
maker.observe(50000.0)
|
|
maker.update_book(49995.0, 50005.0)
|
|
for _ in range(20):
|
|
q = maker.quote()
|
|
if q:
|
|
assert q.bid <= 49995.0 # never above best bid
|
|
assert q.ask >= 50005.0 # never below best ask
|
|
assert q.bid < q.ask
|
|
|
|
|
|
class TestHlMakerPool:
|
|
def test_add_and_get_makers(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
pool = HlMakerPool(treasury=t)
|
|
pool.add_maker("BTC", max_inventory=0.002)
|
|
pool.add_maker("ETH", max_inventory=0.01)
|
|
assert pool.get("BTC") is not None
|
|
assert pool.get("ETH") is not None
|
|
assert pool.get("SOL") is None
|
|
|
|
def test_observe_and_quote_all(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
pool = HlMakerPool(treasury=t)
|
|
maker_btc = pool.add_maker("BTC", max_inventory=0.002, base_size=0.001)
|
|
pool.observe_all({"BTC": 50000.0})
|
|
quotes = pool.quote_all()
|
|
assert "BTC" in quotes
|
|
assert quotes["BTC"] is not None
|
|
|
|
def test_summary(self):
|
|
t = Treasury(initial_equity=10000.0)
|
|
pool = HlMakerPool(treasury=t)
|
|
pool.add_maker("BTC", max_inventory=0.002)
|
|
pool.observe_all({"BTC": 50000.0})
|
|
s = pool.summary()
|
|
assert "BTC" in s
|