System Trading 게시글

How to Fetch High Impact Events from Forex Factory for Your EA

첨부파일
15505.zip (2.86 KB, 다운로드 0회)

Hey fellow traders! As I'm diving into the world of automated trading, I'm currently crafting an Expert Advisor (EA) for Crude Oil and Brent. One of the key pieces of information I need is the exact timing of the 'Crude Oil Inventory' report. This report usually drops on Wednesdays at 10:30 AM Eastern Time, but holidays can throw a wrench in the schedule. To ensure my EA stays sharp, I decided to tap into Forex Factory to get the most accurate release dates.

First off, we need to add the Forex Factory URL in the OPTIONS | EXPERT ADVISOR tab. You'll want to input this URL: http://www.forexfactory.com/ (check out the image below for guidance).

Next, we have to define a structure in our code to hold the events. This goes at the top of your code, declaring DailyEvents as a global variable, limited by the MaxDailyEvents variable.

// Define event structure
struct EVENTS
{
   string   time;
   string   title;
   string   currency;
   bool     displayed;
};

#define    MaxDailyEvents       20    // If you expect more than 20 high-impact events, increase this number.
EVENTS      DailyEvents[MaxDailyEvents];

Now, we need to retrieve the HTML from Forex Factory and parse it. Don’t worry if HTML isn't your strong suit; I’ll guide you through it!

We start by building the URL for the WebRequest. Since I'm only after today's calendar and not the entire week's, we set the 'day' parameter to today's date and send the request.

string   url="http://www.forexfactory.com/calendar.php?day="; url += MthName(Month()) + DoubleToStr(Day(), 0) + "." + DoubleToStr(Year(), 0);

Next, we send the request, check for any errors, and convert the returned character array into a string for easier parsing.

// Send web request
   ResetLastError();
   res = WebRequest("GET", url, cookie, NULL, timeout, post, 0, result, headers);

   // Check for errors
   if(res == -1)
   {
      Print("Error in WebRequest. Error code = ", GetLastError());
      MessageBox("Add the address 'http://forexfactory.com/' in the
list of allowed URLs on" +
        " tab 'Expert Advisors'", "Error", MB_ICONINFORMATION);
      return(false);
   }

If there are no errors, we convert the character array 'result' to a string for easier parsing.

// Convert character array to a string
HTML = CharArrayToString(result);

Now that we have the string, we can use the 'StringFind' function to locate HTML elements. First, we need to ensure the returned HTML is indeed for today's date, and then we slice out everything before that date tag. The function 'GetHTMLElement' will help us parse the HTML and return the desired values. Here’s how it’s defined:

// Calendar loaded, make sure it's for today's date
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);

Let’s move on to parsing the table rows and extracting the necessary elements: event time, currency, impact, and title. We’ll do this until we hit the end of the calendar or reach our maximum daily events.

// Now get table rows for each event
lasttime = NULL;
cnrt = 0;
date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(), 0) + "." + DoubleToStr(Day(), 0) + " ";
do
{
   // Get event information
   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>");
         
   // Is this a high impact event?
   if(StringFind(Symbol(), currency) != -1 && impact == "High")
   {
      // Add to daily event structure
      DailyEvents[cntr].displayed = false;
      DailyEvents[cntr].time = time;
      DailyEvents[cntr].title = title;
      DailyEvents[cntr++].currency = currency;
   }
                  
   // Cut HTML string to the next table row
   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);

Once we've parsed all the table rows and reached the end of the calendar, it’s time to display the events on our chart. If the event is in the future, we want to display a vertical line; if it’s in the past, no line will be shown.

// Display the high impact events, if any
lasttime = NULL;
for(cntr = 0; cntr < MaxDailyEvents; cntr++)
{
   if(StringLen(DailyEvents[cntr].time) == 0) break;
      
   // Create event marker on chart if last market wasn't the same time
   if(lasttime != DailyEvents[cntr].time)
   {
      res = cntr;
      // If we have a 'pm' in the string, add 12 hours to the time
      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 + ")");
      }
      
      // Create vertical line if event is in the future
      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;
}

If we have upcoming events, I want to notify the user if it’s within 5 minutes of the current time and remove the vertical line associated with it. You can do this by adding a few lines to your 'start()' function.

//+------------------------------------------------------------------+
//| Expert start function |
//+------------------------------------------------------------------+
void start()
{
   string   event = NULL;
   
   // Is there a high impact event in the next 5 minutes?
   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)
      {
         // Event in 5 minutes...
         event += DailyEvents[i].title + " (" + DailyEvents[i].currency + "), ";
         DailyEvents[i].displayed = true;
         
         // Delete the vertical line associated to the event
         if(ObjectFind("VLine" + DoubleToStr(i, 0) >= 0) ObjectDelete("VLine" + DoubleToStr(i, 0));
      }
   }
   
   // Anything to display?
   if(StringLen(event) != 0)
   {
      event += "in 5 minutes.";
      Alert(event);
   }
}

Lastly, to fetch the daily events, just add a line in your OnInit() function.

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
   // Get today's events
   GetHighImpactEvents();
   
   return(INIT_SUCCEEDED);
}

And that’s all there is to it! Feel free to tweak the code to display all events for your currency pair or add parameters to filter the impact level you want (high, medium, low). Also, don’t forget to include a check for the midnight turnaround to fetch a fresh list of daily events. But hey, I’ll leave that fun for you to explore!


Cheers!

-Claude.

연관 포스트

댓글 (0)