A5 · สร้าง/แก้ EA ให้ปลอดภัย
▶ clip: https://youtu.be/hHDWFW8A7lg
จบบทนี้แล้วทำได้:
- อธิบายได้ว่า EA ที่ตั้ง risk 7% ยิงจริง 136% ของทุนได้ยังไง และด่านไหนควรจับได้แต่ไม่จับ
- คิด lot จาก risk% ด้วยมือ แล้วเทียบกับเครื่องมือ
lot_checkให้ได้ค่าเดียวกัน - อ่าน default ของ input ที่เปลี่ยน risk จริงโดยไม่บอก (เช่น
OnlyUp) และคิด risk จริงจาก DD ได้ - ตรวจเลข version ให้ตรงกันทุกจุด และตรวจว่า EA จด ping ก่อน compile
ต้องมีก่อน: ติดตั้ง kit แล้ว (M0-LAB) · ใช้ symbol_check เป็น · lab นี้ไม่มี backtest เป็นการคำนวณล้วน
1 · case 136%: ตั้ง 7% ยิงจริง 22.7 lot

สูตรคิด lot จาก risk% มีตัวแปรสี่ตัว:
lot = ทุน × risk% ÷ (SL × เงินต่อ lot)
ตัวที่พังคือ เงินต่อ lot (เงินที่ 1 lot ได้หรือเสียเมื่อราคาขยับ 1.00)
| ขั้น | ค่า |
|---|---|
| ตั้ง risk | 7% |
| lot ที่ควรได้ | 1.17 |
Exness ส่ง tick_value บน cent account |
0.001 (ค่าที่ถูกคือ 0.1 · ผิด 100 เท่า) |
| สูตรสั่ง | 117 lot |
| ด่าน margin ตัดเหลือ | 22.7 lot |
| risk ที่เกิดจริง | 136% ของทุน |
ลำดับเหตุการณ์:
- EA เชื่อค่าที่ broker ส่งมาตรง ๆ เงินต่อ lot จึงเล็กไป 100 เท่า
- เงินต่อ lot อยู่ในตัวหาร ตัวหารเล็กไป 100 เท่า lot จึงใหญ่ไป 100 เท่า
- ด่าน margin ตัด lot ลงเพราะ margin ไม่พอ ไม่ใช่เพราะ risk เกิน ด่านนี้ไม่ได้คิดว่าหลังตัดแล้ว risk เหลือกี่ % จึงปล่อย 22.7 lot ผ่านไป
- trade นั้นบังเอิญไปถูกทาง บัญชีจึงรอด ถ้าผิดทาง portfolio ไม่ได้แค่แตก แต่ติดลบ
สิ่งที่ต้องจำ: bug นี้ไม่ใช่ผล backtest เพี้ยน แต่เป็น code ที่ส่งคำสั่งจริงแล้วเสียเงินจริง
2 · กฎคิด lot 7 ข้อ

| ข้อ | กฎ | ทำไม |
|---|---|---|
| 1 | ห้าม hardcode เงินต่อ lot | ทองมี contract size อย่างน้อย 3 ค่า (1 / 10 / 100) ค่าคงที่ตัวเดียวถูกได้แค่บาง symbol |
| 2 | หาตัวคูณสกุลบัญชีจากหลายหลักฐานที่อิสระกัน แล้วเอาค่ามากสุด | ดูหัวข้อ "ทำไมค่ามากสุด" ข้างล่าง |
| 3 | หลักฐานขัดกัน หรือได้ค่าที่ไม่ใช่ 1 หรือ 100 → ไม่ยิง | ไม่ trade ดีกว่า trade ด้วยขนาดที่ไม่รู้ |
| 4 | ทุกด่านที่ตัด lot ต้องรายงาน risk% ที่เหลือจริง | case 136% คือด่าน margin ที่ตัดแล้วไม่บอก |
| 5 | มีด่านสุดท้ายตรวจทุก trade | คิด risk% ที่จะเกิดจริงหลังปัด/ตัด lot ทุกครั้งก่อนส่งคำสั่ง |
| 6 | ทดสอบให้ครอบ contract size 1 / 10 / 100 | bug ที่ซ่อนในค่าหนึ่งจะไม่โผล่ในอีกค่า |
| 7 | จำลอง case จริงให้ซ้ำได้ก่อนแก้ | ทำใน Lab ของบทนี้ |
ตัวแปรที่เชื่อตรง ๆ ไม่ได้ (ตารางขวาบนจอ):
| ตัวแปร | ปัญหา |
|---|---|
contract_size |
ต้องทดสอบ 1 / 10 / 100 |
tick_value |
Exness cent ส่ง 0.001 ค่าที่ถูกคือ 0.1 |
| ตัวคูณสกุล | ต้องได้ 1 หรือ 100 (cent = USC) |
volume_max |
ตัด lot เงียบ ๆ (ดู A6 หัวข้อ 4) |
ทำไมเอาค่ามากสุด: ความผิดพลาดสองทางเสียหายไม่เท่ากัน
- ประเมินตัวคูณต่ำไป → เงินต่อ lot เล็ก → lot ใหญ่เกิน → portfolio แตก
- ประเมินตัวคูณสูงไป → เงินต่อ lot ใหญ่ → lot เล็กเกิน → แค่กำไรน้อยลง
ถ้าต้องผิด ให้ผิดทางที่ไม่ทำให้บัญชีแตก lot_check ใน kit ใช้หลักฐานสามทาง (ชื่อสกุลเงิน · OrderCalcProfit ของ 1 lot ที่ขยับ 1.00 · margin ของ 1 lot) แล้วเลือกค่ามากสุด
3 · default ที่ฆ่า portfolio

