สวัสดีครับเพื่อนๆ นักลงทุนทุกคน! วันนี้เราจะมาพูดถึงวิธีการดึงข้อมูลเหตุการณ์สำคัญในตลาด Forex จาก ForexFactory.com เพื่อใช้ใน Expert Advisor (EA) ของเรา โดยเฉพาะสำหรับการเทรดน้ำมันดิบ (Crude Oil) และเบรนท์ (Brent) นะครับ
ในการพัฒนา EA ของผม ผมต้องการข้อมูลวันที่และเวลาที่แน่นอนของรายงาน "Crude Oil Inventory" ซึ่งมักจะถูกปล่อยออกมาในวันพุธเวลา 10:30 น. ตามเวลา Eastern แต่ถ้ามีวันหยุด วันปล่อยข้อมูลอาจเปลี่ยนแปลงได้ ดังนั้นเราจึงต้องตรวจสอบบริการออนไลน์เพื่อยืนยันวันปล่อยข้อมูลนี้
1. เพิ่มเว็บไซต์ใน OPTIONS | EXPERT ADVISOR
เริ่มต้นกันที่การเพิ่มเว็บไซต์ที่เราจะใช้ในการทำ WebRequest เข้าไปในแท็บ OPTIONS | EXPERT ADVISOR โดยใช้ URL นี้ http://www.forexfactory.com/ (ดูรูปด้านล่าง)

