"""XM06 — 52-day-high proximity (closeness-to-recent-high momentum). IDEA: Score = close / rolling_max(high, W) [closeness to recent high]. Assets near their recent high are "in momentum"; rank them cross-sectionally. W in {60, 90}. Causal: rolling_max up through bar i only. Grid: 5 calls max 1. W=60, majors, H=10, k=5, L/S 2. W=90, majors, H=10, k=5, L/S 3. W=60, all, H=10, k=5, L/S (best-W on wider universe) 4. W=60, all, H=5, k=5, L/S (faster rebalance) 5. W=60, all, H=10, k=7, L/S (wider book) """ import sys sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/xsec") import xslib as xs import numpy as np def score_proximity(P, W): """Causal: close[i] / max(high[i-W+1 .. i]). Higher = closer to recent high = long.""" n, A = P.close.shape out = np.full((n, A), np.nan) # rolling max of high, causal window [i-W+1 .. i] high_df = __import__("pandas").DataFrame(P.high) roll_max = high_df.rolling(W, min_periods=max(2, W // 2)).max().values # proximity ratio: close / recent_high (always in (0,1] if no gap-up above window) out = P.close / roll_max return out # ---- run grid ---- results = [] # 1. W=60, majors, H=10, k=5, L/S rep1 = xs.study_xs("XM06_W60_majors", lambda P: score_proximity(P, 60), universe="majors", H=10, k=5, long_short=True) print(xs.fmt(rep1)) results.append(rep1) # 2. W=90, majors, H=10, k=5, L/S rep2 = xs.study_xs("XM06_W90_majors", lambda P: score_proximity(P, 90), universe="majors", H=10, k=5, long_short=True) print(xs.fmt(rep2)) results.append(rep2) # 3. W=60, all, H=10, k=5, L/S rep3 = xs.study_xs("XM06_W60_all", lambda P: score_proximity(P, 60), universe="all", H=10, k=5, long_short=True) print(xs.fmt(rep3)) results.append(rep3) # 4. W=60, all, H=5, k=5, L/S (faster rebalance) rep4 = xs.study_xs("XM06_W60_all_H5", lambda P: score_proximity(P, 60), universe="all", H=5, k=5, long_short=True) print(xs.fmt(rep4)) results.append(rep4) # 5. W=60, all, H=10, k=7, L/S (wider book) rep5 = xs.study_xs("XM06_W60_all_k7", lambda P: score_proximity(P, 60), universe="all", H=10, k=7, long_short=True) print(xs.fmt(rep5)) results.append(rep5) # ---- pick best by: earns_slot > hold-out sharpe > distinctness ---- def score_result(r): earns = 1 if r["earns_slot"] else 0 adds = 1 if r["marginal"].get("verdict") == "ADDS" else 0 hold_sh = r["holdout"].get("sharpe", -999) full_sh = r["full"]["sharpe"] corr_xs01 = abs(r.get("corr_xs01") or 1.0) distinct = 1 if corr_xs01 < 0.6 else 0 return (earns, adds, hold_sh, full_sh, distinct) best = max(results, key=score_result) print("\n=== BEST CONFIG ===") print(xs.fmt(best)) print("JSON:", xs.as_json(best))