#!/usr/bin/env python """r0823b_obiettivo_diretto — OTTIMIZZARE DIRETTAMENTE L'OBIETTIVO DEL PROGETTO (2026-08-23). §58 dell'ondata. Libro, pesi, cron, config: NON TOCCATI (isolamento provato in §0). IL BUCO ------- Ogni ottimizzazione fatta in questo progetto ha massimizzato **un'altra cosa**: * lo **Sharpe** (ogni filone di ricerca direzionale); * **J = P(pass) x P(alive)** (PROP-ALLOC §17, PROP-RECAL §29, SKH-ANCHOR-PROP §32); * **E[payout]** (r0725_hyro, §37); * il **capitale mediano** o **P(arrivare al capitale-rendita)** (§36, r0807_piano_netto). E il critico di §37 ha scritto la frase che apre questo filone: «piu' leva sul funded ALZA E[payout] e ABBASSA P(payout): sono due obiettivi diversi». **Nessuno ha mai ottimizzato DIRETTAMENTE `P(reddito >= 50 EUR/giorno entro H)`**, che e' l'obiettivo DICHIARATO del progetto. I numeri operativi pubblicati (42% -> 7,8% -> 4,4% -> 2,6%) sono tutti **letti alla cella che massimizza J**, non alla cella che massimizza P. LE DUE DEFINIZIONI, DICHIARATE PRIMA DI MISURARE ------------------------------------------------ Il progetto ne usa DUE senza mai metterle sulla stessa pagina, e danno risposte opposte: **A — RICCHEZZA (rendita sostenibile).** «reddito >= 50 EUR/g» = il patrimonio PROPRIO raggiunge il **capitale-rendita** (muro), cioe' il capitale da cui si preleva 50 EUR/g con P(capitale a 20 anni >= capitale iniziale) >= 90% (definizione 25/07, invariata). E' la definizione dei muri, delle traiettorie e di tutto il piano (§36). E' **sostenibile per costruzione**. **B — FLUSSO (produzione realizzata).** «reddito >= 50 EUR/g» = la media dei payout incassati sull'orizzonte, `cum_payout / giorni`, >= 50 EUR/g. E' la definizione di `r0725_prop_ladder` e quindi di **ogni numero del canale funded** (§29 7,8% · §32 4,4% · §37 2,6%). **NON e' sostenibile**: un conto funded che busta il giorno dopo l'orizzonte azzera il flusso, e la stessa cassa che il contatore chiama «reddito» resta nel conto (nel simulatore ufficiale la cassa si accumula E conta come reddito: e' una PRODUZIONE, non un prelievo). Qui si misurano **entrambe**, sullo stesso Monte Carlo e sugli stessi percorsi, e si riporta come cambia la risposta. Primaria = **A**, perche' e' quella su cui il progetto ha costruito il muro, i versamenti e la decisione di venue; B si riporta perche' e' quella dei numeri pubblicati. LO SPAZIO DI POLITICA — dichiarato esaustivamente PRIMA di misurare -------------------------------------------------------------------- 1. `k` leva del libro proprio {1,00 · 1,25 · 1,50} (§38: la chiave NON esiste) 2. `own` ripartizione del libro proprio {LIVE 75/25 · W_A 38/38/25} 3. `lev_fu` leva del conto funded {0,50 · 0,75 · 1,00 · 1,25} 4. `n_max` numero di conti concorrenti {0 · 1 · 3 · 6} (0 = nessun biglietto) 5. `pref` taglia del biglietto {grande · piccolo} 6. `rebuy` ri-comprare dopo un bust {si' · no} 7. `floor` capitale proprio sotto cui NON si compra {$0 · $2.000 · $10.000} 8. `dep` versamento mensile {EUR 0 · 250 · 500} (il piano in corso e' 500) 9. `invest` la cassa lavora sul libro invece di restare ferma {si' · no} Il punto (9) e' un difetto misurabile della macchineria pubblicata: in `pl.simulate` / `pc.simulate` / `gate_c.ladder` **la cassa dei payout resta FERMA per 36 mesi**. LE MIE ATTESE, REGISTRATE PRIMA DI MISURARE -------------------------------------------- A1. L'argmax di P(>=50/g) sara' a leva **piu' alta** dell'argmax di J, e la differenza sara' grande (fattore >2 su P). *Motivo: P(>=50/g) e' una probabilita' di superare una soglia alta = coda destra; J e' una probabilita' di sopravvivenza = coda sinistra.* A2. Sotto la definizione **A** (ricchezza) il canale funded **non** portera' P(36 mesi) sopra zero in modo apprezzabile: il muro e' ~$313k e 36 mesi da $635 sono ~3 ordini di grandezza. Quindi la risposta alla domanda «esiste una politica sopra il 20% a 36 mesi?» sara' **SI' sotto B e NO sotto A**, e questa e' la vera risposta del filone. A3. Investire la cassa invece di lasciarla ferma valdra' poco su B (il flusso non dipende dalla cassa) e molto su A. *Se sbaglio e vale poco anche su A, lo dico.* A4. L'ottimo di P sara' accompagnato da P(rovina) molto alta (>50%) — cioe' sara' un ottimo che il progetto NON dovrebbe adottare, e va riportato come informazione, non come consiglio. A5. Il vincolo binding a 36 mesi non sara' ne' la leva ne' il numero di conti ma il **cap $200k/trader** oppure il **capitale che entra**. Mi aspetto il secondo. CONVENZIONI ----------- * Lente **ACCOPPIATA** ovunque ci sia una barriera a un giorno (regola 25/07, riconfermata §33). * Cella d'ancora **MEDIANA** (non la canonica, che sta al 91° pctl — §32), scelta con lo stesso criterio di `gate_c` su un sottoinsieme d'ancore dichiarato PRIMA. * Funding **DENTRO** (§35), de-luck **x0,89** sul drift (§ r0726_deluck_factor), fisco 33% + patrimoniale 0,2% sul libro proprio (§ r0807), morte-firm 10%/anno, cap $200k/trader. * Baseline del libro: **`hourly`** (la lente di ogni muro e traiettoria) — dichiarata perche' il critico di §57 ha misurato che sotto «75/25» convivono tre baseline diverse. * Muro: **CONGELATO** a k=1 come primaria (si de-leva al traguardo: la leva non deve poter spostare il bersaglio); **MOBILE** come sensibilita' (§53 dichiara che la differenza vale 1,2 anni). Banda del muro propagata dai valori di §57. * Monte Carlo: la risoluzione si dichiara. 1500 percorsi -> SE ~1,0pp su una P vicina al 20%. Uso: nice -n 19 timeout 900 uv run python scripts/research/r0823b_obiettivo_diretto.py ... --fast (griglia ridotta, ~1/3 del tempo) Rete: NESSUNA (solo cache su disco: parquet certificati, cache Binance di §21, cache funding di §35). Nessuna scrittura fuori da stdout. """ from __future__ import annotations import subprocess 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_capcurve as CC # noqa: E402 TAX_RATE, EURUSD, book_series import r0725_prop_coupled as pc # noqa: E402 lente accoppiata import r0725_prop_ladder as pl # noqa: E402 regole firm, scala di conti import r0727_tasse as TX # noqa: E402 PATRIMONIALE, CARRY_ANNI import r0807_piano_netto as PN # noqa: E402 passo_fiscale, accumula, muro import r0822_prop_alloc as PA # noqa: E402 boot_idx, DELUCK import r0822b_prop_recal as PR # noqa: E402 obj_rg, LEVS, pannelli Binance import r0822b_xs01_oos as X # noqa: E402 U13, motore XS01 import r0822c_skh_anchor_prop as AP # noqa: E402 rg_off (offset di SKH01) import r0822d_funding as FD # noqa: E402 il funding import r0822d_gate_c as GC # noqa: E402 ladder, fvec_for, xs_funding from src.portfolio.sleeves import XS_UNIVERSE # noqa: E402 FD.USE_NET = False FAST = "--fast" in sys.argv EURUSD = pl.EURUSD TAX = CC.TAX_RATE PATR = TX.PATRIMONIALE DELUCK = PA.DELUCK # x0,89 misurato W_LIVE = {"TP01": 0.75, "SKH01": 0.25} W_A = {"TP01": 0.38, "SKH01": 0.38, "XS01": 0.25} START_USD = 635.0 # il conto Deribit VERO di oggi SEED_LAD = pl.HORIZON_MONTHS * 0 + 20260822 # lo stesso di gate_c (per la bit-exactness) SEED_BOOT = 58023 N_PATHS = 900 if FAST else 1500 N_PATHS_J = PA.N_PATHS MIN_PAYOUT = GC.MIN_PAYOUT_TRADER ORIZZONTI_M = (24, 36, 60, 120) H_MAX_D = max(ORIZZONTI_M) * 30 MARKS = tuple(m * 30 for m in ORIZZONTI_M) OFFSETS_SUB = tuple(range(0, 690, 90)) if not FAST else (0, 180, 360, 540) # 8 (o 4) a priori PHASES_SUB = AP.PHASES_SUB # (0, 3, 7) — dichiarato da §32 LEVS_FU = (0.50, 0.75, 1.00, 1.25) NMAX = (1, 3, 6) PREFS = ("grande", "piccolo") REBUY = (True, False) # numeri PUBBLICATI da riprodurre PRIMA di produrne di nuovi PUB = dict(muro_L3=313_143.0, perp_L3=0.0635, drift_L3=0.1519, p50g_fund=0.026, p50g_p10=0.015, p50g_p90=0.047, pzero_fund=0.403, p50g_nofund=0.044, muro_p90=186_623.0, muro_m1se=709_753.0) # banda di §57 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}", flush=True) # =========================================================================== # IL SIMULATORE UNIFICATO # =========================================================================== def uni(Ra: np.ndarray, Ga: np.ndarray, Rb: np.ndarray, boot: np.ndarray, *, lev_fu: float = 1.0, n_max: int = 6, pref: str = "grande", rebuy: bool = True, floor_usd: float = 0.0, k_book: float = 1.0, invest: bool = False, dep_eur: float = 0.0, start_usd: float = pl.START_EUR * EURUSD, seed: int = SEED_LAD, refund: bool = False, min_payout: float = 0.0, tax: float = 0.0, patr: float = 0.0, walls: tuple = (), marks: tuple = (), deposit_mode: str = "ladder", deluck_f: float = DELUCK) -> dict: """UN simulatore per le DUE strade, sugli STESSI percorsi. E' una GENERALIZZAZIONE STRETTA di `gate_c.ladder` (che a sua volta e' `pc.simulate` con tre aggiunte): con `n_max=6, pref='grande', rebuy=True, floor=0, k_book=0, invest=False, tax=0, patr=0, deposit_mode='ladder'` deve essere **BIT-EXACT** rispetto a `gate_c.ladder`. E con `n_max=0, invest=True, tax=0.33, patr=0.002, deposit_mode='accumula'` deve essere **BIT-EXACT** rispetto a `PN.accumula`. I due controlli sono in §1. Cio' che aggiunge, e che nessuna macchina pubblicata ha: * un **pot proprio** che compone al libro (`k_book x Rb`) invece di restare fermo, col fisco d'accumulo dentro (stessa `PN.passo_fiscale` del piano); * i **payout che rientrano nel pot** e quindi compongono; * `floor_usd` — un capitale proprio sotto cui non si compra un altro biglietto; * `rebuy` — la scelta di NON ricomprare dopo un bust; * `pref` — biglietto piu' grande o piu' piccolo (piu' tentativi); * il **primo passaggio** al capitale-rendita, per l'obiettivo A. `Ra/Ga` = libro del conto FUNDED (ritorno e gap intraday accoppiato), `Rb` = libro PROPRIO. Il de-luck si applica al DRIFT di R (non al gap): stessa convenzione di `ladder`. """ rng = np.random.default_rng(seed) n_paths, n_days = boot.shape Ram = np.asarray(Ra, float).copy() Ram = Ram - (1.0 - deluck_f) * Ram.mean() Gam = np.asarray(Ga, float) Rbm = np.asarray(Rb, float).copy() Rbm = Rbm - (1.0 - deluck_f) * Rbm.mean() n_slot = int(n_max) FIRMS = pl.FIRMS cash = np.full(n_paths, float(start_usd)) basis = cash.copy() # base fiscale del pot carry = np.zeros((n_paths, TX.CARRY_ANNI)) anno_start = cash.copy() flusso = np.zeros(n_paths) cum_payout = np.zeros(n_paths) spent = np.zeros(n_paths) got_back = np.zeros(n_paths) deposited = np.zeros(n_paths) n_payouts = np.zeros(n_paths, int) n_tickets = np.zeros(n_paths, int) n_pass = np.zeros(n_paths, int) peak_notional = np.zeros(n_paths) if n_slot: Rs_full = Ram[boot] * lev_fu # (paths, days) — tutti i conti uguali Gs_full = Gam[boot] * lev_fu phase = np.full((n_paths, n_slot), -1, np.int8) eq = np.ones((n_paths, n_slot)) firm = np.full((n_paths, n_slot), -1, np.int8) notional = np.zeros((n_paths, n_slot)) price_paid = np.zeros((n_paths, n_slot)) refunded = np.zeros((n_paths, n_slot), bool) used = np.zeros((n_paths, n_slot), bool) firm_alive = np.ones((n_paths, len(FIRMS)), bool) p_death_day = 1.0 - (1.0 - pl.FIRM_DEATH_PER_YEAR) ** (1 / 365.0) Rbp = Rbm[boot] if (invest and k_book > 0) else None hit = {w: np.full(n_paths, -1, int) for w in walls} snap: dict[int, dict] = {} fiscale = (tax > 0 or patr > 0) for t in range(n_days): # ---- morte di una firm (identico a ladder: il draw avviene SEMPRE, anche a 0 slot, # solo se il canale funded esiste) if n_slot: died = rng.random((n_paths, len(FIRMS))) < p_death_day newly_dead = died & firm_alive firm_alive &= ~died if newly_dead.any(): for fi in range(len(FIRMS)): kill = newly_dead[:, fi] if kill.any(): h = (firm == fi) & kill[:, None] phase[h] = -1 notional[h] = 0.0 # ---- acquisto biglietti for k in range(n_slot): free = phase[:, k] == -1 if not rebuy: free &= ~used[:, k] if not free.any(): continue for fi, F in enumerate(FIRMS): u = np.where(firm == fi, notional, 0.0).sum(axis=1) order = sorted(F["tickets"], key=(lambda x: -x[0]) if pref == "grande" else (lambda x: x[0])) for (size, price) in order: buy = (free & firm_alive[:, fi] & (cash >= price) & (cash - price >= floor_usd) & (u + size <= F["cap"])) if not buy.any(): continue cash[buy] -= price flusso[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 used[buy, k] = True free = free & ~buy if not free.any(): break if not free.any(): break # ---- dinamica dei conti r = Rs_full[:, t][:, None] g = Gs_full[:, t][:, 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)))) phase[bust] = -1 notional[bust] = 0.0 passed = in_ev & (eq >= 1.0 + ev_t) & ~bust phase[passed] = 1 eq[passed] = 1.0 n_pass += passed.sum(axis=1) peak_notional = np.maximum(peak_notional, np.where(phase == 1, notional, 0.0).sum(axis=1)) # ---- il POT proprio compone if Rbp is not None: cash = cash * (1.0 + k_book * Rbp[:, t]) # ---- versamento (convenzione `accumula`: giorno 30, 60, ...) if deposit_mode == "accumula" and dep_eur and t % 30 == 0 and t > 0: cash += dep_eur * EURUSD flusso += dep_eur * EURUSD deposited += dep_eur * EURUSD # ---- payout mensile + rimborso + versamento (convenzione `ladder`) if (t + 1) % 30 == 0: if n_slot: fu = phase == 1 pay = fu & (eq > 1.0) & (((eq - 1.0) * notional * pl.SPLIT) >= min_payout) gain = np.where(pay, (eq - 1.0) * notional, 0.0) net = gain.sum(axis=1) * pl.SPLIT * (1.0 - TAX) cum_payout += net cash += net flusso += 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 flusso += amt got_back += amt refunded |= back if deposit_mode == "ladder" and dep_eur: cash += dep_eur * EURUSD flusso += dep_eur * EURUSD deposited += dep_eur * EURUSD # ---- primo passaggio al muro (obiettivo A) for w, arr in hit.items(): nuovi = (arr < 0) & (cash >= w) arr[nuovi] = t # ---- fisco d'accumulo sul pot if fiscale and (t + 1) % 365 == 0: PN.passo_fiscale(cash, anno_start, flusso, carry, tax, patr) anno_start = cash.copy() flusso[:] = 0.0 basis = cash.copy() if (t + 1) in marks: d = t + 1 ed = cum_payout / EURUSD / (d / 365.0) / 365.0 contrib = float(start_usd) + deposited snap[d] = dict(p_flow=float((ed >= pl.TARGET_EUR_DAY).mean()), p_flow10=float((ed >= 10.0).mean()), med_eur=float(np.median(ed)), med_cash=float(np.median(cash)), mean_cash=float(cash.mean()), p10_cash=float(np.percentile(cash, 10)), p_zero=float((cum_payout <= 0).mean()), p_sotto=float((cash < contrib).mean()), p_rovina=float((cash < 0.10 * contrib).mean()), contrib=float(contrib.mean() if np.ndim(contrib) else contrib), **{f"A{w:.0f}": float(((hit[w] >= 0) & (hit[w] < d)).mean()) for w in walls}) ed = cum_payout / EURUSD / (n_days / 365.0) / 365.0 out = dict(eur_day=ed, cash=cash, snap=snap, hit=hit, p_target=float((ed >= pl.TARGET_EUR_DAY).mean()), p_ge10=float((ed >= 10.0).mean()), p_zero=float((cum_payout <= 0).mean()), med=float(np.median(ed)), med_cash=float(np.median(cash)), mean_cash=float(cash.mean()), p10_cash=float(np.percentile(cash, 10)), p90_cash=float(np.percentile(cash, 90)), med_spent=float(np.median(spent)), mean_back=float(got_back.mean()), n_tickets=float(n_tickets.mean()), n_pass=float(n_pass.mean()), peak_notional=float(np.median(peak_notional)), contributed=float(start_usd + deposited.mean())) bump(1) return out def p_wall_entro(res: dict, wall: float, giorni: int) -> float: """P(il patrimonio PROPRIO tocca `wall` entro `giorni`) — obiettivo A.""" h = res["hit"][wall] return float(((h >= 0) & (h < giorni)).mean()) def anni_med(res: dict, wall: float) -> tuple[float, float]: """(mediana INCONDIZIONATA degli anni al traguardo, P(arrivo entro la simulazione)). Non-arrivo = +inf, MAI -1 (lezione 07/08).""" h = res["hit"][wall] y = np.where(h >= 0, h / 365.0, np.inf) return float(np.median(y)), float(np.isfinite(y).mean()) # =========================================================================== def main() -> None: try: sys.stdout.reconfigure(line_buffering=True) except Exception: # pragma: no cover pass print("=" * 104) print(" §58 OBIETTIVO-DIRETTO — ottimizzare `P(reddito >= 50 EUR/g entro H)`, e non altro") print("=" * 104) print(f" {'MODALITA RIDOTTA (--fast)' if FAST else 'griglia piena'} | " f"{N_PATHS} percorsi | orizzonti {ORIZZONTI_M} mesi") # ------------------------------------------------------------ §0 isolamento hr("§0. ISOLAMENTO — questo script NON tocca la produzione (il cron gira dal working tree)") prot = ["src", "config", "scripts/live", "tests", "data/paper_portfolio", "data/live"] dirty = subprocess.run(["git", "status", "--porcelain", "--"] + prot, cwd=ROOT, capture_output=True, text=True).stdout.strip() print(f" git status sui percorsi protetti {prot}:") print(f" {'PULITO — nessuna modifica' if not dirty else 'SPORCO: ' + dirty}") if dirty: raise SystemExit("La produzione risulta modificata: mi fermo.") print(" Nessuna scrittura su disco in tutto lo script (solo stdout). Rete: nessuna.") # ------------------------------------------------------------ §1 repliche hr("§1. REPLICHE — prima di un numero nuovo, la macchina deve riprodurre i vecchi") ok: dict[str, bool] = {} # (R1) il muro L3 (fisco + funding), $313.143 — §36, replicato al dollaro da §57 print("\n R1 IL MURO della lente congiunta L3 (funding dentro, fisco dentro, de-luck x0,89)") rateF = GC.funding_rate() if rateF is None: raise SystemExit("cache funding assente: senza di essa nessun numero di questo filone " "sarebbe confrontabile coi pubblicati.") bookA = FD.book_75_25(None) bookF = FD.book_75_25(rateF).reindex(bookA.index) idxF = pd.DatetimeIndex(bookA.index) rL3 = np.asarray(bookF.values, float) rL3 = rL3 - (1.0 - DELUCK) * rL3.mean() prel = CC.TARGET_EUR_DAY * 365 * CC.EURUSD t = time.time() perp, MURO = PN.muro(rL3, prel, TAX, PATR) ok["R1"] = abs(MURO - PUB["muro_L3"]) < 1.0 print(f" serie {len(rL3)} giorni {idxF.min().date()} -> {idxF.max().date()} | " f"drift {rL3.mean()*365:.4%} (pubbl. {PUB['drift_L3']:.2%})") print(f" perpetua {perp:.4%} (pubbl. {PUB['perp_L3']:.2%}) muro ${MURO:,.0f} " f"(pubbl. ${PUB['muro_L3']:,.0f}) -> " f"{'ESATTO AL DOLLARO' if ok['R1'] else 'DIVERSO'} ({time.time()-t:.0f}s)") bump(1) tick("R1") # ------------------------------------------------- il pannello comune print("\n Il pannello comune (identico a §29/§32/§37): U13 Binance, W-LONG 2021+.") Cb, Ob, Hb, Lb = PR.ohlc_panels(PR.bin_loader, XS_UNIVERSE) p13 = Cb[X.U13].dropna() XSP = {ph: PR.xs_tuples(p13, Ob.reindex(p13.index)[X.U13], Hb.reindex(p13.index)[X.U13], Lb.reindex(p13.index)[X.U13], phase=ph) for ph in PHASES_SUB} xs0 = XSP[PHASES_SUB[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"))] pc.DELUCK = DELUCK ev_b = PA.boot_idx(len(I), 365, N_PATHS_J, seed=8220) fu_b = PA.boot_idx(len(I), 365, N_PATHS_J, seed=8221) xsf = GC.xs_funding_measure(verbose=False) xs_ann = xsf["ann"] print(f" {len(I)} giorni {I[0].date()} -> {I[-1].date()} | " f"XS01 paga {xs_ann*100:+.2f}%/anno di funding (misurato §37)") tick("pannello") # (R2) la cella d'ancora MEDIANA e il numero operativo 2,6% [1,5%, 4,7%] print(f"\n R2 IL NUMERO OPERATIVO DI §37 — {len(OFFSETS_SUB)} offset x {len(PHASES_SUB)} " f"fasi = {len(OFFSETS_SUB)*len(PHASES_SUB)} celle, funding DENTRO, leva argmax-J") print(" (sottoinsieme d'ancore dichiarato PRIMA; §37 ne usa 23x3, qui se ne usano " f"{len(OFFSETS_SUB)}x{len(PHASES_SUB)} per il tempo macchina)") cells = [] for off in OFFSETS_SUB: fA = GC.fvec_for(W_A, I, rateF, off, xs_ann) for ph in PHASES_SUB: R0, G0 = AP.rg_off(W_A, I, XSP[ph], off) Rx = R0 - fA jb, lb = -1.0, None for lv in PR.LEVS: j = PR.obj_rg(Rx, G0, lv, ev_b, fu_b)["J"] if j > jb: jb, lb = j, lv bump(len(PR.LEVS)) lad = GC.ladder(Rx, G0, N_PATHS, lb, SEED_LAD, refund=False) cells.append(dict(off=off, ph=ph, J=jb, lev=lb, p50=lad["p_target"], pz=lad["p_zero"], med=lad["med"])) bump(1) C = pd.DataFrame(cells) med_p, p10, p90 = C["p50"].median(), np.percentile(C["p50"], 10), np.percentile(C["p50"], 90) ok["R2"] = PUB["p50g_p10"] <= med_p <= PUB["p50g_p90"] print(f" P(>=50/g) mediana {med_p:.1%} banda [{p10:.1%}, {p90:.1%}] " f"P(zero) {C['pz'].median():.1%}") print(f" pubblicato §37: {PUB['p50g_fund']:.1%} [{PUB['p50g_p10']:.1%}, " f"{PUB['p50g_p90']:.1%}], P(zero) {PUB['pzero_fund']:.1%} -> " f"{'DENTRO LA BANDA' if ok['R2'] else 'FUORI'}") k_med = int((C["p50"] - C["p50"].median()).abs().idxmin()) OFF_M, PH_M, LEV_J = int(C.loc[k_med, "off"]), int(C.loc[k_med, "ph"]), float(C.loc[k_med, "lev"]) print(f" CELLA D'ANCORA MEDIANA: offset {OFF_M} min, fase {PH_M}, leva argmax-J " f"{LEV_J:.2f}x (non la canonica: 91° pctl, §32)") fM = GC.fvec_for(W_A, I, rateF, OFF_M, xs_ann) R_M0, G_M = AP.rg_off(W_A, I, XSP[PH_M], OFF_M) R_M = R_M0 - fM tick("R2") # il libro PROPRIO sullo stesso pannello rb_full = FD.book_75_25(rateF) if rb_full.index.tz is None: rb_full.index = rb_full.index.tz_localize("UTC") RB_LIVE = np.nan_to_num(rb_full.reindex(I).values.astype(float)) fA_own = GC.fvec_for(W_A, I, rateF, OFF_M, xs_ann) RB_WA = AP.rg_off(W_A, I, XSP[PH_M], OFF_M)[0] - fA_own print(f"\n libro PROPRIO sul pannello comune:") for lab, r in (("LIVE 75/25", RB_LIVE), ("W_A 38/38/25", RB_WA)): print(f" {lab:<14} drift {r.mean()*365:>7.2%} vol {r.std()*365**.5:>6.2%} " f"Sharpe {r.mean()*365/(r.std()*365**.5):>5.2f}") # bootstrap CONDIVISO (confronto appaiato fra tutte le politiche) rngb = np.random.default_rng(SEED_BOOT) nb = int(np.ceil(H_MAX_D / 20)) st = rngb.integers(0, len(I) - 20, size=(N_PATHS, nb)) BOOT = (st[:, :, None] + np.arange(20)[None, None, :]).reshape(N_PATHS, -1)[:, :H_MAX_D] B36 = BOOT[:, :36 * 30] print(f" bootstrap CONDIVISO: {N_PATHS} percorsi x {H_MAX_D} giorni, blocchi 20 -> " f"OGNI confronto di questo filone e' APPAIATO") # (R3) bit-exactness: `uni` in modalita' ladder == `gate_c.ladder` print("\n R3 BIT-EXACTNESS — `uni` in modalita' ladder deve essere `gate_c.ladder`") ref = GC.ladder(R_M, G_M, N_PATHS, LEV_J, SEED_LAD, refund=False, boot=B36) mine = uni(R_M, G_M, RB_LIVE, B36, lev_fu=LEV_J, n_max=pl.MAX_CONCURRENT, pref="grande", rebuy=True, floor_usd=0.0, k_book=0.0, invest=False, dep_eur=0.0, start_usd=pl.START_EUR * EURUSD, seed=SEED_LAD, refund=False, min_payout=0.0, tax=0.0, patr=0.0, deposit_mode="ladder") d1 = float(np.abs(ref["eur_day"] - mine["eur_day"]).max()) d2 = float(np.abs(ref["cash"] - mine["cash"]).max()) ok["R3"] = (d1 == 0.0 and d2 == 0.0) print(f" max|dif| EUR/g = {d1:.3e} | max|dif| cassa = {d2:.3e} -> " f"{'BIT-EXACT' if ok['R3'] else 'DIVERSO'}") # (R4) bit-exactness: `uni` senza conti == `PN.accumula` print("\n R4 BIT-EXACTNESS — `uni` senza canale funded deve essere `PN.accumula`") paths_own = (RB_LIVE - (1.0 - DELUCK) * RB_LIVE.mean())[B36] a = PN.accumula(paths_own, 500.0, MURO, TAX, PATR, start=START_USD) m = uni(R_M, G_M, RB_LIVE, B36, n_max=0, k_book=1.0, invest=True, dep_eur=500.0, start_usd=START_USD, tax=TAX, patr=PATR, walls=(MURO,), deposit_mode="accumula") d3 = float(np.abs(a["cap"] - m["cash"]).max()) d4 = int(np.abs(np.where(a["colpito"] >= 0, a["colpito"], -1) - m["hit"][MURO]).max()) ok["R4"] = (d3 < 1e-6 and d4 == 0) print(f" max|dif| capitale = ${d3:.3e} | max|dif| giorno di primo passaggio = {d4} -> " f"{'BIT-EXACT' if ok['R4'] else 'DIVERSO'}") print(f" (capitale mediano a 36 mesi ${np.median(m['cash']):,.0f}, " f"P(muro) {float((m['hit'][MURO]>=0).mean()):.1%})") print(f"\n ESITO REPLICHE: {sum(ok.values())}/{len(ok)} — " + ", ".join(f"{k}={'OK' if v else 'NO'}" for k, v in ok.items())) if not all(ok.values()): raise SystemExit("REPLICA INCOMPLETA: un numero nuovo sarebbe indistinguibile da un bug.") tick("§1") # ---- fine repliche; da qui i numeri NUOVI # muro coerente col PANNELLO su cui gira la simulazione (2021+), come sensibilita' rI = RB_LIVE - (1.0 - DELUCK) * RB_LIVE.mean() lo, hi = 0.0, 0.40 for _ in range(13): mid = (lo + hi) / 2 sv = PN.sopravvivenza(rI, 1e6, 1e6 * mid, 20, TAX, PATR, n_paths=1500) lo, hi = (mid, hi) if sv["p10_end"] >= 1e6 else (lo, mid) MURO_I = prel / lo if lo > 0.002 else float("inf") WALLS = (PUB["muro_p90"], MURO, PUB["muro_m1se"]) print(f"\n IL BERSAGLIO (obiettivo A) — e la sua banda, propagata da §57:") print(f" muro PRIMARIO (pubblicato, finestra piena 2019+): ${MURO:,.0f} " f"(perpetua {perp:.2%})") print(f" banda del drift +-1SE (§57): p90 ${PUB['muro_p90']:,.0f} ... " f"-1SE ${PUB['muro_m1se']:,.0f}") print(f" muro COERENTE col pannello 2021+ (drift {rI.mean()*365:.2%}): " + (f"${MURO_I:,.0f}" if np.isfinite(MURO_I) else "IRRAGGIUNGIBILE (perpetua ~0)")) print(" ⚠️ La simulazione gira sul pannello 2021+ (l'unico dove XS01 esiste) mentre il muro") print(" pubblicato e' calcolato sulla finestra piena: la disparita' e' DICHIARATA e la") print(" riga qui sopra la quantifica. Primaria resta la pubblicata, per confrontabilita'.") tick("muro") def run(**kw) -> dict: base = dict(lev_fu=1.0, n_max=0, pref="grande", rebuy=True, floor_usd=0.0, k_book=1.0, invest=True, dep_eur=500.0, start_usd=START_USD, seed=SEED_LAD, refund=True, min_payout=MIN_PAYOUT, tax=TAX, patr=PATR, walls=WALLS, marks=MARKS, deposit_mode="ladder") base.update(kw) boot = base.pop("boot", BOOT) return uni(base.pop("Ra", R_M), base.pop("Ga", G_M), base.pop("Rb", RB_LIVE), boot, **base) # ====================================================================== hr("§2. LE DUE DEFINIZIONI DI «REDDITO >= 50 EUR/g», SULLA STESSA POLITICA E SUGLI STESSI PATH") print(" A = RICCHEZZA: il patrimonio PROPRIO tocca il capitale-rendita (sostenibile).") print(" B = FLUSSO : media dei payout incassati >= 50 EUR/g (la definizione dei numeri") print(" pubblicati del canale funded — NON sostenibile).") print(f" Versamento: EUR 500/mese (il piano in `config/live.json`), start ${START_USD:,.0f}.") REF = { "LIBRO (oggi: 75/25, k=1, nessun biglietto)": dict(n_max=0), "PROP come pubblicato (6 conti, leva argmax-J, cassa FERMA)": dict(n_max=6, lev_fu=LEV_J, invest=False, k_book=0.0, tax=0.0, patr=0.0), "PROP + cassa che lavora sul libro (stessa leva)": dict(n_max=6, lev_fu=LEV_J, invest=True, k_book=1.0), } refres = {k: run(**v) for k, v in REF.items()} print(f"\n {'politica':<52} {'H':>5} {'A: P(muro)':>11} {'B: P(>=50/g)':>13} " f"{'mediana $':>11} {'P(12}") for lab, r in refres.items(): for m in ORIZZONTI_M: sn = r["snap"][m * 30] print(f" {lab if m == ORIZZONTI_M[0] else '':<52} {m:>4}m " f"{sn[f'A{MURO:.0f}']:>11.1%} {sn['p_flow']:>13.1%} " f"${sn['med_cash']:>10,.0f} {sn['p_sotto']:>12.1%}") print("\n 📌 Le due definizioni NON ordinano le politiche allo stesso modo, e a 36 mesi non") print(" sono nemmeno commensurabili: sotto A il canale funded e' un ACCELERATORE di") print(" capitale, sotto B e' l'unico modo di avere un flusso.") tick("§2") # ====================================================================== hr("§3. LA CURVA DI LEVA — dove sta l'argmax di CIASCUN obiettivo (attesa A1)") print(f" Cella d'ancora mediana (offset {OFF_M}, fase {PH_M}), 6 conti, cassa che lavora,") print(" EUR 500/mese. J e' calcolato con la STESSA `PR.obj_rg` di §29/§32/§37.") print(f"\n {'leva':>6} {'J':>7} {'B: P(>=50/g) 36m':>17} {'A: P(muro) 120m':>16} " f"{'P(zero)':>8} {'P(12} {'mediana $ 120m':>15}") LEVS_ALL = PR.LEVS curve = [] for lv in LEVS_ALL: j = PR.obj_rg(R_M, G_M, lv, ev_b, fu_b)["J"] bump(1) r = run(n_max=6, lev_fu=lv) s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] curve.append(dict(lev=lv, J=j, B36=s36["p_flow"], A120=s120[f"A{MURO:.0f}"], pz=s36["p_zero"], psotto=s120["p_sotto"], med=s120["med_cash"])) print(f" {lv:>6.3f} {j:>7.3f} {s36['p_flow']:>17.1%} {s120[f'A{MURO:.0f}']:>16.1%} " f"{s36['p_zero']:>8.1%} {s120['p_sotto']:>12.1%} ${s120['med_cash']:>14,.0f}") CU = pd.DataFrame(curve) aJ = float(CU.loc[CU["J"].idxmax(), "lev"]) aB = float(CU.loc[CU["B36"].idxmax(), "lev"]) aA = float(CU.loc[CU["A120"].idxmax(), "lev"]) print(f"\n argmax J = {aJ:.2f}x · argmax B(36m) = {aB:.2f}x · " f"argmax A(120m) = {aA:.2f}x") print(f" B alla leva argmax-J: {float(CU.loc[CU['J'].idxmax(),'B36']):.1%} -> " f"B al proprio argmax: {CU['B36'].max():.1%} " f"(fattore {CU['B36'].max()/max(float(CU.loc[CU['J'].idxmax(),'B36']),1e-9):.1f}x)") print(f" ATTESA A1 ({'CONFERMATA' if aB > aJ and CU['B36'].max() > 2*float(CU.loc[CU['J'].idxmax(),'B36']) else 'PARZIALE/SMENTITA'}): " "l'argmax di P sta a leva piu' alta di quello di J.") tick("§3") # ====================================================================== hr("§4. LO SPAZIO DI POLITICA, OTTIMIZZATO SU P DIRETTAMENTE (36 mesi, obiettivo B)") grid = [dict(lev_fu=lv, n_max=nm, pref=pf, rebuy=rb) for lv in LEVS_FU for nm in NMAX for pf in PREFS for rb in REBUY] print(f" {len(grid)} celle dichiarate PRIMA: leva {LEVS_FU} x conti {NMAX} x " f"taglia {PREFS} x rebuy {REBUY}") print(f" fisse: libro proprio LIVE 75/25 k=1, cassa che lavora, floor $0, EUR 500/mese.") rows = [] for g in grid: r = run(**g) s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] rows.append(dict(**g, B36=s36["p_flow"], B24=r["snap"][24 * 30]["p_flow"], B60=r["snap"][60 * 30]["p_flow"], B120=s120["p_flow"], A36=s36[f"A{MURO:.0f}"], A120=s120[f"A{MURO:.0f}"], A120lo=s120[f"A{PUB['muro_p90']:.0f}"], A120hi=s120[f"A{PUB['muro_m1se']:.0f}"], pz=s36["p_zero"], psotto36=s36["p_sotto"], rov36=s36["p_rovina"], med120=s120["med_cash"], ntick=r["n_tickets"])) G = pd.DataFrame(rows) print(f"\n LE 8 MIGLIORI SU B(36 mesi) — e cosa costano sugli altri assi:") print(f" {'leva':>5} {'conti':>6} {'taglia':>8} {'rebuy':>6} {'B 24m':>7} {'B 36m':>7} " f"{'B 60m':>7} {'A 120m':>7} {'P(zero)':>8} {'P(13} {'bigl.':>6}") for _, r in G.sort_values("B36", ascending=False).head(8).iterrows(): print(f" {r['lev_fu']:>5.2f} {int(r['n_max']):>6} {r['pref']:>8} " f"{'si' if r['rebuy'] else 'no':>6} {r['B24']:>7.1%} {r['B36']:>7.1%} " f"{r['B60']:>7.1%} {r['A120']:>7.1%} {r['pz']:>8.1%} {r['psotto36']:>13.1%} " f"{r['ntick']:>6.1f}") print(f"\n LE 6 MIGLIORI SU A(120 mesi, muro pubblicato ${MURO:,.0f}):") print(f" {'leva':>5} {'conti':>6} {'taglia':>8} {'rebuy':>6} {'A 36m':>7} {'A 120m':>7} " f"{'A120 p90':>9} {'A120 -1SE':>10} {'B 36m':>7} {'mediana $ 120m':>15}") for _, r in G.sort_values("A120", ascending=False).head(6).iterrows(): print(f" {r['lev_fu']:>5.2f} {int(r['n_max']):>6} {r['pref']:>8} " f"{'si' if r['rebuy'] else 'no':>6} {r['A36']:>7.1%} {r['A120']:>7.1%} " f"{r['A120lo']:>9.1%} {r['A120hi']:>10.1%} {r['B36']:>7.1%} " f"${r['med120']:>14,.0f}") bestB = G.loc[G["B36"].idxmax()] bestA = G.loc[G["A120"].idxmax()] print(f"\n ARGMAX B(36m) = leva {bestB['lev_fu']:.2f}x, {int(bestB['n_max'])} conti, " f"biglietto {bestB['pref']}, rebuy {'si' if bestB['rebuy'] else 'no'} -> " f"{bestB['B36']:.1%}") print(f" ARGMAX A(120m) = leva {bestA['lev_fu']:.2f}x, {int(bestA['n_max'])} conti, " f"biglietto {bestA['pref']}, rebuy {'si' if bestA['rebuy'] else 'no'} -> " f"{bestA['A120']:.1%}") print(f" I due argmax {'COINCIDONO' if (bestB[['lev_fu','n_max','pref','rebuy']].tolist() == bestA[['lev_fu','n_max','pref','rebuy']].tolist()) else 'SONO DIVERSI'}.") tick("§4") # ====================================================================== hr("§5. LE DIMENSIONI RESTANTI — floor, versamento, leva del libro, ripartizione propria") bp = dict(lev_fu=float(bestB["lev_fu"]), n_max=int(bestB["n_max"]), pref=str(bestB["pref"]), rebuy=bool(bestB["rebuy"])) print(f" Politica di riferimento: l'argmax di B {bp}") print(f"\n (a) FLOOR — capitale proprio sotto cui non si compra un altro biglietto") print(f" {'floor':>10} {'B 36m':>8} {'A 120m':>8} {'P(zero)':>9} {'mediana $ 120m':>15}") for fl in (0.0, 2_000.0, 10_000.0): r = run(floor_usd=fl, **bp) s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] print(f" ${fl:>9,.0f} {s36['p_flow']:>8.1%} {s120[f'A{MURO:.0f}']:>8.1%} " f"{s36['p_zero']:>9.1%} ${s120['med_cash']:>14,.0f}") print(f"\n (b) VERSAMENTO MENSILE — la leva che il progetto misura come dominante") print(f" {'EUR/mese':>10} {'strada':>10} {'B 36m':>8} {'A 120m':>8} {'A 240m':>8} " f"{'mediana $ 120m':>15}") for dep in (0.0, 250.0, 500.0, 1_000.0): for lab, kw in (("PROP", bp), ("LIBRO", dict(n_max=0))): r = run(dep_eur=dep, **kw) s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] a240 = anni_med(r, MURO) print(f" {dep:>10,.0f} {lab:>10} {s36['p_flow']:>8.1%} " f"{s120[f'A{MURO:.0f}']:>8.1%} {a240[1]:>8.1%} ${s120['med_cash']:>14,.0f}") print(" (la colonna 'A 240m' e' P(traguardo) sull'intera simulazione = 120 mesi: coincide") print(" con A 120m — la si stampa per rendere esplicito che l'orizzonte massimo e' 10 anni)") print(f"\n (c) LEVA DEL LIBRO PROPRIO — muro CONGELATO (primaria) e MOBILE (sensibilita')") print(" ⚠️ §38: la chiave di scala NON ESISTE in `config/live.json`; §57: a k=1,50x il") print(" peggior giorno e' 21,48% e la guardia dello scettico (<=20%) lo BOCCIA.") print(f" {'k':>5} {'muro mobile':>13} {'A 120m congel.':>15} {'A 120m mobile':>14} " f"{'B 36m':>7} {'mediana $ 120m':>15}") for k in (1.00, 1.25, 1.50): rk = rI * k lo, hi = 0.0, 0.40 for _ in range(11): mid = (lo + hi) / 2 sv = PN.sopravvivenza(np.asarray(rL3, float) * k, 1e6, 1e6 * mid, 20, TAX, PATR, n_paths=1200) lo, hi = (mid, hi) if sv["p10_end"] >= 1e6 else (lo, mid) mk = prel / lo if lo > 0.002 else float("inf") r = run(k_book=k, walls=(MURO, mk) if np.isfinite(mk) else (MURO,), **bp) s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] am = s120.get(f"A{mk:.0f}", float("nan")) if np.isfinite(mk) else float("nan") print(f" {k:>5.2f} " + (f"${mk:>12,.0f}" if np.isfinite(mk) else f"{'IRRAGG.':>13}") + f" {s120[f'A{MURO:.0f}']:>15.1%} " + (f"{am:>14.1%}" if am == am else f"{'—':>14}") + f" {s36['p_flow']:>7.1%} ${s120['med_cash']:>14,.0f}") bump(1) print(f"\n (d) RIPARTIZIONE DEL LIBRO PROPRIO — LIVE 75/25 contro W_A 38/38/25") print(" (la seconda mette XS01 anche sul capitale proprio: §46 ha falsificato la soglia") print(" dei $20k da min-order, ma la decisione di venue del 26/07 tiene tutto su") print(" Deribit fino a $20k -> e' una sensibilita', non una proposta)") print(f" {'libro proprio':>16} {'B 36m':>8} {'A 120m':>8} {'mediana $ 120m':>15}") for lab, rbk in (("LIVE 75/25", RB_LIVE), ("W_A 38/38/25", RB_WA)): r = run(Rb=rbk, **bp) s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] print(f" {lab:>16} {s36['p_flow']:>8.1%} {s120[f'A{MURO:.0f}']:>8.1%} " f"${s120['med_cash']:>14,.0f}") print(f"\n (e) LA CASSA CHE LAVORA — attesa A3") print(f" {'cassa':>16} {'B 36m':>8} {'A 120m':>8} {'mediana $ 36m':>14} " f"{'mediana $ 120m':>15}") inv = {} for lab, kw in (("ferma (pubbl.)", dict(invest=False, k_book=0.0, tax=0.0, patr=0.0)), ("investita", dict(invest=True, k_book=1.0))): r = run(**{**bp, **kw}) inv[lab] = r s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] print(f" {lab:>16} {s36['p_flow']:>8.1%} {s120[f'A{MURO:.0f}']:>8.1%} " f"${s36['med_cash']:>13,.0f} ${s120['med_cash']:>14,.0f}") dB = (inv["investita"]["snap"][36 * 30]["p_flow"] - inv["ferma (pubbl.)"]["snap"][36 * 30]["p_flow"]) dA = (inv["investita"]["snap"][120 * 30][f"A{MURO:.0f}"] - inv["ferma (pubbl.)"]["snap"][120 * 30][f"A{MURO:.0f}"]) print(f" ATTESA A3: dB {dB*100:+.2f}pp, dA {dA*100:+.2f}pp -> " f"{'CONFERMATA' if abs(dB) < 0.02 and dA > 0.02 else 'da leggere nel testo'}") tick("§5") # ====================================================================== hr("§6. QUANTO COSTA LA DIFFERENZA FRA L'OTTIMO E CIO' CHE IL PROGETTO FA OGGI") oggi = run(n_max=0) pubb = run(n_max=6, lev_fu=LEV_J, invest=False, k_book=0.0, tax=0.0, patr=0.0) optB = run(**bp) optA = run(lev_fu=float(bestA["lev_fu"]), n_max=int(bestA["n_max"]), pref=str(bestA["pref"]), rebuy=bool(bestA["rebuy"])) print(f" {'politica':<44} {'B 36m':>8} {'A 36m':>8} {'A 120m':>8} {'anni al muro':>13} " f"{'P(16}") for lab, r in (("OGGI: libro 75/25 k=1, nessun biglietto", oggi), ("PUBBLICATA: 6 conti a leva argmax-J", pubb), ("ARGMAX B (flusso)", optB), ("ARGMAX A (ricchezza)", optA)): s36, s120 = r["snap"][36 * 30], r["snap"][120 * 30] med, parr = anni_med(r, MURO) print(f" {lab:<44} {s36['p_flow']:>8.1%} {s36[f'A{MURO:.0f}']:>8.1%} " f"{s120[f'A{MURO:.0f}']:>8.1%} " + (f"{med:>12.1f}a" if np.isfinite(med) else f"{'>10a':>13}") + f" {s36['p_sotto']:>16.1%}") dB36 = optB["snap"][36 * 30]["p_flow"] - oggi["snap"][36 * 30]["p_flow"] dA120 = optA["snap"][120 * 30][f"A{MURO:.0f}"] - oggi["snap"][120 * 30][f"A{MURO:.0f}"] print(f"\n COSTO DI NON OTTIMIZZARE: su B(36m) {dB36*100:+.1f}pp, " f"su A(120m) {dA120*100:+.1f}pp.") tick("§6") # ====================================================================== hr("§7. LA DOMANDA DECISIVA — esiste una politica con P(>=50 EUR/g entro 36 mesi) > 20%?") maxB = float(G["B36"].max()) maxA36 = float(G["A36"].max()) rowB = G.loc[G["B36"].idxmax()] print(f" Sotto la definizione B (FLUSSO, quella dei numeri pubblicati):") print(f" massimo su {len(G)} politiche = {maxB:.1%} " f"(leva {rowB['lev_fu']:.2f}x, {int(rowB['n_max'])} conti, biglietto {rowB['pref']}, " f"rebuy {'si' if rowB['rebuy'] else 'no'})") print(f" ma con P(zero payout) {rowB['pz']:.1%} e P(finire sotto il versato) " f"{rowB['psotto36']:.1%}") print(f" -> {'SI, SOPRA IL 20%' if maxB > 0.20 else 'NO, SOTTO IL 20%'}") print(f"\n Sotto la definizione A (RICCHEZZA sostenibile, il muro del progetto):") print(f" massimo su {len(G)} politiche a 36 mesi = {maxA36:.2%} " f"(a 120 mesi: {float(G['A120'].max()):.1%})") print(f" -> {'SI' if maxA36 > 0.20 else 'NO'}, e non per poco: il muro e' " f"${MURO:,.0f} e a 36 mesi il capitale mediano migliore e' " f"${float(G['med120'].max()):,.0f} a 120 mesi.") print(f"\n ATTESA A2 ({'CONFERMATA' if (maxB > 0.20 and maxA36 < 0.05) else 'SMENTITA'}): " "«SI' sotto B e NO sotto A».") print(f" ATTESA A4 ({'CONFERMATA' if rowB['pz'] > 0.50 or rowB['psotto36'] > 0.50 else 'SMENTITA'}): " "l'ottimo di P e' una politica ad alta rovina.") # il vincolo che fissa il massimo print(f"\n QUALE VINCOLO FISSA IL MASSIMO — si toglie un vincolo per volta (obiettivo B, 36m):") print(f" {'scenario':<46} {'B 36m':>8} {'delta':>8}") base_b = float(rowB["B36"]) scen = [] r = run(start_usd=10_000.0, **bp); scen.append(("capitale iniziale $10.000 invece di $635", r)) r = run(dep_eur=2_000.0, **bp); scen.append(("versamento EUR 2.000/mese invece di 500", r)) cap_old = [F["cap"] for F in pl.FIRMS] for F in pl.FIRMS: F["cap"] *= 5 r = run(**bp); scen.append(("cap per firm x5 ($1M / $2M)", r)) for F, c in zip(pl.FIRMS, cap_old): F["cap"] = c dead_old = pl.FIRM_DEATH_PER_YEAR pl.FIRM_DEATH_PER_YEAR = 0.0 r = run(**bp); scen.append(("morte-firm 0%/anno invece di 10%", r)) pl.FIRM_DEATH_PER_YEAR = dead_old r = run(n_max=6, **{k: v for k, v in bp.items() if k != "n_max"}) scen.append(("6 conti concorrenti (se non lo e' gia')", r)) for lab, r in scen: b = r["snap"][36 * 30]["p_flow"] print(f" {lab:<46} {b:>8.1%} {(b-base_b)*100:>+7.1f}pp") print(f" ATTESA A5: il vincolo binding e' il capitale che entra " f"(riga 'versamento' e riga 'capitale iniziale').") # ====================================================================== hr("VERDETTO") eur_g_oggi = oggi["snap"][36 * 30]["med_cash"] print(f" Trial contati al rialzo: {TRIALS}. Tempo {time.time()-T0:.0f}s. " f"Percorsi {N_PATHS} (SE ~{100*np.sqrt(0.2*0.8/N_PATHS):.1f}pp su una P vicina al 20%).") print(f"\n * L'obiettivo del progetto ha DUE definizioni operative in uso e danno risposte") print(f" opposte alla stessa domanda. Con la definizione del canale funded (FLUSSO) il") print(f" massimo a 36 mesi e' {maxB:.1%}; con quella dei muri e del piano (RICCHEZZA") print(f" SOSTENIBILE) e' {maxA36:.2%}.") print(f" * L'ottimo di P(>=50/g) NON e' l'ottimo di J: {CU['B36'].max():.1%} contro " f"{float(CU.loc[CU['J'].idxmax(),'B36']):.1%} alla leva argmax-J.") print(f" * In EUR/giorno, la mediana di cio' che il libro di oggi produce a 36 mesi resta") print(f" ZERO (non preleva), e il capitale mediano e' ${eur_g_oggi:,.0f}: la rendita") print(f" perpetua su quel capitale vale {perp*eur_g_oggi/365/EURUSD:.2f} EUR/giorno.") print("=" * 104) if __name__ == "__main__": main()