feat(strategy2): 7 strategie esotiche — VRP harvesting 90.5% acc, 274% ann, €29/day
Strategie testate: - Mean reversion oraria: edge minimo - Funding rate proxy: edge minimo - Vol selling (straddle): 72% acc, 82% ann ✅ - Momentum 5m: fallita (20% acc) - Gap fade sessione: edge moderato ETH - Iron condor: non funziona simulato - VRP refined: 88-90% acc, 200-325% ann, DD 1.6-2.5% ✅✅ Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user