"""XM02 — Multi-L z-blend momentum
Score = mean of xs_zscore(past_return(close, L)) over a set of lookback windows L.
Compare two window sets: {30,90} (XS01-like) vs {20,60,120} (extended).
Grid: 5 study_xs calls total — vary universe / windows / H.
"""
import sys
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/xsec")
import xslib as xs
import numpy as np

# ── score helpers ─────────────────────────────────────────────────────────────

def blend_mom(close, lookbacks):
    """Mean of xs_zscore(past_return(close, L)) for each L in lookbacks."""
    scores = [xs.xs_zscore(xs.past_return(close, L)) for L in lookbacks]
    stacked = np.stack(scores, axis=2)          # (n_days, n_assets, n_L)
    return np.nanmean(stacked, axis=2)           # (n_days, n_assets)


L_SHORT  = [30, 90]            # mirrors XS01 blend
L_LONG   = [20, 60, 120]       # extended set
L_WIDE   = [20, 60, 90, 120]   # even wider blend

# ── 5 backtests ───────────────────────────────────────────────────────────────

results = []

# 1. XS01-equivalent blend {30,90} on ALL universe — baseline reference
rep1 = xs.study_xs(
    "XM02-3090-all",
    lambda P: blend_mom(P.close, [30, 90]),
    universe="all", H=10, k=5, long_short=True,
)
print(xs.fmt(rep1))
results.append(rep1)

# 2. Extended blend {20,60,120} on ALL universe
rep2 = xs.study_xs(
    "XM02-206012-all",
    lambda P: blend_mom(P.close, [20, 60, 120]),
    universe="all", H=10, k=5, long_short=True,
)
print(xs.fmt(rep2))
results.append(rep2)

# 3. Extended blend {20,60,120} on MAJORS (19 alts — XS01 universe)
rep3 = xs.study_xs(
    "XM02-206012-majors",
    lambda P: blend_mom(P.close, [20, 60, 120]),
    universe="majors", H=10, k=5, long_short=True,
)
print(xs.fmt(rep3))
results.append(rep3)

# 4. Wide blend {20,60,90,120} on ALL, shorter rebalance H=5
rep4 = xs.study_xs(
    "XM02-wide-H5-all",
    lambda P: blend_mom(P.close, [20, 60, 90, 120]),
    universe="all", H=5, k=5, long_short=True,
)
print(xs.fmt(rep4))
results.append(rep4)

# 5. Wide blend on ALL, longer H=20 (less turnover)
rep5 = xs.study_xs(
    "XM02-wide-H20-all",
    lambda P: blend_mom(P.close, [20, 60, 90, 120]),
    universe="all", H=20, k=5, long_short=True,
)
print(xs.fmt(rep5))
results.append(rep5)

# ── pick BEST by: earns_slot > hold-out sharpe > distinctness ────────────────

def _score(r):
    earns   = 1 if r["earns_slot"] else 0
    verdict = 1 if r["marginal"].get("verdict") == "ADDS" else 0
    hold_sh = r["holdout"].get("sharpe", -99)
    full_sh = r["full"]["sharpe"]
    dist    = 1 if (r["corr_xs01"] or 1.0) < 0.6 else 0
    return (earns, verdict, hold_sh, full_sh, dist)

best = max(results, key=_score)

print("\n" + "=" * 60)
print("BEST CONFIG:")
print(xs.fmt(best))
print("JSON:", xs.as_json(best))
