export const meta = {
  name: 'mr02eth-replace-search',
  description: 'Cerca sostituto/miglioria a MR02/ETH: 112 strategie distinte su harness onesto + verifica avversariale',
  phases: [
    { title: 'Generate', detail: '112 agenti, una strategia ETH distinta ciascuno, backtest onesto fee-aware OOS' },
    { title: 'Verify', detail: 'verifica avversariale dei survivor (look-ahead audit + re-run + robustezza)' },
  ],
}

// ---------------------------------------------------------------- baseline & recipe
const BASELINE = `BASELINE DA BATTERE (MR02/ETH sullo STESSO engine explore_lab, ETH 1h, fee 0.10% RT, lev 3x, pos 0.15):
- canonico (Donchian n=20, sl 2*ATR, max_bars 24, TP a centro canale): full Sharpe 7.49, OOS Sharpe 10.94, full DD 42%, OOS DD 18%, exposure 31%, 2392 trade, fee0.2% positivo.
- trend-filtrato (come sopra + salta se |close-EMA200|/ATR(14) > 3.0): full Sharpe 8.45, OOS Sharpe 11.96, full DD 25%, OOS DD 13%, exposure 16%, 1148 trade, fee0.2% positivo.
Il PROBLEMA di questo sleeve e' il DD/whipsaw (fada il trend al ribasso, poi shorta il rimbalzo). Un buon SOSTITUTO deve: battere OOS Sharpe ~12 E/O tagliare il full DD sotto ~20%, restando OOS positivo, sopravvivere a fee 0.20% RT, con la maggior parte degli anni 2021+ positivi. DD piu' basso a Sharpe comparabile e' GIA' valore. Anche un buon DIVERSIFICATORE (Sharpe decente + decorrelato, esposizione diversa) e' utile.`

const RECIPE = `Lavora in /opt/docker/PythagorasGoal. Testa UNA idea di strategia come candidata a SOSTITUIRE/MIGLIORARE MR02/ETH.
Usa l'harness ONESTO condiviso (no look-ahead, fee-aware, OOS). Scrivi UNO script self-contained in /tmp/cand_KEY.py (KEY = la tua key, univoca) ed eseguilo:
  cd /opt/docker/PythagorasGoal && uv run python /tmp/cand_KEY.py

API (import from scripts.analysis.explore_lab):
- get_df(asset, tf) -> df [open,high,low,close,volume,timestamp,dt]. Usa asset="ETH", tf="1h" (puoi testare anche tf="4h").
- atr(df,n=14)->np.array ; ema(x,n)->np.array ; rsi(close,n=14)->np.array
- simulate(entries, df, fee_rt=0.001, lev=3.0, pos=0.15, split=-1) -> dict(trades,win,ret,dd,sharpe,yearly,exposure)
- evaluate(name, entries, df, fees=(0,0.0005,0.001,0.002)) -> dict(full,oos,sweep,sweep_oos,pos_yrs,n_yrs) e stampa una riga.
- robust(res)->bool.
Se la tua idea usa DVOL/funding/Hurst/fractali, puoi importare da scripts.analysis.regime_lab: load(asset,tf), regime_features(df), frac_features(df), load_features(asset,tf) (cache; vedi il file se serve). Se non sono disponibili, ripiega su feature calcolate dalle sole OHLCV. Se la tua idea e' shape/kNN, vedi scripts.analysis.shape_lab (analog_entries, analog_signals).
entries = list di {"i":int, "d":+1/-1, "max_bars":int, "tp":float|None, "sl":float|None}. L'ingresso esegue a close[i]. TP/SL sono intrabar al livello (SL valutato PRIMA del TP). split>0 nel simulate = solo entries con i>=split (OOS).

ANTI-LOOK-AHEAD (non negoziabile): direzione e prezzo alla barra i usano SOLO dati [0..i] (close[i] incluso). Mai usare high/low/close della barra i+ per decidere ingresso/direzione. Canali/rolling che devono escludere la barra corrente vanno .shift(1). Prezzo d'ingresso = close[i]. La famiglia squeeze e' stata scartata proprio per questo errore: NON ripeterlo.

${BASELINE}

Procedura: implementa l'idea, fai uno sweep PICCOLO (2-4 config di parametri), scegli la MIGLIORE per OOS Sharpe a parita' di: sopravvive a fee 0.20% RT e full DD non peggiore della baseline. Verifica l'assenza di look-ahead (perturba le barre future e controlla che gli entries non cambino, oppure argomenta perche' non c'e').

Restituisci SOLO il risultato strutturato della tua MIGLIORE config. Sii ONESTO: se non batte la baseline, riporta i numeri VERI (peggiori) — un risultato negativo e' informazione utile. NON inventare numeri: devono venire dall'esecuzione reale dello script.`

