research: ondata 26/07-bis — TP01 su barra parziale + i 2 gate mai costruiti

0 sleeve nuovi. Book, pesi, cron, config INVARIATI.

T1 — anche TP01 legge una barra giornaliera PARZIALE nel live, ma non conta.
Stesso fatto strutturale di SKH01: resample_tf non scarta il giorno in corso e
current_target prende [-1]; il feed si ricostruisce alle 00:30 UTC, quindi per
tutta la giornata il book vede oggi come 1 barra oraria su 24 (verificato).
Il docstring "ultima barra CHIUSA" era falso: corretto.

Tre path a un grado di liberta' per volta, 24 ancore, differenze appaiate:
  barra parziale   ΔFULL -0.031 (pos 7/24)  ΔHOLD +0.118 (pos 19/24)
  ritardo 1h       ΔFULL -0.004 (pos 11/24 = moneta)
  leva LIVE/MODEL  1.004
-> trascurabile, nessun cambio al live.

All'ancora canonica sembra peggio del vero: a offset 0 la parziale costa -0.230
di hold-out, che e' il MINIMO della banda (mediana +0.118). Speculare alla
lezione del 26/07: li' l'ancora canonica nascondeva un vantaggio, qui inventa
un danno.

REGOLA: la parzialita' dell'ultima barra conta in proporzione a quanto il
segnale pesa la barra piu' recente. Donchian breakout su 230m (la barra corrente
E' il segnale) -> +0.38; TSMOM 30/90/180g -> ±0.03. Non si trasferisce.

T2 — implausible_sharpe e anchor_luck_band codificati in altlib (debito
raccomandato 3 volte e mai scritto), piu' anchor_luck_delta che codifica
l'errore di stamattina (mediana delle differenze appaiate, non differenza
delle mediane).

Il gate ha segnalato VRP01 e il difetto era MIO: perdite contate su tutte le
barre, ma VRP01 e' settimanale su griglia giornaliera (94.2% di zeri) -> "0.96%,
coda assente" su uno sleeve in produzione. Sulle barre ATTIVE e' 16.5%, la forma
giusta di un credit spread a rischio definito. La lezione era gia' cablata il
giorno prima nel monitor DVOLSPREAD ("barre attive, non giorni di calendario").

Applicazione retroattiva 7/7 tutti ok, con controlli positivi obbligatori
superati (firme CC01 e deep-OTM segnalate, rumore Sh 0.62 no).

Replica indipendente del finding d'ancora del 02/07: il gate applicato alla
cieca a TP01 ritrova canonica +0.237 = 92 pctl delle 24, mediana onesta +0.056,
fortuna +0.182 — contro mediana 0.04 misurata il 02/07 con implementazione
separata. L'hold-out onesto di TP01 e' ~+0.05, non 0.31.

NON fatto: il book ricalcolato sul path live, bloccato da incompatibilita' di
lenti (simulatore per-trade vs sleeve vol-targeted). Follow-up dichiarato.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-25 22:36:40 +00:00
parent 6d0813a399
commit 37be1df838
7 changed files with 947 additions and 2 deletions
+21 -2
View File
@@ -115,7 +115,23 @@ class TrendPortfolio:
return tgt
def current_target(self, df: pd.DataFrame) -> float:
"""Posizione-bersaglio decisa all'ultima barra CHIUSA (per il paper/live)."""
"""Posizione-bersaglio all'ULTIMA BARRA DEL df — che nel live e' PARZIALE (per paper/live).
⚠️ Il docstring precedente diceva "ultima barra CHIUSA": e' un'assunzione sul chiamante e
nel live **non e' verificata**. `resample_tf` non scarta la barra in corso e il feed
certificato viene ricostruito alle 00:30 UTC, quindi per tutta la giornata il book vede il
giorno corrente come una barra da **1 ora su 24** (verificato 26/07: `barre1h=1/24`).
MISURATO (`scripts/research/r0726_tp01_partial_day.py`, 24 ancore, differenze appaiate):
l'effetto e' **trascurabile** — barra parziale ΔSharpe FULL 0.031 / HOLD +0.118, ritardo
d'esecuzione di 1h ~0 (11/24 = moneta), leva gonfiata **+0.4%**. Nessun cambio richiesto.
Il perche' e' la regola generale: la parzialita' dell'ultima barra conta in proporzione a
**quanto il segnale pesa la barra piu' recente**. TP01 e' un TSMOM 30/90/180 giorni: l'ora
mancante e' 1/24 di UNA osservazione su 30-180. SKH01 e' un Donchian breakout su barra
230m, dove la barra corrente E' il segnale: li' lo stesso difetto vale +0.38 di Sharpe
(misura del 26/07). Non si trasferisce una conclusione fra i due.
"""
return float(self.target_series(df)[-1])
def net_returns(self, df: pd.DataFrame) -> tuple[np.ndarray, pd.Series]:
@@ -179,7 +195,10 @@ def _bars_per_year(idx: pd.DatetimeIndex) -> float:
def resample_tf(df_1h: pd.DataFrame, rule: str) -> pd.DataFrame:
"""Resample 1h -> rule (confini 00:00 UTC). Schema con 'datetime'.
NB: usare SOLO per-singolo-TF (qui leak-free); MAI ffill/combine mixed-TF su questi
timestamp open-labeled (label='left') -> look-ahead. Deploy a >=12h (vedi docstring modulo)."""
timestamp open-labeled (label='left') -> look-ahead. Deploy a >=12h (vedi docstring modulo).
⚠️ NON scarta la barra IN CORSO: l'ultima riga puo' essere parziale. E' irrilevante nel
backtest (l'ultima barra e' l'ultima) ma NON nel live, dove `current_target` legge proprio
quella — vedi il suo docstring per la misura dell'effetto."""
g = df_1h.copy()
idx = pd.to_datetime(g["timestamp"], unit="ms", utc=True)
idx.name = "dt"