"""S2-02: Funding Rate Strategy. Quando il funding rate è molto positivo → troppi long → short il perpetual. Quando molto negativo → troppi short → long il perpetual. Si cattura sia il mean reversion del prezzo che il funding rate stesso. Ingresso: quando funding > 0.03% o < -0.03% (8h rate). """ from __future__ import annotations import sys sys.path.insert(0, ".") import numpy as np import pandas as pd from src.data.downloader import load_data FEE = 0.001 INITIAL = 1000 LEVERAGE = 3 def simulate_funding_strategy(asset): """Simula funding rate strategy usando il proxy: overnight returns. Crypto funding settlement ogni 8h → prezzo tende a correggersi dopo settlement. Proxy: se ultime 8h hanno avuto forte trend, aspettati reversal dopo settlement. """ print(f"\n{'#'*60}") print(f" {asset} — FUNDING RATE PROXY STRATEGY") print(f"{'#'*60}") df_1h = load_data(asset, "1h") close = df_1h["close"].values volume = df_1h["volume"].values n = len(close) split = int(n * 0.7) timestamps = pd.to_datetime(df_1h["timestamp"], unit="ms", utc=True) hours = timestamps.dt.hour.values # Funding settlement su Deribit: 00:00, 08:00, 16:00 UTC settlement_hours = {0, 8, 16} configs = [ (0.01, 0.02, 8, 0.02, "mild_1pct"), (0.015, 0.025, 8, 0.015, "moderate_1.5pct"), (0.02, 0.03, 8, 0.015, "strong_2pct"), (0.01, 0.015, 4, 0.01, "fast_1pct_4h"), (0.02, 0.03, 12, 0.02, "slow_2pct_12h"), (0.025, 0.04, 6, 0.015, "extreme_2.5pct"), ] for entry_thr, tp_mult_unused, hold_max, stop, name in configs: capital = float(INITIAL) correct = 0 total = 0 daily_trades = {} for i in range(max(split, 8), n - hold_max): hour = hours[i] if hour not in settlement_hours: continue day = timestamps[i].strftime("%Y-%m-%d") if daily_trades.get(day, 0) >= 1: continue # 8h return prima del settlement = proxy per funding pressure ret_8h = (close[i] - close[i - 8]) / close[i - 8] # Volume spike = conferma vol_avg = np.mean(volume[max(0, i - 48) : i]) vol_recent = np.mean(volume[i - 8 : i]) vol_spike = vol_recent / vol_avg if vol_avg > 0 else 1 direction = None if ret_8h > entry_thr and vol_spike > 1.1: direction = "short" # troppi long, attendi reversal elif ret_8h < -entry_thr and vol_spike > 1.1: direction = "long" # troppi short, attendi rimbalzo if direction is None: continue entry_price = close[i] for j in range(i + 1, min(i + hold_max + 1, n)): price = close[j] if direction == "long": pnl_pct = (price - entry_price) / entry_price else: pnl_pct = (entry_price - price) / entry_price if pnl_pct <= -stop or pnl_pct >= stop * 2 or j == min(i + hold_max, n - 1): exit_price = price break else: exit_price = close[min(i + hold_max, n - 1)] if direction == "long": trade_ret = (exit_price - entry_price) / entry_price else: trade_ret = (entry_price - exit_price) / entry_price # Add funding rate income (approx 0.01% per 8h period if direction correct) funding_income = 0.0001 * (hold_max / 8) if trade_ret > 0 else 0 net = (trade_ret + funding_income) * LEVERAGE - FEE * 2 * LEVERAGE capital += capital * 0.2 * net capital = max(capital, 0) total += 1 if trade_ret > 0: correct += 1 daily_trades[day] = daily_trades.get(day, 0) + 1 if total < 10: continue acc = correct / total * 100 ret = (capital - INITIAL) / INITIAL * 100 test_days = (n - split) / 24 test_years = test_days / 365.25 ann = ((capital / INITIAL) ** (1 / test_years) - 1) * 100 if test_years > 0 and capital > 0 else -100 dpnl = (capital - INITIAL) / test_days if test_days > 0 else 0 days_active = len(daily_trades) tag = "✅" if acc >= 60 and ann >= 30 else "" print(f" {name:20s}: trades={total:4d} acc={acc:.1f}% ret={ret:+.1f}% ann={ann:+.1f}% €/day={dpnl:.2f} active_days={days_active} {tag}") for asset in ["ETH", "BTC"]: simulate_funding_strategy(asset)