"""Valida il CrossSectionalWorker: replay bar-per-bar == backtest XS01.xsec_sim? Come validate_worker_pairs: alimenta il worker con finestre trailing crescenti del pannello 8-asset e confronta capitale finale e n.trade col backtest di riferimento scripts.strategies.XS01_cross_sectional.xsec_sim. Se combaciano, la semantica live e' fedele. """ from __future__ import annotations import shutil import sys import tempfile from pathlib import Path import pandas as pd PROJECT_ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(PROJECT_ROOT)) from src.live.xsec_worker import CrossSectionalWorker from scripts.strategies.XS01_cross_sectional import aligned_panel, xsec_sim, UNIVERSE, LB, HOLD def main(): print("=" * 88) print(" VALIDAZIONE CrossSectionalWorker — replay live vs backtest xsec_sim (fee 0.10% RT/book)") print("=" * 88) M = aligned_panel(UNIVERSE) dfs = {a: pd.DataFrame({"timestamp": M.index.values, "close": M[a].values}) for a in UNIVERSE} n = len(M) tmp = Path(tempfile.mkdtemp(prefix="xsec_val_")) try: w = CrossSectionalWorker(UNIVERSE, tf="1h", params={"lb": LB, "hold": HOLD}, fee_rt=0.0005, data_dir=tmp) w._save = lambda: None; w._log = lambda *a, **k: None; w._notify = lambda *a, **k: None window = LB + 6 for k in range(LB + 1, n + 1): # prima finestra = lb+1 barre -> ingresso al bar lb lo = max(0, k - window) w.tick({a: dfs[a].iloc[lo:k] for a in UNIVERSE}) bt = xsec_sim(UNIVERSE) bt_cap = 1000.0 * (1 + bt["ret"] / 100) cap_ok = abs(w.capital - bt_cap) / bt_cap < 0.02 if bt_cap else False trd_ok = abs(w.total_trades - bt["trades"]) <= max(2, bt["trades"] * 0.02) ww = w.total_wins / w.total_trades * 100 if w.total_trades else 0 print(f"\n {'':<6}{'cap':>14}{'trades':>8}{'win%':>7}") print(f" WORKER{w.capital:>14.0f}{w.total_trades:>8d}{ww:>7.1f}") print(f" BCKTST{bt_cap:>14.0f}{bt['trades']:>8d}{bt['win']:>7.1f}") print(f"\n ESITO: {'OK (replay == backtest)' if (cap_ok and trd_ok) else 'DIFF -> INDAGARE'}") print(" (diff minime attese da bar finale aperta / troncamento)") finally: shutil.rmtree(tmp, ignore_errors=True) if __name__ == "__main__": main()