input OnlyUp=true ทำให้ EA คิด lot จาก balance สูงสุดที่เคยมี ไม่ใช่ balance ปัจจุบัน ผลคือ
risk จริง = risk ที่ตั้ง ÷ (1 − DD)
ทำไมเป็นสูตรนี้: lot คิดจากยอดสูงสุด แต่เงินที่เหลือในบัญชีคือยอดสูงสุด × (1 − DD) ขนาดความเสียหายต่อ trade เท่าเดิม แต่ทุนที่ต้องรับลดลง สัดส่วนจึงโตขึ้น
| DD | risk จริงต่อ trade (ตั้ง 7%) |
|---|---|
| 0% | 7% |
| 50% | 14% |
| 80% | 35% |
ยิ่ง DD ลึก risk จริงยิ่งพุ่ง ช่วงที่บัญชีอ่อนแอที่สุดคือช่วงที่ EA เสี่ยงมากที่สุด
case จริง (EA-B risk 7%):
- สูตรนี้ทำนายได้ ×133 และบัญชีแตกวันที่ 7 มี.ค. 2025
- สูตรตรงกับของจริงในช่วง 0.97–1.03 เท่า
- 22 จาก 28 preset รับ default
trueมาเงียบ ๆ - ด่านตรวจ risk ใน EA ก็หารด้วยยอดสูงสุดตัวเดียวกัน จึงคิดว่า risk ยังเป็น 7% และมองไม่เห็นปัญหา
- guard รายวันของ preset PROD ปิดหมด (
Use*=falseทุกตัว) ค่าเพดานที่ตั้งไว้จึงไม่ทำงาน
บทเรียน:
- อ่าน default ทุกตัว ไม่ใช่แค่ input ที่คุณตั้งเอง input ที่ไม่ได้อยู่ใน
.setใช้ค่า default ของ code - ด่านตรวจต้องไม่ใช้ตัวเลขชุดเดียวกับสิ่งที่มันตรวจ ด่านที่หารด้วยยอดสูงสุดเหมือนสูตร lot จะผ่านเสมอ
- ห้ามต่อเส้นผลจาก risk ต่ำไปเดาผลที่ risk สูง risk จริงไม่ได้โตตาม risk ที่ตั้งเป็นเส้นตรงเมื่อ DD ลึก
4 · version · ping log · compile

