#!/usr/bin/env python3 # -*- coding: utf-8 -*- """เทียบ variant + เช็คว่า BUY-only/SELL-only run แยก ให้ผลตรงกับการ split ใน analysis""" import pandas as pd, numpy as np, math PT=0.01 def load(p): d=pd.read_csv(p); d["datetime"]=pd.to_datetime(d["datetime"],format="%Y.%m.%d %H:%M"); return d def prop_z(k1,n1,k2,n2): if not n1 or not n2: return float("nan") p=(k1+k2)/(n1+n2); se=math.sqrt(p*(1-p)*(1/n1+1/n2)) return (k1/n1-k2/n2)/se if se>0 else float("nan") def boot(v,n=10000): v=np.asarray(v,float); r=np.random.default_rng(7) if len(v)==0: return (np.nan,np.nan) m=v[r.integers(0,len(v),(n,len(v)))].mean(1); return np.percentile(m,2.5),np.percentile(m,97.5) print("="*78) print("A) ความไวต่อกฎ 'แท่งไส้หลังซิกปิดไปทางไหน' (GLOSSARY §4.1b — โค้ชขัดกันตรงๆ)") print("="*78) print(f"{'variant':<34}{'N sig':>7}{'rate B':>9}{'95%CI':>18}{'CTRL':>8}{'z':>7}") print("-"*78) for f,nm in [("data/maepla_l0_all.csv","OPPOSITE (โมจา) = default"), ("data/maepla_l0_kaew.csv","SAME (ลูกแก้ว)"), ("data/maepla_l0_any.csv","ANY (ไม่บังคับทิศปิด)")]: d=load(f); s=d[(d.kind=="SIG")&(d.status==0)]; c=d[d.kind=="CTRL"] lo,hi=boot(s.tp1_before_sl.values) z=prop_z(int(s.tp1_before_sl.sum()),len(s),int(c.tp1_before_sl.sum()),len(c)) print(f"{nm:<34}{len(s):>7}{s.tp1_before_sl.mean()*100:>8.1f}% [{lo*100:5.1f}%,{hi*100:5.1f}%]{c.tp1_before_sl.mean()*100:>7.1f}%{z:>7.2f}") print("-"*78) print(" → ไม่มี variant ไหนแตะเกณฑ์ผ่าน 22% เลย · ทุกตัวอยู่ในกรอบ baseline สุ่ม\n") print("="*78) print("B) ตรวจสอบว่า 'รันแยก BUY-only / SELL-only' ให้ผลเท่ากับการ split ใน analysis") print("="*78) d=load("data/maepla_l0_all.csv") for f,dname in [("data/maepla_l0_buyonly.csv","BUY"),("data/maepla_l0_sellonly.csv","SELL")]: sep=load(f); s_sep=sep[(sep.kind=="SIG")&(sep.status==0)] s_all=d[(d.kind=="SIG")&(d.status==0)&(d.direction==dname)] same_n = len(s_sep)==len(s_all) same_r = abs(s_sep.tp1_before_sl.mean()-s_all.tp1_before_sl.mean())<1e-12 print(f" {dname:<6} รันแยก N={len(s_sep):4d} rate={s_sep.tp1_before_sl.mean()*100:5.2f}% | " f"split N={len(s_all):4d} rate={s_all.tp1_before_sl.mean()*100:5.2f}% → " f"{'ตรงกันเป๊ะ' if (same_n and same_r) else 'ไม่ตรง !!'}") print(" (ยืนยัน: ระดับ 0 ไม่มี interaction ระหว่างฝั่ง — 1 run = 3 run)\n") print("="*78) print("C) การเซ็นเซอร์ของหน้าต่าง 20 แท่ง (ถ้าโดนตัดเยอะ ผลการแข่งจะเพี้ยน)") print("="*78) d=load("data/maepla_l0_all.csv") for nm,g in [("SIG",d[(d.kind=="SIG")&(d.status==0)]),("CTRL",d[d.kind=="CTRL"])]: none=((g.min_to_tp1<0)&(g.min_to_sl300<0)).mean() print(f" {nm:<5} ไม่ถึงทั้ง TP1 และ SL ภายใน 20 แท่ง : {none*100:.1f}% " f"(hit TP1 {g.hit_tp1.mean()*100:.1f}% / hit SL {g.hit_sl.mean()*100:.1f}%)") print(" → ทั้งสองชุดโดนเซ็นเซอร์เท่ากัน การเทียบยังยุติธรรม\n") print("="*78) print("D) การสอบเทียบเครื่องวัด (ต้องผ่าน ไม่งั้นผลทั้งหมดใช้ไม่ได้)") print("="*78) c=d[d.kind=="CTRL"] print(f" baseline CTRL ที่ SL300/TP1500 = {c.tp1_before_sl.mean()*100:.2f}% " f"vs null ทฤษฎี random walk 16.67% ต่าง {c.tp1_before_sl.mean()*100-16.67:+.2f}pp") print(f" CTRL BUY {c[c.direction=='BUY'].tp1_before_sl.mean()*100:.1f}% vs " f"CTRL SELL {c[c.direction=='SELL'].tp1_before_sl.mean()*100:.1f}% " f"← drift ทองขาขึ้นโผล่ตรงที่ควรโผล่ (เครื่องวัดจับของจริงได้)") print(f" race ตัดสินด้วย M1 : {(d.race_src=='M1').mean()*100:.1f}% (ไม่มี fallback H4)") print("="*78)