| """
|
| Gold-set generator for Wyckoff structure labelling (2026-10-05).
|
|
|
| Each sample = the last W H1 bars ending at a decision bar t. CAUSAL: nothing after t is drawn, so a
|
| labeller (a vision model or a human) sees exactly what a trader sees at t. ANONYMOUS: no dates, no
|
| symbol, price rescaled to ATR units from the window's first close, volume to the window's median, so
|
| the labeller cannot recall the history. The key (symbol, timestamp) goes to a separate CSV.
|
| Sealed: nothing dated >= 2025-01-01 is ever sampled.
|
| python wyckoff_gold.py SP500,NAS100 40 pilot # symbols, n per symbol, set name
|
| """
|
| import os, sys, numpy as np, pandas as pd
|
| import matplotlib; matplotlib.use("Agg")
|
| import matplotlib.pyplot as plt
|
| sys.path.insert(0, os.path.dirname(__file__))
|
| import discover as D
|
|
|
| W = 120
|
| OUT = os.path.join(os.path.dirname(__file__), "wyckoff_gold")
|
|
|
|
|
| def render(b: pd.DataFrame, path: str):
|
| c0 = b.c.iloc[0]
|
| atr = (b.h - b.l).rolling(14, min_periods=1).mean().iloc[-1]
|
| sc = lambda x: (x - c0) / atr
|
| v = b.tv / b.tv.median()
|
| fig, (a, v_ax) = plt.subplots(2, 1, figsize=(11, 6.5), sharex=True, gridspec_kw={"height_ratios": [3, 1]})
|
| x = np.arange(len(b))
|
| up = b.c >= b.o
|
| a.vlines(x, sc(b.l), sc(b.h), color="k", lw=0.8)
|
| a.bar(x, (sc(b.c) - sc(b.o)).abs().clip(lower=0.02), bottom=np.minimum(sc(b.o), sc(b.c)), width=0.7,
|
| color=np.where(up, "#2a9d4a", "#d62f2f"))
|
| a.set_ylabel("price (ATR units)"); a.grid(alpha=.25)
|
| v_ax.bar(x, v, color=np.where(up, "#2a9d4a", "#d62f2f"), width=0.8); v_ax.set_ylabel("rel. volume")
|
| v_ax.set_xlabel("bar (last bar = now; nothing to the right exists)"); v_ax.grid(alpha=.25)
|
| fig.tight_layout(); fig.savefig(path, dpi=80); plt.close(fig)
|
|
|
|
|
| def main():
|
| syms = sys.argv[1].split(","); n = int(sys.argv[2]); name = sys.argv[3]
|
| d = os.path.join(OUT, name); os.makedirs(d, exist_ok=True)
|
| rng = np.random.default_rng(int(os.environ.get("SEED","7"))); key = []
|
| for s in syms:
|
| h = D.load_h1(s); h = h[h.index < D.SEAL]
|
| # event-driven sampling: decision bars where price moved >=2 ATR from the 20-bar mean or at random
|
| idx = rng.choice(np.arange(W, len(h)), n, replace=False)
|
| for i in sorted(idx):
|
| sid = f"{len(key):04d}"
|
| render(h.iloc[i - W + 1:i + 1], os.path.join(d, sid + ".png"))
|
| key.append((sid, s, h.index[i], h.c.iloc[i]))
|
| pd.DataFrame(key, columns=["id", "sym", "t", "close"]).to_csv(os.path.join(d, "_key.csv"), index=False)
|
| print(len(key), "charts ->", d)
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|