forked from chiki2bum2/SniperGold_ML
128 lines
4.6 KiB
Python
128 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
| |||
"""P2.5: FULL 19-FEATURE PARITY — EA corrected (BTTFBias fixed) vs build_features_p2.
| |||
| |||
Join timestamp (EA dump) -> build_features_p2 utk bar yg sama.
| |||
Per-feature: abs(runtime - training) <= eps.
| |||
eps diskrit (f0-f5,f7-f12,f18): 1e-9 ; kontinu (f6,f13-f17): 1e-6
| |||
"""
| |||
import os
| |||
import sys
| |||
import csv
| |||
import datetime as dt
| |||
| |||
import numpy as np
| |||
| |||
HERE = os.path.dirname(os.path.abspath(__file__))
| |||
sys.path.insert(0, HERE)
| |||
import build_features_p2 as BFP # noqa: E402
| |||
| |||
DATA = os.path.normpath(os.path.join(HERE, "..", "..", "..", "..",
| |||
"Files", "AlgoForge", "Data"))
| |||
EA_FIXED = os.path.join(HERE, "AlgoForge_bt_features_fixed_XAUUSD_M15.csv")
| |||
SRC_AGENT = r"D:\TradingTerminal\HFM Metatrader 5\Tester\Agent-127.0.0.1-3000\MQL5\Files\AlgoForge_bt_features_XAUUSD_M15.csv"
| |||
| |||
FEAT = ["f0_htf1", "f1_htf2", "f2_htf3", "f3_swing", "f4_internal", "f5_bias",
| |||
"f6_eqpos", "f7_sweep", "f8_choch", "f9_chochok", "f10_eqh", "f11_eql",
| |||
"f12_dsign", "f13_dmag", "f14_dhigh", "f15_dlow", "f16_mom20",
| |||
"f17_range", "f18_conf"]
| |||
EPS = [1e-9, 1e-9, 1e-9, 1e-9, 1e-9, 1e-9,
| |||
1e-6, 1e-9, 1e-9, 1e-9, 1e-9, 1e-9,
| |||
1e-9, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6]
| |||
| |||
| |||
def log(msg):
| |||
print(msg, flush=True)
| |||
| |||
| |||
def load_npz(name):
| |||
z = np.load(os.path.join(DATA, name + ".npz"))
| |||
return (z["time"].astype(np.int64), z["open"].astype(np.float64),
| |||
z["high"].astype(np.float64), z["low"].astype(np.float64),
| |||
z["close"].astype(np.float64), z["tick_volume"].astype(np.float64))
| |||
| |||
| |||
def parse_ea_time(s):
| |||
return int(dt.datetime.strptime(s, "%Y.%m.%d %H:%M")
| |||
.replace(tzinfo=dt.timezone.utc).timestamp())
| |||
| |||
| |||
def main():
| |||
if not os.path.exists(EA_FIXED):
| |||
import shutil
| |||
shutil.copy2(SRC_AGENT, EA_FIXED)
| |||
log(f"copied corrected dump -> {EA_FIXED}")
| |||
| |||
log("Load data...")
| |||
t, o, h, l, c, v = load_npz("XAUUSD_M15")
| |||
keep = t >= int(dt.datetime(2017, 1, 1, tzinfo=dt.timezone.utc).timestamp())
| |||
t, o, h, l, c, v = t[keep], o[keep], h[keep], l[keep], c[keep], v[keep]
| |||
htf = {}
| |||
for key in ("D1", "H4", "H1"):
| |||
ht_, ho_, hh_, hl_, hc_, hv_ = load_npz("XAUUSD_" + key)
| |||
htf[key] = (hh_, hl_, hc_, ht_)
| |||
| |||
log("Load EA corrected dump...")
| |||
rows = []
| |||
with open(EA_FIXED, encoding="utf-8-sig") as f:
| |||
rdr = csv.reader(f, delimiter="\t")
| |||
next(rdr, None)
| |||
for r in rdr:
| |||
if len(r) < 22:
| |||
continue
| |||
try:
| |||
tt = parse_ea_time(r[0].strip())
| |||
fea = [float(x) for x in r[3:22]]
| |||
close_ea = float(r[1])
| |||
except ValueError:
| |||
continue
| |||
rows.append((tt, fea, close_ea))
| |||
log(f" EA rows={len(rows)}")
| |||
| |||
py_idx = {int(tt): i for i, tt in enumerate(t)}
| |||
joined = [(py_idx[tt], fea, close_ea, tt) for (tt, fea, close_ea) in rows if tt in py_idx]
| |||
missing = [tt for (tt, fea, close_ea) in rows if tt not in py_idx]
| |||
log(f" joined={len(joined)} missing={len(missing)}")
| |||
if missing:
| |||
for tt in missing[:5]:
| |||
log(f" missing ts: {dt.datetime.fromtimestamp(tt, dt.timezone.utc)}")
| |||
| |||
idxs = np.array([j[0] for j in joined], dtype=np.int64)
| |||
log("Compute build_features_p2 over parity rows...")
| |||
F = BFP.build_features_p2(t, o, h, l, c, v, htf, idxs=idxs)
| |||
log(" done")
| |||
| |||
# close sanity
| |||
close_py = c[idxs]
| |||
d_close = np.abs(close_py - np.array([j[2] for j in joined]))
| |||
log(f"feed sanity close: max|d|={d_close.max():.6f} mean|d|={d_close.mean():.6f}")
| |||
| |||
log("")
| |||
log("=== PER-FEATURE PARITY (EA fixed vs build_features_p2) ===")
| |||
log(f"{'feature':12s} {'mismatch':>10s} {'rate':>9s} {'max|d|':>12s} {'eps':>8s}")
| |||
all_ok = True
| |||
n = len(joined)
| |||
for j in range(19):
| |||
d = np.abs(F[:, j] - np.array([jf[1][j] for jf in joined]))
| |||
m = int((d > EPS[j]).sum())
| |||
rate = m / n
| |||
status = "PASS" if m == 0 else "FAIL"
| |||
if m > 0:
| |||
all_ok = False
| |||
log(f"{FEAT[j]:12s} {m:>5d}/{n:<5d} {rate:9.4f} {d.max():12.6e} {EPS[j]:8.0e} {status}")
| |||
| |||
# tanpa row pertama (artefak pre-test, computed late)
| |||
log("")
| |||
log("=== TANPA ROW PERTAMA (artefak 2025.12.31 20:00) ===")
| |||
F2 = F[1:]
| |||
for j in range(19):
| |||
d = np.abs(F2[:, j] - np.array([jf[1][j] for jf in joined[1:]]))
| |||
m = int((d > EPS[j]).sum())
| |||
if m:
| |||
log(f" {FEAT[j]:12s} mismatch={m}/{n-1} rate={m/(n-1):.4f} max|d|={d.max():.6e} FAIL")
| |||
else:
| |||
log(f" {FEAT[j]:12s} mismatch=0/{n-1} PASS")
| |||
return 0 if all_ok else 2
| |||
| |||
| |||
if __name__ == "__main__":
| |||
sys.exit(main())
|