"""r0725_ib10k — E SE METTO 10K SU IB? Lo split ottimale Deribit/IB (2026-07-25). Domanda dell'operatore, posta dopo l'ondata rendita: "se metto 10K in IB?". Non e' una domanda su GTAA01: e' una domanda di ALLOCAZIONE FRA DUE VENUE, e le due gambe hanno profili opposti: * DERIBIT (TP01+SKH01): Sharpe ~0.98 de-luck, CAGR ~11%, vol 11.4% — e' il MOTORE di reddito. * IB (GTAA01): Sharpe ~0.6, CAGR ~3.5-5%, vol ~7% — e' un DIVERSIFICATORE (corr ~+0.10), e a $600 era negativo per il pavimento di commissione; a $10k il pavimento diventa trascurabile (0.02% per ordine invece dell'1-3%) -> **il deposito SBLOCCA lo sleeve**. Tre effetti che si sommano e che vanno contati INSIEME: 1. sblocco di GTAA01 (il pavimento IB smette di mordere); 2. spostamento del baricentro su un venue a CAGR basso (se ci va TUTTO, il reddito CALA); 3. **fisco diverso**: plusvalenze ETF 26% vs crypto 33% (L.199/2025) -> un euro lordo su IB vale il 10% in piu' netto di un euro lordo su Deribit. (+ pavimento alternativo: la liquidita' IB non investita rende interesse ~2% EUR / ~4% USD.) Output: la curva dello split, giudicata su TRE metriche diverse perche' danno risposte diverse — reddito atteso netto, rendita perpetua (preservazione del capitale), e reddito a ISO-RISCHIO. ONESTA': (a) SKH01 sul path live, de-luck x0.6 (lente di decisione del progetto); (b) GTAA01 col costo IB REALE (pavimento fisso) e banda/cadenza scelte sul plateau; (c) le aliquote sono l'assunzione dichiarata 26%/33% — da verificare col commercialista, NON un parere fiscale; (d) i numeri di GTAA01 sono su ~30 anni, quelli crypto su ~7. Uso: `uv run python scripts/research/r0725_ib10k.py` """ from __future__ import annotations import sys from pathlib import Path import numpy as np import pandas as pd ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT / "scripts" / "research")) from src.portfolio.portfolio import combine_outer, metrics # noqa: E402 import r0724_skh_live_weight as skl # noqa: E402 from r0725_capcurve import (EURUSD, gtaa_banded, metrics as _m, survival, # noqa: E402 tp01_realistic) TAX_CRYPTO = 0.33 # L.199/2025 dal 1/1/2026 TAX_EQUITY = 0.26 # plusvalenze su ETF (assunzione dichiarata) IB_CASH_RATE = 0.02 # interesse su liquidita EUR non investita (IBKR, sopra $10k) IB_MARGIN_RATE = 0.055 # costo del margine IB in USD (benchmark + spread) — assunzione dichiarata DERIBIT_FUNDING = 0.02 # funding medio dei perp Deribit (ricerca 24/07: ciclo 0-4%/anno) DELUCK = 0.6 DERIBIT_NOW = 600.0 # cio' che c'e' oggi sul conto Deribit BOOK_START = pd.Timestamp("2019-03-14", tz="UTC") def _d(s: pd.Series) -> pd.Series: s = s.dropna().sort_index() if s.index.tz is None: s.index = s.index.tz_localize("UTC") return s def _deluck(s: pd.Series) -> pd.Series: return s - (1.0 - DELUCK) * float(s.mean()) def gtaa_best_band(alloc: float) -> tuple[float, int, dict]: """Config di costo per GTAA al capitale dato, scelta sul PLATEAU (weekly, banda 25-100): non e' un parametro di segnale, si sceglie sul costo e si dichiara.""" best = None for every in (5, 21): for band in (25.0, 50.0, 100.0): if band > alloc / 6: continue m = metrics(gtaa_banded(alloc, band, every)) if best is None or m["sharpe"] > best[2]["sharpe"]: best = (band, every, m) if best is None: # capitale troppo piccolo per una banda best = (1.0, 21, metrics(gtaa_banded(alloc, 1.0, 21))) return best def build(total: float, f_ib: float) -> dict: """Book con frazione f_ib del capitale su IB (GTAA01) e il resto su Deribit (TP01/SKH01).""" a_ib, a_der = total * f_ib, total * (1.0 - f_ib) skh = _d(skl.skh_book(0, "hourly")) cols, w = {}, {} if a_der > 1.0: cols["TP01"] = _deluck(_d(tp01_realistic(a_der * 0.75))) cols["SKH01"] = _deluck(skh) w["TP01"] = (1.0 - f_ib) * 0.75 w["SKH01"] = (1.0 - f_ib) * 0.25 band = every = None if a_ib > 1.0: band, every, _ = gtaa_best_band(a_ib) cols["GTAA01"] = _deluck(_d(gtaa_banded(a_ib, band, every))) w["GTAA01"] = f_ib combo = combine_outer(cols, w, lo=BOOK_START) m = metrics(combo) vol = float(combo.std() * np.sqrt(365)) # fisco misto: la quota IB e' tassata al 26%, la quota Deribit al 33% tax_blend = f_ib * TAX_EQUITY + (1.0 - f_ib) * TAX_CRYPTO eur_day = total * m["cagr"] * (1.0 - tax_blend) / EURUSD / 365.0 return dict(metrics=m, vol=vol, combo=combo, tax=tax_blend, eur_day=eur_day, band=band, every=every, a_ib=a_ib, a_der=a_der) def perp_rate(combo: pd.Series, k: float = 1.0, n: int = 1500) -> float: """Prelievo perpetuo (P(cap a 20a >= cap iniziale) >= 90%).""" r = combo.values.astype(float) lo, hi = 0.0, 0.35 for _ in range(12): mid = (lo + hi) / 2 if survival(r, 1e6, 1e6 * mid, 20, k, n_paths=n)["p10_end"] >= 1e6: lo = mid else: hi = mid return lo def main() -> None: total = DERIBIT_NOW + 10_000.0 * EURUSD # $600 + EUR 10k print("=" * 100) print(f" SE METTO 10K SU IB — capitale totale ${total:,.0f} " f"(= $600 Deribit + EUR 10.000)") print("=" * 100) print(f" fisco assunto: ETF {TAX_EQUITY:.0%} / crypto {TAX_CRYPTO:.0%} | de-luck x{DELUCK} | " f"SKH01 path live") print(f" pavimento alternativo: liquidita' IB non investita ~{IB_CASH_RATE:.0%}/anno EUR " f"= EUR {total/EURUSD*IB_CASH_RATE*(1-TAX_EQUITY)/365:.2f}/g\n") print(f" {'quota su IB':>12} {'GTAA banda':>12} {'Sharpe':>7} {'CAGR':>7} {'vol':>6} " f"{'maxDD':>7} {'fisco':>6} {'EUR/g':>7} {'rendita':>8} {'EUR/g rend.':>12}") rows = [] for f_ib in (0.0, 0.25, 0.50, 0.75, 0.90, 0.94, 1.0): b = build(total, f_ib) pr = perp_rate(b["combo"]) eur_perp = total * pr * (1.0 - b["tax"]) / EURUSD / 365.0 lbl = "—" if b["band"] is None else f"${b['band']:.0f}/{ 'sett' if b['every']==5 else 'mens'}" print(f" {f_ib:>11.0%} {lbl:>12} {b['metrics']['sharpe']:>7.2f} " f"{b['metrics']['cagr']:>7.1%} {b['vol']:>6.1%} {b['metrics']['maxdd']:>7.1%} " f"{b['tax']:>6.0%} {b['eur_day']:>7.2f} {pr:>8.2%} {eur_perp:>12.2f}") rows.append((f_ib, b, pr)) print("\n ('quota su IB' 94% = mettere i 10k su IB e lasciare i $600 dove sono;") print(" 'rendita' = prelievo perpetuo al 90% di preservazione del capitale.)") # --- ISO-RISCHIO: e' qui che un diversificatore a basso CAGR si giudica print("\n" + "-" * 100) print(" A ISO-RISCHIO (ogni split portato a vol 15% con la leva) — il confronto corretto") print("-" * 100) print(f" {'quota su IB':>12} {'leva':>6} {'CAGR iso':>9} {'EUR/g iso':>10} " f"{'rendita iso':>12} {'EUR/g rend.iso':>15}") best = None for f_ib, b, _ in rows: k = min(0.15 / b["vol"], 3.0) pr = perp_rate(b["combo"], k=k) eur = total * b["metrics"]["cagr"] * k * (1.0 - b["tax"]) / EURUSD / 365.0 eur_p = total * pr * (1.0 - b["tax"]) / EURUSD / 365.0 print(f" {f_ib:>11.0%} {k:>6.2f}x {b['metrics']['cagr']*k:>9.1%} {eur:>10.2f} " f"{pr:>12.2%} {eur_p:>15.2f}") if best is None or eur_p > best[1]: best = (f_ib, eur_p, k, pr) print(f"\n -> split che massimizza la RENDITA a iso-rischio: {best[0]:.0%} su IB " f"(leva {best[2]:.2f}x, rendita {best[3]:.2%} = EUR {best[1]:.2f}/g)") # --- ISO-RISCHIO CON VINCOLI DI LEVA REALI ------------------------------- # La leva che l'iso-rischio chiede non e' sempre ottenibile: su IB un conto da EUR 10k ha # Reg-T (2x max sugli ETF); il portfolio margin parte da ~$110k. Su Deribit i perp danno # leva alta. La leva ATTUABILE del book misto e' quindi limitata dalla gamba peggiore. print("\n" + "-" * 100) print(" ISO-RISCHIO CON LEVA ATTUABILE (IB Reg-T 2.0x su ETF; Deribit perp 3.0x)") print("-" * 100) print(f" {'quota su IB':>12} {'leva max':>9} {'leva usata':>11} {'CAGR':>7} " f"{'EUR/g':>7} {'rendita':>9} {'EUR/g rend.':>12}") print(" (COSTO DEL MARGINE INCLUSO: la parte presa a prestito si paga — IB ~5.5%/anno sul") print(" margine USD, Deribit funding perp ~2%/anno medio. Ignorarlo gonfia ogni riga levata.)") print(f" {'quota su IB':>12} {'leva max':>9} {'leva usata':>11} {'CAGR lordo':>11} " f"{'costo leva':>11} {'CAGR netto':>11} {'EUR/g':>7} {'rendita':>9} {'EUR/g rend.':>12}") best2 = None for f_ib, b, _ in rows: k_want = min(0.15 / b["vol"], 3.0) k_max = f_ib * 2.0 + (1.0 - f_ib) * 3.0 # vincolo pesato per venue k = min(k_want, k_max) borrow_rate = f_ib * IB_MARGIN_RATE + (1.0 - f_ib) * DERIBIT_FUNDING fin = max(k - 1.0, 0.0) * borrow_rate # costo sulla quota presa a prestito cagr_gross = b["metrics"]["cagr"] * k cagr_net = cagr_gross - fin pr = max(perp_rate(b["combo"], k=k) - fin, 0.0) # il costo grava anche sul prelievo eur_p = total * pr * (1.0 - b["tax"]) / EURUSD / 365.0 eur = total * cagr_net * (1.0 - b["tax"]) / EURUSD / 365.0 flag = " (leva TAGLIATA)" if k < k_want - 1e-9 else "" print(f" {f_ib:>11.0%} {k_max:>8.2f}x {k:>10.2f}x {cagr_gross:>11.1%} " f"{fin:>11.1%} {cagr_net:>11.1%} {eur:>7.2f} {pr:>9.2%} {eur_p:>12.2f}{flag}") if best2 is None or eur_p > best2[1]: best2 = (f_ib, eur_p, k, pr) print(f"\n -> con leva ATTUABILE E costo del margine il migliore e' {best2[0]:.0%} su IB " f"(leva {best2[2]:.2f}x, rendita {best2[3]:.2%} = EUR {best2[1]:.2f}/g)") # --- il confronto che conta: GTAA vs LIQUIDITA' FERMA --------------------- print("\n" + "-" * 100) print(" IL CONFRONTO ONESTO: GTAA01 sui 10k vs la stessa liquidita' FERMA che prende interesse") print("-" * 100) b94 = [b for f, b, _ in rows if abs(f - 0.94) < 1e-9][0] cash_eur_day = total / EURUSD * IB_CASH_RATE * (1 - TAX_EQUITY) / 365 print(f" 10k investiti in GTAA01 (+ $600 su Deribit) : EUR {b94['eur_day']:.2f}/g " f"maxDD {b94['metrics']['maxdd']:.1%}") print(f" 10k FERMI a interesse ~{IB_CASH_RATE:.0%} (+ $600 Deribit): EUR " f"{cash_eur_day + rows[0][1]['eur_day']*DERIBIT_NOW/total:.2f}/g maxDD ~0%") print(f" -> il premio di GTAA01 sopra la liquidita' e' ~EUR " f"{b94['eur_day'] - cash_eur_day:.2f}/g, pagato con un maxDD del " f"{b94['metrics']['maxdd']:.0%}.") print(" (tasso liquidita' = assunzione dichiarata; un BTP/monetario EUR renderebbe di piu'.)") if __name__ == "__main__": main()