chore(reset): v2.0.0 — storico certificato Deribit mainnet, ripartenza pulita

Reset del progetto su fondamenta verificate dopo la scoperta che l'intera
libreria "validata OOS" era artefatto di feed contaminato (print fantasma del
feed Cerbero TESTNET + storico Binance/USDT).

- Storico ricostruito da Deribit MAINNET (ccxt pubblico, tokenless) e
  CERTIFICATO (certify_feed.py): BTC/ETH puliti su TUTTA la storia
  (mediana 2-6 bps vs Coinbase USD), integrita' OHLC + coerenza resample
  (maxΔ 0.00) + cross-venue OK. Alt esclusi (illiquidi/divergenti: LTC/DOGE
  50-82% barre flat; XRP/BNB non certificabili).
- Verdetto sul feed pulito: FADE / PAIRS / XS01 / TSM01 morti (ogni
  portafoglio Sharpe -2.3..-3.0, DD ~40%); solo SH01 e frammenti HONEST
  con segnale residuo, da ri-validare in isolamento.
- Cleanup "restart pulito": strategie, stack live (src/live, src/portfolio,
  runner/executor, yml, docker), ~100 script ricerca/gate, waste/games/
  portfolios, dati non certificati + cache e 60+ diari -> archiviati in Old/
  (preservati, non cancellati). Diario consolidato in un unico documento.
- Skeleton ricerca tenuto: Strategy ABC + indicatori + src/fractal +
  src/backtest/engine + load_data; tool dati certificati (rebuild_history,
  certify_feed, audit_feed, multi_source_check).
- Universo dati ATTIVO: solo BTC/ETH (5m/15m/1h); guardrail fisico
  (load_data su alt -> FileNotFoundError). Esecuzione DISABILITATA, conto flat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-19 15:16:03 +00:00
parent 8401a280b9
commit 14522262e6
383 changed files with 1971 additions and 779 deletions
+164
View File
@@ -0,0 +1,164 @@
"""S2-06: Iron Condor simulato + Variance Risk Premium harvesting.
Vendi un range: se il prezzo sta dentro il range a scadenza → profitto.
Più sofisticato del vol selling puro:
- Calcolo IV vs RV (variance risk premium)
- Selezione larghezza condor in base a IV/RV ratio
- Dynamic position sizing: più capital quando IV/RV ratio è alto
- Ingresso giornaliero, scadenze 24h e 48h
- Include: tail risk protection (chiudi se move > 2 ATR)
"""
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
def realized_vol_ann(close: np.ndarray, window: int) -> np.ndarray:
log_ret = np.diff(np.log(np.where(close == 0, 1e-10, close)))
result = np.full(len(close), 0.5)
for i in range(window, len(log_ret)):
result[i + 1] = np.std(log_ret[i - window : i]) * np.sqrt(24 * 365)
return result
def run_iron_condor(asset, tf="1h"):
print(f"\n{'#'*60}")
print(f" {asset} {tf} — IRON CONDOR / VARIANCE PREMIUM")
print(f"{'#'*60}")
df = load_data(asset, tf)
close = df["close"].values
high = df["high"].values
low = df["low"].values
n = len(close)
split = int(n * 0.7)
timestamps = pd.to_datetime(df["timestamp"], unit="ms", utc=True)
rv_24 = realized_vol_ann(close, 24)
rv_48 = realized_vol_ann(close, 48)
rv_168 = realized_vol_ann(close, 168) # 1 week
IV_PREMIUM = 1.25 # IV typically 1.2-1.3x RV in crypto
configs = [
# (dte_hours, condor_width_mult, max_loss_pct, vrp_min, pos_pct, name)
(24, 1.0, 0.03, 1.10, 0.15, "24h_1x_std"),
(24, 1.5, 0.04, 1.10, 0.12, "24h_1.5x_safe"),
(24, 0.8, 0.025, 1.15, 0.18, "24h_0.8x_aggr"),
(48, 1.0, 0.035, 1.10, 0.15, "48h_1x_std"),
(48, 1.5, 0.05, 1.10, 0.12, "48h_1.5x_safe"),
(48, 0.7, 0.025, 1.20, 0.20, "48h_0.7x_highVRP"),
(72, 1.2, 0.04, 1.10, 0.12, "72h_1.2x"),
(24, 1.0, 0.03, 1.30, 0.20, "24h_veryHighVRP"),
(24, 1.2, 0.035, 1.10, 0.15, "24h_1.2x_balanced"),
]
for dte, width_mult, max_loss, vrp_min, pos_pct, name in configs:
capital = float(INITIAL)
correct = 0
total = 0
daily_trades = {}
max_dd = 0
peak = capital
for i in range(max(split, 170), n - dte):
day = timestamps.iloc[i].strftime("%Y-%m-%d")
if daily_trades.get(day, 0) >= 1:
continue
hour = timestamps.iloc[i].hour
if hour != 8:
continue
rv_short = rv_24[i]
rv_long = rv_168[i]
if rv_short <= 0 or rv_long <= 0:
continue
iv_est = rv_long * IV_PREMIUM
vrp_ratio = iv_est / rv_short
if vrp_ratio < vrp_min:
continue
spot = close[i]
t_years = dte / (24 * 365)
# Condor range: spot ± width * daily_std * sqrt(t)
daily_std = rv_short / np.sqrt(365)
range_width = width_mult * daily_std * np.sqrt(dte / 24) * spot
upper_strike = spot + range_width
lower_strike = spot - range_width
# Premium collected (simplified BS for condor)
# Premium ≈ IV * sqrt(t) * (width factor)
premium_pct = iv_est * np.sqrt(t_years) * 0.4 * (1 / width_mult)
# Check if price stays in range
exit_idx = min(i + dte, n - 1)
price_path = close[i : exit_idx + 1]
max_move = max(np.max(price_path) - spot, spot - np.min(price_path))
final_price = close[exit_idx]
in_range = lower_strike <= final_price <= upper_strike
breached_hard = max_move > spot * max_loss
if breached_hard:
pnl_pct = -max_loss * pos_pct
elif in_range:
pnl_pct = premium_pct * pos_pct
else:
# Partial loss: exceeded range but not catastrophic
excess = max(0, final_price - upper_strike, lower_strike - final_price)
loss = min(excess / spot, max_loss)
pnl_pct = (premium_pct - loss) * pos_pct
fee_cost = FEE * 2 * pos_pct
net_pnl = pnl_pct - fee_cost
capital += capital * net_pnl
capital = max(capital, 0)
if capital > peak:
peak = capital
dd = (peak - capital) / peak if peak > 0 else 0
max_dd = max(max_dd, dd)
total += 1
if net_pnl > 0:
correct += 1
daily_trades[day] = daily_trades.get(day, 0) + 1
if total < 20:
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 >= 70 and ann >= 50 else "" if acc >= 65 and ann >= 30 else ""
print(f" {name:22s}: trades={total:4d} acc={acc:.1f}% ret={ret:+.1f}% ann={ann:+.1f}% dd={max_dd*100:.1f}% €/day={dpnl:.2f} active={days_active} {tag}")
for asset in ["ETH", "BTC"]:
run_iron_condor(asset)
# === COMBINAZIONE: Iron Condor + Funding + Gap Fade ===
print(f"\n{'#'*60}")
print(f" COMBINAZIONE: MULTI-STRATEGY PORTFOLIO")
print(f"{'#'*60}")
# Simula portafoglio: 50% iron condor ETH, 25% iron condor BTC, 25% gap fade ETH
print(" (Dettagli nel prossimo script con backtest combinato)")