Files
PythagorasGoal/scripts/research/r0825_piano_10a_500.py
T
Adriano Dal Pastro ee5c6ed539 ricerca: il piano a 10 anni dal conto vero, l'ETF-quando-flat SCARTATO, slippage rifatto
Giornata partita da "stato trades" e finita sul disegno del sistema. Versamento di
1.400 USDC atterrato alle 11:03:35Z (equity $667,88 -> $2.066,88); il giro delle 11:47
ha ribilanciato correttamente e ha ripiazzato i disaster-SL alla taglia nuova -- prima
volta che il ramo riparato stamattina gira sul serio.

(1) PIANO A 10 ANNI DAL CONTO VERO -- r0825_piano_10a_500.py (nuovo)
Le tabelle pubblicate partono da $600/$635: rifatte su $2.067, lente L3 CONGIUNTA.
Replica superata: chiede EUR 1.718/m dove la tabella da $635 chiedeva EUR 1.733.
EUR 500/mese per 10 anni -> mediana $114.934, rendita 18,35 EUR/g, P(>=50 EUR/g) = 0,0%
su 3.000 traiettorie. Il bersaglio con EUR 500/m arriva al 17o anno.

  L'EQUIVALENZA CHE ORDINA IL PIANO: EUR 100/mese in piu' == +4,07%/anno di drift,
  cioe' +27% su TUTTO il drift del libro. A 10 anni i bonifici fanno il 59%.
  Tutta la leva autorizzabile vale quanto EUR 100-150/mese: k=1,25 (+15,6%) vale MENO
  di EUR 100/mese in piu' (+19,1%), e si porta dietro il peggior giorno al 21,48%.

  E il libro a k=1 rende MENO dell'S&P (15,19% vs 17,40%): il vantaggio sta nello
  Sharpe (1,35 vs 0,89) e senza leva NON si converte in rendimento. Senza leva il libro
  non si giustifica come veicolo di ACCUMULO -- si giustifica come veicolo di RENDITA,
  dove serve 2,5x meno capitale ($254k contro $646k) perche' la perpetua vive sul DD.