2. กำหนดโครงสร้างในโค้ด
เราต้องกำหนดโครงสร้างในโค้ดของเราเพื่อเก็บเหตุการณ์ ซึ่งจะถูกวางไว้ที่ส่วนบนของโค้ด โดยจะประกาศตัวแปร DailyEvents เป็นตัวแปรระดับโลกที่มีจำนวนเหตุการณ์สูงสุดที่เก็บได้ตามตัวแปร MaxDailyEvents
// กำหนดโครงสร้างเหตุการณ์ struct EVENTS { string time; string title; string currency; bool displayed; }; #define MaxDailyEvents 20 // ถ้าคุณคิดว่ามีเหตุการณ์สำคัญมากกว่า 20 ให้เพิ่มตัวเลขนี้ EVENTS DailyEvents[MaxDailyEvents];
3. ดึงข้อมูล HTML จาก ForexFactory.com
ถัดไป เราต้องสร้าง URL สำหรับ WebRequest โดยเราแค่ต้องการปฏิทินของวันนี้และไม่ใช่ทั้งหมดในสัปดาห์ โดยเราสามารถตั้งค่าพารามิเตอร์ day ของคำขอให้เป็นวันที่วันนี้และส่งคำขอไป
string url="http://www.forexfactory.com/calendar.php?day="; url += MthName(Month()) + DoubleToStr(Day(), 0) + "." + DoubleToStr(Year(), 0);
4. ส่งคำขอและตรวจสอบข้อผิดพลาด
หลังจากนั้นเราจะส่งคำขอ ตรวจสอบรหัสข้อผิดพลาด (ถ้ามี) และแปลงอาร์เรย์ตัวอักษรที่ส่งกลับเป็นสตริง ซึ่งจะทำให้เราง่ายต่อการแยกวิเคราะห์โค้ด HTML
// ส่งคำขอเว็บ ResetLastError(); res = WebRequest("GET", url, cookie, NULL, timeout, post, 0, result, headers); // ตรวจสอบข้อผิดพลาด if(res == -1) { Print("Error in WebRequest. Error code = ", GetLastError()); MessageBox("เพิ่มที่อยู่ 'http://forexfactory.com/' ใน รายการ URL ที่อนุญาตใน" + " แท็บ 'Expert Advisors'", "Error", MB_ICONINFORMATION); return(false); }
5. แปลงอาร์เรย์ตัวอักษรเป็นสตริง
หากไม่มีข้อผิดพลาด เราก็แค่แปลงอาร์เรย์ตัวอักษร result เป็นสตริงเพื่อให้การแยกวิเคราะห์ทำได้ง่ายขึ้น
// แปลงอาร์เรย์ตัวอักษรเป็นสตริง HTML = CharArrayToString(result);
6. เริ่มการแยกวิเคราะห์ข้อมูล
เมื่อเรามีสตริงแล้ว เราสามารถใช้ฟังก์ชัน StringFind เพื่อตรวจสอบว่า HTML ที่ส่งกลับมานั้นเป็นของวันที่วันนี้หรือไม่ และตัดข้อมูลที่ไม่ต้องการทิ้ง
// ตรวจสอบว่าเป็นข้อมูลของวันที่วันนี้ int i = StringFind(HTML, "<span class=\"date\">"); if(i == -1) return(false); HTML = StringSubstr(HTML, i); string date = GetHTMLElement(HTML, "<span>", "</span>"); if(date != MthName(Month()) + " " + DoubleToStr(Day(),0)) return(false);
7. ดึงข้อมูลเหตุการณ์
เมื่อเรามั่นใจว่าปฏิทินที่โหลดมีข้อมูลสำหรับวันที่วันนี้แล้ว เราจะเริ่มแยกข้อมูลจากแต่ละแถวในตารางเพื่อดึงข้อมูลที่เราต้องการ ได้แก่ เวลาของเหตุการณ์ สกุลเงิน ผลกระทบ และชื่อเหตุการณ์
// เริ่มดึงข้อมูลจากแต่ละแถว lasttime = NULL; cnrt = 0; date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(),0) + "." + DoubleToStr(Day(), 0) + " "; do { // ดึงข้อมูลเหตุการณ์ time = GetHTMLElement(HTML, "<td class=\"calendar__cell calendar__time time\">", "</td>"); if(StringFind(time, "<a name=\"upnext\"") == 0) time = GetHTMLElement(time, "class=\"upnext\">", "</span>"); if( StringLen(time) != 0) lasttime = time; if( StringLen(time) == 0) time = lasttime; time = date + time; currency = GetHTMLElement(HTML, "<td class=\"calendar__cell calendar__currency currency\">", "</td>"); impact = GetHTMLElement(HTML, "<span title=\"", "\" class=\""); i = StringFind(impact, " Impact"); if(i != - 1) impact = StringSubstr(impact, 0, i); title = GetHTMLElement(HTML, "\"calendar__event-title\">", "</span>"); // เป็นเหตุการณ์สำคัญหรือไม่? if( StringFind( Symbol(), currency) != - 1 && impact == "High") { // เพิ่มเข้าไปในโครงสร้างเหตุการณ์ประจำวัน DailyEvents[cntr].displayed = false; DailyEvents[cntr].time = time; DailyEvents[cntr].title = title; DailyEvents[cntr++].currency = currency; } // ตัดสตริง HTML ไปยังแถวถัดไป i = StringFind(HTML, "</tbody> </table> </td> </tr> "); if(i != - 1) HTML = StringSubstr(HTML, i+ 30); if( StringFind(HTML, "</table> <div class=\"foot\">") == 0) i = - 1; } while(i != - 1 || cntr == MaxDailyEvents);
8. แสดงเหตุการณ์บนกราฟ
เมื่อเราดึงข้อมูลจากทุกแถวในปฏิทินจนถึงจุดสิ้นสุดแล้ว เราจำเป็นต้องแสดงเหตุการณ์บนกราฟ ถ้าเหตุการณ์นั้นอยู่ในอนาคต เราจะให้แสดงเส้นแนวตั้ง แต่ถ้าเป็นอดีตจะไม่แสดงเส้น
// แสดงเหตุการณ์ที่สำคัญ ถ้ามี lasttime = NULL; for(cntr = 0; cntr < MaxDailyEvents; cntr++) { if( StringLen(DailyEvents[cntr].time) == 0) break; // สร้างเครื่องหมายเหตุการณ์บนกราฟถ้าตลาดล่าสุดไม่ใช่เวลาเดียวกัน if(lasttime != DailyEvents[cntr].time) { res = cntr; // ถ้ามี "pm" ในสตริง ให้เพิ่ม 12 ชั่วโมงเข้าไปในเวลา if( StringFind(DailyEvents[cntr].time, "pm") != - 1) DailyEvents[cntr].time = TimeToStr( StrToTime(DailyEvents[cntr].time) + 43200); if( ObjectCreate( 0, Event + cntr, OBJ_EVENT, 0, StrToTime(DailyEvents[cntr].time), 0)) { ObjectSetString( 0, Event + cntr, OBJPROP_TEXT, DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"); ObjectSetInteger( 0, Event + cntr, OBJPROP_COLOR, Red); ObjectSetInteger( 0, Event + cntr, OBJPROP_WIDTH, 2); ObjectSetInteger( 0, Event + cntr, OBJPROP_BACK, true); ObjectSetInteger( 0, Event + cntr, OBJPROP_SELECTABLE, false); ObjectSetInteger( 0, Event + cntr, OBJPROP_SELECTED, false); ObjectSetInteger( 0, Event + cntr, OBJPROP_HIDDEN, true); ObjectSetString( 0, Event + cntr, OBJPROP_TOOLTIP, DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"); } // สร้างเส้นแนวตั้งถ้าเหตุการณ์อยู่ในอนาคต if( TimeCurrent() < TimeOffset(DailyEvents[cntr].time, 0)) { if( ObjectCreate( 0, VLine + cntr, OBJ_VLINE, 0, TimeOffset(DailyEvents[cntr].time, 0), 0)) { ObjectSetInteger( 0, VLine + cntr, OBJPROP_COLOR, Red); ObjectSetInteger( 0, VLine + cntr, OBJPROP_WIDTH, 1); ObjectSetInteger( 0, VLine + cntr, OBJPROP_BACK, true); ObjectSetInteger( 0, VLine + cntr, OBJPROP_SELECTABLE, false); ObjectSetInteger( 0, VLine + cntr, OBJPROP_SELECTED, false); ObjectSetInteger( 0, VLine + cntr, OBJPROP_HIDDEN, true); ObjectSetString( 0, VLine + cntr, OBJPROP_TOOLTIP, DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"); } } else DailyEvents[cntr].displayed = true; } else { title = ObjectGetString( 0, Event + res, OBJPROP_TOOLTIP); title += "\n" + DailyEvents[cntr].title + " (" + DailyEvents[cntr].currency + ")"; ObjectSetString( 0, Event + res, OBJPROP_TOOLTIP, title); if( TimeCurrent() < TimeOffset(DailyEvents[cntr].time, 0)) ObjectSetString( 0, VLine + res, OBJPROP_TOOLTIP, title); } lasttime = DailyEvents[cntr].time; }
9. แจ้งเตือนเหตุการณ์ในอนาคต
สำหรับเหตุการณ์ที่อยู่ในอนาคต ผมต้องการแจ้งเตือนผู้ใช้เกี่ยวกับเหตุการณ์ที่จะเกิดขึ้นภายใน 5 นาทีของเวลาปัจจุบันและลบเส้นแนวตั้งออก ซึ่งสามารถทำได้โดยการเพิ่มโค้ดในฟังก์ชัน start() ของ EA หรือ Indicator
//+------------------------------------------------------------------+ //| ฟังก์ชันเริ่มต้น Expert | //+------------------------------------------------------------------+ void start() { string event = NULL; // มีเหตุการณ์สำคัญใน 5 นาทีถัดไปหรือไม่? for( int i = 0; i < MaxDailyEvents; i++) { if( StringLen(DailyEvents[i].time) == 0) break; if( TimeCurrent() >= StrToTime(DailyEvents[i].time) - 300 && TimeCurrent() < StrToTime(DailyEvents[i].time) && !DailyEvents[i].displayed) { // เหตุการณ์ใน 5 นาที... event += DailyEvents[i].title + " (" + DailyEvents[i].currency + "), "; DailyEvents[i].displayed = true; // ลบเส้นแนวตั้งที่เชื่อมโยงกับเหตุการณ์ if( ObjectFind( "VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete( "VLine" + DoubleToStr(i, 0)); } } // มีอะไรให้แสดงหรือไม่? if( StringLen(event) != 0) { event += "ใน 5 นาที."; Alert(event); } }
10. รับเหตุการณ์ประจำวัน
และสุดท้าย เราต้องดึงเหตุการณ์ประจำวัน ซึ่งสามารถทำได้โดยการเพิ่มบรรทัดในฟังก์ชัน OnInit()
//+------------------------------------------------------------------+ //| ฟังก์ชันการเริ่มต้น Expert | //+------------------------------------------------------------------+ int OnInit() { // รับเหตุการณ์ของวันนี้ GetHighImpactEvents(); return( INIT_SUCCEEDED); }
เป็นเรื่องง่ายและตรงไปตรงมา! คุณสามารถปรับแต่งโค้ดเพื่อแสดงเหตุการณ์ทั้งหมดสำหรับคู่เงินนั้นๆ หรือเพิ่มพารามิเตอร์การป้อนข้อมูลใน Indicator หรือ EA ของคุณเพื่อระบุผลกระทบที่ต้องการแสดง (สูง, กลาง หรือ ต่ำ) และแน่นอนว่าอย่าลืมตรวจสอบการเปลี่ยนแปลงเวลาในตอนเที่ยงคืนเพื่อรับรายการใหม่ของเหตุการณ์ประจำวัน แต่ผมจะให้คุณเล่นกับมันเองนะครับ :)
ขอบคุณครับ!
- Claude.
โพสต์ที่เกี่ยวข้อง
- แนะนำ MCM Control Panel สำหรับ EA และอินดิเคเตอร์หลายสกุลเงิน
- ทำความรู้จักกับ Fundamental Trader EA บน MetaTrader 4 สำหรับการเทรดข่าว
- สร้าง Expert Advisor ด้วย MQL5 Wizard: สัญญาณซื้อขายจาก Morning/Evening Stars + MFI
- สร้าง Expert Advisor ด้วย MQL5 Wizard สำหรับสัญญาณการเทรด Bullish Harami/Bearish Harami และ RSI
- การสร้าง Expert Advisor ด้วย MQL5 Wizard: สัญญาณการเทรดจาก Morning/Evening Stars + RSI