526a40b01e
Renamed all "VIP N" to "Tier N" in config, server, and HTML dropdowns. Added recalc_equity_curve() that rebuilds the equity curve with new fee rates. Previously the equity curve was passed through unchanged when switching tiers, so the chart visually stayed identical even though PnL numbers changed. Now each tier produces its own curve. Example OBI historical: Tier 0 equity ends at 141.5, Tier 6 at 149.7 — the chart visibly shifts up as fees drop from 4.5bp to 2.4bp taker.
92 lines
3.8 KiB
Python
92 lines
3.8 KiB
Python
"""
|
||
Hyperliquid fee tiers — perps and spot, base rates + staking discounts.
|
||
|
||
Source: https://hyperliquid.gitbook.io/hyperliquid-docs/trading/fees
|
||
|
||
Fee = base_rate × staking_multiplier
|
||
Staking tiers are based on staked HYPE tokens.
|
||
"""
|
||
|
||
from dataclasses import dataclass, field
|
||
from typing import Optional
|
||
|
||
# ── Perps fee tiers (base rates) ──
|
||
PERPS_TIERS = {
|
||
0: {"name": "Tier 0", "volume": 0, "taker": 0.00045, "maker": 0.00015},
|
||
1: {"name": "Tier 1", "volume": 5_000_000, "taker": 0.00040, "maker": 0.00012},
|
||
2: {"name": "Tier 2", "volume": 25_000_000, "taker": 0.00035, "maker": 0.00008},
|
||
3: {"name": "Tier 3", "volume": 100_000_000,"taker": 0.00030, "maker": 0.00004},
|
||
4: {"name": "Tier 4", "volume": 500_000_000, "taker": 0.00028, "maker": 0.00000},
|
||
5: {"name": "Tier 5", "volume": 2_000_000_000, "taker": 0.00026, "maker": 0.00000},
|
||
6: {"name": "Tier 6", "volume": 7_000_000_000, "taker": 0.00024, "maker": 0.00000},
|
||
}
|
||
|
||
# ── Spot fee tiers (base rates) ──
|
||
SPOT_TIERS = {
|
||
0: {"name": "Tier 0", "volume": 0, "taker": 0.00070, "maker": 0.00040},
|
||
1: {"name": "Tier 1", "volume": 100_000, "taker": 0.00060, "maker": 0.00030},
|
||
2: {"name": "Tier 2", "volume": 1_000_000, "taker": 0.00050, "maker": 0.00020},
|
||
3: {"name": "Tier 3", "volume": 10_000_000, "taker": 0.00040, "maker": 0.00010},
|
||
4: {"name": "Tier 4", "volume": 50_000_000, "taker": 0.00030, "maker": 0.00005},
|
||
5: {"name": "Tier 5", "volume": 200_000_000, "taker": 0.00020, "maker": 0.00000},
|
||
6: {"name": "Tier 6", "volume": 1_000_000_000,"taker":0.00010,"maker": -0.00005},
|
||
}
|
||
|
||
# ── Staking discount multipliers ──
|
||
STAKING_TIERS = {
|
||
"none": {"name": "No Stake", "multiplier": 1.00},
|
||
"wood": {"name": "Wood", "multiplier": 0.95},
|
||
"bronze": {"name": "Bronze", "multiplier": 0.90},
|
||
"silver": {"name": "Silver", "multiplier": 0.85},
|
||
"gold": {"name": "Gold", "multiplier": 0.80},
|
||
"platinum": {"name": "Platinum", "multiplier": 0.70},
|
||
"diamond": {"name": "Diamond", "multiplier": 0.60},
|
||
}
|
||
|
||
|
||
def effective_rate(base_rate: float, staking_tier: str = "none") -> float:
|
||
"""Calculate effective fee rate after staking discount."""
|
||
mult = STAKING_TIERS.get(staking_tier, STAKING_TIERS["none"])["multiplier"]
|
||
return base_rate * mult
|
||
|
||
|
||
def get_perp_fees(vip_tier: int, staking_tier: str = "none", fee_model: str = "taker") -> float:
|
||
"""Get effective perp fee for a given VIP tier and staking tier."""
|
||
tier = PERPS_TIERS.get(vip_tier, PERPS_TIERS[0])
|
||
base = tier[fee_model] if fee_model in ("taker", "maker") else tier["taker"]
|
||
return effective_rate(base, staking_tier)
|
||
|
||
|
||
def get_spot_fees(vip_tier: int, staking_tier: str = "none", fee_model: str = "taker") -> float:
|
||
"""Get effective spot fee for a given VIP tier and staking tier."""
|
||
tier = SPOT_TIERS.get(vip_tier, SPOT_TIERS[0])
|
||
base = tier[fee_model] if fee_model in ("taker", "maker") else tier["taker"]
|
||
return effective_rate(base, staking_tier)
|
||
|
||
|
||
def fee_tier_from_volume(volume_14d: float, market: str = "perps") -> int:
|
||
"""Determine fee tier from 14-day rolling volume."""
|
||
tiers = PERPS_TIERS if market == "perps" else SPOT_TIERS
|
||
current = 0
|
||
for t in sorted(tiers.keys()):
|
||
if volume_14d >= tiers[t]["volume"]:
|
||
current = t
|
||
return current
|
||
|
||
|
||
# ── Strategy-specific defaults (matching existing classification) ──
|
||
STRATEGY_FEE_MODELS = {
|
||
"Order Book Imbalance": "taker",
|
||
"Iceberg Detection": "taker",
|
||
"Funding Rate Arb": "taker",
|
||
"Pairs Trading": "taker",
|
||
"Avellaneda-Stoikov": "maker",
|
||
"Momentum Breakout": "taker",
|
||
"Mean Reversion": "taker",
|
||
"Hawkes OFI": "taker",
|
||
"Deep LOB": "maker",
|
||
"Cartea-Jaimungal": "maker",
|
||
"Queue Imbalance": "taker",
|
||
"Guéant Market Making": "maker",
|
||
}
|