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

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

A5-1

สูตรคิด 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% ของทุน

ลำดับเหตุการณ์:

  1. EA เชื่อค่าที่ broker ส่งมาตรง ๆ เงินต่อ lot จึงเล็กไป 100 เท่า
  2. เงินต่อ lot อยู่ในตัวหาร ตัวหารเล็กไป 100 เท่า lot จึงใหญ่ไป 100 เท่า
  3. ด่าน margin ตัด lot ลงเพราะ margin ไม่พอ ไม่ใช่เพราะ risk เกิน ด่านนี้ไม่ได้คิดว่าหลังตัดแล้ว risk เหลือกี่ % จึงปล่อย 22.7 lot ผ่านไป
  4. trade นั้นบังเอิญไปถูกทาง บัญชีจึงรอด ถ้าผิดทาง portfolio ไม่ได้แค่แตก แต่ติดลบ

สิ่งที่ต้องจำ: bug นี้ไม่ใช่ผล backtest เพี้ยน แต่เป็น code ที่ส่งคำสั่งจริงแล้วเสียเงินจริง

2 · กฎคิด lot 7 ข้อ

A5-2

ข้อ กฎ ทำไม
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

A5-3

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 ทุกตัว) ค่าเพดานที่ตั้งไว้จึงไม่ทำงาน

บทเรียน:

  1. อ่าน default ทุกตัว ไม่ใช่แค่ input ที่คุณตั้งเอง input ที่ไม่ได้อยู่ใน .set ใช้ค่า default ของ code
  2. ด่านตรวจต้องไม่ใช้ตัวเลขชุดเดียวกับสิ่งที่มันตรวจ ด่านที่หารด้วยยอดสูงสุดเหมือนสูตร lot จะผ่านเสมอ
  3. ห้ามต่อเส้นผลจาก risk ต่ำไปเดาผลที่ risk สูง risk จริงไม่ได้โตตาม risk ที่ตั้งเป็นเส้นตรงเมื่อ DD ลึก

4 · version · ping log · compile

A5-4

เลข 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% ให้ซ้ำได้ก่อนแก้

A5-L

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

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 ทั้งคู่

check_version และ check_ping_log

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 ก่อน

ทวนท้ายบท

A5-Q

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