ข้ามไปที่เนื้อหา

A6 · ออกแบบรอบ backtest หลาย broker และหลาย test period

▶ clip: https://youtu.be/2byLOh38Cso

จบบทนี้แล้วทำได้:

  • ออกแบบ matrix EA × broker × test period ที่ตอบคำถามเดียว โดยนับ k ใน ledger ก่อนกด run
  • บอกได้ว่า broker หลายตัวนับเป็นหลักฐานอิสระกี่ตัว
  • รู้ว่า tester ไม่จำลองอะไรบ้าง และผลกระทบหนักกับ EA แบบไหน
  • อ่านผล sweep risk และ walk-forward โดยไม่ถูก volume_max และพื้น lot หลอก

ต้องมีก่อน: A1 (prereg · กติกานับ k ข้อ A1-3) · A5 · ใช้ tick_depth / tick_years / is_oos เป็นจาก Standard


1 · matrix EA × broker × test period

A6-1

ก่อนวาด matrix ต้องรู้สี่เรื่องตามลำดับ

1. ชั้นของ tick กำหนดว่า broker ไหนตอบปีไหนได้ broker ที่ไม่มี tick จริงในปีนั้น MT5 จะสร้าง tick จาก M1 ให้เงียบ ๆ ผลของ cell นั้นใช้ไม่ได้ (S5) ดังนั้น cell แรกที่ต้องตัดคือ cell ที่ broker ไม่มี tick ครบ

2. broker ที่ข้อมูลสั้นที่สุดเป็นตัวตัดสินช่วง ถ้าคำถามต้องการหลาย broker ใน test period เดียวกัน ช่วงต้องสั้นเท่าที่ broker ที่สั้นที่สุดมี ถ้าอยากใช้ช่วงยาวกว่าบน broker ที่มีข้อมูลยาว ให้แยก config เป็นอีกคำถาม ไม่ใช่ยืดช่วงของทั้ง matrix ไปตาม broker ที่ยาวที่สุด เพราะ cell ของ broker ที่สั้นจะกลายเป็นข้อมูลที่ MT5 สร้างเอง

3. ทุก cell เพิ่ม k ใน Šidák ledger จึงต้องนับก่อนออกแบบ k ยิ่งมาก เส้น t ที่ต้องผ่านยิ่งสูง ถ้านับหลัง run จะเจอว่าเส้นขยับจนไม่มีอะไรผ่าน แล้วจะเกิดแรงจูงใจตัด cell ทิ้งเพื่อลด k ซึ่งคือการเลือกหลังเห็นผล

ตัวอย่างบนจอ: 5 EA × 3 test period = 15 run แต่ k เพิ่มแค่ 10 (290 → 300) เพราะ period ที่เป็น C0 ไม่นับ

ที่มาของตัวอย่างนี้คือ prereg B1 ของผู้สอน: คำถามเดียว ใช้ test period ชุดคัดกรองเดิมซ้ำ (C0) บวก IS ปีเก่าสองปี

period คืออะไร นับ k?
C0 run ซ้ำรอบคัดกรองเดิม เพื่อตรวจว่าทำซ้ำได้ (จำนวน trade ใกล้รอบเดิม) · เป็นช่วงข้อมูลที่ใช้ไปแล้ว ไม่นับ — ไม่ได้ใช้เลือกอะไร
IS ปีเก่า 1 test ใหม่ นับ
IS ปีเก่า 2 test ใหม่ นับ

กติกา: k เพิ่มตามจำนวน run ที่มีสิทธิ์ถูกเลือก run ที่มีไว้ตรวจความถูกต้องของระบบเฉย ๆ ไม่นับ แต่ต้องเขียนใน prereg ก่อน run ว่า cell ไหนเป็นแบบไหน

4. สร้าง config เป็นชุด matrix ใหญ่พิมพ์ config ทีละ file แล้วพลาดง่าย ผู้สอนใช้ make_cap_configs (ชุดหลายทุน) และ make_multi_configs (ชุดหลายสินค้า) ทั้งสองตัวมี --list ดูก่อนว่าจะได้ config อะไรโดยไม่เขียน file

2 · สี่ broker ไม่ได้แปลว่าสี่ตัวอย่าง

A6-2

run signal เดียวกันบนสี่ broker คือตลาดเดียวกัน ต่างกันแค่ feed จึงไม่ได้สี่ตัวอย่างอิสระ

