Home Systeemhandel Bericht

Haal Hoogwaardige Economische Evenementen van ForexFactory.com voor je MetaTrader 4 EA

Bijlage
15505.zip (2.86 KB, Downloaden 2 keer)

Hallo traders! Terwijl ik momenteel een Expert Advisor (EA) ontwikkel voor Crude Oil en Brent, wil ik graag de exacte datum en tijd van het 'Crude Oil Inventory' rapport van ForexFactory.com ophalen. Dit rapport wordt meestal op woensdag om 10:30 uur Eastern tijd vrijgegeven, maar bij feestdagen kan de releasedatum veranderen. Aangezien dit een belangrijk rapport is voor mijn EA, moet ik een online dienst raadplegen om de releasedatum te verifiëren.

Het eerste wat je moet doen, is in de OPTIES | EXPERT ADVISOR tab het webadres toevoegen dat gebruikt zal worden voor de WebRequest: http://www.forexfactory.com/ (zie afbeelding 1).

Vervolgens moet je een structuur in je code definiëren om de evenementen op te slaan. Dit plaats je ergens bovenaan je code, waar je 'DailyEvents' declareert als een globale variabele met een maximum aantal opgeslagen evenementen dat is gedefinieerd door de variabele 'MaxDailyEvents'.

// Definieer de evenementstructuur
struct EVENTS
{
   string   tijd;
   string   titel;
   string   valuta;
   bool     weergegeven;
};

#define     MaxDailyEvents       20    // Als je denkt dat je meer dan 20 hoogimpact evenementen hebt, verhoog dit getal.
EVENTS      DailyEvents[MaxDailyEvents];

Daarna moeten we de HTML-code van ForexFactory.com ophalen en parseren. Maak je geen zorgen als je niet goed bent in HTML, ik help je erdoorheen :)

We moeten eerst de URL voor de WebRequest opbouwen. Aangezien ik alleen hun kalender voor de dag wilde en niet de standaard (de hele week), kunnen we dit doen door de 'day'-parameter van de aanvraag in te stellen op de datum van vandaag en de aanvraag te versturen.

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

Vervolgens verzenden we de aanvraag, controleren de foutcode (indien aanwezig) en zetten de teruggegeven karakterarray om in een string. Dit maakt het gemakkelijker om de HTML-code te parseren.

// Stuur webaanvraag
   ResetLastError();
   res = WebRequest("GET", url, cookie, NULL, timeout, post, 0, result, headers);

   // Controleer op fouten
   if(res == -1)
   {
      Print("Fout in WebRequest. Foutcode = ", GetLastError());
      MessageBox("Voeg het adres 'http://forexfactory.com/' toe aan de
lijst van toegestane URL's op" +
        " tab 'Expert Advisors'", "Fout", MB_ICONINFORMATION);
      return(false);
   }

Als er geen fout is, zetten we de karakterarray 'result' om in een string voor betere parsing.

// Zet karakterarray om in een string
HTML = CharArrayToString(result);

Nu we een string hebben, kunnen we de functie 'StringFind' gebruiken om HTML-elementen te lokaliseren. Het eerste wat we moeten doen, is ervoor zorgen dat de teruggegeven HTML inderdaad voor de datum van vandaag is en alles voor deze HTML-tag afsnijden. De functie 'GetHTMLElement' wordt gebruikt om de HTML-code te parseren en de waarde tussen de opgegeven HTML-tags terug te geven. Zie hieronder voor de definitie.

// Kalender geladen, zorg ervoor dat het voor de datum van vandaag is
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);

Hier is de definitie van de functie 'GetHTMLElement'.

//+------------------------------------------------------------------+
//| Haal een HTML-element op
//+------------------------------------------------------------------+
string   GetHTMLElement(string HTML, string ElementStart, string ElementEnd)
{
   string   data = NULL;
   
   // Vind start- en eindpositie voor het element
   int s = StringFind(HTML, ElementStart) + StringLen(ElementStart);
   int e = StringFind(StringSubstr(HTML, s), ElementEnd);
   
   // Geef de inhoud van het element terug
   if(e != 0) data = StringSubstr(HTML, s, e);
   return(data);
}

Oké, nu we ervoor hebben gezorgd dat de kalender die is teruggekomen voor de datum van vandaag is, laten we beginnen met het parseren van elke rij van de tabel en de elementen op te halen die we nodig hebben. Namelijk evenementtijd, evenementvaluta, evenementimpact en evenementtitel. We moeten dit doen voor elke tabelrij in de HTML-code totdat het einde van de kalender is bereikt of het maximum aantal dagelijkse evenementen is bereikt.

Zodra de gegevens voor elke rij zijn geëxtraheerd, voegen we deze toe aan de structuur DailyEvents.

