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())
|