const SCHEMA = {
  type: 'object',
  additionalProperties: false,
  required: ['key','family','implemented','ran_ok','best_config','trades','exposure','full_sharpe','full_ret','full_dd','oos_sharpe','oos_ret','oos_dd','fee02_full','fee02_oos','pos_yrs','n_yrs','no_lookahead','beats_baseline','verdict','note'],
  properties: {
    key: { type: 'string' },
    family: { type: 'string' },
    implemented: { type: 'boolean' },
    ran_ok: { type: 'boolean', description: 'lo script ha girato senza errori e i numeri vengono dall esecuzione reale' },
    best_config: { type: 'string', description: 'parametri della config migliore' },
    trades: { type: 'integer' },
    exposure: { type: 'number', description: '% barre in posizione (full)' },
    full_sharpe: { type: 'number' },
    full_ret: { type: 'number', description: '% ritorno full' },
    full_dd: { type: 'number', description: '% max drawdown full' },
    oos_sharpe: { type: 'number' },
    oos_ret: { type: 'number' },
    oos_dd: { type: 'number' },
    fee02_full: { type: 'number', description: 'ritorno % full a fee 0.20% RT' },
    fee02_oos: { type: 'number', description: 'ritorno % OOS a fee 0.20% RT' },
    pos_yrs: { type: 'integer', description: 'anni positivi' },
    n_yrs: { type: 'integer' },
    no_lookahead: { type: 'boolean' },
    beats_baseline: { type: 'boolean', description: 'batte la baseline MR02/ETH trend-filtrata (OOS Sharpe ~12 e/o DD<20%)' },
    verdict: { type: 'string', enum: ['substitute','improvement','diversifier','reject'] },
    note: { type: 'string', description: '1-2 frasi: perche funziona o perche no, e l angolo distintivo' },
  },
}

