research(intraday): asse intraday/microstruttura — lead più vicino al reale ma NON deployabile
16 agenti su segnali low-turnover intraday (sessione/funding, reversione post-evento, breakout range del giorno prima) su feed certificati 1h/15m, giudice = marginal scorer indurito + fee-sweep. Lab: intra_score.py (wrappa study_marginal a TF scelto + turnover/fee), meta_intra.py (corr-TP01 + per-cut), verify_intra.py (walk-forward + in-sample-null + drop-one + fee-stress). Esito: 10/16 "earns_slot" -> 5 genuinamente ortogonali (corr<0.4). Combo dei 5: Sharpe 1.80, corr 0.17, leak-free, passa walk-forward (+0.30/+0.37 dove l'ortho dava -0.07), pre-2025 uplift +0.28, drop-one e fee-robusto. Sembrava IL lead. 3 scettici: (1) open_drive = ARTEFATTO etichettatura UTC (shift confine 4h -> uplift negativo); prevday_range_breakout REGGE (unico onesto, eseguibile). (2) combo fallisce il null a corr-zero (20-24° pctl: aggiunge meno del rumore), è HEDGE (corr -0.57..-0.80 a Sharpe-TP01) + tail-luck (80% PnL in top-5 giorni delle gambe revert). (3) robust-plateau ma null-pctl 0.20 = diversificazione di stream ortogonale, non timing-alpha; + finzione fee micro-ribilanciamento a $600. Verdetto: niente in live, resta solo TP01. Lead forward-monitor: prevday_range_breakout. Lezioni harness da codificare: test shift-confine-giorno (artefatti calendar), fee discretizzata a piccolo capitale, causality guard nel lab intraday. Diario 2026-06-21-intraday-microstructure.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""meta_intra — orchestrator read on the intraday 'earns_slot' set. Like the ortho wave:
|
||||
10 'slots' cannot be 10 alphas. Compute corr-to-TP01 (the hardened scorer passes a high
|
||||
in-sample Sharpe even when it is borrowed trend-beta), mutual correlation, and per-cut
|
||||
uplift, to separate GENUINELY ORTHOGONAL low-turnover intraday signals from trend-in-disguise.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import importlib.util, sys
|
||||
from pathlib import Path
|
||||
import numpy as np, pandas as pd
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
|
||||
import altlib as al # noqa: E402
|
||||
AG = HERE / "agents"
|
||||
CUTS = ["2021-01-01", "2022-01-01", "2023-01-01", "2024-01-01", "2025-01-01"]
|
||||
|
||||
|
||||
def _target(p):
|
||||
s = importlib.util.spec_from_file_location(p.stem, p); m = importlib.util.module_from_spec(s); s.loader.exec_module(m); return m.target
|
||||
|
||||
|
||||
def _sh(s):
|
||||
r = np.asarray(s.dropna().values, float); return float(np.mean(r)/np.std(r)*np.sqrt(365.25)) if len(r) > 2 and np.std(r) > 0 else 0.0
|
||||
|
||||
|
||||
def _u(c, B, cut, w=0.25):
|
||||
J = pd.concat({"B": B, "C": c}, axis=1, join="inner").dropna(); J = J[J.index >= pd.Timestamp(cut, tz="UTC")]
|
||||
return _sh((1-w)*J["B"]+w*J["C"]) - _sh(J["B"]) if len(J) > 30 else float("nan")
|
||||
|
||||
|
||||
def main():
|
||||
import json
|
||||
lb = json.loads((HERE/"intra_leaderboard.json").read_text())
|
||||
slots = [r["name"] for r in lb if r.get("earns_slot")]
|
||||
B = al.tp01_baseline_daily()
|
||||
daily = {}
|
||||
for name in slots:
|
||||
p = AG/f"{name}.py"; tf = "15m" if "_15m" in name else "1h"
|
||||
try:
|
||||
daily[name.replace("agent_", "")] = al.candidate_daily(_target(p), tf=tf)
|
||||
except Exception as e:
|
||||
print(f" skip {name}: {e}")
|
||||
names = list(daily)
|
||||
M = pd.concat(daily, axis=1, join="inner").dropna()
|
||||
corrTP = {n: round(float(pd.concat({"B": B, "C": daily[n]}, axis=1, join="inner").dropna().corr().iloc[0, 1]), 2) for n in names}
|
||||
print(f"\n INTRADAY earns_slot set ({len(names)}) — corr to TP01 & per-cut uplift")
|
||||
print(f" {'signal':<26}{'corrTP':>7} per-cut uplift " + " ".join(c[:4] for c in CUTS))
|
||||
for n in sorted(names, key=lambda x: corrTP[x]):
|
||||
ups = [_u(daily[n], B, c) for c in CUTS]
|
||||
tag = "ORTHO" if abs(corrTP[n]) < 0.4 else ("trend-beta" if corrTP[n] > 0.6 else "mixed")
|
||||
print(f" {n:<26}{corrTP[n]:>7} " + " ".join(f"{u:>+5.2f}" for u in ups) + f" [{tag}]")
|
||||
print(f"\n mutual corr among the LOW-corr (<0.4 to TP01) ones:")
|
||||
ortho = [n for n in names if abs(corrTP[n]) < 0.4]
|
||||
if len(ortho) >= 2:
|
||||
print(M[ortho].corr().round(2).to_string())
|
||||
# combined equal-weight of the orthogonal ones
|
||||
if ortho:
|
||||
combo = M[ortho].mean(axis=1)
|
||||
print(f"\n ORTHO combo ({len(ortho)}): standalone Sh {_sh(combo):.2f} corrTP {float(pd.concat({'B':B,'C':combo},axis=1,join='inner').dropna().corr().iloc[0,1]):.2f}")
|
||||
print(" per-cut uplift: " + " ".join(f"{_u(combo,B,c):+.2f}" for c in CUTS))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user