""" 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