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

795 lines
42 KiB
Python

"""r0823b_ladder_redo — §60 LADDER-REDO: la politica multi-conto e' ancora MISTO? (2026-08-23)
LA DOMANDA
----------
Il 2026-07-25 (`r0725_prop_ladder.py` + `r0725_prop_coupled.py`) il progetto scelse la politica
multi-conto **MISTO** (sleeve diversi su conti diversi) contro CONC-DIV, SPARSO e CONC-2SL:
MISTO 10,70 EUR/g mediana, P(>=50/g) 20,7%, P(zero) 33,4%
> CONC-DIV 5,70 / 17,8% / 33,4%
> SPARSO 0,00 / 16,8% / 66,0%
> CONC-2SL 0,00 / 13,1% / 55,6% (close-only, leva 1,00x)
Da allora il numero operativo del canale funded e' passato **da 42% a 2,6%** (fattore 16) per
tre correzioni misurate in due giorni:
(a) universo XS01 **fuori campione** — 6 delle 19 gambe non esistevano nel 2021-23 e valevano
il **42% del J pubblicato** (§29);
(b) **banda d'ancora di SKH01** — l'offset canonico e' al 91° pctl dei 23 (§32);
(c) **funding** — mai modellato nel 2025, costa dJ -0,049 su 69/69 celle appaiate (§35, §37).
Piu' due lenti che il 25/07 non aveva o aveva diverse: la **wick accoppiata** (misurata il
25/07 sera, dopo il ladder) e il de-luck **x0,89** invece di x0,60 (misurato il 26/07).
**Nessuno ha ri-misurato la politica.** La conclusione "MISTO" e' stata EREDITATA.
LE ATTESE, REGISTRATE PRIMA DI MISURARE
---------------------------------------
A1. **La replica dell'ORDINE riuscira', quella dei LIVELLI no.** `pl.sleeve_panel` ri-deriva le
serie dal feed corrente (+4 settimane dal 25/07): §37 ha gia' visto -11% su `r0725_hyro`
per la stessa ragione. Mi aspetto livelli 10-30% piu' bassi e ordine identico.
A2. **Il funding NON puo' ribaltare l'ordine, e semmai lo RAFFORZA.** Il costo di funding per
sleeve e' misurato (§35/§37, a peso 1,0): TP01 2,10%/a, SKH01 2,32%/a, XS01 1,45%/a. Il
costo medio di politica e' quindi CONC-2SL 2,16% > CONC-A 2,04% > CONC-DIV 1,98% >
SPARSO 1,96% > **MISTO 1,82%** — cioe' il vincitore del 25/07 e' anche quello che paga
MENO funding, ma lo spread e' solo **0,33 pp/anno** (un sesto del costo). Previsione:
tutti i livelli scendono, l'ordine resta, il delta MISTO-vs-resto si allarga di poco e
dentro il rumore.
A3. **La correzione che PUO' ribaltare l'ordine e' XS01, non il funding.** MISTO e SPARSO
poggiano su conti a **XS01 puro** (2/6 e 2/6 slot); se il drift di XS01 fuori campione e'
piu' debole (Sharpe 1,04 e maxDD -19,2% contro -11,2% dello sleeve ufficiale, §29), sono
proprio quelle politiche a perdere. Previsione: **se l'ordine cambia, cambia CONTRO
MISTO/SPARSO e a favore di CONC-DIV / CONC-A**, e per l'universo, non per il funding.
A4. **Il numero di conti e' il vero vincolo, e non e' stato mai misurato.** Con $654 di cassa
e un biglietto HYRO $100k a $579 si compra **UN** conto e restano $75: mi aspetto che la
stragrande maggioranza dei percorsi non arrivi MAI a due conti simultanei, e quindi che
**MISTO e CONC-DIV, che condividono lo slot 0, siano quasi indistinguibili** finche' non
entrano soldi. Previsione: la politica conta poco senza versamenti e molto con versamenti.
A5. **Il deposito rimborsabile (§30) fa piu' differenza sulla SCALA che sull'EV**, perche' i
$579 che tornano ricomprano un biglietto: +1-3pp su P(>=50/g), come previde §37.
COSA FA
-------
§1 REPLICA del 25/07 (`pl.simulate` close-only/indip, `pc.simulate` accoppiata).
§2 CONTROLLI: `ladder_multi` bit-exact contro `pc.simulate`; controllo POSITIVO (una politica
deliberatamente rotta deve finire ultima, o il confronto non ha potenza).
§3 DECOMPOSIZIONE a un grado di liberta' per volta: lente -> de-luck -> universo/finestra ->
funding. E' il metodo di §29: senza, non si sa QUALE correzione fa cosa.
§4 BANDA D'ANCORA: 8 offset x 3 fasi (sottocampione DICHIARATO), con e senza funding, tutte
le politiche insieme sugli STESSI sorteggi -> mediana delle differenze APPAIATE.
§5 La previsione A2 sul funding, verificata.
§6 LA DIMENSIONE MAI TESTATA: la traiettoria del NUMERO DI CONTI nel tempo, con quota
rimborsabile e con/senza versamenti.
§7 MDE, e verdetto.
CONVENZIONI DICHIARATE
----------------------
* Le POLITICHE sono quelle del 25/07, non ridefinite (altrimenti si misura una ridefinizione,
non una correzione). Aggiunte due sole varianti, dichiarate: **CONC-A** = W_A 38/38/25 (il
centro della regione robusta di §29, cioe' la configurazione su cui poggiano §32 e §37) e
**MISTO-A** = MISTO col nucleo W_A al posto di book_div (separa "il nucleo" dal "mescolare").
* Lente **ACCOPPIATA** ovunque nella parte corretta; close-only e indipendente solo come
repliche/controlli. De-luck **x0,89** (conservativo: §32 nota che sulla dimensione d'ancora
e' un doppio conteggio).
* Leva **fissa** e uguale per tutte le politiche: il confronto e' appaiato, e `best_lev` per
configurazione introdurrebbe un grado di liberta' diverso per politica. Girata a 1,00x
(grid piena) e 0,75x (controllo).
* Firm death 10%/anno, cap $200k/firm, fisco 33%, split 80% — tutte ereditate, nessuna scelta.
* Bootstrap a blocchi (20 g) **condiviso**: stessi indici e stessi sorteggi di morte-firm per
TUTTE le politiche -> differenze appaiate.
Rete: NESSUNA (`--no-net` forzato; cache funding e cache Binance gia' su disco).
Uso: `nice -n 19 timeout 900 uv run python scripts/research/r0823b_ladder_redo.py`
"""
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:
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 ladder originale + regole firm (25/07)
import r0822_prop_alloc as PA # noqa: E402 bootstrap/J (22/08)
import r0822b_prop_recal as PR # noqa: E402 (R,G) su pannello libero (22/08)
import r0822b_xs01_oos as X # noqa: E402 motore XS01 + U13 Binance (22/08)
import r0822c_skh_anchor_prop as AP # noqa: E402 offset di SKH01 (22/08)
import r0822d_funding as FD # noqa: E402 funding (22/08)
import r0822d_gate_c as GC # noqa: E402 funding per-sleeve + ladder a 1 cfg (22/08)
from src.portfolio.sleeves import XS_UNIVERSE # noqa: E402
FD.USE_NET = False
EURUSD = pl.EURUSD
TAX_RATE = pl.TAX_RATE
SPLIT = pl.SPLIT
FIRMS = pl.FIRMS
MAXC = pl.MAX_CONCURRENT # 6 slot
HDAYS = pl.HORIZON_MONTHS * 30 # 1080
DELUCK_NEW = PA.DELUCK # 0,89 (26/07)
DELUCK_OLD = pl.DELUCK # 0,60 (25/07)
TARGET = pl.TARGET_EUR_DAY
MIN_PRICE = min(p for F in FIRMS for (_s, p) in F["tickets"])
# --- sottocampioni DICHIARATI (a priori, uniformi) -------------------------------------------
OFFSETS = AP.OFFSETS[::3] # 8 degli 23 offset: 0,90,...,630 — uniforme a priori
PHASES = GC.PHASES_SUB # (0,3,7) — lo stesso di §37
N_PATHS = 1500 # risoluzione MC dichiarata (~+-1pp su P(>=50/g))
N_PATHS_REP = 3000 # per la replica: identico al 25/07
SEED = 20260725 # il seme del 25/07
LEV_MAIN, LEV_ALT = 1.00, 0.75
# `--quick` = AUTO-TEST: esercita ogni ramo di codice in ~2 minuti. NON produce numeri da citare
# (griglia e percorsi ridotti); serve a non scoprire un errore di stampa dopo venti minuti.
QUICK = "--quick" in sys.argv
if QUICK:
OFFSETS = OFFSETS[:2]
PHASES = PHASES[:2]
N_PATHS = 300
N_PATHS_REP = 300
# --- numeri PUBBLICATI da riprodurre ----------------------------------------------------------
PUB_2507 = { # r0725_prop_ladder, CLOSE-ONLY leva 1,00x
"CONC-2SL": (0.00, 0.131, 0.556),
"CONC-DIV": (5.70, 0.178, 0.334),
"SPARSO": (0.00, 0.168, 0.660),
"MISTO": (10.70, 0.207, 0.334),
}
PUB_COUPLED = "P(>=50/g) 5,6-6,5% a 0,75x, P(zero) 52% a 0,75x / 65% a 1,00x (25/07 sera)"
PUB_GATEC = dict(p50g=0.026, pzero=0.403) # §37, W_A, funding dentro, mediana d'ancora
# --- costi di funding per sleeve, PUBBLICATI (§35/§37), a peso 1,0 ----------------------------
FUND_PUB = {"TP01": 0.0210, "SKH01": 0.0232, "XS01": 0.0145}
TRIALS = 0
T0 = time.time()
def bump(n: int = 1) -> None:
global TRIALS
TRIALS += n
def hr(t: str = "") -> None:
print("\n" + "=" * 104)
if t:
print(" " + t)
print("=" * 104)
def tick(lab: str) -> None:
print(f" [{time.time() - T0:6.0f}s] {lab}")
# ==================================================================================
# LA MACCHINA: una scala di conti che gira PIU' POLITICHE sugli STESSI sorteggi
# ==================================================================================
def ladder_multi(Rm: np.ndarray, Gm: np.ndarray, sel: np.ndarray, n_paths: int, lev: float,
seed: int, deluck: float, refund: bool = False, deposit_eur: float = 0.0,
start_eur: float = pl.START_EUR, block: int = 20,
boot: np.ndarray | None = None,
track: bool = False) -> dict:
"""`r0725_prop_coupled.simulate` generalizzato a N politiche in una corsa sola.
Rm, Gm : (giorni, n_cfg) — ritorni di chiusura e gap (<=0) di ciascuna CONFIGURAZIONE.
sel : (n_group, n_slot) — indice di configurazione per ogni slot di ogni politica.
I gruppi (= politiche) sono impilati sull'asse dei percorsi e ricevono **gli stessi indici
di bootstrap e gli stessi sorteggi di morte-firm**: il confronto fra politiche e' appaiato
per costruzione (stesso mondo, allocazione diversa).
Con n_group=1 e refund/deposit spenti consuma il flusso di numeri casuali NELLO STESSO
ORDINE di `pc.simulate` -> deve essere BIT-EXACT (controllo §2).
"""
rng = np.random.default_rng(seed)
L = len(Rm)
n_grp, n_slot = sel.shape
if boot is None:
n_blocks = int(np.ceil(HDAYS / block))
st = rng.integers(0, L - block, size=(n_paths, n_blocks))
boot = (st[:, :, None] + np.arange(block)[None, None, :]).reshape(n_paths, -1)[:, :HDAYS]
# morte-firm: un solo sorteggio (n_days, n_paths, n_firm) == n_days chiamate consecutive
du = rng.random((HDAYS, n_paths, len(FIRMS)))
Rd = Rm - (1.0 - deluck) * Rm.mean(axis=0, keepdims=True)
P = n_grp * n_paths
SELP = np.repeat(sel, n_paths, axis=0) # (P, n_slot)
rowsP = np.arange(P)[:, None]
cash = np.full(P, start_eur * EURUSD)
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)
cum_payout = np.zeros(P)
spent = np.zeros(P)
got_back = np.zeros(P)
n_tickets = np.zeros(P, int)
max_conc = np.zeros(P, int)
max_open = np.zeros(P, int)
ever2 = np.zeros(P, bool)
ever_slot1 = np.zeros(P, bool) # lo slot 1 e' mai stato aperto? (= la politica conta)
traj = np.zeros((HDAYS // 30, n_grp)) if track else None
p_death_day = 1.0 - (1.0 - pl.FIRM_DEATH_PER_YEAR) ** (1 / 365.0)
tick_sorted = [sorted(F["tickets"], key=lambda x: -x[0]) for F in FIRMS]
for t in range(HDAYS):
died = np.tile(du[t], (n_grp, 1)) < p_death_day
newly = died & firm_alive
firm_alive &= ~died
if newly.any():
for fi in range(len(FIRMS)):
kill = newly[:, fi]
if kill.any():
hit = (firm == fi) & kill[:, None]
phase[hit] = -1
notional[hit] = 0.0
if (cash >= MIN_PRICE).any():
for k in range(n_slot):
free = phase[:, k] == -1
if not free.any():
continue
for fi, F in enumerate(FIRMS):
used = np.where(firm == fi, notional, 0.0).sum(axis=1)
for (size, price) in tick_sorted[fi]:
buy = (free & firm_alive[:, fi] & (cash >= price)
& (used + size <= F["cap"]))
if not buy.any():
continue
cash[buy] -= price
spent[buy] += price
n_tickets[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
if k >= 1:
ever_slot1 |= buy
free = free & ~buy
if not free.any():
break
if not free.any():
break
rd = Rd[boot[:, t], :] # (n_paths, n_cfg)
gd = Gm[boot[:, t], :]
rdP = np.tile(rd, (n_grp, 1))
gdP = np.tile(gd, (n_grp, 1))
r = rdP[rowsP, SELP] * lev
g = gdP[rowsP, SELP] * lev
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))))
phase[bust] = -1
notional[bust] = 0.0
passed = in_ev & (eq >= 1.0 + ev_t) & ~bust
phase[passed] = 1
eq[passed] = 1.0
nfu = (phase == 1).sum(axis=1)
max_conc = np.maximum(max_conc, nfu)
max_open = np.maximum(max_open, (phase >= 0).sum(axis=1))
ever2 |= nfu >= 2
if (t + 1) % 30 == 0:
fu = phase == 1
gain = np.where(fu & (eq > 1.0), (eq - 1.0) * notional, 0.0)
net = gain.sum(axis=1) * SPLIT * (1.0 - TAX_RATE)
cum_payout += net
cash += net
pay = fu & (eq > 1.0)
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
if deposit_eur:
cash += deposit_eur * EURUSD
if track:
traj[(t + 1) // 30 - 1] = nfu.reshape(n_grp, n_paths).mean(axis=1)
out = []
for gi in range(n_grp):
s = slice(gi * n_paths, (gi + 1) * n_paths)
ed = cum_payout[s] / EURUSD / (HDAYS / 365.0) / 365.0
out.append(dict(eur_day=ed, med=float(np.median(ed)),
p10=float(np.percentile(ed, 10)), p90=float(np.percentile(ed, 90)),
mean=float(ed.mean()),
p_ge10=float((ed >= 10.0).mean()),
p_target=float((ed >= TARGET).mean()),
p_zero=float((cum_payout[s] <= 0).mean()),
n_tickets=float(n_tickets[s].mean()),
max_conc=float(max_conc[s].mean()),
max_open=float(max_open[s].mean()),
p_ever2=float(ever2[s].mean()),
p_slot1=float(ever_slot1[s].mean()),
med_cash=float(np.median(cash[s])),
mean_back=float(got_back[s].mean()),
spent=float(spent[s].mean())))
bump(n_grp)
return dict(groups=out, traj=traj)
# ==================================================================================
# POLITICHE
# ==================================================================================
W_2SL = {"TP01": 0.75, "SKH01": 0.25}
W_DIV = {"TP01": 0.55, "SKH01": 0.20, "XS01": 0.25}
W_A = {"TP01": 0.38, "SKH01": 0.38, "XS01": 0.25}
W_TP = {"TP01": 1.0}
W_SKH = {"SKH01": 1.0}
W_XS = {"XS01": 1.0}
CFGS = [W_2SL, W_DIV, W_A, W_TP, W_SKH, W_XS] # indici 0..5
I2SL, IDIV, IA, ITP, ISKH, IXS = range(6)
POLICIES = {
"CONC-2SL ogni conto = book live": [I2SL] * MAXC,
"CONC-DIV ogni conto = diversif.": [IDIV] * MAXC,
"SPARSO 1 sleeve per conto": [ITP, IXS, ISKH, ITP, IXS, ISKH],
"MISTO meta' div / meta' single": [IDIV, IXS, IDIV, ITP, IDIV, IXS],
"CONC-A ogni conto = W_A 38/38/25": [IA] * MAXC,
"MISTO-A MISTO col nucleo W_A": [IA, IXS, IA, ITP, IA, IXS],
}
PNAMES = list(POLICIES)
SEL = np.array([POLICIES[p] for p in PNAMES], dtype=int)
SHORT = [p.split()[0] for p in PNAMES]
def _tab(rows: list[tuple], head: tuple) -> None:
print(" " + " ".join(f"{h:>{w}}" for h, w in head))
for r in rows:
print(" " + " ".join(f"{v:>{w}}" for v, (_h, w) in zip(r, head)))
# ==================================================================================
def main() -> None:
try:
sys.stdout.reconfigure(line_buffering=True)
except Exception: # pragma: no cover
pass
print("=" * 104)
print(" §60 LADDER-REDO — la politica multi-conto e' ancora MISTO?")
print("=" * 104)
print(" ATTESE REGISTRATE (dal docstring, prima di misurare):")
print(" A1 l'ORDINE del 25/07 si replica, i LIVELLI no (+4 settimane di feed).")
print(" A2 il FUNDING non ribalta l'ordine e semmai lo rafforza (MISTO paga MENO:")
print(" 1,82%/a contro 2,16% di CONC-2SL; spread 0,33pp = un sesto del costo).")
print(" A3 se l'ordine cambia, cambia per l'UNIVERSO XS01 e CONTRO MISTO/SPARSO.")
print(" A4 con $654 si compra UN conto: la politica quasi non conta senza versamenti.")
print(" A5 il deposito rimborsabile vale piu' sulla SCALA che sull'EV (+1-3pp).")
# ============================================================ §1 REPLICA 25/07
hr("§1. REPLICA — i numeri pubblicati il 25/07, rigirati oggi con la stessa macchina")
M, names = pl.sleeve_panel()
print(f" pannello `pl.sleeve_panel()`: {len(M)} giorni, sleeve {names}, de-luck x{DELUCK_OLD}")
pols_old = pl.policies(names)
rows = []
got = {}
for pname, slots in pols_old.items():
key = pname.split()[0]
r = pl.simulate(M, slots, n_paths=N_PATHS_REP, lev=1.0, seed=SEED, intraday=False)
got[key] = (r["med"], r["p_target"], r["p_zero"])
pmed, pp50, ppz = PUB_2507[key]
rows.append((key, f"{r['med']:.2f}", f"{pmed:.2f}",
f"{r['p_target']:.1%}", f"{pp50:.1%}",
f"{r['p_zero']:.1%}", f"{ppz:.1%}"))
bump()
_tab(rows, (("politica", 9), ("EUR/g oggi", 11), ("PUB", 6),
("P>=50 oggi", 11), ("PUB", 6), ("P0 oggi", 8), ("PUB", 6)))
ord_now = sorted(got, key=lambda k: -got[k][1])
ord_pub = sorted(PUB_2507, key=lambda k: -PUB_2507[k][1])
same = ord_now == ord_pub
print(f"\n ordine su P(>=50/g) oggi: {' > '.join(ord_now)}")
print(f" ordine su P(>=50/g) 25/07: {' > '.join(ord_pub)}")
print(f" >>> ORDINE {'REPLICATO' if same else 'NON replicato'}; livelli "
f"{'piu bassi' if np.mean([got[k][1] for k in got]) < np.mean([PUB_2507[k][1] for k in PUB_2507]) else 'piu alti'}"
f" (media P(>=50/g) {np.mean([got[k][1] for k in got]):.1%} contro "
f"{np.mean([PUB_2507[k][1] for k in PUB_2507]):.1%}).")
print(" A1 " + ("CONFERMATA" if same else "REFUTATA") +
" — `pl.sleeve_panel` ri-deriva le serie dal feed CORRENTE (stessa causa del -11%")
print(" che §37 misuro' su `r0725_hyro`): la macchina e' quella, il vintage no.")
tick("§1")
# ============================================================ §2 CONTROLLI
hr("§2. CONTROLLI — bit-exact contro `pc.simulate`, e un controllo POSITIVO")
cfgs_pc = [(0.75, 0.25, 0.0), (0.55, 0.20, 0.25), (1.0, 0.0, 0.0),
(0.0, 1.0, 0.0), (0.0, 0.0, 1.0)]
START_OLD = "2024-01-01"
mats = [pc.book_tuples(*c, start=START_OLD) for c in cfgs_pc]
Lc = min(len(m[0]) for m in mats)
Rc = np.stack([m[0][-Lc:] for m in mats], axis=1)
Gc = np.stack([m[1][-Lc:] for m in mats], axis=1)
pc.DELUCK = DELUCK_OLD
slots_conc = [0] * MAXC
ref = pc.simulate(cfgs_pc, slots_conc, n_paths=800, lev=1.0, seed=99,
lens="coupled", start=START_OLD)
mine = ladder_multi(Rc, Gc, np.array([slots_conc]), n_paths=800, lev=1.0, seed=99,
deluck=DELUCK_OLD)["groups"][0]
d = float(np.abs(np.sort(ref["eur_day"]) - np.sort(mine["eur_day"])).max())
d2 = float(np.abs(ref["eur_day"] - mine["eur_day"]).max())
print(f" ladder_multi (1 gruppo) vs pc.simulate, lente accoppiata, 800 percorsi:")
print(f" max|diff| percorso-per-percorso = {d2:.3e} (ordinati: {d:.3e})")
print(f" -> {'BIT-EXACT' if d2 == 0.0 else 'DIVERGENTE'}")
# controllo positivo: una politica volutamente rotta (leva 3x = busta subito) deve finire ultima
selpos = np.array([slots_conc, slots_conc])
rp = ladder_multi(Rc, Gc, selpos, n_paths=800, lev=1.0, seed=99, deluck=DELUCK_OLD)
rbad = ladder_multi(Rc, Gc, np.array([slots_conc]), n_paths=800, lev=3.0, seed=99,
deluck=DELUCK_OLD)["groups"][0]
ok_pos = rbad["p_target"] < rp["groups"][0]["p_target"]
print(f" controllo POSITIVO — la stessa politica a leva 3,00x (deve bustare):")
print(f" P(>=50/g) 1,00x {rp['groups'][0]['p_target']:.1%} vs 3,00x {rbad['p_target']:.1%}"
f" -> {'il confronto ha POTENZA' if ok_pos else '!! NESSUNA POTENZA'}")
print(f" controllo di pairing — due gruppi identici devono dare lo stesso vettore: "
f"max|diff| {np.abs(rp['groups'][0]['eur_day'] - rp['groups'][1]['eur_day']).max():.3e}")
tick("§2")
# ============================================================ §3 pannello corretto
hr("§3. IL PANNELLO CORRETTO — U13 Binance fuori campione, W-LONG 2021+, funding")
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])
XSP = {ph: PR.xs_tuples(p13, o13, h13, l13, phase=ph) for ph in PHASES}
bump(len(PHASES))
xs0 = XSP[PHASES[0]]
cry_idx = pc.crypto_daily_tuples(1.0, 0.0).index
base = cry_idx.intersection(xs0.index)
first13 = xs0.index[np.flatnonzero(xs0["R"].values != 0.0)[0]]
S_LONG = max(first13, pd.Timestamp("2021-01-01", tz="UTC"))
I = base[base >= S_LONG]
print(f" W-LONG: {len(I)} giorni {I[0].date()} -> {I[-1].date()} | "
f"XS01 = U13 Binance ({len(X.U13)} gambe) | de-luck x{DELUCK_NEW}")
rate = GC.funding_rate()
if rate is None:
print(" !! cache funding assente: il filone NON puo' rispondere alla domanda (c). STOP.")
return
xsf = GC.xs_funding_measure(verbose=False)
xs_ann = xsf["ann"]
print(f" funding: TP01/SKH01 da serie misurate; XS01 = {xs_ann*100:+.2f}%/anno costante "
f"(§37, IC95 [{(xs_ann-1.96*xsf['se'])*100:+.2f}, {(xs_ann+1.96*xsf['se'])*100:+.2f}])")
boot = PA.boot_idx(len(I), HDAYS, N_PATHS, seed=SEED)
def build_on(idx: pd.DatetimeIndex, xs: pd.DataFrame, off: int,
fund: bool) -> tuple[np.ndarray, np.ndarray]:
"""(R, gap) di TUTTE le configurazioni su un indice e una serie XS01 dati."""
R = np.zeros((len(idx), len(CFGS)))
G = np.zeros((len(idx), len(CFGS)))
for ci, w in enumerate(CFGS):
r, g = AP.rg_off(w, idx, xs, off)
if fund:
r = r - GC.fvec_for(w, idx, rate, off, xs_ann)
R[:, ci], G[:, ci] = r, g
return R, G
def build(off: int, ph: int, fund: bool) -> tuple[np.ndarray, np.ndarray]:
return build_on(I, XSP[ph], off, fund)
# costo di funding EFFETTIVO per configurazione (verifica di A2)
print(f"\n costo di funding per configurazione (%/anno di equity a leva 1,00x, off 0):")
fcost = {}
for ci, w in enumerate(CFGS):
fv = GC.fvec_for(w, I, rate, 0, xs_ann)
fcost[ci] = float(np.mean(fv)) * 365 * 100
nm = ["book_2SL", "book_DIV", "W_A", "TP01 solo", "SKH01 solo", "XS01 solo"]
for ci in range(len(CFGS)):
pred = sum(FUND_PUB[k] * v for k, v in CFGS[ci].items()) * 100
print(f" {nm[ci]:<11} misurato {fcost[ci]:>5.2f}%/a atteso da §35/§37 {pred:>5.2f}%/a")
# CONTROLLO: il reindex su I non deve mangiare barre in silenzio (un NaN->0 e' un costo
# sottostimato che nessun numero segnala).
cov_tp = float(GC.f_tp01_sleeve(rate).reindex(I).notna().mean())
cov_sk = float(GC.f_skh_sleeve(rate, 0).reindex(I).notna().mean())
print(f" CONTROLLO di copertura su W-LONG: TP01 {cov_tp:.1%} delle barre, SKH01 {cov_sk:.1%}"
f" -> {'ok' if min(cov_tp, cov_sk) > 0.99 else '!! IL REINDEX MANGIA BARRE'}")
print(" ⚠ I costi misurati sono PIU' BASSI degli attesi, e non e' un disaccordo: §35 pubblica")
print(" -2,16%/a sul 2019+, -1,39% sul 2022-03+ e -0,55% sul 2025+ (il costo SCENDE nel")
print(" tempo) e questa finestra parte nel 2021. Costo del libro 75/25, anno per anno:")
fser = pd.Series(GC.fvec_for(W_2SL, I, rate, 0, xs_ann), index=I)
print(" " + " ".join(f"{y}:{float(g.mean()*365)*100:.2f}%"
for y, g in fser.groupby(fser.index.year)))
print(f" 🚨 Su tutta la storia oraria SKH01 paga -2,32% e TP01 -2,10% (§35). Su W-LONG sono")
print(f" {fcost[ISKH]:.2f}% e {fcost[ITP]:.2f}%: **il verso del confronto TP01-vs-SKH01 sul")
print(f" funding si INVERTE cambiando finestra** — l'aritmetica con cui avevo derivato A2")
print(f" usava i numeri di storia piena, quindi la previsione va verificata, non dedotta.")
print(f" costo di funding per POLITICA (media sugli slot):")
polfund = {}
for pi, p in enumerate(PNAMES):
v = float(np.mean([fcost[c] for c in SEL[pi]]))
polfund[SHORT[pi]] = v
print(f" {SHORT[pi]:<9} {v:>5.2f}%/a")
tick("§3")
# ============================================================ §4 decomposizione
hr("§4. DECOMPOSIZIONE — un grado di liberta' per volta (ancora 0, fase 0, leva 1,00x)")
print(" Senza questa tabella si sa che il numero e' cambiato, non QUALE correzione lo cambia.")
# gli indici di CFGS non sono quelli di cfgs_pc: si rimappa (le prime 4 politiche sono
# le uniche del 25/07; CONC-A e MISTO-A non esistevano e compaiono solo dal passo S3).
map_pc = {I2SL: 0, IDIV: 1, ITP: 2, ISKH: 3, IXS: 4}
sel4_pc = np.array([[map_pc[c] for c in POLICIES[p]] for p in PNAMES[:4]])
bpc = PA.boot_idx(Lc, HDAYS, N_PATHS, seed=SEED)
s0 = ladder_multi(Rc, np.zeros_like(Gc), sel4_pc, N_PATHS, 1.0, SEED, DELUCK_OLD, boot=bpc)
s1 = ladder_multi(Rc, Gc, sel4_pc, N_PATHS, 1.0, SEED, DELUCK_OLD, boot=bpc)
s2 = ladder_multi(Rc, Gc, sel4_pc, N_PATHS, 1.0, SEED, DELUCK_NEW, boot=bpc)
# --- S2b/S3a: UNIVERSO e FINESTRA separati, sullo STESSO indice comune (crypto n HL n Bin).
XS_HL = pc.xsec_daily_tuples("shared")
I24 = I[I >= pd.Timestamp("2024-01-01", tz="UTC")].intersection(XS_HL.index)
b24 = PA.boot_idx(len(I24), HDAYS, N_PATHS, seed=SEED)
R2b, G2b = build_on(I24, XS_HL, 0, False)
Rchk, Gchk, Ichk = pc.book_tuples(0.55, 0.20, 0.25, start="2024-01-01")
kk = pd.DatetimeIndex(Ichk).isin(I24)
jj = pd.DatetimeIndex(I24).isin(pd.DatetimeIndex(Ichk))
dchk = float(np.abs(Rchk[kk] - R2b[:, IDIV][jj]).max())
print(f" CONTROLLO: `rg_off` con le tuple HL riproduce `pc.book_tuples` (book_div) su "
f"{int(kk.sum())} giorni a max|diff| = {dchk:.3e}")
s2b = ladder_multi(R2b, G2b, SEL[:4], N_PATHS, 1.0, SEED, DELUCK_NEW, boot=b24)
R3a, G3a = build_on(I24, XSP[PHASES[0]], 0, False)
s3a = ladder_multi(R3a, G3a, SEL[:4], N_PATHS, 1.0, SEED, DELUCK_NEW, boot=b24)
R3, G3 = build(0, PHASES[0], False)
s3 = ladder_multi(R3, G3, SEL[:4], N_PATHS, 1.0, SEED, DELUCK_NEW, boot=boot)
R4, G4 = build(0, PHASES[0], True)
s4 = ladder_multi(R4, G4, SEL[:4], N_PATHS, 1.0, SEED, DELUCK_NEW, boot=boot)
lab = ["S0 25/07 tale e quale (HL19 2024+, close-only, x0,60)",
"S1 + lente ACCOPPIATA (misurata il 25/07 SERA)",
"S2 + de-luck x0,89 invece di x0,60 (26/07)",
"S2b [= S2 su indice comune: controllo di macchina]",
"S3a + UNIVERSO: XS01 = U13 Binance, stessa finestra",
"S3b + FINESTRA: W-LONG 2021+ (fuori campione)",
"S4 + FUNDING = la lente onesta di oggi"]
ALL = (s0, s1, s2, s2b, s3a, s3, s4)
print(f"\n P(>=50 EUR/g) per politica, {N_PATHS} percorsi, stessi sorteggi:")
print(" " + f"{'passo':<52}" + "".join(f"{s:>10}" for s in SHORT[:4]) + f"{' ordine':<40}")
for l, st in zip(lab, ALL):
v = [g["p_target"] for g in st["groups"]]
o = " > ".join([SHORT[i] for i in np.argsort(-np.array(v))])
print(f" {l:<52}" + "".join(f"{x:>9.1%} " for x in v) + f" {o:<40}")
print(f"\n EUR/g MEDIO per politica (la MEDIANA e' degenere: tabella sotto):")
print(" " + f"{'passo':<52}" + "".join(f"{s:>10}" for s in SHORT[:4]))
for l, st in zip(lab, ALL):
print(f" {l:<52}" + "".join(f"{g['mean']:>9.2f} " for g in st["groups"]))
print(f"\n EUR/g MEDIANA — il numero di TESTA del 25/07 era 'MISTO 10,70':")
print(" " + f"{'passo':<52}" + "".join(f"{s:>10}" for s in SHORT[:4]))
for l, st in zip(lab, ALL):
print(f" {l:<52}" + "".join(f"{g['med']:>9.2f} " for g in st["groups"]))
tick("§4")
# ============================================================ §5 banda d'ancora
hr(f"§5. BANDA D'ANCORA — {len(OFFSETS)} offset x {len(PHASES)} fasi, "
f"funding ON/OFF, {len(PNAMES)} politiche")
print(f" offset (sottocampione uniforme DICHIARATO dei 23): {list(OFFSETS)}")
print(f" fasi XS01: {list(PHASES)} (lo stesso sottocampione di §37)")
print(f" leva {LEV_MAIN:.2f}x fissa e uguale per tutte (confronto appaiato); "
f"{N_PATHS} percorsi condivisi.")
cells = []
REF: dict[str, np.ndarray] = {} # vettori per-percorso alla cella di riferimento
for off in OFFSETS:
for ph in PHASES:
for fund in (False, True):
R, G = build(off, ph, fund)
res = ladder_multi(R, G, SEL, N_PATHS, LEV_MAIN, SEED, DELUCK_NEW, boot=boot)
for pi, g in enumerate(res["groups"]):
cells.append(dict(off=off, ph=ph, fund=fund, pol=SHORT[pi],
p50=g["p_target"], pz=g["p_zero"], med=g["med"],
p10g=g["p_ge10"], mean=g["mean"], ever2=g["p_ever2"],
slot1=g["p_slot1"], ntix=g["n_tickets"],
maxc=g["max_conc"]))
if off == 0 and ph == PHASES[0] and fund:
REF[SHORT[pi]] = g["eur_day"]
tick(f"offset {off}")
C = pd.DataFrame(cells)
for fund, flab in ((True, "CON funding (la lente onesta)"), (False, "SENZA funding")):
s = C[C["fund"] == fund]
print(f"\n --- {flab} — mediana sulle {len(OFFSETS)*len(PHASES)} celle d'ancora")
print(f" {'politica':>10} {'P(>=50/g)':>10} {'banda ancora p10-p90':>22} {'P(zero)':>9} "
f"{'EUR/g med':>10} {'EUR/g medio':>12} {'P(>=10/g)':>10} {'P(2o conto)':>12}")
for p in SHORT:
q = s[s["pol"] == p]
print(f" {p:>10} {q['p50'].median():>10.2%} "
f"[{np.percentile(q['p50'],10):>9.2%},{np.percentile(q['p50'],90):>9.2%}] "
f"{q['pz'].median():>9.1%} {q['med'].median():>10.2f} "
f"{q['mean'].median():>12.2f} {q['p10g'].median():>10.1%} "
f"{q['slot1'].median():>12.1%}")
print(" ordine per metrica (se le tre non concordano, la classifica e' un artefatto")
print(" della metrica scelta, non un fatto):")
for mkey, mlab in (("p50", "P(>=50/g)"), ("mean", "EUR/g medio"), ("p10g", "P(>=10/g)")):
o = s.groupby("pol")[mkey].median().sort_values(ascending=False)
print(f" {mlab:<12} {' > '.join(o.index)}")
# riproduzione di §37 (W_A = CONC-A, funding dentro)
q = C[(C["fund"]) & (C["pol"] == "CONC-A")]
print(f"\n RIPRODUZIONE §37 (CONC-A = W_A 38/38/25, funding dentro, mediana d'ancora):")
print(f" P(>=50/g) {q['p50'].median():.1%} (PUB {PUB_GATEC['p50g']:.1%}) | "
f"P(zero) {q['pz'].median():.1%} (PUB {PUB_GATEC['pzero']:.1%})")
print(" ⚠ non e' identica per costruzione: §37 usa `best_lev` per configurazione e 23")
print(" offset x 3 fasi; qui la leva e' FISSA a 1,00x per tutte le politiche (appaiato)")
print(f" e gli offset sono {len(OFFSETS)}. L'ordine di grandezza e' il controllo.")
# differenze APPAIATE cella per cella
print(f"\n DIFFERENZE APPAIATE cella per cella (mediana delle differenze, mai differenza")
print(f" delle mediane), funding dentro. Riferimento = MISTO (il vincitore del 25/07):")
sf = C[C["fund"]]
piv = sf.pivot_table(index=["off", "ph"], columns="pol", values="p50")
ncell = len(piv)
print(f" {'politica':>10} {'d P(>=50/g) vs MISTO':>22} {'>0 su celle':>13} "
f"{'p10':>8} {'p90':>8}")
for p in SHORT:
if p == "MISTO":
continue
d = piv[p] - piv["MISTO"]
print(f" {p:>10} {d.median()*100:>21.2f}pp {int((d>0).sum()):>7}/{ncell:<5} "
f"{np.percentile(d,10)*100:>7.2f}pp {np.percentile(d,90)*100:>7.2f}pp")
# --- controllo di LEVA: l'ordine dipende dalla leva scelta?
print(f"\n CONTROLLO DI LEVA — le stesse celle a {LEV_ALT:.2f}x (off 0, {len(PHASES)} fasi,")
print(f" funding ON). Se l'ordine cambia con la leva, non e' una proprieta' della politica:")
alt = []
for ph in PHASES:
R, G = build(0, ph, True)
res = ladder_multi(R, G, SEL, N_PATHS, LEV_ALT, SEED, DELUCK_NEW, boot=boot)
for pi, g in enumerate(res["groups"]):
alt.append(dict(ph=ph, pol=SHORT[pi], p50=g["p_target"], pz=g["p_zero"],
mean=g["mean"]))
A = pd.DataFrame(alt)
oa = A.groupby("pol")["p50"].median().sort_values(ascending=False)
o1 = C[(C["fund"]) & (C["off"] == 0)].groupby("pol")["p50"].median().sort_values(ascending=False)
print(f" {'politica':>10} {'P(>=50/g) @0,75x':>18} {'P(>=50/g) @1,00x':>18} {'P(zero) @0,75x':>16}")
for p_ in SHORT:
print(f" {p_:>10} {A[A['pol']==p_]['p50'].median():>17.2%} "
f"{o1[p_]:>17.2%} {A[A['pol']==p_]['pz'].median():>15.1%}")
print(f" ordine @0,75x: {' > '.join(oa.index)}")
print(f" ordine @1,00x: {' > '.join(o1.index)}")
print(f" -> {'STESSO ordine' if list(oa.index) == list(o1.index) else 'ORDINE DIVERSO: la leva conta'}")
tick("§5")
# ============================================================ §6 la previsione sul funding
hr("§6. LA PREVISIONE A2 SUL FUNDING, VERIFICATA (appaiata cella per cella)")
pv = C.pivot_table(index=["off", "ph", "pol"], columns="fund", values="p50")
pv = pv.reset_index()
print(f" {'politica':>10} {'costo fund %/a':>15} {'d P(>=50/g)':>13} {'<0 su celle':>13} "
f"{'d EUR/g med':>13}")
dmed = {}
for p in SHORT:
q = pv[pv["pol"] == p]
d = (q[True] - q[False]).values
dmed[p] = float(np.median(d))
pm = C.pivot_table(index=["off", "ph", "pol"], columns="fund", values="med").reset_index()
qm = pm[pm["pol"] == p]
dm = (qm[True] - qm[False]).values
print(f" {p:>10} {polfund[p]:>14.2f}% {np.median(d)*100:>12.2f}pp "
f"{int((d<0).sum()):>7}/{len(d):<5} {np.median(dm):>12.2f}")
ordf_on = C[C["fund"]].groupby("pol")["p50"].median().sort_values(ascending=False).index.tolist()
ordf_off = C[~C["fund"]].groupby("pol")["p50"].median().sort_values(ascending=False).index.tolist()
a2 = ordf_on == ordf_off
print(f"\n ordine SENZA funding: {' > '.join(ordf_off)}")
print(f" ordine CON funding: {' > '.join(ordf_on)}")
print(f" >>> A2 {'CONFERMATA' if a2 else 'REFUTATA'}: il funding "
f"{'NON cambia' if a2 else 'CAMBIA'} l'ordine fra politiche.")
cc = np.corrcoef([polfund[p] for p in SHORT], [dmed[p] for p in SHORT])[0, 1]
print(f" correlazione (costo di funding della politica, danno misurato): {cc:+.2f} "
f"[atteso negativo: chi paga di piu' perde di piu']")
tick("§6")
# ============================================================ §7 numero di conti
hr("§7. LA DIMENSIONE MAI TESTATA — il NUMERO DI CONTI non e' dato, si COMPRA")
Rf, Gf = build(0, 0, True)
scen = [("nessun versamento, quota persa", 0.0, False),
("nessun versamento, quota RIMBORSATA (§30)", 0.0, True),
("EUR 500/mese, quota persa", 500.0, False),
("EUR 500/mese, quota RIMBORSATA", 500.0, True)]
trajs = {}
for lab_s, dep, ref_ in scen:
res = ladder_multi(Rf, Gf, SEL, N_PATHS, LEV_MAIN, SEED, DELUCK_NEW,
refund=ref_, deposit_eur=dep, boot=boot, track=True)
trajs[lab_s] = res
print(f"\n --- {lab_s}")
print(f" {'politica':>10} {'biglietti':>10} {'max conti':>10} {'P(mai >=2)':>11} "
f"{'P(>=50/g)':>10} {'EUR/g med':>10} {'P(zero)':>9} {'rimborso $':>11}")
for pi, g in enumerate(res["groups"]):
print(f" {SHORT[pi]:>10} {g['n_tickets']:>10.2f} {g['max_conc']:>10.2f} "
f"{1-g['p_ever2']:>10.1%} {g['p_target']:>10.1%} {g['med']:>10.2f} "
f"{g['p_zero']:>9.1%} {g['mean_back']:>11.0f}")
print("\n TRAIETTORIA del numero MEDIO di conti funded vivi (mesi 6/12/18/24/30/36):")
for lab_s in trajs:
tr = trajs[lab_s]["traj"]
print(f" {lab_s:<44}" + "".join(
f"{tr[m-1].mean():>7.2f}" for m in (6, 12, 18, 24, 30, 36)))
print("\n DISPERSIONE fra politiche (max-min di P(>=50/g)) per scenario — quanto CONTA")
print(" la scelta della politica:")
for lab_s in trajs:
v = [g["p_target"] for g in trajs[lab_s]["groups"]]
best = SHORT[int(np.argmax(v))]
print(f" {lab_s:<44} spread {max(v)-min(v):>6.2%} vincitore {best}")
tick("§7")
# ============================================================ §8 MDE e verdetto
hr("§8. MDE — la finestra distingue davvero due politiche?")
sf = C[C["fund"]]
piv = sf.pivot_table(index=["off", "ph"], columns="pol", values="p50")
print(" TRE risoluzioni, e sono cose DIVERSE. Confonderle e' il modo standard di trasformare")
print(" rumore in classifica.")
print(f"\n (a) MONTE CARLO appaiato, cella di riferimento (off 0, fase {PHASES[0]}, funding ON):")
print(" i due esiti sono osservati sugli STESSI percorsi -> SE di McNemar sui discordanti.")
print(f" {'coppia':>22} {'d P(>=50/g)':>13} {'discordanti':>12} {'SE':>8} {'z':>8}")
base = REF["MISTO"] >= TARGET
for p_ in SHORT:
if p_ == "MISTO":
continue
oth = REF[p_] >= TARGET
n01 = int((base & ~oth).sum())
n10 = int((~base & oth).sum())
d = float(base.mean() - oth.mean())
se = float(np.sqrt(n01 + n10) / len(base)) if (n01 + n10) else float("nan")
z = d / se if se and se > 0 else float("nan")
print(f" {'MISTO - ' + p_:>22} {d*100:>+12.2f}pp {n01 + n10:>12} "
f"{se*100:>7.2f}pp {z:>+8.2f}")
print(" ⚠ e' la risoluzione della SIMULAZIONE, non dell'evidenza: dice se due politiche")
print(" differiscono SU QUESTI percorsi, non se differirebbero nel mondo.")
print(f"\n (b) BANDA D'ANCORA sulle {len(piv)} celle (mediana delle differenze APPAIATE).")
print(" 🚨 NON e' un intervallo di confidenza e non ci si attacca un p-value (regola §57:")
print(" le 24 ancore correlano 0,63 e valgono ~2 osservazioni indipendenti). Si legge come")
print(" robustezza alla SCELTA dell'ancora, e basta:")
print(f" {'coppia':>22} {'mediana':>11} {'p10':>11} {'p90':>11} {'segno tenuto':>14}")
for p_ in SHORT:
if p_ == "MISTO":
continue
d = (piv["MISTO"] - piv[p_]).values
print(f" {'MISTO - ' + p_:>22} {np.median(d)*100:>+10.2f}pp "
f"{np.percentile(d,10)*100:>+10.2f}pp {np.percentile(d,90)*100:>+10.2f}pp "
f"{int((d>0).sum()):>6}/{len(d):<7}")
yrs = len(I) / 365.25
print(f"\n (c) DATO — l'unica che limita davvero. La finestra e' {yrs:.1f} anni e i {N_PATHS}")
print(f" percorsi sono ricampionamenti degli STESSI {len(I)} giorni: il bootstrap non crea")
print(f" informazione. MDE sul drift ~ 1,96/sqrt({yrs:.1f}) = {1.96/np.sqrt(yrs):.2f} di Sharpe.")
print(" Il differenziale di FUNDING fra politiche misurato in §3 e' ~0,10pp/anno di drift:")
print(" irrisorio rispetto all'MDE. Cio' che le politiche possono davvero separare non e'")
print(" un differenziale di rendimento ma la GEOMETRIA — correlazione fra conti e")
print(" barriera per-conto — e quella si misura sulla forma, non sul drift.")
hr("VERDETTO")
fin = C[C["fund"]].groupby("pol")["p50"].median().sort_values(ascending=False)
fin_med = C[C["fund"]].groupby("pol")["med"].median()
fin_pz = C[C["fund"]].groupby("pol")["pz"].median()
for p in fin.index:
print(f" {p:>10} P(>=50/g) {fin[p]:>6.2%} EUR/g med {fin_med[p]:>6.2f} "
f"P(zero) {fin_pz[p]:>6.1%}")
win = fin.index[0]
print(f"\n VINCITORE OGGI: {win} (25/07: MISTO)")
print(f" celle valutate: {len(C)} righe = {len(OFFSETS)}x{len(PHASES)}x2x{len(PNAMES)}; "
f"valutazioni MC totali contate al rialzo: {TRIALS}")
print(f" tempo {time.time()-T0:.0f}s")
print("=" * 104)
if __name__ == "__main__":
main()