Files
Adriano Dal Pastro 8c0b5f97ee registro: chiusi §58-69 — dodici verdetti, 0 candidati, e due appoggi tolti a decisioni gia' prese
I dodici filoni della sesta ondata erano rimasti `_in corso_`: la sessione si e'
chiusa dopo che gli agenti avevano scritto gli script e prima che i verdetti
fossero consolidati, e i loro messaggi finali sono persi. I numeri qui NON
vengono da quei messaggi: vengono dalla riesecuzione dei dodici script
(07:38-08:06 UTC, sequenziale, log in logs/r0823b/ che e' gitignored).
E' il motivo per cui l'ondata non e' andata persa: ogni script calcola il
proprio verdetto a runtime.

Cosa tocca decisioni gia' prese:
- §67 il gate pre-registrato XSR01 del 23/10 legge un monitor tarato sul
  pavimento del venue sbagliato (C* $15-20k, non ~$3k)
- §64 la raccomandazione di §51 (raccogliere la catena USDC) non e'
  giustificata dalla ragione che porta: le due superfici sono la stessa
- §60 la politica MISTO scelta il 25/07 non e' piu' l'ottimo (oggi MISTO-A)
- §63 domanda fiscale NUOVA, diversa da quella aperta il 07/08

Il risultato piu' grande e' di §58: l'obiettivo del progetto ha DUE definizioni
operative in uso che danno 33,9% contro 0,33% sulla stessa domanda, e non era
mai stato detto quale si stesse ottimizzando.

r0823b_quasi_passati.py (§68) terminava con IndexError: Griglia.combo()
indicizzava con self.idx (2720 giorni) un sottoinsieme di 958 righe. Corretto
col parametro idx esplicito piu' un controllo di lunghezza; la
rinormalizzazione e' riga per riga, quindi i valori sono quelli dell'intento
dell'autore. La correzione e' del coordinatore, non dell'autore, ed e'
dichiarata nel registro.

Libro, pesi, cron, config INVARIATI. Nessun ordine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 12:40:30 +00:00

785 lines
43 KiB
Python

"""r0823b_split_deposito — §62 SPLIT-DEPOSITO: quanta parte del versamento va ai BIGLIETTI (2026-08-23).
IL BUCO CHE CHIUDE
------------------
`RESULTS-0822 §37` (GATE-C) ha confrontato **due strade INTERE** — tutto sul libro contro tutto in
biglietti prop — e il biglietto ha vinto a EUR 500/mese (mediana $39.820 contro $22.444,
P(>=50/g) 13,7% contro 0,0%). Ma **«tutto o niente» non e' una politica: e' un caso limite.**
Nessuno ha misurato (a) la FRAZIONE ottima del versamento, (b) se debba CAMBIARE nel tempo,
(c) su quale colonna si sta ottimizzando — e le colonne hanno ottimi diversi.
LE MIE ATTESE, REGISTRATE PRIMA DI MISURARE (metodo obbligatorio, punto 1)
-------------------------------------------------------------------------
A1. **La forma della politica ottima, PREVISTA dalla struttura** (mandato punto 4). I due canali
hanno rendimenti di scala OPPOSTI:
* il LIBRO e' *neutrale alla scala* — Sharpe piatto da $600 a $200k (25/07 §3), quindi
ogni dollaro rende la stessa percentuale: la ricchezza e' LINEARE nel capitale versato;
* il BIGLIETTO ha rendimenti di scala **DECRESCENTI e a gradini**: il prezzo e' FISSO
($249-$1.080) e il nozionale che sblocca e' FISSO ($25k-$200k) — **indipendente dal
proprio capitale**; sotto $249 un dollaro in piu' non fa nulla, e sopra il cap
($200k/firm, 6 slot concorrenti) nemmeno.
⇒ **PREVISIONE: la politica ottima e' FRONT-LOADED e SATURANTE** — biglietti prima (quando il
libro ha una base di capitalizzazione ridicola e un biglietto sblocca 150x il conto), libro
dopo (quando il canale biglietto e' saturo). Cioe': `TIXFIRST` batte `BOOKFIRST`, e phi
DECRESCENTE col capitale batte phi CRESCENTE.
A2. **Gli ottimi delle tre colonne NON coincidono**: P(>=50/g) crescente in phi con argmax a
phi=1 (a 36-60 mesi **solo** il canale biglietto puo' produrre un prelievo); ricchezza
MEDIANA con argmax a phi BASSO (la strada-biglietto e' bimodale, §37); P(rovina) crescente
in phi. **Se e' cosi', «la frazione ottima» non esiste finche' non si dice quale colonna.**
A3. **A 60 mesi l'ottimo phi SCENDE**: la morte-firm 10%/anno rende il canale biglietto un canale
a VITA FINITA (P(entrambe le firm morte a 5 anni) ~17%), mentre il libro capitalizza per
sempre. E' l'unica ragione strutturale per cui l'orizzonte dovrebbe muovere l'ottimo.
A4. **Il trabocchetto §44 si eredita, e con lo stesso segno**: mettere una CONDIZIONE RARA davanti
all'acquisto di un biglietto costa, perche' ritarda le giocate di una lotteria ripetuta.
Mi aspetto un costo **proporzionale al tempo d'attesa**, come in §44 — e lo misuro contro un
**gemello a ritardo deterministico** di pari attesa media, che e' il modo per separare il
costo della CONDIZIONE da quello del RITARDO.
A5. **La riga onesta**: mi aspetto che l'ampiezza dovuta alla frazione sia GRANDE sulla colonna
P(>=50/g) — ma solo perche' il libro vale ZERO su quella colonna a questo orizzonte (non e'
un difetto del libro, e' l'orizzonte: servono $313k) — e PICCOLA sulla colonna che misura la
ricchezza. Se esce cosi', va detto che **la frazione conta sulla metrica sbagliata**.
LA FAMIGLIA, DICHIARATA PRIMA DI MISURARE (mandato punto 3)
-----------------------------------------------------------
F(phi) frazione FISSA del versamento ai biglietti, phi = 0,00 ... 1,00 (11 celle).
phi=1 == la strada BIGLIETTO di §37; phi=0 == la strada LIBRO di §37.
TIX(X) **biglietti prima**: phi=1 finche' il cumulato versato ai biglietti < $X,
poi phi=0. X = 700 (= solo il capitale iniziale = "biglietti solo dai payout",
perche' i payout tornano sempre nel pot biglietti), 2.000, 5.000, 10.000.
BOOK(X) **libro prima**: phi=0 finche' il libro < $X, poi phi=1. X = 2.000, 5.000,
10.000, 20.000.
PHI_UP(X) phi CRESCE col capitale: phi = clip(libro / X, 0, 1), X = 10.000.
PHI_DN(X) phi DECRESCE col capitale: phi = 1 - clip(libro / X, 0, 1), X = 10.000.
CASH(B) phi=1 ma la cassa in eccesso oltre $B va al libro (B = 1.200 = il biglietto piu'
caro). E' l'unica politica che puo' DOMINARE phi=1 per costruzione.
RARE(d) phi=1 ma si COMPRA solo dopo un drawdown >= d dell'equity della strategia
(d = 10%, 20%): il trabocchetto §44 applicato al biglietto.
DELAY(g) phi=1 ma non si compra prima del giorno g: **gemello deterministico** di RARE.
Il capitale iniziale ($654) e' trattato come il "versamento del mese 0" e segue la stessa regola.
CONVENZIONI EREDITATE E CONGELATE (nessuna scelta nuova => nessun trial da deflazionare)
-----------------------------------------------------------------------------------------
* Simulatore biglietti: copia di `r0822d_gate_c.ladder` (che e' bit-exact vs `r0725_prop_coupled.
simulate`) con l'aggiunta del pot LIBRO. Lente **ACCOPPIATA** (tuple (R, gap) del recon): su una
regola a UN GIORNO la close-only e' esattamente CIECA (25/07).
* Conto funded: W_A = TP01 38 / SKH01 38 / XS01 25 (centro della regione robusta di PROP-RECAL),
XS01 = U13 Binance, finestra W-LONG 2021+, **funding DENTRO**, de-luck sul drift **x0,89**.
* Pot LIBRO: `FD.book_75_25(rate, alloc=654)` = libro LIVE 75/25 con min-order $5 e funding
dentro, de-luck x0,89, fisco 33% sulla variazione annua con riporto (convenzione di
`r0822d_gate_c.book_road` = quella di `r0807_piano_netto`). ⚠ Dichiarato: NON contiene la
patrimoniale 0,2%/anno che `PN.accumula` invece include; la differenza e' misurata in §1.
* Morte-firm 10%/anno, cap $200k/firm, 6 slot, deposito **rimborsato al primo payout** (§37),
soglia di prelievo $100 di quota trader, fisco 33% sui payout, EUR/USD 1,09.
* Rendita: `perp` e muro dalla lente **L3 CONGIUNTA** (`PN.muro`), cioe' la stessa che produce i
$313k del piano.
Uso: `nice -n 19 timeout 900 uv run python scripts/research/r0823b_split_deposito.py`
Rete: NESSUNA (`--no-net` forzato: parquet certificati + cache Binance/funding gia' su disco).
"""
from __future__ import annotations
import sys
import time
from pathlib import Path
import numpy as np
import pandas as pd
ROOT = Path(__file__).resolve().parents[2]
for _p in (ROOT, ROOT / "scripts" / "research", ROOT / "scripts" / "research" / "alt"):
sys.path.insert(0, str(_p))
if "--no-net" not in sys.argv: # r0822d_funding legge USE_NET all'import
sys.argv.append("--no-net")
import r0725_prop_coupled as pc # noqa: E402 lente accoppiata (25/07)
import r0725_prop_ladder as pl # noqa: E402 regole firm + scala di conti (25/07)
import r0807_piano_netto as PN # noqa: E402 muro / accumula (07/08)
import r0727_tasse as TX # noqa: E402 patrimoniale
import r0822_prop_alloc as PA # noqa: E402 J, bootstrap (22/08)
import r0822b_prop_recal as PR # noqa: E402 PROP-RECAL (22/08)
import r0822b_xs01_oos as X # noqa: E402 universo U13 + cache Binance
import r0822c_skh_anchor_prop as AP # noqa: E402 offset di SKH01
import r0822d_funding as FD # noqa: E402 il funding (22/08)
import r0822d_gate_c as GC # noqa: E402 §37: ladder + book_road
from src.portfolio.sleeves import XS_UNIVERSE # noqa: E402
FD.USE_NET = False
EURUSD = pl.EURUSD
TAX_RATE = pl.TAX_RATE
SPLIT = pl.SPLIT
DELUCK = PA.DELUCK # x0,89 MISURATO (r0726_deluck_factor)
FIRMS = pl.FIRMS
N_SLOT = pl.MAX_CONCURRENT
TARGET = pl.TARGET_EUR_DAY
START_EUR = 600.0 # $654 = il conto reale (convenzione di §37)
MIN_PAYOUT = GC.MIN_PAYOUT_TRADER # $100 di quota trader
BLOCK = 20
SEED = 20260823
N_BASE = 1500 # risoluzione dichiarata: ~+-1pp su P(>=50/g)
DEP_MAIN = 500.0 # il piano in corso (config/live.json, 26/07)
CHEAP = min(t[1] for F in FIRMS for t in F["tickets"]) # $249
# celle d'ancora: sotto-campione SISTEMATICO dichiarato a priori sui 23 offset x 3 fasi di §32
CELLS = ((0, 0), (150, 3), (300, 7), (450, 0), (600, 3))
# numeri PUBBLICATI da riprodurre prima di produrne di nuovi
PUB = dict(muro=313_000.0, p50g_37=0.137, med_tix_37=39_820.0, med_book_37=22_444.0,
med_tix_0=132.0, med_book_0=787.0, p50g_0=0.042, pzero_37=0.403, p50g_anchor=0.026)
T0 = time.time()
def clock() -> str:
return f"[{time.time()-T0:5.0f}s]"
def hr(t: str = "") -> None:
print("\n" + "=" * 108)
if t:
print(f" {t}")
print("=" * 108)
# ===========================================================================================
# LE POLITICHE — (etichetta, tipo, parametro). Dichiarate sopra, nel docstring.
# ===========================================================================================
def phi_of(kind: str, par: float, book: np.ndarray, cash: np.ndarray,
to_tix: np.ndarray) -> np.ndarray:
"""Frazione del versamento che va al pot BIGLIETTI. Vettoriale sul blocco di percorsi."""
if kind == "FIX":
return np.full(len(book), float(par))
if kind == "TIX": # biglietti prima
return (to_tix < par).astype(float)
if kind == "BOOK": # libro prima
return (book >= par).astype(float)
if kind == "PHI_UP": # cresce col capitale
return np.clip(book / par, 0.0, 1.0)
if kind == "PHI_DN": # decresce col capitale
return 1.0 - np.clip(book / par, 0.0, 1.0)
if kind in ("CASH", "RARE", "DELAY"): # phi = 1, la differenza e' altrove
return np.ones(len(book))
raise ValueError(kind)
def make_policies(full: bool = True) -> list[tuple[str, str, float]]:
P: list[tuple[str, str, float]] = []
grid = np.round(np.arange(0.0, 1.001, 0.10), 2) if full else np.array([0.0, 0.25, 0.50, 0.75, 1.0])
for f in grid:
P.append((f"F {f:.2f}", "FIX", float(f)))
if not full:
return P
for xk in (700.0, 2_000.0, 5_000.0, 10_000.0):
P.append((f"TIX ${xk:,.0f}", "TIX", xk))
for xk in (2_000.0, 5_000.0, 10_000.0, 20_000.0):
P.append((f"BOOK ${xk:,.0f}", "BOOK", xk))
P.append(("PHI_UP $10k", "PHI_UP", 10_000.0))
P.append(("PHI_DN $10k", "PHI_DN", 10_000.0))
P.append(("CASH-ATT $1.2k", "CASH", 1_200.0))
P.append(("RARE dd 10%", "RARE", 0.10))
P.append(("RARE dd 20%", "RARE", 0.20))
P.append(("DELAY 95g", "DELAY", 95.0))
P.append(("DELAY 713g", "DELAY", 713.0))
return P
# ===========================================================================================
# IL SIMULATORE COMBINATO — pot BIGLIETTI + pot LIBRO sullo STESSO percorso
# ===========================================================================================
def sim_split(R: np.ndarray, G: np.ndarray, rb: np.ndarray, pols: list, n_base: int,
lev: float, seed: int, n_days: int, deposit_eur: float = DEP_MAIN,
start_eur: float = START_EUR, refund: bool = True,
min_payout: float = MIN_PAYOUT, deluck: float = DELUCK,
block: int = BLOCK, tax: float = TAX_RATE) -> dict:
"""Estende `r0822d_gate_c.ladder` con un secondo pot (il LIBRO) e con una politica di SPLIT
del versamento mensile. Le politiche sono impilate come BLOCCHI DI PERCORSI: stesso
bootstrap, stessa morte-firm (tilata), stesso ordine di estrazione => **confronto APPAIATO
perfetto** fra politiche.
Con `pols=[("x","FIX",1.0)]`, `refund=False`, `deposit=0`, `min_payout=0` dev'essere
BIT-EXACT rispetto a `GC.ladder` (controllo R2). Con `pols=[("x","FIX",0.0)]` il pot libro
dev'essere BIT-EXACT rispetto a `GC.book_road` (controllo R3).
"""
n_pol = len(pols)
P = n_pol * n_base
L = len(R)
rng = np.random.default_rng(seed)
Rd = R.astype(float) - (1.0 - deluck) * float(R.astype(float).mean())
Gd = G.astype(float)
Bd = rb.astype(float) - (1.0 - deluck) * float(rb.astype(float).mean())
n_blocks = int(np.ceil(n_days / block))
starts0 = rng.integers(0, L - block, size=(n_base, n_blocks)) # stesso stream di GC
starts = np.tile(starts0, (n_pol, 1)) # ...e TILATO: appaiato
deaths0 = rng.random((n_days, n_base, len(FIRMS))) # morte-firm, tilata
p_death_day = 1.0 - (1.0 - pl.FIRM_DEATH_PER_YEAR) ** (1 / 365.0)
pid = np.repeat(np.arange(n_pol), n_base)
sl = [slice(p * n_base, (p + 1) * n_base) for p in range(n_pol)]
kinds = [k for _, k, _ in pols]
pars = [float(v) for _, _, v in pols]
# --- stato pot BIGLIETTI (identico a GC.ladder) ---------------------------------------
cash = np.zeros(P)
phase = np.full((P, N_SLOT), -1, np.int8)
eq = np.ones((P, N_SLOT))
firm = np.full((P, N_SLOT), -1, np.int8)
notional = np.zeros((P, N_SLOT))
price_paid = np.zeros((P, N_SLOT))
refunded = np.zeros((P, N_SLOT), bool)
firm_alive = np.ones((P, len(FIRMS)), bool)
used_f = np.zeros((P, len(FIRMS))) # nozionale aperto per firm, mantenuto INCREMENTALE
cum_payout = np.zeros(P)
spent = np.zeros(P)
got_back = np.zeros(P)
n_payouts = np.zeros(P, int)
n_bought = np.zeros(P, int)
to_tix = np.zeros(P) # cumulato VERSATO al pot biglietti (non i payout)
to_book = np.zeros(P)
# --- stato pot LIBRO (identico a GC.book_road) ----------------------------------------
bookc = np.zeros(P)
basis = np.zeros(P)
carry = np.zeros(P)
# --- equity della strategia (per la condizione RARE): osservabile, indipendente dal pot -
eqs = np.ones(P)
peak = np.ones(P)
def deposita(amount: np.ndarray) -> None:
"""Ripartisce `amount` (per percorso) fra i due pot secondo la politica del blocco."""
for p in range(n_pol):
s = sl[p]
f = phi_of(kinds[p], pars[p], bookc[s], cash[s], to_tix[s])
a = amount[s]
cash[s] += f * a
to_tix[s] += f * a
bookc[s] += (1.0 - f) * a
basis[s] += (1.0 - f) * a
to_book[s] += (1.0 - f) * a
deposita(np.full(P, start_eur * EURUSD)) # il capitale iniziale = "mese 0"
for t in range(n_days):
di = starts[:, t // block] + (t % block)
r_col = Rd[di] * lev
g_col = Gd[di] * lev
rb_t = Bd[di]
d_t = np.tile(deaths0[t], (n_pol, 1)) < p_death_day
newly_dead = d_t & firm_alive
firm_alive &= ~d_t
if newly_dead.any():
for fi in range(len(FIRMS)):
kill = newly_dead[:, fi]
if kill.any():
hit = (firm == fi) & kill[:, None]
phase[hit] = -1
notional[hit] = 0.0
used_f[kill, fi] = 0.0
# --- gating dell'acquisto: default aperto, chiuso per RARE/DELAY ------------------
allow = np.ones(P, bool)
for p in range(n_pol):
if kinds[p] == "RARE":
allow[sl[p]] = (eqs[sl[p]] / peak[sl[p]] - 1.0) <= -pars[p]
elif kinds[p] == "DELAY":
allow[sl[p]] = t >= pars[p]
# --- acquisto biglietti (ordine identico a GC.ladder) ----------------------------
for k in range(N_SLOT):
free = (phase[:, k] == -1) & allow
if not free.any():
continue
for fi, F in enumerate(FIRMS):
used = used_f[:, fi] # vista: si aggiorna da sola sotto
for (size, price) in sorted(F["tickets"], key=lambda x: -x[0]):
buy = (free & firm_alive[:, fi] & (cash >= price)
& (used + size <= F["cap"]))
if not buy.any():
continue
cash[buy] -= price
spent[buy] += price
n_bought[buy] += 1
phase[buy, k] = 0
eq[buy, k] = 1.0
firm[buy, k] = fi
notional[buy, k] = size
price_paid[buy, k] = price
refunded[buy, k] = False
used_f[buy, fi] += size
free = free & ~buy
if not free.any():
break
if not free.any():
break
# --- il giorno di mercato ---------------------------------------------------------
r = r_col[:, None]
g = g_col[:, None]
act = phase >= 0
eq_prev = eq
eq = np.where(act, eq * (1.0 + r), eq)
eq_low = np.where(act, eq_prev * (1.0 + r + g), eq)
r_low = r + g
for fi, F in enumerate(FIRMS):
s_ = act & (firm == fi)
if not s_.any():
continue
ev_t, ev_dd, ev_dl = F["ev"]
fu_ml, fu_dl = F["fu"]
in_ev = s_ & (phase == 0)
in_fu = s_ & (phase == 1)
bust = ((in_ev & ((eq_low < 1.0 - ev_dd) | (r_low < -ev_dl)))
| (in_fu & ((eq_low < 1.0 - fu_ml) | (r_low < -fu_dl))))
if bust.any():
used_f[:, fi] -= np.where(bust, notional, 0.0).sum(axis=1)
phase[bust] = -1
notional[bust] = 0.0
passed = in_ev & (eq >= 1.0 + ev_t) & ~bust
phase[passed] = 1
eq[passed] = 1.0
# --- il pot LIBRO + l'equity osservabile della strategia --------------------------
bookc = np.maximum(bookc * (1.0 + rb_t), 0.0)
eqs = eqs * (1.0 + rb_t)
peak = np.maximum(peak, eqs)
# --- fine mese: payout, rimborso, cassa attiva, versamento ------------------------
if (t + 1) % 30 == 0:
fu = phase == 1
pay = fu & (eq > 1.0) & (((eq - 1.0) * notional * SPLIT) >= min_payout)
gain = np.where(pay, (eq - 1.0) * notional, 0.0)
net = gain.sum(axis=1) * SPLIT * (1.0 - tax)
cum_payout += net
cash += net
n_payouts += (pay.sum(axis=1) > 0).astype(int)
eq = np.where(pay, 1.0, eq)
if refund:
back = pay & ~refunded
amt = np.where(back, price_paid, 0.0).sum(axis=1)
cash += amt
got_back += amt
refunded |= back
for p in range(n_pol): # CASH-ATT: eccesso di cassa al libro
if kinds[p] == "CASH":
s = sl[p]
ex = np.maximum(cash[s] - pars[p], 0.0)
cash[s] -= ex
bookc[s] += ex
basis[s] += ex
if deposit_eur:
deposita(np.full(P, deposit_eur * EURUSD))
# --- fine anno: fisco sul pot LIBRO (convenzione GC.book_road) --------------------
if (t + 1) % 365 == 0:
gg = (bookc - basis) + carry
due = np.where(gg > 0, tax * gg, 0.0)
carry = np.where(gg > 0, 0.0, gg)
bookc = bookc - due
basis = bookc.copy()
years = n_days / 365.0
flow = cum_payout / EURUSD / years / 365.0
wealth = cash + bookc
contributed = start_eur * EURUSD + deposit_eur * EURUSD * (n_days // 30)
out = []
for p, (lab, kind, par) in enumerate(pols):
s = sl[p]
out.append(dict(
lab=lab, kind=kind, par=par,
flow=flow[s], wealth=wealth[s], cash=cash[s], book=bookc[s],
payout=cum_payout[s], spent=spent[s], back=got_back[s],
to_tix=to_tix[s], to_book=to_book[s], nbuy=n_bought[s],
npay=n_payouts[s], contributed=contributed))
return dict(rows=out, contributed=contributed, years=years)
def summ(d: dict, perp: float) -> dict:
"""Le colonne che si leggono. `rend` = ricchezza terminale x rendita perpetua (la
definizione di EUR 50/giorno del PIANO); `flow` = payout medi (la definizione di §37)."""
w, f = d["wealth"], d["flow"]
rend = w * perp / 365.0 / EURUSD
return dict(
lab=d["lab"],
p50_flow=float((f >= TARGET).mean()),
p50_rend=float((rend >= TARGET).mean()),
med_w=float(np.median(w)), mean_w=float(w.mean()),
p10_w=float(np.percentile(w, 10)), p90_w=float(np.percentile(w, 90)),
med_flow=float(np.median(f)), med_rend=float(np.median(rend)),
p_loss=float((w < d["contributed"]).mean()),
p_ruin=float((w < CHEAP).mean()),
p_nopay=float((d["payout"] <= 0).mean()),
med_tix=float(np.median(d["to_tix"])), nbuy=float(np.mean(d["nbuy"])))
# ===========================================================================================
def main() -> None:
try:
sys.stdout.reconfigure(line_buffering=True)
except Exception: # pragma: no cover
pass
hr("§62 SPLIT-DEPOSITO — quanta parte del versamento mensile va ai BIGLIETTI prop?")
print(" §37 ha confrontato due CASI LIMITE (tutto libro / tutto biglietti). Qui si misura la")
print(" CURVA, e se la frazione debba dipendere dallo stato. Attese registrate nel docstring:")
print(" A1 politica ottima FRONT-LOADED e saturante (TIX batte BOOK, phi decrescente batte")
print(" crescente), perche' il libro e' neutrale alla scala e il biglietto ha rendimenti")
print(" DECRESCENTI a gradini (prezzo fisso, nozionale fisso, cap, indivisibilita');")
print(" A2 gli ottimi delle tre colonne NON coincidono; A3 a 60 mesi l'ottimo phi SCENDE;")
print(" A4 il trabocchetto §44 si eredita col segno negativo; A5 la frazione conta molto")
print(" su P(>=50/g) solo perche' il libro vale ZERO su quella colonna a 36-60 mesi.")
# ================================================================= dati
hr(f"§0. IL PANNELLO — le stesse serie di §37 (U13 Binance, W-LONG 2021+) {clock()}")
Cb, Ob, Hb, Lb = PR.ohlc_panels(PR.bin_loader, XS_UNIVERSE)
p13 = Cb[X.U13].dropna()
o13, h13, l13 = (Ob.reindex(p13.index)[X.U13], Hb.reindex(p13.index)[X.U13],
Lb.reindex(p13.index)[X.U13])
phases = sorted({ph for _, ph in CELLS})
XSP = {ph: PR.xs_tuples(p13, o13, h13, l13, phase=ph) for ph in phases}
xs0 = XSP[0]
base = pc.crypto_daily_tuples(1.0, 0.0).index.intersection(xs0.index)
first13 = xs0.index[np.flatnonzero(xs0["R"].values != 0.0)[0]]
I = base[base >= max(first13, pd.Timestamp("2021-01-01", tz="UTC"))]
print(f" W-LONG: {len(I)} giorni {I[0].date()} -> {I[-1].date()} | de-luck x{DELUCK}")
rate = GC.funding_rate()
if rate is None:
print(" !! cache funding assente: il filone NON gira senza funding (lente L3). STOP.")
return
xs_ann = GC.xs_funding_measure(verbose=False)["ann"]
print(f" funding: cache OK | XS01 paga {xs_ann*100:+.2f}%/anno (riproduzione di §37)")
rb_full = FD.book_75_25(rate, alloc=654.0)
if rb_full.index.tz is None:
rb_full.index = rb_full.index.tz_localize("UTC")
rb = np.nan_to_num(rb_full.reindex(I).values.astype(float))
print(f" pot LIBRO (75/25 a $654, funding dentro): drift {rb.mean()*365*100:.2f}%/anno, "
f"vol {rb.std()*np.sqrt(365)*100:.1f}%, Sharpe {rb.mean()*365/(rb.std()*np.sqrt(365)):.2f}")
W_A = {"TP01": 0.38, "SKH01": 0.38, "XS01": 0.25}
ev_b = PA.boot_idx(len(I), 365, PA.N_PATHS, seed=8220)
fu_b = PA.boot_idx(len(I), 365, PA.N_PATHS, seed=8221)
RG: dict = {}
for off, ph in CELLS:
f = GC.fvec_for(W_A, I, rate, off, xs_ann)
R0, G0 = AP.rg_off(W_A, I, XSP[ph], off)
Rx = R0 - f
j, lv, _ = GC.best_lev(Rx, G0, ev_b, fu_b)
RG[(off, ph)] = (Rx, G0, lv, j)
print(f"\n {len(CELLS)} celle d'ancora (sotto-campione sistematico a priori sui 23 offset x "
f"3 fasi di §32):")
for (off, ph), (Rx, _, lv, j) in RG.items():
print(f" offset {off:>3} min, fase {ph} -> J {j:.3f} @ leva {lv:.3f}x "
f"drift {Rx.mean()*365*100:+6.2f}%/anno")
# ================================================================= §1 repliche
hr(f"§1. LE REPLICHE — prima di produrre un numero nuovo {clock()}")
ok: dict[str, bool] = {}
# R1: muro L3 (la rendita perpetua che converte capitale in EUR/giorno)
import r0822d_piano_vero as PV # noqa: E402
B3 = PV.costruisci_serie()
r_l3 = PV.deluck(B3["fund"].values.astype(float))
netto = TARGET * 365 * EURUSD
perp, muro = PN.muro(r_l3, netto, TAX_RATE, TX.PATRIMONIALE)
ok["R1"] = abs(muro - PUB["muro"]) < 3_000.0
print(f" R1 muro L3 CONGIUNTA: perpetua {perp:.2%} · ${muro:,.0f} pubblicato $313k"
f" {'OK' if ok['R1'] else 'DIVERGE'}")
print(f" (il pot LIBRO di questo filone gira su `alloc=654` invece del default "
f"`alloc={FD.ALLOC:.0f}` di L3: drift "
f"{rb.mean()*365*100:.2f}% contro {PV.deluck(B3['fund'].values.astype(float)).mean()*365*100:.2f}% "
f"-> differenza dichiarata, non nascosta)")
# R2: il mio simulatore == GC.ladder (che e' bit-exact vs pc.simulate)
cell0 = CELLS[0]
R0, G0, LV0, _ = RG[cell0]
ref = GC.ladder(R0, G0, N_BASE, LV0, SEED, refund=False, min_payout=0.0, deposit_eur=0.0)
mine = sim_split(R0, G0, rb, [("ctl", "FIX", 1.0)], N_BASE, LV0, SEED, 1080,
deposit_eur=0.0, refund=False, min_payout=0.0)
a = np.sort(ref["eur_day"])
b = np.sort(mine["rows"][0]["flow"])
d2 = float(np.abs(ref["eur_day"] - mine["rows"][0]["flow"]).max())
ok["R2"] = d2 < 1e-12
print(f" R2 sim_split(phi=1) vs GC.ladder, percorso per percorso: max|diff| = {d2:.3e}"
f" {'BIT-EXACT' if ok['R2'] else 'DIVERGE'} (ordinati {np.abs(a-b).max():.3e})")
# R3: il pot libro == GC.book_road, sugli stessi sorteggi
n_blocks = int(np.ceil(1080 / BLOCK))
rng_c = np.random.default_rng(SEED)
st_c = rng_c.integers(0, len(I) - BLOCK, size=(N_BASE, n_blocks))
BOOT_C = (st_c[:, :, None] + np.arange(BLOCK)[None, None, :]).reshape(N_BASE, -1)[:, :1080]
brd = GC.book_road(rb, BOOT_C, START_EUR, DEP_MAIN)
mineb = sim_split(R0, G0, rb, [("ctl", "FIX", 0.0)], N_BASE, LV0, SEED, 1080,
deposit_eur=DEP_MAIN)
d3 = float(np.abs(np.sort(brd["cash"]) - np.sort(mineb["rows"][0]["wealth"])).max())
ok["R3"] = d3 < 1e-8
print(f" R3 sim_split(phi=0) vs GC.book_road (stessi blocchi): max|diff| = ${d3:.3e}"
f" {'IDENTICO' if ok['R3'] else 'DIVERGE'}")
# R4: gli estremi di §37, alla banda d'ancora (la cella mediana di §37 non e' pubblicata)
print(f"\n R4 GLI ESTREMI DI §37 — le due strade intere, sulle {len(CELLS)} celle d'ancora")
print(f" (§37 gira sulla SUA cella mediana, non pubblicata: qui si verifica che i suoi")
print(f" numeri cadano DENTRO la banda, non che coincidano)")
print(f"\n {'versamento':>11} {'strada':>10} {'mediana (banda celle)':>34} "
f"{'media':>12} {'P(>=50/g)':>22}")
r37, _r4 = {}, []
for dep in (0.0, DEP_MAIN):
for lab, phi in (("BIGLIETTO", 1.0), ("LIBRO", 0.0)):
med, mea, p50 = [], [], []
for c in CELLS:
Rc, Gc, lvc, _ = RG[c]
s = sim_split(Rc, Gc, rb, [(lab, "FIX", phi)], N_BASE, lvc, SEED, 1080,
deposit_eur=dep)
q = summ(s["rows"][0], perp)
med.append(q["med_w"]); mea.append(q["mean_w"]); p50.append(q["p50_flow"])
r37[(dep, lab)] = (np.median(med), np.median(mea), np.median(p50))
pubm = PUB["med_tix_37"] if (dep and lab == "BIGLIETTO") else (
PUB["med_book_37"] if dep else (PUB["med_tix_0"] if lab == "BIGLIETTO"
else PUB["med_book_0"]))
inside = min(med) <= pubm <= max(med)
_r4.append(bool(inside))
print(f" EUR{dep:>7,.0f}/m {lab:>10} ${np.median(med):>10,.0f} "
f"[${min(med):>8,.0f},${max(med):>9,.0f}] ${np.median(mea):>11,.0f} "
f"{np.median(p50):>9.1%} [{min(p50):>5.1%},{max(p50):>5.1%}] "
f"{'PUB dentro' if inside else 'PUB fuori'}")
ok["R4"] = all(_r4)
print(f" §37 pubblica: BIGLIETTO EUR500 ${PUB['med_tix_37']:,.0f} / P {PUB['p50g_37']:.1%} · "
f"LIBRO ${PUB['med_book_37']:,.0f} · BIGLIETTO EUR0 ${PUB['med_tix_0']:,.0f} · "
f"LIBRO EUR0 ${PUB['med_book_0']:,.0f}")
print(f"\n REPLICHE: {sum(ok.values())}/{len(ok)} "
f"{'tutte OK' if all(ok.values()) else 'ATTENZIONE: ' + str([k for k,v in ok.items() if not v])}")
if not (ok["R2"] and ok["R3"]):
print(" Senza R2/R3 i numeri sotto sarebbero di un'altra macchina. STOP.")
return
# ================================================================= §2 la curva
hr(f"§2. LA CURVA DELLA FRAZIONE — 36 mesi, EUR {DEP_MAIN:.0f}/mese, {N_BASE} percorsi {clock()}")
print(" Tutte le politiche girano nello STESSO Monte Carlo (blocchi impilati): stesso")
print(" bootstrap, stessa morte-firm => ogni delta e' APPAIATO percorso per percorso.")
POLS = make_policies(full=True)
RES: dict = {}
for c in CELLS:
Rc, Gc, lvc, _ = RG[c]
s = sim_split(Rc, Gc, rb, POLS, N_BASE, lvc, SEED, 1080, deposit_eur=DEP_MAIN)
RES[c] = {r["lab"]: r for r in s["rows"]}
print(f" cella {c} fatta {clock()}")
CONTRIB = s["contributed"]
fix_labs = [p[0] for p in POLS if p[1] == "FIX"]
print(f"\n Versato in 36 mesi: ${CONTRIB:,.0f} (capitale iniziale ${START_EUR*EURUSD:,.0f} "
f"+ 36 x EUR{DEP_MAIN:.0f})")
print(f"\n {'phi':>6} {'P(>=50/g) FLUSSO':>26} {'P(>=50/g) RENDITA':>18} "
f"{'ricch. MEDIANA':>26} {'media':>11} {'P(<versato)':>12} {'P(<$249)':>10} "
f"{'EUR/g med':>10}")
print(f" {'':>6} {'(la metrica di §37)':>26} {'(la metrica del PIANO)':>18}")
curva = []
for lab in fix_labs:
q = {c: summ(RES[c][lab], perp) for c in CELLS}
g = lambda k: float(np.median([q[c][k] for c in CELLS])) # noqa: E731
lohi = lambda k: (min(q[c][k] for c in CELLS), max(q[c][k] for c in CELLS)) # noqa: E731
p50, pl_, ph_ = g("p50_flow"), *lohi("p50_flow")
mw, mlo, mhi = g("med_w"), *lohi("med_w")
rendm = g("med_flow") + g("med_rend")
curva.append(dict(lab=lab, phi=float(lab.split()[1]), p50=p50, med=mw,
mean=g("mean_w"), ploss=g("p_loss"), pruin=g("p_ruin"),
prend=g("p50_rend"), eurg=rendm))
print(f" {lab.split()[1]:>6} {p50:>13.1%} [{pl_:>5.1%},{ph_:>5.1%}] "
f"{g('p50_rend'):>17.1%} ${mw:>10,.0f} [${mlo:>7,.0f},${mhi:>8,.0f}] "
f"${g('mean_w'):>10,.0f} {g('p_loss'):>12.1%} {g('p_ruin'):>10.1%} {rendm:>10.2f}")
CV = pd.DataFrame(curva)
a_p50 = CV.loc[CV["p50"].idxmax()]
a_med = CV.loc[CV["med"].idxmax()]
a_mean = CV.loc[CV["mean"].idxmax()]
a_saf = CV.loc[CV["ploss"].idxmin()]
print(f"\n ARGMAX PER COLONNA — la risposta al mandato punto 2:")
print(f" P(>=50/g) flusso : phi = {a_p50['phi']:.2f} ({a_p50['p50']:.1%})")
print(f" ricchezza MEDIANA: phi = {a_med['phi']:.2f} (${a_med['med']:,.0f})")
print(f" ricchezza MEDIA : phi = {a_mean['phi']:.2f} (${a_mean['mean']:,.0f})")
print(f" P(<versato) min : phi = {a_saf['phi']:.2f} ({a_saf['ploss']:.1%})")
print(f" P(>=50/g) RENDITA: max {CV['prend'].max():.1%} su TUTTE le celle "
f"-> {'nessuno arriva' if CV['prend'].max() < 0.005 else 'qualcuno arriva'}")
print(f" >>> ATTESA A2 ('gli ottimi non coincidono'): "
f"{'CONFERMATA' if len({round(a_p50['phi'],2), round(a_med['phi'],2)}) > 1 else 'SMENTITA'}")
# ---- risoluzione MC, misurata (mandato: riportarla accanto a ogni delta) --------------
print(f"\n §2.1 RISOLUZIONE MONTE CARLO — misurata su 3 semi (non assunta) {clock()}")
probe = [("F 0.00", "FIX", 0.0), ("F 0.50", "FIX", 0.5), ("F 1.00", "FIX", 1.0)]
Rc, Gc, lvc, _ = RG[CELLS[0]]
seeds = (SEED, SEED + 101, SEED + 202)
tabS = {}
for sd in seeds:
s = sim_split(Rc, Gc, rb, probe, N_BASE, lvc, sd, 1080, deposit_eur=DEP_MAIN)
tabS[sd] = {r["lab"]: summ(r, perp) for r in s["rows"]}
sp_lvl = max(max(tabS[sd][l]["p50_flow"] for sd in seeds)
- min(tabS[sd][l]["p50_flow"] for sd in seeds) for l in ("F 0.50", "F 1.00"))
d_pair = [tabS[sd]["F 1.00"]["p50_flow"] - tabS[sd]["F 0.50"]["p50_flow"] for sd in seeds]
sp_pair = max(d_pair) - min(d_pair)
print(f" {'seme':>10} {'P50 phi=0.5':>13} {'P50 phi=1.0':>13} {'delta appaiato':>16} "
f"{'med. ricch. phi=0':>18}")
for sd in seeds:
print(f" {sd:>10} {tabS[sd]['F 0.50']['p50_flow']:>13.2%} "
f"{tabS[sd]['F 1.00']['p50_flow']:>13.2%} "
f"{tabS[sd]['F 1.00']['p50_flow']-tabS[sd]['F 0.50']['p50_flow']:>+16.2%} "
f"${tabS[sd]['F 0.00']['med_w']:>17,.0f}")
print(f" ampiezza fra semi: LIVELLI {sp_lvl*100:.2f} pp · DIFFERENZE APPAIATE "
f"{sp_pair*100:.2f} pp -> ogni delta sotto ~{max(sp_pair,0.0)*100:.1f} pp e' RUMORE")
# ================================================================= §3 politiche di stato
hr(f"§3. LE POLITICHE DIPENDENTI DALLO STATO — famiglia dichiarata prima {clock()}")
print(f" {'politica':>16} {'P(>=50/g)':>22} {'ricch. mediana':>15} {'media':>11} "
f"{'P(<versato)':>12} {'P(<$249)':>10} {'$ ai biglietti':>15} {'biglietti':>10}")
fam = [p[0] for p in POLS if p[1] in ("TIX", "BOOK", "PHI_UP", "PHI_DN", "CASH")]
ref_lab = "F 1.00"
qref = {c: summ(RES[c][ref_lab], perp) for c in CELLS}
for lab in [ref_lab, "F 0.00"] + fam:
q = {c: summ(RES[c][lab], perp) for c in CELLS}
g = lambda k: float(np.median([q[c][k] for c in CELLS])) # noqa: E731
dp = float(np.median([q[c]["p50_flow"] - qref[c]["p50_flow"] for c in CELLS]))
npos = sum(1 for c in CELLS if q[c]["p50_flow"] - qref[c]["p50_flow"] > 0)
mark = "" if lab == ref_lab else f" d {dp*100:+5.2f}pp ({npos}/{len(CELLS)})"
print(f" {lab:>16} {g('p50_flow'):>9.1%}{mark:>13} ${g('med_w'):>14,.0f} "
f"${g('mean_w'):>10,.0f} {g('p_loss'):>12.1%} {g('p_ruin'):>10.1%} "
f"${g('med_tix'):>14,.0f} {g('nbuy'):>10.1f}")
tixb = float(np.median([summ(RES[c]["TIX $5,000"], perp)["p50_flow"] for c in CELLS]))
bookb = float(np.median([summ(RES[c]["BOOK $5,000"], perp)["p50_flow"] for c in CELLS]))
up = float(np.median([summ(RES[c]["PHI_UP $10k"], perp)["p50_flow"] for c in CELLS]))
dn = float(np.median([summ(RES[c]["PHI_DN $10k"], perp)["p50_flow"] for c in CELLS]))
print(f"\n >>> ATTESA A1 (front-loaded): TIX $5k {tixb:.1%} contro BOOK $5k {bookb:.1%} "
f"-> {'CONFERMATA' if tixb > bookb else 'SMENTITA'}; "
f"phi DECRESCENTE {dn:.1%} contro CRESCENTE {up:.1%} "
f"-> {'CONFERMATA' if dn > up else 'SMENTITA'}")
cashp = {c: summ(RES[c]["CASH-ATT $1.2k"], perp) for c in CELLS}
d_cash = float(np.median([cashp[c]["med_w"] - qref[c]["med_w"] for c in CELLS]))
d_cash50 = float(np.median([cashp[c]["p50_flow"] - qref[c]["p50_flow"] for c in CELLS]))
print(f" CASH-ATT (l'unica che puo' dominare phi=1): ricchezza mediana "
f"${d_cash:+,.0f}, P(>=50/g) {d_cash50*100:+.2f}pp "
f"({sum(1 for c in CELLS if cashp[c]['med_w'] > qref[c]['med_w'])}/{len(CELLS)} celle)")
# ================================================================= §4 il trabocchetto §44
hr(f"§4. IL TRABOCCHETTO DI §44 — la CONDIZIONE davanti al bonifico {clock()}")
print(" §44: «comprare meglio e comprare tardi sono la stessa mossa». Qui la condizione non")
print(" ritarda un BONIFICO ma un ACQUISTO di biglietto. Si separa il costo della CONDIZIONE")
print(" da quello del RITARDO con un GEMELLO DETERMINISTICO di pari attesa media.")
print(f"\n {'politica':>14} {'attesa media (g)':>18} {'P(>=50/g)':>11} {'d appaiato':>12} "
f"{'ricch. mediana':>15} {'d':>11}")
# attesa media della condizione, misurata sulla stessa serie
for lab in ("F 1.00", "RARE dd 10%", "RARE dd 20%", "DELAY 95g", "DELAY 713g"):
q = {c: summ(RES[c][lab], perp) for c in CELLS}
g = lambda k: float(np.median([q[c][k] for c in CELLS])) # noqa: E731
dp = float(np.median([q[c]["p50_flow"] - qref[c]["p50_flow"] for c in CELLS]))
dm = float(np.median([q[c]["med_w"] - qref[c]["med_w"] for c in CELLS]))
wait = {"F 1.00": 0.0, "DELAY 95g": 95.0, "DELAY 713g": 713.0}.get(lab, float("nan"))
if np.isnan(wait):
d_ = float(lab.split()[-1].rstrip("%")) / 100.0
eqp = np.cumprod(1.0 + PV.deluck(rb))
dd = eqp / np.maximum.accumulate(eqp) - 1.0
hit = np.flatnonzero(dd <= -d_)
wait = float(hit[0]) if len(hit) else float("inf")
print(f" {lab:>14} {wait:>18.0f} {g('p50_flow'):>11.1%} {dp*100:>+11.2f}pp "
f"${g('med_w'):>14,.0f} ${dm:>+10,.0f}")
print(" (l'attesa di RARE e' il primo giorno in cui la condizione si verifica sulla serie")
print(" storica de-luckata: nel bootstrap e' una variabile aleatoria, qui e' un'ancora)")
# ================================================================= §5 la scala
hr(f"§5. I RENDIMENTI DI SCALA — la previsione A1, misurata direttamente {clock()}")
print(" Il canale BIGLIETTO assorbe soldi solo a gradini (prezzo fisso, 6 slot, cap firm).")
print(" Quanto ne assorbe davvero, e quando satura?")
Rc, Gc, lvc, _ = RG[CELLS[0]]
print(f"\n {'versamento':>12} {'$ versati ai bigl.':>19} {'$ SPESI in biglietti':>21} "
f"{'assorbimento':>13} {'cassa finale med':>17} {'biglietti comprati':>19}")
for dep in (0.0, 250.0, 500.0, 1_000.0, 2_000.0):
s = sim_split(Rc, Gc, rb, [("F 1.00", "FIX", 1.0)], N_BASE, lvc, SEED, 1080,
deposit_eur=dep)
r = s["rows"][0]
got = float(np.mean(r["to_tix"]))
sp = float(np.mean(r["spent"]))
print(f" EUR{dep:>8,.0f}/m ${got:>18,.0f} ${sp:>20,.0f} {sp/max(got,1e-9):>12.1%} "
f"${np.median(r['cash']):>16,.0f} {np.mean(r['nbuy']):>19.1f}")
print(" ('assorbimento' = quanta parte dei soldi mandati al pot biglietti finisce davvero")
print(" in un biglietto; il resto resta CASSA FERMA — e' il costo dell'indivisibilita'.)")
print(f"\n §5.1 LA FRAZIONE CONTRO L'IMPORTO — la domanda che decide {clock()}")
print(f" {'versamento':>12} {'phi=0 P(>=50/g)':>16} {'phi=1 P(>=50/g)':>16} "
f"{'ampiezza phi':>13} {'phi=0 ricch.med':>16} {'phi=1 ricch.med':>16}")
prev = None
imp_rows = []
for dep in (0.0, 250.0, 500.0, 1_000.0):
s = sim_split(Rc, Gc, rb, [("F 0.00", "FIX", 0.0), ("F 1.00", "FIX", 1.0)],
N_BASE, lvc, SEED, 1080, deposit_eur=dep)
q0, q1 = summ(s["rows"][0], perp), summ(s["rows"][1], perp)
imp_rows.append((dep, q0, q1))
print(f" EUR{dep:>8,.0f}/m {q0['p50_flow']:>16.1%} {q1['p50_flow']:>16.1%} "
f"{(q1['p50_flow']-q0['p50_flow'])*100:>+12.1f}pp ${q0['med_w']:>15,.0f} "
f"${q1['med_w']:>15,.0f}")
prev = (q0, q1)
d_phi = imp_rows[2][2]["p50_flow"] - imp_rows[2][1]["p50_flow"]
d_dep_tix = imp_rows[2][2]["p50_flow"] - imp_rows[1][2]["p50_flow"]
d_dep_book = imp_rows[2][1]["med_w"] - imp_rows[1][1]["med_w"]
print(f"\n A EUR500/m: passare phi 0->1 vale {d_phi*100:+.1f}pp di P(>=50/g); passare il")
print(f" VERSAMENTO da EUR250 a EUR500 (a phi=1) vale {d_dep_tix*100:+.1f}pp.")
print(f" Sulla RICCHEZZA (phi=0): EUR250 -> EUR500 vale ${d_dep_book:+,.0f} di mediana.")
# ================================================================= §6 60 mesi
hr(f"§6. ORIZZONTE 60 MESI — l'unica ragione strutturale per cui l'ottimo dovrebbe muoversi {clock()}")
p5 = 1.0 - (1.0 - pl.FIRM_DEATH_PER_YEAR) ** 5
print(f" A 5 anni ogni firm muore con p = {p5:.0%}; entrambe con p = {p5**2:.0%}. Il canale")
print(f" biglietto ha VITA FINITA, il libro no. Attesa A3: l'ottimo phi SCENDE.")
POLS60 = ([("F 0.00", "FIX", 0.0), ("F 0.20", "FIX", 0.20), ("F 0.50", "FIX", 0.50),
("F 0.80", "FIX", 0.80), ("F 1.00", "FIX", 1.0),
("TIX $5,000", "TIX", 5_000.0), ("BOOK $5,000", "BOOK", 5_000.0),
("PHI_DN $10k", "PHI_DN", 10_000.0), ("CASH-ATT $1.2k", "CASH", 1_200.0)])
R60: dict = {}
for c in CELLS[:3]:
Rc2, Gc2, lvc2, _ = RG[c]
s = sim_split(Rc2, Gc2, rb, POLS60, N_BASE, lvc2, SEED, 1800, deposit_eur=DEP_MAIN)
R60[c] = {r["lab"]: r for r in s["rows"]}
print(f"\n {'politica':>16} {'P(>=50/g) 36m':>14} {'P(>=50/g) 60m':>14} {'ricch.med 60m':>15} "
f"{'media 60m':>12} {'P(<versato)':>12} {'P(>=50/g) RENDITA 60m':>22}")
for lab, _, _ in POLS60:
q36 = float(np.median([summ(RES[c][lab], perp)["p50_flow"] for c in CELLS[:3]]))
q = {c: summ(R60[c][lab], perp) for c in CELLS[:3]}
g = lambda k: float(np.median([q[c][k] for c in CELLS[:3]])) # noqa: E731
print(f" {lab:>16} {q36:>14.1%} {g('p50_flow'):>14.1%} ${g('med_w'):>14,.0f} "
f"${g('mean_w'):>11,.0f} {g('p_loss'):>12.1%} {g('p50_rend'):>22.1%}")
c60 = pd.DataFrame([dict(phi=float(l.split()[1]),
p50=float(np.median([summ(R60[c][l], perp)["p50_flow"]
for c in CELLS[:3]])),
med=float(np.median([summ(R60[c][l], perp)["med_w"]
for c in CELLS[:3]])))
for l, k, _ in POLS60 if k == "FIX"])
print(f"\n argmax P(>=50/g): 36 mesi phi={a_p50['phi']:.2f} · 60 mesi "
f"phi={c60.loc[c60['p50'].idxmax(),'phi']:.2f}")
print(f" argmax ricchezza mediana: 36 mesi phi={a_med['phi']:.2f} · 60 mesi "
f"phi={c60.loc[c60['med'].idxmax(),'phi']:.2f}")
print(f" >>> ATTESA A3 ('a 60 mesi l'ottimo phi scende'): "
f"{'CONFERMATA' if c60.loc[c60['p50'].idxmax(),'phi'] < a_p50['phi'] else 'SMENTITA'}")
# ================================================================= §7 verdetto
hr(f"§7. VERDETTO {clock()}")
sp = max(sp_pair, 0.0) * 100
rng_p50 = (CV["p50"].max() - CV["p50"].min()) * 100
rng_med = CV["med"].max() - CV["med"].min()
print(f" Ampiezza della CURVA fra phi=0 e phi=1 (36 mesi, EUR{DEP_MAIN:.0f}/m):")
print(f" P(>=50/g) flusso : {rng_p50:.1f} pp (risoluzione MC {sp:.1f} pp) -> "
f"{'SEGNALE' if rng_p50 > 3*sp else 'DENTRO IL RUMORE'}")
print(f" ricchezza mediana: ${rng_med:,.0f}")
print(f" P(>=50/g) rendita: {(CV['prend'].max()-CV['prend'].min())*100:.1f} pp")
print(f" P(<versato) : {(CV['ploss'].max()-CV['ploss'].min())*100:.1f} pp")
print(f"\n In EUR/giorno (mediana, flusso + rendita terminale — le due NON si sommano")
print(f" senza doppio conteggio, si leggono separate):")
for lab in ("F 0.00", "F 0.50", "F 1.00"):
row = CV[CV["lab"] == lab].iloc[0]
print(f" {lab}: EUR {row['eurg']:.2f}/giorno mediani a 36 mesi")
print(f"\n Il target e' EUR {TARGET:.0f}/giorno.")
print(f" TRIALS: nessuna cella SELEZIONATA (la famiglia e' dichiarata nel docstring e tutte")
print(f" le celle sono riportate) -> nessun deflated-Sharpe da calcolare; e la grandezza")
print(f" misurata e' una P, non uno Sharpe.")
print(f"\n {clock()} fine.")
if __name__ == "__main__":
main()