Initial project scaffold: five quant strategies for Hyperliquid Testnet
Set up the directory structure and wrote placeholder logic for: - Order Book Imbalance: trades on L2 bid/ask skew - Iceberg/TWAP detection: follows whale accumulation patterns - Funding rate arbitrage: delta-neutral carry on perp funding - Pairs trading: BTC/ETH spread mean reversion - Avellaneda-Stoikov market making: optimal bid/ask quoting Also added shared risk manager, portfolio tracker, and a plain-language strategy walkthrough in docs/.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
Iceberg / TWAP detection strategy.
|
||||
|
||||
Large traders often split big orders into small slices to avoid
|
||||
slippage. This strategy detects those patterns by watching for
|
||||
recurring same-sized trades above average volume, then enters
|
||||
in the same direction.
|
||||
"""
|
||||
from collections import deque
|
||||
from nautilus_trader.trading.strategy import Strategy
|
||||
from nautilus_trader.config import StrategyConfig
|
||||
|
||||
|
||||
class IcebergDetectorConfig(StrategyConfig, frozen=True):
|
||||
instrument_id: str
|
||||
lookback_seconds: int = 300
|
||||
volume_spike_mult: float = 3.0
|
||||
min_slices: int = 4
|
||||
trade_size: float = 0.001
|
||||
|
||||
|
||||
class IcebergDetector(Strategy):
|
||||
"""
|
||||
Detects iceberg/TWAP execution patterns.
|
||||
|
||||
Logic:
|
||||
1. Track trade sizes in a rolling window
|
||||
2. When a trade is much larger than average, flag it
|
||||
3. If same size repeats N times -> confirmed iceberg
|
||||
4. Trade in the same direction
|
||||
"""
|
||||
|
||||
def __init__(self, config: IcebergDetectorConfig) -> None:
|
||||
super().__init__(config)
|
||||
self.config = config
|
||||
self.recent_sizes: deque[float] = deque(maxlen=100)
|
||||
self.slice_count = 0
|
||||
self.last_flagged_size: float | None = None
|
||||
|
||||
def on_start(self) -> None:
|
||||
self.subscribe_trade_ticks(self.config.instrument_id)
|
||||
self.log.info(f"Iceberg detector started on {self.config.instrument_id}")
|
||||
|
||||
def on_trade_tick(self, tick) -> None:
|
||||
self.recent_sizes.append(tick.size)
|
||||
avg = sum(self.recent_sizes) / len(self.recent_sizes) if self.recent_sizes else 0
|
||||
|
||||
if tick.size > avg * self.config.volume_spike_mult:
|
||||
if tick.size == self.last_flagged_size:
|
||||
self.slice_count += 1
|
||||
else:
|
||||
self.slice_count = 1
|
||||
self.last_flagged_size = tick.size
|
||||
else:
|
||||
self.slice_count = 0
|
||||
|
||||
if self.slice_count >= self.config.min_slices:
|
||||
self.log.info(
|
||||
f"Iceberg: {self.slice_count} slices of size {self.last_flagged_size}"
|
||||
)
|
||||
self.submit_order(self.order_factory.market(
|
||||
instrument_id=self.config.instrument_id,
|
||||
order_side="BUY" if tick.is_buyer_maker else "SELL",
|
||||
quantity=self.config.trade_size,
|
||||
))
|
||||
self.slice_count = 0
|
||||
Reference in New Issue
Block a user