""" PRE-REGISTERED (written before the run, trial N=12): does restricting H4 dip entries to the LAST bar of the trading day beat all-bar entries? Same config (z20<-1.5, exit at mean, 3 ATR stop, <=10 bars), no new thresholds. Survives only if last-bar ret/DD >= all-bar in the pooled book AND in >=3 of 4 indices (per-trade bp) AND in >=4 of 6 calendar years 2021-26 (per-trade bp), keeping >=40% of trades. Also reports holding period / exit mix (descriptive). """ import sys, numpy as np, pandas as pd sys.path.insert(0, ".") import backtest as bt, macro_gates as mg from run_screen import zscore_entries def book(period, last_only): out = [] for s in mg.IDX: d = bt.load(s, period); e, xma = zscore_entries(d, 20, -1.5, 0) ts = pd.DatetimeIndex(d["ts"]) if last_only: e = e & (pd.Series(ts).groupby(ts.normalize()).transform("max") == pd.Series(ts)).to_numpy() tr = bt.add_r(bt.simulate(d, e, 1, xma, 10, 3.0), d, 3.0) for t in tr: t["symbol"] = s; t["exit_t"] = d["ts"][t["exit_i"]] out += tr return out A, L = book("PERIOD_H4", False), book("PERIOD_H4", True) print("HOLDING / EXITS (H4):") for n, tr in (("all-bar", A), ("last-bar", L)): b = np.array([t["bars"] for t in tr]); r = pd.Series([t["reason"] for t in tr]).value_counts(normalize=True).round(2).to_dict() print(f" {n:<9} n={len(tr)} mean {b.mean():.1f} bars (~{b.mean()*4/24:.1f} d) median {np.median(b):.0f} exits {r}") D = book("PERIOD_D1", False); b = np.array([t["bars"] for t in D]) print(f" D1 book n={len(D)} mean {b.mean():.1f} days median {np.median(b):.0f} exits {pd.Series([t['reason'] for t in D]).value_counts(normalize=True).round(2).to_dict()}") sa, sl = mg.window_stats(A, "2021-01-01", "2030-01-01"), mg.window_stats(L, "2021-01-01", "2030-01-01") print(f"\nPOOLED all-bar {sa['n']} {sa['bp']:.1f}bp rdd {sa['rdd']:.2f} DD {sa['dd']:.1%} | last-bar {sl['n']} {sl['bp']:.1f}bp rdd {sl['rdd']:.2f} DD {sl['dd']:.1%}") win_i = 0 for s in mg.IDX: x = [t["ret"]*1e4 for t in A if t["symbol"]==s]; y = [t["ret"]*1e4 for t in L if t["symbol"]==s] print(f" {s:<7} all {len(x):>4} {np.mean(x):6.1f}bp | last {len(y):>4} {np.mean(y):6.1f}bp"); win_i += np.mean(y) >= np.mean(x) win_y = 0 for y in range(2021, 2027): f = lambda tr: [t["ret"]*1e4 for t in tr if t["t"].astype("datetime64[Y]").astype(int)+1970 == y] x, z = f(A), f(L); ok = len(z) > 0 and np.mean(z) >= np.mean(x); win_y += ok print(f" {y}: all {len(x):>3} {np.mean(x):6.1f}bp | last {len(z):>3} {np.mean(z):6.1f}bp") keep = len(L)/len(A) print(f"\nrdd ok {sl['rdd']>=sa['rdd']} indices {win_i}/4 years {win_y}/6 kept {keep:.0%} ->", "SURVIVES" if sl['rdd']>=sa['rdd'] and win_i>=3 and win_y>=4 and keep>=.4 else "REJECTED")