// ---------------------------------------------------------------- 112 idee distinte
// [key, family, idea]
const SPECS = [
  // A. fade gated da regime (il fix del whipsaw)
  ['adx_gate_fade','gated-fade','Donchian/Bollinger fade su ETH ma SALTA quando ADX(14) e alto (regime trending). Calcola ADX causale; entra in fade solo se ADX<soglia (sweep 18/22/25). Tesi: evita di fadare i trend forti che fanno il whipsaw a MR02.'],
  ['kaufman_er_gate','gated-fade','Mean-reversion fade gated dal Kaufman Efficiency Ratio (|close-close[-n]| / somma|delta| su n barre). Fada solo se ER basso (mercato choppy/range), salta se ER alto (trending). Sweep n e soglia.'],
  ['hurst_gate_fade','gated-fade','Donchian fade ma entra solo se rolling-Hurst (causale, dalle close) < soglia anti-persistente (sweep 0.45/0.5/0.55). Usa frac_features da regime_lab se disponibile, altrimenti Hurst R/S manuale.'],
  ['varratio_gate_fade','gated-fade','Donchian fade gated dal variance-ratio (VR<1 = mean-reverting). Entra in fade solo quando VR(k) sotto soglia. Sweep k e soglia.'],
  ['rv_pct_gate_fade','gated-fade','Donchian fade ma salta quando la realized-vol percentile (rolling) e nel quartile alto: la vol estrema = crash/parabola dove la fade muore. Sweep finestra e soglia percentile.'],
  ['dvol_gate_fade','gated-fade','Bollinger/Donchian fade ETH gated dalla DVOL percentile (regime_lab.load+regime_features). Testa fade SOLO in DVOL bassa (calmo) vs alta. Riporta quale regime e migliore.'],
  ['vrp_gate_fade','gated-fade','Fade gated dal VRP (vol risk premium = dvol-rv) e dal livello DVOL. Test del finding FR01: edge su VRP<0 + DVOL bassa. Da regime_lab. Fada solo in quel regime.'],
  ['funding_gate_fade','gated-fade','Donchian fade gated dal funding (regime_lab): es. evita fade long quando funding molto negativo (panic). Sweep soglia funding_z.'],
  ['emaslope_gate_fade','gated-fade','Fade ma salta quando la pendenza di EMA200 (slope su k barre, normalizzata da ATR) e ripida: non fadare contro un trend strutturale. Sweep soglia slope.'],
  ['choppiness_gate_fade','gated-fade','Donchian fade gated dal Choppiness Index (alto=range, basso=trend). Entra solo se CI>soglia (range). Sweep finestra/soglia.'],
  ['rsq_gate_fade','gated-fade','Fade gated dall R^2 di una regressione lineare rolling sul log-prezzo: alto R^2 = trend pulito (salta), basso = range (fada). Sweep finestra/soglia.'],
  ['bbw_gate_fade','gated-fade','Bollinger fade gated dalla band-width (BBW): fada solo quando BBW in regime medio/alto ma non esplosivo. Sweep soglie BBW percentile.'],
  ['atr_pct_gate_fade','gated-fade','Donchian fade ma salta quando ATR-percentile rolling e estremo (>p80): la coda di vol e dove il whipsaw uccide. Sweep percentile.'],
  ['htf_align_fade','gated-fade','Fade ETH 1h ma NON contro il trend 4h: salta i long-fade se EMA20<EMA50 su 4h (downtrend) e i short-fade se uptrend 4h. Resample 4h dalla 1h. Fada solo allineato/neutro.'],
  ['asym_trenddist_fade','gated-fade','Donchian fade con soglie trend-distance ASIMMETRICHE long vs short, e cap piu stretto sul lato contro-trend HTF. Sweep coppie di soglie.'],
  ['btc_regime_fade','gated-fade','Fade ETH solo quando BTC e in regime range (BTC |close-EMA200|/ATR sotto soglia): se BTC sta trendando forte, anche ETH trenda e la fade muore. Trade ETH, gate su BTC.'],

  // B. meccanismi mean-reversion alternativi
  ['rsi2_revert','mr-alt','RSI(2) di Connors: long quando RSI2<10, short quando RSI2>90, exit su RSI2 che torna a 50 o max_bars. Sweep soglie e max_bars su ETH 1h.'],
  ['rsi14_bands','mr-alt','RSI(14) revert con bande: long RSI<30, short RSI>70, TP al ritorno a 50 (proxy prezzo), SL ATR. Sweep.'],
  ['pctb_fade','mr-alt','Bollinger %B fade: long quando %B<0, short quando %B>1, TP a media, SL ATR. Sweep finestra/sigma/max_bars. Confronta con MR01.'],
  ['zscore_price_fade','mr-alt','Z-score del prezzo vs SMA(n): entra quando |z|>soglia contro il movimento, TP a z=0 (SMA), SL ATR. Sweep n/soglia. Versione simmetrica del DIP.'],
  ['zscore_ret_fade','mr-alt','Z-score del rendimento di barra (MR07-like) ma ri-tunato per ETH: |z|>soglia su finestra n, exit in multipli ATR. Sweep n/soglia/exit.'],
  ['vwap_revert','mr-alt','Reversion a VWAP rolling (volume-weighted): entra quando il prezzo devia >k*sigma dal VWAP, TP al VWAP. Sweep finestra/k.'],
  ['keltner_fade_eth','mr-alt','Keltner channel fade ri-tunato per ETH (EMA +/- m*ATR): fada la rottura della banda Keltner, TP a EMA. Sweep m/finestra. MR03 era debole su BTC ma ETH puo differire.'],
  ['cci_revert','mr-alt','CCI(n) extreme revert: long CCI<-100, short CCI>+100, exit su CCI->0 o max_bars. Sweep.'],
  ['williamsr_revert','mr-alt','Williams %R revert: long %R<-80, short %R>-20, TP a media canale, SL ATR. Sweep.'],
  ['stoch_revert','mr-alt','Stochastic %K/%D extreme revert su ETH: long quando %K<20 e cross-up, short %K>80 cross-down. Sweep finestre.'],
  ['connors_rsi','mr-alt','Connors RSI (RSI3 del prezzo + RSI2 della streak + percentrank del rendimento) extreme revert. Sweep soglie.'],
  ['anchored_vwap_revert','mr-alt','Reversion a VWAP ancorato all ultimo swing-low/high (Williams): entra quando il prezzo si allontana >k*ATR dall AVWAP, TP all AVWAP.'],
  ['median_z_fade','mr-alt','Z robusto: (close - rolling median) / rolling MAD. Fada |z|>soglia, TP a mediana. Piu robusto agli outlier della SMA-z. Sweep.'],
  ['pctrank_fade','mr-alt','Percent-rank del close nella finestra rolling: long se rank<0.05, short se rank>0.95, TP al rank 0.5 (proxy). Sweep finestra.'],
  ['double_bollinger','mr-alt','Doppia Bollinger: entra fade alla banda esterna (2.5-3 sigma), esce alla banda interna (1 sigma) invece che alla media. Sweep sigma esterna/interna.'],
  ['fade_to_ema','mr-alt','Donchian/Bollinger fade ma TP all EMA(n) invece che SMA/centro-canale (target dinamico che segue il trend). Sweep n EMA.'],
  ['nbar_lowhigh_rsi','mr-alt','Entra long su nuovo minimo a N barre CON RSI<35 (doppia conferma di esaurimento), short speculare. TP a media, SL ATR. Sweep N.'],
  ['overshoot_swing_fade','mr-alt','Fada quando il prezzo supera lo swing-high/low precedente (Williams) di k*ATR e poi la barra chiude rientrando: false-breakout fade. Sweep k.'],

  // C. exit migliori sulla Donchian fade (stesso ingresso)
  ['tight_sl_confirm','exit','Donchian fade con SL piu stretto (1.0/1.5 ATR) ma close-confirm (esci solo se il close sfonda SL-0.5ATR). Replica EXIT-16. Sweep buffer.'],
  ['fast_tp_partial','exit','Donchian fade con TP a frazione del canale (0.25/0.5 width) invece che al centro: incassa prima il rimbalzo, riduce il tempo a rischio. Sweep frazione.'],
  ['short_timestop','exit','Donchian fade con time-stop corto (max_bars 6/8/12 invece di 24): esce prima che il whipsaw maturi. Sweep max_bars.'],
  ['atr_trailing_exit','exit','Donchian fade con uscita a ATR-trailing dopo l ingresso (trail il massimo favorevole di k*ATR). Sweep k. (la ricerca dice che il trailing spesso fallisce: verifica onestamente).'],
  ['breakeven_stop','exit','Donchian fade: dopo che il trade va in utile di +x*ATR, sposta lo stop a breakeven. Sweep x.'],
  ['rsi_exit','exit','Donchian fade con exit quando RSI torna oltre 50 (mean ripristinata) invece del TP fisso. Sweep.'],
  ['return_to_ema_exit','exit','Donchian fade con exit quando il prezzo ri-tocca l EMA(50) (ritorno alla media mobile) o max_bars. Sweep EMA.'],
  ['volscaled_maxbars','exit','Donchian fade con max_bars scalato sulla vol: meno barre in alta-vol, piu in bassa-vol. Sweep mapping.'],
  ['chandelier_exit','exit','Donchian fade con Chandelier exit (max favorevole - k*ATR). Sweep k.'],
  ['tp_opposite_band','exit','Donchian fade con TP alla banda OPPOSTA (reversione completa del canale) invece del centro. Piu ambizioso, meno frequente. Sweep.'],

  // D. trend-following su ETH (prende cio che la fade perde)
  ['ema_cross_4h','trend','EMA20/EMA100 cross su ETH 4h, long quando EMA20>EMA100, flat altrimenti (TR01-style su ETH solo). Niente fade. Valuta come diversificatore direzionale.'],
  ['donchian_breakout','trend','Donchian BREAKOUT trend (opposto del fade): long su rottura del massimo a N barre, stop sotto il minimo. La ricerca dice che i breakout crypto rientrano: verifica ONESTAMENTE se su ETH regge netto fee.'],
  ['macd_trend','trend','MACD(12,26,9) trend-following su ETH 1h/4h: long su cross rialzista sopra zero, exit su cross opposto. Sweep TF.'],
  ['dual_ma_atr','trend','Dual-MA (fast/slow) con filtro ATR sul gap: entra trend solo se separazione MA > k*ATR (evita whipsaw delle MA). Sweep.'],
  ['supertrend','trend','Supertrend (ATR band) su ETH: segui il flip. Sweep multiplier/periodo.'],
  ['momentum_sign','trend','Momentum semplice: long se rendimento a H barre > 0 (12h/24h/48h), tieni H barre. Time-series momentum su ETH. Sweep H.'],
  ['tsmom_eth','trend','TSMOM multi-orizzonte (3/6/12 mesi sul daily resample di ETH) con risk-off se sotto SMA100. Solo ETH. Valuta come diversificatore.'],
  ['breakout_vol_confirm','trend','Channel breakout con conferma di volume (rottura valida solo se volume>media*k). Sweep.'],
  ['heikin_trend','trend','Heikin-Ashi trend: long su serie di candele HA verdi, exit su prima rossa. Costruisci HA causale. Sweep.'],
  ['triple_screen','trend','Triple-screen: trend 4h (EMA) definisce il bias, ingresso 1h su pullback nella direzione del trend (no contro-trend). Sweep.'],

  // E. volatilita
  ['squeeze_expansion','vol','Bollinger-squeeze -> espansione, ma ingresso ONESTO: entra solo DOPO che la barra di espansione e CHIUSA, nella sua direzione, a close[i] (non anticipare). Verifica se l edge sparisce come per la famiglia squeeze scartata.'],
  ['atr_breakout','vol','ATR breakout: entra quando |close-close[-1]|>k*ATR nella direzione del movimento (continuazione) OPPURE contro (reversione) — testa entrambe e riporta quale regge. Sweep k.'],
  ['volofvol_revert','vol','Mean-reversion della vol-of-vol: quando la realized-vol fa uno spike estremo (z alto), fada il prezzo (gli spike di vol = capitolazione che rimbalza). Sweep.'],
  ['or_breakout_daily','vol','Opening-range breakout: definisci il range delle prime k ore UTC del giorno, entra sulla rottura con SL all altro lato. Sweep k. Trade ETH 1h.'],
  ['rv_regime_switch','vol','Switch fade/trend in base al regime di realized-vol: fade in bassa-vol (range), trend-follow in alta-vol. Una strategia adattiva. Sweep soglia.'],
  ['keltner_squeeze','vol','Keltner-inside-Bollinger squeeze: rileva la compressione, poi entra sulla direzione della prima rottura confermata (close oltre la banda). Onesto. Sweep.'],

  // F. cross-asset / relative
  ['btc_leadlag','cross','BTC lead-lag: il rendimento di BTC alla barra i predice ETH alla barra i+1. Entra ETH a close[i] nella direzione del segnale BTC (solo dati fino a i). Sweep soglia/horizon.'],
  ['ethbtc_ratio_revert','cross','Reversione del ratio ETH/BTC: quando il log-ratio devia >z*sigma dalla sua media, prendi posizione DIREZIONALE su ETH (long ETH se ratio depresso). Sweep n/z.'],
  ['eth_beta_residual','cross','Residuo beta: regredisci ETH su BTC (beta rolling causale), fada il residuo (ETH ricco/povero vs BTC). Posizione direzionale ETH. Sweep finestra.'],
  ['btc_trend_eth_fade','cross','Fade ETH SOLO quando BTC e in range (gia simile a btc_regime_fade ma qui il gate e la pendenza EMA di BTC + la sua DVOL). Combina due gate BTC.'],
  ['eth_vs_basket_mom','cross','Cross-sectional: ETH momentum relativo vs basket (BTC,BNB,SOL,XRP). Long ETH se sovra-performa il basket di recente (continuazione) o sotto-performa (reversione) — testa entrambe.'],
  ['funding_spread','cross','Spread di funding ETH-BTC (regime_lab): quando il funding di ETH e estremo vs BTC, prendi posizione di reversione su ETH. Sweep.'],

  // G. ML / shape
  ['sh01_logit_eth','ml','LogisticRegression stile SH01 su ETH: 17 feature di forma (body/shadow, rendimenti, pendenza, curvatura, pos max/min, RSI, estensione) su W24, predice segno a H12, walk-forward causale, entra se proba>0.58. Riusa scripts.analysis.shape_ml_research se possibile. ETH-specifico.'],
  ['analog_knn_eth','ml','Analog kNN sulla forma (shape_lab.analog_entries) su ETH: W/H/K sweep stretto, agree>0.6. Causale (KDTree ribuilt). Valuta come diversificatore.'],
  ['gbm_features_eth','ml','GradientBoostingClassifier walk-forward su feature ingegnerizzate (RSI, ATR-norm returns, distance-from-EMA, vol, Donchian-pos) per predire il segno a H barre. Train solo sul passato. Sweep H/threshold.'],
  ['logit_regime_mom','ml','LogReg walk-forward su feature di regime+momentum (DVOL, funding, ER, rendimenti multi-h) per predire direzione ETH a H. Da regime_lab. Sweep.'],
  ['rf_direction','ml','RandomForest walk-forward direzione ETH su feature tecniche. Train espandente. Sweep n_estimators/H/threshold. Onesto (no leakage temporale).'],
  ['ridge_return_sign','ml','Ridge regression walk-forward che prevede il rendimento a H barre; entra sul segno se |pred|>soglia. Feature: lag returns, RSI, ATR, distance-EMA. Sweep.'],

  // H. microstruttura / calendario
  ['intraday_seasonality','micro','Stagionalita oraria: trova le ore UTC con edge di reversione/continuazione su ETH (split-half per evitare overfit), trada solo quelle. Onesto su OOS.'],
  ['gap_fade','micro','Gap fade: quando una barra apre/chiude con un gap >k*ATR vs la precedente, fada il gap (reversione). Sweep k.'],
  ['hourofday_fade','micro','Fade Donchian condizionato all ora del giorno: attiva la fade solo nelle ore storicamente mean-reverting. Verifica OOS (rischio overfit alto: sii severo).'],
  ['dayofweek','micro','Effetto giorno-della-settimana su ETH: posizioni condizionate al weekday (es. weekend illiquido). Severo su OOS (probabile rumore).'],
  ['funding_settlement','micro','Timing settlement funding (00/08/16 UTC): fade del movimento attorno al settlement (over-reaction pre/post funding). Sweep finestra.'],
  ['large_candle_reversal','micro','Reversione dopo candela estesa: se |close-open|>k*ATR (barra-shock), entra contro alla chiusura della barra successiva. Sweep k.'],
  ['three_bar_reversal','micro','Pattern 3-barre: 3 chiusure consecutive nello stesso verso poi entra contro (esaurimento). Sweep n-barre/soglia.'],
  ['consecutive_exhaustion','micro','N candele rosse consecutive -> long (e speculare). Conta le streak causalmente, entra all N-esima. Sweep N. TP a media, SL ATR.'],

  // I. combinazioni / ensemble
  ['donchian_rsi_confirm','combo','Donchian fade CON conferma RSI (long solo se RSI<40 oltre alla rottura del canale): doppia conferma per ridurre i falsi segnali nei trend.'],
  ['bb_donchian_confluence','combo','Confluenza Bollinger + Donchian: fada solo quando ENTRAMBE le bande sono rotte simultaneamente (segnale piu forte, meno frequente, meno whipsaw).'],
  ['volspike_fade','combo','Fade solo su spike di volume (volume>media*k): la capitolazione su volume rimbalza meglio del drift silenzioso. Sweep k.'],
  ['funding_tailwind_fade','combo','Donchian fade con vento di funding: fada gli short (entra long) solo se funding positivo (i long pagano = pressione di unwind ribassista esaurita) e viceversa. Da regime_lab.'],
  ['regime_switch_classifier','combo','Classificatore di regime (trend vs range via ADX/ER/Hurst) che decide SE fadare o trend-followare ad ogni barra: una sola strategia adattiva. Sweep soglie del classificatore.'],
  ['vote_ensemble_mr','combo','Ensemble a voto di 3 segnali MR indipendenti (Bollinger, Donchian, z-return): entra solo se >=2 concordano sulla direzione. Riduce i falsi.'],
  ['adaptive_donchian','combo','Donchian a lookback ADATTIVO: n scalato sulla vol (canale piu lungo in alta-vol, piu corto in bassa-vol). Sweep mapping vol->n.'],

  // J. statistico-robusto
  ['ou_halflife','stat','Ornstein-Uhlenbeck: stima half-life e media di reversione (rolling, causale), entra quando la deviazione dalla media OU supera z*sigma, exit a half-life. Sweep.'],
  ['kalman_meanrev','stat','Kalman filter sul prezzo (livello+trend) come media dinamica; fada la deviazione dal livello stimato. Causale (filtro one-pass). Sweep Q/R.'],
  ['quantile_band_fade','stat','Bande a quantili rolling (5/95 percentile su finestra n) invece di sigma: fada la rottura del quantile, TP al quantile 50. Piu robusto a code fat. Sweep n/quantili.'],
  ['theilsen_residual','stat','Detrend Theil-Sen rolling (pendenza robusta), fada il residuo quando estremo. Sweep finestra.'],
  ['hampel_outlier_fade','stat','Hampel filter: identifica gli outlier (|x-median|>k*MAD) e fada l outlier (reversione). Sweep k/finestra.'],
  ['rollreg_residual_z','stat','Regressione lineare rolling (prezzo~tempo), z del residuo; fada |z|>soglia, TP a residuo 0. Sweep finestra/soglia.'],
  ['dominant_cycle_revert','stat','Stima del ciclo dominante (autocorrelazione/zero-cross rolling), entra in reversione in fase con il ciclo. Causale. Sweep.'],

  // K. ulteriori gate/varianti per arrivare a 112
  ['choppiness_donchian','gated-fade','Choppiness Index + Donchian: fada solo se CI>61.8 (range conclamato). Variante severa di choppiness_gate_fade con soglia fissa Fibonacci. Sweep secondario su n.'],
  ['er_bollinger','gated-fade','Efficiency-Ratio gate su Bollinger fade (non Donchian): fada la banda solo se ER<soglia. Confronta con kaufman_er_gate (li su Donchian).'],
  ['adx_rsi2','combo','ADX<20 (range) come gate per un RSI(2) extreme-revert: solo MR in regime non-trending. Sweep.'],
  ['hurst045_only','gated-fade','Fade attiva SOLO quando rolling-Hurst<0.45 (forte anti-persistenza): regime ultra-mean-reverting. Pochi trade, alta qualita? Verifica esposizione/OOS.'],
  ['dvol_low_fade','gated-fade','Fade ETH solo quando DVOL < mediana (regime calmo): la calma e dove la reversione paga e il whipsaw e raro. Da regime_lab. Sweep soglia.'],
  ['vrp_neg_dvol_low','gated-fade','Replica diretta del finding FR01 su ETH: fade attiva su VRP<0 E DVOL bassa. Da regime_lab. Misura Sharpe/DD/esposizione e decorrelazione.'],
  ['funding_extreme_fade','gated-fade','Carry/funding reversion: quando il funding_z e estremo (>|2|), fada il prezzo nella direzione dell unwind atteso. Da regime_lab. Sweep.'],
  ['range_day_fade','gated-fade','Filtro range-day: fada solo se il range della sessione corrente (rolling 24h) < media*soglia (giornata compressa = reversione affidabile). Sweep.'],
  ['mtf_donchian','combo','Donchian multi-timeframe: ingresso su rottura del canale 1h ma con canale di riferimento 4h (TP al centro del canale 4h). Sweep n1/n4.'],
  ['volweighted_fade','combo','Fade pesata dal volume: ingresso solo se il volume della barra di segnale e nel quartile alto (conferma di partecipazione). Sweep.'],
  ['false_break_fade','mr-alt','Fade del falso breakout: il prezzo rompe il canale Donchian ma la barra SUCCESSIVA chiude di nuovo dentro -> entra contro la rottura a quella chiusura. Onesto. Sweep n.'],
  ['band_walk_exhaustion','mr-alt','Esaurimento del band-walk: dopo k chiusure consecutive fuori dalla banda Bollinger (band walking), fada il rientro alla prima chiusura dentro. Sweep k/sigma.'],
  ['pivot_revert','stat','Reversione ai pivot floor classici (P, R1/R2, S1/S2 calcolati sul giorno precedente): fada il tocco di R2/S2 verso P. Causale (pivot da ieri). Sweep.'],
  ['fractal_swing_revert','stat','Reversione agli swing di Williams (frattali a 5 barre confermati con ritardo): fada il tocco di un nuovo frattale verso la media. Causale (conferma ritardata). Sweep.'],
  ['lrc_fade','stat','Linear Regression Channel: canale di regressione rolling +/- 2 std del residuo; fada il tocco dei bordi verso la linea centrale. Sweep finestra.'],
]

