"""XD02 — High-skew momentum (POSITIVE sign). Mechanism: Score = +roll_skew(ret, 60). Idea: positive skew = right-tailed distribution = asset had big up-moves. Does positive skew predict cross-sectional outperformance in crypto alts? (XD01 tested negative skew; this tests the opposite hypothesis.) Grid (<= 5 runs): 1. majors, H=10, k=5, LS (baseline) 2. all, H=10, k=5, LS (wider universe) 3. majors, H=5, k=5, LS (faster rebalance) 4. majors, H=10, k=5, LS, win=30 (shorter lookback) 5. majors, H=10, k=3, LS (concentrated book) """ import sys sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/xsec") import xslib as xs import numpy as np # Score: positive rolling skewness of daily returns # Higher skew -> more right-tailed -> long this asset def score_skew(P, win=60): return xs.roll_skew(P.ret, win) print("=" * 60) print("XD02 — HIGH-SKEW MOMENTUM (positive sign, does positive skew pay?)") print("=" * 60) # Run 1: majors, H=10, k=5, LS, win=60 r1 = xs.study_xs("XD02-MJ-H10-k5-w60", lambda P: score_skew(P, 60), universe="majors", H=10, k=5, long_short=True) print(xs.fmt(r1)) print("JSON:", xs.as_json(r1)) print() # Run 2: all universe, H=10, k=5, LS, win=60 r2 = xs.study_xs("XD02-ALL-H10-k5-w60", lambda P: score_skew(P, 60), universe="all", H=10, k=5, long_short=True) print(xs.fmt(r2)) print("JSON:", xs.as_json(r2)) print() # Run 3: majors, H=5, k=5, LS, win=60 (faster rebalance) r3 = xs.study_xs("XD02-MJ-H5-k5-w60", lambda P: score_skew(P, 60), universe="majors", H=5, k=5, long_short=True) print(xs.fmt(r3)) print("JSON:", xs.as_json(r3)) print() # Run 4: majors, H=10, k=5, LS, win=30 (shorter lookback) r4 = xs.study_xs("XD02-MJ-H10-k5-w30", lambda P: score_skew(P, 30), universe="majors", H=10, k=5, long_short=True) print(xs.fmt(r4)) print("JSON:", xs.as_json(r4)) print() # Run 5: majors, H=10, k=3, LS, win=60 (concentrated) r5 = xs.study_xs("XD02-MJ-H10-k3-w60", lambda P: score_skew(P, 60), universe="majors", H=10, k=3, long_short=True) print(xs.fmt(r5)) print("JSON:", xs.as_json(r5)) print() # Select best by: earns_slot > holdout sharpe > corr_xs01 (lower is better) results = [r1, r2, r3, r4, r5] earners = [r for r in results if r["earns_slot"]] if earners: best = max(earners, key=lambda r: r["holdout"].get("sharpe", 0)) else: # fallback: highest holdout + positive full, then lowest xs01 corr pos = [r for r in results if r["full"]["sharpe"] > 0 and r["holdout"].get("sharpe", 0) > 0] if pos: best = max(pos, key=lambda r: r["holdout"].get("sharpe", 0) - abs(r.get("corr_xs01") or 0)) else: best = max(results, key=lambda r: r["holdout"].get("sharpe", -99)) print("=" * 60) print("BEST CONFIG:") print(xs.fmt(best)) print("JSON:", xs.as_json(best))