ทำให้ EA หยุดเองเมื่อขาดทุนถึงลิมิตต่อวัน — Daily Loss Limit ที่ใช้ได้จริง (2026)

มีเทรดเดอร์คนหนึ่งทักมาหาผมตอนเจ็ดโมงเช้า ข้อความแรกคือภาพหน้าจอแดชบอร์ดของ prop firm ขึ้นตัวแดงคำเดียว: Daily Loss Limit Breached
เขาสอบ challenge มาสองรอบแล้ว รอบนี้ผ่านครึ่งทางมาด้วยดี EA ที่ใช้ก็ "มี daily loss limit" — เขาย้ำคำนี้กับผมหลายรอบ เพราะตอนซื้อมา คนขายบอกว่ามี และในหน้า input ของ EA ก็มีช่องให้กรอกจริงๆ
คืนที่พัง ราคาวิ่งแรงช่วงตีสองตามเวลาไทย ไม้ที่ลอยอยู่ติดลบลึกลงเรื่อยๆ EA ไม่ได้ทำอะไรเลยจนกว่าแท่ง H1 ใหม่จะเปิด พอมันตื่นมาเช็ก ตัวเลขก็เลยเส้นที่ prop firm ขีดไว้ไปแล้ว ไม่มีปุ่มย้อนเวลา บัญชีจบตรงนั้น ค่าสอบหายไปอีกหนึ่งรอบ — ทั้งที่ ถ้า EA ตัดตัวเองเร็วกว่านั้นสักสองนาที บัญชีจะยังอยู่
ผมรับเขียนและแก้ EA มา 15 ปี เคสแบบนี้เจอบ่อยจนเล่าได้โดยไม่ต้องเปิดแชตดู และเกือบทุกเคสพังด้วยสาเหตุซ้ำๆ ไม่กี่ข้อ ซึ่งทั้งหมดแก้ได้ด้วยโค้ดไม่ถึงร้อยบรรทัด — ถ้ารู้ว่าต้องระวังตรงไหน
บทความนี้จะพาทำ circuit breaker หรือเบรกเกอร์ตัดวงจรให้ EA: ขาดทุนถึงลิมิตของวัน → ปิดไม้ทั้งหมด → หยุดเทรดจนกว่าจะขึ้นวันใหม่ โดยเจาะจุดที่คนพลาดจริงๆ ทีละจุด ตั้งแต่เรื่องที่ฟังดูง่ายที่สุดอย่าง "วันใหม่เริ่มตอนไหน" (คำตอบไม่ใช่เที่ยงคืนบ้านเรา) ไปจนถึงกับดักในโค้ดที่ทำให้ปิดไม้ไม่ครบแบบเงียบๆ
เขียนให้คนเทรด prop firm เป็นหลัก เพราะกลุ่มนี้เจ็บจริงเจ็บไว — ลิมิตของ prop firm ไม่ใช่คำเตือน มันคือเส้นตายของบัญชี แต่ถ้าคุณเทรดพอร์ตตัวเอง ทุกอย่างในบทความนี้ใช้ได้เหมือนกัน แค่เปลี่ยนคนขีดเส้นจาก prop firm มาเป็นตัวคุณเอง
ทำไม EA ส่วนใหญ่ "มี daily loss limit" แต่คุมไม่อยู่จริง
EA ที่ผมรับมาแก้ ส่วนใหญ่ไม่ได้ไม่มีระบบจำกัดขาดทุน — มันมี แต่มีแบบที่ใช้งานจริงไม่ได้ ปัญหาแยกได้เป็นสามชั้น และ EA จำนวนมากพลาดครบทั้งสามชั้นพร้อมกัน
ชั้นที่ 1: เช็กลิมิตเฉพาะตอนเปิดแท่งใหม่ ไม่ได้เช็กทุก tick
EA จำนวนมากถูกเขียนให้ทำงานหนักเฉพาะตอน "แท่งใหม่เปิด" ซึ่งเป็นแนวทางที่ดีสำหรับตรรกะหาสัญญาณเข้า — ประหยัดเครื่อง ไม่เทรดถี่เกิน แต่พอเอาแนวทางเดียวกันไปใช้กับการเช็กลิมิตขาดทุน มันกลายเป็นหายนะทันที
ลองนึกภาพ EA ที่รันบน H1 แล้วเช็กลิมิตแค่ตอนแท่งเปิด: ระหว่าง 60 นาทีในแท่งนั้น ราคาจะวิ่งไปไหนก็ได้ ข่าวแรงออกตอนนาทีที่ 5 ไม้ที่ลอยอยู่ติดลบทะลุลิมิตตอนนาทีที่ 12 — EA จะรู้ตัวตอนนาทีที่ 60 ซึ่งความเสียหายจริงอาจเลยลิมิตไปแล้วเท่าตัว
ลิมิตขาดทุนไม่ใช่สัญญาณเทรด มันคือระบบความปลอดภัย และระบบความปลอดภัยต้องทำงาน ทุก tick เหมือนเบรกรถที่ต้องพร้อมทุกวินาที ไม่ใช่เช็กทุกต้นชั่วโมง การเช็กแบบนี้แทบไม่กินเครื่องเลย (เดี๋ยวเห็นในโค้ดว่ามันคือการบวกเลขไม่กี่ค่า) ดังนั้นข้ออ้างเรื่อง performance ฟังไม่ขึ้น
ชั้นที่ 2: นับแต่ขาดทุนที่ "ปิดแล้ว" ไม่นับไม้ที่ยังลอยอยู่
อันนี้เจ็บกว่าชั้นแรก เพราะมัน ดูเหมือนทำงานถูก — EA คำนวณผลรวมของไม้ที่ปิดไปแล้ววันนี้ (realized P&L) เทียบกับลิมิต ตัวเลขใน log สวยงาม ทุกอย่างดูปกติ
แต่ prop firm แทบทุกเจ้าวัด daily loss จาก equity ไม่ใช่จากไม้ที่ปิดแล้ว แปลว่าไม้ที่ยังเปิดอยู่และกำลังติดลบ (floating loss) ถูกนับเต็มๆ ในสายตาของเขา ขณะที่ EA ของคุณไม่เห็นมันเลย
สถานการณ์คลาสสิก: วันนี้ยังไม่ปิดไม้ขาดทุนสักไม้ realized = 0 EA รายงานว่า "ยังห่างลิมิตอีกเยอะ" — แต่มีไม้ลอยติดลบอยู่ 4% ของพอร์ต บวก swap ที่โดนหักไปเมื่อคืนอีกนิด equity จริงเลยเส้นไปแล้ว EA ที่นับแต่ realized จะยิงไม้ใหม่เพิ่มด้วยซ้ำ เพราะในบัญชีของมัน วันนี้ยังขาวสะอาด
ระบบสาย Grid และ Martingale คือกลุ่มที่ตายด้วยข้อนี้บ่อยที่สุด เพราะธรรมชาติของมันคือถือไม้ติดลบหลายไม้พร้อมกันโดยไม่ปิด — realized ดูสวยตลอด จน equity พังในครั้งเดียว
ชั้นที่ 3: ตรวจเจอแล้ว แต่ไม่มี "ประตู" กันยิงออเดอร์ใหม่
ชั้นสุดท้ายคือชั้นที่คนเขียนโค้ดเองพลาดบ่อย: EA ตรวจเจอว่าเกินลิมิต ปิดไม้เรียบร้อย print ข้อความสวยงามว่า "Daily limit reached!" — แล้วบรรทัดถัดมา ตรรกะเทรดปกติของมันก็เจอสัญญาณเข้า และยิงออเดอร์ใหม่ทันที
เพราะการ "ตรวจเจอ" กับการ "ห้ามเทรด" เป็นคนละเรื่องกัน ถ้าไม่มีสถานะกลาง (ผมจะเรียกว่า HALTED) ที่ทุกจุดในโค้ดต้องเช็กก่อนส่งออเดอร์ การตรวจเจอก็เป็นแค่การพิมพ์ log หนึ่งบรรทัด ไม้ใหม่จะถูกเปิด ขาดทุนต่อ แล้ววนกลับมาปิด-เปิดใหม่ไปเรื่อยๆ ทั้งวัน ซึ่งแย่กว่าไม่มีลิมิตเสียอีก เพราะเสียทั้งเงินทั้ง spread ทุกรอบที่วน
สรุปสามชั้นเป็นตารางให้เห็นภาพ:
| จุดพลาด | อาการที่เห็น | ผลลัพธ์จริง |
|---|---|---|
| เช็กเฉพาะแท่งใหม่ | log ปกติดี ไม่มี error | รู้ตัวช้าสุด 1 แท่งเต็มๆ — ขาดทุนเลยลิมิตไปไกลแล้ว |
| นับแต่ realized | ตัวเลขใน log ยังไม่เกินลิมิต | equity จริงเกินไปแล้วเพราะ floating + swap ไม่ถูกนับ |
| ไม่มีประตู HALTED | ปิดไม้แล้ว print แจ้งเตือนด้วย | เปิดไม้ใหม่ในวินาทีถัดมา วนขาดทุนซ้ำทั้งวัน |
เบรกเกอร์ที่ใช้ได้จริงต้องอุดครบทั้งสามชั้น: เช็กทุก tick · นับ P&L รวมทั้ง realized และ floating · มีสถานะ HALTED ที่ปิดประตูจริง — สามหัวข้อถัดไปคือการลงมือทำทีละชั้น แต่ก่อนถึงโค้ด ต้องเคลียร์คำถามที่ฟังดูโง่ที่สุดแต่ทำเงินหายมากที่สุดก่อน: "วันนี้" ของ EA เริ่มตอนไหน
เส้นแบ่งวันคือเที่ยงคืน "เวลาเซิร์ฟเวอร์" — จุดที่คนไทยพลาดมากที่สุด
ถ้าให้เลือกจุดเดียวจากบทความนี้ไปตรวจ EA ที่คุณใช้อยู่ ผมให้ตรวจจุดนี้ก่อนเลย เพราะมันเป็นจุดที่พลาดกันเยอะที่สุด และพลาดแบบไม่รู้ตัวนานเป็นเดือน
คำว่า "ขาดทุนต่อวัน" ต้องมีนิยามว่า "วัน" เริ่มและจบตรงไหน สมองคนไทยจะตอบอัตโนมัติว่าเที่ยงคืนบ้านเรา — แต่ EA ไม่ได้อยู่บ้านเรา มันอยู่กับเซิร์ฟเวอร์ของโบรก และนาฬิกาเดียวที่มันเห็นผ่าน TimeCurrent() คือ เวลาเซิร์ฟเวอร์โบรก
โบรกส่วนใหญ่ในตลาด forex ตั้งเวลาเซิร์ฟเวอร์เป็น GMT+2 หรือ GMT+3 (เพื่อให้แท่ง daily ตรงกับรอบตลาดนิวยอร์กปิด) ขณะที่ไทยอยู่ GMT+7 ลองเทียบดู:
| เวลาเซิร์ฟเวอร์โบรก | เที่ยงคืนเซิร์ฟเวอร์ = เวลาไทย | แปลว่า "วันใหม่" ของ EA เริ่มตอน |
|---|---|---|
| GMT+2 | ตี 5 เช้าบ้านเรา | 05:00 น. ตามเวลาไทย |
| GMT+3 (ช่วง DST) | ตี 4 เช้าบ้านเรา | 04:00 น. ตามเวลาไทย |

