"""ALT-OPT — la famiglia opzioni USDC-LINEARE di Deribit, mai guardata dal progetto (2026-08-22). CONTESTO. Il filone VRP-QUOTE-VERE di questa stessa ondata ha trovato che `collect_chain.py` interroga `{"currency": "BTC"|"ETH"}`, che su Deribit restituisce le sole opzioni INVERSE (regolate in BTC/ETH). Il conto e' in USDC. Esiste accanto una famiglia USDC-LINEARE con lotti ~10x piu' piccoli, e su alcuni sottostanti (SOL, XRP, HYPE, AVAX) e' molto piu' popolata di BTC_USDC. Il progetto non l'ha mai misurata. DOMANDA. Esiste su questa famiglia una struttura a RISCHIO DEFINITO (put credit spread, la stessa geometria di VRP01: vendi ~-0.28, compri ~-0.10) eseguibile con qualche centinaio di dollari, con spread e liquidita' che non se la mangino? COSA MISURA, in ordine, e si FERMA appena un vincolo la uccide: 1. i fatti del venue letti dall'API pubblica (min_trade_amount, tick_size, contract_size, costo in $ di UN lotto), e la LIQUIDITA' vera: spread relativo (ask-bid)/mid ai delta che servono davvero, non sull'ATM, + profondita' in cima al book; 2. il collaterale: margine della gamba corta secondo la formula pubblicata dal venue, e max-loss della struttura (i due numeri differiscono per un fatto — se il venue netta le gambe — che l'API PUBBLICA NON dice: e' dichiarato come tale, non indovinato); 3. quanta storia c'e' (risposta: nessuna) e quindi cosa si potrebbe al massimo concludere. COSA NON PUO' FARE, e va detto prima dei numeri: **non esiste un backtest possibile**. Il nostro collettore raccoglie solo le inverse BTC/ETH e l'archivio ereditato pure. Questo file misura le condizioni di UN ISTANTE. Il massimo verdetto ottenibile e' `LEAD` = "vale la pena raccogliere il dato", con il costo di raccolta stimato in chiamate/ora sul giro esistente. VINCOLI DI PROGETTO CITATI, non aggirati: (a) "niente short-vol da modello in deploy" (19/06). Qui i prezzi sono VERI, non modellati — che e' un'altra cosa — ma la regola resta finche' non esiste un campione che contenga uno STRESS. Un istante di calma non e' un campione. (b) SOL e' escluso dall'universo DIREZIONALE per decisione dell'operatore del 22/08. Quella decisione riguarda TP01/SKH01 congelati come terza gamba di trend, e il suo stesso testo dichiara che un meccanismo diverso la riapre. Un put credit spread non e' direzionale nel senso di quella decisione. Ma il guardrail sul DATO vale lo stesso: nessun file nuovo in `data/raw/`, e i prezzi del sottostante qui vengono da `underlying_price` della catena, mai da `load_data`. (c) il gate IV-rank>0.30 e' l'unico alpha misurato di VRP01, e su questi sottostanti NON e' calcolabile: non abbiamo un giorno di storia di vol implicita. Senza quel gate la struttura non e' VRP01, e' vendere vol a caso. CONVENZIONE DI UNITA' (la trappola di questo file): le opzioni INVERSE si quotano in CRIPTO per contratto, le USDC-LINEARI in USDC per unita' di sottostante. Confrontare i due premi senza convertire darebbe numeri sbagliati di un fattore ~10^4-10^5. Qui ogni importo in dollari passa per `prem_usd()`, e le colonne unit-free (spread relativo, costo/credito) sono le uniche direttamente confrontabili fra le due famiglie. RETE: sole letture pubbliche, nessun ordine, pacing a ~2 richieste/s, e il file SI RIFIUTA di partire nella finestra :24-:29 (e' quando `cron_chain` usa lo stesso IP: il rate limit Deribit e' per-IP e il progetto ha gia' avuto un guasto per questo, 29/07). nice -n 19 timeout 900 uv run python scripts/research/r0822_alt_options.py nice -n 19 timeout 900 uv run python scripts/research/r0822_alt_options.py --cache # riusa """ from __future__ import annotations import argparse import json import math import time from datetime import UTC, datetime from pathlib import Path import numpy as np import requests API = "https://www.deribit.com/api/v2/public" TIMEOUT = 20 RPS = 2.0 CACHE = Path("/tmp/claude-1001/-opt-docker-PythagorasGoal/" "b6cc75e7-14f8-4c32-bd07-ab8a0d2aaee6/scratchpad/altopt_cache.json") SHORT_DELTA, LONG_DELTA = -0.28, -0.10 # la geometria di VRP01, non ri-scelta qui DTE_LO, DTE_HI = 4.0, 45.0 # dal settimanale di VRP01 (4-10) fino a ~1.5 mesi OI_MIN = 100.0 # la stessa soglia di collect_chain.py CAPITAL = 635.0 # il conto vero TAKER_CAP = 0.125 # cap fee opzioni Deribit: 12.5% del premio LINEAR = ("SOL_USDC", "XRP_USDC", "ETH_USDC", "HYPE_USDC", "AVAX_USDC", "BTC_USDC") INVERSE = ("BTC", "ETH") # termine di paragone: il progetto le conosce # ---------------------------------------------------------------- rete (parca, sola lettura) class Budget: def __init__(self, rps: float = RPS) -> None: self.rps, self._next, self.calls, self.err, self.r429 = rps, 0.0, 0, 0, 0 def wait(self) -> None: now = time.monotonic() if now < self._next: time.sleep(self._next - now) self._next = max(now, self._next) + 1.0 / self.rps def guardia_finestra() -> None: m = datetime.now(UTC).minute if 24 <= m <= 29: raise SystemExit(f"minuto {m}: finestra di cron_chain (:25-:29). Rilancia dopo il :30.") def get(path: str, params: dict, b: Budget, tries: int = 3): for k in range(tries): b.wait() b.calls += 1 try: r = requests.get(f"{API}/{path}", params=params, timeout=TIMEOUT) except Exception: b.err += 1 time.sleep(1.5 * (k + 1)) continue if r.status_code == 429: b.r429 += 1 time.sleep(2.0 * (k + 1)) continue if r.status_code != 200: b.err += 1 time.sleep(1.0 * (k + 1)) continue try: return r.json()["result"] except Exception: b.err += 1 return None return None def fetch_all(b: Budget) -> dict: """6 chiamate: instruments + book_summary per USDC, BTC, ETH. Niente per-strumento.""" out = {} for cur in ("USDC", "BTC", "ETH"): out[f"inst_{cur}"] = get("get_instruments", {"currency": cur, "kind": "option", "expired": "false"}, b) or [] out[f"summ_{cur}"] = get("get_book_summary_by_currency", {"currency": cur, "kind": "option"}, b) or [] if not out["inst_USDC"]: # il venue potrebbe non accettare currency=USDC out["inst_USDC"] = get("get_instruments", {"currency": "any", "kind": "option", "expired": "false"}, b) or [] out["summ_USDC"] = get("get_book_summary_by_currency", {"currency": "any", "kind": "option"}, b) or [] return out # ---------------------------------------------------------------- Black-Scholes (r=0, come il sleeve) def put_delta(S: float, K: float, T: float, sig: float) -> float: if not (S > 0 and K > 0 and T > 0 and sig > 0): return float("nan") d1 = (math.log(S / K) + 0.5 * sig * sig * T) / (sig * math.sqrt(T)) return 0.5 * (1.0 + math.erf(d1 / math.sqrt(2.0))) - 1.0 # ---------------------------------------------------------------- unita' def is_inverse(fam: str) -> bool: return fam in INVERSE def prem_usd(price: float, r: dict) -> float: """Premio in DOLLARI di `min_trade_amount` contratti quotati a `price`. Lineare: il prezzo e' gia' in USDC per unita' di sottostante. Inverse: il prezzo e' in CRIPTO per contratto -> si moltiplica per il sottostante. """ k = r["csize"] * r["minamt"] return price * k * (r["S"] if is_inverse(r["fam"]) else 1.0) def loss_usd(Ks: float, Kl: float, r: dict) -> float: """Perdita massima strutturale in dollari, per `min_trade_amount` contratti. Lineare: esatta, (Ks-Kl) x quantita'. Inverse: il payoff e' in cripta (max(0,K-S)/S), il peggiore e' a S=Kl e vale (Ks-Kl)/Kl cripto = (Ks-Kl) dollari a quel prezzo -> stessa formula, ma APPROSSIMATA (il valore in dollari della perdita dipende da dove finisce S). """ return (Ks - Kl) * r["csize"] * r["minamt"] # ---------------------------------------------------------------- margine (FONTE SECONDARIA) def im_short_put_usd(S: float, K: float, mark_usd: float, qty: float) -> float: """Initial margin di una short put, in USDC, secondo la formula PUBBLICATA da Deribit. ⚠️ FONTE SECONDARIA, dichiarata: l'API PUBBLICA non espone il margine. Il numero che decide davvero — se Deribit NETTA le due gambe di uno spread in margine standard — non e' leggibile da qui: si conferma con `private/get_margins`, che richiede una chiave (lettura, ma non pubblica) e quindi NON e' stato usato. """ if not (S > 0 and K > 0): return float("nan") otm = max(0.0, S - K) / S # una put e' OTM quando K < S per_contratto = max(max(0.15 - otm, 0.10) * S, 0.075 * S) + max(0.0, mark_usd / max(qty, 1e-12)) return per_contratto * qty # ---------------------------------------------------------------- costruzione della vista def build(raw: dict) -> list[dict]: inst, summ = {}, {} for cur in ("USDC", "BTC", "ETH"): for i in raw.get(f"inst_{cur}") or []: inst[i["instrument_name"]] = i for s in raw.get(f"summ_{cur}") or []: summ[s["instrument_name"]] = s rows = [] now_ms = datetime.now(UTC).timestamp() * 1000.0 for name, i in inst.items(): s = summ.get(name) if s is None: continue fam = name.split("-")[0] dte = (float(i.get("expiration_timestamp") or 0) - now_ms) / 86400_000.0 bid, ask = s.get("bid_price"), s.get("ask_price") bid = float(bid) if bid else None # Deribit manda 0/None per "nessun lato" ask = float(ask) if ask else None iv, S = s.get("mark_iv"), s.get("underlying_price") K = float(i.get("strike") or 0) typ = "P" if i.get("option_type") == "put" else "C" T = max(dte, 0.0) / 365.25 d = (put_delta(float(S), K, T, float(iv) / 100.0) if (S and iv and K and T > 0 and typ == "P") else float("nan")) rows.append(dict( name=name, fam=fam, typ=typ, K=K, dte=dte, S=float(S) if S else float("nan"), iv=float(iv) if iv else float("nan"), delta_bs=d, bid=bid, ask=ask, mid=((bid + ask) / 2 if (bid and ask) else None), mark=float(s.get("mark_price") or 0.0), oi=float(s.get("open_interest") or 0.0), vol=float(s.get("volume") or 0.0), tick=float(i.get("tick_size") or 0.0), steps=i.get("tick_size_steps") or [], minamt=float(i.get("min_trade_amount") or 0.0), csize=float(i.get("contract_size") or 0.0), taker=i.get("taker_commission"), settle=i.get("settlement_currency"), )) return rows def rel_spread(r: dict) -> float: if r["bid"] is None or r["ask"] is None or not r["mid"]: return float("nan") return (r["ask"] - r["bid"]) / r["mid"] # ---------------------------------------------------------------- 1. i fatti del venue def famiglie(rows: list[dict]) -> dict: print("\n" + "=" * 104) print("1a. I FATTI DEL VENUE — public/get_instruments + get_book_summary_by_currency") print("=" * 104) print(f"{'famiglia':<10} {'strum':>6} {'OI>=100':>8} {'min_amt':>9} {'c_size':>7} " f"{'tick':>9} {'sottost.$':>11} {'$/lotto':>10} {'taker':>8} {'settle':>7}") tab = {} for f in sorted({r["fam"] for r in rows}): sub = [r for r in rows if r["fam"] == f] liq = [r for r in sub if r["oi"] >= OI_MIN] S = float(np.nanmedian([r["S"] for r in sub])) mins = {r["minamt"] for r in sub} cs = {r["csize"] for r in sub} a = sub[0] lot = a["minamt"] * a["csize"] * S tab[f] = dict(n=len(sub), nliq=len(liq), minamt=a["minamt"], csize=a["csize"], tick=a["tick"], S=S, lot=lot, taker=a["taker"]) if f in LINEAR or f in INVERSE: avv = "" if (len(mins) == 1 and len(cs) == 1) else " <- min/c_size NON uniformi" print(f"{f:<10} {len(sub):>6} {len(liq):>8} {a['minamt']:>9.4g} {a['csize']:>7.4g} " f"{a['tick']:>9.5g} {S:>11.2f} {lot:>10.2f} {str(a['taker']):>8} " f"{str(a['settle']):>7}{avv}") print("\n `$/lotto` = min_trade_amount x contract_size x sottostante = il NOZIONALE di un") print(" lotto (NON il premio, che e' molto minore). E' la granularita' minima imposta dal venue.") print(" `taker` per le opzioni Deribit e' una frazione del SOTTOSTANTE con cap al 12.5% del") print(" premio: su un'ala molto OTM morde il CAP, non la percentuale.") return tab def replica(tab: dict) -> None: print("\n" + "-" * 104) print("1b. CONTROLLO POSITIVO — riproduco i conteggi dichiarati dal coordinatore (22/08)?") print("-" * 104) atteso = {"BTC": (1038, 415), "ETH": (932, 548), "BTC_USDC": (686, 5), "ETH_USDC": (660, 119), "SOL_USDC": (574, 341), "XRP_USDC": (522, 250), "HYPE_USDC": (396, 172), "AVAX_USDC": (294, 146), "TRX_USDC": (310, 115)} print(f"{'famiglia':<10} {'strum att':>10} {'strum oggi':>11} {'liq att':>8} {'liq oggi':>9}") for f, (n_a, l_a) in atteso.items(): t = tab.get(f) if t is None: print(f"{f:<10} {n_a:>10} {'ASSENTE':>11} {l_a:>8} {'-':>9}") else: print(f"{f:<10} {n_a:>10} {t['n']:>11} {l_a:>8} {t['nliq']:>9}") print(" La catena si muove di ora in ora (scadenze che nascono, OI che cambia): scarti di") print(" poche unita' sono la misura, non un disaccordo. Uno scarto GRANDE sarebbe un problema.") # ---------------------------------------------------------------- 2. liquidita' ai delta utili def gambe(rows: list[dict], fam: str) -> list[dict]: puts = [r for r in rows if r["fam"] == fam and r["typ"] == "P" and DTE_LO <= r["dte"] <= DTE_HI and np.isfinite(r["delta_bs"])] out = [] for e in sorted({round(r["dte"], 4) for r in puts}): g = [r for r in puts if round(r["dte"], 4) == e] s = min(g, key=lambda r: abs(r["delta_bs"] - SHORT_DELTA)) lo = min(g, key=lambda r: abs(r["delta_bs"] - LONG_DELTA)) if s["K"] > lo["K"]: out.append({"dte": e, "short": s, "long": lo, "n_strike": len(g)}) return out def liquidita(rows: list[dict]) -> dict: print("\n" + "=" * 104) print(f"2. LA LIQUIDITA' AI DELTA CHE SERVONO ({SHORT_DELTA} corta / {LONG_DELTA} lunga),") print(f" NON sull'ATM. Finestra {DTE_LO:.0f}-{DTE_HI:.0f} giorni. Delta = BS su mark_iv, r=0.") print("=" * 104) print(f"{'famiglia':<10} {'scad':>5} {'2lati':>6} {'d corta':>8} {'d lunga':>8} " f"{'spr% corta':>11} {'spr% lunga':>11} {'credito$':>9} {'costo/cred':>11} " f"{'fee/cred':>9} {'maxloss$':>9}") res = {} for fam in list(LINEAR) + list(INVERSE): gg = gambe(rows, fam) if not gg: print(f"{fam:<10} {'0':>5} nessuna scadenza utilizzabile nella finestra") continue ss, ll, ds, dl, cred, cost, fee, ml = [], [], [], [], [], [], [], [] due = neg = 0 for g in gg: s, lo = g["short"], g["long"] rs, rl = rel_spread(s), rel_spread(lo) if not (np.isfinite(rs) and np.isfinite(rl)): continue due += 1 c_mid = prem_usd(s["mid"], s) - prem_usd(lo["mid"], lo) c_exe = prem_usd(s["bid"], s) - prem_usd(lo["ask"], lo) if c_mid <= 0: neg += 1 continue # fee taker Deribit: min(0.03% del sottostante, 12.5% del premio) per gamba, x2 gambe, # x2 (apertura + chiusura/esercizio). Conservativo ma e' il listino. def _fee(r: dict) -> float: notion = r["S"] * r["csize"] * r["minamt"] return min(float(r["taker"] or 0.0003) * notion, TAKER_CAP * prem_usd(r["mid"], r)) ss.append(rs); ll.append(rl) ds.append(s["delta_bs"]); dl.append(lo["delta_bs"]) cred.append(c_mid) cost.append((c_mid - c_exe) / c_mid) fee.append(2.0 * (_fee(s) + _fee(lo)) / c_mid) ml.append(loss_usd(s["K"], lo["K"], s) - c_exe) if not cred: print(f"{fam:<10} {len(gg):>5} {due:>6} nessuna struttura con credito positivo a mid " f"({neg} a credito<=0)") continue r = dict(n=len(gg), due=due, neg=neg, s=float(np.median(ss)), l=float(np.median(ll)), ds=float(np.median(ds)), dl=float(np.median(dl)), cred=float(np.median(cred)), cost=float(np.median(cost)), fee=float(np.median(fee)), ml=float(np.median(ml))) res[fam] = r print(f"{fam:<10} {r['n']:>5} {due:>6} {r['ds']:>8.3f} {r['dl']:>8.3f} " f"{r['s']*100:>10.1f}% {r['l']*100:>10.1f}% {r['cred']:>9.2f} " f"{r['cost']*100:>10.1f}% {r['fee']*100:>8.1f}% {r['ml']:>9.2f}") print("\n `2lati` = strutture in cui ENTRAMBE le gambe hanno bid E ask. Una riga presente non") print(" e' un dato presente: una gamba con un solo lato non e' negoziabile a un prezzo noto.") print(" `d corta`/`d lunga` = delta REALIZZATI (non i target): se la griglia degli strike e'") print(" grossolana la struttura che compreresti non e' quella che hai chiesto.") print(" `costo/cred` = quanto dell'incasso a mid resta sul tavolo attraversando lo spread su") print(" ENTRAMBE le gambe. Riferimento del progetto su BTC/ETH inverse: ~10% del credito.") print(" `fee/cred` = listino taker Deribit, 2 gambe x apertura+chiusura, col cap 12.5%.") print(" `credito$` e `maxloss$` sono per UN LOTTO MINIMO.") return res def profondita(rows: list[dict], fams: list[str], b: Budget) -> None: print("\n" + "=" * 104) print("2b. PROFONDITA' IN CIMA AL BOOK (public/get_order_book depth=5), sulle gambe scelte") print("=" * 104) print(f"{'famiglia':<10} {'gamba':<6} {'n':>3} {'lotti al best':>14} {'$ premio al best':>17} " f"{'ask/tick lunga':>15} {'max|delta venue-BS|':>21}") for fam in fams: gg = gambe(rows, fam)[:4] # max 4 scadenze/famiglia: budget di rete for lato, key in (("corta", "short"), ("lunga", "long")): lots, prem, dd, tk = [], [], [], [] for g in gg: r = g[key] ob = get("get_order_book", {"instrument_name": r["name"], "depth": 5}, b) if not ob: continue side = ob.get("bids") if key == "short" else ob.get("asks") if not side: continue px, sz = float(side[0][0]), float(side[0][1]) lots.append(sz / r["minamt"] if r["minamt"] else float("nan")) prem.append(prem_usd(px, r) * (sz / max(r["minamt"], 1e-12))) if r["tick"]: tk.append(px / r["tick"]) gv = (ob.get("greeks") or {}).get("delta") if gv is not None and np.isfinite(r["delta_bs"]): dd.append(abs(float(gv) - r["delta_bs"])) if not lots: print(f"{fam:<10} {lato:<6} {'0':>3} book vuoto su tutte le scadenze provate") continue print(f"{fam:<10} {lato:<6} {len(lots):>3} {np.median(lots):>14.1f} " f"{np.median(prem):>17.2f} " f"{(np.median(tk) if tk else float('nan')):>15.1f} " f"{(max(dd) if dd else float('nan')):>21.4f}") print("\n `lotti al best` = size in cima al book / lotto minimo: quante strutture minime") print(" entrano senza muovere il prezzo. `ask/tick` sulla gamba LUNGA e' il controllo") print(" d'artefatto del 30/07: un'ala a 1-2 tick e' un prezzo di griglia, non un prezzo.") print(" `max|delta venue-BS|` valida il MIO calcolo del delta contro le greche del venue: se") print(" non e' piccolo, tutta la selezione degli strike qui sopra e' sbagliata.") # ---------------------------------------------------------------- 3. collaterale def collaterale(rows: list[dict], res: dict) -> None: print("\n" + "=" * 104) print("3. IL COLLATERALE — quanto conto serve per UNA struttura minima (conto reale $635)") print("=" * 104) print(f"{'famiglia':<10} {'IM corta+ala $':>15} {'max-loss $':>11} {'IM/conto':>9} " f"{'strutture @635 (IM)':>20} {'(max-loss)':>12}") for fam in res: gg = gambe(rows, fam) ims, mls = [], [] for g in gg: s, lo = g["short"], g["long"] if s["mid"] is None or lo["ask"] is None: continue qty = s["csize"] * s["minamt"] im = im_short_put_usd(s["S"], s["K"], prem_usd(s["mark"], s), qty) ims.append(im + prem_usd(lo["ask"], lo)) # l'ala si PAGA: e' cassa, non margine mls.append(loss_usd(s["K"], lo["K"], s)) if not ims: continue im, ml = float(np.median(ims)), float(np.median(mls)) print(f"{fam:<10} {im:>15.2f} {ml:>11.2f} {im/CAPITAL:>8.1%} " f"{CAPITAL/im:>20.1f} {CAPITAL/ml:>12.1f}") print("\n `IM corta+ala` = margine iniziale della sola put venduta (formula PUBBLICATA dal") print(" venue, FONTE SECONDARIA) + il premio dell'ala, che si paga in contanti. E' il") print(" fabbisogno se il venue NON netta le gambe.") print(" `max-loss` = perdita massima strutturale = il fabbisogno se il venue LE NETTA.") print(" ⚠️ La differenza fra i due numeri e' l'unica cosa importante di questa tabella e NON") print(" E' LEGGIBILE dall'API pubblica: si chiude con `private/get_margins` (lettura, ma") print(" autenticata -> fuori dal perimetro dichiarato di questo file).") def costo_raccolta(tab: dict) -> None: print("\n" + "=" * 104) print("4. COSTO DI RACCOLTA — cosa costerebbe aggiungere una famiglia al giro esistente") print("=" * 104) print(" `collect_chain.py` oggi: ~650 chiamate in ~160s a 4 rps (BTC+ETH inverse), al :25.") print(f"{'famiglia':<10} {'chiamate/giro':>14} {'+s a 4 rps':>11} {'+% sul giro':>12}") for f in LINEAR: t = tab.get(f) if t: n = t["nliq"] + 2 # + get_instruments + get_book_summary print(f"{f:<10} {n:>14.0f} {n/4.0:>11.1f} {n/650*100:>11.0f}%") print("\n ⚠️ Il vincolo non e' la CPU ma il rate limit Deribit PER-IP, gia' costato un guasto") print(" il 29/07 (fallback silenzioso del feed 5m di SKH01). Ogni famiglia aggiunta allunga") print(" la finestra in cui il giro occupa l'IP.") # ---------------------------------------------------------------- main def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--cache", action="store_true", help="riusa lo snapshot su disco (niente rete)") a = ap.parse_args() print("=" * 104) print("ALT-OPT — opzioni USDC-LINEARI su Deribit: c'e' una struttura eseguibile a $635?") print("=" * 104) print("Sola lettura pubblica, nessun ordine. UNO SNAPSHOT: qui non esiste un backtest.") b = Budget() if a.cache and CACHE.exists(): raw = json.loads(CACHE.read_text()) print(f"\n[cache] {CACHE}") else: guardia_finestra() t0 = time.time() raw = fetch_all(b) CACHE.parent.mkdir(parents=True, exist_ok=True) CACHE.write_text(json.dumps(raw)) print(f"\n[rete] {b.calls} chiamate, {b.err} errori, {b.r429} risposte 429, " f"{time.time()-t0:.0f}s") rows = build(raw) print(f"[dato] {len(rows)} strumenti con specifiche E quote — snapshot " f"{datetime.now(UTC):%Y-%m-%d %H:%M} UTC") if not rows: print("NESSUN DATO: il venue non ha risposto. Verdetto: non misurabile.") return 1 tab = famiglie(rows) replica(tab) res = liquidita(rows) vive = [f for f in res if res[f]["due"] >= 2] if a.cache: print("\n2b. PROFONDITA': non girata (--cache non usa la rete).") elif not vive: print("\n2b. PROFONDITA': non girata — nessuna famiglia con >=2 strutture a due lati.") else: guardia_finestra() profondita(rows, vive, b) collaterale(rows, res) costo_raccolta(tab) print("\n" + "=" * 104) print("5. COSA QUESTO FILE NON PUO' DIRE (dichiarato prima di qualunque verdetto)") print("=" * 104) print(" * Non c'e' STORIA: il collettore raccoglie BTC/ETH inverse, l'archivio ereditato pure.") print(" Zero giorni di catena su SOL/XRP/HYPE/AVAX/*_USDC -> nessun backtest, nessun") print(" hold-out, nessun deflated-Sharpe. Il massimo verdetto ottenibile e' LEAD.") print(" * Non c'e' IV-RANK: il gate>0.30 e' l'unico alpha misurato di VRP01 e richiede la") print(" distribuzione storica della vol implicita del sottostante. Senza, la struttura non") print(" e' VRP01: e' vendere vol a caso. (Su BTC/ETH quel gate e' passato 0/19 settimane.)") print(" * Non c'e' STRESS nel campione: la regola 'niente short-vol da modello in deploy' e'") print(" del 19/06 e la condizione dichiarata per rivalutarla e' un crash CATTURATO.") print(" * Il margine e' da FORMULA PUBBLICATA, non dall'API: il netting delle gambe non e'") print(" leggibile pubblicamente.") print(" * E' UN ISTANTE: uno spread relativo mediano misurato a un'ora del sabato non e' la") print(" sua distribuzione. Servirebbe almeno un ciclo settimanale per sapere se e' tipico.") print(f"[rete, totale] {b.calls} chiamate, {b.err} errori, {b.r429} risposte 429") return 0 if __name__ == "__main__": raise SystemExit(main())