"""Settling the context score with nine instruments instead of four. On the honest engine the Wyckoff context slope landed at +0.0239 R/trace, t +1.37, sign held in 6 of 8 cells - too weak to trade, too consistent to dismiss. `sqxbars.py` has since made five more instruments readable, sharing no data path with the original four: FTSE100, UK100, WTI (two independent feeds) and USDCAD. The test is unchanged and was fixed before any of this ran: the ORIGINAL LPS configuration (market entry at the next bar's open, stop at the retest extreme, 2R target), scored by the five traces of book 2 2.3 / 7.1, with the single pre-specified prediction that expR rises monotonically with the number of agreeing traces. Nothing is tuned per instrument. WHAT WOULD SETTLE IT EITHER WAY ------------------------------- real the pooled slope holds near +0.024 with t comfortably past 2, and the new instruments - which had no hand in choosing anything - carry their share of it nothing the slope drifts toward zero as power rises, and the new instruments split evenly The second is what a small sample of noisy cells looks like when it is finally given enough data to speak. The five new instruments are the honest out-of-sample here: every parameter in this test was set on the original four. Bases on the breadth instruments use a SYNTHESISED spread and are approximate; the slope is not, because cost is nearly uncorrelated with the context score (measured: +0.0008 R/trace). """ import numpy as np, sys, time sys.stdout.reconfigure(encoding='utf-8', errors='replace') import fills, book, breadth, test_lps2 NATIVE = ('EURUSD', 'USDJPY', 'XAUUSD', 'SP500') def cells(tfs=('M15', 'H1')): for tf in tfs: for s in NATIVE: bk = fills.Book(s) yield s, tf, bk, book.frame(s, tf, bk), 'original' for s in breadth.SPREAD_BP: bk, f = breadth.get(s, tf) yield breadth.NICE[s], tf, bk, f, 'new' if __name__ == '__main__': tfs = tuple(a for a in sys.argv[1:] if a in ('M15', 'H1', 'H4')) or ('M15', 'H1') print("=== CONTEXT SLOPE: NINE INSTRUMENTS ===") print(" same LPS configuration, unchanged. The five 'new' instruments had no hand") print(" in choosing any parameter, so they are the out-of-sample arm.\n") print(f" {'sym':>9}{'tf':>5}{'set':>10}{'n':>7} " + "".join(f"{k:>12}" for k in range(5)) + f"{'slope':>9}{'t':>7}{'base':>9}") PR, PA, PT, tag = [], [], [], [] for s, tf, bk, f, kind in cells(tfs): try: a = test_lps2.events(s, tf, bk=bk, f=f) except Exception as ex: print(f" {s:>9}{tf:>5}{kind:>10} failed: {ex}") continue if a is None: print(f" {s:>9}{tf:>5}{kind:>10} - too few") continue R, ag = a['R'], a['ag'] txt = [f"{R[ag==k].mean():+6.3f}({int((ag==k).sum()):>4})" if (ag == k).sum() >= 25 else f"{'-':>12}" for k in range(5)] sl, tt = book.slope_t(R, ag) print(f" {s:>9}{tf:>5}{kind:>10}{a['n']:>7} " + "".join(txt) + f"{sl:>+9.4f}{tt:>+7.2f}{R.mean():>+9.4f}") PR.append(R); PA.append(ag); PT.append(a['t']); tag.append((kind, sl, R.mean())) if not PR: sys.exit() def pooled(sel, label): R = np.concatenate([r for r, k in zip(PR, tag) if sel(k)]) A = np.concatenate([a for a, k in zip(PA, tag) if sel(k)]) sl, tt = book.slope_t(R, A) pos = sum(1 for k in tag if sel(k) and k[1] > 0) tot = sum(1 for k in tag if sel(k)) print(f" {label:<26} n={len(R):>7,} slope {sl:>+8.4f} t {tt:>+6.2f}" f" base {R.mean():>+8.4f} positive-slope cells {pos}/{tot}") return R, A print() Rn, An = pooled(lambda k: k[0] == 'original', 'ORIGINAL four') Rb, Ab = pooled(lambda k: k[0] == 'new', 'NEW five (out of sample)') R, A = pooled(lambda k: True, 'ALL nine') print() for k in range(6): m = A == k if m.sum() < 25: continue se = R[m].std(ddof=1) / np.sqrt(m.sum()) print(f" {k} agree n={int(m.sum()):>6} expR {R[m].mean():+7.4f} +/- {se:.4f}" f" t {book.tstat(R[m]):+6.2f}") print("\n The out-of-sample line is the one that matters: those five instruments") print(" had no hand in choosing the trigger, the traces, or any threshold.")