ข้อสังเกต ตัวเลข อ่านว่า
Robo-Cen ตรงกับ Robo-ECN 91% สอง broker นี้เป็นหลักฐานชิ้นเดียว ไม่ใช่สองชิ้น
Gold-Snap 2022 · signal เดียวกัน Exness +9.7R · Robo −6.7R feed เปลี่ยนผลได้จริง โดยเฉพาะ trade ช่วงข่าวที่สั้นไม่เกิน 2 นาที — กลับขั้วข้าม feed
Wisdom · นาฬิกา server ตกบน broker UTC+0 (−0.426% ต่อ trade ใน OOS) · ผ่านบน UTC+2 และ UTC+3 EA ที่อิงเวลาของวัน ผลขึ้นกับ timezone ของ server
mode V ต่ำ ต่างกัน −10.5 ถึง −12.5 จุด ทั้ง 4 broker ดูเหมือนยืนยันกันดี แต่ era control ปี 2019–2023 ได้ +0.7 ช่วง −5.4 ถึง +6.6

case สุดท้ายสำคัญที่สุด: สี่ broker ชี้ทางเดียวกันหมดในช่วงเดียวกัน ก็ยังเป็นแค่ "ช่วงเวลาเดียว · ตลาดเดียว" ตัวที่ล้มข้อสรุปคือการเปลี่ยนช่วงเวลา (era) ไม่ใช่การเพิ่ม broker

วิธีนับ: นับเฉพาะ feed ที่อิสระกันจริง broker ที่ feed เดียวกัน (หรือ server เดียวกันคนละประเภทบัญชี) นับเป็นหนึ่ง

3 · สิ่งที่ tester ไม่จำลอง

A6-3

tester ไม่จำลอง หลักฐาน ผลกับการอ่าน backtest
slippage entry ของ stop order บัญชีจริง: เสีย 81 ครั้ง ได้ 9 ครั้ง · median +$0.466/oz เป็น cost ทางเดียว ไม่ใช่ noise ที่หักล้างกันเอง backtest จึงดีกว่าจริงเสมอ
delay กับ pending order ตั้ง delay แล้วราคา fill ไม่ขยับเลย 0 จาก 181 คู่ ทดสอบ delay ใน tester ไม่ได้บอกอะไรเกี่ยวกับ EA ที่เข้าด้วยใบ pending
spread ต่อประเภทบัญชี บัญชี Razor กับ Standard ได้ราคาเดียวกันเป๊ะ 962 deal เทียบประเภทบัญชีด้วย backtest ไม่ได้
ราคาในแท่ง M1 backtest M1 เกินจริง ~$1.90 ต่อ trade ดูตารางข้างล่าง

ทำไม $1.90 ต่อ trade หนักกับ SL แคบ: ค่านี้คงที่เป็นดอลลาร์ แต่ R วัดเป็นสัดส่วนของ SL

SL $1.90 คิดเป็น R
$3 1.90 ÷ 3 = 0.63R
$25 1.90 ÷ 25 = 0.076R

EA ที่ SL แคบเสียเกือบทั้ง edge ไปกับความคลาดเคลื่อนนี้ EA ที่ SL กว้างแทบไม่รู้สึก

slippage ทำให้แพ้บ่อยขึ้น ไม่ใช่แพ้หนักขึ้น เพราะ SL ผูกกับราคาที่ fill ไม่ใช่ราคาที่สั่ง ระยะ SL จึงยังเท่าเดิม ขนาดแพ้ต่อ trade ยัง 1R แต่จำนวน trade ที่แพ้เพิ่มขึ้น ถ้าคุณมองหาผลของ slippage ที่ "ขนาดแพ้เฉลี่ย" จะไม่เจอ ต้องดูที่ win rate และ E[R]

ตัวอย่างที่ทำให้เรื่องนี้ชี้ขาด: EA-A มี edge +0.1 ถึง +0.35R ต่อ trade แต่ slippage บน cent account กิน 0.38R มากกว่า edge ทั้งหมด การเลือก broker จึงสำคัญกว่าการ tune

4 · sweep risk และ walk-forward

A6-4

DD ลดลงเมื่อ risk เพิ่ม = signal ว่ามีอะไรผิด ตัวอย่าง CXM: risk 7% DD 56.6% แต่ risk 10% DD เหลือ 10.2% ทางคณิตศาสตร์ risk สูงขึ้นต้องได้ DD สูงขึ้น ถ้ากลับทิศ แปลว่า lot ที่ยิงจริงไม่ได้เป็นไปตาม risk ที่ตั้ง สาเหตุที่เจอคือ volume_max ของ broker ตัด lot เงียบ ๆ

ตรวจด้วย

bt\ea-bt.exe cap_scan

cap_scan อ่านรายงานที่ run หลายทุนแล้วจับสองอาการจากตัวเลขในรายงาน โดยไม่ต้องพึ่ง log:

