24565974c0
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>
89 lines
4.2 KiB
Python
89 lines
4.2 KiB
Python
"""verify_intra — adversarial gauntlet on the intraday orthogonal combo, the SAME tests
|
|
that killed the ortho relative-value wave. Does the low-turnover intraday combo survive?
|
|
1. in-sample (pre-2025) standalone Sharpe + per-cut uplift (is it pre-2025 real or 2025-only?)
|
|
2. WALK-FORWARD selection (pick orthogonal positive-uplift signals on PAST data, test forward)
|
|
3. drop-one-mechanism (carried by one signal?)
|
|
4. fee stress to 0.30% RT
|
|
"""
|
|
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"
|
|
ORTHO = ["agent_05_open_drive", "agent_09_prevday_range_breakout", "agent_06_vol_event_revert_15m",
|
|
"agent_07_volume_spike_revert", "agent_08_gap_fill"]
|
|
|
|
|
|
def _t(name):
|
|
p = AG/f"{name}.py"; s = importlib.util.spec_from_file_location(name, 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="2018-01-01", end=None, w=0.25):
|
|
J = pd.concat({"B": B, "C": c}, axis=1, join="inner").dropna(); J = J[J.index >= pd.Timestamp(cut, tz="UTC")]
|
|
if end: J = J[J.index < pd.Timestamp(end, tz="UTC")]
|
|
return _sh((1-w)*J["B"]+w*J["C"]) - _sh(J["B"]) if len(J) > 30 else float("nan")
|
|
|
|
|
|
def daily(name, fee=al.FEE_SIDE):
|
|
tf = "15m" if "_15m" in name else "1h"
|
|
return al.candidate_daily(_t(name), tf=tf, fee_side=fee)
|
|
|
|
|
|
def main():
|
|
B = al.tp01_baseline_daily()
|
|
dl = {n: daily(n) for n in ORTHO}
|
|
M = pd.concat(dl, axis=1, join="inner").dropna()
|
|
combo = M.mean(axis=1)
|
|
H = pd.Timestamp("2025-01-01", tz="UTC")
|
|
ci = combo[combo.index < H]
|
|
print(f"\n COMBO standalone Sharpe full {_sh(combo):.2f} PRE-2025 {_sh(ci):.2f} corrTP {pd.concat({'b':B,'c':combo},axis=1,join='inner').dropna().corr().iloc[0,1]:.2f}")
|
|
print(f" per-cut uplift: " + " ".join(f"{c[:4]} {_u(combo,B,c):+.2f}" for c in ["2021-01-01","2022-01-01","2023-01-01","2024-01-01","2025-01-01"]))
|
|
# pre-2025-only uplift (exclude the suspect window entirely)
|
|
pre = pd.concat({"B": B, "C": combo}, axis=1, join="inner").dropna(); pre = pre[pre.index < H]
|
|
print(f" PRE-2025 ONLY uplift (2018->2025): {_sh(0.75*pre['B']+0.25*pre['C'])-_sh(pre['B']):+.3f}")
|
|
|
|
print("\n WALK-FORWARD SELECTION (pick orthogonal +uplift signals on PAST only, test fwd):")
|
|
ALL = sorted(p.stem for p in AG.glob("agent_*.py"))
|
|
dlall = {}
|
|
for n in ALL:
|
|
try: dlall[n] = daily(n)
|
|
except Exception: pass
|
|
for sel_end in ["2023-01-01", "2024-01-01"]:
|
|
picks = []
|
|
for n, d in dlall.items():
|
|
up = _u(d, B, "2018-01-01", sel_end)
|
|
cc = pd.concat({"b": B, "c": d}, axis=1, join="inner").dropna()
|
|
cc = cc[cc.index < pd.Timestamp(sel_end, tz="UTC")]
|
|
corr = abs(cc.corr().iloc[0, 1]) if len(cc) > 30 else 1
|
|
if not np.isnan(up) and up > 0.05 and corr < 0.4:
|
|
picks.append(n)
|
|
if picks:
|
|
cb = pd.concat({n: dlall[n] for n in picks}, axis=1, join="inner").dropna().mean(axis=1)
|
|
print(f" select<{sel_end}: {len(picks)} picks {[p.replace('agent_','')[:12] for p in picks]}")
|
|
print(f" -> FORWARD uplift {sel_end}->now: {_u(cb, B, sel_end):+.3f}")
|
|
else:
|
|
print(f" select<{sel_end}: no qualifying picks")
|
|
|
|
print("\n DROP-ONE-MECHANISM (full & pre-2025 uplift):")
|
|
for drop in ORTHO:
|
|
keep = [n for n in ORTHO if n != drop]
|
|
cb = M[keep].mean(axis=1)
|
|
pr = pd.concat({"B": B, "C": cb}, axis=1, join="inner").dropna(); pr = pr[pr.index < H]
|
|
print(f" -{drop.replace('agent_',''):<26} full {_u(cb,B):+.3f} pre2025 {_sh(0.75*pr['B']+0.25*pr['C'])-_sh(pr['B']):+.3f}")
|
|
|
|
print("\n FEE STRESS (combo):")
|
|
for fee in [0.0005, 0.001, 0.0015]:
|
|
cb = pd.concat({n: daily(n, fee) for n in ORTHO}, axis=1, join="inner").dropna().mean(axis=1)
|
|
print(f" {2*fee*100:.2f}%RT: standalone Sh {_sh(cb):.2f} uplift_full {_u(cb,B):+.3f}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|