ผลที่ตามมาในชีวิตจริงมีสองเรื่องที่ต้องรู้:
เรื่องแรก — ลิมิตไม่รีเซ็ตตอนเที่ยงคืนบ้านเรา สมมติคุณขาดทุนหนักตอน 4 ทุ่มคืนวันจันทร์ เบรกเกอร์ตัดแล้วหยุดเทรด คุณเข้านอนคิดว่า "พรุ่งนี้เริ่มใหม่" — แต่ตี 1 ของบ้านเราคืนนั้นยังเป็น "วันจันทร์" ของเซิร์ฟเวอร์อยู่เลย EA จะไม่ปลดล็อกจนกว่าจะถึงตี 4-5 เช้าวันอังคาร ถ้าคุณเขียนโค้ดให้รีเซ็ตตามเวลาไทย EA จะกลับมาเทรดตอนเที่ยงคืนทั้งที่โควตาขาดทุนของ "วันเซิร์ฟเวอร์" นั้นหมดไปแล้ว — เท่ากับเปิดโอกาสขาดทุนสองเด้งในวันเดียวของ prop firm
เรื่องที่สอง — ช่วงตี 3 ถึงตี 5 คือรอยต่ออันตราย ถ้าคุณ (หรือ EA) เทรดช่วงนั้น คุณกำลังคาบเกี่ยวสองวันเทรดในสายตาของระบบ ไม้ที่เปิดตอนตี 3 อาจไปปิดตอนตี 5 ซึ่งข้ามเส้นแบ่งวันไปแล้ว — ขาดทุนของไม้นั้นจะไปตกอยู่ "วันใหม่" ทั้งที่ความรู้สึกเราคือคืนเดียวกัน ยิ่งใครเทรดช่วงตลาดอเมริกาปิด-เอเชียเปิด ต้องเข้าใจรอยต่อนี้ให้ชัดก่อนตั้งลิมิต
เช็กเวลาเซิร์ฟเวอร์ของโบรกตัวเองยังไง
ง่ายที่สุดคือให้ EA พิมพ์เทียบสองค่าออกมาดูกัน:
// เทียบเวลาเซิร์ฟเวอร์กับเวลาเครื่องเรา — รันครั้งเดียวก็รู้ offset
void PrintServerOffset()
{
Print("เวลาเซิร์ฟเวอร์โบรก : ", TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES));
Print("เวลาเครื่องเรา (ไทย): ", TimeToString(TimeLocal(), TIME_DATE|TIME_MINUTES));
// ผลต่างสองค่านี้คือ offset — โบรก GMT+2 จะห่างจากไทยราว 5 ชั่วโมง
}
TimeCurrent() คือเวลาเซิร์ฟเวอร์ ณ tick ล่าสุด ส่วน TimeLocal() คือเวลาเครื่องที่รัน MT5 (ถ้าเครื่องคุณตั้งเวลาไทย ก็คือเวลาไทย) ผลต่างของสองค่านี้บอก offset ทันที ไม่ต้องไปถาม support โบรก
และพอรู้แล้วว่า "วัน" ของเซิร์ฟเวอร์คืออะไร การหา "เที่ยงคืนของวันนี้" ในโค้ดก็สั้นมาก:
// หาเที่ยงคืนของ "วันนี้" ตามเวลาเซิร์ฟเวอร์
datetime DayStart()
{
datetime now = TimeCurrent();
return now - (now % 86400); // ตัดเศษชั่วโมง/นาที/วินาทีทิ้ง เหลือ 00:00 ของวัน
}
ค่านี้คือจุดตั้งต้นของทุกอย่างในบทความนี้ — ใช้เป็นขอบล่างตอนดึงประวัติเทรด และใช้คำนวณเวลาปลดล็อกของเบรกเกอร์
คำเตือนสองข้อก่อนไปต่อ
หนึ่ง — offset ของโบรกไม่ได้นิ่งตลอดปี โบรกจำนวนมากขยับเวลาเซิร์ฟเวอร์ตาม Daylight Saving Time ของฝั่งยุโรป/อเมริกา คือสลับระหว่าง GMT+2 กับ GMT+3 ปีละสองครั้ง (ราวปลายมีนาคมและปลายตุลาคม) แปลว่า "ตี 5" ที่คุณจำไว้ อาจกลายเป็น "ตี 4" ในอีกครึ่งปี ถ้าโค้ดของคุณอิง TimeCurrent() ตรงๆ แบบข้างบน ตัวโค้ดจะปรับตามเองอัตโนมัติ — แต่ ความเข้าใจของคุณ ต้องปรับตามด้วย โดยเฉพาะถ้าคุณตั้งเวลาห้ามเทรดช่วงรอยต่อวันไว้
สอง — สำคัญมากสำหรับสาย prop firm: "วัน" ของ prop firm อาจไม่ใช่ "วัน" ของโบรก prop firm บางเจ้านับ daily loss ตาม timezone ของบริษัทตัวเอง เช่น ตามเวลายุโรปกลาง หรือรีเซ็ตตอนห้าโมงเย็นเวลานิวยอร์ก ซึ่งอาจไม่ตรงกับเที่ยงคืนเซิร์ฟเวอร์ของโบรกที่บัญชีคุณรันอยู่ ถ้าสองนาฬิกานี้ไม่ตรงกัน คุณจะเจอสถานการณ์พิลึก: EA คุมลิมิตถูกต้องทุกอย่างตามวันของโบรก แต่ prop firm ตัดสินคุณด้วยวันของเขา — คุมถูกวิธี แต่ผิดวัน ก่อนใช้งานจริงต้องเข้าไปอ่านนิยาม "daily" ในกฎของเจ้าที่คุณสอบ แล้วเทียบกับเวลาเซิร์ฟเวอร์บัญชีให้ตรงกัน ถ้าไม่ตรง ทางแก้ที่ปลอดภัยคือขยับเส้นแบ่งวันในโค้ดให้ตามนิยามของ prop firm (เลื่อน DayStart() ด้วย offset คงที่) หรืออย่างน้อยตั้งลิมิตภายในให้เผื่อมากขึ้น
คำนวณผลขาดทุนของวันให้ถูก — realized บวก floating บวก swap
ได้เส้นแบ่งวันแล้ว ต่อไปคือคำถามที่สอง: "วันนี้ขาดทุนไปเท่าไหร่แล้ว" — ตัวเลขนี้ต้องประกอบจากสองก้อนเสมอ
ก้อนแรก: realized — กำไร/ขาดทุนของไม้ที่ปิดไปแล้วตั้งแต่เที่ยงคืนเซิร์ฟเวอร์ ก้อนที่สอง: floating — กำไร/ขาดทุนของไม้ที่ยังเปิดค้างอยู่ ณ วินาทีนี้
ขาดก้อนใดก้อนหนึ่ง ตัวเลขที่ได้คือคนละเรื่องกับ equity ที่ prop firm มองอยู่
ก้อนแรก: อ่าน realized จากประวัติ deal
ใน MT5 การอ่านผลของไม้ที่ปิดแล้วทำผ่านประวัติ deal: เลือกช่วงเวลาด้วย HistorySelect() แล้ววนอ่านทีละ deal
// ผลกำไร/ขาดทุนที่ "ปิดแล้ว" ของวันนี้ (ตามวันเซิร์ฟเวอร์)
double RealizedToday()
{
double total = 0.0;
HistorySelect(DayStart(), TimeCurrent());
for(int i = 0; i < HistoryDealsTotal(); i++)
{
ulong ticket = HistoryDealGetTicket(i);
long entry = HistoryDealGetInteger(ticket, DEAL_ENTRY);
if(entry != DEAL_ENTRY_OUT && entry != DEAL_ENTRY_INOUT)
continue; // นับเฉพาะ deal ขาออก — deal ขาเข้าไม่มี P&L ของตัวเอง
total += HistoryDealGetDouble(ticket, DEAL_PROFIT)
+ HistoryDealGetDouble(ticket, DEAL_SWAP)
+ HistoryDealGetDouble(ticket, DEAL_COMMISSION);
}
return total;
}
จุดที่คนพลาดในโค้ดสั้นๆ นี้มีสองจุด:
จุดแรก — ต้องกรองเฉพาะ DEAL_ENTRY_OUT กับ DEAL_ENTRY_INOUT ใน MT5 การเปิดไม้หนึ่งครั้งและปิดหนึ่งครั้งจะสร้าง deal สองรายการ: deal ขาเข้า (IN) กับ deal ขาออก (OUT) — กำไร/ขาดทุนทั้งหมดถูกบันทึกไว้ที่ deal ขาออกเท่านั้น deal ขาเข้ามีกำไรเป็นศูนย์เสมอเพราะมันยังไม่มีอะไรให้วัด การวนบวกทุก deal โดยไม่กรองจึงได้แต่ศูนย์มารกการคำนวณเปล่าๆ และที่แย่กว่านั้นคือใน history ยังมี deal ประเภทอื่นปนอยู่ เช่น รายการฝาก/ถอนเงินหรือ balance adjustment ซึ่งถ้าเผลอนับเข้าไป ตัวเลข "ขาดทุนวันนี้" จะเพี้ยนทันทีที่มีการเติมเงิน ส่วน DEAL_ENTRY_INOUT คือกรณีไม้ reverse (ปิดฝั่งหนึ่งแล้วเปิดสวนในคำสั่งเดียว) ซึ่งมี P&L ของขาที่ถูกปิดติดมาด้วย ต้องนับเสมอ
จุดที่สอง — ต้องบวก swap และ commission เข้าไปด้วย เพราะ prop firm วัดจาก equity ซึ่งโดนหักสองค่านี้ไปแล้วจริงๆ EA ที่นับแต่ DEAL_PROFIT เปล่าๆ จะรายงานขาดทุนน้อยกว่าความจริงเสมอ ระบบที่เทรดถี่โดน commission กิน ระบบที่ถือข้ามคืนโดน swap กิน — ไม่มีระบบไหนรอดทั้งคู่
ก้อนที่สอง: อ่าน floating จากไม้ที่เปิดอยู่
// ผลกำไร/ขาดทุน "ลอยตัว" ของไม้ที่ยังเปิดอยู่ทั้งหมด
double FloatingNow()
{
double total = 0.0;
for(int i = 0; i < PositionsTotal(); i++)
{
if(PositionGetTicket(i) == 0) continue; // เลือกไม้เข้า context ไปพร้อมกัน
total += PositionGetDouble(POSITION_PROFIT)
+ PositionGetDouble(POSITION_SWAP); // swap คือต้นทุนที่เกิดขึ้นแล้วจริง
}
return total;
}
สังเกตว่าผมบวก POSITION_SWAP เข้าไปด้วย — หลายคนตัดออกเพราะคิดว่า "ยังไม่ปิดไม้ ยังไม่จ่ายจริง" ซึ่งเข้าใจผิดครับ swap ถูกคิดเข้าบัญชีทุกคืนที่ถือข้าม ไม่ว่าไม้จะปิดหรือยัง มันคือต้นทุนที่ เกิดขึ้นแล้ว และสะท้อนอยู่ใน equity แล้ว ไม้ grid ที่ถือมาสองสัปดาห์อาจมี swap สะสมติดลบมากกว่า floating loss ของตัวไม้เองด้วยซ้ำ การไม่นับ swap คือการประเมินความเสี่ยงต่ำกว่าจริง ในจังหวะที่ต้องการความแม่นยำมากที่สุด — คือจังหวะที่กำลังจะชนลิมิต
รวมสองก้อน = ตัวเลขที่เอาไปเทียบลิมิต
บรรทัดเดียวจบ: double pnlToday = RealizedToday() + FloatingNow();
ค่านี้ติดลบเมื่อวันนี้ขาดทุนสุทธิ และคือตัวเลขที่ใกล้เคียงมุมมอง equity ของ prop firm ที่สุดเท่าที่ EA คำนวณเองได้ เทียบให้เห็นชัดๆ ว่าแต่ละวิธีนับต่างกันแค่ไหน:
| วิธีนับ | นับอะไรบ้าง | ตรงกับที่ prop firm เห็นไหม |
|---|---|---|
| realized อย่างเดียว | เฉพาะไม้ที่ปิดแล้ว | ไม่ตรง — พลาด floating ทั้งก้อน อันตรายที่สุด |
| realized + floating (ไม่รวม swap/commission) | ไม้ปิดแล้ว + ไม้ลอย | เกือบตรง แต่รายงานขาดทุนน้อยกว่าจริงเสมอ |
| realized + floating + swap + commission | ทุกอย่างที่กระทบ equity | ใกล้เคียงที่สุด — ใช้แบบนี้ |
มีเกร็ดหนึ่งที่ควรรู้: บาง prop firm นิยาม daily loss จาก "balance หรือ equity ณ จุดเริ่มวัน" ที่ต่างกัน บางเจ้าใช้ balance ตอนเที่ยงคืน บางเจ้าใช้ equity ตอนเที่ยงคืน (ซึ่งรวม floating ของไม้ที่ค้างข้ามวันมา) ตัวเลขฐานต่างกันทำให้ระยะถึงลิมิตต่างกันได้พอสมควรถ้ามีไม้ค้างข้ามคืนเยอะ — อ่านกฎของเจ้าที่ใช้ให้ละเอียด แล้วปรับสูตรฐานให้ตรง โครงโค้ดข้างบนรองรับทั้งสองแบบ แค่เปลี่ยนว่าเก็บค่าฐานอะไรไว้ตอนเปิดวัน
ประตูที่ปิดจริง — สถานะ HALTED และลำดับตอนเบรกเกอร์ตัด
มีตัวเลขที่ถูกต้องแล้ว ขั้นต่อไปคือส่วนที่ทำให้มันกลายเป็น "เบรกเกอร์" จริงๆ ไม่ใช่แค่เครื่องวัด นั่นคือสถานะกลางหนึ่งตัวกับลำดับการทำงานที่ตายตัว
ลำดับตอนตัดต้องเป็นแบบนี้เสมอ:
- ปิดไม้ที่เปิดอยู่ทั้งหมด — หยุดเลือดก่อน ไม่มีอะไรสำคัญกว่านี้
- ยกเลิก pending order ทั้งหมด — ไม่งั้น limit/stop order ที่แขวนไว้จะกลายเป็นไม้ใหม่หลังเบรกเกอร์ตัด ซึ่งเท่ากับเบรกแล้วรถยังไหลต่อ
- ตั้งสถานะ HALTED พร้อมเวลาปลดล็อก — บันทึกว่าห้ามเทรดจนถึงเมื่อไหร่
- ปลดล็อกอัตโนมัติ เมื่อถึงเที่ยงคืนเซิร์ฟเวอร์ถัดไป — ไม่ต้องพึ่งคนมากดอะไร