// Haal nu tabelrijen op voor elk evenement
lasttime = NULL;
cnrt = 0;
date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(), 0) + "." + DoubleToStr(Day(), 0) + " ";
do
{
   // Haal evenementinformatie op
   tijd = GetHTMLElement(HTML, "<td class=\"calendar__cell calendar__time time\">", "</td>");
   if(StringFind(tijd, "<a name=\"upnext\"") == 0) tijd = GetHTMLElement(tijd, "class=\"upnext\">", "</span>");
   if(StringLen(tijd) != 0) lasttime = tijd;
   if(StringLen(tijd) == 0) tijd = lasttime; 
   tijd = date + tijd;
   valuta = 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);
   titel = GetHTMLElement(HTML, "\"calendar__event-title\">", "</span>");
         
   // Is dit een hoogimpact evenement?
   if(StringFind(Symbol(), valuta) != -1 && impact == "Hoog")
   {
      // Voeg toe aan dagelijkse evenementstructuur
      DailyEvents[cntr].weergeven = false;
      DailyEvents[cntr].tijd = tijd;
      DailyEvents[cntr].titel = titel;
      DailyEvents[cntr++].valuta = valuta;
   }
                  
   // Snijd de HTML-string naar de volgende tabelrij
   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);

Als we alle tabelrijen hebben geparsed en het einde van de kalender hebben bereikt, moeten we de evenementen op de grafiek weergeven. Als het evenement in de toekomst is, wil ik een verticale lijn tonen en als het in het verleden is, geen lijn.

// Toon de hoogimpact evenementen, indien aanwezig
lasttime = NULL;
for(cntr = 0; cntr < MaxDailyEvents; cntr++)
{
   if(StringLen(DailyEvents[cntr].tijd) == 0) break;
      
   // Maak een evenementmarker op de grafiek als de laatste markt niet dezelfde tijd had
   if(lasttime != DailyEvents[cntr].tijd)
   {
      res = cntr;
      // Als we een 'pm' in de string hebben, voeg 12 uur toe aan de tijd
      if(StringFind(DailyEvents[cntr].tijd, "pm") != -1) DailyEvents[cntr].tijd = TimeToStr(StrToTime(DailyEvents[cntr].tijd) + 43200);
      if(ObjectCreate(0, Event + cntr, OBJ_EVENT, 0, StrToTime(DailyEvents[cntr].tijd), 0))
    {
      ObjectSetString(0, Event + cntr, OBJPROP_TEXT, DailyEvents[cntr].titel + " (" + DailyEvents[cntr].valuta + ")");
      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].titel + " (" + DailyEvents[cntr].valuta + ")");
      }
      
      // Maak verticale lijn als het evenement in de toekomst is
      if(TimeCurrent() < TimeOffset(DailyEvents[cntr].tijd, 0))
      {
         if(ObjectCreate(0, VLine + cntr, OBJ_VLINE, 0, TimeOffset(DailyEvents[cntr].tijd, 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].titel + " (" + DailyEvents[cntr].valuta + ")");
        }
      }
      else
         DailyEvents[cntr].weergeven = true;
} 
   else
   {
      titel = ObjectGetString(0, Event + res, OBJPROP_TOOLTIP);            
      titel += "\n" + DailyEvents[cntr].titel + " (" + DailyEvents[cntr].valuta + ")";
      ObjectSetString(0, Event + res, OBJPROP_TOOLTIP, titel);
      if(TimeCurrent() < TimeOffset(DailyEvents[cntr].tijd, 0)) ObjectSetString(0, VLine + res, OBJPROP_TOOLTIP, titel);
   }
   lasttime = DailyEvents[cntr].tijd;
}

Als de evenementen in de toekomst zijn, wil ik de gebruiker waarschuwen voor een aankomend evenement als het binnen 5 minuten van de actuele tijd valt en de verticale lijn verwijderen. Dit kan gedaan worden door wat code toe te voegen in je 'start()' functie van de EA of indicator.

//+------------------------------------------------------------------+
//| Expert startfunctie                                             |
//+------------------------------------------------------------------+
void start()
{
   string   evenement = NULL;
   
   // Is er een hoogimpact evenement binnen 5 minuten?
   for(int i = 0; i < MaxDailyEvents; i++)
   {
      if(StringLen(DailyEvents[i].tijd) == 0) break;
      if(TimeCurrent() >= StrToTime(DailyEvents[i].tijd) - 300 && TimeCurrent() < StrToTime(DailyEvents[i].tijd) && !DailyEvents[i].weergeven)
      {
         // Evenement binnen 5 minuten...
         evenement += DailyEvents[i].titel + " (" + DailyEvents[i].valuta + "), ";
         DailyEvents[i].weergeven = true;
         
         // Verwijder de verticale lijn die bij het evenement hoort
         if(ObjectFind("VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete("VLine" + DoubleToStr(i, 0));
      }  
   }
   
   // Iets te tonen?
   if(StringLen(evenement) != 0)
   {
      evenement += "in 5 minuten.";
      Alert(evenement);
   }
}

Tot slot moeten we de dagelijkse evenementen ophalen. Dit doe je door een regel toe te voegen in je OnInit() functie.

//+------------------------------------------------------------------+
//| Expert initialisatiefunctie                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Haal de evenementen van vandaag op
   GetHighImpactEvents();
   
   return(INIT_SUCCEEDED);
}

Mooi en eenvoudig. Je kunt de code natuurlijk aanpassen om alle evenementen voor de valutapaar weer te geven of invoerparameters aan je indicator of EA toe te voegen om te specificeren welke impact moet worden weergegeven (hoog, gemiddeld of laag) en natuurlijk een controle toevoegen voor de middernachtsovergang om een nieuwe lijst van dagelijkse evenementen te krijgen, maar dat laat ik aan jou over :)


Cheers!

-Claude.

Gerelateerde berichten

Reactie (0)