// ---------------------------------------------------------------- esecuzione
phase('Generate')
log(`Lancio ${SPECS.length} agenti, una strategia ETH distinta ciascuno (harness onesto fee-aware OOS)`)

const results = await parallel(SPECS.map(([key, family, idea]) => () =>
  agent(
    `${RECIPE}\n\n========\nLA TUA IDEA — key="${key}", family="${family}":\n${idea}\n\nUsa /tmp/cand_${key}.py come file. Restituisci il risultato strutturato (campi key e family valorizzati con i tuoi).`,
    { label: `gen:${key}`, phase: 'Generate', schema: SCHEMA }
  ).then(r => r ? { ...r, key, family } : null)
))

const ran = results.filter(Boolean)
log(`${ran.length}/${SPECS.length} agenti rientrati. Filtro i survivor per la verifica avversariale.`)

// survivor: ha girato davvero, e o batte la baseline o e' chiaramente interessante
// (OOS Sharpe alto, oppure DD ben piu basso a Sharpe decente), e regge la fee 0.2%.
const survivors = ran.filter(r =>
  r.ran_ok && r.implemented && r.no_lookahead &&
  r.full_ret > 0 && r.oos_ret > 0 && r.fee02_oos > 0 && r.fee02_full > 0 &&
  (
    r.beats_baseline ||
    r.oos_sharpe >= 11.0 ||
    (r.full_dd <= 20.0 && r.oos_sharpe >= 8.0) ||
    (r.full_dd <= 12.0 && r.oos_sharpe >= 5.0)   // diversificatore a basso DD
  )
)