อาการ อ่านว่า
ทุนโตแต่ lot ไม่โตตาม (กำไรตัน) ชน volume_max
trade น้อยกว่าทุนอื่นในกลุ่มเดียวกัน lot ต่ำกว่า volume_min ถูกข้าม

ทำไมต้องใช้เครื่องมือ: รายงาน MT5 ไม่บอกว่า lot ถูกตัด และ run ที่จบปกติจะไม่มีอะไรฟ้อง แถวนั้นยังขึ้นว่าเป็น risk ที่ตั้ง ทั้งที่ risk จริงต่ำกว่า cap_scan อ่าน folder ตามโครงที่ make_cap_configs สร้าง (<test period>\cap<ทุน>\<EA>\<version>\<broker>\<preset>.htm)

พื้น lot 0.01 ก็ฆ่า leg ของกลยุทธ์ได้ อีกด้านของปัญหาเดียวกัน เมื่อ lot ที่คำนวณได้ต่ำกว่า 0.01 trade นั้นหายไป case จริง: leg 1 ลดจาก 396 trade เหลือ 9 trade ผลคือ walk-forward ได้ E[R] "ดีขึ้น" เป็น +0.53 เพียงเพราะ leg ที่อ่อนที่สุดหายไปเอง ไม่ใช่เพราะกลยุทธ์ดีขึ้น

ก่อนอ่านผล walk-forward ให้นับ trade ต่อ leg ต่อ test period ถ้าจำนวน trade ของ leg ไหนหดลงมากในบาง test period ตัวเลข E[R] รวมเชื่อไม่ได้

ข้อจำกัดของเครื่องมือสองตัว:

เครื่องมือ ใช้ได้เฉพาะ
walk EA ที่มี input ให้ tune
mc --from/--to (ตัดช่วงจากรายงานเดิม) EA ที่ไม่มีสถานะข้าม trade — ไม่หยุดหลังแพ้ N trade · ไม่มีเพดานรายวัน · ไม่ทบ lot

EA ที่มีสถานะข้าม trade ตัดช่วงจากรายงานเดิมไม่ได้ เพราะ trade แรกของช่วงที่ตัดมาได้รับสถานะ (lot · ตัวนับแพ้) จากช่วงก่อนหน้า ต้อง run จริงในช่วงนั้น


Lab · matrix EA × broker × test period ให้คำถามเดียว

A6-L

lab นี้ออกแบบอย่างเดียว ไม่ run ทุกคำสั่งพิมพ์ bt\ea-bt.exe นำหน้า

ข้อจำกัดของ cell: ใช้ได้เฉพาะช่วงข้อมูลที่ใช้ไปแล้ว หรือ Robo-Cen ปี 2016–2019 · ห้ามแตะ OOS ที่ยังสะอาด · ห้ามแตะ 2026-08 เป็นต้นไป (สงวนไว้ให้ forward) — lab ฝึกออกแบบไม่ควรเผาข้อมูลที่ยังใช้ตัดสินได้

ขั้นที่ 1 เขียนคำถามข้อเดียว เช่น "EA X ยังบวกใน era เก่าไหม" matrix ทุก cell ต้องช่วยตอบคำถามนี้ cell ที่ไม่ช่วยให้ตัดทิ้ง

ขั้นที่ 2 ดูว่า broker ไหนมี tick ครบ 12 เดือนปีไหน

bt\ea-bt.exe tick_years --own

tick_years อ่าน file tick ที่อยู่ในเครื่องแล้วเท่านั้น ถ้ายังไม่เคยดึงย้อนไปปีที่ต้องการ ให้ run tick_depth --terminal mt5\MT5_<ชื่อ> --from <YYYY-MM> ก่อน (ปิด MT5 ตัวนั้นก่อน) · * ต่อท้ายเดือนแรก = file เล็กกว่า 60% ของเดือนอื่น อาจดึงไม่ครบเดือน

บนเครื่องผู้สอน ก่อนปี 2022 มีแค่ Robo-Cen จึงมี broker เดียว เครื่องคุณอาจต่างกัน

ขั้นที่ 3 ทุก cell ตรวจช่วงด้วย is_oos --check แล้วจดว่าเป็น block อะไร

bt\ea-bt.exe is_oos --check 2025-01-01 2025-06-30
bt\ea-bt.exe is_oos --check 2017-01-01 2017-06-30

output จริง:

2025-01-01 .. 2025-06-30 → IS 2025                                                        (exit 0)
2017-01-01 .. 2017-06-30 → ★ matches no block — this range is neither IS nor OOS under the policy   (exit 1)

