diff --git a/scripts/analysis/regime_lab.py b/scripts/analysis/regime_lab.py index 40a2257..e7de80d 100644 --- a/scripts/analysis/regime_lab.py +++ b/scripts/analysis/regime_lab.py @@ -74,15 +74,20 @@ def _rolling_pct(x: np.ndarray, win: int) -> np.ndarray: lambda w: (w.iloc[-1] >= w).mean(), raw=False).values -def regime_features(df: pd.DataFrame, pct_win: int = 252, rv_win: int = 24, fund_win: int = 168) -> dict: - """Tutte causali. dvol_pct/funding_z usano solo finestra passata. vrp = dvol - rv annualizz.""" +_BARS_PER_YEAR = {"1h": 24 * 365, "4h": 6 * 365, "1d": 365} + + +def regime_features(df: pd.DataFrame, tf: str = "1h", pct_win: int = 252, rv_win: int = 24, + fund_win: int = 168) -> dict: + """Tutte causali. dvol_pct/funding_z usano solo finestra passata. vrp = dvol - rv annualizz. + tf serve ad annualizzare correttamente la realized vol (sqrt barre/anno per timeframe).""" c = df["close"].values.astype(float) dvol = df["dvol"].values.astype(float) fund = df["funding"].values.astype(float) ret = np.zeros_like(c); ret[1:] = np.diff(np.log(c)) - # realized vol annualizzata (in punti %, scala come DVOL): std rolling * sqrt(barre/anno) - bars_per_year = {1: 24 * 365}.get(1, 24 * 365) # default 1h; per tf diversi e' un proxy - rv = pd.Series(ret).rolling(rv_win).std().values * np.sqrt(24 * 365) * 100 + # realized vol annualizzata (punti %, scala come DVOL): std rolling * sqrt(barre/anno del tf) + bpy = _BARS_PER_YEAR.get(tf, 24 * 365) + rv = pd.Series(ret).rolling(rv_win).std().values * np.sqrt(bpy) * 100 dvol_pct = _rolling_pct(dvol, pct_win) fmean = pd.Series(fund).rolling(fund_win).mean().values fstd = pd.Series(fund).rolling(fund_win).std().values @@ -142,7 +147,7 @@ def _cache_path(asset: str, tf: str) -> Path: def build_cache(asset: str, tf: str, frac_step: int = 6) -> pd.DataFrame: """Precompute OHLCV + regime + frattali -> parquet condiviso (per i 100 agenti).""" df = load(asset, tf) - R = regime_features(df) + R = regime_features(df, tf=tf) F = frac_features(df, step=frac_step) for k in _FEATCOLS_R: df[k] = R[k] @@ -166,9 +171,12 @@ def report(name: str, entries: list[dict], df: pd.DataFrame, asset: str = "", tf """Netto-fee full + OOS (ultimo 30%) + sweep fee, via engine onesto di explore_lab. Ritorna dict compatto: trades, full/oos (ret%, sharpe, dd, acc), robust (OK su tutte le fee).""" if not entries: - return {"name": name, "trades": 0, "verdict": False, "note": "no entries"} - ev = evaluate(name, entries, df) # full + oos + fee sweep - return ev + # struttura compatibile con robust() (tutti zero) -> robust()=False pulito, niente crash + z = {"ret": 0.0, "sharpe": 0.0, "dd": 0.0, "trades": 0, "win": 0.0, "exposure": 0.0, "yearly": {}} + print(f" {name:<24s} NO ENTRIES") + return {"full": dict(z), "oos": dict(z), "sweep": {0.0: 0.0, 0.0005: 0.0, 0.001: 0.0, 0.002: 0.0}, + "sweep_oos": {0.0: 0.0, 0.0005: 0.0, 0.001: 0.0, 0.002: 0.0}, "pos_yrs": 0, "n_yrs": 0} + return evaluate(name, entries, df) # full + oos + fee sweep if __name__ == "__main__":