// ordina per una metrica composita: premia OOS Sharpe e penalizza DD
const score = r => r.oos_sharpe - 0.10 * r.full_dd
survivors.sort((a, b) => score(b) - score(a))
const toVerify = survivors.slice(0, 24)   // cap la verifica ai 24 migliori
log(`${survivors.length} survivor; verifico avversarialmente i top ${toVerify.length}`)

phase('Verify')
const VSCHEMA = {
  type: 'object', additionalProperties: false,
  required: ['key','confirmed','reproduced','lookahead_found','overfit_risk','full_sharpe','full_dd','oos_sharpe','oos_dd','beats_mr02eth','note'],
  properties: {
    key: { type: 'string' },
    confirmed: { type: 'boolean', description: 'edge reale, eseguibile, fee-robusto, dopo audit indipendente' },
    reproduced: { type: 'boolean', description: 'ho ri-eseguito e ho ottenuto numeri coerenti (entro ~15%)' },
    lookahead_found: { type: 'boolean' },
    overfit_risk: { type: 'string', enum: ['low','med','high'] },
    full_sharpe: { type: 'number' },
    full_dd: { type: 'number' },
    oos_sharpe: { type: 'number' },
    oos_dd: { type: 'number' },
    beats_mr02eth: { type: 'boolean', description: 'batte davvero MR02/ETH (OOS Sharpe>=~12 a DD<=25, o DD<20 a Sharpe comparabile)' },
    note: { type: 'string' },
  },
}

