Files
PythagorasGoal/scripts/research/r0725_ib10k.py
T
Adriano Dal Pastro b1c3ff1bb8 docs(fisco): quadro fiscale verificato sulle fonti — la citazione normativa era sbagliata
Verificato sulle fonti (Fisco Oggi dell'Agenzia, Eutekne, Fiscomania, Circolare AdE 30/E
del 27/10/2023, guide professionali) cio' che il progetto assumeva senza averlo mai
controllato. NON e' un parere fiscale.

CONFERMATO, e nessun numero del piano cambia: 33% sulle plusvalenze cripto realizzate dal
1/1/2026 (art. 67 c.1 lett. c-sexies TUIR); franchigia EUR 2.000 abolita dal 2025;
minusvalenze riportabili 4 periodi ma solo contro plusvalenze cripto (art. 68 c. 9-bis);
patrimoniale 2 per mille sul valore al 31/12; regime dichiarativo per gli exchange esteri.

CORRETTO: il progetto citava «L.199/2025» come origine del 33% in 5 punti (r0725_capcurve,
r0725_ib10k x2, r0727_tasse, r0807_asset_compare, diario 24/07). E' falso. Il 33% dal 2026
e l'abolizione della franchigia vengono dalla L. 207/2024 art. 1 c. 23-29. La L. 199/2025
art. 1 c. 28 ritaglia il 26% per i soli token e-money denominati in EURO: BTC/ETH e le
stablecoin in dollari restano al 33%.

RESTA APERTA la domanda che vale $22k di muro: la Circolare 30/E non tratta i derivati, e
le fonti professionali collocano i derivati su cripto fuori dalle cripto-attivita'
(c-quater, RT Sez. II, 26%) — ma parlando di CFD di broker UE regolati in euro, non di
contratti inverse marginati e regolati IN CRIPTO su sede extra-UE. Registrata la domanda
da porre al commercialista nei termini esatti.

Trovata per strada una conseguenza modellistica: se i derivati sono c-quater, sono un
comparto di compensazione separato → il buffer di carry UNICO di r0807_piano_netto e
r0727_tasse e' ottimistico sulla coda (non sull'aliquota).

REGOLA: una fonte normativa citata in un commento di codice si verifica come un numero —
questa era sbagliata da settimane in 5 file e nessun test poteva accorgersene.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 19:51:50 +00:00

218 lines
11 KiB
Python

"""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. 207/2024) -> 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. 207/2024 art. 1 c.23-29, 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()