Systemhandel 게시글

So integrierst du hochkarätige Wirtschaftsdaten in deinen EA für MetaTrader 4

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

Hallo Trader-Kollegen! Heute möchte ich mit euch teilen, wie ich meinen Expert Advisor (EA) für Rohöl und Brent entwickle und dabei die hochkarätigen Wirtschaftsdaten von ForexFactory.com einbinde. Besonders wichtig ist der "Crude Oil Inventory" Bericht, der normalerweise mittwochs um 10:30 Uhr veröffentlicht wird. Feiertage können den Veröffentlichungstermin jedoch ändern, daher ist es entscheidend, auf aktuelle Daten zuzugreifen.

Der erste Schritt ist, die URL von ForexFactory in den Optionen deines EAs zu definieren. Gehe dazu auf den Reiter OPTIONEN | EXPERT ADVISOR und füge die folgende URL hinzu: http://www.forexfactory.com/ (siehe Bild 1).

Als nächstes musst du in deinem Code eine Struktur definieren, um die Ereignisse zu speichern. Diese Struktur sollte ganz oben in deinem Code stehen und 'DailyEvents' als globale Variable deklarieren, wobei die maximale Anzahl der gespeicherten Ereignisse durch die Variable 'MaxDailyEvents' festgelegt wird.

// Ereignisstruktur definieren
struct EVENTS
{
   string   time;
   string   title;
   string   currency;
   bool     displayed;
};

#define     MaxDailyEvents       20    // Erhöhe diese Zahl, wenn du mehr als 20 hochkarätige Ereignisse erwartest.
EVENTS      DailyEvents[MaxDailyEvents];

Jetzt müssen wir den HTML-Code von ForexFactory.com abrufen und analysieren. Keine Sorge, auch wenn du dich mit HTML nicht auskennst, führe ich dich Schritt für Schritt durch den Prozess :)

Wir beginnen mit dem Aufbau der URL für die Webanfrage. Da ich nur den Kalender für den heutigen Tag und nicht für die gesamte Woche wollte, setze ich den 'day'-Parameter der Anfrage auf das heutige Datum.

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

Danach senden wir die Anfrage, überprüfen den Fehlercode (sofern vorhanden) und konvertieren das zurückgegebene Zeichenarray in einen String, was das Analysieren des HTML-Codes erleichtert.

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

   // Fehler überprüfen
   if(res == -1)
   {
      Print("Fehler bei WebRequest. Fehlercode = ", GetLastError());
      MessageBox("Füge die Adresse 'http://forexfactory.com/' zur
Liste der erlaubten URLs im " +
        "Reiter 'Expert Advisors'", "Fehler", MB_ICONINFORMATION);
      return(false);
   }

Wenn kein Fehler auftritt, konvertieren wir das Zeichenarray 'result' in einen String für eine bessere Analyse.

// Zeichenarray in String umwandeln
HTML = CharArrayToString(result);

Jetzt, wo wir einen String haben, können wir die Funktion 'StringFind' verwenden, um die HTML-Elemente zu lokalisieren. Zuerst stellen wir sicher, dass das zurückgegebene HTML tatsächlich für das heutige Datum ist, und schneiden alles vor diesem HTML-Tag ab. Die Funktion 'GetHTMLElement' wird verwendet, um den HTML-Code zu analysieren und den Wert zwischen den angegebenen HTML-Tags zurückzugeben. Hier ist die Definition:

// Kalender geladen, sicherstellen, dass es für heute ist
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);

Die Definition der Funktion 'GetHTMLElement' sieht folgendermaßen aus:

//+------------------------------------------------------------------+
//| HTML-Element extrahieren
//+------------------------------------------------------------------+
string   GetHTMLElement(string HTML, string ElementStart, string ElementEnd)
{
   string   data = NULL;
   
   // Start- und Endposition für Element finden
   int s = StringFind(HTML, ElementStart) + StringLen(ElementStart);
   int e = StringFind(StringSubstr(HTML, s), ElementEnd);
   
   // Elementinhalt zurückgeben
   if(e != 0) data = StringSubstr(HTML, s, e);
   return(data);
}

