Files
ramseshk 5304534e38 feat: advanced microstructure modules — HLP, Hawkes, Whipsaw, Term Structure, Liq Waterfall, Spoof Detector
6 new modules with 46 new tests (230 total):

#21 HLP Vault Monitor (live/monitors/hlp_vault.py):
  Tracks Hyperliquid's native protocol market maker at address
  0xfefefe... Queries clearinghouseState + metaAndAssetCtxs.
  - Delta exposure per asset (notional + PnL)
  - Overextension detection (notional exceeds  M threshold)
  - Rebalancing signals: fade_short when HLP too short,
    fade_long when HLP too long (front-run forced rebalancing)
  - Toxicity score: HLP losing money = absorbing informed flow
  - Historical delta tracking

#29 Hawkes Processes (microstructure/hawkes.py):
  Multivariate Hawkes calibrator for limit order book dynamics.
  - MLE calibration via SGD gradient descent on log-likelihood
  - Branching ratio enforcement (alpha/beta < 0.99 for stationarity)
  - Intensity computation λ_i(t) with cross-excitation
  - Activity forecasting (expected event count in horizon)
  - Synthetic event generator (Ogata thinning)
  - Pure functions: hawkes_intensity, hawkes_log_likelihood,
    generate_hawkes_events

#23 Funding Whipsaw Trader (live/strategies/funding_whipsaw.py):
  Premium index decay trading in final 60s of funding epoch.
  - Detects deterministic convergence of premium→0 at settlement
  - Time-scaled position sizing (larger closer to settlement)
  - Auto-close after funding epoch completes
  - Confidence scoring based on premium magnitude

#32 Term Structure Monitor (live/monitors/term_structure.py):
  Perp/quarterly/bi-quarterly futures basis curve trading.
  - Quarterly-perp basis with z-score anomaly detection
  - BiQ-quarterly curve steepness monitoring
  - Fair quarterly price via interest rate parity + funding carry
  - Calendar spread signals: buy_basis, sell_basis,
    curve_steepener, curve_flattener

#24 Liquidation Waterfall (live/monitors/liq_waterfall.py):
  Cross-margin liquidation order prediction.
  - Margin ratio tracking (equity / maintenance margin)
  - Danger/critical level classification
  - Asset liquidation priority: maintenance / book_liquidity ratio
    (least liquid asset relative to margin = dumped first)
  - Strategy output: widen_spreads on target, tighten on rest

#31 Spoof Detector (microstructure/spoof_detector.py):
  Adversarial ML-style spoofing pattern recognition.
  - Rule 1: Large order far from mid, cancelled immediately
  - Rule 2: Cancel right before trade approaches price level
  - Rule 3: Oversized order with no fill within short lifetime
  - Spoof probability (rolling window ratio)
  - Cancel-to-fill ratio monitoring
2026-08-07 17:52:20 +08:00

154 lines
6.0 KiB
Python

"""
Tests for live/monitors/hlp_vault.py — HLP protocol-level market maker tracking.
"""
from unittest.mock import patch
from live.monitors.hlp_vault import HlpVaultMonitor
HLP_ADDRESS = "0xfefefefefefefefefefefefefefefefefefefefe"
def _mock_meta(): return {"universe": [
{"name": "BTC", "szDecimals": 5},
{"name": "ETH", "szDecimals": 6},
{"name": "SOL", "szDecimals": 7},
]}
def _mock_asset_ctxs(): return [
{"funding": "0.00001", "markPx": "64500", "oraclePx": "64480", "openInterest": "50000000"},
{"funding": "0.000005", "markPx": "3200", "oraclePx": "3195", "openInterest": "30000000"},
{"funding": "0.00002", "markPx": "140", "oraclePx": "139.5", "openInterest": "10000000"},
]
def _mock_clearinghouse(positions=None):
aps = []
if positions:
for coin, (side, szi, entry_px, upnl) in positions.items():
aps.append({"type": "oneWay", "position": {
"coin": coin, "side": side, "szi": str(szi),
"entryPx": str(entry_px), "unrealizedPnl": str(upnl),
}})
return {"assetPositions": aps, "withdrawable": "1000000"}
class TestHlpVaultMonitor:
def test_initial_state_empty(self):
monitor = HlpVaultMonitor(testnet=True)
s = monitor.summary()
assert s["assets_tracked"] == 0
assert s["total_delta_usd"] == 0.0
def test_update_populates_positions(self):
monitor = HlpVaultMonitor(testnet=True)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()], # metaAndAssetCtxs → list
_mock_clearinghouse({"BTC": ("A", 10.5, 64000, 5250),
"ETH": ("B", 50.0, 3100, -2500)}), # clearinghouseState → dict
]
monitor.update()
assert monitor.position("BTC") < 0 # side=A = short
assert monitor.position("ETH") > 0 # side=B = long
assert monitor.summary()["assets_tracked"] >= 2
def test_delta_exposure_usd(self):
monitor = HlpVaultMonitor(testnet=True)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"BTC": ("A", 10.0, 64000, 5000)}),
]
monitor.update()
delta = monitor.delta_exposure()
assert "BTC" in delta
assert abs(delta["BTC"]["notional_usd"]) > 600000
def test_is_overextended(self):
monitor = HlpVaultMonitor(testnet=True, overextended_threshold=5.0)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"BTC": ("A", 100.0, 64000, 50000)}),
]
monitor.update()
assert monitor.is_overextended("BTC")
def test_not_overextended_with_small_position(self):
monitor = HlpVaultMonitor(testnet=True, overextended_threshold=5.0)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"BTC": ("A", 1.0, 64000, 500)}),
]
monitor.update()
assert not monitor.is_overextended("BTC")
def test_rebalancing_signal_long(self):
monitor = HlpVaultMonitor(testnet=True, overextended_threshold=5.0)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"BTC": ("A", 100.0, 64000, 50000)}),
]
monitor.update()
signal = monitor.rebalancing_signal("BTC")
assert signal["overextended"]
assert signal["signal"] in ("fade_short", "fade_long", "neutral")
def test_rebalancing_signal_short(self):
monitor = HlpVaultMonitor(testnet=True, overextended_threshold=5.0)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"ETH": ("B", 2000.0, 3100, 50000)}),
]
monitor.update()
signal = monitor.rebalancing_signal("ETH")
assert signal["overextended"]
def test_toxicity_score_zero_with_no_data(self):
monitor = HlpVaultMonitor(testnet=True)
assert monitor.toxicity_score() == 0.0
def test_toxicity_score_detects_losing_flow(self):
monitor = HlpVaultMonitor(testnet=True)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({
"BTC": ("A", 10.0, 64000, -50000),
"ETH": ("A", 50.0, 3100, -25000),
}),
]
monitor.update()
score = monitor.toxicity_score()
assert score > 0
def test_historical_tracking(self):
monitor = HlpVaultMonitor(testnet=True)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"BTC": ("A", 10.0, 64000, 0)}),
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"BTC": ("A", 12.0, 64100, 1000)}),
]
monitor.update()
monitor.update()
history = monitor.delta_history("BTC")
assert len(history) == 2
def test_summary_includes_all_fields(self):
monitor = HlpVaultMonitor(testnet=True)
with patch.object(monitor, '_api_post') as m:
m.side_effect = [
[_mock_meta(), _mock_asset_ctxs()],
_mock_clearinghouse({"BTC": ("A", 10.0, 64000, 5000)}),
]
monitor.update()
s = monitor.summary()
assert "assets_tracked" in s
assert "total_delta_usd" in s
assert "toxicity_score" in s
assert "overextended_assets" in s
assert "signals" in s