const verified = await parallel(toVerify.map(r => () =>
  agent(
    `Verifica AVVERSARIALE di una strategia candidata a sostituire MR02/ETH. Lavora in /opt/docker/PythagorasGoal con l'harness onesto scripts.analysis.explore_lab (get_df, simulate, evaluate, robust, atr, ema, rsi). Default: il tuo compito e' SMENTIRE.\n\n${BASELINE}\n\nCandidata key="${r.key}" (family ${r.family}).\nConfig dichiarata: ${r.best_config}\nNumeri dichiarati: full Sharpe ${r.full_sharpe}, OOS Sharpe ${r.oos_sharpe}, full DD ${r.full_dd}%, OOS DD ${r.oos_dd}%, trade ${r.trades}, exposure ${r.exposure}%, fee0.2% full ${r.fee02_full}, fee0.2% OOS ${r.fee02_oos}.\nDescrizione idea: la trovi rifacendola da zero.\n\nRI-IMPLEMENTA tu stesso la strategia (in /tmp/verify_${r.key}.py) sulla SUA config dichiarata, eseguila sull'harness, e controlla: (1) LOOK-AHEAD — l'ingresso/direzione usa solo dati fino a close[i]? Perturba le barre future e verifica che gli entries non cambino. (2) RIPRODUCIBILITA — i numeri tornano entro ~15%? (3) ROBUSTEZZA/OVERFIT — regge a fee 0.20% RT, a piccole variazioni dei parametri (plateau, non picco isolato), ed e' positiva nella maggior parte degli anni 2021+? (4) batte DAVVERO MR02/ETH (OOS Sharpe e/o DD)?\n\nSe non riesci a riprodurre o trovi look-ahead, confirmed=false. Riporta i TUOI numeri ri-eseguiti, non quelli dichiarati. Sii severo: meglio bocciare un falso positivo che promuovere un artefatto.`,
    { label: `verify:${r.key}`, phase: 'Verify', schema: VSCHEMA }
  ).then(v => v ? { ...v, key: r.key, family: r.family, gen: r } : null)
))