แปลงเป็นโค้ดหลักใน OnTick():
input double InpDailyLossLimit = 500.0; // ลิมิตขาดทุนต่อวัน (สกุลเงินบัญชี)
bool g_halted = false;
datetime g_haltedUntil = 0;
void OnTick()
{
// 1) เช็กลิมิตทุก tick — ก่อนตรรกะอื่นทั้งหมด
double pnlToday = RealizedToday() + FloatingNow();
if(!g_halted && pnlToday <= -InpDailyLossLimit)
{
CloseAllPositions(); // หยุดเลือดก่อน
CancelAllPending(); // กัน pending กลายเป็นไม้ใหม่
g_halted = true;
g_haltedUntil = DayStart() + 86400; // เที่ยงคืนเซิร์ฟเวอร์ถัดไป
Print("CIRCUIT BREAKER: หยุดเทรดถึง ", TimeToString(g_haltedUntil));
return;
}
// 2) ประตู — ห้ามผ่านถ้ายัง HALTED
if(!CanTrade()) return;
// 3) ตรรกะเทรดปกติของ EA อยู่ใต้บรรทัดนี้เท่านั้น
}
// ประตูเดียวที่ทุกจุดในโค้ดต้องผ่านก่อนส่งออเดอร์
bool CanTrade()
{
if(g_halted && TimeCurrent() >= g_haltedUntil)
{
g_halted = false; // ขึ้นวันใหม่แล้ว ปลดล็อกอัตโนมัติ
Print("Circuit breaker: ปลดล็อก เริ่มวันเทรดใหม่");
}
return !g_halted;
}
จุดที่ผมขอเน้นเป็นตัวหนา: ทุกจุดในโค้ดที่มีการเรียก OrderSend() หรือฟังก์ชันที่ห่อมัน ต้องเรียก CanTrade() ก่อนเสมอ ไม่ใช่แค่จุดเดียวต้นทาง OnTick() — เพราะ EA จริงมักมีทางยิงออเดอร์มากกว่าหนึ่งทาง: จุดเปิดไม้ตามสัญญาณ จุดเปิดไม้แก้ (recovery/grid) จุดตั้ง pending ล่วงหน้า บางตัวมีตรรกะใน OnTimer() หรือ OnTradeTransaction() ด้วย ถ้ามีทางไหนหลุดไม่ผ่านประตูแม้แต่ทางเดียว สถานะ HALTED ก็ไม่มีความหมาย เหมือนล็อกประตูหน้าบ้านแน่นหนาแต่ประตูหลังแง้มไว้
ถ้ากลัวพลาด วิธีตรวจที่ตรงไปตรงมาที่สุดคือกด Ctrl+F ค้นทุกจุดที่มี OrderSend และ trade. (ถ้าใช้คลาส CTrade) ในโปรเจกต์ แล้วไล่ดูว่าเหนือบรรทัดนั้นมีการเช็ก CanTrade() ครบทุกจุดหรือยัง — งานสิบนาทีที่คุ้มค่ามาก
อีกเรื่องที่มองข้ามกันคือ EA รีสตาร์ทแล้วสถานะหาย — ตัวแปร g_halted อยู่ในหน่วยความจำ ถ้า VPS รีบูตหรือคุณปิด-เปิดเทอร์มินัลกลางวัน ตัวแปรจะกลับเป็น false และ EA จะเทรดต่อทั้งที่วันนี้ชนลิมิตไปแล้ว ทางแก้ที่ง่ายและพอเพียงคือให้ OnInit() คำนวณ P&L ของวันใหม่ทันทีจาก history (ฟังก์ชัน RealizedToday() ที่มีอยู่แล้วนั่นแหละ) ถ้าพบว่าเกินลิมิตอยู่แล้ว ก็ตั้ง HALTED กลับคืนตั้งแต่ยังไม่ทันเทรด — ข้อดีของการคำนวณจาก history แทนการจำสถานะไว้ในไฟล์คือมันสร้างความจริงขึ้นใหม่ได้เสมอไม่ว่าจะรีสตาร์ทกี่รอบ
กับดักโค้ดสองอันที่ทำให้ "ปิดไม้ไม่ครบแบบเงียบๆ"
มาถึงส่วนที่ผมเจอในงานแก้ EA บ่อยที่สุด สองกับดักนี้ร้ายตรงที่มันไม่ error ไม่ crash ไม่ฟ้องอะไรเลย — EA ดูเหมือนทำงานปกติ แต่ตอนเบรกเกอร์ตัดจริง ไม้ปิดไม่ครบ และคุณจะรู้ตัวก็ตอนที่ไม้ที่เหลือค้างลากบัญชีทะลุลิมิตไปแล้ว
กับดักที่ 1: วนลูปปิดไม้ต้องวนถอยหลังเท่านั้น
ดูโค้ดปิดไม้ทั้งหมดที่ถูกต้องก่อน:
#include <Trade/Trade.mqh>
CTrade trade;
void CloseAllPositions()
{
// ต้องวนถอยหลังจากตัวสุดท้ายลงมา 0 เสมอ
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(!trade.PositionClose(ticket))
Print("ปิดไม้ ", ticket, " ไม่สำเร็จ: ", trade.ResultRetcodeDescription());
}
}
void CancelAllPending()
{
for(int i = OrdersTotal() - 1; i >= 0; i--) // ถอยหลังด้วยเหตุผลเดียวกัน
{
ulong ticket = OrderGetTicket(i);
if(ticket == 0) continue;
if(!trade.OrderDelete(ticket))
Print("ยกเลิก pending ", ticket, " ไม่สำเร็จ: ", trade.ResultRetcodeDescription());
}
}
ทำไมต้องถอยหลัง? เพราะรายการ position ใน MT5 เป็นเหมือนแถวที่ขยับชิดกันตลอดเวลา สมมติมีไม้ 5 ไม้ที่ index 0-4 แล้วคุณวนเดินหน้า: ปิดไม้ index 0 สำเร็จ → ไม้ที่เหลือทั้งหมดเลื่อนลงมาหนึ่งช่อง ไม้ที่เคยอยู่ index 1 ตอนนี้กลายเป็น index 0 — แต่ลูปของคุณเดินไป index 1 แล้ว เท่ากับ ข้ามไม้นั้นไปเฉยๆ ผลคือวนจบรอบเดียวจะปิดได้แค่ไม้เว้นไม้ เหลือค้างประมาณครึ่งหนึ่ง
ที่อันตรายคือมันเงียบสนิท — ลูปทำงานจบตามปกติ ไม่มี error สักบรรทัด log ก็ดูสะอาด และในการทดสอบทั่วไปที่มีไม้เดียวสองไม้ บั๊กนี้แทบไม่แสดงอาการ มันจะโผล่ตอนที่มีไม้เยอะๆ ซึ่งก็คือตอนที่ grid กำลังบานหรือตลาดกำลังผันผวน — จังหวะที่คุณต้องการให้ปิดครบที่สุดพอดี
การวนถอยหลังแก้ปัญหานี้หมดจด: ปิดไม้ index 4 → ไม้ index 0-3 ไม่กระทบ → ลดมาปิด index 3 → ไล่ลงไปเรื่อยๆ ไม่มีตัวไหนเลื่อนหนี สังเกตว่าในโค้ดข้างบนผมวนถอยหลังทั้ง CloseAllPositions() และ CancelAllPending() — รายการ pending order ก็ขยับชิดแบบเดียวกับ position เป๊ะ พลาดได้ด้วยกลไกเดียวกัน
กับดักที่ 2: filling mode ต้องเลือกตามที่ symbol รองรับจริง
ตอนส่งคำสั่งปิดไม้ MT5 ต้องระบุ "โหมดการเติมออเดอร์" (filling mode) ไปด้วย ซึ่งมีสามแบบหลัก: FOK (Fill or Kill — ได้ครบทั้งจำนวนหรือไม่เอาเลย), IOC (Immediate or Cancel — ได้เท่าไหร่เอาเท่านั้น ที่เหลือยกเลิก), และ Return (ค้างรอในระบบ)
ปัญหาคือ โบรกแต่ละเจ้า แต่ละ symbol รองรับไม่เหมือนกัน และถ้าคุณส่งโหมดที่ symbol นั้นไม่รองรับ เทอร์มินัลจะตีกลับคำสั่งทันที (error 4756 / retcode 10030 = TRADE_RETCODE_INVALID_FILL) ตั้งแต่ยังไม่ทันออกจากเครื่อง — คำสั่งปิดไม้ไม่ถึงเซิร์ฟเวอร์ด้วยซ้ำ
ลองนึกภาพ: เบรกเกอร์ตรวจเจอว่าชนลิมิต สั่งปิดไม้ทั้งหมด แต่ทุกคำสั่งโดนตีกลับเพราะ filling mode ผิด — ไม้ทุกไม้ยังลอยอยู่ครบ ขาดทุนวิ่งต่อ ในขณะที่ log เต็มไปด้วย error ที่ไม่มีใครนั่งดูตอนตีสอง นี่คือสาเหตุที่ EA ที่ก๊อปโค้ดจากเน็ตมาแล้ว "ใช้ได้กับโบรกเก่า แต่พังกับโบรกใหม่" — เพราะ hard-code โหมดไว้ตายตัว
วิธีที่ถูกคืออ่านจาก symbol ว่ารองรับอะไร แล้วเลือกตามลำดับ:
// เลือก filling mode ตามที่ symbol รองรับจริง — FOK ก่อน แล้ว IOC แล้วค่อย Return
ENUM_ORDER_TYPE_FILLING PickFilling(string symbol)
{
long modes = SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE);
if((modes & SYMBOL_FILLING_FOK) != 0) return ORDER_FILLING_FOK;
if((modes & SYMBOL_FILLING_IOC) != 0) return ORDER_FILLING_IOC;
return ORDER_FILLING_RETURN; // ไม่ประกาศ FOK/IOC = ใช้ Return
}
// ใช้กับ CTrade ก่อนส่งคำสั่ง:
trade.SetTypeFilling(PickFilling(_Symbol));
ค่าที่อ่านได้จาก SYMBOL_FILLING_MODE เป็น bitmask คือ symbol หนึ่งอาจรองรับหลายโหมดพร้อมกัน โค้ดข้างบนไล่เช็กทีละ bit ตามลำดับความเข้มงวด ถ้าใช้คลาส CTrade ให้เซ็ตด้วย SetTypeFilling() ครั้งเดียวตอน OnInit() ก็ได้ แต่อย่าลืมว่าถ้า EA เทรดหลาย symbol ต้องเลือกใหม่ต่อ symbol
สองกับดักนี้เจอคู่กันบ่อย และมักเจอในโค้ดที่ backtest ผ่านสวยงามด้วย — เพราะใน Strategy Tester ทุกคำสั่ง execute สมบูรณ์แบบตลอด เงื่อนไขที่ทำให้มันพังมีเฉพาะบนเซิร์ฟเวอร์จริง ซึ่งเป็นธีมเดียวกับที่ผมเขียนไว้ในบทความ วิธี Backtest EA ใน MT5 ว่ามีบั๊กทั้งกลุ่มที่ backtest ไม่มีทางเจอ
ตั้งลิมิตเท่าไหร่ดี — โดยเฉพาะถ้าเทรด prop firm
โค้ดถูกหมดแล้ว เหลือคำถามเชิงนโยบาย: ตัวเลขลิมิตควรเป็นเท่าไหร่
สำหรับภาพรวมของวงการ prop firm ส่วนใหญ่ตั้ง daily loss ไว้ราว 4–5% ของพอร์ต และ max drawdown รวมราว 8–10% — ย้ำว่านี่คือ "ภาพรวม" ไม่ใช่ตัวเลขของเจ้าใดเจ้าหนึ่ง แต่ละเจ้ามีนิยาม วิธีวัด และตัวเลขต่างกันในรายละเอียด บางเจ้าวัดจาก balance บางเจ้าวัดจาก equity บางเจ้ามี trailing drawdown ที่ขยับตามกำไร ก่อนตั้งค่าอะไร ให้เปิดกฎของเจ้าที่คุณใช้อ่านเองหนึ่งรอบเสมอ อย่าเชื่อตัวเลขจากบทความไหนรวมถึงบทความนี้
ประเด็นที่สำคัญกว่าตัวเลขของ prop firm คือ: ลิมิตภายใน EA ต้องแคบกว่าลิมิตของ prop firm เสมอ — ห้ามตั้งเท่ากันเด็ดขาด ด้วยเหตุผลสามข้อ:
- Slippage ตอนปิด — ราคาที่ EA เห็นตอนตัดสินใจ กับราคาที่ปิดได้จริง ไม่ใช่ราคาเดียวกัน โดยเฉพาะตอนตลาดวิ่งแรงซึ่งเป็นจังหวะที่เบรกเกอร์มักทำงานพอดี
- ช่องว่างระหว่าง tick — ต่อให้เช็กทุก tick ราคาก็กระโดดข้าม tick ได้ ช่วงข่าวแรง ราคากระโดดทีละหลายจุดเป็นเรื่องปกติ
- ความต่างของนาฬิกาและวิธีวัด — ตามที่คุยไปในเรื่องเส้นแบ่งวันและนิยาม daily ของแต่ละเจ้า
แนวที่ผมใช้เวลาทำโมดูลนี้ให้ลูกค้าสาย prop firm คือเผื่อ buffer ไว้ราว 20–30% ของลิมิตจริง ตัวอย่างการคิด (สมมติพอร์ต 100,000 หน่วย และ prop firm ให้ daily loss 5%):
| รายการ | ค่า | หมายเหตุ |
|---|---|---|
| ลิมิตของ prop firm | 5,000 (5%) | เส้นตายจริง — แตะแล้วบัญชีจบ |
| buffer เผื่อ slippage/ช่องว่าง tick | 1,000–1,500 | ราว 20–30% ของลิมิต |
| ลิมิตที่ตั้งใน EA | 3,500–4,000 (3.5–4%) | เบรกเกอร์ตัดที่เส้นนี้ |
บางคนเห็นตารางนี้แล้วเสียดาย — "เท่ากับผมใช้โควตาไม่เต็มสิ" ใช่ครับ และนั่นแหละคือประเด็น: โควตาที่ใช้เต็มคือโควตาที่พร้อมจะเกินได้ตลอดเวลา ระหว่าง "เทรดต่อได้อีกนิดวันนี้" กับ "บัญชีอยู่รอดถึงพรุ่งนี้" สำหรับคนสอบ challenge คำตอบไม่ควรต้องคิดนาน
อีกมุมที่ควรคิดคือความสัมพันธ์ระหว่างลิมิตกับขนาดไม้: ถ้า EA ของคุณเสี่ยงต่อไม้ 1% ลิมิต 4% แปลว่ารับขาดทุนติดกันได้ 4 ไม้ก่อนหยุด — ตัวเลขนี้สมเหตุสมผลไหมกับสถิติขาดทุนติดกันของระบบคุณ? ถ้าระบบขาดทุนติดกัน 6-7 ไม้เป็นเรื่องปกติ (ดูได้จากผล backtest) ลิมิต 4% จะทำให้เบรกเกอร์ตัดบ่อยเกินไปจนระบบไม่ได้เดินตามแผน ทางแก้ไม่ใช่ขยายลิมิต แต่คือ ลดขนาดไม้ ให้ชุดขาดทุนปกติของระบบอยู่ในลิมิตได้ — เรื่องนี้ต้องดูจากข้อมูล backtest ที่เชื่อถือได้ ซึ่งผมเขียนวิธีทำไว้ละเอียดในบทความ backtest
ต่อยอดจาก daily loss limit ธรรมดา
โครงที่มีถึงตรงนี้คือเวอร์ชันพื้นฐานที่ควรมีในทุก EA แต่พอมันทำงานนิ่งแล้ว มีทิศทางต่อยอดอีกหลายทางที่ใช้โครงเดียวกันเกือบทั้งหมด ผมเล่าสั้นๆ พอให้เห็นภาพว่าอะไรทำได้บ้าง:
ลิมิตรายสัปดาห์ — เปลี่ยนขอบล่างของ HistorySelect() จากเที่ยงคืนวันนี้เป็นเที่ยงคืนวันจันทร์ของสัปดาห์ ที่เหลือใช้โครงเดิมทั้งหมด เหมาะกับคนที่กลัวอาการ "ขาดทุนวันละนิดจนครบโควตาทั้งสัปดาห์ในสามวัน"
หยุดเมื่อขาดทุนติดกัน N ไม้ — วนอ่าน deal ล่าสุดย้อนหลัง นับว่าขาดทุนติดกันมากี่ไม้ ถ้าถึงเกณฑ์ (เช่น 4 ไม้) ให้พักเทรดชั่วคราว อันนี้จับอาการ "ระบบไม่เข้ากับสภาพตลาดวันนี้" ได้เร็วกว่าลิมิตที่เป็นจำนวนเงิน เพราะบางวันระบบแพ้ติดๆ กันด้วยไม้เล็กๆ ที่ยังไม่ชนลิมิตเงินแต่ส่งสัญญาณชัดแล้ว
แจ้งเตือนเข้ามือถือตอนเบรกเกอร์ตัด — เพิ่มบรรทัดเดียวในลำดับการตัด: SendNotification("Circuit breaker ตัดแล้ว: ขาดทุนวันนี้ถึงลิมิต") ข้อความจะเด้งเข้าแอป MT5 บนมือถือทันที (ต้องผูก MetaQuotes ID ในเทอร์มินัลก่อน ตั้งได้ที่ Tools → Options → Notifications) เรื่องนี้สำคัญกว่าที่คิด — เบรกเกอร์ที่ตัดเงียบๆ ตอนตีสองแล้วคุณมาเห็นตอนเก้าโมงเช้า กับเบรกเกอร์ที่ปลุกคุณทันที ให้ความรู้สึกควบคุมต่างกันมาก และบางครั้งการรู้เร็วช่วยให้ตัดสินใจเรื่องอื่นทัน เช่น EA ตัวอื่นที่ยังรันอยู่
Drawdown จาก peak equity แทนรายวัน — ลิมิตรายวันรีเซ็ตทุกเช้า แต่ max drawdown ของ prop firm ส่วนใหญ่ไม่รีเซ็ต มันวัดจากจุดสูงสุดที่บัญชีเคยไปถึง โครงเดียวกันปรับได้: เก็บค่า equity สูงสุดไว้ (อัปเดตทุก tick) แล้วเทียบ equity ปัจจุบันกับค่านั้น ถ้าห่างเกินเกณฑ์ก็ตัดด้วยลำดับเดียวกัน — ต่างกันแค่เบรกเกอร์ตัวนี้ไม่ปลดล็อกเองตอนเที่ยงคืน ต้องให้คนมาตัดสินใจ เพราะการชน max drawdown คือสัญญาณว่าต้องทบทวนระบบ ไม่ใช่แค่พักหนึ่งคืน
EA หลายตัวแชร์สถานะ HALTED ร่วมกัน — ถ้าคุณรัน EA หลายตัวบนเทอร์มินัลเดียวกัน (คนละชาร์ต คนละคู่เงิน) แต่ทุกตัวอยู่บนบัญชี prop firm เดียวกัน ลิมิตรายวันเป็นของบัญชีรวม ไม่ใช่ของ EA แต่ละตัว — EA ตัวหนึ่งตัดตัวเองแล้ว แต่อีกสามตัวยังเทรดต่อ ก็จบเหมือนเดิม ทางแก้ใน MQL5 คือ Global Variable ของเทอร์มินัล ซึ่งเป็นตัวแปรกลางที่ทุก EA ในเทอร์มินัลเดียวกันอ่าน/เขียนร่วมกันได้:
#define HALT_FLAG "DAILY_HALT_UNTIL" // ชื่อตัวแปรกลาง ใช้ตรงกันทุก EA
// ตอนเบรกเกอร์ของตัวไหนตัด — ประกาศให้ทั้งเทอร์มินัลรู้
GlobalVariableSet(HALT_FLAG, (double)(DayStart() + 86400));
// ทุก EA เพิ่มเงื่อนไขนี้เข้าไปในประตู CanTrade() ของตัวเอง
bool HaltedGlobally()
{
if(!GlobalVariableCheck(HALT_FLAG)) return false;
return TimeCurrent() < (datetime)GlobalVariableGet(HALT_FLAG);
}
พอตัวใดตัวหนึ่งชนลิมิตของบัญชี ทุกตัวจะหยุดพร้อมกันในทิกถัดไป — โดยมีเงื่อนไขสำคัญคือ ทุกตัวต้องฝังโมดูลนี้และยอมเช็กตัวแปรกลางเหมือนกัน ซึ่งพาเราไปสู่หัวข้อถัดไปพอดี: ข้อจำกัดของทั้งหมดนี้
ข้อจำกัดที่ผมต้องบอกตรงๆ
ผมเขียนโมดูลแบบนี้ให้ลูกค้ามาเยอะ และทุกครั้งจะบอกข้อจำกัดชุดเดียวกันก่อนส่งงานเสมอ เพราะเบรกเกอร์ที่คุณ คิดว่า กันได้ทุกอย่าง อันตรายกว่าเบรกเกอร์ที่คุณรู้ขอบเขตของมันชัดๆ
หนึ่ง — คุมได้เฉพาะ EA ที่ฝังโมดูลนี้เท่านั้น EA ตัวอื่นบนชาร์ตอื่นที่ไม่มีโมดูล (หรือมีแต่ไม่เช็กตัวแปรกลางร่วมกัน) ยิงออเดอร์ได้ตามปกติ เบรกเกอร์ไม่ใช่ผนังกั้นทั้งบัญชี มันคือวินัยของ EA แต่ละตัว
สอง — หยุดมือคนไม่ได้ ไม่มีกลไกใน MQL5 ที่ห้ามเจ้าของบัญชีกดเปิดไม้เองจากหน้าจอหรือมือถือ Global Variable ช่วยประสานได้เฉพาะระหว่าง EA ที่ยอมเช็กด้วยกันเท่านั้น ถ้าปัญหาจริงของคุณคือมือตัวเองแอบเทรดหลังชนลิมิต (ซึ่งเป็นปัญหาคลาสสิกของคนสอบ challenge) เครื่องมือทางโค้ดช่วยไม่ได้ — อันนั้นต้องแก้ที่พฤติกรรม เช่น เอารหัสผ่านบัญชีเทรดออกจากมือถือช่วงสอบ
สาม — การตัดในตลาดผันผวนไม่ได้สวยงามเสมอ จังหวะที่เบรกเกอร์ทำงานมักเป็นจังหวะที่ตลาดกำลังแรง คำสั่งปิดอาจโดน slippage หรือเจอ partial fill คือปิดได้บางส่วน เหลือเศษไม้ค้างไปถึง tick ถัดไปให้ตามปิดซ้ำ โค้ดที่ดีต้องเผื่อการวนปิดซ้ำจนกว่าจะเกลี้ยง ไม่ใช่สั่งรอบเดียวแล้วถือว่าจบ
สี่ — ตัวเลขตอนตัดสินใจไม่ใช่ตัวเลขตอนปิดได้จริง P&L ที่เบรกเกอร์ใช้ตัดสินใจคือราคา ณ tick นั้น แต่กว่าคำสั่งจะเดินทางถึงเซิร์ฟเวอร์และ execute เสร็จ ราคาขยับไปแล้ว ในตลาดปกติสองค่านี้ต่างกันน้อยมาก แต่ในตลาดเร็ว — ซึ่งเป็นตอนที่เบรกเกอร์ทำงานพอดี — ความต่างมีนัยสำคัญ นี่คือเหตุผลหลักของ buffer 20–30% ที่คุยไปในหัวข้อก่อน
ห้า — race condition กับ pending order มีหน้าต่างเวลาแคบๆ ที่ pending order ซึ่งราคากำลังวิ่งเข้าใส่อยู่แล้วฝั่งเซิร์ฟเวอร์ อาจ trigger กลายเป็นไม้จริงก่อนคำสั่ง CancelAllPending() ของเราไปถึง โอกาสเกิดต่ำแต่ไม่ใช่ศูนย์ โดยเฉพาะช่วงข่าว ทางบรรเทาคือให้ลูปเช็กหลังตัด (tick ถัดๆ ไป) คอยดูว่ามีไม้ใหม่โผล่มาหลังสถานะ HALTED หรือไม่ ถ้ามีก็ปิดทิ้งทันที
ทั้งห้าข้อไม่ได้แปลว่าเบรกเกอร์ไม่มีประโยชน์ — มันแปลว่าเบรกเกอร์คือ ชั้นป้องกันชั้นสุดท้าย ไม่ใช่ชั้นเดียว ขนาดไม้ที่เหมาะสม การกระจายความเสี่ยง และระบบที่ผ่านการทดสอบมาดี ยังคงเป็นด่านหน้าเสมอ เบรกเกอร์มีไว้รับสถานการณ์ที่ด่านหน้าเอาไม่อยู่ ซึ่งเกิดขึ้นได้จริงกับทุกระบบไม่ว่าจะทดสอบมาดีแค่ไหน
เช็กลิสต์ก่อนปล่อยเบรกเกอร์ใช้งานจริง
รวมทุกอย่างในบทความเป็นรายการติ๊ก — ไล่ให้ครบก่อนเอาไปแขวนกับบัญชีที่มีเดิมพันจริง โดยเฉพาะบัญชี challenge:
เรื่องเวลา
- รู้ offset ระหว่างเวลาเซิร์ฟเวอร์โบรกกับเวลาไทย (พิมพ์เทียบ
TimeCurrent()กับTimeLocal()มาดูแล้ว) - เส้นแบ่งวันในโค้ดอิงเที่ยงคืนเซิร์ฟเวอร์ ไม่ใช่เวลาไทยหรือเวลาเครื่อง
- อ่านนิยาม "daily" ของ prop firm ที่ใช้แล้ว และเทียบกับเวลาเซิร์ฟเวอร์บัญชีว่าตรงกันหรือต้องเลื่อน offset
- รู้ว่าโบรกตัวเองขยับเวลาตาม DST หรือไม่
เรื่องตัวเลข
- P&L ของวันรวมครบ: realized + floating + swap + commission
- อ่าน history โดยกรองเฉพาะ
DEAL_ENTRY_OUTและDEAL_ENTRY_INOUT - รู้ว่า prop firm วัดฐานจาก balance หรือ equity ณ จุดเริ่มวัน และตั้งสูตรฐานให้ตรง
- ลิมิตใน EA แคบกว่าลิมิตของ prop firm อย่างน้อย 20%
- ลิมิตสอดคล้องกับขนาดไม้และสถิติขาดทุนติดกันของระบบ (ไม่ตัดถี่จนระบบเดินไม่ได้)
เรื่องโค้ด
- เช็กลิมิตทุก tick ใน
OnTick()ก่อนตรรกะอื่นทั้งหมด - ลำดับตอนตัดครบ: ปิดไม้ → ยกเลิก pending → ตั้ง HALTED → ปลดล็อกเองวันถัดไป
- ค้นทุกจุดที่มี
OrderSend/trade.แล้วยืนยันว่าทุกจุดผ่านCanTrade()ก่อน - ลูปปิดไม้และยกเลิก pending วนถอยหลังทั้งคู่
- filling mode อ่านจาก
SYMBOL_FILLING_MODEไม่ได้ hard-code -
OnInit()คำนวณ P&L วันนี้ใหม่จาก history — รีสตาร์ทแล้วสถานะ HALTED ไม่หาย - ถ้ารันหลาย EA บนบัญชีเดียว: ทุกตัวเช็ก Global Variable กลางตัวเดียวกัน
เรื่องทดสอบ
- รันใน Strategy Tester แล้วเห็นเบรกเกอร์ตัดและปลดล็อกตรงเวลาที่ควร ไม่มีออเดอร์หลุดระหว่าง HALTED
- ทดลองบน Demo โดยตั้งลิมิตต่ำๆ ให้มันตัดจริงต่อหน้าอย่างน้อยหนึ่งครั้ง — อย่าให้ครั้งแรกที่เบรกเกอร์ทำงานคือวันที่เงินจริงแขวนอยู่
- เปิด
SendNotification()แล้วทดสอบว่าแจ้งเตือนเข้ามือถือจริง
ข้อที่คนข้ามบ่อยที่สุดคือข้อรองสุดท้าย — หลายคนเขียนเบรกเกอร์เสร็จแล้วไม่เคยเห็นมันทำงานเลยสักครั้งจนถึงวันที่มันต้องทำงานจริง ระบบความปลอดภัยที่ไม่เคยถูกซ้อมใช้ ไม่ต่างจากถังดับเพลิงที่ไม่เคยเช็กแรงดัน
คำถามที่พบบ่อยเรื่อง Daily Loss Limit ใน EA
Q1: Daily Loss Limit ใน EA คืออะไร ต่างจาก Stop Loss ยังไง?
Stop Loss คุมความเสียหายของ "ไม้เดียว" ส่วน Daily Loss Limit คุมความเสียหายรวมของ "ทั้งวัน" — ต่อให้ทุกไม้มี SL เรียบร้อย ระบบก็ยังขาดทุนติดกันหลายไม้จนยอดรวมของวันบานได้ Daily Loss Limit คือเบรกเกอร์อีกชั้นที่บอกว่าวันนี้พอแล้ว: ปิดไม้ทั้งหมด ยกเลิก pending และห้ามเปิดไม้ใหม่จนกว่าจะขึ้นวันเทรดใหม่ สองอย่างนี้ต้องมีคู่กัน ไม่ใช่เลือกอย่างใดอย่างหนึ่ง
Q2: ทำไมต้องเช็กลิมิตทุก tick เช็กตอนเปิดแท่งใหม่ไม่พอหรือ?
ไม่พอครับ เพราะระหว่างแท่งราคาวิ่งได้ไกลมาก EA ที่เช็กเฉพาะตอนแท่ง H1 เปิด อาจรู้ตัวช้าสุดเกือบหนึ่งชั่วโมงเต็ม ซึ่งในช่วงข่าวแรงเพียงพอให้ขาดทุนทะลุลิมิตไปไกลจนกู่ไม่กลับ ลิมิตขาดทุนคือระบบความปลอดภัย ไม่ใช่สัญญาณเทรด จึงต้องเช็กทุก tick — ภาระการคำนวณต่ำมากเพราะเป็นแค่การวนบวกตัวเลขไม่กี่ค่า ไม่มีผลต่อประสิทธิภาพของ EA อย่างมีนัยสำคัญ
Q3: ลิมิตรายวันรีเซ็ตตอนไหน เที่ยงคืนบ้านเราใช่ไหม?
ไม่ใช่ครับ และนี่คือจุดที่คนไทยพลาดมากที่สุด — เส้นแบ่งวันของ EA คือเที่ยงคืน "เวลาเซิร์ฟเวอร์โบรก" ซึ่งส่วนใหญ่ตั้ง GMT+2 หรือ GMT+3 ขณะที่ไทยคือ GMT+7 แปลว่าวันใหม่ของ EA เริ่มราวตี 4 ถึงตี 5 ตามเวลาไทย ถ้าขาดทุนหนักตอน 4 ทุ่ม ลิมิตจะยังไม่รีเซ็ตตอนเที่ยงคืนบ้านเรา ต้องรอถึงเช้ามืด และต้องระวังเพิ่มว่าโบรกบางเจ้าเปลี่ยน offset ตาม DST ปีละสองครั้ง ส่วน prop firm บางเจ้าก็นับวันด้วย timezone ของตัวเองซึ่งอาจไม่ตรงกับเซิร์ฟเวอร์โบรกอีกชั้น — ต้องเช็กให้ตรงกันทั้งสามนาฬิกา
Q4: ต้องนับกำไร/ขาดทุนอะไรบ้างในลิมิตรายวัน?
ต้องนับให้ครบสี่ส่วน: กำไร/ขาดทุนของไม้ที่ปิดแล้ววันนี้ (realized) กำไร/ขาดทุนลอยตัวของไม้ที่ยังเปิดอยู่ (floating) swap และ commission — เพราะ prop firm วัดจาก equity ซึ่งสะท้อนทั้งสี่ส่วนแล้ว EA ที่นับแต่ realized จะรายงานว่ายังไม่เกินลิมิตทั้งที่ equity จริงเกินไปแล้ว ฝั่งโค้ด MQL5 ตอนอ่าน history ต้องกรองเฉพาะ deal ประเภท DEAL_ENTRY_OUT และ DEAL_ENTRY_INOUT เพราะกำไร/ขาดทุนถูกบันทึกที่ deal ขาออกเท่านั้น
Q5: EA มี daily loss limit แล้ว รับประกันว่าจะไม่โดน prop firm ตัดใช่ไหม?
ไม่ใช่ครับ เบรกเกอร์ลดความเสี่ยงได้มากแต่รับประกันไม่ได้ เพราะมีช่องว่างที่โค้ดคุมไม่ถึง: slippage ตอนปิดไม้ในตลาดเร็ว partial fill ที่ทำให้เหลือเศษไม้ค้าง pending order ที่ trigger ก่อนคำสั่งยกเลิกไปถึง EA ตัวอื่นที่ไม่ได้ฝังโมดูล และมือของเราเองที่กดเทรดเพิ่ม วิธีรับมือคือตั้งลิมิตภายใน EA ให้แคบกว่าลิมิตของ prop firm ราว 20–30% เพื่อให้ช่องว่างพวกนี้ยังอยู่ในพื้นที่ปลอดภัย
Q6: prop firm ให้ daily loss 5% ควรตั้งลิมิตใน EA เท่าไหร่?
แนวที่ผมใช้คือ 3.5–4% คือเผื่อ buffer ราว 20–30% จากเส้นตายจริง เพื่อรองรับ slippage ราคากระโดดข้าม tick และความคลาดเคลื่อนของนาฬิกา/วิธีวัดระหว่าง EA กับ prop firm และก่อนตั้งต้องอ่านกฎของเจ้าที่ใช้เองเสมอว่าเขาวัดจาก balance หรือ equity และรีเซ็ตวันตอนไหน เพราะแต่ละเจ้านิยามไม่เหมือนกัน ตัวเลข 4–5% เป็นเพียงภาพรวมของวงการ ไม่ใช่กฎของเจ้าใดเจ้าหนึ่ง
Q7: รัน EA หลายตัวบนบัญชีเดียว จะให้หยุดพร้อมกันทั้งหมดได้ไหม?
ได้ ถ้าทุกตัวอยู่บนเทอร์มินัล MT5 เดียวกันและทุกตัวฝังโมดูลที่เช็กตัวแปรกลางร่วมกัน — ใช้ Global Variable ของเทอร์มินัล (GlobalVariableSet/GlobalVariableGet) เป็นธงกลาง ตัวไหนชนลิมิตก่อนก็เซ็ตธงพร้อมเวลาปลดล็อก ตัวอื่นเห็นธงแล้วหยุดตามในทิกถัดไป ข้อจำกัดคือมันคุมได้เฉพาะ EA ที่ยอมเช็กธงด้วยกันเท่านั้น EA ที่ไม่มีโมดูลหรือรันอยู่คนละเทอร์มินัลจะไม่รับรู้อะไรเลย
Q8: ทดสอบ circuit breaker ใน Strategy Tester ได้ไหม?
ได้และควรทำ — รัน backtest ด้วยโหมด Every tick based on real ticks แล้วดู log ว่าเบรกเกอร์ตัดตรงจังหวะที่ควรตัด ปลดล็อกตรงเที่ยงคืนเซิร์ฟเวอร์จริง และไม่มีออเดอร์ใหม่โผล่ระหว่าง HALTED แต่อย่าลืมว่า Strategy Tester จำลองการ execute แบบสมบูรณ์แบบ — slippage จริง partial fill และ filling mode ที่โบรกตีกลับ เป็นเงื่อนไขที่มีเฉพาะบนเซิร์ฟเวอร์จริง จึงต้องรันบนบัญชี Demo ต่ออีกช่วงหนึ่งเสมอ วิธีตั้งค่า tester ให้ผลเชื่อถือได้ผมเขียนไว้ละเอียดในบทความ วิธี Backtest EA ใน MT5
สรุป
- EA ส่วนใหญ่คุม daily loss ไม่อยู่เพราะพลาดสามชั้น — เช็กแค่ตอนแท่งใหม่ นับแต่ realized และไม่มีประตูกันยิงออเดอร์หลังตรวจเจอ ต้องอุดครบทั้งสามถึงเรียกว่ามีเบรกเกอร์จริง
- เส้นแบ่งวันคือเที่ยงคืนเวลาเซิร์ฟเวอร์ ไม่ใช่เที่ยงคืนไทย — วันใหม่ของ EA เริ่มราวตี 4-5 บ้านเรา โบรกเปลี่ยน offset ตาม DST ได้ และ prop firm อาจนับวันด้วยนาฬิกาของตัวเองอีกชั้น
- P&L ของวันต้องรวม realized + floating + swap + commission — เพราะ prop firm วัดจาก equity ขาดตัวไหนไปคือประเมินความเสี่ยงต่ำกว่าจริง
- ลำดับตอนตัดตายตัว: ปิดไม้ → ยกเลิก pending → ตั้ง HALTED → ปลดล็อกเองวันถัดไป และทุกจุดที่ส่งออเดอร์ต้องผ่านประตูเช็กสถานะก่อน ไม่งั้น HALTED เป็นแค่ log
- ลูปปิดไม้ต้องวนถอยหลัง และ filling mode ต้องอ่านจาก symbol — สองกับดักเงียบที่ทำให้ปิดไม้ไม่ครบในจังหวะคอขาดบาดตาย
- ลิมิตใน EA ต้องแคบกว่าลิมิต prop firm ราว 20–30% — เผื่อ slippage ราคากระโดด และความคลาดเคลื่อนของนาฬิกา
- เบรกเกอร์คือชั้นป้องกันชั้นสุดท้าย ไม่ใช่ชั้นเดียว — มันหยุด EA ตัวอื่นไม่ได้ หยุดมือคนไม่ได้ และตัดกลางตลาดผันผวนอาจไม่เกลี้ยงในครั้งเดียว รู้ขอบเขตของมันแล้วใช้ร่วมกับขนาดไม้ที่เหมาะสมเสมอ
ถ้าจะให้เลือกข้อเดียวไปตรวจ EA ของคุณคืนนี้ — ข้อ 2 ครับ เปิดดูว่าโค้ดรีเซ็ตวันด้วยนาฬิกาไหน เพราะมันคือจุดที่ผิดกันเยอะที่สุดและตรวจง่ายที่สุด
อยากได้เบรกเกอร์แบบนี้ใน EA ที่ใช้อยู่? ส่งมาให้ดูได้
ถ้าคุณมี EA ที่รักอยู่แล้วแต่ไม่แน่ใจว่าระบบจำกัดขาดทุนของมันอุดครบทั้งสามชั้นหรือเปล่า — หรืออยากฝังโมดูล circuit breaker แบบในบทความนี้เข้าไปโดยไม่กระทบตรรกะเดิม — ส่งไฟล์ EA มาให้ผมดูได้เลย ประเมินราคาฟรี ตอบกลับใน 1 วัน
รับทั้งงานเขียน EA ใหม่, แก้ไข EA เดิม, และเพิ่มโมดูลบริหารความเสี่ยงให้ EA ที่มีอยู่แล้ว — เริ่มต้น 500 บาท รับใบเสนอราคาภายใน 24 ชม.
📱 Line: @lafanoom 📞 โทร: 085-937-7580 💬 Facebook: facebook.com/thaimql 📧 Email: Lafanoom@gmail.com
🕒 เวลาทำการ: ทุกวัน (10:00 - 20:00 น.)
แหล่งอ้างอิง — บทความนี้อ้างอิงงานเขียนบน MQL5.com ขอบคุณผู้เขียนครับ:
- Ushana Kevin Iorkumbul — Implementing a Daily Loss Limit and Drawdown Circuit Breaker in MQL5 (28 ส.ค. 2569) — สถาปัตยกรรม circuit breaker, การคำนวณ P&L รวม, ลำดับการตัด และรายการข้อจำกัด
อ่านต่อ: วิธี Backtest EA ใน MT5 ให้แม่น · รับเขียน EA ทุกสิ่งที่ต้องรู้ · Grid Trading คืออะไร · ราคาเขียน EA เท่าไหร่
บทความนี้เขียนจากประสบการณ์รับเขียนและแก้ EA มา 15 ปี โค้ดตัวอย่างทั้งหมดเป็นโครงสำหรับศึกษา ต้องปรับและทดสอบกับบัญชีและโบรกของคุณเองก่อนใช้จริง กฎของ prop firm แต่ละเจ้าต่างกันในรายละเอียด — อ่านกฎของเจ้าที่คุณใช้เองเสมอ และทดสอบทุกอย่างบน Demo ก่อนใช้เงินจริงครับ