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:
@@ -0,0 +1,376 @@
|
||||
"""intraday_regime.py — FILONE B: "INTRADAY REGIME BTC/ETH" (eseguibile) — 2026-06-29.
|
||||
|
||||
TESI. Cercare un meccanismo SUB-DAILY sui dati certificati 1h/4h/.../12h BTC/ETH che sia
|
||||
ORTOGONALE sia a TP01 (TSMOM trend daily, long-flat) sia a SKH01 (regime BuzVola/BuzVolume
|
||||
+ Donchian breakout a 230m). SKH01 prova che il sub-daily PUO' funzionare ed essere
|
||||
quasi-ortogonale: qui si esplora un MECCANISMO DIVERSO, basato sulla QUALITA' del moto
|
||||
intraday (efficiency-ratio / vol-expansion / thrust) come REGIME che condiziona una
|
||||
posizione direzionale tenuta ~1 giorno.
|
||||
|
||||
Il killer ricorrente del progetto sotto le 12h e' il MURO-FEE (0.10% RT) + overfitting.
|
||||
La ricetta che SKH01 usa per sopravvivere: DECISIONE sub-daily ma HOLD ~1 giorno -> pochi
|
||||
trade -> la fee non uccide. Qui ogni meccanismo e' costruito per essere a basso turnover
|
||||
(gate di regime che tiene flat la maggior parte del tempo, lookback non microscopici) e
|
||||
viene giudicato col fee-sweep ALLA SUA FREQUENZA REALE. Se muore appena si mette la fee ->
|
||||
SCARTATO e documentato (e' un risultato valido).
|
||||
|
||||
MECCANISMI (tutti come posizione CONTINUA decisa <= close[i], cosi' passano nativamente per
|
||||
eval_weights / study_marginal / day_boundary_robust / eval_weights_smallcap di altlib):
|
||||
|
||||
ERM Efficiency-Ratio regime momentum. ER = |moto netto su L barre| / |percorso| (Kaufman):
|
||||
alto = moto intraday "pulito"/direzionale, basso = chop. Prendi la direzione del moto
|
||||
netto SOLO quando ER >= soglia (regime trendy intraday), altrimenti flat. Vol-target.
|
||||
Storia economica: quando il prezzo intraday e' EFFICIENTE il momentum continua; quando
|
||||
e' choppy non c'e' edge. DIVERSO da SKH01 (regime vol/volume) e da TP01 (TSMOM 1-6 mesi).
|
||||
|
||||
VEM Vol-Expansion Momentum. Direzione = segno del moto su Lmom barre, ATTIVA solo quando la
|
||||
vol realizzata corta > vol realizzata lunga (espansione di volatilita'). Vol-target.
|
||||
|
||||
VBR Volatility/thrust breakout (Larry-Williams-style, ROLLING, no calendario). Segui solo i
|
||||
movimenti significativi: posizione = segno(c[i]-c[i-1]) quando |Δ| > k*ATR, altrimenti
|
||||
tieni la precedente. Momentum-continuation di thrust.
|
||||
|
||||
TOD Time-of-day seasonality (CONTROLLO calendario). Direzione per ora-del-giorno via media
|
||||
espandente causale. Incluso APPOSTA per passarlo a day_boundary_robust: e' il tipo di
|
||||
effetto che ha ucciso open_drive (artefatto di etichettatura del giorno UTC).
|
||||
|
||||
GATE (CLAUDE.md): causale/no-leak, NETTO fee 0.10% RT + sweep 0.00-0.20% a freq reale, OOS
|
||||
hold-out + griglia + plateau, day_boundary_robust per effetti calendario, MARGINAL vs TP01
|
||||
(earns_slot / has_insample_edge / multi-cut / non-hedge), corr con SKH01, haircut $600.
|
||||
|
||||
Esecuzione: uv run python scripts/research/intraday_regime.py
|
||||
Idempotente, niente scritture su disco (solo report a stdout).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from functools import lru_cache
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt")
|
||||
import altlib as al # noqa: E402
|
||||
|
||||
ASSETS = ("BTC", "ETH")
|
||||
SCREEN_TFS = ("1h", "4h", "6h", "8h", "12h")
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# TARGET FACTORIES (ogni fattoria ritorna un target_fn(df) causale, posizione continua)
|
||||
# ===========================================================================
|
||||
def make_erm(tf: str, L_days: float, thr: float, long_flat: bool,
|
||||
target_vol: float = 0.20):
|
||||
"""Efficiency-Ratio regime momentum. L_days = lunghezza finestra in GIORNI (-> barre via bpd)."""
|
||||
def fn(df):
|
||||
c = df["close"].values.astype(float)
|
||||
n = len(c)
|
||||
L = max(2, round(L_days * al.bars_per_day(df)))
|
||||
net = np.full(n, np.nan)
|
||||
net[L:] = c[L:] - c[:-L]
|
||||
step = np.abs(np.diff(c, prepend=c[0])) # |c[k]-c[k-1]|, causale
|
||||
path = pd.Series(step).rolling(L, min_periods=L).sum().values
|
||||
er = np.divide(np.abs(net), path, out=np.zeros(n), where=(path > 0))
|
||||
active = (er >= thr) & np.isfinite(net)
|
||||
raw = np.where(active, np.sign(net), 0.0)
|
||||
if long_flat:
|
||||
raw = np.clip(raw, 0.0, None)
|
||||
return al.vol_target(raw, df, target_vol=target_vol, vol_win_days=30, leverage_cap=2.0)
|
||||
return fn
|
||||
|
||||
|
||||
def make_vem(tf: str, Lmom_days: float, Lshort_days: float, Llong_days: float,
|
||||
long_flat: bool, target_vol: float = 0.20):
|
||||
"""Vol-expansion momentum: momentum attivo solo quando rv_corta > rv_lunga (espansione)."""
|
||||
def fn(df):
|
||||
c = df["close"].values.astype(float)
|
||||
n = len(c)
|
||||
bpd = al.bars_per_day(df)
|
||||
Lmom = max(2, round(Lmom_days * bpd))
|
||||
ws, wl = max(2, round(Lshort_days * bpd)), max(3, round(Llong_days * bpd))
|
||||
r = al.simple_returns(c)
|
||||
rv_s = al.rolling_std(r, ws)
|
||||
rv_l = al.rolling_std(r, wl)
|
||||
expand = (rv_s > rv_l) & np.isfinite(rv_s) & np.isfinite(rv_l)
|
||||
net = np.full(n, np.nan)
|
||||
net[Lmom:] = c[Lmom:] - c[:-Lmom]
|
||||
raw = np.where(expand & np.isfinite(net), np.sign(net), 0.0)
|
||||
if long_flat:
|
||||
raw = np.clip(raw, 0.0, None)
|
||||
return al.vol_target(raw, df, target_vol=target_vol, vol_win_days=30, leverage_cap=2.0)
|
||||
return fn
|
||||
|
||||
|
||||
def make_vbr(tf: str, k: float, atr_win: int, long_flat: bool, target_vol: float = 0.20):
|
||||
"""Thrust-breakout rolling: segui i moti significativi (|Δ| > k*ATR), altrimenti hold."""
|
||||
def fn(df):
|
||||
c = df["close"].values.astype(float)
|
||||
a = al.atr(df, atr_win)
|
||||
a_prev = np.roll(a, 1); a_prev[0] = a[0] # ATR noto a inizio barra (causale)
|
||||
delta = np.diff(c, prepend=c[0])
|
||||
sig = np.where(np.abs(delta) > k * a_prev, np.sign(delta), np.nan)
|
||||
raw = pd.Series(sig).ffill().fillna(0.0).values
|
||||
if long_flat:
|
||||
raw = np.clip(raw, 0.0, None)
|
||||
return al.vol_target(raw, df, target_vol=target_vol, vol_win_days=30, leverage_cap=2.0)
|
||||
return fn
|
||||
|
||||
|
||||
def make_tod(tf: str, long_flat: bool, target_vol: float = 0.20, min_obs: int = 20):
|
||||
"""Time-of-day seasonality (controllo calendario). Direzione = segno della media espandente
|
||||
causale del rendimento della stessa ora-del-giorno. Da passare a day_boundary_robust."""
|
||||
def fn(df):
|
||||
c = df["close"].values.astype(float)
|
||||
r = al.simple_returns(c)
|
||||
hour = pd.to_datetime(df["datetime"], utc=True).dt.hour.values
|
||||
n = len(c)
|
||||
sums = {}; cnts = {}
|
||||
raw = np.zeros(n)
|
||||
for i in range(1, n):
|
||||
h_prev = int(hour[i - 1]) # aggiorna con la barra GIA' chiusa
|
||||
sums[h_prev] = sums.get(h_prev, 0.0) + r[i - 1]
|
||||
cnts[h_prev] = cnts.get(h_prev, 0) + 1
|
||||
h = int(hour[i])
|
||||
if cnts.get(h, 0) >= min_obs:
|
||||
raw[i] = 1.0 if sums[h] >= 0 else -1.0
|
||||
if long_flat:
|
||||
raw = np.clip(raw, 0.0, None)
|
||||
return al.vol_target(raw, df, target_vol=target_vol, vol_win_days=30, leverage_cap=2.0)
|
||||
return fn
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# SCREENING — griglia leggera per (asset,tf,params) via eval_weights (vettoriale).
|
||||
# ===========================================================================
|
||||
def _screen_cell(fn, tf):
|
||||
"""Min-asset full/hold Sharpe, fee@0.10 e @0.20 RT, turnover, time-in-market."""
|
||||
fulls, holds, f10, f20, turn, tim = [], [], [], [], [], []
|
||||
for a in ASSETS:
|
||||
df = al.get(a, tf)
|
||||
tgt = fn(df)
|
||||
ev = al.eval_weights(df, tgt, fee_side=0.0005) # 0.10% RT
|
||||
ev0 = al.eval_weights(df, tgt, fee_side=0.001) # 0.20% RT
|
||||
fulls.append(ev["full"]["sharpe"]); holds.append(ev["holdout"].get("sharpe", 0.0))
|
||||
f10.append(ev["full"]["sharpe"]); f20.append(ev0["full"]["sharpe"])
|
||||
turn.append(ev["turnover_per_year"]); tim.append(ev["time_in_market"])
|
||||
return dict(tf=tf, min_full=round(min(fulls), 3), min_hold=round(min(holds), 3),
|
||||
min_f10=round(min(f10), 3), min_f20=round(min(f20), 3),
|
||||
turnover=round(float(np.mean(turn)), 1), tim=round(float(np.mean(tim)), 2))
|
||||
|
||||
|
||||
def screen_family(name, factory, grid, tfs=SCREEN_TFS):
|
||||
"""Esegue la griglia, ritorna lista di dict ordinata per min_hold (solo fee-surviving in cima)."""
|
||||
rows = []
|
||||
for tf in tfs:
|
||||
for params in grid:
|
||||
fn = factory(tf=tf, **params)
|
||||
m = _screen_cell(fn, tf)
|
||||
m["params"] = params
|
||||
m["fee_ok"] = bool(m["min_f20"] > 0)
|
||||
rows.append(m)
|
||||
rows.sort(key=lambda r: (r["fee_ok"], r["min_hold"]), reverse=True)
|
||||
print(f"\n===== {name}: top celle (di {len(rows)}) =====")
|
||||
print(f" {'tf':>4} {'minFull':>7} {'minHold':>7} {'f@.10':>6} {'f@.20':>6} "
|
||||
f"{'turn/y':>7} {'tim':>5} feeOK params")
|
||||
for r in rows[:10]:
|
||||
print(f" {r['tf']:>4} {r['min_full']:+7.2f} {r['min_hold']:+7.2f} {r['min_f10']:+6.2f} "
|
||||
f"{r['min_f20']:+6.2f} {r['turnover']:>7.0f} {r['tim']:>5.2f} "
|
||||
f"{str(r['fee_ok']):>5} {r['params']}")
|
||||
return rows
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# DEEP-DIVE sul vincitore: marginal vs TP01 + day_boundary + corr SKH01 + haircut $600.
|
||||
# ===========================================================================
|
||||
@lru_cache(maxsize=1)
|
||||
def _skh_daily() -> pd.Series:
|
||||
"""Rendimenti giornalieri SKH01-V2-DD (50/50 BTC+ETH) dallo sleeve di progetto (read-only)."""
|
||||
from src.portfolio.sleeves import _skyhook_returns
|
||||
s = _skyhook_returns()
|
||||
if s.index.tz is None:
|
||||
s.index = s.index.tz_localize("UTC")
|
||||
return s
|
||||
|
||||
|
||||
def corr_to_skh(fn, tf) -> dict:
|
||||
cand = al.candidate_daily(fn, tf=tf)
|
||||
skh = _skh_daily()
|
||||
J = pd.concat({"C": cand, "S": skh}, axis=1, join="inner").dropna()
|
||||
JH = J[J.index >= al.HOLDOUT]
|
||||
return dict(n=int(len(J)),
|
||||
corr_full=round(float(J["C"].corr(J["S"])), 3) if len(J) > 5 else None,
|
||||
corr_hold=round(float(JH["C"].corr(JH["S"])), 3) if len(JH) > 5 else None)
|
||||
|
||||
|
||||
def haircut_600(fn, tf) -> dict:
|
||||
"""Sharpe onesto a $600: salta i ribilanci < $5 (eval_weights_smallcap), per asset + media."""
|
||||
out = {}
|
||||
for a in ASSETS:
|
||||
df = al.get(a, tf)
|
||||
sc = al.eval_weights_smallcap(df, fn(df), capital=600.0, min_order=5.0)
|
||||
out[a] = dict(modeled=sc["modeled"]["sharpe"], real=sc["realistic"]["sharpe"],
|
||||
haircut=sc["sharpe_haircut"], n_tr=sc["n_executed_trades"])
|
||||
return out
|
||||
|
||||
|
||||
def plateau_erm(tf="8h"):
|
||||
"""Plateau fine L_days x thr al TF vincente (min-asset full/hold/f@.20). Un edge vero ha un
|
||||
PLATEAU, non una cella isolata."""
|
||||
print("\n" + "=" * 78)
|
||||
print(f"PLATEAU ERM @ {tf} (min-asset; L_days righe, thr colonne) — full / hold / f@.20")
|
||||
print("=" * 78)
|
||||
Ls = (1.5, 2.0, 2.5, 3.0); thrs = (0.30, 0.35, 0.40, 0.45, 0.50)
|
||||
print(" L\\thr " + "".join(f"{t:>16.2f}" for t in thrs))
|
||||
for L in Ls:
|
||||
cells = []
|
||||
for t in thrs:
|
||||
m = _screen_cell(make_erm(tf=tf, L_days=L, thr=t, long_flat=False), tf)
|
||||
cells.append(f"{m['min_full']:+.2f}/{m['min_hold']:+.2f}/{m['min_f20']:+.2f}")
|
||||
print(f" {L:>4.1f} " + "".join(f"{c:>16}" for c in cells))
|
||||
|
||||
|
||||
def vs_book(fn, tf):
|
||||
"""Il test decisivo del gate #5: ERM AGGIUNGE oltre il book esistente (TP01+SKH01), o e'
|
||||
SKH01 travestito? Sharpe/DD full & hold dei blend incrementali su griglia giornaliera."""
|
||||
cand = al.candidate_daily(fn, tf=tf)
|
||||
tp = al.tp01_baseline_daily()
|
||||
skh = _skh_daily()
|
||||
J = pd.concat({"T": tp, "S": skh, "C": cand}, axis=1, join="inner").dropna()
|
||||
JH = J[J.index >= al.HOLDOUT]
|
||||
blends = [
|
||||
("TP01", (1.0, 0.0, 0.0)),
|
||||
("TP01+SKH 75/25", (0.75, 0.25, 0.0)),
|
||||
("TP01+SKH+ERM 60/25/15", (0.60, 0.25, 0.15)),
|
||||
("TP01+SKH+ERM 55/20/25", (0.55, 0.20, 0.25)),
|
||||
]
|
||||
print("\n" + "=" * 78)
|
||||
print("vs BOOK ESISTENTE (TP01+SKH01) — ERM aggiunge oltre SKH? (gate #5)")
|
||||
print("=" * 78)
|
||||
print(f" {'blend':<26} {'FULL Sh':>8} {'FULL DD':>8} {'HOLD Sh':>8} {'HOLD DD':>8}")
|
||||
for label, (wt, ws, wc) in blends:
|
||||
bf = wt * J["T"] + ws * J["S"] + wc * J["C"]
|
||||
bh = wt * JH["T"] + ws * JH["S"] + wc * JH["C"]
|
||||
print(f" {label:<26} {al._sh(bf):>+8.2f} {al._dd_ret(bf) * 100:>7.1f}% "
|
||||
f"{al._sh(bh):>+8.2f} {al._dd_ret(bh) * 100:>7.1f}%")
|
||||
|
||||
|
||||
def deep_dive(name, fn, tf, calendar=False):
|
||||
print("\n" + "#" * 78)
|
||||
print(f"# DEEP-DIVE: {name} (tf={tf})")
|
||||
print("#" * 78)
|
||||
|
||||
caus = al.causality_ok(fn, tf=tf)
|
||||
print(f"\n[CAUSALITA'] ok={caus['ok']} max_tail_diff={caus['max_tail_diff']} "
|
||||
f"(checked={caus['checked']})")
|
||||
|
||||
print("\n[FEE-SWEEP a frequenza reale] (study_weights su entrambi gli asset)")
|
||||
sw = al.study_weights(name, fn, tfs=(tf,))
|
||||
print(al.fmt(sw))
|
||||
|
||||
print("\n[MARGINAL vs TP01]")
|
||||
sm = al.study_marginal(name, fn, tf=tf)
|
||||
print(al.fmt_marginal(sm))
|
||||
|
||||
sk = corr_to_skh(fn, tf)
|
||||
print(f"\n[CORR con SKH01] full={sk['corr_full']} hold={sk['corr_hold']} "
|
||||
f"(n_giorni={sk['n']})")
|
||||
|
||||
if calendar:
|
||||
print("\n[DAY-BOUNDARY ROBUST] (OBBLIGATORIO per effetti ora/sessione/giorno)")
|
||||
else:
|
||||
print("\n[DAY-BOUNDARY ROBUST] (sanity: un segnale di prezzo dev'essere ~INVARIANT)")
|
||||
db = al.day_boundary_robust(fn, tf=tf)
|
||||
print(f" verdict={db['verdict']} spread={db.get('spread')} "
|
||||
f"min={db.get('min')} max={db.get('max')} per_offset={db.get('per_offset')}")
|
||||
|
||||
print("\n[HAIRCUT $600] (eval_weights_smallcap: salta ribilanci < $5)")
|
||||
hc = haircut_600(fn, tf)
|
||||
for a, d in hc.items():
|
||||
print(f" {a}: modeled Sh {d['modeled']:+.2f} -> real Sh {d['real']:+.2f} "
|
||||
f"(haircut {d['haircut']:+.2f}, trade eseguiti {d['n_tr']})")
|
||||
|
||||
return dict(name=name, tf=tf, causal=caus["ok"], earns_slot=sm["earns_slot"],
|
||||
marginal=sm["marginal_verdict"], corr_skh=sk, day_boundary=db["verdict"],
|
||||
haircut=hc)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# MAIN
|
||||
# ===========================================================================
|
||||
def main():
|
||||
print("=" * 78)
|
||||
print("FILONE B — INTRADAY REGIME BTC/ETH (intraday_regime.py)")
|
||||
print("=" * 78)
|
||||
tp01 = al.tp01_baseline_daily()
|
||||
print(f"Baseline TP01 (50/50) full Sharpe ~{al._sh(tp01):.2f} "
|
||||
f"hold ~{al._sh(tp01[tp01.index >= al.HOLDOUT]):.2f} (riferimento marginale)")
|
||||
|
||||
# ---- Griglie (compatte: plateau leggibile, no overfit di griglia gigante) ----
|
||||
erm_grid = [dict(L_days=L, thr=t, long_flat=lf)
|
||||
for L in (1.0, 2.0, 3.0) for t in (0.35, 0.50) for lf in (False, True)]
|
||||
vem_grid = [dict(Lmom_days=lm, Lshort_days=2.0, Llong_days=10.0, long_flat=lf)
|
||||
for lm in (1.0, 3.0) for lf in (False, True)]
|
||||
vbr_grid = [dict(k=k, atr_win=14, long_flat=lf)
|
||||
for k in (0.5, 1.0, 1.5) for lf in (False, True)]
|
||||
tod_grid = [dict(long_flat=lf) for lf in (False, True)]
|
||||
|
||||
fam = {
|
||||
"ERM": (make_erm, erm_grid, SCREEN_TFS),
|
||||
"VEM": (make_vem, vem_grid, ("4h", "6h", "8h", "12h")),
|
||||
"VBR": (make_vbr, vbr_grid, ("4h", "6h", "8h", "12h")),
|
||||
"TOD": (make_tod, tod_grid, ("1h",)),
|
||||
}
|
||||
screens = {}
|
||||
for name, (factory, grid, tfs) in fam.items():
|
||||
screens[name] = screen_family(name, factory, grid, tfs)
|
||||
|
||||
# ---- Vincitore per famiglia (best min_hold tra le fee-surviving con min_full>0) ----
|
||||
print("\n" + "=" * 78)
|
||||
print("VINCITORI PER FAMIGLIA (best min_hold tra fee-surviving, min_full>0)")
|
||||
print("=" * 78)
|
||||
winners = {}
|
||||
for name, (factory, grid, tfs) in fam.items():
|
||||
ok = [r for r in screens[name] if r["fee_ok"] and r["min_full"] > 0]
|
||||
pool = ok if ok else screens[name]
|
||||
w = max(pool, key=lambda r: r["min_hold"])
|
||||
winners[name] = w
|
||||
print(f" {name}: tf={w['tf']} {w['params']} minFull={w['min_full']:+.2f} "
|
||||
f"minHold={w['min_hold']:+.2f} f@.20={w['min_f20']:+.2f} feeOK={w['fee_ok']}")
|
||||
|
||||
# ---- Deep-dive sui due meccanismi piu' promettenti (per min_hold) + il controllo TOD ----
|
||||
ranked = sorted(["ERM", "VEM", "VBR"],
|
||||
key=lambda n: winners[n]["min_hold"], reverse=True)
|
||||
deep = []
|
||||
for name in ranked[:2]:
|
||||
w = winners[name]
|
||||
factory = fam[name][0]
|
||||
fn = factory(tf=w["tf"], **w["params"])
|
||||
deep.append(deep_dive(f"{name} {w['params']}", fn, w["tf"], calendar=False))
|
||||
|
||||
# controllo calendario: TOD passa SEMPRE per day_boundary_robust
|
||||
wt = winners["TOD"]
|
||||
fn_tod = make_tod(tf=wt["tf"], **wt["params"])
|
||||
deep.append(deep_dive(f"TOD {wt['params']}", fn_tod, wt["tf"], calendar=True))
|
||||
|
||||
# ---- Analisi extra sul vincitore ERM (plateau fine + vs book TP01+SKH01) ----
|
||||
we = winners["ERM"]
|
||||
fn_erm = make_erm(tf=we["tf"], **we["params"])
|
||||
plateau_erm(we["tf"])
|
||||
vs_book(fn_erm, we["tf"])
|
||||
|
||||
# ---- Verdetto sintetico ----
|
||||
print("\n" + "=" * 78)
|
||||
print("SINTESI")
|
||||
print("=" * 78)
|
||||
for d in deep:
|
||||
print(f" {d['name']:<26} tf={d['tf']:>3} | marginal={d['marginal']:<9} "
|
||||
f"earns_slot={d['earns_slot']!s:<5} corrSKH(full/hold)="
|
||||
f"{d['corr_skh']['corr_full']}/{d['corr_skh']['corr_hold']} "
|
||||
f"day_boundary={d['day_boundary']}")
|
||||
any_slot = any(d["earns_slot"] for d in deep)
|
||||
print(f"\n => earns_slot su qualche meccanismo? {any_slot}")
|
||||
print(" (vedi diario docs/diary/2026-06-29-intraday-regime.md per il verdetto ragionato)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user