5304534e38
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
92 lines
3.9 KiB
Python
92 lines
3.9 KiB
Python
"""
|
|
Tests for live/strategies/funding_whipsaw.py — premium index decay trading.
|
|
"""
|
|
from unittest.mock import patch, MagicMock
|
|
from live.strategies.funding_whipsaw import FundingWhipsawTrader
|
|
|
|
|
|
class TestFundingWhipsaw:
|
|
def test_initial_no_signal_outside_window(self):
|
|
"""With default 60s entry window and >60s to funding, no signal."""
|
|
trader = FundingWhipsawTrader()
|
|
trader.update(mark_px=64500, oracle_px=64480)
|
|
with patch.object(trader, 'seconds_to_funding', return_value=300.0):
|
|
s = trader.signal()
|
|
assert s["action"] == "none"
|
|
assert s["reason"] == "outside_entry_window"
|
|
|
|
def test_enter_long_on_negative_premium(self):
|
|
trader = FundingWhipsawTrader(min_premium_bps=0.5)
|
|
trader.update(mark_px=64400, oracle_px=64500) # negative premium: -1.55 bps
|
|
with patch.object(trader, 'seconds_to_funding', return_value=30.0):
|
|
s = trader.signal()
|
|
assert s["action"] == "enter_long"
|
|
assert s["side"] == "buy"
|
|
assert s["confidence"] > 0
|
|
assert s["size"] > 0
|
|
|
|
def test_enter_short_on_positive_premium(self):
|
|
trader = FundingWhipsawTrader(min_premium_bps=0.5)
|
|
trader.update(mark_px=64600, oracle_px=64500) # positive premium: +1.55 bps
|
|
with patch.object(trader, 'seconds_to_funding', return_value=30.0):
|
|
s = trader.signal()
|
|
assert s["action"] == "enter_short"
|
|
assert s["side"] == "sell"
|
|
assert s["confidence"] > 0
|
|
|
|
def test_no_signal_on_small_premium(self):
|
|
trader = FundingWhipsawTrader(min_premium_bps=5.0)
|
|
trader.update(mark_px=64501, oracle_px=64500) # tiny premium: 0.015 bps
|
|
with patch.object(trader, 'seconds_to_funding', return_value=30.0):
|
|
s = trader.signal()
|
|
assert s["action"] == "none"
|
|
assert s["reason"] == "premium_too_small"
|
|
|
|
def test_close_after_funding(self):
|
|
"""After entering, close when funding settles."""
|
|
trader = FundingWhipsawTrader()
|
|
trader.update(mark_px=64600, oracle_px=64500)
|
|
with patch.object(trader, 'seconds_to_funding', return_value=30.0):
|
|
s = trader.signal()
|
|
assert s["action"].startswith("enter")
|
|
|
|
# Now funding just happened
|
|
with patch.object(trader, 'seconds_to_funding', return_value=8*3600 - 2.0):
|
|
with patch.object(trader, 'seconds_since_funding', return_value=2.0):
|
|
s = trader.signal()
|
|
assert s["action"] == "close"
|
|
|
|
def test_hold_after_entry(self):
|
|
trader = FundingWhipsawTrader()
|
|
trader.update(mark_px=64600, oracle_px=64500)
|
|
with patch.object(trader, 'seconds_to_funding', return_value=30.0):
|
|
trader.signal() # enter
|
|
# Next tick, still before funding
|
|
with patch.object(trader, 'seconds_to_funding', return_value=25.0):
|
|
s = trader.signal()
|
|
assert s["action"] == "hold"
|
|
|
|
def test_larger_position_with_more_premium(self):
|
|
trader = FundingWhipsawTrader(min_premium_bps=0.5, max_size=0.001)
|
|
trader.update(mark_px=65100, oracle_px=64500) # large premium
|
|
with patch.object(trader, 'seconds_to_funding', return_value=30.0):
|
|
s = trader.signal()
|
|
assert s["confidence"] > 0.5 # high confidence
|
|
assert s["size"] > 0
|
|
|
|
def test_seconds_to_funding_returns_positive(self):
|
|
trader = FundingWhipsawTrader()
|
|
secs = trader.seconds_to_funding()
|
|
assert secs > 0
|
|
assert secs <= 8 * 3600 # Max 8 hours
|
|
|
|
def test_signal_includes_premium_info(self):
|
|
trader = FundingWhipsawTrader()
|
|
trader.update(mark_px=64600, oracle_px=64500)
|
|
with patch.object(trader, 'seconds_to_funding', return_value=45.0):
|
|
s = trader.signal()
|
|
assert "premium_bps" in s
|
|
assert "seconds_to_funding" in s
|
|
assert "confidence" in s
|
|
assert s["premium_bps"] > 0
|