research(crypto): 4 filoni 2026-06-29 — ERM lead sub-daily (forward), 3 scartati/deboli

Ricerca onesta su BTC/ETH + universo HL, branch separato (nessun impatto live).
Harness condiviso altlib (causale, fee 0.10% RT, marginal vs TP01, day-boundary,
haircut $600). Test 19/19 verdi.

- A DVOL direzionale  -> LEAD hedge/DD-dampener, NON sleeve (buy-the-fear; is_hedge).
- B Intraday ERM 8h   -> LEAD forte / forward-monitor: earns_slot=True, ADDS oltre
                         SKH01 (TP01+SKH+ERM 60/25/15 FULL 1.88/HOLD 1.46/DD 8.9%).
                         Caveat: plateau hold-out single-row, multiple-testing non
                         deflazionato, exec 8h. Controllo TOD = FAIL atteso.
- C Cross-sectional non-mom (low-vol HL) -> DEBOLE/forward-monitor (deflated-Sh 0.13,
                         storia 2.5a, non eseguibile $600) STAT-MODE.
- D Macro regime-gate -> RIDONDANTE col trend (corr->TP01 0.989), SCARTATO.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-29 19:48:36 +00:00
parent a158d0e2ae
commit aad69f9790
12 changed files with 2283 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
"""Test del filone B — INTRADAY REGIME (scripts/research/intraday_regime.py).
Verifica leggera e veloce (un solo asset) che:
* i target factory producano array della lunghezza giusta e CAUSALI (no look-ahead);
* il meccanismo ERM (efficiency-ratio regime momentum) sia long/short di natura;
* la cella canonica ERM 8h L=2 thr=0.35 abbia Sharpe FULL positivo netto fee (sanity dell'edge).
NB: NON costruisce la baseline TP01/SKH01 (lento) — quello e' nello script di ricerca.
"""
import sys
import importlib.util
import numpy as np
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
import altlib as al # noqa: E402
_spec = importlib.util.spec_from_file_location(
"intraday_regime", "/opt/docker/PythagorasGoal/scripts/research/intraday_regime.py")
ir = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(ir)
def test_erm_target_shape_and_ls():
df = al.get("BTC", "8h")
tgt = ir.make_erm(tf="8h", L_days=2.0, thr=0.35, long_flat=False)(df)
assert len(tgt) == len(df)
assert np.isfinite(tgt).all()
# L/S: deve esistere sia esposizione long sia short (non e' long-only)
assert (tgt > 0).any() and (tgt < 0).any()
# long_flat=True -> nessuno short
tgt_lf = ir.make_erm(tf="8h", L_days=2.0, thr=0.35, long_flat=True)(df)
assert (tgt_lf >= -1e-9).all()
def test_erm_causal_no_leak():
# causality_ok ricalcola il target su prefissi troncati e pretende che la coda combaci
res = al.causality_ok(ir.make_erm(tf="8h", L_days=2.0, thr=0.35, long_flat=False),
tf="8h", assets=("BTC",))
assert res["ok"], f"look-ahead in ERM: {res}"
def test_erm_winner_positive_full_sharpe():
fn = ir.make_erm(tf="8h", L_days=2.0, thr=0.35, long_flat=False)
for a in ("BTC", "ETH"):
df = al.get(a, "8h")
ev = al.eval_weights(df, fn(df), fee_side=0.0005) # 0.10% RT
assert ev["full"]["sharpe"] > 0.5, f"{a} full Sharpe {ev['full']['sharpe']}"
def test_vbr_and_tod_causal():
for fn in (ir.make_vbr(tf="8h", k=1.0, atr_win=14, long_flat=False),
ir.make_tod(tf="1h", long_flat=True)):
res = al.causality_ok(fn, tf=("8h" if fn is not None else "1h"),
assets=("BTC",)) if False else None
# VBR causale (8h) e TOD causale (1h), un asset per velocita'
assert al.causality_ok(ir.make_vbr(tf="8h", k=1.0, atr_win=14, long_flat=False),
tf="8h", assets=("BTC",))["ok"]
assert al.causality_ok(ir.make_tod(tf="1h", long_flat=True),
tf="1h", assets=("BTC",))["ok"]