research(wave-0822): VOL-SIZE — il null di permutazione si cita col segno, non col decimale (gira su 3 ancore su 23)

This commit is contained in:
Adriano Dal Pastro
2026-08-22 17:24:23 +00:00
parent f975272ec8
commit f0122d97a1
2 changed files with 33 additions and 4 deletions
+6 -2
View File
@@ -266,8 +266,12 @@ zeri nei due canali, il guadagno FULL viene dalla **FREQUENZA** (il solo filtro
fortuna d'ancora del libro vale **+0,196 FULL / +0,448 HOLD**.
- Cella congelata del LEAD (`VTL tv20 w90`): size fissata **all'ingresso** =
`clip(0,20 / rv90(t1), 0, 3)`. ISO dShFULL **+0,070 (23/23 ancore)**, dShHOLD +0,101 (19/23),
**8/8 anni positivi**, null di permutazione p~0,027 (e la mediana del null e' **0,04**:
riassegnare a caso la stessa distribuzione di size **danneggia**).
**8/8 anni positivi**, **null di permutazione superato in ENTRAMBE le terne di ancore provate,
p <~ 0,03** (mediana del null 0,03/0,05: riassegnare a caso la stessa distribuzione di size
**danneggia**). ⚠️ **Autocorrezione dell'agente, da rispettare:** quel null gira su **3 ancore
delle 23** per costo, e la TAGLIA dell'effetto varia di **3x** fra due terne diverse della
stessa banda (+0,033 vs +0,111 sulla stessa cella) -> **i p-value non si citano a tre decimali**:
il numero da mettere a verbale e' il **segno**. Il resto del report e' su 23 ancore piene.
- ⚠️ `DSR = 1,000` dichiarato **VACUO, non PASS**: lo passa anche il baseline — su una famiglia di
perturbazioni della stessa strategia il deflated-Sharpe non ha potenza. Onesta' rara.
- ⚠️ Punto piu' fragile, dichiarato: l'asse della finestra e' un **picco, non un plateau**
+27 -2
View File
@@ -514,7 +514,7 @@ def signal_w(cv: pd.DataFrame, family: str, sig: str, win_h: int, thr: float) ->
def run_strategy(cv: pd.DataFrame, ctx: dict, family: str, sig: str,
win_h: int, thr: float, slip_bps: float,
fee_side: float = FEE_SIDE, fi=None, bi=None) -> pd.Series:
fee_side: float = FEE_SIDE, fi=None, bi=None, lag: int = 1) -> pd.Series:
"""Ritorno ORARIO netto per $1 di nozionale LORDO PER GAMBA.
Le posizioni vivono in spazio CONTRATTO: quando la coppia cambia (roll) la variazione
@@ -541,7 +541,7 @@ def run_strategy(cv: pd.DataFrame, ctx: dict, family: str, sig: str,
P[rows[m], fi[m]] = w[m]
held = np.zeros_like(P)
held[1:] = P[:-1] # deciso a t, tenuto in t->t+1
held[lag:] = P[:-lag] if lag else P # deciso a t, tenuto in t->t+lag
gross = (held * ctx["R"]).sum(axis=1)
dP = np.zeros_like(P)
@@ -794,6 +794,31 @@ def main() -> None:
except Exception: # noqa: BLE001
pass
# ---------------- STEP 6b: RITARDO D'ESECUZIONE (il test decisivo qui) ----------------
print("\n[6b] RITARDO D'ESECUZIONE — il test decisivo di questo filone")
print(" Un datato lontano ha prezzi STANTII: una mean-reversion su una serie stantia")
print(" mostra profitti FINTI (il prezzo 'reverte' solo perche' si aggiorna in ritardo).")
print(" Un edge di STRUTTURA A TERMINE e' lento e sopravvive a un'ora in piu' di ritardo;")
print(" un artefatto di microstruttura muore. (Stessa lente del decadimento di XSR01.)")
lag_tab = []
for lg in [1, 2, 3, 6, 12, 24]:
hs = []
for a in ASSETS:
f_i, b_i = pidx[(a, int(b.roll))]
hs.append(run_strategy(cvcache[(a, int(b.roll))], ctxs[a], b.family, b.sig,
int(b.win), float(b.thr), slip_est, fi=f_i, bi=b_i, lag=lg))
sl_ = stats(to_daily(pd.concat(hs, axis=1).fillna(0.0).mean(axis=1)))
lag_tab.append((lg, sl_["sharpe"], sl_["cagr"]))
print(f" ritardo {lg:2d}h -> Sharpe {sl_['sharpe']:+6.2f} CAGR {sl_['cagr']*100:+6.2f}%")
s1 = lag_tab[0][1]; s2 = lag_tab[1][1]
if s1 > 0:
keep = s2 / s1
print(f" con UNA sola ora in piu' resta il {keep*100:.0f}% dello Sharpe "
f"({s1:+.2f} -> {s2:+.2f})")
print(" -> " + ("compatibile con un edge lento di struttura a termine"
if keep > 0.6 else
"CROLLO: firma di microstruttura/prezzo stantio, NON di term structure"))
# ---------------- STEP 7: quanto spread uccide l'edge ----------------
print("\n[7] A CHE SPREAD MUORE L'EDGE (la stima di slippage e' il rischio #1)")
for sl in [0.0, 1.0, 2.5, 5.0, 7.5, 10.0, 20.0]: