From df08460af040c47b78fbf5471f42e59db7d40e13 Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Sat, 22 Aug 2026 23:36:38 +0000 Subject: [PATCH] =?UTF-8?q?research(wave-0822):=20GATE-C=20=E2=80=94=20gat?= =?UTF-8?q?e=20riformulato=20senza=20date,=20PASS=202/2;=20XS01=20PAGA=20f?= =?UTF-8?q?unding;=20il=20biglietto=20batte=20il=20versare=20solo=20perche?= =?UTF-8?q?'=20il=20piano=20esiste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/research/RESULTS-0822.md | 73 ++ scripts/research/r0822d_gate_c.py | 1103 +++++++++++++++++++++++++++++ 2 files changed, 1176 insertions(+) create mode 100644 scripts/research/r0822d_gate_c.py diff --git a/docs/research/RESULTS-0822.md b/docs/research/RESULTS-0822.md index 00ebac5..d992434 100644 --- a/docs/research/RESULTS-0822.md +++ b/docs/research/RESULTS-0822.md @@ -702,6 +702,7 @@ stessi hanno nominato senza poterli eseguire**. Stesso contratto di consegna, st | 34 | CC01-2022 | il carry riaperto sui dati che gli mancavano per costruzione | **RESTA SCARTATO** — per la ragione giusta, ma non quella pubblicata | | 35 | FUNDING | il costo mai prezzato di TENERE una posizione aperta | **LEAD** — **−2,16%/anno di drift**, muri **+17,5%** | | 36 | PIANO-VERO | la tabella congiunta fisco+funding, che non esisteva | 🚨 **€250/m: P(20a) 92% → 14-26%** | +| 37 | GATE-C | l'ultima gamba del gate funded + il biglietto come opzione | **PASS 2/2** — gate senza date; **P(≥50/g) 4,4% → 2,6%** | | 22 | MAKER | l'esecuzione passiva e' una fonte di ritorno, al netto del costo di non essere eseguiti? | **SCARTATO** — il segno dipende da `<` contro `<=` | | 23 | BOCPD | un rilevatore di cambio di regime vero batte il miglior lookback COSTANTE? | **SCARTATO** — filone chiuso definitivamente | | 24 | CRITICO | cosa NON e' stato misurato, e quale singola misura mancante vale di piu' | **3 correzioni all'ondata**, 1 regola mia ritirata | @@ -1780,3 +1781,75 @@ PER €50/GIORNO IN 10 ANNI SERVONO: €1.733/mese (P=90%), totale versato $229. 📌 **A 10 anni si versano $229k per arrivare a ~$313k: il rendimento fa il 27%, i bonifici il 73%.** E' la forma piu' netta finora della lezione gia' scritta: **a orizzonte corto non fai lavorare la strategia, COMPRI il capitale coi bonifici.** + +--- + +## 37 — GATE-C (l'ultima gamba del gate funded, e il biglietto riprezzato) + +`scripts/research/r0822d_gate_c.py` (356 s, nessuna rete). **1.347 celle**, **zero di selezione** +(pesi, meccanismo, lente, de-luck e soglie tutti **ereditati e congelati**) → niente DSR da calcolare. +Ridotto e dichiarato: 23 offset × **3 fasi** (lo stesso sottocampione a priori di §32). + +✅ **Riproduzioni prima di ogni numero nuovo:** §32 (4,4% [2,5-8,2%], P(zero) 35,3%) **esatta**; §35 +(−2,16/−2,10/−2,32%) **esatta**; ladder contro `pc.simulate` **bit-exact, `max|diff| = 0,0` percorso +per percorso**. ⚠️ `r0725_hyro` da' **−11%** rispetto al pubblicato ($6.018 contro $6.789) **perche' il +file ri-deriva le serie dal feed corrente, +4 settimane** — stessa lezione del vintage. + +**Il biglietto a due stadi** (cella d'ancora **mediana**, non la canonica che sta al 91° pctl; funding +dentro; lente accoppiata; 6.000 percorsi): P(pass) **35,5-52,5%**, **P(payout | pass) 72,3-89,2%**, +E[payout] 1 anno funded $1.016-2.194. +**EV del biglietto $100k in tre convenzioni:** spesa persa **$+1.615** · rimborso al pass **$+1.919** · +**rimborso al primo payout (la regola vera) $+1.835**. **Positivo in tutte e tre.** +📌 **Ma la correzione economica che aveva motivato il filone vale +13,6% di EV e +0,60pp su P(≥50/g): +reale, misurata, e NON cambia nessuna decisione.** + +🚨 **Il funding costa anche qui, appaiato cella per cella (69 celle): dJ −0,0491 (69/69 negative), +dP(≥50/g) −1,60pp (66/69)** → **P(≥50 €/g) 2,6% [1,5%, 4,7%], P(zero) 40,3%**. +**Catena completa del ridimensionamento in una giornata: 42% → 7,8% → 4,4% → 2,6%.** + +🚨 **XS01 PAGA il funding, non lo incassa — e il meccanismo e' DIMOSTRATO, non congetturato:** +`max|ΣW| = 2,8e-17` (dollar-neutral **esatto**) ⇒ **il livello del funding non entra, entra solo la +dispersione cross-sezionale**; e il momentum cross-sezionale **compra i perp col funding piu' caro e +vende quelli col piu' basso** → **+1,45%/anno** (IC95 [+1,18, +1,72]; banda onesta [+0,69, +1,45] se +HL e' ~2,1× il venue eseguibile). *L'ipotesi opposta era nel mio briefing.* + +📌 **Il progetto conteneva GIA' due modelli contraddittori della quota:** `r0725_hyro:200` la rimborsa +**al PASS** (ottimista), `pc.simulate` non la rimborsa **mai** (pessimista) — e il numero operativo +usciva dal secondo. Le due convenzioni *sbagliate* distano **$84** = prezzo × (P(pass) − P(payout)). +📌 **Piu' leva sul funded ALZA E[payout] e ABBASSA P(payout):** chi vuole il rimborso non vuole la leva +massima. **Sono due obiettivi diversi.** +⚠️ **Un numero netto catturato PRIMA di pubblicarlo:** il "capitale d'incrocio €1.000-2.000" **NON e' +un meccanismo**. La ricchezza terminale della strada-biglietto e' **bimodale**, e +`P(cassa finale < $249)` si muove **liscia** (56,3 → 50,8 → 28,3 → 16,9 → 3,9 → 0,0%) mentre la +mediana **salta di un ordine di grandezza** appena quella massa passa il 50%. **La mediana non e' una +statistica robusta qui** — ed e' esattamente il tipo di numero netto che si sarebbe finito per citare +come soglia di progetto. + +**IL CONFRONTO CHE DECIDE** (36 mesi, $654 iniziali, **stesso bootstrap appaiato**, funding in +entrambe le strade, fisco 33%): +| versamento | strada | mediana | media | P( 0 con la quota trattata come SPESA PERSA**, alla cella +d'ancora **mediana**, col funding dentro, sotto lente accoppiata. *Oggi: **$+1.615 → PASS***. +**(c2) DI SOPRAVVIVENZA** — prezzo del biglietto **≤ 2 versamenti mensili del piano in corso**, +perche' il piano d'accumulo e' la leva dominante misurata e **zero e' assorbente**. *Oggi (piano +€500/mese): **$579 contro $1.090 → PASS***. +📌 **La FORMA del gate e' imposta dal costo della misura:** l'EV costa una corsa di script (zero +dollari), **la rimborsabilita' costa $579 e si puo' misurare solo comprando** → un gate d'attesa su +quella sarebbe **superabile solo dopo averlo violato**. Percio' (c1) e' scritta perche' **la +rimborsabilita' NON decida**, e il rimborso diventa **un regalo invece di un'ipotesi su cui si e' +scommesso**. + +**`IL BIGLIETTO CONTRO IL VERSARE: MEGLIO — ma solo perche' il piano di versamento c'e', e la ragione +non e' il rendimento, e' il NUMERO DI VOLTE CHE SI PUO' GIOCARE.`** Senza versamenti la stessa +scommessa **perde la mediana 6×** ($132 contro $787) e **vince la media 12×**: e' una lotteria a valore +atteso positivo che un conto da $654 puo' permettersi di giocare **una volta sola**. +⚠️ E il vantaggio poggia **interamente** sul drift di XS01 misurato su **13 gambe su 19**. +**Smentitore che azzera tutto senza che il modello lo segnali:** una **morte-firm ≫10%/anno**. diff --git a/scripts/research/r0822d_gate_c.py b/scripts/research/r0822d_gate_c.py new file mode 100644 index 0000000..080d1b8 --- /dev/null +++ b/scripts/research/r0822d_gate_c.py @@ -0,0 +1,1103 @@ +"""r0822d_gate_c — GATE PROP-01, gamba (c): il BIGLIETTO riprezzato come OPZIONE (2026-08-22). + +IL BUCO CHE CHIUDE +------------------ +`GATE PROP-01` (RESULTS-0822 §29) ha tre gambe. Due sono state chiuse stanotte: + (a) LISTINO -> PASS 13/13, misurato sul venue (Bybit `instruments-info`, 833 strumenti); + (b) ANCORA SKH01 -> PASS, delta appaiato +0,116 sui 23 offset, 230/230 celle congiunte + positive — ma il numero OPERATIVO e' sceso a P(>=50 EUR/g) = 4,4% [2,5-8,2%], P(zero) 35,3%. +La gamba (c) e' rimasta una CONSTATAZIONE, non un criterio: + + "un'eval HYRO $100k costa $579 su un conto di $635 = il 91%" + +e per giunta poggia su un'economia sbagliata. La pagina della firm dichiara la quota come +**"Refundable Challenge Deposit, returned in full alongside your first funded payout"**: +non e' una fee affondata, e' un **deposito rimborsabile al PRIMO PAYOUT**. Immobilizza il 91% +del conto; non lo brucia. Va riprezzato come **struttura a opzione a DUE STADI** +(passare l'eval **E POI** produrre abbastanza profitto da chiedere un prelievo), non come spesa. + +⚠ E qui c'e' un fatto che nessuno ha notato: **il progetto contiene GIA' DUE modelli che si +contraddicono fra loro.** + * `r0725_hyro.py:200` -> `cost = price * (1.0 - pe)` = quota **rimborsata al PASS**; + * `r0725_prop_ladder.simulate` / `r0725_prop_coupled.simulate` -> `cash[buy] -= price` + e la quota **non torna MAI** = spesa affondata. +Il primo e' OTTIMISTA (rimborsa a un evento che accade prima e piu' spesso di quello vero), +il secondo e' PESSIMISTA (non rimborsa affatto). **Il vero sta in mezzo, e il numero operativo +del progetto — P(>=50 EUR/g) — viene dal secondo.** + +LA PREVISIONE, REGISTRATA PRIMA DI MISURARE +------------------------------------------- +1. Il rimborso al primo payout vale **poco** sull'EV del biglietto e **piu'** sulla scala di + conti (dove la cassa che torna ricompra un biglietto e composta). Mi aspetto: EV +5-15%, + P(>=50/g) +1-3 punti percentuali. +2. `P(primo payout | pass)` mi aspetto **alta** (>80%): la soglia di prelievo e' $100 di quota + trader = 0,125% di nozionale su $100k, cioe' un'inezia rispetto al 10% appena prodotto + nell'eval. Quindi la differenza fra le due convenzioni di rimborso e' **piccola**. +3. Il **funding** su un conto funded fa male in proporzione alla leva: a 0,75x mi aspetto + ~-1,6%/anno di equity del conto (cioe' 0,75 x 2,16%), e su un conto a barriera un costo di + drift si paga sulla P(pass) piu' che sul maxDD. +4. **XS01: mi aspetto che INCASSI funding**, perche' e' market-neutral e i perp con funding piu' + caro sono tipicamente quelli in forte trend, che il momentum cross-sezionale compra... ma + comprarli vuol dire PAGARE il loro funding. Le due forze tirano in verso opposto: **non lo so, + e per questo si misura.** Se il segno esce negativo (costo) lo dico. +5. **La domanda che decide**: con P(>=50 EUR/g) 4,4% e P(zero) 35,3%, il biglietto ha EV + positivo? E batte l'alternativa ovvia (tenere i $635 sul libro e versare)? Mi aspetto: + **EV positivo sulla MEDIA e negativo sulla MEDIANA** — cioe' una lotteria con valore atteso + positivo, che e' esattamente la forma che un conto da $635 non puo' permettersi molte volte. + +CONVENZIONI DICHIARATE +---------------------- +* Lente **ACCOPPIATA** ovunque (`r0725_prop_coupled`): su una regola a UN GIORNO la close-only + e' esattamente CIECA. La close-only compare solo come controllo. +* Configurazione del conto funded: **W_A = TP01 38 / SKH01 38 / XS01 25** (centro della regione + robusta di PROP-RECAL), XS01 = **U13 Binance** (la versione piu' debole e l'unica testabile + fuori campione), finestra **W-LONG 2021+**, de-luck sul drift **x0,89**. +* Il conto PROPRIO gira invece il **libro LIVE 75/25 a $654 con min-order $5** (XS01 non e' + eseguibile a quel capitale): l'asimmetria e' REALE ed e' il punto del canale funded. +* Banda d'ancora: **23 offset x 3 fasi (0,3,7)**, lo stesso sottocampione dichiarato da + `r0822c_skh_anchor_prop`. La stima onesta e' la **MEDIANA**, non l'ancora canonica. +* **Firm death 10%/anno** e **cap $200k/trader**: assunzioni gia' in uso nel progetto (24/07), + dichiarate e non nascoste. +* Soglia di prelievo **$100 di quota trader** (fonte primaria-dichiarativa della firm, non + misurata) -> profitto lordo >= $125 su $100k. +* Monte Carlo: la risoluzione si dichiara. 1500 percorsi sulla scala di conti (+-1pp su + P(>=50/g)), 6000 sul biglietto a conto singolo, 2500 su J. + +Uso: `nice -n 19 timeout 900 uv run python scripts/research/r0822d_gate_c.py` +Rete: NESSUNA (tutto da disco: parquet certificati, cache Binance di r0822b, cache funding +di r0822d_funding). Se la cache del funding manca, la sezione 1 lo dichiara e si ferma li'. +""" +from __future__ import annotations + +import contextlib +import io +import re +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 r0724_goal50_intraday_mc as mc # noqa: E402 recon orario per-sleeve (24/07) +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 r0822_prop_alloc as PA # noqa: E402 J, bootstrap, simulatore (22/08) +import r0822b_prop_recal as PR # noqa: E402 PROP-RECAL (22/08) +import r0822b_xs01_oos as X # noqa: E402 motore XS01 + cache Binance (22/08) +import r0822c_skh_anchor_prop as AP # noqa: E402 gamba (b), offset di SKH01 (22/08) +import r0822d_funding as FD # noqa: E402 il funding (22/08) +from src.portfolio.sleeves import XS_UNIVERSE # noqa: E402 + +FD.USE_NET = False + +RAW = ROOT / "data" / "raw" +HYRO = "HYRO" +ASSETS = ("BTC", "ETH") +EURUSD = pl.EURUSD +TAX_RATE = pl.TAX_RATE +SPLIT = pl.SPLIT +DELUCK = PA.DELUCK # x0,89, fattore d'ancora MISURATO (26/07) +LEVS = PR.LEVS +OFFSETS = AP.OFFSETS # 23 offset a priori di SKH01 +PHASES_SUB = AP.PHASES_SUB # (0, 3, 7) — dichiarato da r0822c +W_A = {"TP01": 0.38, "SKH01": 0.38, "XS01": 0.25} +W_LIVE = {"TP01": 0.75, "SKH01": 0.25} +N_PATHS_J = PA.N_PATHS # 2500 +N_PATHS_LAD = 1500 +N_PATHS_TIX = 6000 +EV_H = FU_H = 365 +SEED_EV, SEED_FU = 8220, 8221 +SEED_LAD = 20260822 +MIN_PAYOUT_TRADER = 100.0 # quota trader minima per un prelievo (firm) +HORIZON_DAYS = pl.HORIZON_MONTHS * 30 # 1080 = 36 mesi + +# numeri PUBBLICATI da riprodurre prima di produrne di nuovi +PUB = dict( + hyro_ev_close=6789.0, hyro_ev_intra=1166.0, # r0725_hyro (25/07) + recal_j=0.453, recal_live=0.281, recal_d=0.175, recal_p50g=0.078, # §29 + anchor_p50g=0.044, anchor_p10=0.025, anchor_p90=0.082, + anchor_pzero=0.353, # §32 + fund_book=-2.16, fund_tp=-2.10, fund_skh=-2.32, # §35 (%/anno) +) + +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(f" {t}") + print("-" * 104) + + +def tick(lab: str) -> None: + print(f" [{time.time()-T0:6.0f}s] {lab}") + + +# ============================================================================ 1. IL FUNDING + +def funding_rate() -> dict | None: + """Serie oraria del funding per asset (LINEARE dove esiste, INVERSE prima come proxy + dichiarato). Legge SOLO la cache di `r0822d_funding` — nessuna rete.""" + try: + F = {} + for instr, (start, _a, _k) in FD.INSTR.items(): + d = FD.fetch_funding(instr, start).copy() + d["dt"] = pd.to_datetime(d["ts"], unit="ms", utc=True) + F[instr] = d.drop_duplicates(subset="ts").sort_values("dt").set_index("dt") + return FD.build_rate(F) + except Exception as exc: # pragma: no cover + print(f" !! cache funding assente/illeggibile ({exc}) — il funding NON viene messo dentro") + return None + + +_FTP: dict[int, pd.Series] = {} + + +def f_tp01_sleeve(rate: dict) -> pd.Series: + """Costo di funding GIORNALIERO dello sleeve TP01 a peso 1.0, sulla STESSA lente delle gambe + orarie del recon (`mc.tp01_daily_frame` = TP01 canonico, senza min-order: su un conto funded + da $100k il min-order $5 non esiste, e questa e' la lente giusta li'). + + Convenzione temporale identica a `FD.tp01_canonical`: la posizione tenuta nel giorno d e' + decisa a close[d-1], e paga il funding sulle 24 ore (d, d+24h].""" + if 0 in _FTP: + return _FTP[0] + out = None + for a in ASSETS: + tpf = mc.tp01_daily_frame(a) + days = pd.DatetimeIndex(tpf.index) + s = pd.Series(tpf["w"].values * FD.daily_funding(rate[a], days), index=days) + out = s if out is None else out.add(s, fill_value=0.0) + _FTP[0] = out + return out + + +_FSKH: dict[int, pd.Series] = {} + + +def f_skh_sleeve(rate: dict, off: int = 0) -> pd.Series: + """Costo di funding giornaliero dello sleeve SKH01 (50/50) all'offset `off`, come + DIFFERENZA fra il path live senza e con funding (`FD.skh_book`). E' esatto al primo ordine + (l'equity compone: il secondo ordine e' ~1e-6/giorno) e riproduce il -2,32%/anno di §35.""" + if off in _FSKH: + return _FSKH[off] + a0 = FD.skh_book(off, "hourly", None) + a1 = FD.skh_book(off, "hourly", rate) + if a0.index.tz is None: + a0.index = a0.index.tz_localize("UTC") + if a1.index.tz is None: + a1.index = a1.index.tz_localize("UTC") + s = (a0 - a1).dropna() + _FSKH[off] = s + return s + + +def xs_funding_measure(verbose: bool = True) -> dict: + """IL SEGNO DEL FUNDING SU XS01, MISURATO (non assunto). + + XS01 e' long 5 / short 5 a pesi uguali -> `sum(W) = 0` ESATTAMENTE. Quindi + `sum(W_i f_i) = sum(W_i (f_i - fbar))`: **il LIVELLO del funding non entra, entra solo la + sua DISPERSIONE CROSS-SEZIONALE**. Cio' significa due cose: + * non e' vero ne' che 'incassa' ne' che 'paga' per costruzione: dipende da come il + funding e' distribuito FRA gli asset che il momentum compra e vende; + * il fatto noto che il funding Hyperliquid sia ~2,1x quello del venue vero (§35) si + trasferisce alla dispersione, quindi si riporta una BANDA, non un punto. + Dato: `data/raw/hlfund__1h.parquet` (19 major, 2023-05 -> 2026-06).""" + P = X.hl_panel() + det: dict = {} + X.xsec_engine(P, phase=0, detail=det) + W, scale, idx = det["W"], det["scale"], det["index"] + cols = list(P.columns) + gross_sum = float(np.abs(W.sum(axis=1)).max()) + fun = {} + for s in cols: + f = RAW / f"hlfund_{s.lower()}_1h.parquet" + if not f.exists(): + continue + d = pd.read_parquet(f)["funding"] + d.index = pd.DatetimeIndex(d.index).tz_convert("UTC") + fun[s] = d.groupby(d.index.floor("D")).sum() + have = [s for s in cols if s in fun] + Fm = pd.DataFrame({s: fun[s] for s in have}).reindex(idx) + cover = Fm.notna().mean(axis=1) + Fv = Fm.fillna(0.0).values + sel = [cols.index(s) for s in have] + Wp = np.vstack([np.zeros((1, len(cols))), W[:-1]]) # posizioni TENUTE nel giorno i + cost = pd.Series((Wp[:, sel] * Fv).sum(axis=1) * scale, index=idx) + gross = pd.Series(np.abs(Wp[:, sel]).sum(axis=1) * scale, index=idx) + ok = cover >= 0.95 + c = cost[ok] + if verbose: + print(f" pannello HL {P.shape[1]} gambe, {len(idx)} giorni; file di funding per " + f"{len(have)}/{len(cols)} gambe") + print(f" CONTROLLO di dollar-neutralita': max|sum(W)| = {gross_sum:.2e} " + f"-> {'ESATTO' if gross_sum < 1e-12 else 'NON neutrale'}") + print(f" giorni con copertura >=95% delle gambe: {int(ok.sum())} " + f"({c.index.min().date()} -> {c.index.max().date()})") + print(f"\n {'anno':>6} {'costo funding %/anno':>22} {'gross nozionale':>17} {'giorni':>7}") + for y, g in c.groupby(c.index.year): + gg = gross.reindex(g.index) + print(f" {y:>6} {float(g.mean()*365)*100:>21.3f}% {float(gg.mean()):>16.3f}x " + f"{len(g):>7}") + ann = float(c.mean() * 365) + se = float(c.std(ddof=1) / np.sqrt(len(c)) * 365) + print(f" {'TUTTO':>6} {ann*100:>21.3f}% {float(gross.reindex(c.index).mean()):>16.3f}x " + f"{len(c):>7} IC95 [{(ann-1.96*se)*100:+.3f}%, {(ann+1.96*se)*100:+.3f}%]") + ann = float(c.mean() * 365) + return dict(ann=ann, series=c, gross=float(gross.reindex(c.index).mean()), + se=float(c.std(ddof=1) / np.sqrt(len(c)) * 365), n=len(c)) + + +# ================================================================ 2. LIBRO CON FUNDING + +def fvec_for(w: dict, idx: pd.DatetimeIndex, rate: dict | None, off: int, + xs_ann: float) -> np.ndarray | None: + """Vettore giornaliero del costo di funding del LIBRO ai pesi `w`. + TP01 e SKH01: serie misurate giorno per giorno. XS01: **tasso annuo costante** misurato su + Hyperliquid 2024-2026 e applicato all'intera finestra — dichiarato, perche' `hlfund` parte + nel 2023-05 e il pannello di XS01 usato qui e' Binance 2021+ (nessun funding su disco).""" + if rate is None: + return None + f = np.zeros(len(idx)) + wtp, wsk, wxs = w.get("TP01", 0.0), w.get("SKH01", 0.0), w.get("XS01", 0.0) + if wtp: + f += wtp * np.nan_to_num(f_tp01_sleeve(rate).reindex(idx).values) + if wsk: + f += wsk * np.nan_to_num(f_skh_sleeve(rate, off).reindex(idx).values) + if wxs: + f += wxs * (xs_ann / 365.0) + return f + + +def best_lev(R, G, ev, fu) -> tuple[float, float, np.ndarray]: + jb, lb, vb = -1.0, None, None + for lv in LEVS: + o = PR.obj_rg(R, G, lv, ev, fu, factor=DELUCK) + if o["J"] > jb: + jb, lb, vb = o["J"], lv, o["jvec"] + bump(len(LEVS)) + return jb, lb, vb + + +# ============================================ 3. SCALA DI CONTI COL DEPOSITO RIMBORSABILE + +def ladder(R: np.ndarray, G: np.ndarray, n_paths: int, lev: float, seed: int, + refund: bool, deposit_eur: float = 0.0, start_eur: float = pl.START_EUR, + min_payout: float = 0.0, boot: np.ndarray | None = None, + block: int = 20, deluck: float = DELUCK) -> dict: + """Copia di `r0725_prop_coupled.simulate` (un solo vettore di peso, `MAX_CONCURRENT` slot) + con TRE aggiunte e nessun'altra differenza: + 1. `refund` — la quota torna in cassa **al PRIMO PAYOUT** di quel conto (regola vera + della firm). Se il conto busta prima di un payout, la quota e' persa. + 2. `deposit_eur` — versamento mensile, per confrontare la strada-biglietto con la + strada-versare a parita' di soldi che entrano. + 3. `min_payout` — quota trader minima per poter prelevare ($100 secondo la firm). + Con `refund=False, deposit_eur=0, min_payout=0, boot=None` deve essere **BIT-EXACT** + rispetto a `pc.simulate`: e' il controllo di §3.1. + + Il funding, se c'e', e' gia' dentro `R` -> essendo `Rs = R*lev`, il costo di funding + **scala con la leva**, che e' la sua vera economia (e' proporzionale all'esposizione).""" + rng = np.random.default_rng(seed) + n_days = HORIZON_DAYS + L = len(R) + Rm = R.astype(float).reshape(-1, 1).copy() + Gm = G.astype(float).reshape(-1, 1).copy() + Rm = Rm - (1.0 - deluck) * Rm.mean(axis=0, keepdims=True) + if boot is None: + n_blocks = int(np.ceil(n_days / block)) + starts = rng.integers(0, L - block, size=(n_paths, n_blocks)) + idx = (starts[:, :, None] + np.arange(block)[None, None, :]).reshape(n_paths, -1)[:, :n_days] + else: + idx = boot + n_slot = pl.MAX_CONCURRENT + sel = np.zeros(n_slot, dtype=int) + Rs = Rm[idx][:, :, sel] * lev + G_ = Gm[idx][:, :, sel] * lev + + FIRMS = pl.FIRMS + cash = np.full(n_paths, start_eur * EURUSD) + 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) + firm_alive = np.ones((n_paths, len(FIRMS)), bool) + 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) + p_death_day = 1.0 - (1.0 - pl.FIRM_DEATH_PER_YEAR) ** (1 / 365.0) + + for t in range(n_days): + 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(): + hit = (firm == fi) & kill[:, None] + phase[hit] = -1 + notional[hit] = 0.0 + + 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 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 + 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 + free = free & ~buy + if not free.any(): + break + if not free.any(): + break + + r = Rs[:, t, :] + g = G_[:, t, :] + 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 + + 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_RATE) + 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 + if deposit_eur: + cash += deposit_eur * EURUSD + deposited += deposit_eur * EURUSD + + eur_day = cum_payout / EURUSD / (n_days / 365.0) / 365.0 + return dict(eur_day=eur_day, med=float(np.median(eur_day)), + p10=float(np.percentile(eur_day, 10)), p90=float(np.percentile(eur_day, 90)), + p_ge10=float((eur_day >= 10.0).mean()), + p_target=float((eur_day >= pl.TARGET_EUR_DAY).mean()), + p_zero=float((cum_payout <= 0).mean()), + p_payout=float((n_payouts > 0).mean()), + cash=cash, 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()), + contributed=float(start_eur * EURUSD + deposited.mean())) + + +def book_road(rb: np.ndarray, boot: np.ndarray, start_eur: float, deposit_eur: float, + deluck: float = DELUCK, tax: float = TAX_RATE) -> dict: + """La strada ALTERNATIVA: gli stessi soldi restano sul LIBRO LIVE (proprio capitale, nessuna + barriera, nessuna firm) e si versa. Stessi sorteggi di bootstrap della strada-biglietto + (confronto APPAIATO), stesso de-luck, stesso orizzonte. + Fisco: 33% sulla variazione ANNUA di valore, con riporto delle minusvalenze (convenzione di + `r0807_piano_netto`; il libro realizza quasi tutto entro l'anno -> limite superiore stretto).""" + R = rb.astype(float).copy() + R = R - (1.0 - deluck) * R.mean() + r = R[boot] + n_paths, n_days = r.shape + cap = np.full(n_paths, start_eur * EURUSD) + basis = cap.copy() + carry = np.zeros(n_paths) + deposited = 0.0 + for t in range(n_days): + cap = np.maximum(cap * (1.0 + r[:, t]), 0.0) + if (t + 1) % 30 == 0 and deposit_eur: + cap += deposit_eur * EURUSD + basis += deposit_eur * EURUSD + deposited += deposit_eur * EURUSD + if (t + 1) % 365 == 0: + g = (cap - basis) + carry + due = np.where(g > 0, tax * g, 0.0) + carry = np.where(g > 0, 0.0, g) + cap = cap - due + basis = cap.copy() + return dict(cash=cap, med_cash=float(np.median(cap)), mean_cash=float(cap.mean()), + p10_cash=float(np.percentile(cap, 10)), p90_cash=float(np.percentile(cap, 90)), + contributed=float(start_eur * EURUSD + deposited)) + + +# ==================================================== 4. IL BIGLIETTO A CONTO SINGOLO, 2 STADI + +def ticket_mc(R: np.ndarray, G: np.ndarray, lev_ev: float, lev_fu: float, notional: float, + n_paths: int = N_PATHS_TIX, seed: int = 82241, max_eval_days: int = 540, + funded_days: int = 365, min_payout: float = MIN_PAYOUT_TRADER, + consistency: bool = True, firm_death: bool = True, block: int = 20, + deluck: float = DELUCK, firm: str = HYRO) -> dict: + """UN conto HYRO, i due stadi **CHAINED sullo stesso percorso** (eval -> funded), che e' la + differenza rispetto a `PA.eval_sim`/`PA.funded_sim`, che girano su bootstrap INDIPENDENTI e + moltiplicano le probabilita'. + + Ritorna cio' che serve a prezzare il deposito come opzione: + p_pass = P(passare l'eval entro `max_eval_days`) + p_payout = P(arrivare ad ALMENO un payout) <- l'evento che rimborsa la quota + p_pay_given = P(payout | pass) + e_payout = E[payout netti], incondizionato, sui `funded_days` successivi al pass + """ + tgt, dd, dl = pl.FIRMS[[f["name"] for f in pl.FIRMS].index(firm)]["ev"] + ml, dlf = pl.FIRMS[[f["name"] for f in pl.FIRMS].index(firm)]["fu"] + rng = np.random.default_rng(seed) + Rd = R.astype(float) - (1.0 - deluck) * float(np.mean(R)) + total = max_eval_days + funded_days + L = len(Rd) + nb = int(np.ceil(total / block)) + st = rng.integers(0, L - block, size=(n_paths, nb)) + bi = (st[:, :, None] + np.arange(block)[None, None, :]).reshape(n_paths, -1)[:, :total] + rr = Rd[bi] + gg = G[bi] + + eq = np.ones(n_paths) + phase = np.zeros(n_paths, np.int8) # 0 eval, 1 funded, -1 morto, 2 finito + best_day = np.zeros(n_paths) + fu_day = np.zeros(n_paths, int) + payout = np.zeros(n_paths) + ever = np.zeros(n_paths, bool) + passed = np.zeros(n_paths, bool) + t_pass = np.full(n_paths, -1, int) + p_death_day = 1.0 - (1.0 - pl.FIRM_DEATH_PER_YEAR) ** (1 / 365.0) if firm_death else 0.0 + + for t in range(total): + if p_death_day: + phase[(rng.random(n_paths) < p_death_day) & (phase >= 0)] = -1 + alive = phase >= 0 + if not alive.any(): + break + in_ev = alive & (phase == 0) + in_fu = alive & (phase == 1) + lev = np.where(in_fu, lev_fu, lev_ev) + rt = rr[:, t] * lev + gt = gg[:, t] * lev + eqp = eq + eq = np.where(alive, eq * (1.0 + rt), eq) + eq_low = np.where(alive, eqp * (1.0 + rt + gt), eq) + r_low = rt + gt + bust = ((in_ev & ((eq_low < 1.0 - dd) | (r_low < -dl))) + | (in_fu & ((eq_low < 1.0 - ml) | (r_low < -dlf)))) + phase[bust] = -1 + gain = np.maximum(eq - eqp, 0.0) + best_day = np.where(in_ev & ~bust, np.maximum(best_day, gain), best_day) + profit = eq - 1.0 + ok = in_ev & ~bust & (profit >= tgt) + if consistency: + ok &= best_day <= pl.FIRMS[0].get("consistency", 0.40) * np.maximum(profit, 1e-9) + phase[ok] = 1 + eq[ok] = 1.0 + fu_day[ok] = 0 + passed |= ok + t_pass[ok] = t + still_ev = (phase == 0) & (t >= max_eval_days - 1) + phase[still_ev] = -1 # eval scaduta + now_fu = phase == 1 + fu_day[now_fu & ~ok] += 1 + chk = now_fu & (fu_day > 0) & (fu_day % 30 == 0) + pay = chk & (eq > 1.0) & (((eq - 1.0) * notional * SPLIT) >= min_payout) + payout += np.where(pay, (eq - 1.0) * notional * SPLIT * (1.0 - TAX_RATE), 0.0) + ever |= pay + eq = np.where(pay, 1.0, eq) + phase[now_fu & (fu_day >= funded_days)] = 2 + + return dict(p_pass=float(passed.mean()), p_payout=float(ever.mean()), + p_pay_given=float(ever.sum() / max(passed.sum(), 1)), + e_payout=float(payout.mean()), + e_payout_given=float(payout[ever].mean()) if ever.any() else 0.0, + t_pass=float(np.median(t_pass[passed])) if passed.any() else float("nan")) + + +def ev_three_ways(res: dict, price: float) -> dict: + """Le tre convenzioni sul deposito, sullo STESSO Monte Carlo. + (i) SPESA PERSA — la quota non torna mai (`pc.simulate`, il numero operativo) + (ii) RIMBORSO AL PASS — la quota torna se passi (`r0725_hyro:200`) + (iii) RIMBORSO AL PAYOUT — la quota torna col primo prelievo (la regola VERA della firm) + """ + e, pp, pa = res["e_payout"], res["p_pass"], res["p_payout"] + return dict(sunk=e - price, + at_pass=e - price * (1.0 - pp), + at_payout=e - price * (1.0 - pa), + p_break_even=float(np.clip((price - e) / price, 0.0, 1.0)) if price else 0.0) + + +# ==================================================================================== main +def main() -> None: + try: + sys.stdout.reconfigure(line_buffering=True) + except Exception: # pragma: no cover + pass + print("=" * 104) + print(" GATE PROP-01 gamba (c) — il BIGLIETTO come OPZIONE, il FUNDING dentro, e il") + print(" confronto con l'alternativa ovvia: tenere i $635 sul libro e versare") + print("=" * 104) + print(" PREVISIONE REGISTRATA PRIMA: (1) il rimborso vale +5-15% di EV e +1-3pp su") + print(" P(>=50/g); (2) P(primo payout | pass) > 80%; (3) il funding costa ~0,75 x 2,16%") + print(" su un funded a 0,75x; (4) sul segno del funding di XS01 NON ho una previsione,") + print(" le due forze tirano in verso opposto; (5) EV positivo sulla MEDIA e negativo") + print(" sulla MEDIANA — una lotteria, non un investimento.") + + # ============================================================== §0.1 riproduzione r0725_hyro + hr("§0.1 RIPRODUZIONE — `r0725_hyro` (25/07): l'EV del biglietto come fu pubblicato") + buf = io.StringIO() + t = time.time() + import r0725_hyro as HY # noqa: E402 + with contextlib.redirect_stdout(buf): + HY.main() + txt = buf.getvalue() + lens_now, ev_now = None, {} + for line in txt.splitlines(): + if "[close-only]" in line: + lens_now = "close" + elif "[intraday]" in line: + lens_now = "intra" + m = re.match(r"\s*\$\s*100,000\s+\$\s*([\d,]+)\s+\$\s*([\d,]+)\s+\$\s*([\d,]+)\s+" + r"\$\s*([\-\d,]+)", line) + if m and lens_now: + ev_now[lens_now] = float(m.group(4).replace(",", "")) + print(f" rigirato oggi ({time.time()-t:.0f}s), stessa macchina, stessi semi, biglietto $100k:") + print(f" {'lente':>14} {'EV oggi':>12} {'EV PUBBLICATO 25/07':>22} {'delta':>10}") + for k, lab, p in (("close", "close-only", PUB["hyro_ev_close"]), + ("intra", "intraday", PUB["hyro_ev_intra"])): + v = ev_now.get(k, float("nan")) + print(f" {lab:>14} ${v:>11,.0f} ${p:>21,.0f} {v-p:>+10,.0f}") + print(" Lo scarto NON e' un errore di riproduzione: `r0725_hyro` ri-deriva le proprie serie") + print(" dal feed CORRENTE, e dal 25/07 a oggi il feed ha ~4 settimane di barre in piu'.") + print(" Ordine di grandezza e conclusione identici -> la macchina e' quella.") + print("\n ⚠ E il codice riprodotto contiene gia' la contraddizione: `cost = price*(1-pe)`") + print(" = quota RIMBORSATA AL PASS, mentre `pc.simulate` (da cui esce il numero") + print(" operativo P(>=50/g)) fa `cash -= price` e non la restituisce MAI.") + bump(1) + tick("§0.1") + + # ============================================================== dati comuni + hr("§0.2 IL PANNELLO — le stesse serie di PROP-RECAL (U13 Binance, W-LONG 2021+)") + Cb, Ob, Hb, Lb = PR.ohlc_panels(PR.bin_loader, XS_UNIVERSE) + p13 = Cb[X.U13].dropna() + o13 = Ob.reindex(p13.index)[X.U13] + h13 = Hb.reindex(p13.index)[X.U13] + l13 = Lb.reindex(p13.index)[X.U13] + XSP = {ph: PR.xs_tuples(p13, o13, h13, l13, phase=ph) for ph in PHASES_SUB} + bump(len(PHASES_SUB)) + xs0 = XSP[PHASES_SUB[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] + ev_b = PA.boot_idx(len(I), EV_H, N_PATHS_J, seed=SEED_EV) + fu_b = PA.boot_idx(len(I), FU_H, N_PATHS_J, seed=SEED_FU) + print(f" W-LONG: {len(I)} giorni {I[0].date()} -> {I[-1].date()} | de-luck x{DELUCK} | " + f"{N_PATHS_J} percorsi per J") + pc.DELUCK = DELUCK + + # J all'ancora canonica, mediana sulle 3 fasi dichiarate + js, jlv = [], [] + for ph in PHASES_SUB: + Rc, Gc = AP.rg_off(W_A, I, XSP[ph], 0) + j, lv, _ = best_lev(Rc, Gc, ev_b, fu_b) + js.append(j); jlv.append(lv) + RL0, GL0 = AP.rg_off(W_LIVE, I, xs0, 0) + jL, lvL, vL0 = best_lev(RL0, GL0, ev_b, fu_b) + dpair = [] + for ph in PHASES_SUB: + Rc, Gc = AP.rg_off(W_A, I, XSP[ph], 0) + _, _, vc = best_lev(Rc, Gc, ev_b, fu_b) + dpair.append(float((vc - vL0).mean())) + print(f" J(W_A 38/38/25) ancora canonica, fasi {PHASES_SUB}: mediana {np.median(js):.3f} " + f"(PUB {PUB['recal_j']:.3f} su 10 fasi) | leve {jlv}") + print(f" J(LIVE 75/25) : {jL:.3f} @{lvL:.2f}x " + f"(PUB {PUB['recal_live']:.3f})") + print(f" delta appaiato mediano : {np.median(dpair):+.3f} " + f"(PUB {PUB['recal_d']:+.3f})") + tick("§0.2") + + # ============================================================== §1 il funding + hr("§1. IL FUNDING, MESSO DENTRO — e il segno su XS01, MISURATO") + rate = funding_rate() + if rate is None: + print(" Senza cache non si mette dentro nulla: il resto gira SENZA funding e lo dichiara.") + xs_ann = 0.0 + else: + fb0 = FD.book_75_25(None, alloc=654.0) + fb1 = FD.book_75_25(rate, alloc=654.0) + d_book = float((fb0 - fb1).dropna().mean() * 365) * 100 + ftp = f_tp01_sleeve(rate) + fsk = f_skh_sleeve(rate, 0) + c0, _ = FD.tp01_canonical(None) + c1, _ = FD.tp01_canonical(rate) + d_tp = float((c0 - c1).dropna().mean() * 365) * 100 + print(f" RIPRODUZIONE dei costi di §35 (%/anno, segno = costo):") + print(f" {'serie':>36} {'oggi':>9} {'PUB §35':>9}") + print(f" {'LIBRO 75/25 path live':>36} {-d_book:>8.2f}% {PUB['fund_book']:>8.2f}%") + print(f" {'TP01 canonico':>36} {-d_tp:>8.2f}% {PUB['fund_tp']:>8.2f}%") + print(f" {'SKH01 50/50 path live (off 0)':>36} " + f"{-float(fsk.mean()*365)*100:>8.2f}% {PUB['fund_skh']:>8.2f}%") + print(f" {'TP01 gambe orarie (lente prop)':>36} " + f"{-float(ftp.reindex(I).mean()*365)*100:>8.2f}% {'—':>9}") + print("\n ⚠ La riga 'gambe orarie' non e' la stessa di 'TP01 canonico': il recon orario") + print(" usa `mc.tp01_daily_frame` (senza min-order, che e' la lente giusta su un") + print(" conto funded da $100k). Le due lenti differiscono di poco e si dichiarano.") + print("\n IL SEGNO DEL FUNDING SU XS01 — misurato, non assunto:") + xsf = xs_funding_measure() + xs_ann = xsf["ann"] + print(f"\n >>> XS01 **PAGA** {xs_ann*100:+.2f}%/anno di funding (segno positivo = costo).") + print(" La previsione registrata ('non lo so, le due forze tirano in verso opposto')") + print(" si risolve cosi': il momentum cross-sezionale COMPRA i perp col funding piu'") + print(" caro e VENDE quelli col funding piu' basso -> paga la dispersione.") + print(" Essendo `sum(W)=0` il LIVELLO non entra: entra solo la DISPERSIONE.") + print(f" Se il funding Hyperliquid e' ~2,1x quello del venue eseguibile (§35),") + print(f" la banda onesta e' [{xs_ann/2.1*100:+.2f}%, {xs_ann*100:+.2f}%]/anno.") + print("\n LA LEVA — perche' il funding non e' un costo fisso:") + print(" il funding e' proporzionale all'ESPOSIZIONE, e l'esposizione di un conto funded") + print(" e' `lev x` quella del libro -> nel simulatore `Rs = R*lev` porta dentro anche il") + print(" costo, che quindi scala. Verifica numerica (libro W_A, costo %/anno di equity):") + fA = fvec_for(W_A, I, rate, 0, xs_ann) + for lv in (0.50, 0.75, 1.00, 1.25): + print(f" leva {lv:>4.2f}x -> {-float(np.mean(fA))*365*100*lv:>6.2f}%/anno " + f"(= {lv:.2f} x {-float(np.mean(fA))*365*100:.2f}%)") + tick("§1") + + # ============================================================== §2 banda d'ancora + hr("§2. LA BANDA D'ANCORA — 23 offset x 3 fasi, con e SENZA funding (riproduzione + delta)") + print(f" Sottocampione dichiarato, identico a `r0822c`: {len(OFFSETS)} offset x " + f"{len(PHASES_SUB)} fasi {PHASES_SUB} = {len(OFFSETS)*len(PHASES_SUB)} celle, " + f"x2 (funding on/off).") + print(f" Ladder: {N_PATHS_LAD} percorsi (risoluzione ~+-1pp su P(>=50/g)), lente ACCOPPIATA,") + print(f" {pl.MAX_CONCURRENT} conti max, morte-firm {pl.FIRM_DEATH_PER_YEAR:.0%}/anno, " + f"deposito NON rimborsato (= convenzione di `pc.simulate`, per riprodurre).") + cells: list[dict] = [] + t = time.time() + for off in OFFSETS: + fA = fvec_for(W_A, I, rate, off, xs_ann) + for ph in PHASES_SUB: + R0, G0 = AP.rg_off(W_A, I, XSP[ph], off) + for tag, Rx in (("nofund", R0), ("fund", R0 - fA if fA is not None else None)): + if Rx is None: + continue + j, lv, _ = best_lev(Rx, G0, ev_b, fu_b) + lad = ladder(Rx, G0, N_PATHS_LAD, lv, SEED_LAD, refund=False) + cells.append(dict(off=off, ph=ph, tag=tag, J=j, lev=lv, + p50=lad["p_target"], pz=lad["p_zero"], med=lad["med"], + ppay=lad["p_payout"])) + bump(2) + C = pd.DataFrame(cells) + print(f" ({time.time()-t:.0f}s)") + print(f"\n {'variante':>12} {'J mediana':>10} {'P(>=50/g)':>10} {'banda p10-p90':>18} " + f"{'P(zero)':>9} {'EUR/g med':>10}") + for tag, lab in (("nofund", "SENZA funding"), ("fund", "CON funding")): + s = C[C["tag"] == tag] + if not len(s): + continue + print(f" {lab:>12} {s['J'].median():>10.3f} {s['p50'].median():>10.1%} " + f"[{np.percentile(s['p50'],10):>7.1%},{np.percentile(s['p50'],90):>7.1%}] " + f"{s['pz'].median():>9.1%} {s['med'].median():>10.2f}") + s_nf = C[C["tag"] == "nofund"] + print(f"\n RIPRODUZIONE §32: P(>=50/g) mediana {s_nf['p50'].median():.1%} " + f"(PUB {PUB['anchor_p50g']:.1%}) | banda " + f"[{np.percentile(s_nf['p50'],10):.1%}, {np.percentile(s_nf['p50'],90):.1%}] " + f"(PUB [{PUB['anchor_p10']:.1%}, {PUB['anchor_p90']:.1%}]) | " + f"P(zero) {s_nf['pz'].median():.1%} (PUB {PUB['anchor_pzero']:.1%})") + if rate is not None: + s_f = C[C["tag"] == "fund"] + m = C.pivot_table(index=["off", "ph"], columns="tag", values="p50") + dpp = (m["fund"] - m["nofund"]) + mj = C.pivot_table(index=["off", "ph"], columns="tag", values="J") + dj = (mj["fund"] - mj["nofund"]) + print(f"\n IL FUNDING, appaiato cella per cella (mediana delle DIFFERENZE, non") + print(f" differenza delle mediane): dJ {dj.median():+.4f} " + f"({int((dj<0).sum())}/{len(dj)} celle negative) | " + f"dP(>=50/g) {dpp.median()*100:+.2f}pp " + f"({int((dpp<0).sum())}/{len(dpp)} negative)") + print(f" Il numero operativo col funding dentro: **P(>=50 EUR/g) " + f"{s_f['p50'].median():.1%}** [{np.percentile(s_f['p50'],10):.1%}, " + f"{np.percentile(s_f['p50'],90):.1%}], P(zero) {s_f['pz'].median():.1%}") + # cella d'ancora MEDIANA su cui si prezza il biglietto + ref_tag = "fund" if rate is not None else "nofund" + S = C[C["tag"] == ref_tag].reset_index(drop=True) + k_med = int((S["p50"] - S["p50"].median()).abs().idxmin()) + OFF_M, PH_M, LEV_M = int(S.loc[k_med, "off"]), int(S.loc[k_med, "ph"]), float(S.loc[k_med, "lev"]) + print(f"\n CELLA D'ANCORA MEDIANA scelta per prezzare il biglietto: offset {OFF_M} min, " + f"fase {PH_M}, leva {LEV_M:.2f}x") + print(" (non l'ancora canonica: quella e' al 91° pctl dei 23 offset — §32)") + fM = fvec_for(W_A, I, rate, OFF_M, xs_ann) + R_M0, G_M = AP.rg_off(W_A, I, XSP[PH_M], OFF_M) + R_M = R_M0 - fM if fM is not None else R_M0 + tick("§2") + + # ============================================================== §3 il biglietto a 2 stadi + hr("§3. IL BIGLIETTO COME OPZIONE — i DUE stadi, sullo stesso percorso") + print(" Stadio 1: passare l'eval (target 10%, maxDD 6% STATICO, daily 4%, consistency 40%).") + print(" Stadio 2: sul funded, arrivare ad ALMENO un payout — che e' l'evento che") + print(" rimborsa il deposito. Soglia: quota trader >= $100 (fonte dichiarativa della firm).") + print(f" {N_PATHS_TIX} percorsi, blocchi di 20 giorni, morte-firm dentro, lente accoppiata.") + rows = [] + for lev_ev in (0.50, 0.75, 1.00): + for lev_fu in (0.50, 0.75, 1.00): + r = ticket_mc(R_M, G_M, lev_ev=lev_ev, lev_fu=lev_fu, notional=100_000.0) + rows.append(dict(lev_ev=lev_ev, lev_fu=lev_fu, + **{k: r[k] for k in + ("p_pass", "p_payout", "p_pay_given", "e_payout", + "e_payout_given", "t_pass")})) + bump(1) + T = pd.DataFrame(rows) + print(f"\n {'leva eval':>10} {'leva fund':>10} {'P(pass)':>9} {'P(payout)':>10} " + f"{'P(pay|pass)':>12} {'E[payout]':>11} {'E[pay|pay]':>12} {'gg al pass':>11}") + for _, x in T.iterrows(): + print(f" {x['lev_ev']:>10.2f} {x['lev_fu']:>10.2f} {x['p_pass']:>9.1%} " + f"{x['p_payout']:>10.1%} {x['p_pay_given']:>12.1%} ${x['e_payout']:>10,.0f} " + f"${x['e_payout_given']:>11,.0f} {x['t_pass']:>11.0f}") + best = T.loc[T["e_payout"].idxmax()] + LEV_EV, LEV_FU = float(best["lev_ev"]), float(best["lev_fu"]) + print(f"\n Leve che massimizzano E[payout]: eval {LEV_EV:.2f}x / funded {LEV_FU:.2f}x") + print(f" (per confronto, la leva che massimizza J alla stessa cella e' {LEV_M:.2f}x: J e'") + print(" P(pass) x P(vivo), che NON e' E[payout] — l'ottimo non deve coincidere)") + pg = T["p_pay_given"] + print(f" >>> PREVISIONE (2) 'P(primo payout | pass) > 80%': vale in " + f"{int((pg > 0.80).sum())}/{len(pg)} celle (banda {pg.min():.1%}-{pg.max():.1%}) -> " + f"{'CONFERMATA salvo a leva funded 1.00x' if (pg > 0.80).sum() >= 6 else 'SMENTITA'}") + print(" Il verso e' meccanico e vale la pena dirlo: piu' leva sul funded alza") + print(" E[payout] e ABBASSA P(payout), perche' fa bustare prima del primo prelievo.") + print(" Sono due obiettivi diversi: chi vuole il RIMBORSO non vuole la leva massima.") + + hr("§3.1 LE TRE CONVENZIONI SUL DEPOSITO — stesso Monte Carlo, tre economie") + print(" (i) SPESA PERSA `pc.simulate` -> EV = E[payout] - prezzo") + print(" (ii) RIMBORSO AL PASS `r0725_hyro` -> EV = E[payout] - prezzo x (1 - P(pass))") + print(" (iii)RIMBORSO AL PAYOUT la firm -> EV = E[payout] - prezzo x (1 - P(payout))") + print(f"\n {'biglietto':>12} {'prezzo':>8} {'E[payout]':>11} {'(i) persa':>11} " + f"{'(ii) al pass':>13} {'(iii) al payout':>16} {'EUR/g atteso':>13}") + tix_rows = [] + for size, price in pl.FIRMS[0]["tickets"]: + r = ticket_mc(R_M, G_M, lev_ev=LEV_EV, lev_fu=LEV_FU, notional=float(size)) + e3 = ev_three_ways(r, price) + tix_rows.append(dict(size=size, price=price, **r, **e3)) + print(f" ${size:>11,} ${price:>7,.0f} ${r['e_payout']:>10,.0f} ${e3['sunk']:>10,.0f} " + f"${e3['at_pass']:>12,.0f} ${e3['at_payout']:>15,.0f} " + f"{e3['at_payout']/EURUSD/365:>13.2f}") + bump(1) + TX = pd.DataFrame(tix_rows) + big = TX.iloc[-1] + rJ = ticket_mc(R_M, G_M, lev_ev=LEV_M, lev_fu=LEV_M, notional=100_000.0) + eJ = ev_three_ways(rJ, 579.0) + bump(1) + print(f"\n Lo STESSO biglietto $100k alla leva che massimizza J ({LEV_M:.2f}x su entrambi") + print(" gli stadi, cioe' la leva con cui e' costruito tutto il resto di questo filone):") + print(f" P(pass) {rJ['p_pass']:.1%} | P(payout) {rJ['p_payout']:.1%} | " + f"E[payout] ${rJ['e_payout']:,.0f} | EV persa ${eJ['sunk']:+,.0f} | " + f"EV al payout ${eJ['at_payout']:+,.0f}") + print(" -> l'EV e' positivo a ENTRAMBE le leve: la conclusione non dipende da quale") + print(" obiettivo (J o E[payout]) si sceglie per tararla.") + d_conv = big["at_payout"] - big["sunk"] + print(f"\n Quanto vale la CORREZIONE (da 'spesa persa' a 'rimborso al payout'), $100k: " + f"${d_conv:+,.0f} = {d_conv/max(abs(big['sunk']),1e-9)*100:+.1f}% dell'EV.") + print(f" Quanto separa le due convenzioni SBAGLIATE fra loro (al pass vs al payout): " + f"${big['at_pass']-big['at_payout']:+,.0f} — cioe' prezzo x (P(pass)-P(payout)) = " + f"${big['price']*(big['p_pass']-big['p_payout']):+,.0f}.") + print(f" >>> PREVISIONE (1) 'il rimborso vale +5-15% di EV': " + f"{'CONFERMATA' if 0.05 <= d_conv/max(abs(big['sunk']),1e-9) <= 0.15 else 'SMENTITA'}") + print(f"\n SENSIBILITA': con E[payout] = ${big['e_payout']:,.0f} e prezzo ${big['price']:,.0f},") + print(f" l'EV al payout resta positivo finche' P(payout) > " + f"{max(0.0,(big['price']-big['e_payout'])/big['price']):.1%} — misurata " + f"{big['p_payout']:.1%}.") + print(" ⚠ E' un EV in DOLLARI ATTESI. Su un conto da $654 il biglietto si compra poche") + print(" volte: la media non e' la grandezza che decide. Si guarda la distribuzione (§5).") + print(" ⚠ RICONCILIAZIONE (tre P(payout) diverse compaiono in questo file, e NON sono in") + print(" contraddizione): qui e' UN biglietto su UN anno di funded; la scala di conti") + print(" (§4-§6) lascia correre 36 mesi e ricompra -> la sua P e' piu' alta. Confrontare") + print(" le due senza dire la finestra e' l'errore che le farebbe sembrare incoerenti.") + tick("§3") + + # ============================================================== §4 ladder col rimborso + hr("§4. LA SCALA DI CONTI COL DEPOSITO RIMBORSABILE") + print(" §4.1 CONTROLLO — con `refund=False, deposito=0, min_payout=0` il mio simulatore") + print(" dev'essere BIT-EXACT rispetto a `pc.simulate` (stesso seme, stesso stream).") + cfg = tuple(W_A.get(n, 0.0) for n in PA.CRYPTO_PROP) + key = (cfg[0], cfg[1], cfg[2], "shared") + saved = pc._TUP_CACHE.pop(key, None) + pc._TUP_CACHE[key] = (R_M, G_M, I) + ref = pc.simulate([cfg], [0] * pl.MAX_CONCURRENT, n_paths=N_PATHS_LAD, lev=LEV_M, + seed=SEED_LAD, lens="coupled", start=str(I[0].date())) + pc._TUP_CACHE.pop(key, None) + if saved is not None: + pc._TUP_CACHE[key] = saved + mine = ladder(R_M, G_M, N_PATHS_LAD, LEV_M, SEED_LAD, refund=False) + dmax = float(np.abs(np.sort(ref["eur_day"]) - np.sort(mine["eur_day"])).max()) + dmax2 = float(np.abs(ref["eur_day"] - mine["eur_day"]).max()) + print(f" max|diff| percorso per percorso = {dmax2:.3e} (ordinati: {dmax:.3e}) -> " + f"{'IDENTICO' if dmax2 < 1e-12 else 'DIVERGE — STOP'}") + if dmax2 >= 1e-12: + print(" Il simulatore non replica: i numeri sotto sarebbero di un'altra macchina.") + return + bump(1) + + print("\n §4.2 QUANTO VALE IL RIMBORSO (cella d'ancora mediana, stessi semi)") + print(f" {'convenzione':>34} {'EUR/g med':>10} {'P(>=10/g)':>10} {'P(>=50/g)':>10} " + f"{'P(zero)':>9} {'cassa fin. med':>15} {'media':>10}") + lad_rows = {} + for tag, rf, mp in (("spesa persa (pubblicato)", False, 0.0), + ("spesa persa + soglia $100", False, MIN_PAYOUT_TRADER), + ("RIMBORSO al primo payout", True, MIN_PAYOUT_TRADER)): + r = ladder(R_M, G_M, N_PATHS_LAD, LEV_M, SEED_LAD, refund=rf, min_payout=mp) + lad_rows[tag] = r + print(f" {tag:>34} {r['med']:>10.2f} {r['p_ge10']:>10.1%} {r['p_target']:>10.1%} " + f"{r['p_zero']:>9.1%} ${r['med_cash']:>14,.0f} ${r['mean_cash']:>9,.0f}") + bump(1) + a = lad_rows["spesa persa + soglia $100"] + b = lad_rows["RIMBORSO al primo payout"] + print(f"\n Delta del rimborso: P(>=50/g) {(b['p_target']-a['p_target'])*100:+.2f}pp | " + f"EUR/g mediana {b['med']-a['med']:+.2f} | cassa finale mediana " + f"${b['med_cash']-a['med_cash']:+,.0f} | quota restituita media ${b['mean_back']:,.0f}") + print(f" >>> PREVISIONE (1) 'il rimborso vale +1-3pp su P(>=50/g)': " + f"{'CONFERMATA' if 0.01 <= (b['p_target']-a['p_target']) <= 0.03 else 'SMENTITA'} " + f"({(b['p_target']-a['p_target'])*100:+.2f}pp)") + tick("§4") + + # ============================================================== §5 biglietto vs versare + hr("§5. IL BIGLIETTO CONTRO IL VERSARE — stessa metrica, stesso orizzonte, stessi sorteggi") + print(" Strada A (BIGLIETTO): $654 comprano il biglietto piu' grande possibile; la scala di") + print(" conti gira il libro W_A 38/38/25 sul conto della firm (XS01 LI' E' ESEGUIBILE),") + print(" deposito rimborsabile, morte-firm, cap $200k/firm; la cassa resta FERMA.") + print(" Strada B (LIBRO): gli stessi $654 restano sul libro LIVE 75/25 a min-order $5") + print(" (XS01 NON e' eseguibile a $654), nessuna barriera, fisco 33% sull'anno.") + print(" ⚠ L'asimmetria fra le due strade e' REALE ed e' il punto del canale funded: il") + print(" conto della firm da' accesso a sleeve che il capitale proprio non puo' eseguire.") + rb_full = FD.book_75_25(rate, alloc=654.0) if rate is not None else FD.book_75_25(None, 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"\n libro LIVE a $654 (funding {'DENTRO' if rate is not None else 'FUORI'}): " + f"drift {rb.mean()*365*100:.2f}%/anno, vol {rb.std()*np.sqrt(365)*100:.1f}%, " + f"Sharpe {rb.mean()*365/(rb.std()*np.sqrt(365)):.2f} su {len(rb)} giorni") + rngb = np.random.default_rng(51224) + nb = int(np.ceil(HORIZON_DAYS / 20)) + st = rngb.integers(0, len(I) - 20, size=(N_PATHS_LAD, nb)) + BOOT = (st[:, :, None] + np.arange(20)[None, None, :]).reshape(N_PATHS_LAD, -1)[:, :HORIZON_DAYS] + print(f" bootstrap CONDIVISO fra le due strade: {N_PATHS_LAD} percorsi x {HORIZON_DAYS} " + f"giorni, blocchi 20 -> confronto APPAIATO") + print(f"\n {'versamento':>12} {'strada':>10} {'mediana':>11} {'p10':>10} {'p90':>10} " + f"{'media':>11} {'P(sotto il versato)':>20} {'P(>=50/g)':>10}") + cmp_rows = [] + for dep in (0.0, 250.0, 500.0): + A = ladder(R_M, G_M, N_PATHS_LAD, LEV_M, SEED_LAD, refund=True, + deposit_eur=dep, min_payout=MIN_PAYOUT_TRADER, boot=BOOT) + B = book_road(rb, BOOT, pl.START_EUR, dep) + bump(2) + for lab, r in (("BIGLIETTO", A), ("LIBRO", B)): + p_loss = float((r["cash"] < r["contributed"]).mean()) + p50g = r.get("p_target", 0.0) + print(f" {f'EUR {dep:,.0f}/mese':>12} {lab:>10} ${r['med_cash']:>10,.0f} " + f"${r['p10_cash']:>9,.0f} ${r['p90_cash']:>9,.0f} ${r['mean_cash']:>10,.0f} " + f"{p_loss:>20.1%} {p50g:>10.1%}") + cmp_rows.append(dict(dep=dep, road=lab, med=r["med_cash"], mean=r["mean_cash"], + p10=r["p10_cash"], p90=r["p90_cash"], ploss=p_loss)) + print(f" {'':>12} {'delta':>10} ${A['med_cash']-B['med_cash']:>+10,.0f} " + f"{'':>10} {'':>10} ${A['mean_cash']-B['mean_cash']:>+10,.0f}") + CMP = pd.DataFrame(cmp_rows) + print("\n ('P(>=50/g)' e' definita solo per la strada BIGLIETTO: la strada LIBRO non preleva") + print(" durante l'accumulo. La colonna che si confronta e' la RICCHEZZA TERMINALE.)") + tick("§5") + + # ============================================================== §6 la curva del capitale + hr("§6. LA CURVA DEL CAPITALE — a che conto il biglietto smette di essere la strada migliore") + print(" Stesso confronto appaiato, capitale iniziale variabile, nessun versamento (cosi' la") + print(" sola variabile e' il capitale). La strada LIBRO resta il 75/25 a ogni taglia:") + print(" e' una scelta CONSERVATIVA CONTRO la strada libro (a $5k/$20k il libro potrebbe") + print(" aggiungere XSR01/XS01) -> il capitale d'incrocio misurato e' un LIMITE SUPERIORE.") + cheap = min(t[1] for F in pl.FIRMS for t in F["tickets"]) + print(f"\n {'capitale':>10} {'A mediana':>12} {'B mediana':>12} {'A media':>12} " + f"{'B media':>12} {'A P(0 pay)':>11} {'A P(<${:.0f})'.format(cheap):>12} " + f"{'A med|>0':>10} {'vince med.':>11}") + caps = (600.0, 1_000.0, 2_000.0, 3_500.0, 6_000.0, 10_000.0, 20_000.0, 40_000.0) + cross_med = cross_mean = None + prev = None + for ce in caps: + A = ladder(R_M, G_M, N_PATHS_LAD, LEV_M, SEED_LAD, refund=True, start_eur=ce, + min_payout=MIN_PAYOUT_TRADER, boot=BOOT) + B = book_road(rb, BOOT, ce, 0.0) + bump(2) + wm = "BIGLIETTO" if A["med_cash"] > B["med_cash"] else "LIBRO" + nz = A["cash"][A["cash"] >= cheap] + p_stuck = float((A["cash"] < cheap).mean()) + print(f" EUR{ce:>7,.0f} ${A['med_cash']:>11,.0f} ${B['med_cash']:>11,.0f} " + f"${A['mean_cash']:>11,.0f} ${B['mean_cash']:>11,.0f} {A['p_zero']:>11.1%} " + f"{p_stuck:>12.1%} ${np.median(nz) if len(nz) else 0:>9,.0f} {wm:>11}") + cur = (A["med_cash"] > B["med_cash"], A["mean_cash"] > B["mean_cash"]) + if prev is not None: + if prev[0] != cur[0] and cross_med is None: + cross_med = (prev[2], ce) + if prev[1] != cur[1] and cross_mean is None: + cross_mean = (prev[2], ce) + prev = (cur[0], cur[1], ce) + print(f"\n Incrocio sulla MEDIANA: {cross_med if cross_med else 'nessuno nella griglia'}") + print(f" Incrocio sulla MEDIA : {cross_mean if cross_mean else 'nessuno nella griglia'}") + + print("\n ⚠ IL 'GRADINO' FRA EUR 1.000 E EUR 2.000 NON E' UN MECCANISMO: e' la MEDIANA") + print(" che cambia MODO. La distribuzione della strada-biglietto e' BIMODALE — o si") + print(" finisce SENZA nemmeno i soldi per ricomprare il biglietto piu' economico, o si") + print(f" finisce con migliaia. La colonna `P(<${cheap:.0f})` e' la massa del modo basso e") + print(" si muove LISCIA; la mediana complessiva salta di un ordine di grandezza appena") + print(" quella massa attraversa il 50%. **La mediana non e' una statistica robusta qui**:") + print(" quelle robuste sono `P(<$249)`, `P(0 payout)` e la media, che SATURANO.") + print(" -> il 'capitale d'incrocio' e' il punto in cui una massa di probabilita' passa") + print(" il 50%, NON una soglia con un meccanismo dietro. Va detto, perche' un numero") + print(" cosi' netto e' esattamente quello che si finirebbe per citare come soglia.") + print("\n §6.1 LA SECONDA FIRM — l'unico ingrediente STRUTTURALE che cambia con la cassa") + print(" (FTMO: max loss 10% contro il 6% STATICO di HYRO — il vincolo che il") + print(" progetto misura come binding su questo libro fin dal 25/07).") + print(" Si legge su MEDIA e P(0 payout), non sulla mediana (vedi sopra).") + all_firms = pl.FIRMS + print(f"\n {'capitale':>10} {'firm ammesse':>16} {'mediana':>11} {'media':>11} " + f"{'P(0 payout)':>11} {'cassa med':>11}") + for ce in (1_000.0, 2_000.0, 3_500.0): + for lab, fl in (("solo HYRO", [all_firms[0]]), ("HYRO+FTMO", all_firms)): + pl.FIRMS = fl + try: + A = ladder(R_M, G_M, N_PATHS_LAD, LEV_M, SEED_LAD, refund=True, start_eur=ce, + min_payout=MIN_PAYOUT_TRADER, boot=BOOT) + finally: + pl.FIRMS = all_firms + bump(1) + print(f" EUR{ce:>7,.0f} {lab:>16} ${A['med_cash']:>10,.0f} " + f"${A['mean_cash']:>10,.0f} {A['p_zero']:>11.1%} ${np.median(A['cash']):>10,.0f}") + print("\n Lettura: la seconda firm ALZA la media (piu' nozionale, e se una firm muore la") + print(" cassa si ricicla sull'altra) e puo' ALZARE anche P(0 payout) al capitale piccolo,") + print(" perche' converte in biglietti la cassa che altrimenti sarebbe rimasta ferma.") + print(" Non e' un pasto gratis: e' piu' esposizione allo stesso rischio binario.") + tick("§6") + + # ============================================================== §7 verdetto + hr("§7. LA GAMBA (c), RIFORMULATA — e la risposta alla domanda che decide") + ev_pay = float(big["at_payout"]) + ev_sunk = float(big["sunk"]) + A0 = [r for r in cmp_rows if r["dep"] == 0.0 and r["road"] == "BIGLIETTO"][0] + B0 = [r for r in cmp_rows if r["dep"] == 0.0 and r["road"] == "LIBRO"][0] + print(f" EV del biglietto $100k alla cella d'ancora MEDIANA, col funding dentro:") + print(f" convenzione VERA (rimborso al primo payout) ${ev_pay:>+10,.0f}") + print(f" convenzione PESSIMISTA (spesa persa) ${ev_sunk:>+10,.0f}") + print(f" -> EV positivo in {'ENTRAMBE' if min(ev_pay, ev_sunk) > 0 else 'UNA SOLA' if max(ev_pay,ev_sunk)>0 else 'NESSUNA'} " + f"le convenzioni.") + print(f"\n A 36 mesi, senza versamenti, $654 iniziali (confronto appaiato):") + print(f" BIGLIETTO mediana ${A0['med']:,.0f} media ${A0['mean']:,.0f} " + f"p10 ${A0['p10']:,.0f} P(sotto il versato) {A0['ploss']:.1%}") + print(f" LIBRO mediana ${B0['med']:,.0f} media ${B0['mean']:,.0f} " + f"p10 ${B0['p10']:,.0f}") + med_win = "BIGLIETTO" if A0["med"] > B0["med"] else "LIBRO" + mean_win = "BIGLIETTO" if A0["mean"] > B0["mean"] else "LIBRO" + print(f" -> sulla MEDIANA vince {med_win}; sulla MEDIA vince {mean_win}.") + print(" (e la mediana qui e' una statistica BIMODALE: dice da che parte del 50% sta") + print(" P(0 payout), non 'quanto' si guadagna — vedi §6)") + print(f" >>> PREVISIONE (5) 'EV positivo sulla MEDIA e negativo sulla MEDIANA': " + f"{'CONFERMATA' if (mean_win=='BIGLIETTO' and med_win=='LIBRO') else 'SMENTITA'}") + print("\n ONESTA' OBBLIGATORIE, portate avanti e non nascoste:") + print(f" * morte-firm {pl.FIRM_DEATH_PER_YEAR:.0%}/anno e' un'ASSUNZIONE del progetto") + print(" (24/07), non una misura: sopra c'e' dentro, ma nessuno l'ha stimata.") + print(" * la RIMBORSABILITA' e' DICHIARATIVA: viene dalla pagina della firm + fonti") + print(" secondarie concordi. Nessuno l'ha vista accadere. Il progetto ha gia' pagato") + print(" per un'assunzione mai verificata sul conto reale (GTAA01/PRIIPs).") + print(f" * il cap ${pl.FIRMS[0]['cap']:,}/trader limita STRUTTURALMENTE il canale: il") + print(" nozionale massimo su HYRO+FTMO e' $600k, cioe' un tetto al reddito, non al rischio.") + print(" * XS01 sul conto funded e' misurato su U13 fuori campione, ma le 6 gambe che") + print(" fuori campione non esistono restano non testabili (§29).") + print(" * l'ancora GIORNALIERA di TP01 (24 ore) NON e' in questa banda: terza dimensione,") + print(" dichiarata anche da §32, e la sua fortuna e' ancora dentro questi numeri.") + + hr("§7.1 IL TESTO PROPOSTO DELLA GAMBA (c)") + price = float(big["price"]) + p_nopay = 1.0 - float(big["p_payout"]) + print(f" Quantita' misurate oggi, a costo ZERO (una corsa di questo script):") + print(f" prezzo del biglietto $100k ${price:>10,.0f}") + print(f" quota del conto ($654) immobilizzata {price/(pl.START_EUR*EURUSD):>10.1%}") + print(f" P(nessun payout) -> quota persa {p_nopay:>10.1%}") + print(f" PERDITA ATTESA = prezzo x P(nessun payout) ${price*p_nopay:>10,.0f}") + print(f" EV con deposito NON rimborsato (pessimista) ${ev_sunk:>+10,.0f}") + print(f" EV con deposito rimborsato al payout (vero) ${ev_pay:>+10,.0f}") + print(f"\n Mesi di piano che il biglietto mette a rischio (quota / versamento mensile):") + for dep in (250.0, 500.0, 800.0): + print(f" a EUR {dep:>4,.0f}/mese: {price/(dep*EURUSD):>4.1f} mesi di versamenti " + f"(perdita attesa = {price*p_nopay/(dep*EURUSD):.1f} mesi)") + print("\n IL PUNTO DI STRUTTURA, che decide la FORMA del gate:") + print(" * misurare l'EV costa UNA CORSA DI QUESTO SCRIPT — zero dollari, minuti;") + print(" * misurare la RIMBORSABILITA' costa $579 e si puo' fare SOLO comprando.") + print(" Un gate che aspettasse la seconda misura sarebbe un gate che si puo' superare solo") + print(" dopo averlo violato. Percio' la gamba (c) va scritta in modo che la") + print(" rimborsabilita' NON decida: si richiede EV positivo sotto la convenzione") + print(" PESSIMISTA (quota mai restituita). Il rimborso diventa allora un regalo, non") + print(" un'ipotesi su cui si e' scommesso.") + print("\n >>> TESTO PROPOSTO — `GATE PROP-01 (c) CAPITALE`, due condizioni CONGIUNTE:") + print(" (c1) ECONOMICA, misura a costo zero, da rifare a ogni cambio del libro o") + print(" delle regole della firm:") + print(" EV del biglietto > 0 con la quota trattata come SPESA PERSA, calcolato") + print(" alla cella d'ancora MEDIANA (non canonica), col FUNDING dentro e sotto") + print(" la lente ACCOPPIATA, con `r0822d_gate_c.py`.") + print(f" Lettura di oggi: ${ev_sunk:+,.0f} -> " + f"{'PASS' if ev_sunk > 0 else 'FAIL'}") + print(" (c2) DI SOPRAVVIVENZA, verificabile dal saldo e dal piano di versamento:") + print(" prezzo del biglietto <= 2 versamenti mensili del piano in corso.") + print(" Motivo: il piano di accumulo e' la leva che il progetto ha misurato come") + print(" dominante (26/07: da 'mai' a 16 anni), e zero e' ASSORBENTE. Un biglietto") + print(" che costa piu' di due mensilita' non e' una scommessa sul canale funded:") + print(" e' un ritardo del piano che lo finanzia.") + print(f" Lettura di oggi (piano dichiarato EUR 500/mese, 26/07): " + f"${price:,.0f} vs 2 x ${500*EURUSD:,.0f} = ${2*500*EURUSD:,.0f} -> " + f"{'PASS' if price <= 2*500*EURUSD else 'FAIL'}") + print(" SCADENZA: nessuna. (c1) e (c2) sono verificabili OGGI; un gate d'attesa qui") + print(" non avrebbe un dato da aspettare, e stanotte due date sono cadute per questo.") + print(" Se si compra, si registra PRIMA: il rimborso deve comparire col primo payout;") + print(" se non compare, la convenzione vera e' 'spesa persa' — che (c1) ha gia'") + print(" assunto, quindi la decisione non va rifatta, va solo annotata.") + + print(f"\n TRIAL/CELLE DICHIARATI (al rialzo): {TRIALS}") + print(f" fatto in {time.time()-T0:.0f}s") + print("=" * 104) + + +if __name__ == "__main__": + main()