Files
PythagorasGoal/scripts/portfolio/run_deribit_book.py
T
Adriano Dal Pastro 160ad300be feat(portfolio): Deribit-only executable book (TP01+SKH01) + periodic rebalancing
- 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>
2026-06-23 20:26:53 +00:00

87 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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()