feat(shape): SH01 Shape-ML validato come diversificatore + doc

Validazione dura del solo edge sopravvissuto alla ricerca shape (ML walk-forward
LogisticRegression sulle feature di forma). SH01 config W24 H12 th0.58:
- BTC robusto ovunque (expanding +219%/OOS+42% Sharpe2.72 8-9anni; rolling2y
  +166%/+96%; stress leva2x+slippage OK), ETH/ADA solo expanding, LTC/SOL/XRP no.
- Griglia 5/27 robuste su cresta W24/H8-12 -> overfit moderato, config conservativa.
- Free-lunch: corr +0.08 col MASTER, aggiungerlo migliora OOS (Sharpe 4.33->5.10,
  DD 4.7->4.2%). Diversificatore, non motore standalone. Regge fee 0.20% RT.

SH01 come Strategy (in MODULE_MAP) + run() riproducibile. shape_ml_research esteso
con walk-forward rolling (train_window). Live richiede worker con retraining.
Diario 2026-05-29-shape.md, CLAUDE.md famiglia SHAPE-ML.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-29 12:31:26 +02:00
parent 4ac87ab385
commit 2596687679
6 changed files with 396 additions and 4 deletions
+8 -4
View File
@@ -244,10 +244,13 @@ def analog_feat_entries(df, W=24, H=12, K=60, rebuild=300, min_lib=1500,
# =============================================================================
def ml_wf_entries(df, W=24, H=12, model="gb", thresh=0.58,
train_min=4000, retrain=500, n_estimators=80, max_depth=3,
tp_atr=None, sl_atr=None, trend_max=None, ema_long=200) -> list[dict]:
"""Walk-forward: a blocchi di `retrain` barre, allena su TUTTO il passato il cui esito
tp_atr=None, sl_atr=None, trend_max=None, ema_long=200,
train_window=None) -> list[dict]:
"""Walk-forward: a blocchi di `retrain` barre, allena sul passato il cui esito
e' noto, predice il blocco corrente. Scaler+modello fittati solo sul train.
Entra a close[i] se proba della classe predetta >= thresh. model in {gb, logit}."""
Entra a close[i] se proba della classe predetta >= thresh. model in {gb, logit}.
train_window: se None -> expanding (tutto il passato); se int -> ROLLING (solo le
ultime train_window barre prima del blocco) -> test di robustezza piu' severo."""
c = df["close"].values
n = len(c)
a = atr(df, 14)
@@ -268,7 +271,8 @@ def ml_wf_entries(df, W=24, H=12, model="gb", thresh=0.58,
blk_end = min(blk + retrain, n - 1)
# TRAIN: finestre la cui forma E il cui esito (e+H) sono < blk
# cioe' e <= blk-1-H (esito realizzato prima del primo test del blocco)
tr_ends = ends[(ends <= blk - 1 - H) & (ends >= W - 1)]
lo_end = (blk - 1 - H - train_window) if train_window is not None else (W - 1)
tr_ends = ends[(ends <= blk - 1 - H) & (ends >= max(W - 1, lo_end))]
tr_ends = tr_ends[~np.isnan(sgn[tr_ends])]
if len(tr_ends) < 800:
blk = blk_end