160ad300be
- deribit_book_sleeves(): TP01 75% + SKH01 25% — the two directional BTC/ETH legs on ONE venue (Deribit), both since 2019. Excludes XS01 (Hyperliquid/stat-mode) & VRP01 (modeled options). FULL Sharpe 1.78 / HOLD 1.17 / DD 9.4% (research). - rebalance_sim(): realistic PERIODIC rebalancing (drift between dates, turnover cost at Deribit-taker ~5bps/side) vs the idealized continuous rebalance of combined_daily. period=1 + cost=0 reduces to continuous (tested). - run_deribit_book.py: report — continuous vs weekly/biweekly/monthly rebal, per-year, accumulation €2k & $600-real, min-order $5 note. Finding: turnover is LOW (0.2-0.4x/yr), so monthly rebal (€7,919) ~= continuous (€7,938) — cost is negligible; daily would be sub-min-order fiction at $600 -> use >= weekly. - +2 tests (rebalance_sim continuity & cost). Full suite green. TP01 is the only live-armed leg; SKH01 is the candidate 2nd leg (validate execution code first). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
87 lines
3.9 KiB
Python
87 lines
3.9 KiB
Python
"""REPORT del BOOK DERIBIT-ONLY realmente eseguibile = TP01 + SKH01 (75/25).
|
||
|
||
Le due gambe direzionali BTC/ETH sullo STESSO venue (Deribit), entrambe dal 2019. Esclude XS01
|
||
(Hyperliquid, stat-mode) e VRP01 (opzioni modellate). Mostra:
|
||
1. metriche oneste continuo (rebalance-continuo) vs RIBILANCIAMENTO PERIODICO realistico
|
||
(settimanale/mensile) con costo turnover Deribit-taker;
|
||
2. per-anno, accumulo da €2k (e nota €600 reale + min-order $5);
|
||
3. posizioni correnti per gamba.
|
||
|
||
uv run python scripts/portfolio/run_deribit_book.py
|
||
"""
|
||
from __future__ import annotations
|
||
import sys
|
||
from pathlib import Path
|
||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||
sys.path.insert(0, str(PROJECT_ROOT))
|
||
import numpy as np
|
||
|
||
from src.portfolio.portfolio import StrategyPortfolio, metrics, yearly, rebalance_sim, HOLDOUT
|
||
|
||
CAP = 2000.0
|
||
REAL = 600.0 # capitale reale (vedi CLAUDE.md), min-order Deribit $5
|
||
COST_RATE = 0.0005 # Deribit taker per-lato (~0.10% RT sul turnover netto)
|
||
|
||
|
||
def line(tag, daily, extra=""):
|
||
m = metrics(daily); h = metrics(daily[daily.index >= HOLDOUT])
|
||
eqf = CAP * float(np.prod(1.0 + daily.values))
|
||
print(f" {tag:<26} FULL Sh {m['sharpe']:.2f} ret {m['ret']*100:+.0f}% DD {m['maxdd']*100:.1f}% "
|
||
f"| HOLD Sh {h['sharpe']:.2f} DD {h['maxdd']*100:.1f}% | €2k→€{eqf:,.0f} {extra}")
|
||
return m, h
|
||
|
||
|
||
def main():
|
||
from src.portfolio.sleeves import deribit_book_sleeves
|
||
sleeves = deribit_book_sleeves()
|
||
pf = StrategyPortfolio(sleeves, capital=CAP)
|
||
w = pf.weights()
|
||
cols = {s.name: s.daily() for s in sleeves}
|
||
|
||
print("=" * 100)
|
||
print(f" BOOK DERIBIT-ONLY (eseguibile) — {' + '.join(f'{k} {v*100:.0f}%' for k, v in w.items())} "
|
||
f"| capitale €{CAP:,.0f} (reale ≈ ${REAL:,.0f}) | hold-out {HOLDOUT.date()}+")
|
||
print("=" * 100)
|
||
|
||
# standalone per-gamba
|
||
print("\n PER-GAMBA (standalone):")
|
||
for s in sleeves:
|
||
d = s.daily(); m = metrics(d); h = metrics(d[d.index >= HOLDOUT])
|
||
print(f" {s.name:<16} [{w[s.name]*100:>3.0f}%] FULL Sh {m['sharpe']:.2f} DD {m['maxdd']*100:.0f}% "
|
||
f"| HOLD Sh {h['sharpe']:.2f} DD {h['maxdd']*100:.0f}%")
|
||
|
||
print("\n COMBINATO — rebalance-CONTINUO (idealizzato, no costi) vs PERIODICO (reale, costo turnover):")
|
||
cont = pf.combined_daily()
|
||
line("continuo (no costo)", cont)
|
||
sims = {}
|
||
for tag, period in (("settimanale (7g)", 7), ("bisettimanale (14g)", 14), ("mensile (30g)", 30)):
|
||
sim = rebalance_sim(cols, w, period_days=period, cost_rate=COST_RATE)
|
||
sims[tag] = sim
|
||
line(f"rebal {tag}", sim["daily"], extra=f"| turnover {sim['turnover_per_year']:.1f}×/anno, {sim['n_rebalances']} ribilanci")
|
||
|
||
# raccomandato = mensile
|
||
rec = sims["mensile (30g)"]["daily"]
|
||
print("\n PER ANNO (rebal mensile, netto costo):")
|
||
for y, d in yearly(rec).items():
|
||
print(f" {y}: ret {d['ret']*100:>+7.1f}% DD {d['dd']*100:>5.1f}%")
|
||
|
||
print("\n ACCUMULO (rebal mensile):")
|
||
for cap, lbl in ((CAP, "€2k nominale"), (REAL, "$600 reale")):
|
||
eq = cap * np.cumprod(1.0 + rec.values)
|
||
yrs = len(rec) / 365.25
|
||
print(f" {lbl:<14}: {cap:,.0f} → {eq[-1]:,.0f} (×{eq[-1]/cap:.1f}, ~{(eq[-1]-cap)/(yrs*365.25):+,.2f}/g)")
|
||
|
||
print("\n POSIZIONI CORRENTI (ultima barra chiusa):")
|
||
for name, pos in pf.current_positions().items():
|
||
print(f" {name}: {pos if pos is not None else 'segnale dual-TF (no pos-fn) — vedi engine'}")
|
||
|
||
print("\n NOTE ONESTE:")
|
||
print(" · TP01 = unico armato live su Deribit (flat=risk-off). SKH01 = 2a gamba candidata (perp BTC/ETH).")
|
||
print(" · SKH01 equity daily-step (Sharpe lens). A $600 il min-order è $5: un ribilancio mensile")
|
||
print(" muove abbastanza nozionale da eseguirsi; il giornaliero NO (Δ sub-$5 = finzione) → usa ≥ settimanale.")
|
||
print(" · Prima del deploy 2a gamba: validare causalità sul CODICE D'ESECUZIONE reale e costi del book a 230m.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|