feat: Phase 4 — controlled strategy deployment module + 38 tests

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.
This commit is contained in:
ramseshk
2026-08-07 14:47:08 +08:00
parent 639dd4fb6d
commit 4f66ef36a9
13 changed files with 1229 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
"""
Tests for live/treasury.py — central treasury and risk management.
"""
from live.treasury import Treasury
class TestTreasury:
def test_initial_equity(self):
t = Treasury(initial_equity=10000.0)
assert t.equity == 10000.0
assert t.total_pnl() == 0.0
def test_can_open_within_limits(self):
t = Treasury(initial_equity=10000.0, max_position_per_asset=0.005)
result = t.can_open("BTC", side="buy", size=0.001, mark_price=50000.0)
assert result["allowed"]
def test_cannot_open_exceed_inventory(self):
t = Treasury(initial_equity=10000.0, max_position_per_asset=0.002)
t.can_open("BTC", side="buy", size=0.001, mark_price=50000.0)
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
result = t.can_open("BTC", side="buy", size=0.0015, mark_price=50000.0)
assert not result["allowed"]
def test_record_fill_updates_position(self):
t = Treasury(initial_equity=10000.0)
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
assert t.position("BTC") == 0.001
def test_record_close_updates_pnl(self):
t = Treasury(initial_equity=10000.0)
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
t.record_fill("BTC", side="sell", size=0.001, price=50100.0, fee=10.0, pnl=100.0)
assert t.position("BTC") == 0.0
assert t.total_pnl() > 0
def test_unrealized_pnl(self):
t = Treasury(initial_equity=10000.0)
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
t.update_mark_price("BTC", 50200.0)
assert t.unrealized_pnl() > 0
def test_pnl_pct(self):
t = Treasury(initial_equity=10000.0)
t.record_fill("BTC", side="buy", size=0.1, price=50000.0, fee=0.1, pnl=0)
t.update_mark_price("BTC", 50200.0) # 0.1 * 200 = $20 unrealized >> $0.10 fee
assert t.pnl_pct() > 0
def test_circuit_breaker_drawdown(self):
t = Treasury(initial_equity=10000.0, max_drawdown_pct=-1.0)
# Force large negative PnL
t._realized_pnl = -5000.0
t._fees_paid = 0
t._check_breakers()
assert t.is_halted()
def test_liquidation_distance(self):
t = Treasury(initial_equity=50000.0)
t.record_fill("BTC", side="buy", size=1.0, price=50000.0, fee=10.0, pnl=0)
dist = t.liquidation_distance("BTC")
assert dist > 0
def test_all_positions(self):
t = Treasury()
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
t.record_fill("ETH", side="sell", size=0.01, price=3000.0, fee=10.0, pnl=0)
positions = t.all_positions
assert positions["BTC"] == 0.001
assert positions["ETH"] == -0.01
def test_net_exposure(self):
t = Treasury()
t.record_fill("BTC", side="buy", size=0.002, price=50000.0, fee=10.0, pnl=0)
t.record_fill("ETH", side="buy", size=0.003, price=3000.0, fee=10.0, pnl=0)
assert t.net_exposure == 0.005
def test_summary(self):
t = Treasury(initial_equity=10000.0)
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
s = t.summary()
assert "equity" in s
assert "pnl_pct" in s
assert "positions" in s
assert "BTC" in s["positions"]
def test_toxic_fill_tracking(self):
t = Treasury(initial_equity=10000.0, max_toxic_rate=0.1)
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=0)
for _ in range(9):
t.record_fill("BTC", side="buy", size=0.001, price=50000.0, fee=10.0, pnl=-1.0)
t.record_toxic_fill()
t.record_toxic_fill()
t._check_breakers()
# 2/10 = 20% toxic > 10% threshold
assert t.is_halted()