Add Hyperliquid fee tier selector — 7 VIP levels × 7 staking tiers

config/fee_tiers.py: complete Hyperliquid fee schedule with perps and spot
base rates plus staking discount multipliers. effective_rate() computes
the actual fee after staking discount. get_perp_fees() returns the
effective rate for a given VIP tier, staking tier, and fee model.

Backtest runner: added --fee-tier (0-6) and --staking-tier flags.
Regenerated all 12 backtests at VIP 0 baseline. Runner now shows fee tier
info at startup.

Server: /api/backtest/{name}/recalc endpoint accepts ?fee_tier=X&staking_tier=Y
and returns recalculated PnL with the new fee structure. On-the-fly
recalculation — no need to re-run the backtest.

Dashboard: VIP tier dropdown (VIP 0-6) and staking tier dropdown
(None/Wood/Bronze/Silver/Gold/Platinum/Diamond) in backtest detail panel.
Changing either instantly recalculates PnL via the API.

Key finding: Cartea-Jaimungal goes from -5.58% net at VIP0 to +2.39% net
at VIP6+Diamond (maker rebate: exchange pays YOU -0.0024% to provide
liquidity). Fee structure completely changes strategy viability assessment.
This commit is contained in:
ramseshk
2026-08-04 07:26:40 +00:00
parent ecfdd56d8f
commit 0c0d2124ad
16 changed files with 45910 additions and 6 deletions
+13 -4
View File
@@ -7,6 +7,7 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from common.metrics import sharpe, sortino, max_drawdown, win_rate
from config.fee_tiers import get_perp_fees, PERPS_TIERS, STAKING_TIERS
RESULTS_DIR = Path(__file__).resolve().parent / "results"
os.makedirs(RESULTS_DIR, exist_ok=True)
@@ -30,14 +31,15 @@ CONFIGS = {
"gueant": {"name":"Guéant Market Making","desc":"Closed-form asymptotic MM — adverse selection handling","alloc":100.0,"daily_ret":0.0018,"daily_vol":0.005,"fee_model":"maker"},
}
def simulate(key, periods=720, include_fees=True):
def simulate(key, periods=720, include_fees=True, fee_tier=0, staking_tier="none"):
# Deterministic seed per strategy (hash() is randomized per Python process)
_fixed_seeds = {"ofi":42,"iceberg":43,"funding_arb":44,"pairs":45,"avellaneda":46,
"momentum":47,"mean_rev":48,"hawkes":49,"deep_lob":50,
"cartea":51,"queue_imb":52,"gueant":53}
random.seed(_fixed_seeds.get(key, 42))
cfg = CONFIGS[key]
fee_rate = MAKER_FEE if cfg.get("fee_model") == "maker" else TAKER_FEE
fee_model = cfg.get("fee_model", "taker")
fee_rate = get_perp_fees(fee_tier, staking_tier, fee_model)
hr = cfg["daily_ret"]/24; hv = cfg["daily_vol"]/(24**0.5)
eq_gross=100.0; eq_net=100.0; curve_gross=[]; curve_net=[]; rets=[]; trades=[]
total_fees=0.0
@@ -92,16 +94,23 @@ def main():
p=argparse.ArgumentParser()
p.add_argument("--strategy","-s",choices=list(CONFIGS)+["all"],default="all")
p.add_argument("--no-fees",action="store_true",help="Exclude simulated fees from PnL")
p.add_argument("--fee-tier",type=int,default=0,choices=range(7),help="VIP fee tier 0-6 (default: 0)")
p.add_argument("--staking-tier",default="none",choices=list(STAKING_TIERS.keys()),help="Staking discount tier (default: none)")
a=p.parse_args()
keys=list(CONFIGS) if a.strategy=="all" else [a.strategy]
include_fees=not a.no_fees
ft_info = PERPS_TIERS[a.fee_tier]
st_info = STAKING_TIERS[a.staking_tier]
print("="*60)
print(f" FTDT Quant Lab — Backtest Runner ({len(keys)} strategies)")
print(f" Fees: {'INCLUDED (default)' if include_fees else 'EXCLUDED (--no-fees)'}")
print(f" Fee Tier: {ft_info['name']} (taker={ft_info['taker']*100:.3f}%, maker={ft_info['maker']*100:.3f}%)")
print(f" Staking: {st_info['name']} ({st_info['multiplier']*100:.0f}% multiplier)")
print(f" Effective taker: {get_perp_fees(a.fee_tier,a.staking_tier,'taker')*100:.4f}%")
print(f" Effective maker: {get_perp_fees(a.fee_tier,a.staking_tier,'maker')*100:.4f}%")
print("="*60)
for k in keys:
cfg=CONFIGS[k]; print(f"\n Running: {cfg['name']}...")
r=simulate(k, include_fees=include_fees); save(r)
r=simulate(k, include_fees=include_fees, fee_tier=a.fee_tier, staking_tier=a.staking_tier); save(r)
print(f" Net PnL: {r['pnl_pct']:+.2f}% | Gross: {r['pnl_gross_pct']:+.2f}% | Fees: ${r['fees_total']:.2f} | Sharpe: {r['sharpe']:.2f} | Win: {r['win_rate']:.0%}")
print("\n"+"="*60); print(" Results in backtests/results/"); print(" View at: https://ftdt.io/cv (Backtest tab)"); print("="*60)