research(wave-0822): ORTHO-SCREEN 7/7 scartato (e uno screen largo non puo' passare il proprio DSR); XS-LITE falsifica il muro dei 20k di XS01
This commit is contained in:
@@ -8,6 +8,8 @@ null de-levering superato + eseguibilita' al capitale dichiarato.
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 9 | ADAPTIVE-HORIZON | **SCARTATO** | il "vincitore adattivo" ha lookback incollato al bordo il 100% del tempo = TSMOM costante a 20g (corr 1.000, dSh 0.00 in 8/8 anni e 0/12 ancore); isolando le celle davvero adattive -> NEUTRAL, corr→TP01 0.90 = TP01 travestito || 4 | DEALER-GAMMA | **SCARTATO** | la gamba tradeable e' INCOERENTE (BTC non separa, ETH separa al ROVESCIO); cio' che resta e' quasi tutto DVOL (corr 0.66), gia' refutato il 26/06. DSR 0.440 e la cella migliore sta SOTTO il massimo atteso dal rumore |
|
| 9 | ADAPTIVE-HORIZON | **SCARTATO** | il "vincitore adattivo" ha lookback incollato al bordo il 100% del tempo = TSMOM costante a 20g (corr 1.000, dSh 0.00 in 8/8 anni e 0/12 ancore); isolando le celle davvero adattive -> NEUTRAL, corr→TP01 0.90 = TP01 travestito || 4 | DEALER-GAMMA | **SCARTATO** | la gamba tradeable e' INCOERENTE (BTC non separa, ETH separa al ROVESCIO); cio' che resta e' quasi tutto DVOL (corr 0.66), gia' refutato il 26/06. DSR 0.440 e la cella migliore sta SOTTO il massimo atteso dal rumore |
|
||||||
| 2 | GROWTH-POLICY | **LEAD** (condizione, non data) | il libro gira al **7% di Kelly** e raccoglie il **15%** della crescita massima in log; il gradino eseguibile 1.00x->1.25-1.50x vale 14.7a -> 12.9-11.6a al muro. Ma un solo giorno -10% all'anno porta k* da ~10x a **2x**: non si decide su un conto vero con la lente close-only |
|
| 2 | GROWTH-POLICY | **LEAD** (condizione, non data) | il libro gira al **7% di Kelly** e raccoglie il **15%** della crescita massima in log; il gradino eseguibile 1.00x->1.25-1.50x vale 14.7a -> 12.9-11.6a al muro. Ma un solo giorno -10% all'anno porta k* da ~10x a **2x**: non si decide su un conto vero con la lente close-only |
|
||||||
|
| 12 | ORTHO-SCREEN | **SCARTATO 7/7** | nessuna famiglia arriva a ADDS+DSR; e il motivo e' **aritmetico**: su 168 trial il massimo atteso dal rumore e' Sharpe **1.572**, SOPRA il soffitto direzionale misurato (~1.3) -> uno screen largo su BTC/ETH direzionale **non puo'** passare un DSR, per costruzione |
|
||||||
|
| 3 | XS-LITE | **SCARTATO** (come sleeve) + **1 soglia pubblicata falsificata** | concentrare XS01 non crea uno sleeve nuovo (corr 0.81-0.96 col canonico, DSR FAIL, de-levering non superato) — ma il muro *"XS01 serve ~$20k"* e' misurato su una diagnostica di TURNOVER: il ribilancio vero smette di passare sotto **~$109 di sleeve (~$730 di book), 27x piu' in basso** |
|
||||||
|
|
||||||
## Note che sopravvivono ai singoli filoni
|
## Note che sopravvivono ai singoli filoni
|
||||||
|
|
||||||
@@ -69,3 +71,50 @@ vedono la variabile**. E' per questo che la leva e' l'unica leva del libro mai e
|
|||||||
- 📌 **Sottoprodotto da verificare (tocca un'etichetta del libro live):** a `target_vol=20%` la vol
|
- 📌 **Sottoprodotto da verificare (tocca un'etichetta del libro live):** a `target_vol=20%` la vol
|
||||||
**realizzata** di TP01 e' **12,14%** — il target vale sulla posizione quando c'e', e TP01 e'
|
**realizzata** di TP01 e' **12,14%** — il target vale sulla posizione quando c'e', e TP01 e'
|
||||||
long-flat. **L'etichetta sovrastima il rischio preso di ~40%.**
|
long-flat. **L'etichetta sovrastima il rischio preso di ~40%.**
|
||||||
|
|
||||||
|
### 12 — ORTHO-SCREEN (r0822_ortho_screen.py, 174 trial: 7 famiglie x 24 + 6 controlli)
|
||||||
|
📌 **Il risultato piu' riusabile dell'ondata, ed e' metodologico:** il deflated-Sharpe va calcolato
|
||||||
|
**di screen** (168 trial) e non solo di famiglia (24). Su quel pool il massimo atteso dal puro rumore
|
||||||
|
e' **Sharpe 1.572**, cioe' **sopra il soffitto direzionale misurato del progetto (~1.3)**.
|
||||||
|
**Conseguenza: una ricerca a rete larga su un singolo stream direzionale BTC/ETH non puo' passare il
|
||||||
|
proprio gate — non e' sfortuna, e' aritmetica.** Le ondate future o dichiarano famiglie molto piu'
|
||||||
|
piccole in anticipo, o cambiano meccanismo (non-direzionale / cross-sectional).
|
||||||
|
📌 **Per la prima volta nel progetto l'eseguibilita' a $600 non e' il vincolo binding di niente**
|
||||||
|
(haircut 0.00-0.01 su 7/7): muore tutto molto prima, sull'edge.
|
||||||
|
- Famiglie: RSKEW (skew realizzata), TACC (accelerazione del trend), VPX (volume-prezzo), XDISP
|
||||||
|
(dispersione dei 51 alt come timer), XCORR (corr BTC-ETH), XTAIL (dopo shock 3σ), VRAT
|
||||||
|
(variance-ratio). Miglior DSR di famiglia 0.633, di screen **0.034**. `robust_oos` False 7/7.
|
||||||
|
- **TACC** e' l'unica ADDS (corr→TP01 0.09) ma il suo uplift hold-out **vive tutto nel 2026** (2025
|
||||||
|
da solo −0.314) = finestra fortunata. E la domanda della famiglia ha risposta: **e' il LIVELLO,
|
||||||
|
non l'accelerazione** — la cella scelta si riduce al ritorno a 5 giorni, corr **+0.784** col
|
||||||
|
momentum di livello.
|
||||||
|
- ✅ **Tre falsificazioni che chiudono spazio:** (1) la mean-reversion **non torna in vita** sotto due
|
||||||
|
conditioner mai provati (volume, shock 3σ): la selezione in-sample sceglie il ramo di
|
||||||
|
CONTINUAZIONE in entrambi i casi; (2) la dispersione dei 51 alt come timer di mercato e'
|
||||||
|
**negativa** (−0.899 sulla sola finestra attiva, non e' un artefatto di calendario); (3) RSKEW e'
|
||||||
|
il ritratto del fitting — **miglior in-sample dello screen (1.281) e peggior hold-out (−0.494)**,
|
||||||
|
col segno OPPOSTO all'a-priori teorico dichiarato.
|
||||||
|
- ⚠️ **6ª occorrenza del null del de-levering** (VRAT, maxDD 4.4% -> `k*TP01` fa meglio).
|
||||||
|
- ⚠️ Due candidati hanno l'ancora canonica come **PEGGIORE** delle 8 (TACC, VRAT): la fortuna
|
||||||
|
d'ancora non ha un verso fisso, e guardare solo il canonico a volte **inventa un danno**.
|
||||||
|
|
||||||
|
### 3 — XS-LITE (r0822_xs_lite.py, 26 celle + 120 valutazioni d'ancora)
|
||||||
|
✅ Repliche **bit-exact** prima di ogni delta: XS01 vs `sleeves._xsec_returns` e XSR01 vs
|
||||||
|
`basket_from_positions(demean=True)`, entrambe `max|diff| = 0.0`.
|
||||||
|
📌 **Falsificazione di un numero pubblicato:** il muro *"XS01 serve ~$20k"* non e' un fatto di
|
||||||
|
Sharpe ma di **turnover** — e a capitale piccolo il min-order salta la **deriva del vol-target**
|
||||||
|
(|Δw| giornaliero 0.001) che **non porta segnale**, non il ribilancio (|Δw| 0.091-0.157). Capitale
|
||||||
|
minimo perche' il ribilancio passi: **$109 (k=5) / $86 (k=3) / $64 (k=2)** di sleeve. Stessa lezione
|
||||||
|
gia' imparata su TP01 nel 2026 ("a $600 il min-order e' gia' la banda ottimale") e **mai applicata a
|
||||||
|
XS01**. ⚠️ L'agente ha usato **min-order $10 (Hyperliquid)**, non $5 (Deribit) — un audit dedicato
|
||||||
|
sta verificando i minimi veri del venue.
|
||||||
|
- Concentrare **non** ripara il rischio #1 di XSR01: XS-LITE regge oltre **50 bps/gamba**, XSR-LITE
|
||||||
|
muore a **~28 bps a ogni k, pieno incluso**.
|
||||||
|
- La radice dell'ampiezza **non descrive** XS01: da 10 a 4 gambe si perde il **2%** di Sharpe
|
||||||
|
mediano-di-fase mentre N_hhi passa 6.9 -> 3.0 (il segnale sta negli **estremi** del ranking; le
|
||||||
|
gambe 3-5 per lato aggiungono rischio quanto segnale). Il collasso arriva solo a k=1 (41%).
|
||||||
|
- ⚠️ **Da inseguire — tocca un gate pre-registrato: lo Sharpe 1.82 di XSR01 NON si riproduce oggi.**
|
||||||
|
Sulla finestra identica a quella di scoperta la lente "paniere" da' **1.75** e la lente "libro" di
|
||||||
|
`paper_xsr` da' **2.23**; 1.82 non e' nessuna delle due. Spiegazione piu' probabile: `data/raw` e'
|
||||||
|
gitignored e il cron riscrive i parquet HL ogni notte -> **stesso codice, dati diversi** (identico
|
||||||
|
allo scoperto del 07/08 su GTAA/TLT). **La decisione del 23/10 poggia su quel numero.**
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ def sezione2(snap: pd.DataFrame) -> pd.DataFrame:
|
|||||||
g["p_x24"] = [bboot_p(d[d.odec == k].x24.values, block=48) for k in g.index]
|
g["p_x24"] = [bboot_p(d[d.odec == k].x24.values, block=48) for k in g.index]
|
||||||
print(g.round(3).to_string())
|
print(g.round(3).to_string())
|
||||||
print(" av4/av24 = |ret| futuro medio: e' la gamba 'squeeze/cascata' dell'ipotesi")
|
print(" av4/av24 = |ret| futuro medio: e' la gamba 'squeeze/cascata' dell'ipotesi")
|
||||||
print(" (piu' vol dopo un estremo di OI). E' QUASI PIATTA (0.59-0.75%% a 4h, solo il decile 0")
|
print(" (piu' vol dopo un estremo di OI). E' QUASI PIATTA (0.59-0.75% a 4h, solo il decile 0")
|
||||||
print(" leggermente sopra): la 'cascata' prevedibile non c'e'.")
|
print(" leggermente sopra): la 'cascata' prevedibile non c'e'.")
|
||||||
|
|
||||||
print("\n--- CONTROLLO: e' solo 'il prezzo si e' appena mosso'? ---")
|
print("\n--- CONTROLLO: e' solo 'il prezzo si e' appena mosso'? ---")
|
||||||
|
|||||||
@@ -453,9 +453,10 @@ def main() -> None:
|
|||||||
# ---------------------------------------------------------------- 4. NULL LOCATION-MATCHED
|
# ---------------------------------------------------------------- 4. NULL LOCATION-MATCHED
|
||||||
P("\n[4] NULL LOCATION-MATCHED (regola 02/07: e' la POSIZIONE o e' l'OI?)")
|
P("\n[4] NULL LOCATION-MATCHED (regola 02/07: e' la POSIZIONE o e' l'OI?)")
|
||||||
P(" Confronto APPAIATO per evento: tw(livello speciale) - tw(placebo alla stessa distanza).")
|
P(" Confronto APPAIATO per evento: tw(livello speciale) - tw(placebo alla stessa distanza).")
|
||||||
P(" placebo: rand=strike uniforme (== permutazione dell'OI, equivalenza esatta) · adj=strike")
|
P(" placebo PER REGOLA: adj_r = strike adiacente a K_r · jit_r = strike arbitrario a")
|
||||||
P(" adiacente al max-OI · jit=strike arbitrario a distanza 0.5-1.5x (analogo Fib±jitter) ·")
|
P(" distanza 0.5-1.5x |K_r - S| (analogo del Fib±jitter del 02/07).")
|
||||||
P(" mid=centro della griglia quotata (zero info OI) · mr7=media 7g dello spot (mean-reversion).")
|
P(" placebo GLOBALI: rand = strike uniforme (== permutazione dell'OI, equivalenza esatta) ·")
|
||||||
|
P(" mid = centro della griglia quotata (zero info OI) · mr7 = media 7g dello spot.")
|
||||||
P(f" {'hte':>4} {'rule':>5} {'Δ vs adj_r':>12} {'Δ vs jit_r':>12}"
|
P(f" {'hte':>4} {'rule':>5} {'Δ vs adj_r':>12} {'Δ vs jit_r':>12}"
|
||||||
f" {'Δ vs rand':>12} {'Δ vs mid':>12} {'Δ vs mr7':>12}")
|
f" {'Δ vs rand':>12} {'Δ vs mid':>12} {'Δ vs mr7':>12}")
|
||||||
npos = ntot = 0
|
npos = ntot = 0
|
||||||
@@ -518,7 +519,7 @@ def main() -> None:
|
|||||||
P("\n [6-bis] LA STESSA MACCHINA SUI LIVELLI PLACEBO (stesse finestre, stessa fee, stesso")
|
P("\n [6-bis] LA STESSA MACCHINA SUI LIVELLI PLACEBO (stesse finestre, stessa fee, stesso")
|
||||||
P(" sizing): se un placebo regge quanto il livello 'speciale', l'OI non aggiunge nulla.")
|
P(" sizing): se un placebo regge quanto il livello 'speciale', l'OI non aggiunge nulla.")
|
||||||
nulls = []
|
nulls = []
|
||||||
for rl in ("mp", "oi", "mid", "mr7", "rand", "jit", "maj", "short", "long"):
|
for rl in ("mp", "oi", "mid", "mr7", "rand", "jit_mp", "maj", "short", "long"):
|
||||||
for hte in (3, 6, 12, 24):
|
for hte in (3, 6, 12, 24):
|
||||||
for bn, bd in bands.items():
|
for bn, bd in bands.items():
|
||||||
d, _i = strat_daily(ev, rl, hte, bd, "sign", "all", FEE_SIDE_REAL)
|
d, _i = strat_daily(ev, rl, hte, bd, "sign", "all", FEE_SIDE_REAL)
|
||||||
@@ -527,7 +528,7 @@ def main() -> None:
|
|||||||
cagr=mm["cagr"], dd=mm["dd"]))
|
cagr=mm["cagr"], dd=mm["dd"]))
|
||||||
N = pd.DataFrame(nulls)
|
N = pd.DataFrame(nulls)
|
||||||
piv = N.pivot_table(index=["hte", "band"], columns="rule", values="sharpe")
|
piv = N.pivot_table(index=["hte", "band"], columns="rule", values="sharpe")
|
||||||
P(piv.reindex(columns=["mp", "oi", "mid", "mr7", "rand", "jit", "maj", "short", "long"])
|
P(piv.reindex(columns=["mp", "oi", "mid", "mr7", "rand", "jit_mp", "maj", "short", "long"])
|
||||||
.to_string(float_format=lambda v: f"{v:6.2f}"))
|
.to_string(float_format=lambda v: f"{v:6.2f}"))
|
||||||
P(f" celle placebo valutate: {len(N)} (contano come trial: la griglia dichiarata sale)")
|
P(f" celle placebo valutate: {len(N)} (contano come trial: la griglia dichiarata sale)")
|
||||||
|
|
||||||
|
|||||||
@@ -360,7 +360,10 @@ def sezione2(curve: pd.DataFrame) -> dict:
|
|||||||
|
|
||||||
print("\n (c) IL CONFOUND DI QUESTO FILONE — la pendenza e' informazione NUOVA o RV riciclata?")
|
print("\n (c) IL CONFOUND DI QUESTO FILONE — la pendenza e' informazione NUOVA o RV riciclata?")
|
||||||
rvp = (r1.rolling(24).std() * np.sqrt(24 * 365) * 100).reindex(idx)
|
rvp = (r1.rolling(24).std() * np.sqrt(24 * 365) * 100).reindex(idx)
|
||||||
rvf = (r1.shift(-24).rolling(24).std().shift(-23) * np.sqrt(24 * 365) * 100).reindex(idx)
|
# RV su (t, t+24h]: rolling(24) etichettata a t+24 e riportata indietro a t. (Una prima
|
||||||
|
# stesura aveva uno shift di troppo e misurava la finestra (+24h, +47h): corretto in
|
||||||
|
# sessione confrontando con una seconda implementazione a serie rovesciata.)
|
||||||
|
rvf = (r1.rolling(24).std().shift(-24) * np.sqrt(24 * 365) * 100).reindex(idx)
|
||||||
cf = curve[curve.asset == a].copy()
|
cf = curve[curve.asset == a].copy()
|
||||||
cf["hr"] = pd.to_datetime(cf["hr"], utc=True).dt.as_unit("ns")
|
cf["hr"] = pd.to_datetime(cf["hr"], utc=True).dt.as_unit("ns")
|
||||||
ivf = cf.set_index("hr")[f"iv_{FRONT}"].reindex(idx)
|
ivf = cf.set_index("hr")[f"iv_{FRONT}"].reindex(idx)
|
||||||
@@ -563,9 +566,14 @@ def sezione3(chain: pd.DataFrame, atm_exp: pd.DataFrame, curve: pd.DataFrame) ->
|
|||||||
f"({prem/CAPITALE:.0%} del conto), vega ${vega:.2f}/pt-vol, fee ${fee:.2f}/gamba")
|
f"({prem/CAPITALE:.0%} del conto), vega ${vega:.2f}/pt-vol, fee ${fee:.2f}/gamba")
|
||||||
print(f" carry lordo ${carry_g:+.3f}/giorno per struttura; attrito per giro "
|
print(f" carry lordo ${carry_g:+.3f}/giorno per struttura; attrito per giro "
|
||||||
f"${friz:.2f} => {friz/carry_g:.0f} giorni per andare in pari")
|
f"${friz:.2f} => {friz/carry_g:.0f} giorni per andare in pari")
|
||||||
print(f"\n Un calendar spread e' DUE gambe: a $635 una sola struttura ETH impegna il")
|
print("\n Un calendar spread e' DUE gambe. Cio' che la tabella mostra e' il PREMIO di UNA")
|
||||||
print(f" ~15-30% del conto e rende centesimi al giorno. BTC e' fuori dal lotto minimo.")
|
print(" gamba al lotto minimo: BTC 26% del conto, ETH 10%. Il premio non e' tutto il")
|
||||||
print(f" Il bersaglio dichiarato e' 50 EUR/giorno: qui si parla di due ordini di grandezza sotto.")
|
print(" fabbisogno — la gamba CORTA vuole margine, e la misura del 2026-07-30 su una")
|
||||||
|
print(" struttura BTC a rischio definito dava $6.210 di collaterale per lotto. Quindi:")
|
||||||
|
print(" BTC resta fuori per il margine, ETH entra ma una sola struttura impegna il")
|
||||||
|
print(" 10-25% del conto per un carry LORDO di centesimi al giorno.")
|
||||||
|
print(" Il bersaglio dichiarato e' 50 EUR/giorno: qui siamo 2-3 ordini di grandezza sotto,")
|
||||||
|
print(" e il conto non regge la SECONDA struttura che servirebbe per diversificare.")
|
||||||
TRIALS.append(("Q2: 2 asset x eseguibilita' al lotto minimo", 2))
|
TRIALS.append(("Q2: 2 asset x eseguibilita' al lotto minimo", 2))
|
||||||
|
|
||||||
|
|
||||||
@@ -671,17 +679,31 @@ def sezione4(curve: pd.DataFrame) -> None:
|
|||||||
hold = tgt.shift(1).fillna(0.0)
|
hold = tgt.shift(1).fillna(0.0)
|
||||||
net = (hold * d["r"] - A.FEE_SIDE * hold.diff().abs().fillna(0.0)).dropna()
|
net = (hold * d["r"] - A.FEE_SIDE * hold.diff().abs().fillna(0.0)).dropna()
|
||||||
dd_c = A._dd_ret(net)
|
dd_c = A._dd_ret(net)
|
||||||
|
# ⚠️ il k giusto e' il PIU' GRANDE che sta sotto il DD del candidato, non il primo che
|
||||||
|
# trovi salendo da 0.05: partendo dal basso si confronta il candidato con un baseline
|
||||||
|
# quasi spento, che ha un DD ridicolo e uno Sharpe gonfiato dal rapporto. (Errore
|
||||||
|
# commesso e corretto in sessione: dava "candidato sopra il null" con k=0.05.)
|
||||||
|
ks = np.arange(0.05, 3.01, 0.05)
|
||||||
best = None
|
best = None
|
||||||
for k in np.arange(0.05, 1.01, 0.05):
|
for k in ks[::-1]:
|
||||||
b = k * d["r"].reindex(net.index)
|
b = k * d["r"].reindex(net.index)
|
||||||
if A._dd_ret(b) <= dd_c:
|
if A._dd_ret(b) <= dd_c:
|
||||||
best = (k, A._sh(b), A._dd_ret(b))
|
best = (float(k), A._sh(b), A._dd_ret(b))
|
||||||
break
|
break
|
||||||
print(f" {a}: candidato Sharpe {A._sh(net):+.2f} maxDD {dd_c:.2%} | "
|
sh_c = A._sh(net)
|
||||||
+ (f"buy&hold de-leverato k={best[0]:.2f} -> stesso DD ({best[2]:.2%}) con Sharpe "
|
if best is None:
|
||||||
f"{best[1]:+.2f} => {'IL CANDIDATO NON SOPRAVVIVE' if best[1] >= A._sh(net) else 'candidato sopra il null'}"
|
print(f" {a}: candidato Sharpe {sh_c:+.2f} maxDD {dd_c:.2%} | nessun k in "
|
||||||
if best else "nessun k<=1 raggiunge quel DD"))
|
f"[0.05,3.00] raggiunge quel DD")
|
||||||
TRIALS.append((f"Q3 {a}: 20 valori di k nel null de-levering", 20))
|
else:
|
||||||
|
verdict = ("IL CANDIDATO NON SOPRAVVIVE (il de-levering fa meglio)"
|
||||||
|
if best[1] >= sh_c else "candidato sopra il null di de-levering")
|
||||||
|
print(f" {a}: candidato Sharpe {sh_c:+.2f} maxDD {dd_c:.2%} | buy&hold a leva "
|
||||||
|
f"k={best[0]:.2f} -> stesso o minor DD ({best[2]:.2%}) con Sharpe {best[1]:+.2f}"
|
||||||
|
f" => {verdict}")
|
||||||
|
imp = A.implausible_sharpe(net)
|
||||||
|
print(f" implausible_sharpe sul candidato di finestra: implausible="
|
||||||
|
f"{imp['implausible']} {imp['reasons']}")
|
||||||
|
TRIALS.append((f"Q3 {a}: 60 valori di k nel null de-levering", 60))
|
||||||
|
|
||||||
|
|
||||||
# ===========================================================================================
|
# ===========================================================================================
|
||||||
@@ -745,15 +767,24 @@ def sezione5(curve: pd.DataFrame) -> None:
|
|||||||
if k in rep:
|
if k in rep:
|
||||||
print(f" {k:20s} = {rep[k]}")
|
print(f" {k:20s} = {rep[k]}")
|
||||||
imp = A.implausible_sharpe(era)
|
imp = A.implausible_sharpe(era)
|
||||||
print(f" implausible_sharpe: flagged={imp.get('flagged')} ({imp.get('reasons')})")
|
print(f" implausible_sharpe (proxy, era DVOL): implausible={imp['implausible']} "
|
||||||
|
f"{imp['reasons']}")
|
||||||
|
print(f" earns_slot = (assoluto non-FAIL) AND (marginale ADDS): qui il marginale e' "
|
||||||
|
f"{rep.get('marginal_verdict')} -> **earns_slot = False**.")
|
||||||
TRIALS.append(("Sez.5: 2 varianti proxy (long-only, L/S) x 1 soglia", 2))
|
TRIALS.append(("Sez.5: 2 varianti proxy (long-only, L/S) x 1 soglia", 2))
|
||||||
|
|
||||||
sub("(c) il precedente che questo replica")
|
sub("(c) il precedente che questo replica")
|
||||||
print(" `dvol_directional.py` (2026-06-29) testo' VRP-Z = z-score causale di (IV-RV) come")
|
print(" `dvol_directional.py` (2026-06-29) testo' VRP-Z = z-score causale di (IV-RV) come")
|
||||||
print(" segnale DIREZIONALE su 5 anni, con la griglia completa: verdetto **HEDGE,")
|
print(" segnale DIREZIONALE su 5 anni, con la griglia completa: verdetto **HEDGE,")
|
||||||
print(" earns_slot=False** — paga solo quando TP01 e' debole, quindi non e' alpha.")
|
print(" earns_slot=False**. Qui, con la variante a SOGLIA BINARIA invece che a z-score,")
|
||||||
print(" La pendenza della term structure e', su questa lente, la stessa variabile con la")
|
print(" il verdetto misurato e' NEUTRAL con uplift NEGATIVO — un verdetto diverso, la")
|
||||||
print(" gamba realizzata sostituita da una implicita. Il filone non e' nuovo: e' quello.")
|
print(" stessa conclusione (earns_slot=False in entrambi). La differenza sta nella")
|
||||||
|
print(" variante, non nell'esito, e va riportata cosi': non sto dichiarando una replica")
|
||||||
|
print(" che non ho fatto.")
|
||||||
|
print(" Il punto strutturale resta: la pendenza e' il premio di vol con la gamba")
|
||||||
|
print(" REALIZZATA sostituita da una IMPLICITA (SEZIONE 2c: corr(pendenza, RV passata)")
|
||||||
|
print(" = -0.50/-0.57). Non e' una variabile nuova per questo progetto: e' quella, con")
|
||||||
|
print(" un rumore di misura piu' basso e 5 anni di storia in meno.")
|
||||||
|
|
||||||
|
|
||||||
# ===========================================================================================
|
# ===========================================================================================
|
||||||
@@ -778,7 +809,6 @@ def sezione6() -> None:
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
hr("r0822_term_structure — TERM STRUCTURE DELLA VOL IMPLICITA BTC/ETH")
|
hr("r0822_term_structure — TERM STRUCTURE DELLA VOL IMPLICITA BTC/ETH")
|
||||||
print(__doc__.split("METODO.")[0].strip()[:0] or "", end="")
|
|
||||||
chain = load_quoted_chain()
|
chain = load_quoted_chain()
|
||||||
sezione0(chain)
|
sezione0(chain)
|
||||||
atm_exp = build_atm_by_expiry(chain)
|
atm_exp = build_atm_by_expiry(chain)
|
||||||
|
|||||||
@@ -303,6 +303,20 @@ def sizes_from_L(ex: dict, L: pd.Series) -> np.ndarray:
|
|||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- libro
|
# --------------------------------------------------------------------------- libro
|
||||||
|
def sizes_of(nm, ex: dict, SZ: dict, VTL: dict, ACT: dict, Lbook: pd.Series | None = None):
|
||||||
|
"""Vettore di size per-trade di una cella qualsiasi. Un solo posto in cui e' definita:
|
||||||
|
§8 (eseguibilita'), §9 (deriva) e §10 (null di permutazione) devono usare LA STESSA."""
|
||||||
|
if nm is None or nm == "BASE":
|
||||||
|
return size_flat(ex)
|
||||||
|
if nm in SZ:
|
||||||
|
return SZ[nm](ex)
|
||||||
|
if nm in VTL:
|
||||||
|
return sizes_from_L(ex, leverage_series(ex["base_daily"], **VTL[nm]))
|
||||||
|
if nm in ACT:
|
||||||
|
return sizes_from_L(ex, activity_L(ex["base_daily"], **ACT[nm]))
|
||||||
|
return sizes_from_L(ex, Lbook)
|
||||||
|
|
||||||
|
|
||||||
def book(tp: pd.Series, skh: pd.Series) -> pd.Series:
|
def book(tp: pd.Series, skh: pd.Series) -> pd.Series:
|
||||||
return combine_outer({"TP01": tp, "SKH01": skh}, {"TP01": W_TP, "SKH01": W_SKH})
|
return combine_outer({"TP01": tp, "SKH01": skh}, {"TP01": W_TP, "SKH01": W_SKH})
|
||||||
|
|
||||||
@@ -498,7 +512,8 @@ def main() -> None:
|
|||||||
print(" de-levering (k<1 sul BASELINE che pareggia il maxDD della variante)")
|
print(" de-levering (k<1 sul BASELINE che pareggia il maxDD della variante)")
|
||||||
print("-" * 112)
|
print("-" * 112)
|
||||||
print(f" {'variante':<28}{'wSKH eff':>9}{'dShFULL':>9}{'pos/n':>8}{'dShHOLD':>9}{'pos/n':>8}"
|
print(f" {'variante':<28}{'wSKH eff':>9}{'dShFULL':>9}{'pos/n':>8}{'dShHOLD':>9}{'pos/n':>8}"
|
||||||
f"{'| ISO dF':>10}{'pos/n':>8}{'ISO dH':>9}{'pos/n':>8}{'dDDpp':>8}{'k_iso':>8}")
|
f"{'| ISO dF':>10}{'pos/n':>8}{'ISO dH':>9}{'pos/n':>8}{'dDDpp':>8}{'k_iso':>8}"
|
||||||
|
f"{'null de-lev':>14}")
|
||||||
base_b = BK["BASE"]
|
base_b = BK["BASE"]
|
||||||
RES = {}
|
RES = {}
|
||||||
for nm in ALL:
|
for nm in ALL:
|
||||||
@@ -525,7 +540,13 @@ def main() -> None:
|
|||||||
print(f" {nm:<28}{we:>9.3f}{dF['median_paired']:>+9.3f}{dF['n_positive']:>5}/{len(offs):<3}"
|
print(f" {nm:<28}{we:>9.3f}{dF['median_paired']:>+9.3f}{dF['n_positive']:>5}/{len(offs):<3}"
|
||||||
f"{dH['median_paired']:>+9.3f}{dH['n_positive']:>5}/{len(offs):<3}"
|
f"{dH['median_paired']:>+9.3f}{dH['n_positive']:>5}/{len(offs):<3}"
|
||||||
f"{iF['median_paired']:>+10.3f}{iF['n_positive']:>5}/{len(offs):<3}"
|
f"{iF['median_paired']:>+10.3f}{iF['n_positive']:>5}/{len(offs):<3}"
|
||||||
f"{iH['median_paired']:>+9.3f}{iH['n_positive']:>5}/{len(offs):<3}{dd:>+8.2f}{ks:>8}")
|
f"{iH['median_paired']:>+9.3f}{iH['n_positive']:>5}/{len(offs):<3}{dd:>+8.2f}{ks:>8}"
|
||||||
|
f"{vd:>14}")
|
||||||
|
print(" ⚠️ NOTA sul null del de-levering: `sh(k*base)` e' IDENTICO a `sh(base)` perche' lo")
|
||||||
|
print(" Sharpe e' invariante a una costante -> in questa forma il null COINCIDE col confronto")
|
||||||
|
print(" degli Sharpe, ed e' per questo che qui lo Sharpe e' la metrica che decide e il DD no.")
|
||||||
|
print(" 'k_iso' resta come diagnostica: quanta leva dovrebbe cedere il baseline per pareggiare")
|
||||||
|
print(" il maxDD della variante. 'DE-LEVERING' = la variante NON batte quel baseline ridotto.")
|
||||||
print(" wSKH eff = peso EFFETTIVO di SKH nel libro (i nominali restano 75/25: la size lo")
|
print(" wSKH eff = peso EFFETTIVO di SKH nel libro (i nominali restano 75/25: la size lo")
|
||||||
print(" muove). Colonne 'ISO' = confronto vs il baseline RI-SCALATO a quello stesso peso:")
|
print(" muove). Colonne 'ISO' = confronto vs il baseline RI-SCALATO a quello stesso peso:")
|
||||||
print(" e' li' che si legge la FORMA. Le colonne non-ISO contengono anche il cambio di peso.")
|
print(" e' li' che si legge la FORMA. Le colonne non-ISO contengono anche il cambio di peso.")
|
||||||
@@ -687,24 +708,10 @@ def main() -> None:
|
|||||||
f" anni positivi {npos}/{len(yrs)}")
|
f" anni positivi {npos}/{len(yrs)}")
|
||||||
print()
|
print()
|
||||||
for nm in top:
|
for nm in top:
|
||||||
if nm in SZ:
|
Lb = (leverage_series(BK["BASE"][can], BVT[nm]["tv"], BVT[nm]["w"], BVT[nm]["cap"])
|
||||||
szs = np.concatenate([SZ[nm](EX[can][a]) for a in ASSETS])
|
if nm in BVT else None)
|
||||||
|
szs = np.concatenate([sizes_of(nm, EX[can][a], SZ, VTL, ACT, Lb) for a in ASSETS])
|
||||||
dys = pd.DatetimeIndex(np.concatenate([EX[can][a]["day_ent"].values for a in ASSETS]))
|
dys = pd.DatetimeIndex(np.concatenate([EX[can][a]["day_ent"].values for a in ASSETS]))
|
||||||
elif nm in VTL or nm in ACT:
|
|
||||||
mk = ((lambda b: leverage_series(b, **VTL[nm])) if nm in VTL
|
|
||||||
else (lambda b: activity_L(b, **ACT[nm])))
|
|
||||||
szs, dys = [], []
|
|
||||||
for a in ASSETS:
|
|
||||||
szs.append(sizes_from_L(EX[can][a], mk(EX[can][a]["base_daily"])))
|
|
||||||
dys.append(EX[can][a]["day_ent"].values)
|
|
||||||
szs = np.concatenate(szs); dys = pd.DatetimeIndex(np.concatenate(dys))
|
|
||||||
else:
|
|
||||||
L = leverage_series(BK["BASE"][can], BVT[nm]["tv"], BVT[nm]["w"], BVT[nm]["cap"])
|
|
||||||
szs, dys = [], []
|
|
||||||
for a in ASSETS:
|
|
||||||
szs.append(sizes_from_L(EX[can][a], L))
|
|
||||||
dys.append(EX[can][a]["day_ent"].values)
|
|
||||||
szs = np.concatenate(szs); dys = pd.DatetimeIndex(np.concatenate(dys))
|
|
||||||
s = pd.Series(szs, index=dys)
|
s = pd.Series(szs, index=dys)
|
||||||
med = s.groupby(s.index.year).median()
|
med = s.groupby(s.index.year).median()
|
||||||
rho = float(np.corrcoef(np.arange(len(med)), med.values)[0, 1]) if len(med) > 2 else float("nan")
|
rho = float(np.corrcoef(np.arange(len(med)), med.values)[0, 1]) if len(med) > 2 else float("nan")
|
||||||
@@ -715,6 +722,33 @@ def main() -> None:
|
|||||||
print(" (la vol crypto e' scesa lungo il campione -> qualunque 1/vol pesa di piu' il")
|
print(" (la vol crypto e' scesa lungo il campione -> qualunque 1/vol pesa di piu' il")
|
||||||
print(" periodo recente, che e' anche l'hold-out). La riga 'corr col tempo' la misura.")
|
print(" periodo recente, che e' anche l'hold-out). La riga 'corr col tempo' la misura.")
|
||||||
|
|
||||||
|
# noqa
|
||||||
|
print("\n" + "-" * 112)
|
||||||
|
print(" 10. NULL DI PERMUTAZIONE DELLA SIZE — la stessa MULTINSIEME di size, riassegnata a")
|
||||||
|
print(" caso ai trade. Se il vantaggio a iso-peso sopravvive al null, conta QUALE trade")
|
||||||
|
print(" riceve quale size (informazione); se no, e' solo la DISTRIBUZIONE delle size.")
|
||||||
|
print("-" * 112)
|
||||||
|
rng = np.random.default_rng(20260822)
|
||||||
|
a10 = list(offs[:: max(1, len(offs) // 3)])[:3]
|
||||||
|
NDRAW = 150
|
||||||
|
for nm in dict.fromkeys([best_iso, best_sleeve]):
|
||||||
|
real = float(np.median([sh(BK[nm][o]) - sh(CTRL[nm][o]) for o in a10]))
|
||||||
|
nul = []
|
||||||
|
for _ in range(NDRAW):
|
||||||
|
v = []
|
||||||
|
for o in a10:
|
||||||
|
szp = {a: rng.permutation(sizes_of(nm, EX[o][a], SZ, VTL, ACT)) for a in ASSETS}
|
||||||
|
lg = leg_daily(EX[o], szp)
|
||||||
|
m_s = vol(lg) / vol(SLE["BASE"][o]) if vol(SLE["BASE"][o]) > 0 else 1.0
|
||||||
|
v.append(sh(book(TP, lg)) - sh(book(TP, SLE["BASE"][o] * m_s)))
|
||||||
|
nul.append(float(np.median(v)))
|
||||||
|
nul = np.asarray(nul)
|
||||||
|
pc = float((nul < real).mean()) * 100
|
||||||
|
print(f" {nm:<26} reale {real:+.3f} null mediana {np.median(nul):+.3f} "
|
||||||
|
f"p90 {np.percentile(nul, 90):+.3f} max {nul.max():+.3f} "
|
||||||
|
f"-> percentile {pc:.1f} (p ~ {(1 - pc / 100):.3f})")
|
||||||
|
print(f" {NDRAW} permutazioni x {len(a10)} ancore {a10}; seme fisso 20260822.")
|
||||||
|
|
||||||
print("\n" + "=" * 112)
|
print("\n" + "=" * 112)
|
||||||
print(f" fatto in {time.time()-t0:.0f}s")
|
print(f" fatto in {time.time()-t0:.0f}s")
|
||||||
print("=" * 112)
|
print("=" * 112)
|
||||||
@@ -728,19 +762,13 @@ def netted_target(asset: str, ex: dict, nm, SZ, VTL, ACT, BVT, SLE, TP, can, df1
|
|||||||
ts1 = df1h["timestamp"].values.astype(np.int64) + 3_600_000
|
ts1 = df1h["timestamp"].values.astype(np.int64) + 3_600_000
|
||||||
pos = np.zeros(len(ts1))
|
pos = np.zeros(len(ts1))
|
||||||
L1h = np.ones(len(ts1))
|
L1h = np.ones(len(ts1))
|
||||||
if nm is None:
|
if nm is not None and nm in BVT: # BOOKVT: leva anche sulla gamba TP01
|
||||||
sizes = size_flat(ex)
|
|
||||||
elif nm in SZ:
|
|
||||||
sizes = SZ[nm](ex)
|
|
||||||
elif nm in VTL:
|
|
||||||
sizes = sizes_from_L(ex, leverage_series(ex["base_daily"], **VTL[nm]))
|
|
||||||
elif nm in ACT:
|
|
||||||
sizes = sizes_from_L(ex, activity_L(ex["base_daily"], **ACT[nm]))
|
|
||||||
else: # BOOKVT
|
|
||||||
L = leverage_series(book(TP, SLE["BASE"][can]), BVT[nm]["tv"], BVT[nm]["w"], BVT[nm]["cap"])
|
L = leverage_series(book(TP, SLE["BASE"][can]), BVT[nm]["tv"], BVT[nm]["w"], BVT[nm]["cap"])
|
||||||
sizes = sizes_from_L(ex, L)
|
sizes = sizes_of(nm, ex, SZ, VTL, ACT, L)
|
||||||
idx1h = pd.DatetimeIndex(pd.to_datetime(df1h["timestamp"].values, unit="ms", utc=True))
|
idx1h = pd.DatetimeIndex(pd.to_datetime(df1h["timestamp"].values, unit="ms", utc=True))
|
||||||
L1h = L.reindex(idx1h.floor("D")).ffill().fillna(1.0).values
|
L1h = L.reindex(idx1h.floor("D")).ffill().fillna(1.0).values
|
||||||
|
else:
|
||||||
|
sizes = sizes_of(nm, ex, SZ, VTL, ACT)
|
||||||
t_in, t_out = ex["ts_close"][ex["i_ent"]], ex["ts_close"][ex["i_ex"]]
|
t_in, t_out = ex["ts_close"][ex["i_ent"]], ex["ts_close"][ex["i_ex"]]
|
||||||
for k in range(len(t_in)):
|
for k in range(len(t_in)):
|
||||||
j0 = int(np.searchsorted(ts1, t_in[k], side="left"))
|
j0 = int(np.searchsorted(ts1, t_in[k], side="left"))
|
||||||
|
|||||||
@@ -382,13 +382,19 @@ def main() -> None:
|
|||||||
thr = float(np.quantile(vals[:-1], 0.30))
|
thr = float(np.quantile(vals[:-1], 0.30))
|
||||||
last_open = ser[ser > 0.30]
|
last_open = ser[ser > 0.30]
|
||||||
since = (V.index[-1] - last_open.index[-1]).days if len(last_open) else None
|
since = (V.index[-1] - last_open.index[-1]).days if len(last_open) else None
|
||||||
|
inwin = ser[(ser.index >= puts["ts"].min()) & (ser.index <= puts["ts"].max())]
|
||||||
|
near = inwin.max() if len(inwin) else float("nan")
|
||||||
print(f" {a}: quota di giorni col gate APERTO per anno — "
|
print(f" {a}: quota di giorni col gate APERTO per anno — "
|
||||||
+ " ".join(f"{y}:{v:.0%}" for y, v in per_year.items()))
|
+ " ".join(f"{y}:{v:.0%}" for y, v in per_year.items()))
|
||||||
print(f" DVOL oggi {vals[-1]:.1f} · serve DVOL > {thr:.1f} "
|
print(f" DVOL oggi {vals[-1]:.1f} · serve DVOL > {thr:.1f} "
|
||||||
f"(+{thr / vals[-1] - 1:.0%}) per riaprire il gate · ultimo giorno aperto "
|
f"(+{thr / vals[-1] - 1:.0%}) per riaprire il gate · ultimo giorno aperto "
|
||||||
f"{last_open.index[-1]:%Y-%m-%d} ({since} giorni fa)")
|
f"{last_open.index[-1]:%Y-%m-%d} ({since} giorni fa)")
|
||||||
|
print(f" quanto vicino c'e' andato DENTRO la finestra: IV-rank max "
|
||||||
|
f"{near:.4f} il {inwin.idxmax():%Y-%m-%d} — "
|
||||||
|
f"{'mancato per ' + format(0.30 - near, '.4f') if near <= 0.30 else 'aperto'}")
|
||||||
print(" → il campione non e' 'sfortunato': cade dentro un regime di vol bassa lungo e\n"
|
print(" → il campione non e' 'sfortunato': cade dentro un regime di vol bassa lungo e\n"
|
||||||
" persistente. La misura giusta si potra' rifare quando quel numero sara' superato,\n"
|
" persistente. Ma il margine NON e' comodo: il gate ha sfiorato l'apertura, e\n"
|
||||||
|
" bastano ~+10% di DVOL per riaprirlo. La misura giusta si potra' rifare quando quel numero sara' superato,\n"
|
||||||
" e da allora servira' comunque un anno di settimane per avere un campione.")
|
" e da allora servira' comunque un anno di settimane per avere un campione.")
|
||||||
|
|
||||||
ret = {a: (canon[a]["ST"].iloc[-1] / canon[a]["spot"].iloc[0] - 1.0) for a in ASSETS}
|
ret = {a: (canon[a]["ST"].iloc[-1] / canon[a]["spot"].iloc[0] - 1.0) for a in ASSETS}
|
||||||
@@ -668,6 +674,23 @@ def main() -> None:
|
|||||||
f"MEDIANA ONESTA {band['median']:.2f} · banda [{band['lo']:.2f}, {band['hi']:.2f}] · "
|
f"MEDIANA ONESTA {band['median']:.2f} · banda [{band['lo']:.2f}, {band['hi']:.2f}] · "
|
||||||
f"positiva in {band['frac_positive']:.0%} di {band['n_anchors']} ancore · "
|
f"positiva in {band['frac_positive']:.0%} di {band['n_anchors']} ancore · "
|
||||||
f"fortuna {band['luck']:+.2f}")
|
f"fortuna {band['luck']:+.2f}")
|
||||||
|
# DOVE vive l'instabilita': nel numeratore (il guadagno) o nel denominatore (la vol)?
|
||||||
|
det = []
|
||||||
|
for o in offsets:
|
||||||
|
w = by_off(o)
|
||||||
|
if len(w) > 2 and w.std(ddof=1) > 0:
|
||||||
|
det.append((o, float(w.mean()), float(w.std(ddof=1)), len(w)))
|
||||||
|
if det:
|
||||||
|
mm = np.array([d[1] for d in det])
|
||||||
|
ss = np.array([d[2] for d in det])
|
||||||
|
print(f" media settimanale fra le ancore: [{mm.min():+.2%}, {mm.max():+.2%}] "
|
||||||
|
f"(rapporto {mm.max() / max(mm.min(), 1e-9):.1f}x) · "
|
||||||
|
f"deviazione standard: [{ss.min():.2%}, {ss.max():.2%}] "
|
||||||
|
f"(rapporto {ss.max() / max(ss.min(), 1e-9):.1f}x)")
|
||||||
|
print(f" → l'ancora NON cambia quanto si guadagna, cambia il DENOMINATORE: con\n"
|
||||||
|
f" {det[0][3]} settimane e nessuna perdita la vol campionaria e' quasi\n"
|
||||||
|
f" arbitraria, e lo Sharpe con lei. Non e' che le 08:00 siano un'ora\n"
|
||||||
|
f" magica — e' che questa statistica non porta informazione.")
|
||||||
|
|
||||||
print("\n (d) null del de-levering / beta — 'e' reddito da volatilita' o crypto travestito?'")
|
print("\n (d) null del de-levering / beta — 'e' reddito da volatilita' o crypto travestito?'")
|
||||||
print(" Lo spread ha delta positivo (≈ +0.18 all'ingresso): in un campione che sale del")
|
print(" Lo spread ha delta positivo (≈ +0.18 all'ingresso): in un campione che sale del")
|
||||||
@@ -697,8 +720,15 @@ def main() -> None:
|
|||||||
dly = comb.resample("1D").sum().fillna(0.0)
|
dly = comb.resample("1D").sum().fillna(0.0)
|
||||||
rep = A.marginal_vs_tp01(dly)
|
rep = A.marginal_vs_tp01(dly)
|
||||||
act = int((dly != 0).sum())
|
act = int((dly != 0).sum())
|
||||||
print(f" verdetto={rep.get('verdict')} corr={rep.get('corr'):.3f} "
|
def _f(k):
|
||||||
f"(barre ATTIVE {act}/{len(dly)} = {act / len(dly):.0%})")
|
v = rep.get(k)
|
||||||
|
return f"{v:.3f}" if isinstance(v, (int, float)) and v is not None else str(v)
|
||||||
|
print(f" verdetto={rep.get('verdict')} corr={_f('corr')} "
|
||||||
|
f"insample_edge={rep.get('has_insample_edge')} robust_oos={rep.get('robust_oos')} "
|
||||||
|
f"is_hedge={rep.get('is_hedge')}")
|
||||||
|
print(f" barre ATTIVE {act}/{len(dly)} = {act / len(dly):.0%} — un `None` qui non e'\n"
|
||||||
|
f" un bug: le sotto-misure che richiedono un hold-out non hanno dati per\n"
|
||||||
|
f" esistere, e la funzione lo dichiara invece di inventare un numero.")
|
||||||
print(f" ⚠️ {len(comb)} settimane su un hold-out che non esiste: il verdetto e' "
|
print(f" ⚠️ {len(comb)} settimane su un hold-out che non esiste: il verdetto e' "
|
||||||
f"rumore, si riporta per non ometterlo.")
|
f"rumore, si riporta per non ometterlo.")
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
@@ -719,36 +749,75 @@ def main() -> None:
|
|||||||
|
|
||||||
# ------------------------------------------------------------ §7 VERDETTO
|
# ------------------------------------------------------------ §7 VERDETTO
|
||||||
hr("§7 VERDETTO")
|
hr("§7 VERDETTO")
|
||||||
print(""" SCARTATO — su questi dati la domanda non e' decidibile, e i tre motivi sono
|
print(""" SCARTATO — su questi dati la domanda non e' decidibile. Quattro motivi, indipendenti
|
||||||
indipendenti l'uno dall'altro:
|
l'uno dall'altro: ciascuno da solo basterebbe.
|
||||||
|
|
||||||
1. IL CAMPIONE NON CONTIENE LA STRATEGIA. 0 settimane su 19 passano il gate IV-rank>0.30
|
1. IL CAMPIONE NON CONTIENE LA STRATEGIA. 0 settimane su 19 passano il gate IV-rank>0.30
|
||||||
che E' l'alpha di VRP01. Il campione e' vol implicita al 24-28 percentile E un rialzo
|
che E' l'alpha di VRP01 — il sleeve sarebbe stato FLAT per l'intero campione. La DVOL
|
||||||
forte del sottostante: il regime migliore possibile per vendere put, non uno neutro.
|
mediana sta al 7 (BTC) / 11 (ETH) percentile della storia 2021+, e il sottostante e'
|
||||||
Le 10 settimane per asset (non 16: prima del 2026-06-09 la finestra 4-10 DTE non
|
salito del +25% / +44%: vol implicita bassa E rialzo forte = il regime MIGLIORE
|
||||||
esiste) danno 10/10 vincenti su BTC. La lente giusta non e' lo Sharpe, e' la regola
|
possibile per vendere put, non uno neutro. Le settimane sono 10 per asset, non 16
|
||||||
del tre: 0 perdite su 10 lascia un tasso vero fino al 30%, su un payoff che perde
|
(prima del 2026-06-09 l'archivio seguiva solo la finestra 13-20 DTE: quella 4-10 DTE
|
||||||
~7x il credito.
|
non esiste). Esito: 10/10 vincenti su BTC, e la lente giusta non e' lo Sharpe ma la
|
||||||
|
regola del tre — 0 perdite su 10 lascia un tasso vero fino al 30%, su un payoff che
|
||||||
|
perde ~7x il credito.
|
||||||
|
⚠️ Sfumatura che va detta: il gate non e' lontano. Ha mancato l'apertura per 0.0002 di
|
||||||
|
IV-rank il 2026-06-07, e bastano ~+10% di DVOL per riaprirlo. Il campione e' dentro un
|
||||||
|
regime di vol bassa persistente, non davanti a un muro.
|
||||||
|
|
||||||
2. LA FAMIGLIA CHE HA STORIA NON E' QUELLA CHE SI PUO' ESEGUIRE. Le quote raccolte
|
2. IL TITOLO E' QUASI TUTTO FORTUNA D'ANCORA. L'ora d'ingresso e' un max-of-k mai
|
||||||
sono le opzioni INVERSE (margine e regolamento in BTC/ETH); il conto e' in USDC.
|
dichiarato, ed e' la prima volta che si misura su questa struttura: su 9 ancore lo
|
||||||
La famiglia USDC-lineare esiste per BTC ed ETH ed ha un lotto minimo 10x piu' piccolo
|
Sharpe canonico BTC 32.58 sta all'89 percentile e la MEDIANA ONESTA e' 1.45, con la
|
||||||
(BTC 0.01 invece di 0.1) — quindi il muro «BTC fuori a $3.000» del 30/07, congelato
|
banda che tocca il NEGATIVO (-0.35). Fortuna +31.13. Su ETH 3.90 -> 2.41.
|
||||||
in un test, e' misurato sulla famiglia sbagliata. Ma di quella famiglia abbiamo ZERO
|
Il numero da citare per BTC e' 1.45, non 32.58 — e a quel punto non c'e' piu' niente
|
||||||
ore di storia e l'open interest e' ~0.
|
di straordinario da spiegare.
|
||||||
|
|
||||||
3. LO SPREAD E' IL COSTO DOMINANTE E NON E' MODELLABILE DA UN MID. Attraversare il
|
3. LA FAMIGLIA CHE HA STORIA NON E' QUELLA CHE SI PUO' ESEGUIRE. Le quote raccolte sono
|
||||||
bid/ask costa da solo una quota grossa del credito, e l'ala che si COMPRA e' la gamba
|
le opzioni INVERSE (margine e regolamento in BTC/ETH); il conto e' in USDC e il book
|
||||||
dove il libro e' piu' largo — lo stesso meccanismo che il 30/07 misurava come f=0.73.
|
esegue sui perpetual lineari USDC. Esiste una famiglia USDC-lineare per BTC ed ETH col
|
||||||
|
lotto minimo 10x piu' piccolo (BTC 0.01 = $773 di nozionale invece di 0.1 = $7.728),
|
||||||
|
quindi il muro «BTC fuori a $3.000» del 30/07 — congelato in
|
||||||
|
tests/test_vrp_profit_take.py — e' misurato sulla famiglia che il conto non margina.
|
||||||
|
E' la 3a occorrenza della stessa forma dopo fee_watch (21/08) e la taratura di
|
||||||
|
venue_watch: un numero puntato su una configurazione diversa da quella che gira.
|
||||||
|
Ma di quella famiglia abbiamo ZERO ore di storia.
|
||||||
|
|
||||||
Cio' che NON si conclude: che la struttura non funzioni. Non e' stata osservata nel regime
|
4. LO SPREAD E' IL COSTO DOMINANTE, E SULLA FAMIGLIA ESEGUIBILE E' PEGGIO. Attraversare
|
||||||
in cui lavora. La regola «niente short-vol da MODELLO in deploy» NON diventa «short-vol da
|
il bid/ask costa ~10% del credito sugli INVERSE; nella regione di strike che serve lo
|
||||||
QUOTE»: le quote ora ci sono, ma sono quote della famiglia sbagliata, in un regime solo.
|
spread relativo mediano e' 24-37% sugli inverse e 29-59% sulle USDC, con open interest
|
||||||
|
~0. Il f del credito netto si replica indipendentemente a 0.714 (IC95 [0.690, 0.779],
|
||||||
|
0/19 osservazioni >= 1.0) — conferma dello 0.73 del 30/07 su un campione piu' lungo e
|
||||||
|
con un percorso diverso.
|
||||||
|
|
||||||
AZIONE RACCOMANDATA (non eseguita — tocca la produzione, e la decisione e' dell'operatore):
|
CIO' CHE NON SI CONCLUDE: che la struttura non funzioni. Non e' stata osservata nel regime
|
||||||
far raccogliere a `collect_chain.py` anche `currency=USDC` (famiglie BTC_USDC/ETH_USDC).
|
in cui lavora. E un risultato a favore c'e', va detto: su BTC il null «e' solo crypto
|
||||||
Costa ~2 chiamate in piu' per giro; senza, fra sei mesi ci ritroveremo con un anno di
|
travestito» e' REFUTATO (beta +0.019, t=0.18) — il PnL non viene dal rialzo. Non basta,
|
||||||
storia della famiglia che non possiamo tradare e zero di quella che potremmo.""")
|
perche' il punto 2 toglie il titolo comunque.
|
||||||
|
|
||||||
|
LA REGOLA NON CAMBIA. «Niente short-vol da MODELLO in deploy» non diventa «short-vol da
|
||||||
|
QUOTE»: le quote adesso ci sono, ma sono quote della famiglia sbagliata, in un regime solo,
|
||||||
|
e con l'ancora che spiega il risultato. La sostituzione della regola resta NON DIMOSTRATA.
|
||||||
|
|
||||||
|
DUE AZIONI, NESSUNA ESEGUITA (toccano la produzione o il conto: decide l'operatore).
|
||||||
|
|
||||||
|
(A) DATO — far raccogliere a `collect_chain.py` anche `currency=USDC`. Costo MISURATO col
|
||||||
|
filtro OI>=100 gia' in vigore: ETH_USDC porterebbe 119 strumenti per giro (+21% di
|
||||||
|
chiamate, da ~570 a ~690), BTC_USDC ne porterebbe 5 su 686 (0.7%) = nulla di
|
||||||
|
utilizzabile. Cioe': l'unica struttura USDC-regolata con un libro vero e' su ETH,
|
||||||
|
lotto minimo 0.1 ETH = $242. Senza questa raccolta, fra sei mesi avremo un anno di
|
||||||
|
storia della famiglia che non possiamo marginare e zero di quella che potremmo — che
|
||||||
|
e' esattamente la posizione di oggi, un'ondata dopo l'altra.
|
||||||
|
|
||||||
|
(B) CONTO — una domanda che nessun dato pubblico chiude e che viene PRIMA di ogni
|
||||||
|
backtest: un saldo in USDC puo' marginare un'opzione INVERSE? Se no, la famiglia con
|
||||||
|
3 mesi di storia non e' negoziabile da questo conto a nessun capitale, e il punto 3
|
||||||
|
smette di essere un dettaglio di lotto per diventare un muro. Si risolve come si
|
||||||
|
risolse il PRIIPs il 26/07: guardando il conto, non i dati.
|
||||||
|
|
||||||
|
SE E QUANDO RIAPRIRLO. Non «quando ci sara' un crash» (criterio senza numero) ma: DVOL BTC
|
||||||
|
> 48.3 o ETH > 62.8 in modo persistente, PIU' ~un anno di settimane raccolte in quel
|
||||||
|
regime sulla famiglia eseguibile. Prima di allora ogni misura su questa struttura
|
||||||
|
descrivera' la sua astensione.""")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user