เลข version ต้องตรงกัน 5 จุด ชื่อ file เป็นตัวตั้ง ที่เหลือต้องตามให้ครบ:
| จุด | ตัวอย่างจาก eas\LAB_MACROSS\LAB_MACROSS_v1.00.mq5 |
|---|---|
| 1 · ชื่อ file ในหัว comment | //| LAB_MACROSS_v1.00.mq5 | |
2 · #property version |
#property version "1.00" |
3 · EA_VER |
#define EA_VER "1.00" |
4 · PresetTag |
input string PresetTag = "v1.00 default"; |
5 · SrvInit(...) |
เฉพาะ EA ที่รายงานเข้า server ของผู้สอน — EA ใน kit ไม่มีจุดนี้ จึงเหลือ 4 จุด |
ตรวจด้วย
bt\ea-bt.exe check_version --only <EA>
ต้องได้ 0 จุดที่ไม่ตรง case จริง: EA-A รุ่นทดลอง v0.12 รายงานตัวเองว่าเป็น 0.11 เพราะลืมแก้ EA_VER จุดเดียว EA_VER เป็นจุดที่ลืมบ่อยที่สุด เพราะอยู่กลาง file ไม่ได้อยู่บนหัว
ping log: ทุก EA ที่ส่งคำสั่ง trade ต้องประกาศ CTradePing แทน CTrade (LAB_MACROSS ทำแล้ว: CTradePing trade;) แล้ว
bt\ea-bt.exe check_ping_log
ต้อง exit 0
ping ไม่ได้อธิบายทุกอย่าง:
| เหตุการณ์ | ping มีผลไหม | ทำไม |
|---|---|---|
| entry ด้วย pending order | ไม่มี | ใบนอนรออยู่ฝั่ง broker แล้ว ตอนราคาชนไม่มี packet วิ่งจาก VPS slippage ตอน entry จึงไม่เกี่ยวกับ ping |
| ปิดด้วย market | มี | EA ส่งคำสั่งตอนนั้น |
| เลื่อน SL | มี | EA ส่งคำสั่งแก้ใบตอนนั้น |
compile: สั่ง MetaEditor ต้องใส่ option /portable ถ้าไม่ใส่ MetaEditor หา Trade.mqh ไม่เจอ (error 106)
Lab · จำลอง bug 22.7 lot / 136% ให้ซ้ำได้ก่อนแก้

lab นี้ไม่มี backtest เป็นการคำนวณล้วน ทุกคำสั่งพิมพ์ bt\ea-bt.exe นำหน้า
ทำไมต้องจำลอง bug ก่อนแก้: ถ้าแก้ก่อน คุณจะพิสูจน์ไม่ได้ว่าแก้ถูกจุด เพราะไม่มีตัวเลข "ก่อนแก้" ให้เทียบ
ขั้นที่ 1 run case จริง
bt\ea-bt.exe lot_check --bug
output จริง:
before fix: EA uses money per lot = 1 (trusts OrderCalcProfit reported in USD)
money per lot (right) 100 (contract 1 x multiplier 100)
money per lot (EA) 1 ← wrong
lot from formula 116.88
after margin cap 22.68
real risk% 135.82% of capital (set 7%)
final gate (x1.5) NO FIRE — real risk% above the setting
after fix: multiplier from three independent sources
money per lot (right) 100 (contract 1 x multiplier 100)
lot from formula 1.16
real risk% 6.95% of capital (set 7%)
final gate (x1.5) FIRE

