"""The one replicated finding, re-tried on an engine that has been proved correct. The Wyckoff CONTEXT score - five cumulative traces from book 2 sections 2.3 and 7.1 - is the only thing in this project that has replicated: +0.045 R per agreeing trace, on two unrelated triggers, right sign in 15 of 16 cells. It was measured with market entries, so it never had the fill bug that killed four other results. But it was measured on M5 mid bars with an average spread bolted on, and it has never been seen through `fills.py`. Two questions, in this order: 1. does the dose-response slope survive an honest bid/ask fill? 2. at the configuration where the BASE is near zero, does base + context clear zero? Question 2 is the whole point. Context is a modifier worth ~+0.045 R per trace and every trigger measured so far starts at -0.15 to -0.33, so it has never had anything to lift. The depth curve says the base is least bad on the SHALLOW side, and the cost ladder says a wider stop divides the cost, so the configuration is chosen by MECHANISM and fixed before looking: phi = 0.50 shallow retest - the adverse-selection curve's best side mrisk = 2.0 stop at 2 ATR, so spread/risk is roughly halved kR = 2.0 unchanged from the work being replicated H = 200 unchanged wait = 40 unchanged Nothing below is tuned. The prediction is the same single pre-specified one: expR must RISE MONOTONICALLY with the number of agreeing traces. The slope is the result. The top bucket is NOT the result - picking it is what mining looks like - but its LEVEL is what decides whether any of this is tradeable, so it is reported separately and honestly. """ import numpy as np, sys, time sys.stdout.reconfigure(encoding='utf-8', errors='replace') import fills, book, wyckoff SYMS = ('EURUSD', 'USDJPY', 'XAUUSD', 'SP500') PHI, MRISK, KR, H, WAIT = 0.50, 2.0, 2.0, 200, 40 def arm(sym, tf, phi=PHI, mrisk=MRISK, kR=KR, bk=None, f=None, ev=None): bk = bk or fills.Book(sym) f = f or book.frame(sym, tf, bk) ev = ev if ev is not None else wyckoff.breakouts(f) if ev is None: return None o = wyckoff.retest(sym, tf, phi, mrisk=mrisk, kR=kR, wait=WAIT, H=H, bk=bk, f=f, ev=ev) if o is None: return None ind = o['indep'] return dict(R=o['R'][ind], ag=o['ag'][ind], t=bk.t[o['idx'][ind]], n=int(ind.sum())) def buckets(R, ag, lo=0, hi=6): out = [] for k in range(lo, hi): m = ag == k out.append((k, int(m.sum()), R[m].mean() if m.sum() else np.nan, book.tstat(R[m]) if m.sum() > 2 else 0.0)) return out if __name__ == '__main__': syms = [s for s in sys.argv[1:] if s in SYMS] or list(SYMS) print("=== CONTEXT DOSE-RESPONSE, HONEST FILLS ===") print(f" phi={PHI} mrisk={MRISK} kR={KR} H={H} wait={WAIT} - fixed before looking") print(" prediction: expR rises monotonically with agreeing traces.\n") print(f" {'sym':>7}{'tf':>4}{'n':>6} " + "".join(f"{k:>12}" for k in range(6)) + f"{'slope':>9}{'t':>7}") PR, PA, PT, cells = [], [], [], [] for tf in ('H1', 'H4'): for s in syms: a = arm(s, tf) if a is None or a['n'] < 150: print(f" {s:>7}{tf:>4} - too few") continue R, ag = a['R'], a['ag'] txt = [] for k, m, mu, _ in buckets(R, ag): txt.append(f"{mu:+6.3f}({m:>4})" if m >= 25 else f"{'-':>12}") sl, tt = book.slope_t(R, ag) cells.append(sl) print(f" {s:>7}{tf:>4}{a['n']:>6} " + "".join(txt) + f"{sl:>+9.4f}{tt:>+7.2f}") PR.append(R); PA.append(ag); PT.append(a['t']) if not PR: sys.exit() R = np.concatenate(PR); ag = np.concatenate(PA); T = np.concatenate(PT) sl, tt = book.slope_t(R, ag) print(f"\n POOLED n={len(R):,} slope {sl:+.4f} R/trace t {tt:+.2f}" f" cells with positive slope {sum(1 for x in cells if x>0)}/{len(cells)}") print(f" {'agree':>7}{'n':>7}{'expR':>9}{'se':>8}{'t':>7} chronological quarters") for k, m, mu, t in buckets(R, ag): sel = ag == k if sel.sum() < 25: continue se = R[sel].std(ddof=1) / np.sqrt(sel.sum()) o = np.argsort(T[sel]) q = [float(x.mean()) for x in np.array_split(R[sel][o], 4)] print(f" {k:>7}{int(sel.sum()):>7}{mu:>+9.4f}{se:>8.4f}{t:>+7.2f} " + "".join(f"{x:>+8.3f}" for x in q) + f" {sum(1 for x in q if x>0)}/4") print("\n The slope is the test. The LEVEL of the top buckets is what decides whether") print(" base + context clears zero - and that is the question this configuration was") print(" built to answer.")