Jetzt, wo wir sichergestellt haben, dass der Kalender für heute ist, beginnen wir mit der Analyse jeder Tabellenzeile und extrahieren die benötigten Elemente: Zeit des Ereignisses, Währung, Einfluss und Titel des Ereignisses. Dies wiederholen wir für jede Tabellenzeile im HTML-Code, bis wir das Ende des Kalenders oder die maximale Anzahl an täglichen Ereignissen erreicht haben.

Sobald die Daten für jede Zeile extrahiert sind, fügen wir sie der Struktur 'DailyEvents' hinzu.

// Tabellenzeilen für jedes Ereignis abrufen
lasttime = NULL;
cnrt = 0;
date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(), 0) + "." + DoubleToStr(Day(), 0) + " ";
do
{
   // Ereignisinformation abrufen
   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>");
         
   // Ist dies ein hochkarätiges Ereignis?
   if(StringFind(Symbol(), currency) != -1 && impact == "High")
   {
      // Zur Struktur der täglichen Ereignisse hinzufügen
      DailyEvents[cntr].displayed = false;
      DailyEvents[cntr].time = time;
      DailyEvents[cntr].title = title;
      DailyEvents[cntr++].currency = currency;
   }
                  
   // HTML-String auf die nächste Tabellenzeile kürzen
   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);

Sobald wir alle Tabellenzeilen analysiert und das Ende des Kalenders erreicht haben, müssen wir die Ereignisse im Chart anzeigen. Bei zukünftigen Ereignissen möchte ich, dass eine vertikale Linie angezeigt wird, während bei vergangenen Ereignissen keine Linie angezeigt wird.

// Hochkarätige Ereignisse anzeigen, falls vorhanden
lasttime = NULL;
for(cntr = 0; cntr < MaxDailyEvents; cntr++)
{
   if(StringLen(DailyEvents[cntr].time) == 0) break;
      
   // Ereignismarker im Chart erstellen, wenn der letzte Markt nicht zur gleichen Zeit war
   if(lasttime != DailyEvents[cntr].time)
   {
      res = cntr;
      // Wenn wir 'pm' im String haben, 12 Stunden zur Zeit hinzufügen
      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 + ")");
      }
      
      // Vertikale Linie erstellen, wenn das Ereignis in der Zukunft ist
      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;
}

Wenn die zukünftigen Ereignisse anstehen, möchte ich den Nutzer in den nächsten 5 Minuten über ein bevorstehendes Ereignis informieren und die vertikale Linie entfernen. Das wird durch Hinzufügen von etwas Code in die start()-Funktion deines EAs oder Indikators erledigt.

//+------------------------------------------------------------------+
//| Startfunktion des EAs                                             |
//+------------------------------------------------------------------+
void start()
{
   string   event = NULL;
   
   // Gibt es in den nächsten 5 Minuten ein hochkarätiges Ereignis?
   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)
      {
         // Ereignis in 5 Minuten...
         event += DailyEvents[i].title + " (" + DailyEvents[i].currency + "), ";
         DailyEvents[i].displayed = true;
         
         // Vertikale Linie entfernen, die mit dem Ereignis verbunden ist
         if(ObjectFind("VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete("VLine" + DoubleToStr(i, 0));
      }  
   }
   
   // Gibt es etwas anzuzeigen?
   if(StringLen(event) != 0)
   {
      event += "in 5 Minuten.";
      Alert(event);
   }
}

Abschließend brauchen wir die täglichen Ereignisse. Das geschieht, indem du eine Zeile in die OnInit()-Funktion hinzufügst.

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des EAs                                     |
//+------------------------------------------------------------------+
int OnInit()
{
   // Hol die Ereignisse von heute
   GetHighImpactEvents();
   
   return(INIT_SUCCEEDED);
}

Einfach und übersichtlich! Natürlich kannst du den Code anpassen, um alle Ereignisse für das Währungspaar anzuzeigen oder Eingabeparameter für deinen Indikator oder EA hinzuzufügen, um festzulegen, welche Auswirkungen angezeigt werden sollen (hoch, mittel oder niedrig). Außerdem kannst du eine Überprüfung für den Mitternachtswechsel hinzufügen, um eine neue Liste von täglichen Ereignissen zu erhalten, aber ich lasse das mal dir überlassen :)


Viel Erfolg beim Traden!

- Claude.

연관 포스트

댓글 (0)