lot_check --bug บน kit จริง: ก่อนแก้ lot from formula 116.88 → after margin cap 22.68 → real risk% 135.82% แล้วด่านสุดท้าย NO FIRE · หลังแก้ 1.16 lot · 6.95% · FIRE
จดสามค่า: lot ที่สูตรสั่ง · lot หลัง margin ตัด · risk% จริง
ขั้นที่ 2 ดู spec ของ symbol ทองบน terminal ของคุณ
bt\ea-bt.exe symbol_check --terminal mt5\MT5_<ชื่อ> --symbol <ทอง>
จด contract_size · tick_value · lot min / max / step · สกุลเงินบัญชีดูใน MT5
ขั้นที่ 3 คิด lot ด้วยทุนของคุณ risk 1% SL 10
bt\ea-bt.exe lot_check --balance <ทุน> --risk 1 --sl 10 --contract <ค่าจากขั้น 2> --ccy <สกุล>
จด lot และ risk% จริง · บน cent account ใส่ --balance เป็นหน่วย cent
ขั้นที่ 4 เปิด eas\LAB_MACROSS\LAB_MACROSS_v1.00.mq5 หา function LotsForRisk() แล้วคิดด้วยมือด้วยค่าเดียวกับขั้น 3 ต้องได้ lot เท่าขั้น 3
LotsForRisk() คิดแบบนี้ (ย่อจาก code):
lossPerLot = −OrderCalcProfit(1 lot, entry → SL) // เงินที่ 1 lot เสียถ้าโดน SL
lots = balance × InpRiskPct / 100 / lossPerLot
lots = ปัดลงตาม SYMBOL_VOLUME_STEP
ถ้า lots > volume_max → ตัดลง (พิมพ์ log)
ถ้า lots < volume_min → ไม่ยิง (ไม่ปัดขึ้น เพราะปัดขึ้นคือเสี่ยงเกินที่ตั้ง)
ด่านสุดท้าย: risk จริง = lots × lossPerLot / balance × 100
ถ้าเกิน InpRiskPct × InpOvershootX (1.5) → ไม่ยิง
ถ้าไม่เท่ากัน แปลว่า broker รายงาน OrderCalcProfit คนละหน่วยกับที่ควร (แบบเดียวกับ case 136%) ให้หยุดและรายงาน ไม่ใช่เลือกค่าใดค่าหนึ่ง สังเกตว่า LotsForRisk() ใช้ OrderCalcProfit เป็นหลักฐานทางเดียว และด่านสุดท้ายก็คิดจาก lossPerLot ตัวเดียวกัน ถ้า OrderCalcProfit ผิด ด่านสุดท้ายจะผิดตามไปด้วย การเทียบกับ lot_check ในขั้นนี้คือหลักฐานทางที่สอง
ขั้นที่ 5 ลองสาม case แล้วดูว่า case ไหนยิง case ไหนไม่ยิง และ exit code
bt\ea-bt.exe lot_check --balance <ทุน> --risk 1 --sl 10 --contract <ค่าเดิม> --ccy <สกุล> --used 1
bt\ea-bt.exe lot_check --balance <ทุน> --risk 1 --sl 10 --contract 10 --ccy <สกุล>
bt\ea-bt.exe lot_check --balance <ทุน> --risk 1 --sl 10 --contract 0 --ccy <สกุล>
--used คือเงินต่อ lot ที่ EA ใช้จริง ใส่ค่าผิดเพื่อจำลอง bug · case ที่ไม่ยิงต้อง exit 1 · --contract 0 ต้องไม่ยิง
ขั้นที่ 6 ถ้าแก้ file EA ต้อง bump version (file ใหม่ ห้ามเขียนทับ) แล้ว
bt\ea-bt.exe check_version
bt\ea-bt.exe check_ping_log
ต้อง exit 0 ทั้งคู่

