EA เปิดออร์เดอร์ซ้ำหลายไม้ในแท่งเดียว — สาเหตุที่แท้จริง วิธีตรวจว่า EA ของคุณเป็นหรือไม่ และตัวกรอง 4 แบบพร้อมโค้ด MQL4 / MQL5 ที่ก็อปไปใช้ได้
อาการที่ EA เปิดออร์เดอร์ทิศเดียวกันหลายไม้ติดกันภายในแท่งเทียนเดียว ไม่ใช่บั๊กของโบรกเกอร์และไม่ใช่ความผิดพลาดของแพลตฟอร์ม — มันคือผลตรงไปตรงมาของการที่ฟังก์ชัน OnTick() ถูกเรียกทุกครั้งที่ราคาขยับ ไม่ใช่ทุกครั้งที่แท่งปิด ถ้าเงื่อนไขเข้าออร์เดอร์ยังเป็นจริงค้างไว้ EA ก็จะยิงคำสั่งซ้ำทุกทิกที่เข้ามา และ 🔑 ความเสียหายจริงไม่ใช่ค่าสเปรดที่จ่ายเพิ่ม แต่คือขนาดสถานะรวมที่กลายเป็น 8 เท่าหรือ 20 เท่าของที่ออกแบบไว้ หน้านี้อธิบายกลไก พร้อม ตารางคำนวณตามได้ 6 ชุด วิธีตรวจด้วยข้อมูลจริงจากบัญชีตัวเอง และโค้ดตัวกรอง 4 แบบทั้ง MQL4 และ MQL5 พร้อมกับดักที่แต่ละแบบพามาด้วย
อาการนี้คืออะไร (คำตอบสั้น ๆ ก่อน)
เปิดประวัติการเทรดขึ้นมาแล้วเห็นออร์เดอร์หลายไม้ที่มีเวลาเปิดห่างกันไม่กี่วินาที ทิศทางเดียวกัน สัญลักษณ์เดียวกัน และราคาใกล้เคียงกันมาก — นั่นคืออาการ ส่วนสาเหตุมีอยู่สองแบบที่เจอบ่อยที่สุด:
- เงื่อนไขเข้ายังเป็นจริงค้างอยู่ — เช่นเงื่อนไข "เส้นค่าเฉลี่ยตัดกัน" ที่เขียนโดยเทียบค่าปัจจุบันกับค่าก่อนหน้า จะเป็นจริงต่อเนื่องได้ทั้งแท่งถ้าค่าทั้งสองยังไม่กลับด้าน
- ไม้เดิมเพิ่งถูกปิดไป แล้วโค้ดถูกเรียกใหม่ทันที — พบมากในระบบที่ตั้งเป้าสั้น ไม้ปิดเร็ว แล้วเงื่อนไขเข้าก็ยังเป็นจริงอยู่พอดี ⇒ วนเข้าใหม่ทันทีบนแท่งเดิม
ทำไมมันเกิด — OnTick() ไม่ได้ทำงานทุกแท่ง แต่ทำงานทุกครั้งที่ราคาขยับ
นี่คือแก่นของเรื่องทั้งหมด และเป็นจุดที่คนเขียน EA ครั้งแรกเข้าใจสลับกันเกือบทุกคน:
| ช่วงเวลา | ทิกต่อนาที (ตัวเลขสมมติ) | ทิกใน 1 แท่ง M15 | ถ้าเงื่อนไขเป็นจริงค้างไว้ 2 นาที จะมีโอกาสยิงกี่ครั้ง |
|---|---|---|---|
| ตลาดเอเชียช่วงเงียบ | ~5 | ~75 | ~10 ครั้ง |
| ช่วงตลาดลอนดอนเปิดตามปกติ | ~30 | ~450 | ~60 ครั้ง |
| ช่วงตัวเลขเศรษฐกิจออก | ~200 | ~3,000 | ~400 ครั้ง |
OnTick() ถูกเรียกในหนึ่งนาที · สิ่งที่ตารางนี้บอกได้จริงมีข้อเดียวคือ จำนวนโอกาสยิงต่อแท่ง มากกว่า 1 อยู่หลายสิบถึงหลายร้อยเท่า🔑 ราคาของทริกเกอร์ซ้ำ — และเหตุผลที่ค่าสเปรดไม่ใช่ปัญหาหลัก
เกือบทุกบทความที่พูดเรื่องนี้จบที่ "เสียค่าสเปรดเพิ่ม" ซึ่งจริง แต่เป็นส่วนที่เล็กที่สุด ลองดูตัวเลขเทียบกันตรง ๆ (สมมติ EURUSD สเปรด 1.0 pip · ตั้งใจเข้า 0.10 ล็อต · SL 20 pip · ความเสี่ยงต่อไม้ที่ออกแบบไว้ $20):
| จำนวนไม้ที่ยิงไปจริง | ค่าสเปรดรวมที่จ่ายเพิ่ม | ล็อตรวมที่ถืออยู่ | ความเสี่ยงจริงถ้าโดน SL ทุกไม้ | คิดเป็นกี่เท่าของที่ตั้งใจ |
|---|---|---|---|---|
| 1 ไม้ (ตามที่ออกแบบ) | $1.00 | 0.10 | $20 | 1× |
| 3 ไม้ | $3.00 | 0.30 | $60 | 3× |
| 8 ไม้ | $8.00 | 0.80 | $160 | 8× |
| 20 ไม้ | $20.00 | 2.00 | $400 | 20× |
เรื่องที่ตามมาทันทีคือมาร์จิน ซึ่งเป็นข้อจำกัดที่บังคับใช้โดยเซิร์ฟเวอร์ ไม่ใช่โดยโค้ดของเรา:
| ล็อตรวม | มาร์จินที่ต้องใช้ (เลเวอเรจ 1:100 · EURUSD ที่ 1.0850) | บัญชี $2,000 รับไหวไหม |
|---|---|---|
| 0.10 | $108.50 | ได้สบาย |
| 0.80 | $868.00 | ได้ แต่เหลือมาร์จินว่างไม่มาก |
| 2.00 | $2,170.00 | ไม่ไหว — เกินยอดคงเหลือทั้งบัญชี |
วิธีตรวจว่า EA ของคุณมีอาการนี้หรือไม่ — ใช้ข้อมูลจริงจากบัญชีตัวเอง
ส่งออกประวัติการเทรดออกมาเป็นไฟล์
ในเทอร์มินัล เปิดแท็บประวัติบัญชี → คลิกขวา → เลือกบันทึกเป็นรายงานแบบละเอียด จะได้ไฟล์ที่มีคอลัมน์เวลาเปิดของทุกไม้ ซึ่งเป็นข้อมูลเดียวที่ต้องใช้
จับเวลาเปิดเข้ากลุ่มตามแท่ง แล้วนับ
เปิดใน Excel หรือ Google Sheets แล้วสร้างคอลัมน์ใหม่ด้วยสูตร =FLOOR(เซลล์เวลาเปิด, TIME(0,15,0)) สำหรับ M15 จากนั้นนับด้วย =COUNTIF(คอลัมน์ใหม่, เซลล์นั้น) — แถวไหนที่นับได้มากกว่า 1 คือแท่งที่มีการยิงซ้ำ
ดูบันทึกของ EA ในแท็บ Experts
ถ้า EA เขียนบรรทัดลงบันทึกทุกครั้งที่ส่งคำสั่ง ให้ดูว่ามีหลายบรรทัดที่เวลาห่างกันไม่กี่วินาทีหรือไม่ วิธีนี้เห็นแม้กระทั่งคำสั่งที่ถูกปฏิเสธ ซึ่งไม่โผล่ในประวัติการเทรด
ทดสอบย้อนหลังในโหมดทุกทิกเท่านั้น
🔑 ข้อนี้สำคัญที่สุดและถูกข้ามบ่อยที่สุด — การทดสอบย้อนหลังในโหมดที่จำลองเฉพาะราคาเปิดของแต่ละแท่ง จะไม่มีวันแสดงอาการนี้เลย เพราะในโหมดนั้น หนึ่งแท่งมีหนึ่งทิกอยู่แล้วโดยปริยาย ⇒ EA ที่ผ่านการทดสอบมาสวยงามอาจกำลังยิงซ้ำในบัญชีจริงอยู่ทุกวัน
ตัวกรองที่ 1 — หนึ่งไม้ต่อหนึ่งแท่ง (แก้ได้ตรงจุดที่สุด)
หลักการคือจำเวลาเปิดของแท่งปัจจุบันไว้ แล้วปล่อยให้โค้ดตัดสินใจทำงานเฉพาะตอนที่เวลานั้นเปลี่ยนไปเท่านั้น
สำหรับ MQL4:
datetime g_lastBar = 0;
bool IsNewBar()
{
datetime t = iTime(_Symbol, PERIOD_CURRENT, 0);
if(t == g_lastBar) return(false);
g_lastBar = t;
return(true);
}
สำหรับ MQL5:
datetime g_lastBar = 0;
bool IsNewBar()
{
datetime t[1];
if(CopyTime(_Symbol, PERIOD_CURRENT, 0, 1, t) < 1)
return(false);
if(t[0] == g_lastBar) return(false);
g_lastBar = t[0];
return(true);
}
วิธีเรียกใช้ — เหมือนกันทั้งสองภาษา:
void OnTick()
{
if(!IsNewBar()) return;
// โค้ดตัดสินใจเข้าออร์เดอร์ทั้งหมด อยู่ใต้บรรทัดนี้
}
- ฟังก์ชันนี้มีผลข้างเคียง — มันแก้ค่า
g_lastBarตอนที่ถูกเรียก ⇒ ถ้าเรียกสองครั้งในทิกเดียวกัน ครั้งที่สองจะได้ค่าเท็จเสมอ ให้เรียกครั้งเดียวแล้วเก็บผลไว้ในตัวแปร - ค่าเริ่มต้นเป็นศูนย์ ⇒ ทิกแรกหลังแนบ EA เข้าชาร์ตจะนับเป็น "แท่งใหม่" ทันที ทั้งที่แท่งนั้นเดินมาครึ่งทางแล้ว ถ้าไม่ต้องการพฤติกรรมนี้ ให้ตั้งค่า
g_lastBarในOnInit()ก่อน PERIOD_CURRENTผูกกับไทม์เฟรมของชาร์ตที่แนบอยู่ ⇒ เปลี่ยนไทม์เฟรมของชาร์ต พฤติกรรมของ EA เปลี่ยนตามทันทีโดยไม่ได้แก้โค้ดเลยสักบรรทัด ทางที่ปลอดภัยกว่าคือประกาศ input ไทม์เฟรมให้ชัด แล้วใช้ค่านั้นแทน- ตัวแปรนี้เป็นของ EA ตัวนั้นบนชาร์ตนั้นเท่านั้น ⇒ ถ้ารัน EA ตัวเดียวกันบนหลายชาร์ตในบัญชีเดียว ต่างคนต่างมีตัวนับของตัวเอง และไม่เห็นกัน การกันซ้ำระดับบัญชีต้องนับสถานะจริงจากเทอร์มินัล โดยกรองด้วย magic number
ตัวกรองที่ 2, 3, 4 — และสิ่งที่แต่ละแบบแก้ไม่ได้
ตัวกรองที่ 2 — ระยะห่างขั้นต่ำระหว่างไม้: ไม่เข้าใหม่จนกว่าราคาจะขยับไปจากราคาที่เข้าครั้งก่อนอย่างน้อยกี่จุด
if(MathAbs(Ask - g_lastEntryPrice) < MinStepPoints * _Point)
return; // ราคายังขยับไม่พอ ไม่เข้าใหม่
ตัวกรองที่ 3 — หน่วงเวลาหลังไม้ล่าสุดถูกปิด: ตรงกับสาเหตุแบบที่สองที่บทความต้นฉบับพูดถึงพอดี คือไม้ปิดเร็วแล้ววนเข้าใหม่ทันที
if(TimeCurrent() - g_lastCloseTime < CooldownSeconds)
return; // เพิ่งปิดไม้ไป ยังไม่เข้าใหม่
ตัวกรองที่ 4 — เพดานจำนวนไม้: ไม่ได้แก้ต้นเหตุ แต่จำกัดความเสียหายสูงสุดต่อวันเอาไว้
if(g_tradesToday >= MaxTradesPerDay) return;
if(CountOpenPositions(MagicNumber) >= MaxOpenPositions) return;
| ตัวกรอง | แก้อาการอะไรได้ | แก้อะไรไม่ได้ | ผลข้างเคียงที่ต้องยอมรับ |
|---|---|---|---|
| หนึ่งไม้ต่อหนึ่งแท่ง | ยิงซ้ำภายในแท่งเดียวกัน — ตรงจุดที่สุด | ยิงซ้ำในแท่งถัดไปที่เงื่อนไขยังเป็นจริงอยู่ | ถ้าสัญญาณจริงเกิดกลางแท่ง ต้องรอจนขึ้นแท่งใหม่ ซึ่งราคาอาจไปไกลแล้ว |
| ระยะห่างขั้นต่ำ | ยิงซ้ำที่ราคาเดียวกัน ทั้งในแท่งและข้ามแท่ง | ยิงซ้ำหลังราคาวิ่งไปไกลกว่าระยะที่ตั้งไว้แล้ว | 🔑 ถ้าตั้งหลวม ระบบจะกลายเป็นระบบเฉลี่ยต้นทุนโดยไม่ตั้งใจ ซึ่งเป็นคนละกลยุทธ์กับที่ออกแบบไว้ |
| หน่วงเวลาหลังปิดไม้ | อาการวนเข้าใหม่ทันทีหลังไม้ปิดเร็ว | ไม้ที่ยิงซ้ำก่อนจะมีการปิดใด ๆ เกิดขึ้น | พลาดสัญญาณจริงที่มาติดกันในช่วงตลาดวิ่งแรง |
| เพดานจำนวนไม้ | จำกัดความเสียหายสูงสุด และกันมาร์จินหมด | ไม่ได้แตะต้นเหตุเลยแม้แต่นิดเดียว | เมื่อชนเพดาน EA จะหยุดเทรดทั้งที่อาจมีสัญญาณจริงตามมา |
🔑 กับดักใหญ่ที่สุด — ตัวกรองพวกนี้ไม่ได้ "แก้บั๊ก" แต่ "เปลี่ยนกลยุทธ์"
นี่คือส่วนที่ต้องพูดให้ชัด เพราะมันเปลี่ยนวิธีที่ควรจะทดสอบต่อทั้งหมด
| สิ่งที่เปลี่ยนไป | ก่อนใส่ตัวกรอง | หลังใส่ตัวกรอง |
|---|---|---|
| ราคาที่ได้เข้า | ราคาแรกในแท่งที่เงื่อนไขเป็นจริง และอีกหลายราคาตามมา | ราคาเปิดของแท่งถัดไปเท่านั้น — ซึ่งอาจดีกว่าหรือแย่กว่าก็ได้ |
| จำนวนไม้ต่อสัญญาณ | ไม่แน่นอน ขึ้นกับอัตราทิกของช่วงเวลานั้น | หนึ่งไม้เสมอ — คงที่และทำนายได้ |
| ความเสี่ยงต่อสัญญาณ | เป็นตัวคูณที่ควบคุมไม่ได้ | เท่ากับที่คำนวณไว้ตอนออกแบบ |
| ผลการทดสอบย้อนหลังของเดิม | 🔴 ใช้ไม่ได้แล้วทั้งชุด — ต้องรันใหม่ทั้งหมดหลังใส่ตัวกรอง เพราะเส้นทางของออร์เดอร์เปลี่ยนไปตั้งแต่ไม้แรก | |
เช็กลิสต์ 6 ข้อ ก่อนปล่อย EA ลงบัญชีจริง
- นับดูแล้วหรือยังว่าประวัติที่ผ่านมามีกี่แท่งที่มีมากกว่าหนึ่งไม้ ด้วยสูตร
FLOOR+COUNTIFในหัวข้อข้างบน - ทดสอบย้อนหลังด้วยโหมดทุกทิกแล้วหรือยัง — โหมดราคาเปิดอย่างเดียวมองไม่เห็นอาการนี้เลย
- มีเพดานจำนวนไม้และเพดานล็อตรวมอยู่หรือไม่ ในฐานะเบรกมือชั้นสุดท้าย
- ถ้ารันหลายชาร์ตพร้อมกัน มีการกันซ้ำระดับบัญชีด้วย magic number หรือยัง
- คำนวณแล้วหรือยังว่าล็อตรวมสูงสุดที่เป็นไปได้ ใช้มาร์จินเท่าไร และบัญชีรับไหวหรือไม่
- รันบนบัญชีทดลองอย่างน้อยหนึ่งรอบเต็มก่อนหรือยัง — บัญชีทดลองแสดงอาการนี้ได้เหมือนบัญชีจริง เพราะมันได้รับทิกชุดเดียวกัน
สรุป — 4 ข้อที่ยืนยันได้ และ 1 ข้อที่หน้านี้ยืนยันไม่ได้
- สาเหตุคือกลไกของแพลตฟอร์ม ไม่ใช่ความผิดพลาดของโบรกเกอร์ —
OnTick()ถูกเรียกทุกครั้งที่ราคาขยับ ซึ่งในหนึ่งแท่งเกิดได้หลายสิบถึงหลายร้อยครั้ง - ความเสียหายหลักไม่ใช่ค่าสเปรด — ยิงซ้ำ 8 ไม้ทำให้จ่ายสเปรดเพิ่ม $8 แต่ทำให้ความเสี่ยงที่ถืออยู่กลายเป็น $160 ซึ่งใหญ่กว่า 20 เท่า
- สภาพที่แย่ที่สุดคือมาร์จินหมดกลางทาง — EA จะได้สถานะที่ไม่มีใครออกแบบและไม่มีใครทดสอบ ตรรกะปิดไม้ที่เขียนไว้จะทำงานบนสมมติฐานที่ผิด
- ตัวกรองแก้ได้จริงด้วยโค้ดไม่กี่บรรทัด — แต่มันเปลี่ยนพฤติกรรมของระบบ ไม่ใช่แค่ซ่อมบั๊ก ⇒ ผลทดสอบย้อนหลังชุดเดิมใช้ไม่ได้อีกต่อไป
อ่านต่อเรื่องที่เกี่ยวข้อง: Expert Advisor คืออะไร · การคำนวณขนาดล็อต · ค่า spread คิดเป็นเงินจริงเท่าไร · Risk Reward Ratio คืออะไร · MACD ตั้งค่าเท่าไหร่ดี และทำไม MT4/MT5 ไม่ตรงกับตำรา · Trading Journal คืออะไร
และถ้าอยากเทียบสิ่งที่อ่านในหน้านี้กับสัญญาณที่มีตัวเลขจุดเข้า จุดตัดขาดทุน และเป้าหมายกำกับทุกไม้ ดูได้ที่ alphasigs.net
บทความนี้จัดทำเพื่อการศึกษาเท่านั้น ไม่ใช่คำแนะนำการลงทุน โค้ดตัวอย่างในหน้านี้เป็นตัวอย่างเชิงหลักการ ผู้นำไปใช้ต้องทดสอบและรับผิดชอบผลด้วยตนเอง ตัวเลขทั้งหมดเป็นตัวอย่างสมมติที่ใช้แสดงวิธีคำนวณ ไม่ใช่ผลการทดสอบย้อนหลัง และไม่ใช่การรับประกันผลใด ๆ ระบบเทรดอัตโนมัติมีความเสี่ยงที่จะสูญเสียเงินลงทุน ควรทดสอบด้วยบัญชีทดลองก่อนใช้กับเงินจริงเสมอ
ความคิดเห็น
แสดงความคิดเห็น