อ่านแบบนี้:

  • ครึ่งแรก 2025 → IS 2025 exit 0 แปลว่าชน block จริง ต้องถามต่อว่า block นั้นใช้ไปแล้วหรือยัง (บัญชีช่วงที่ใช้ไปแล้วอยู่ใน docs\backtest-data-rules.md) exit 0 ไม่ได้แปลว่าใช้ได้
  • ครึ่งแรก 2017 → matches no block exit 1 เพราะ block มาตรฐานครอบแค่ปี 2022–2026 ช่วงนี้จึงไม่ใช่ IS หรือ OOS ของกติกา ใน lab นี้เป็น era เก่าบน Robo-Cen ที่อนุญาต ให้จดว่า "นอก block"

ขั้นที่ 4 ตัด cell ที่ tick ไม่ครบ ให้ broker ที่สั้นที่สุดตัดสินช่วง ถ้าอยากได้ช่วงยาวกว่าบน broker บางตัว → แยก config

ขั้นที่ 5 นับ broker ที่อิสระจริง feed เดียวกันนับหนึ่ง (หัวข้อ 2)

ขั้นที่ 6 นับ k เองตามกติกา A1-3 แล้วดูว่าเส้น t ขยับไปเท่าไร ใช้รายงาน lab ของ Standard

bt\ea-bt.exe verdict lab\reports\tick-quality\Robo --trials 15

output จริง (k = 15):

15 presets tried -> G4 net-t line moves 2.00 -> 2.93 (Sidak) because the best of 15 was picked

preset                 trade   /day       net     comm     gross  $/trade       R      t   t net    PF   win%    need% DDrel%  result
A1-base                  256    1.2   10896.0      0.0   10896.0  42.5625  0.1641   2.05    2.05  1.30  45.70    39.26   33.7  PASS

จนกว่าจะแก้: อ่านเส้นจากบรรทัดบนเอง ห้ามเชื่อ column result ที่ k = 15 แถวนี้ t net 2.05 < 2.93 คือไม่ผ่าน G4 ถ้าใช้ --trials ให้เทียบ t net กับเส้นในบรรทัด "line moves" ทุกแถวด้วยตัวเอง

verdict --trials 15 ที่ column result ผิด

verdict --trials 15 บน kit ชุดนี้: บรรทัดบนบอกเส้นขยับ 2.00 -> 2.93 แต่แถว A1-base ที่ t net 2.05 ยังขึ้น PASS และท้ายตารางเขียน passed all gates 1/1 — ทั้งสองค่านี้ผิด เพราะ column result ยังใช้เส้น 2.00 ไม่สนเส้นที่ขยับ ค่าที่ถูกคือ 2.05 < 2.93 = ไม่ผ่าน G4

ขั้นที่ 7 (ถ้าเขียน config) ตรวจด้วย dry-run โดยไม่ run จริง

bt\ea-bt.exe run --config bt\config_<ชื่อ>.yaml --dry-run

บรรทัดท้าย (dry-run) would run <n> jobs → n ต้องเท่าจำนวน cell ใน matrix ถ้าไม่เท่า แปลว่า config ไม่ได้ครอบ cell ที่ออกแบบ หรือมีงานเกิน

กับดักที่เจอบ่อย: ใส่วันท้ายเป็น 1 ก.ค.

bt\ea-bt.exe is_oos --check 2025-01-01 2025-07-01
2025-01-01 .. 2025-07-01 → ★ matches no block — this range is neither IS nor OOS under the policy   (exit 1)

block จบที่ 30 มิ.ย. ช่วงที่เกินมาหนึ่งวันทำให้ไม่ตรง block ไหนเลย ทางกัน: เอาวันที่จาก is_oos --year <ปี> --yaml เสมอ ห้ามพิมพ์เอง

ส่งงาน: ตาราง matrix column broker · ช่วง · tick ครบ? · block + k ก่อน → หลัง + บอกคู่ broker ที่ไม่อิสระ

ด่านของ lab: ทุก cell มี tick ครบ · มี k ก่อน → หลัง · บอกคู่ broker ที่ไม่อิสระ

เฉลย — ทำเองก่อนแล้วค่อยเปิด

ไม่มีคำตอบเดียว เพราะ tick ในเครื่องแต่ละคนต่างกัน ตรวจงานตัวเองด้วยคำถามเหล่านี้