kit ที่ยังไม่แก้อะไร: check_version ตรวจ 1 file mismatched 0 และบอกว่า not compiled yet (no .ex5) เพราะ kit แจกแค่ source .mq5 (ยังไม่ได้ compile) · check_ping_log ขึ้น missing ping log 0 · หลัง bump version ต้องได้ 0 จุดไม่ตรงแบบนี้เหมือนเดิม
ด่านของ lab: lot ที่คิดมือ = lot_check · อธิบายได้ว่าทำไม 22.68 ผ่านด่าน margin แต่ตกด่านสุดท้าย · contract 0 = ไม่ยิง
ปิด lab ด้วยตารางสอง column ก่อนแก้ / หลังแก้ (lot · risk% จริง · ยิงไหม)
เฉลย — ทำเองก่อนแล้วค่อยเปิด
ขั้นที่ 1
| ก่อนแก้ | หลังแก้ | |
|---|---|---|
| เงินต่อ lot ที่ใช้ | 1 (ผิด) | 100 |
| lot จากสูตร | 116.88 | 1.16 |
| หลัง margin ตัด | 22.68 | — |
| risk% จริง | 135.82% | 6.95% |
| ด่านสุดท้าย (×1.5) | ไม่ยิง | ยิง |
ทำไม 22.68 ผ่านด่าน margin แต่ตกด่านสุดท้าย: ด่าน margin ถามแค่ว่า "margin พอไหม" แล้วตัด lot ลงจนพอ มันไม่ได้คิด risk% เลย ส่วนด่านสุดท้ายคิด risk% จริงด้วยเงินต่อ lot ที่ถูก (100) ได้ 135.82% เกิน 7% × 1.5 = 10.5% จึงไม่ยิง
1.16 กับ 1.17: clip บอกว่าควรได้ 1.17 แต่เครื่องมือได้ 1.16 เพราะ 10,019 × 7% ÷ (6 × 100) = 1.1689 เครื่องมือปัดลงตาม step 0.01 (ปัดขึ้นคือเสี่ยงเกินที่ตั้ง) จึงได้ risk จริง 6.95% ไม่ถึง 7%
ขั้นที่ 3–5 ตัวอย่างนี้ใช้ทุน 10,000 บัญชี USD contract 100 เพื่อ show รูปแบบเท่านั้น ค่าของคุณต้องมาจากขั้น 2
bt\ea-bt.exe lot_check --balance 10000 --risk 1 --sl 10 --contract 100 --ccy USD
money per lot (right) 100 (contract 100 x multiplier 1)
lot from formula 0.10
real risk% 1.00% of capital (set 1%)
final gate (x1.5) FIRE → exit 0
คิดมือตาม LotsForRisk(): โดน SL 10 ที่ contract 100 → 1 lot เสีย 10 × 100 = 1,000 → lots = 10,000 × 1 / 100 / 1,000 = 0.10 ตรงกับ lot_check
| case | ผล | exit |
|---|---|---|
--used 1 |
lot 10.00 · risk จริง 100.00% · ไม่ยิง | 1 |
--contract 10 |
เงินต่อ lot 10 · lot 1.00 · risk จริง 1.00% · ยิง | 0 |
--contract 0 |
ไม่ยิง — spec ไม่ครบหรือตัวคูณไม่ใช่ 1/100 | 1 |
--used 1 คือ bug เดียวกับ case 136% บนบัญชี USD: lot ใหญ่ไป 100 เท่า ด่านสุดท้ายจับได้เพราะคิด risk ด้วยเงินต่อ lot ที่ถูก
จุดที่มักพลาด
| พลาด | ผลที่ตามมา | ทางกัน |
|---|---|---|
เชื่อ tick_value หรือ OrderCalcProfit ทางเดียว |
lot ผิด 100 เท่าบน cent account | หาตัวคูณจากหลายหลักฐาน เอาค่ามากสุด ขัดกัน = ไม่ยิง |
| ด่านตัด lot ไม่รายงาน risk% ที่เหลือ | 22.7 lot = 136% ผ่านไปเงียบ ๆ | ทุกด่านที่ตัด lot พิมพ์ risk% จริงหลังตัด |
| ไม่อ่าน default ของ input | OnlyUp=true ทำ risk จริงพุ่งตาม DD (22/28 preset) |
อ่าน default ทุกตัว ไม่ใช่แค่ที่อยู่ใน .set |
| ด่านตรวจใช้ตัวเลขชุดเดียวกับสูตร | ด่านผ่านเสมอ มองไม่เห็นปัญหา | ด่านต้องคิดจากค่าที่อิสระจากสูตร |
| ต่อเส้นผลจาก risk ต่ำไป risk สูง | ประเมิน DD และ risk จริงต่ำเกิน | วัดที่ risk นั้นจริง |
ลืมแก้ EA_VER |
EA รายงาน version ผิด | check_version --only <EA> ต้อง 0 จุดไม่ตรง |
| คิดว่า ping อธิบาย slippage ตอน entry ของ pending | วิเคราะห์ผิดสาเหตุ | ping มีผลเฉพาะตอนปิดด้วย market และเลื่อน SL |
compile โดยไม่ใส่ /portable |
error 106 หา Trade.mqh ไม่เจอ |
ใส่ /portable ทุกครั้ง |
| แก้สูตรก่อนจำลอง bug | พิสูจน์ไม่ได้ว่าแก้ถูกจุด | run lot_check --bug ก่อน |
ทวนท้ายบท

- ประเมินตัวคูณสกุลผิดทางไหนอันตรายกว่า และเมื่อหลักฐานขัดกันต้องทำอะไร
- preset risk 7% ที่
OnlyUp=trueขณะ DD 50% risk จริงต่อ trade เท่าไร - เลข version ต้องตรงกันกี่จุด อะไรบ้าง
เฉลย
- ประเมินต่ำอันตรายกว่า เพราะ lot ใหญ่เกินจน portfolio แตก ส่วนประเมินสูงแค่กำไรน้อยลง เมื่อหลักฐานขัดกัน หรือได้ค่าที่ไม่ใช่ 1 หรือ 100 → ไม่ยิง
- 7% ÷ (1 − 0.5) = 14%
- 5 จุด ชื่อ file ในหัว comment ·
#property version·EA_VER·PresetTag·SrvInit(EA ใน kit ไม่มีSrvInitจึงตรวจ 4 จุด)