เริ่มต้นเขียน EA (MQL4) — โครงไฟล์ ฟังก์ชันที่ต้องมี เรื่อง Bid/Ask ที่ทำให้ตั้ง TP ผิด และ 5 บั๊กที่เจอซ้ำที่สุด
หน้านี้รวมพื้นฐานการเขียน EA ทั้งกองไว้ที่เดียว ตั้งแต่ EA เขียนด้วยภาษาอะไร โครงไฟล์มีฟังก์ชันอะไรบ้างและทำงานตอนไหน ไปจนถึงเรื่อง Bid กับ Ask ที่ทำให้หลายคนตั้งจุดทำกำไรพลาดไป 2 เท่าของสเปรด โดยไม่รู้ตัว — พร้อมโค้ดที่แก้แล้วทุกจุด
ถ้ายังไม่รู้ว่า EA คืออะไรและใช้ทำอะไรได้บ้าง อ่านภาพรวมที่ EA (Expert Advisor) คืออะไร ก่อน · ส่วนหน้านี้เริ่มจากสมมติว่าคุณจะลงมือเขียนเองแล้ว
EA เขียนด้วยภาษาอะไร และเขียนที่ไหน
EA ของ MetaTrader เขียนด้วยภาษา MQL (MetaQuotes Language) — MT4 ใช้ MQL4 ส่วน MT5 ใช้ MQL5 ทั้งคู่หน้าตาคล้ายภาษา C มาก และเขียนได้จากโปรแกรมเทรดที่ติดตั้งอยู่แล้ว ไม่ต้องลงอะไรเพิ่ม
- เปิดตัวแก้ไขโค้ด — ในโปรแกรมเทรด ไปที่เมนู
Tools → MetaQuotes Language EditorหรือกดF4 - สร้างไฟล์ใหม่ —
File → New → Expert Advisorแล้วตั้งชื่อ ระบบจะสร้างโครงไฟล์ว่าง ๆ ให้พร้อมฟังก์ชันหลักครบ - คอมไพล์ —
File → Compile⇒ ถ้าไม่มี error จะได้ไฟล์.ex4/.ex5ที่เอาไปลากใส่ชาร์ตได้
⚠️ ปุ่มลัดไม่เหมือนกันทุกรุ่น — MetaEditor รุ่นเก่าเป็นF5รุ่นใหม่เป็นF7⇒ ให้ดูตัวเลขที่เมนูของเครื่องตัวเองเป็นหลัก - ดูผลลัพธ์ตอนรัน — ข้อความจาก
Print()จะไปโผล่ที่แท็บ Experts ส่วน error ตอนส่งคำสั่งจะอยู่ที่แท็บ Journal
Tools → MetaQuotes Language Editor หรือกด F4
File → Compile ใน MetaEditor — ภาพนี้เป็นรุ่นที่ผูกไว้กับ F5 ส่วนรุ่นใหม่จะเป็น F7 ⇒ นี่คือเหตุผลที่ให้ดูจากเมนู ไม่ใช่จำตัวเลขจากบทความMQL4/Experts (หรือ MQL5/Experts) ของ data folder ⇒ เปิดจากเมนู File → Open Data Folder ในโปรแกรมเทรด · อย่าไปหาในโฟลเดอร์ที่ติดตั้งโปรแกรม เพราะคนละที่กัน และเป็นสาเหตุที่หลายคนคอมไพล์แล้วไม่เห็น EA โผล่ในหน้าต่าง Navigator
โครงไฟล์ EA — ฟังก์ชันที่ต้องมี และทำงานตอนไหน
ไฟล์ EA ที่สร้างใหม่จะมีฟังก์ชันหลักมาให้สามตัว แต่ละตัวถูกเรียกโดยโปรแกรมเทรดเอง เราไม่ได้เรียกมันเอง
| ฟังก์ชัน | ถูกเรียกตอนไหน | ใช้ทำอะไร | ชื่อเก่าที่เลิกใช้แล้ว |
|---|---|---|---|
OnInit() | ตอนลาก EA ลงชาร์ต หรือเปลี่ยนค่า input | ตั้งค่าเริ่มต้น · ตรวจว่าค่าที่ผู้ใช้กรอกมาใช้ได้ไหม | init() |
OnTick() | ทุกครั้งที่มีราคาใหม่เข้ามา | ที่ที่ตรรกะการเทรดทั้งหมดอยู่ | start() |
OnDeinit() | ตอนถอด EA ออก ปิดชาร์ต หรือปิดโปรแกรม | เก็บกวาดสิ่งที่วาดไว้บนชาร์ต | deinit() |
OnTick() ถูกเรียกบ่อยกว่าที่คิดมาก — ในช่วงตลาดคึกคัก ราคาใหม่เข้ามาได้หลายครั้งต่อวินาที ⇒ ถ้าเขียนคำสั่งเปิดออเดอร์ไว้ตรง ๆ ใน OnTick() โดยไม่มีตัวคุม EA จะเปิดออเดอร์รัวจนพอร์ตพังก่อนที่คุณจะทันกดหยุด · วิธีคุมและตัวกรอง 4 แบบพร้อมโค้ดอยู่ที่ EA เปิดออร์เดอร์ซ้ำในแท่งเดียว//+------------------------------------------------------------------+
//| โครงไฟล์ EA ที่ใช้เป็นจุดเริ่มต้นได้เลย (MQL4) |
//+------------------------------------------------------------------+
input int InpMagic = 20260903; // เลขประจำตัว EA ใช้แยกไม้ของเราออกจากไม้อื่น
input double InpLots = 0.01; // ขนาดล็อต
datetime g_lastBarTime = 0; // เวลาเปิดของแท่งที่ประมวลผลไปแล้ว
int OnInit()
{
if(InpLots <= 0.0)
{
Print("ค่า InpLots ต้องมากกว่า 0");
return(INIT_PARAMETERS_INCORRECT); // บอกให้โปรแกรมหยุด ไม่ใช่รันต่อทั้งที่ค่าผิด
}
return(INIT_SUCCEEDED);
}
bool IsNewBar()
{
datetime t = iTime(_Symbol, _Period, 0);
if(t == g_lastBarTime) return(false);
g_lastBarTime = t;
return(true);
}
void OnTick()
{
if(!IsNewBar()) return; // ทำงานแท่งละครั้ง ไม่ใช่ทุก tick
// ตรรกะการเทรดของคุณอยู่ตรงนี้
}
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, "myEA_"); // ลบเฉพาะของที่ EA ตัวนี้วาดไว้
}Bid กับ Ask — เรื่องที่ทำให้ตั้ง TP ผิดไป 2 เท่าของสเปรด
ก่อนเขียนคำสั่งแรก ต้องจำสองบรรทัดนี้ให้แม่น เพราะทุกอย่างที่เหลือต่อยอดจากมัน
| ประเภทออเดอร์ | เปิดที่ราคา | ปิดที่ราคา | TP และ SL เทียบกับราคาไหน |
|---|---|---|---|
| BUY | Ask (แพงกว่า) | Bid | Bid — TP ทำงานเมื่อ Bid ขึ้นไปถึง |
| SELL | Bid (ถูกกว่า) | Ask | Ask — TP ทำงานเมื่อ Ask ลงมาถึง |
ผลที่ตามมาคือ ถ้าคุณคิดจากราคาที่เห็นตอน "ซื้อ" แล้วเอาไปตั้ง TP ตรง ๆ มันจะเพี้ยนไปเท่ากับสเปรด — และถ้าปรับผิดข้าง จะเพี้ยนเป็นสองเท่า ลองดูตัวอย่าง GBP/USD ที่สเปรด 3 จุด
| คุณอยากให้ออกตอนไหน | ต้องตั้ง TP เท่าไร | เหตุผล |
|---|---|---|
| อยากให้ Bid (ราคาบนกราฟ MT4) แตะ 1.6150 | 1.6150 | TP ของ BUY เทียบกับ Bid อยู่แล้ว ⇒ ไม่ต้องปรับ |
| อยากให้ Ask แตะ 1.6150 | 1.6147 (ลบสเปรด) | ตอน Ask = 1.6150 ราคา Bid อยู่ที่ 1.6147 |
| ถ้าบวกสเปรดแทน (TP = 1.6153) ⇒ ต้องรอ Bid ถึง 1.6153 = Ask ถึง 1.6156 ⇒ ห่างจากที่ตั้งใจ 6 จุด หรือ 2 เท่าของสเปรด | ||
ฝั่ง SELL กลับด้านทุกอย่าง — TP เทียบกับ Ask ⇒ ถ้าอยากให้ Bid บนกราฟลงมาแตะ 1.5850 ต้องตั้ง TP = 1.5853 คือบวกสเปรด · เรื่องสเปรดที่ไม่คงที่และถ่างได้ในบางช่วงเวลา อ่านต่อที่ Spread ถ่าง คืออะไร
ฟังก์ชันเปิดออเดอร์ — และกับดักของการวนส่งซ้ำ
การแยกคำสั่งเปิดออเดอร์ออกเป็นฟังก์ชันของตัวเองเป็นเรื่องที่ควรทำ เพราะมันคือจุดที่อันตรายที่สุดของทั้งโปรแกรม แต่ตัวอย่างเก่าจำนวนมากใส่ลูป "ส่งซ้ำจนกว่าจะสำเร็จ" ไว้ ซึ่งเป็นการเพิ่มความเสี่ยงแบบทวีคูณ
while(ticket < 0) เฉย ๆ) ก็คือลูปที่ยิงคำสั่งไม่หยุดในช่วงที่ตลาดผันผวน//+------------------------------------------------------------------+
//| เปิดออเดอร์แบบมีเพดานความคลาดและตรวจซ้ำก่อนยิงใหม่ (MQL4) |
//+------------------------------------------------------------------+
input int InpSlippage = 3; // ยอมให้ราคาคลาดได้กี่จุด — 0 = ไม่ยอมเลย
// นับไม้ของ EA ตัวนี้บนสัญลักษณ์นี้ ใช้กันการเปิดซ้ำ
int CountMyOrders()
{
int n = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagic) n++;
}
return(n);
}
bool OpenOrder(int cmd, double lots)
{
if(CountMyOrders() > 0)
{
Print("มีไม้ของ EA ตัวนี้อยู่แล้ว ไม่เปิดซ้ำ");
return(false); // กันเปิดซ้ำก่อนเป็นอันดับแรก
}
double price = (cmd == OP_BUY) ? Ask : Bid;
int ticket = OrderSend(_Symbol, cmd, lots, price, InpSlippage,
0.0, 0.0, "myEA_", InpMagic, 0, clrNONE);
if(ticket < 0)
{
int err = GetLastError();
Print("เปิดออเดอร์ไม่สำเร็จ error = ", err);
return(false); // ไม่วนส่งซ้ำ — ปล่อยให้แท่งถัดไปตัดสินใจใหม่
}
return(true);
}สาระของโค้ดนี้คือ ตรวจก่อนยิง ไม่ใช่ยิงแล้วค่อยแก้ — CountMyOrders() ใช้ OrderMagicNumber() แยกไม้ของ EA ตัวนี้ออกจากไม้ที่เปิดด้วยมือหรือจาก EA ตัวอื่นบนบัญชีเดียวกัน ⇒ ถ้าไม่มีเลขนี้ EA จะไปนับไม้ของคนอื่นเป็นของตัวเอง และตัดสินใจผิดทั้งกระดาน
InpSlippage คืออะไร — คือจำนวนจุดที่คุณยอมให้ราคาคลาดจากที่ขอ ตั้ง 0 แปลว่าไม่ยอมเลย ⇒ ในช่วงข่าวจะเปิดไม่ติดบ่อย ส่วนตั้งกว้างแปลว่ายอมเข้าที่ราคาแย่ลงได้ ⇒ กินอัตราส่วนเสี่ยงต่อผลตอบแทนของแผน · รายละเอียดและตัวเลขว่ากินไปเท่าไร อยู่ที่ Requote คืออะไร
แสดงค่าบนชาร์ตเพื่อดีบัก — วิธีดูว่า EA คิดอะไรอยู่
เวลา EA ทำงานไม่ตรงที่คิด สิ่งที่ช่วยได้มากที่สุดคือให้มันบอกออกมาว่ากำลังเห็นค่าอะไร วิธีที่เบาที่สุดคือวาดข้อความไว้มุมชาร์ต
//+------------------------------------------------------------------+
//| แสดงกำไร/ขาดทุนรวมของไม้ EA ตัวนี้ ไว้มุมซ้ายบนของชาร์ต (MQL4) |
//+------------------------------------------------------------------+
void ShowStatus()
{
double profit = 0.0;
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != _Symbol || OrderMagicNumber() != InpMagic) continue;
profit += OrderProfit() + OrderSwap() + OrderCommission();
count++;
}
string name = "myEA_status";
if(ObjectFind(0, name) < 0) // สร้างครั้งเดียวพอ ไม่ต้องสร้างใหม่ทุก tick
{
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 20);
}
ObjectSetString(0, name, OBJPROP_TEXT,
StringFormat("ไม้ %d กำไรสุทธิ %.2f", count, profit));
ObjectSetInteger(0, name, OBJPROP_COLOR, (profit >= 0) ? clrLime : clrRed);
}int แล้วมีทางออกที่ไม่ได้ return ค่า (2) return ทันทีที่เจอไม้แรก ⇒ ได้กำไรของไม้เดียวไม่ใช่ทั้งหมด (3) นับ OrderProfit() เพียว ๆ โดยไม่บวก OrderSwap() กับ OrderCommission() ⇒ ตัวเลขที่เห็นบนชาร์ตไม่ตรงกับยอดที่หักจริงในบัญชี
5 บั๊กที่มือใหม่เจอซ้ำที่สุด
เปิดออเดอร์ใน OnTick โดยไม่มีตัวคุม
OnTick() ถูกเรียกทุกครั้งที่ราคาขยับ ⇒ เงื่อนไขที่เป็นจริงอยู่ 10 วินาทีอาจเปิดออเดอร์ไปหลายสิบไม้ · แก้ด้วยตัวคุมแท่ง (IsNewBar()) และการนับไม้ที่มีอยู่ก่อนเปิด
ไม่ใส่ Magic Number
ไม่มีเลขประจำตัว EA ⇒ OrdersTotal() จะนับไม้ของทุกคนบนบัญชีนั้นรวมกัน · EA สองตัวบนบัญชีเดียวกันจะปิดไม้ของกันและกันโดยไม่ตั้งใจ
ตั้ง TP/SL ผิดข้างสเปรด
คิดจากราคาที่เห็นตอนซื้อแล้วเอาไปตั้งตรง ๆ ⇒ พลาดไปเท่ากับสเปรด และถ้าปรับผิดข้างจะพลาดเป็น 2 เท่า ตามตารางข้างบน
วนส่งคำสั่งซ้ำจนกว่าจะสำเร็จ
ในช่วงตลาดผันผวน คำสั่งที่ตอบกลับช้าอาจสำเร็จไปแล้ว ⇒ วน 5 ครั้งได้ 5 ไม้ · แก้ด้วยการตรวจไม้ที่มีอยู่ก่อนยิงใหม่เสมอ
ไม่เก็บกวาดใน OnDeinit
ป้ายและเส้นที่ EA วาดไว้ค้างบนชาร์ตหลังถอด EA ออก ⇒ รอบหน้าที่ลากลงมาใหม่จะเห็นค่าเก่าปนกับค่าใหม่และวินิจฉัยผิด
ก่อนปล่อย EA ลงบัญชีจริง
เขียนเสร็จแล้วยังไม่จบ ลำดับที่ควรทำคือทดสอบสามชั้น และแต่ละชั้นตอบคนละคำถาม
- Strategy Tester — ตอบว่า "โค้ดทำงานตามที่เขียนไหม"
ดูว่ามันเปิดปิดไม้ตรงเงื่อนไขหรือเปล่า ไม่ใช่ดูว่ากำไรเท่าไร ⇒ ผลกำไรจากการทดสอบย้อนหลังไม่ใช่คำสัญญาว่าจะได้แบบนั้นจริง เพราะข้อมูลย้อนหลังไม่มีสเปรดถ่าง ไม่มีราคาคลาด และไม่มีคำสั่งที่ส่งไม่ติด - บัญชีทดลอง (demo) อย่างน้อย 1 เดือน — ตอบว่า "ทำงานได้ในสภาพจริงไหม"
ตรงนี้จะเจอของที่ผลทดสอบย้อนหลังไม่มีทางเจอ ทั้งสเปรดที่ถ่างตอนข่าว ราคาคลาด และการที่เซิร์ฟเวอร์ตอบกลับช้า ⇒ ให้ดู Journal ทุกวัน ไม่ใช่ดูแค่ยอดเงิน - บัญชีจริงด้วยขนาดเล็กที่สุด — ตอบว่า "เรารับพฤติกรรมของมันได้ไหม"
ขึ้นบัญชีจริงด้วยล็อตต่ำสุดก่อนเสมอ และมีเงื่อนไขปิดสวิตช์ที่เขียนไว้ล่วงหน้าว่าจะหยุดเมื่อไร ⇒ ตัวเลขที่ใช้ตัดสินคืออัตราชนะที่ทำให้เสมอตัวของแผน ไม่ใช่ความรู้สึก
อ่านต่อ
- เขียน EA ตรวจจับแท่งเทียน Bearish Engulfing — ตัวอย่างเต็มที่แปลงนิยามแพทเทิร์นเป็นเงื่อนไขและโค้ดทั้ง MQL4 และ MQL5
- EA เปิดออร์เดอร์ซ้ำในแท่งเดียว — วิธีตรวจว่า EA ของคุณมีอาการนี้ไหม และตัวกรอง 4 แบบพร้อมโค้ด
- EA (Expert Advisor) คืออะไร — ภาพรวมว่าโปรแกรมเทรดอัตโนมัติทำงานยังไง และต้นทุนที่แพงกว่าตัว EA เอง
- AlphaSigs — ตัวอย่างสัญญาณที่คิดระยะเสี่ยงและอัตราชนะเสมอตัวมาให้แล้ว สำหรับคนที่อยากเห็นโครงก่อนเขียนเอง
บทความนี้เป็นเนื้อหาให้ความรู้ด้านการเขียนโปรแกรมเท่านั้น ไม่ใช่คำแนะนำการลงทุน โค้ดตัวอย่างมีไว้เพื่อการศึกษาและควรทดสอบบนบัญชีทดลองก่อนเสมอ ตัวเลขราคาและสเปรดทั้งหมดเป็นตัวอย่างสมมติเพื่อให้ผู้อ่านคำนวณตามได้ ไม่ใช่ผลตอบแทนที่รับรอง การเทรดมีความเสี่ยงที่จะสูญเสียเงินลงทุน ผู้อ่านควรศึกษาและตัดสินใจด้วยตนเอง
UpasiAcons_chi_Mobile Candice Hall https://wakelet.com/wake/KWnezB7jUK_pBZh0yD0CY
ตอบลบconttipslistsu
bieta0at_gi James Waheed UltraISO
ตอบลบDisk Drill
Pinnacle Studio
derolana