The MI sample builder used `MathAbs(labelBarOffset)` as a padding, causing rows from offset and non-offset builds to be paired with a double shift. This broke the positive control, failed the 5× gate, and voided all reported mutual‑information figures. Replace with the fixed `MiShiftPad` constant to ensure builds enumerate the same set of bars and row-k alignment is preserved. Add `BatchOptionsTotal()` to `CNeuronBatchNormOCL` and split the packed BN weight array in the learning report into separate norms for the outgoing dense matrix, gamma, beta, running statistics, and Adam moment buffers. This turns an ambiguous single‑norm reading into precise diagnostics that distinguish weight divergence from scaling issues.
94 lines
4.3 KiB
Python
94 lines
4.3 KiB
Python
"""Five more instruments, to settle whether the context slope is a small real effect or nothing.
|
|
|
|
On the honest engine the Wyckoff context slope came in at +0.0239 R/trace, t +1.37, with 6 of
|
|
8 cells keeping the sign. That is the awkward middle: too weak to trade, too consistent to
|
|
dismiss. The only way past it is more independent instruments, and `sqxbars.py` has just made
|
|
five available that share no data path with the four already used - FTSE, UK100, WTI (two
|
|
feeds) and USDCAD.
|
|
|
|
WHAT IS APPROXIMATED HERE, AND WHY IT IS ACCEPTABLE
|
|
---------------------------------------------------
|
|
These files carry M1 bars with no ask, so the bid/ask book is SYNTHESISED by applying a
|
|
relative spread. That is a real approximation and it is only defensible for this particular
|
|
question, because the thing being measured is a SLOPE across context buckets and the cost was
|
|
already measured to be almost uncorrelated with the context score (+0.0008 R per trace,
|
|
t +0.85, against an effect that would have to be ~50x larger). A cost assumption shifts every
|
|
bucket together; it cannot manufacture or hide a slope.
|
|
|
|
The BASE level is a different matter and is quoted as approximate throughout.
|
|
|
|
Spreads are set as a FRACTION of price rather than in points, which also makes the whole
|
|
thing invariant to the decimal scale - convenient, because these symbols have no reference
|
|
series to calibrate a scale against, and every result here is in ATR units or R-multiples
|
|
anyway. Values are taken from the four instruments where the real spread IS known:
|
|
EURUSD 0.45 bp, USDJPY 0.64 bp, SP500 1.3 bp, XAUUSD 2.1 bp - and rounded UP, so the base is
|
|
pessimistic rather than flattering.
|
|
"""
|
|
import numpy as np, sys, os
|
|
import book, sqxbars
|
|
|
|
#--- relative half-spread inputs, in basis points of price, rounded up from measured peers
|
|
SPREAD_BP = {
|
|
'GBRIDXGBP_dukascopy__the5ers': 1.5, # FTSE 100 cash index
|
|
'UK100_the5ers': 1.5,
|
|
'LIGHTCMDUSD_dukascopy__the5ers': 4.0, # WTI crude
|
|
'XTIUSD_the5ers': 4.0,
|
|
'USDCAD_dukascopy__the5ers': 1.0,
|
|
}
|
|
NICE = {
|
|
'GBRIDXGBP_dukascopy__the5ers': 'FTSE100',
|
|
'UK100_the5ers': 'UK100',
|
|
'LIGHTCMDUSD_dukascopy__the5ers': 'WTI_d',
|
|
'XTIUSD_the5ers': 'WTI_5',
|
|
'USDCAD_dukascopy__the5ers': 'USDCAD',
|
|
}
|
|
|
|
|
|
class MidBook:
|
|
"""A fills.Book built from mid-only M1 bars by applying a relative spread.
|
|
|
|
Quacks like fills.Book. The spread is multiplicative so it scales with price over a
|
|
20-year sample instead of being a constant that is generous in 2012 and absurd in 2026.
|
|
"""
|
|
|
|
def __init__(self, bars, bp):
|
|
t, o, h, l, c = (bars[:, k] for k in range(5))
|
|
self.t = t.astype(np.int64)
|
|
self.n = len(t)
|
|
e = 0.5 * bp * 1e-4
|
|
self.bo, self.bh, self.bl, self.bc = o * (1 - e), h * (1 - e), l * (1 - e), c * (1 - e)
|
|
self.ao, self.ah, self.al, self.ac = o * (1 + e), h * (1 + e), l * (1 + e), c * (1 + e)
|
|
|
|
def index_at(self, t_ms):
|
|
return np.searchsorted(self.t, np.asarray(t_ms, np.int64), 'left')
|
|
|
|
|
|
def get(sym, tf, decimals=6):
|
|
"""-> (MidBook, Frame). Decimals are irrelevant to every statistic computed on these."""
|
|
bars, _ = sqxbars.load(sym, 'M1', decimals=decimals, verbose=False)
|
|
#--- drop duplicate and out-of-order minutes; a resample assumes a sorted, unique index
|
|
t = bars[:, 0].astype(np.int64)
|
|
keep = np.concatenate(([True], np.diff(t) > 0))
|
|
bars = bars[keep]
|
|
bk = MidBook(bars, SPREAD_BP.get(sym, 1.5))
|
|
t, o, h, l, c, v, i0, sp = book._resample(bk, tf)
|
|
return bk, book.Frame(NICE.get(sym, sym), tf, t, o, h, l, c, v, i0, sp)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
import datetime as dt
|
|
print("=== BREADTH INSTRUMENTS ===")
|
|
print(f" {'symbol':>9}{'M1 bars':>12}{'H1 bars':>10} range"
|
|
f"{'':>14}{'median px':>12}{'spread/ATR H1':>15}")
|
|
for s in SPREAD_BP:
|
|
try:
|
|
bk, f = get(s, 'H1')
|
|
except Exception as ex:
|
|
print(f" {NICE.get(s,s):>9} FAILED: {ex}")
|
|
continue
|
|
a = dt.datetime.fromtimestamp(f.t[0] / 1000, dt.UTC)
|
|
b = dt.datetime.fromtimestamp(f.t[-1] / 1000, dt.UTC)
|
|
print(f" {NICE[s]:>9}{bk.n:>12,}{f.n:>10,} {a:%Y-%m-%d}..{b:%Y-%m-%d}"
|
|
f"{np.median(f.c):>12.2f}"
|
|
f"{np.nanmedian(f.spread/np.maximum(f.atr(),1e-12)):>15.4f}")
|