(2) "ETF QUANDO IL LIBRO E' FLAT" -- SCARTATO, r0825_capitale_fermo.py (nuovo)
Il libro e' flat il 28,0% dei giorni (2,7% nel 2021, 77,0% nel 2022, 75,6% nel 2026);
live, esposto 14 giorni su 64, leva lorda mediana 0,00x e max 0,52x su un tetto di 1,0x
-- il cap non ha mai morso, il vincolo e' il segnale.
A ISO-RISCHIO il dinamico PERDE: Sharpe 1,01 contro 1,40 del 50/50 e 1,35 del libro. E
il null a maschera casuale (400 estrazioni, stessa quota, blocchi 20g) lo mette al 30o
percentile: fa PEGGIO di commutare a caso.
A iso-nozionale sembrava vincere (drift 17,09%, il piu' alto) perche' aveva la vol piu'
alta: e' la trappola di M6, il de-levering e' il PRIMO test.

  E IL MECCANISMO CHE SEMBRAVA OVVIO NON ESISTE. Aggregato: SPY 4,91% nei giorni flat
  contro 21,48% negli altri (-16,57%), e la storia si scrive da sola. FALSA: scomposta
  per anno il segno ALTERNA (3 su, 4 giu') e il 2022 -- l'anno che doveva reggerla --
  ha il segno OPPOSTO. Artefatto di composizione: i giorni flat stanno negli ANNI brutti
  per l'azionario, non nei GIORNI brutti. M9 ha fatto il suo lavoro su di me.

(3) SLIPPAGE RIFATTO ALLA TAGLIA VERA -- r0822_slip_audit.py riparato
26 fill (erano 18), $6-$319. I due piu' grandi mai eseguiti sono di oggi e hanno preso
1,01% e 0,54% della loro barra 5m, con il print a meta' del range (q=0,50). Il caso
peggiore resta un fill da $74 del 18/07 al 21,9%: un sabato, nastro inesistente.
L'attrito non e' funzione della TAGLIA ma di taglia/volume-della-barra -- l'estrapolazione
lineare che prevedeva ~71% a questo capitale e' refutata dalla misura diretta.
NB non e' "assente", e' "non ancora testato": manca un fill grande in una barra sottile,
e il weekend e' dove TP01 fa il 38% del proprio gross.

  DIFETTO P1 RIPARATO: l'equity era CABLATA a 636.0 con un commento che diceva di
  leggerla dal watermark. Il giorno del versamento avrebbe stampato $636 sbagliando di
  3,3x proprio la sezione che esiste per dire QUANDO la misura scade. Riparata leggendo
  il watermark -- e poi riparata di nuovo, perche' i fill del campione sono stati
  eseguiti a conti diversi ($597-$2.067) e una base sola e' sbagliata comunque la si
  scelga. Ora la normalizzazione e' PER FILL, e a $600 riproduce il 22,0% originale.

DUE ERRORI MIEI, CATTURATI PRIMA DI PUBBLICARLI
- maschera VUOTA vestita da risultato: la prima stesura di r0825_capitale_fermo prendeva
  i giorni flat dalla serie DE-LUCKATA, ma `deluck` sottrae una costante e lo zero esatto
  sparisce -> maschera vuota, dinamico identico al book, e lo script ha stampato tabelle
  piene e un p-value. Lo ha rivelato solo la riga "0 = 0.0%".
  REGOLA: stampare la CARDINALITA' di una maschera prima di usarla.
- il meccanismo falso della (2), demolito dalla scomposizione per anno.

Suite: 730 passati, 1 fallito -- quello gia' noto di 5.9 (deriva dati, non codice).
Watermark del libro live sopravvissuto intatto alla suite (fixture autouse di stamattina).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
2026-08-25 18:13:15 +00:00

154 lines
7.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.
"""r0825_piano_10a_500.py — €500/mese per 10 anni, dal conto VERO di oggi.
DOMANDA (operatore, 2026-08-25): *"dammi strategia a 10 anni con 500 al mese"*.
PERCHE' NON BASTAVA CITARE LA TABELLA. Le tabelle pubblicate del piano partono da **$600/$635**.
Oggi il conto e' **$2.067** (versamento di 1.400 USDC atterrato alle 11:03:35Z). Il lump e' la
leva piu' grande misurata dopo il versamento mensile stesso (*"€10.000 oggi + €250/m porta P(20a)
da 14% a 45%"*), quindi la riga vecchia sottostima il caso di oggi e non si puo' riusare.
LENTE: **L3 CONGIUNTA** di `r0822d_piano_vero` — libro live 75/25, **funding esatto dentro la
serie**, ancora de-luckata x0.89, **fisco d'accumulo** ogni anno dentro il portafoglio (33% sulla
variazione annua di valore, minusvalenze in carry 4 anni, patrimoniale 0,2%). E' la piu' severa
che il progetto abbia, ed e' quella che ha prodotto muro $313k e *"€1.733/mese per 10 anni"*.
⚠️ DIFETTI EREDITATI, dichiarati perche' vanno **a favore del piano** (registrati il 23/08):
1. `PN.accumula` versa ogni **30 giorni** -> a 10 anni sono **121** versamenti, non 120 (+0,83%);
2. il contatore `versato` e' uno **scalare che non si ferma al traguardo** -> il "versato" a
denominatore e' quello dell'INTERO orizzonte, non quello fino all'arrivo.
Non li ho riparati qui: ripararli cambierebbe i numeri di riferimento e li renderebbe non
confrontabili con tutto il resto della memoria. Vanno LETTI, non dimenticati.
⚠️ E IL NUMERO DA NON DIMENTICARE MAI accanto a questi: la SE del drift L3 e' **5,151%/anno**, e
il muro e' `prelievo/perpetua` = un **1/x su una quantita' che va a zero** -> la banda e'
esplosiva e **asimmetrica verso l'alto**: $187k (p90) · **$313k (punto)** · $1,14M (p10) ·
a **2 SE il traguardo non esiste a nessun capitale**. Percio' la regola del progetto:
**il piano si dimensiona sul VERSAMENTO, che e' certo, non sul muro** (N1).
uv run python scripts/research/r0825_piano_10a_500.py
"""
from __future__ import annotations
import sys
from pathlib import Path
import numpy as np
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "scripts" / "research"))
import r0725_capcurve as CC # noqa: E402
import r0807_piano_netto as PN # noqa: E402
import r0822d_piano_vero as PV # noqa: E402
import r0823_deposit_timing as DT # noqa: E402
# --- lo stato VERO di oggi, non un nominale -------------------------------------------------
START_OGGI = 2066.88 # equity Deribit letta alle 11:47:01Z del 2026-08-25
START_PUBBL = PV.START # 635.0 — la base delle tabelle pubblicate, per il confronto
DEP = 500.0 # EUR/mese
ORIZZONTI = (5, 10, 15, 20)
N_PATHS = 3000
SEED = PV.SEED_TRAJ # 725: stesso seme delle traiettorie pubblicate
BLOCK = PV.BLOCK # 20 giorni
def rendita_eur_giorno(cap: np.ndarray, perp: float) -> np.ndarray:
"""€/giorno NETTI da un capitale, alla perpetua della lente.
⚠️ La perpetua L3 (6,35%) ha gia' le imposte dentro: **non si lordizza una seconda volta**
(errore corretto il 07/08)."""
return cap * perp / 365.0 / CC.EURUSD
def main() -> None:
print("=" * 100)
print(" r0825 — €500/MESE PER 10 ANNI, dal conto vero di oggi ($2.067)")
print("=" * 100)
B = PV.costruisci_serie()
r = PV.deluck(B["fund"].values.astype(float)) # L3 CONGIUNTA, ancora x0.89
lente = PV.Lente("L3 congiunta", r, lordizza=False)
lente.perp, lente.muro = PV.muro_di(lente)
print(f"\n serie: {len(r)} giorni · drift {lente.drift:.2%}/anno · vol {lente.vol:.2%}/anno")
print(f" perpetua {lente.perp:.2%} · MURO ${lente.muro:,.0f} "
f"[banda del progetto: $187k (p90) — $1,14M (p10); a 2 SE non esiste]")
print(f" bersaglio di rendita: €{CC.TARGET_EUR_DAY:.0f}/giorno netti")
print(f"\n{'='*100}\n (1) €{DEP:.0f}/MESE DA ${START_OGGI:,.0f} — cosa consegna, per orizzonte"
f"\n{'='*100}")
print(f" {'oriz.':>6} {'capitale mediano':>18} {'p10':>12} {'p90':>13} "
f"{'€/g mediani':>13} {'P(≥50 €/g)':>12} {'versato':>11} {'fin/vers':>9}")
print(" " + "-" * 98)
righe = {}
for anni in ORIZZONTI:
rng = np.random.default_rng(SEED)
ii = DT.boot_idx(len(r), N_PATHS, anni * 365, BLOCK, rng)
paths = r[ii]
out = PN.accumula(paths, DEP, lente.muro, lente.aliq, lente.patr, start=START_OGGI)
cap, versato = out["cap"], out["versato"]
eur = rendita_eur_giorno(cap, lente.perp)
p50 = float((eur >= CC.TARGET_EUR_DAY).mean())
righe[anni] = dict(med=np.median(cap), eur=np.median(eur), p50=p50, versato=versato)
print(f" {anni:>4}a ${np.median(cap):>16,.0f} ${np.percentile(cap,10):>10,.0f} "
f"${np.percentile(cap,90):>11,.0f} {np.median(eur):>12.2f} {p50:>11.1%} "
f"${versato:>9,.0f} {np.median(cap)/versato:>8.2f}x")
print(f"\n{'='*100}\n (2) COSA HA COMPRATO IL VERSAMENTO DI OGGI — $635 (tabelle pubbl.) vs "
f"$2.067 (reale)\n{'='*100}")
print(f" {'oriz.':>6} {'da $635':>14} {'da $2.067':>14} {'guadagno':>11} "
f"{'€/g da $635':>13} {'€/g da $2.067':>15}")
print(" " + "-" * 78)
for anni in ORIZZONTI:
rng = np.random.default_rng(SEED)
ii = DT.boot_idx(len(r), N_PATHS, anni * 365, BLOCK, rng)
paths = r[ii]
a = PN.accumula(paths, DEP, lente.muro, lente.aliq, lente.patr, start=START_PUBBL)["cap"]
b = PN.accumula(paths, DEP, lente.muro, lente.aliq, lente.patr, start=START_OGGI)["cap"]
ea, eb = rendita_eur_giorno(a, lente.perp), rendita_eur_giorno(b, lente.perp)
print(f" {anni:>4}a ${np.median(a):>12,.0f} ${np.median(b):>12,.0f} "
f"{np.median(b)/np.median(a)-1:>10.1%} {np.median(ea):>12.2f} {np.median(eb):>14.2f}")
print(f"\n{'='*100}\n (3) QUANDO ARRIVA IL BERSAGLIO (€50/g = ${lente.muro:,.0f})"
f"\n{'='*100}")
rng = np.random.default_rng(SEED)
ii = DT.boot_idx(len(r), N_PATHS, 25 * 365, BLOCK, rng)
paths25 = r[ii]
for dep in (0, 250, 500, 800, 1_000):
out = PN.accumula(paths25, float(dep), lente.muro, lente.aliq, lente.patr,
start=START_OGGI)
d = PV.leggi(out["colpito"], anni_sim=25)
med = "mai" if not np.isfinite(d["med"]) else f"{d['med']:.1f}a"
cond = "n/d" if not np.isfinite(d["med_cond"]) else f"{d['med_cond']:.1f}a"
print(f" €{dep:>5}/m -> mediana {med:>6} (condizionata all'arrivo {cond:>6}, "
f"arriva il {d['p_arr']:.0%}) · P(entro 20a) {d['p20']:>5.0%}")
print(f"\n{'='*100}\n (4) IL VERSAMENTO CHE SERVE DAVVERO PER €50/g, da ${START_OGGI:,.0f}"
f"\n{'='*100}")
for anni in (10, 15, 20):
rng = np.random.default_rng(PV.SEED_DEP)
ii = DT.boot_idx(len(r), PV.N_DEP, anni * 365, BLOCK, rng)
p = r[ii]
riga = []
for conf in (0.50, 0.75, 0.90):
d, tot = PV.dep_per_conf(p, lente, conf, start=START_OGGI)
riga.append(f"P={conf:.0%}: €{d:,.0f}/m" + (f" (tot ${tot:,.0f})" if conf == 0.90 else ""))
print(f" {anni:>2} anni -> " + " · ".join(riga))
print(f"\n{'='*100}\n VERDETTO (calcolato a runtime, non scritto a mano)\n{'='*100}")
d10 = righe[10]
print(f" €500/mese per 10 anni da ${START_OGGI:,.0f}:")
print(f" capitale mediano ${d10['med']:,.0f} · rendita mediana {d10['eur']:.2f} €/giorno")
print(f" P(≥50 €/g a 10 anni) = {d10['p50']:.1%}")
print(f" versato ${d10['versato']:,.0f} -> il rendimento fa il "
f"{max(0.0, 1 - d10['versato']/d10['med']):.0%} del risultato, i bonifici il resto")
verdetto = ("CENTRA" if d10["p50"] >= 0.5 else "NON CENTRA")
print(f"\n => a 10 anni €500/mese {verdetto} il bersaglio €50/giorno.")
print(f" => quello che centra a 10 anni sta nella sezione (4); quello che €500/mese centra,")
print(f" e quando, sta nella (3).")
if __name__ == "__main__":
main()