หน้าแรก การเทรดด้วยระบบ โพสต์

วิธีดึงข้อมูลเหตุการณ์สำคัญจาก ForexFactory.com สำหรับการเทรดด้วย Expert Advisor ใน MetaTrader 4

ไฟล์แนบ
15505.zip (2.86 KB, ดาวน์โหลด 2 ครั้ง)

สวัสดีครับเพื่อนๆ นักลงทุนทุกคน! วันนี้เราจะมาพูดถึงวิธีการดึงข้อมูลเหตุการณ์สำคัญในตลาด 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.

โพสต์ที่เกี่ยวข้อง

ความคิดเห็น (0)