ตรวจ ผ่านเมื่อ
คำถาม ข้อเดียว ทุก cell ช่วยตอบ
tick ทุก cell มีเดือนครบใน tick_years --own ไม่มี * ในเดือนที่ใช้
block ทุก cell มีผล is_oos --check จดไว้ · cell ที่ exit 0 มีคำตอบว่า block นั้นใช้ไปแล้วหรือยัง · ไม่มี OOS ที่ยังสะอาด ไม่มี 2026-08 เป็นต้นไป
ช่วง broker ที่สั้นที่สุดตัดสินช่วง ไม่ได้ยืด
broker อิสระ feed เดียวกันนับหนึ่ง (เช่น Robo-Cen กับ Robo-ECN = หนึ่ง)
k นับเฉพาะ cell ที่มีสิทธิ์ถูกเลือก · cell ที่ใช้ตรวจการทำซ้ำ (แบบ C0) เขียนไว้ว่าไม่นับ
dry-run จำนวนงาน = จำนวน cell

ตัวอย่างการอ่าน verdict --trials 15 บนรายงาน Robo: t net 2.05 ไม่ถึงเส้น 2.93 → ไม่ผ่าน G4 แม้ column result จะขึ้น PASS (bug ที่ระบุไว้ข้างบน) · รายงานนี้อยู่ในช่วง ม.ค.–ก.ค. 2026 ซึ่งเป็นช่วงข้อมูลที่ใช้ไปแล้ว

ถ้าเครื่องคุณมีแค่ Robo-Cen ก่อนปี 2022 (แบบเครื่องผู้สอน) matrix สำหรับคำถาม "era เก่า" จะมี broker อิสระแค่หนึ่ง ต้องเขียนข้อจำกัดนี้ไว้ในคำถาม ไม่ใช่เติม broker ที่ tick ไม่ครบเข้าไปให้ดูครบ


จุดที่มักพลาด

พลาด ผลที่ตามมา ทางกัน
ยืดช่วงไปตาม broker ที่ข้อมูลยาวที่สุด cell ของ broker ที่สั้นใช้ tick ที่ MT5 สร้างเอง broker ที่สั้นสุดตัดสินช่วง · แยก config
นับ k หลัง run เส้น t ขยับจนไม่ผ่าน แล้วอยากตัด cell ทิ้ง นับ k ในขั้นออกแบบ เขียนลง prereg
นับ 4 broker เป็น 4 ตัวอย่าง มั่นใจเกินจริง (Robo-Cen ตรง Robo-ECN 91%) นับเฉพาะ feed ที่อิสระ
คิดว่าหลาย broker ยืนยันกัน = ข้อสรุปแข็ง พังเมื่อเปลี่ยน era (mode V ต่ำ) แยกราย era ก่อนสรุป
อ่าน backtest เหมือนไม่มี slippage edge ที่เห็นถูกกินหมดบนบัญชีจริง (EA-A 0.38R) เลือก broker ก่อน tune · คิดต้นทุนจริง
ใช้ delay ทดสอบ EA ที่เข้าด้วย pending ได้ "ผ่าน" ที่ไม่มีความหมาย (0/181) ใช้ด่านต้นทุนแทน
เห็น DD ลดเมื่อ risk เพิ่มแล้วสรุปว่า risk สูงดีกว่า อ่านผลที่ lot ถูกตัดเงียบ ๆ cap_scan
อ่าน walk-forward โดยไม่นับ trade ต่อ leg E[R] "ดีขึ้น" เพราะ leg อ่อนหายเอง นับ trade ต่อ leg ต่อ test period ก่อน
mc --from/--to กับ EA ที่มีสถานะข้าม trade ผลของช่วงที่ตัดผิด run จริงในช่วงนั้น
ใส่วันท้าย 1 ก.ค. matches no block ใช้วันที่จาก is_oos --year --yaml
เชื่อ column result ของ verdict --trials เห็น PASS ทั้งที่ต่ำกว่าเส้น เทียบ t net กับเส้นเอง

ทวนท้ายบท

A6-Q

  1. is_oos --check 2025-01-01 2025-07-01 ได้ "matches no block" เพราะอะไร
  2. signal เดียวกัน run บน 4 broker นับเป็นกี่ตัวอย่าง
  3. sweep risk แล้ว DD ลดลงเมื่อ risk เพิ่ม แปลว่าอะไร และตรวจด้วยอะไร
เฉลย
  1. ขอบท้ายเกิน block — block จบวันที่ 30 มิ.ย. ช่วงที่ลากถึง 1 ก.ค. จึงไม่ตรง block ไหน (2025-01-01 .. 2025-06-30 ได้ IS 2025)
  2. ไม่ใช่ 4 นับเฉพาะ feed ที่อิสระจริง Robo-Cen ตรง Robo-ECN 91% จึงไม่อิสระ
  3. volume_max ตัด lot เงียบ ๆ ตรวจด้วย cap_scan