import numpy as np, sys, datetime as dt sys.stdout.reconfigure(encoding='utf-8',errors='replace') from sklearn.ensemble import HistGradientBoostingClassifier rng=np.random.default_rng(0) def walk_forward(X, y, valid, horizon, n_folds=6, name="", thresholds=(0.0,0.40,0.45,0.50,0.55)): """Purged + embargoed walk-forward. Test blocks are contiguous and separated from the training data by `horizon` bars on BOTH sides, because a triple-barrier label at bar j depends on bars up to j+horizon - without that gap the training set contains the test set's outcomes and every score is fiction.""" n=len(y); idx=np.arange(n) bounds=np.linspace(int(n*0.3), n, n_folds+1).astype(int) out={t:[[],[]] for t in thresholds} # thr -> [hits, calls] covs=[] for f in range(n_folds): te0,te1=bounds[f],bounds[f+1] te=(idx>=te0)&(idx=thr) # directional calls only out[thr][1].append(int(sel.sum())) out[thr][0].append(int((pred[sel]==yt[sel]).sum())) covs.append(te.sum()) print(f"\n=== {name} === folds={len(covs)} test bars={sum(covs)}") base=100*np.mean(y[valid]!=2) print(f" base rates: Buy {100*np.mean(y[valid]==0):.1f}% Sell {100*np.mean(y[valid]==1):.1f}% directional {base:.1f}%") for thr in thresholds: hits=sum(out[thr][0]); calls=sum(out[thr][1]) if calls==0: print(f" conf>={thr:.2f}: no calls"); continue prec=100*hits/calls se=100*np.sqrt(0.25*0.75/calls) print(f" conf>={thr:.2f}: {calls:6d} calls ({100*calls/sum(covs):5.1f}% of bars) precision {prec:5.2f}% " f"vs 25.00% break-even edge {prec-25:+5.2f}pp ({(prec-25)/se:+.1f} sigma)") return F=np.load("F.npy"); meta=np.load("meta.npy"); y=np.load("lab.npy"); valid=np.load("valid.npy") t=meta[:,0] print("shapes",F.shape,y.shape,"valid",int(valid.sum())) walk_forward(F,y,valid,128,name="26 EA features, 2:6 barrier, h=128") # time-of-day / day-of-week: free, and the only inputs here that are NOT a transform of OHLCV hrs=np.array([dt.datetime.fromtimestamp(x,dt.UTC).hour for x in t],dtype=float) dow=np.array([dt.datetime.fromtimestamp(x,dt.UTC).weekday() for x in t],dtype=float) Xt=np.column_stack([F,np.sin(2*np.pi*hrs/24),np.cos(2*np.pi*hrs/24),dow]) walk_forward(Xt,y,valid,128,name="26 features + hour/day-of-week") np.save("hrs.npy",hrs); np.save("dow.npy",dow)