ตัวอย่างการสร้างและเรียกใช้ฟังก์ชัน
ฟังก์ชันเป็นส่วนสำคัญในการเขียนโปรแกรม MQL4 ที่ช่วยให้เราสามารถจัดระเบียบโค้ด ลดการเขียนโค้ดซ้ำซ้อน และทำให้โปรแกรมอ่านง่ายขึ้น
มาดูตัวอย่างการสร้างและเรียกใช้ฟังก์ชันแบบต่างๆ กัน:
1. ฟังก์ชันพื้นฐานไม่มีการรับค่าและส่งค่า
void PrintWelcomeMessage()
{
Print("Welcome to my Expert Advisor!");
Print("Current Symbol: ", Symbol());
Print("Current Timeframe: ", Period());
}
// เรียกใช้ฟังก์ชัน
void OnStart()
{
PrintWelcomeMessage();
}
ฟังก์ชันที่รับค่าใน MQL4:
- คำอธิบาย:
- ฟังก์ชัน
PrintTradeInfo
รับค่า 3 ตัว:symbol
(string): ชื่อคู่สกุลเงินvolume
(double): ปริมาณการเทรดtype
(int): ประเภทของการเทรด (ซื้อหรือขาย)
- ฟังก์ชันนี้ไม่ส่งค่ากลับ (void) แต่ใช้ค่าที่รับเข้ามาในการแสดงข้อมูล
- ฟังก์ชัน
- ประโยชน์:
- ทำให้ฟังก์ชันมีความยืดหยุ่น สามารถทำงานกับข้อมูลที่แตกต่างกันได้
- ช่วยลดการเขียนโค้ดซ้ำซ้อน เพราะสามารถใช้ฟังก์ชันเดียวกับข้อมูลที่ต่างกันได้
- ข้อควรระวัง:
- ต้องส่งค่าให้ครบตามจำนวนและชนิดของพารามิเตอร์ที่กำหนดไว้
- ควรตรวจสอบความถูกต้องของค่าที่รับเข้ามาก่อนนำไปใช้งาน
- การใช้งานจริง:
- ใช้ในการคำนวณค่าต่างๆ เช่น การคำนวณขนาดล็อต, การคำนวณจุดเข้าเทรด
- ใช้ในการตรวจสอบเงื่อนไขต่างๆ เช่น การตรวจสอบว่าควรเข้าเทรดหรือไม่
ฟังก์ชันที่รับค่าช่วยให้การเขียนโปรแกรม Expert Advisor หรือ Script มีความยืดหยุ่นและสามารถนำกลับมาใช้ซ้ำได้ง่ายขึ้น ทำให้โค้ดมีโครงสร้างที่ดีและง่ายต่อการบำรุงรักษา
2. ฟังก์ชันที่รับค่าพารามิเตอร์
void OpenOrder(int orderType, double lotSize)
{
if(orderType == OP_BUY) {
OrderSend(Symbol(), OP_BUY, lotSize, Ask, 3, 0, 0, "Buy Order", 0, 0, clrGreen);
} else if(orderType == OP_SELL) {
OrderSend(Symbol(), OP_SELL, lotSize, Bid, 3, 0, 0, "Sell Order", 0, 0, clrRed);
}
}
// เรียกใช้ฟังก์ชัน
void OnTick()
{
if(SomeCondition()) {
OpenOrder(OP_BUY, 0.1);
} else if(AnotherCondition()) {
OpenOrder(OP_SELL, 0.1);
}
}
ฟังก์ชัน OpenOrder
นี้เป็นตัวอย่างที่ดีของฟังก์ชันที่รับค่าพารามิเตอร์ใน MQL4 ผมจะอธิบายรายละเอียดดังนี้:
- โครงสร้างของฟังก์ชัน:
- ชื่อฟังก์ชัน: OpenOrder
- ชนิดการส่งคืน: void (ไม่มีการส่งค่ากลับ)
- พารามิเตอร์:
- orderType (int): ระบุประเภทของคำสั่ง (ซื้อหรือขาย)
- lotSize (double): ระบุขนาดล็อตของคำสั่ง
- การทำงานของฟังก์ชัน:
- ตรวจสอบประเภทของคำสั่งโดยใช้ if-else
- ใช้ฟังก์ชัน OrderSend() เพื่อส่งคำสั่งซื้อหรือขาย
- ใช้ค่า Ask สำหรับคำสั่งซื้อ และ Bid สำหรับคำสั่งขาย
- ใช้สีเขียวสำหรับคำสั่งซื้อ และสีแดงสำหรับคำสั่งขาย
- การใช้งานฟังก์ชัน:
- เรียกใช้ในฟังก์ชัน OnTick() ซึ่งทำงานทุกครั้งที่ราคาเปลี่ยนแปลง
- ใช้เงื่อนไข SomeCondition() และ AnotherCondition() (ซึ่งไม่ได้แสดงในโค้ด) เพื่อตัดสินใจว่าจะเปิดคำสั่งซื้อหรือขาย
- ส่งค่า OP_BUY หรือ OP_SELL เป็นพารามิเตอร์แรก และขนาดล็อต 0.1 เป็นพารามิเตอร์ที่สอง
- ข้อดีของการใช้ฟังก์ชันแบบนี้:
- ลดการเขียนโค้ดซ้ำซ้อน: ใช้ฟังก์ชันเดียวสำหรับทั้งคำสั่งซื้อและขาย
- เพิ่มความยืดหยุ่น: สามารถเปลี่ยนขนาดล็อตได้ง่ายเมื่อเรียกใช้ฟังก์ชัน
- ทำให้โค้ดในส่วน OnTick() อ่านง่ายและกระชับขึ้น
- ข้อควรระวัง:
- ไม่มีการตรวจสอบความถูกต้องของ orderType (ควรเพิ่มการตรวจสอบ)
- ไม่มีการจัดการข้อผิดพลาดหากการส่งคำสั่งไม่สำเร็จ
- ใช้ Stop Loss และ Take Profit เป็น 0 ซึ่งอาจไม่เหมาะสมในบางกรณี
ฟังก์ชันนี้เป็นตัวอย่างที่ดีของการใช้พารามิเตอร์เพื่อทำให้ฟังก์ชันมีความยืดหยุ่นและใช้งานได้หลากหลายสถานการณ์ในการเทรด
3. ฟังก์ชันที่ส่งค่ากลับ
double CalculateAveragePrice(int periods)
{
double sum = 0;
for(int i = 0; i < periods; i++) {
sum += iClose(Symbol(), 0, i);
}
return sum / periods;
}
// เรียกใช้ฟังก์ชัน
void OnTick()
{
double avg = CalculateAveragePrice(20);
Print("Average price over last 20 periods: ", avg);
}
ฟังก์ชัน CalculateAveragePrice
นี้เป็นตัวอย่างที่ดีของฟังก์ชันที่ส่งค่ากลับใน MQL4 ผมจะอธิบายรายละเอียดดังนี้:
- โครงสร้างของฟังก์ชัน:
- ชื่อฟังก์ชัน: CalculateAveragePrice
- ชนิดการส่งคืน: double (ส่งค่ากลับเป็นตัวเลขทศนิยม)
- พารามิเตอร์:
- periods (int): จำนวนช่วงเวลาที่ต้องการคำนวณค่าเฉลี่ย
- การทำงานของฟังก์ชัน:
- ใช้ลูป for เพื่อรวมราคาปิดของแท่งเทียนตามจำนวน periods ที่กำหนด
- ใช้ฟังก์ชัน iClose() เพื่อดึงราคาปิดของแต่ละแท่งเทียน
- คำนวณค่าเฉลี่ยโดยหารผลรวมด้วยจำนวน periods
- ส่งค่าเฉลี่ยกลับด้วยคำสั่ง return
- การใช้งานฟังก์ชัน:
- เรียกใช้ในฟังก์ชัน OnTick() ซึ่งทำงานทุกครั้งที่ราคาเปลี่ยนแปลง
- ส่งค่า 20 เป็นพารามิเตอร์ เพื่อคำนวณค่าเฉลี่ยของ 20 ช่วงเวลาล่าสุด
- เก็บค่าที่ส่งกลับมาในตัวแปร avg
- แสดงผลค่าเฉลี่ยที่คำนวณได้ด้วยฟังก์ชัน Print()
- ข้อดีของการใช้ฟังก์ชันแบบนี้:
- แยกการคำนวณออกจากส่วนหลักของโปรแกรม ทำให้โค้ดอ่านง่ายขึ้น
- สามารถนำไปใช้ซ้ำได้ง่าย โดยเปลี่ยนจำนวน periods ตามต้องการ
- ส่งค่ากลับเป็น double ทำให้สามารถนำไปใช้ในการคำนวณอื่นๆ ต่อได้
ฟังก์ชันนี้เป็นตัวอย่างที่ดีของการใช้ฟังก์ชันที่ส่งค่ากลับ ซึ่งช่วยในการคำนวณและวิเคราะห์ข้อมูลราคา ทำให้สามารถนำไปใช้ในการตัดสินใจเทรดหรือการวิเคราะห์ทางเทคนิคอื่นๆ ได้อย่างมีประสิทธิภาพ
4. ฟังก์ชันที่รับค่าแบบอ้างอิง (by reference)
void CalculateSupport(double& supportLevel, int periods)
{
supportLevel = Low[iLowest(NULL, 0, MODE_LOW, periods, 0)];
}
// เรียกใช้ฟังก์ชัน
void OnTick()
{
double support;
CalculateSupport(support, 20);
Print("Support level: ", support);
}
- โครงสร้างของฟังก์ชัน:
- ชื่อฟังก์ชัน: CalculateSupport
- ชนิดการส่งคืน: void (ไม่มีการส่งค่ากลับโดยตรง)
- พารามิเตอร์:
- supportLevel (double&): ตัวแปรอ้างอิงที่จะเก็บค่าระดับแนวรับ
- periods (int): จำนวนช่วงเวลาที่ต้องการใช้ในการคำนวณ
- การทำงานของฟังก์ชัน:
- ใช้ฟังก์ชัน iLowest() เพื่อหาแท่งเทียนที่มีราคาต่ำสุดในช่วงเวลาที่กำหนด
- ใช้ค่าที่ได้จาก iLowest() เพื่อดึงราคาต่ำสุดจากอาร์เรย์ Low[]
- กำหนดค่าราคาต่ำสุดนี้ให้กับตัวแปร supportLevel ที่ส่งมาแบบอ้างอิง
- การใช้งานฟังก์ชัน:
- เรียกใช้ในฟังก์ชัน OnTick() ซึ่งทำงานทุกครั้งที่ราคาเปลี่ยนแปลง
- สร้างตัวแปร support เพื่อเก็บค่าระดับแนวรับ
- ส่งตัวแปร support และค่า 20 (จำนวนช่วงเวลา) เข้าไปในฟังก์ชัน
- แสดงผลค่าระดับแนวรับที่คำนวณได้ด้วยฟังก์ชัน Print()
- ข้อดีของการใช้ฟังก์ชันแบบนี้:
- สามารถเปลี่ยนแปลงค่าของตัวแปรที่อยู่นอกฟังก์ชันได้โดยตรง
- ประหยัดหน่วยความจำเมื่อต้องทำงานกับข้อมูลขนาดใหญ่
- เหมาะสำหรับการคำนวณที่ต้องการส่งกลับหลายค่า
- ข้อควรระวัง:
- การใช้งานต้องระมัดระวังเพราะสามารถเปลี่ยนแปลงค่าของตัวแปรภายนอกได้โดยตรง
- อาจทำให้โค้ดเข้าใจยากขึ้นหากใช้ไม่เหมาะสม
- ไม่มีการตรวจสอบความถูกต้องของค่า periods
5. ฟังก์ชันที่ใช้ตัวแปร static
int CountTrades()
{
static int tradeCount = 0;
tradeCount++;
return tradeCount;
}
// เรียกใช้ฟังก์ชัน
void OnTick()
{
if(SomeCondition()) {
int currentTradeNumber = CountTrades();
Print("Opening trade number: ", currentTradeNumber);
// เปิดออเดอร์ที่นี่
}
}
- โครงสร้างของฟังก์ชัน:
- ชื่อฟังก์ชัน: CountTrades
- ชนิดการส่งคืน: int (ส่งค่ากลับเป็นจำนวนเต็ม)
- ไม่มีพารามิเตอร์
- การทำงานของฟังก์ชัน:
- ใช้ตัวแปร static int tradeCount เพื่อเก็บจำนวนการเรียกใช้ฟังก์ชัน
- เพิ่มค่า tradeCount ขึ้นทีละ 1 ทุกครั้งที่ฟังก์ชันถูกเรียกใช้
- ส่งค่า tradeCount กลับ
- การใช้งานฟังก์ชัน:
- เรียกใช้ในฟังก์ชัน OnTick() ภายใต้เงื่อนไข SomeCondition()
- เก็บค่าที่ส่งกลับมาในตัวแปร currentTradeNumber
- แสดงผลจำนวนการเทรดปัจจุบันด้วยฟังก์ชัน Print()
- ความสำคัญของ static:
- ตัวแปร static จะถูกสร้างขึ้นเพียงครั้งเดียวและคงอยู่ตลอดการทำงานของโปรแกรม
- ค่าของตัวแปร static จะไม่ถูกรีเซ็ตเมื่อออกจากฟังก์ชัน
- ทำให้สามารถนับจำนวนการเรียกใช้ฟังก์ชันได้อย่างต่อเนื่อง
- ข้อดีของการใช้ฟังก์ชันแบบนี้:
- สามารถติดตามจำนวนการเรียกใช้ฟังก์ชันหรือการเกิดเหตุการณ์บางอย่างได้
- ไม่ต้องใช้ตัวแปรกลอบอล ทำให้โค้ดเป็นระเบียบและปลอดภัยมากขึ้น
- เหมาะสำหรับการนับจำนวนหรือการทำงานที่ต้องการความต่อเนื่อง
- ข้อควรระวัง:
- ค่าของตัวแปร static จะไม่ถูกรีเซ็ตเมื่อรีรัน EA หรือเปลี่ยนช่วงเวลา (timeframe)
- อาจทำให้เกิดความสับสนหากไม่เข้าใจการทำงานของ static
6. ฟังก์ชันที่มีค่าเริ่มต้นของพารามิเตอร์
void SetStopLoss(int ticket, double stopLoss, int slippage = 3)
{
if(OrderSelect(ticket, SELECT_BY_TICKET)) {
OrderModify(ticket, OrderOpenPrice(), stopLoss, OrderTakeProfit(), 0, clrRed);
}
}
// เรียกใช้ฟังก์ชัน
void OnTick()
{
if(OrdersTotal() > 0) {
int ticket = OrderTicket();
double newStopLoss = Bid - 20 * Point;
SetStopLoss(ticket, newStopLoss); // ใช้ค่า slippage เริ่มต้น
// หรือ
// SetStopLoss(ticket, newStopLoss, 5); // กำหนดค่า slippage เอง
}
}
- โครงสร้างของฟังก์ชัน:
- ชื่อฟังก์ชัน: SetStopLoss
- ชนิดการส่งคืน: void (ไม่มีการส่งค่ากลับ)
- พารามิเตอร์:
- ticket (int): หมายเลขคำสั่งซื้อขาย
- stopLoss (double): ระดับ Stop Loss ใหม่
- slippage (int, ค่าเริ่มต้น = 3): ค่าความคลาดเคลื่อนที่ยอมรับได้
- การทำงานของฟังก์ชัน:
- ใช้ OrderSelect() เพื่อเลือกคำสั่งซื้อขายตาม ticket
- ถ้าเลือกคำสั่งได้สำเร็จ, ใช้ OrderModify() เพื่อแก้ไข Stop Loss
- ใช้ค่า slippage ที่กำหนดหรือค่าเริ่มต้น 3 pip
- การใช้งานฟังก์ชัน:
- เรียกใช้ในฟังก์ชัน OnTick() เมื่อมีคำสั่งซื้อขายเปิดอยู่
- สามารถเรียกใช้โดยไม่ระบุค่า slippage (ใช้ค่าเริ่มต้น 3)
- หรือสามารถระบุค่า slippage เองได้
- ความสำคัญของค่าเริ่มต้นพารามิเตอร์:
- ช่วยให้ฟังก์ชันมีความยืดหยุ่นในการใช้งาน
- ลดความซับซ้อนในการเรียกใช้ฟังก์ชันเมื่อไม่ต้องการระบุค่าทุกพารามิเตอร์
- ทำให้โค้ดสั้นลงและอ่านง่ายขึ้นในกรณีที่ใช้ค่าเริ่มต้นบ่อยๆ
- ข้อดีของการใช้ฟังก์ชันแบบนี้:
- เพิ่มความยืดหยุ่นในการใช้งาน สามารถใช้ค่าเริ่มต้นหรือกำหนดเองได้
- ลดโอกาสเกิดข้อผิดพลาดจากการลืมใส่ค่าพารามิเตอร์
- ทำให้โค้ดสั้นและกระชับขึ้นเมื่อใช้ค่าเริ่มต้นบ่อยๆ
- ข้อควรระวัง:
- ต้องแน่ใจว่าค่าเริ่มต้นที่กำหนดเหมาะสมกับสถานการณ์ส่วนใหญ่
- อาจทำให้เกิดความสับสนหากผู้ใช้ไม่ทราบว่ามีค่าเริ่มต้นอยู่
- ข้อสังเกตเพิ่มเติม:
- การใช้ค่าเริ่มต้น slippage = 3 เป็นการตั้งค่าที่ค่อนข้างทั่วไป แต่อาจต้องปรับตามสภาพตลาดหรือคู่สกุลเงิน
- ฟังก์ชันนี้ไม่ได้ตรวจสอบว่าการแก้ไข Stop Loss สำเร็จหรือไม่ ซึ่งควรเพิ่มการตรวจสอบนี้ในการใช้งานจริง
ฟังก์ชันนี้แสดงให้เห็นถึงการใช้ค่าเริ่มต้นของพารามิเตอร์ใน MQL4 ซึ่งช่วยเพิ่มความยืดหยุ่นในการใช้งานและทำให้โค้ดสั้นลงในกรณีที่ใช้ค่าทั่วไปบ่อยๆ ทำให้การเขียนและบำรุงรักษาโค้ดทำได้ง่ายขึ้น
7. การใช้ฟังก์ชันร่วมกันในสถานการณ์จริง
// ฟังก์ชันตรวจสอบสัญญาณการเทรด
int CheckTradeSignal()
{
double ma20 = iMA(Symbol(), 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0);
double ma50 = iMA(Symbol(), 0, 50, 0, MODE_SMA, PRICE_CLOSE, 0);
if(ma20 > ma50 && Close[1] > ma20) {
return 1; // สัญญาณซื้อ
} else if(ma20 < ma50 && Close[1] < ma20) {
return -1; // สัญญาณขาย
}
return 0; // ไม่มีสัญญาณ
}
// ฟังก์ชันคำนวณขนาด Lot
double CalculateLotSize(double riskPercent)
{
double accountBalance = AccountBalance();
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double stopLoss = 20 * Point; // ตั้งค่า Stop Loss ที่ 20 pips
double lotSize = (accountBalance * riskPercent) / (stopLoss * tickValue * 100);
return NormalizeDouble(lotSize, 2);
}
// ฟังก์ชันหลัก
void OnTick()
{
if(OrdersTotal() == 0) { // ถ้ายังไม่มีออเดอร์เปิดอยู่
int signal = CheckTradeSignal();
if(signal != 0) {
double lotSize = CalculateLotSize(0.01); // risk 1% ของพอร์ต
if(signal == 1) {
OpenOrder(OP_BUY, lotSize);
} else if(signal == -1) {
OpenOrder(OP_SELL, lotSize);
}
}
}
}
ในตัวอย่างสุดท้ายนี้ เราใช้หลายฟังก์ชันร่วมกันเพื่อสร้าง EA ที่สมบูรณ์ขึ้น โดยแต่ละฟังก์ชันทำหน้าที่เฉพาะของตัวเอง ทำให้โค้ดอ่านง่ายและจัดการได้ง่ายขึ้น
1. ฟังก์ชัน CheckTradeSignal()
ฟังก์ชันนี้ใช้สำหรับตรวจสอบสัญญาณการเทรด โดย:
- คำนวณ Moving Average 20 และ 50 คาบ
- ตรวจสอบการตัดกันของ MA และตำแหน่งของราคาปิดล่าสุด
- ส่งคืนค่า 1 สำหรับสัญญาณซื้อ, -1 สำหรับสัญญาณขาย, 0 เมื่อไม่มีสัญญาณ
2. ฟังก์ชัน CalculateLotSize()
ฟังก์ชันนี้คำนวณขนาด Lot ตามเปอร์เซ็นต์ความเสี่ยงที่กำหนด:
- ใช้ยอดเงินในบัญชี (AccountBalance) เป็นฐานในการคำนวณ
- คำนวณขนาด Lot โดยคำนึงถึง Stop Loss ที่ 20 pips
- ปรับค่า Lot size ให้เป็นทศนิยม 2 ตำแหน่งด้วย NormalizeDouble
3. ฟังก์ชัน OnTick()
ฟังก์ชัน OnTick() เป็นฟังก์ชันหลักที่ทำงานทุกครั้งที่มีการเปลี่ยนแปลงราคา:
- ตรวจสอบว่ายังไม่มีออเดอร์เปิดอยู่
- เรียกใช้ CheckTradeSignal() เพื่อตรวจสอบสัญญาณ
- ถ้ามีสัญญาณ, คำนวณขนาด Lot โดยใช้ CalculateLotSize() ด้วยความเสี่ยง 1%
- เปิดออเดอร์ตามสัญญาณที่ได้รับ (ซื้อหรือขาย) ด้วยฟังก์ชัน OpenOrder() (ไม่ได้แสดงในโค้ดตัวอย่าง)
FOREXDUCK (นามปากกา) นักเขียนของเรามีประสบการณ์การเงินการลงทุนกว่า 10 ปี มีความเชี่ยวชาญในการวิเคราะห์ตลาด Forex และคริปโต โดยเฉพาะการวิเคราะห์ทางเทคนิค รวมถึงเทคนิคต่าง