const vok = verified.filter(Boolean)
const confirmed = vok.filter(v => v.confirmed && !v.lookahead_found && v.beats_mr02eth)
confirmed.sort((a, b) => (b.oos_sharpe - 0.1 * b.full_dd) - (a.oos_sharpe - 0.1 * a.full_dd))

log(`Verifica completata: ${confirmed.length} confermati che battono MR02/ETH`)

return {
  n_specs: SPECS.length,
  n_ran: ran.length,
  n_survivors: survivors.length,
  n_verified: vok.length,
  n_confirmed: confirmed.length,
  confirmed,
  all_survivors: survivors.map(s => ({ key: s.key, family: s.family, best_config: s.best_config,
    full_sharpe: s.full_sharpe, full_dd: s.full_dd, oos_sharpe: s.oos_sharpe, oos_dd: s.oos_dd,
    exposure: s.exposure, trades: s.trades, fee02_oos: s.fee02_oos, verdict: s.verdict, note: s.note })),
  verified: vok.map(v => ({ key: v.key, confirmed: v.confirmed, reproduced: v.reproduced,
    lookahead_found: v.lookahead_found, overfit_risk: v.overfit_risk, beats_mr02eth: v.beats_mr02eth,
    full_sharpe: v.full_sharpe, full_dd: v.full_dd, oos_sharpe: v.oos_sharpe, oos_dd: v.oos_dd, note: v.note })),
}
