Comment intégrer les événements à fort impact de ForexFactory dans votre EA pour MetaTrader 4

Mike 2016.05.21 02:37 37 0 0
Pièce jointe

Salut les traders ! Aujourd'hui, je vais vous montrer comment récupérer les événements à fort impact sur ForexFactory.com et les afficher dans votre EA pour MetaTrader 4. Comme je suis en train de développer un Expert Advisor pour le pétrole brut et le Brent, j'avais besoin de connaître la date et l'heure exactes du rapport sur les inventaires de pétrole brut. Ce rapport est généralement publié le mercredi à 10h30, mais en cas de jour férié, la date peut changer. Étant donné que ce rapport est crucial pour mon EA, j'ai dû vérifier un service en ligne pour valider la date de publication.

La première étape consiste à ajouter dans l'onglet OPTIONS | EXPERT ADVISOR le site web qu'il utilisera pour effectuer la WebRequest, ici, nous allons mettre http://www.forexfactory.com/ (voir image 1).

Ensuite, il faut définir une structure dans votre code pour stocker les événements. Cela se place en haut de votre code, où vous déclarerez DailyEvents comme une variable globale avec un nombre maximum d'événements défini par la variable MaxDailyEvents.

// Définir la structure des événements
struct EVENTS
{
   string time;
   string title;
   string currency;
   bool displayed;
};

#define     MaxDailyEvents       20    // Si vous pensez avoir plus de 20 événements à fort impact, augmentez ce nombre.
EVENTS      DailyEvents[MaxDailyEvents];

Maintenant, nous devons récupérer le code HTML depuis ForexFactory.com et le parser. Ne vous inquiétez pas si vous ne comprenez pas le code HTML, je vais vous guider étape par étape :)

Nous devons d'abord construire l'URL pour la WebRequest. Comme je voulais uniquement le calendrier du jour et non celui de la semaine entière, nous allons définir le paramètre day de la requête à la date d'aujourd'hui et envoyer la requête.

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

Ensuite, nous envoyons la requête, vérifions le code d'erreur (s'il y en a) et convertissons le tableau de caractères retourné en chaîne de caractères. Cela facilite le parsing du code HTML.

// Envoyer la requête web
   ResetLastError();
   res = WebRequest("GET", url, cookie, NULL, timeout, post, 0, result, headers);

   // Vérifier les erreurs
   if(res == -1)
   {
      Print("Erreur dans la WebRequest. Code d'erreur = ", GetLastError());
      MessageBox("Ajoutez l'adresse 'http://forexfactory.com/' dans la liste des URL autorisées sur le
onglet 'Expert Advisors'", "Erreur", MB_ICONINFORMATION);
      return(false);
   }

S'il n'y a pas d'erreur, nous convertissons alors le tableau de caractères result en chaîne de caractères pour un meilleur parsing.

// Convertir le tableau de caractères en chaîne
HTML = CharArrayToString(result);

Nous avons maintenant une chaîne, il nous reste à utiliser la fonction StringFind pour localiser les éléments HTML. La première chose à faire est de s'assurer que le HTML retourné concerne bien la date d'aujourd'hui et de couper tout avant cette balise HTML. La fonction GetHTMLElement est utilisée pour parser le code HTML et retourner la valeur entre les balises HTML spécifiées. Voici sa définition.

// Le calendrier est chargé, assurons-nous qu'il s'agit de la date d'aujourd'hui
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);

Maintenant que nous avons vérifié que le calendrier retourné est pour la date d'aujourd'hui, commençons à parser chaque ligne du tableau et à extraire les éléments dont nous avons besoin : l'heure de l'événement, la devise, l'impact et le titre de l'événement. Nous devons faire cela pour chaque ligne du tableau dans le code HTML jusqu'à la fin du calendrier ou jusqu'à ce que nous atteignions MaxDailyEvents.

Une fois les données extraites pour chaque ligne, nous les ajoutons à la structure DailyEvents.

// Récupérer maintenant les lignes du tableau pour chaque événement
lasttime = NULL;
cnrt = 0;
date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(), 0) + "." + DoubleToStr(Day(), 0) + " ";
do
{
   // Obtenir les informations de l'événement
   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>");
         
   // Est-ce un événement à fort impact ?
   if(StringFind(Symbol(), currency) != -1 && impact == "High")
   {
      // Ajouter à la structure des événements quotidiens
      DailyEvents[cntr].displayed = false;
      DailyEvents[cntr].time = time;
      DailyEvents[cntr].title = title;
      DailyEvents[cntr++].currency = currency;
   }
                  
   // Couper la chaîne HTML jusqu'à la prochaine ligne du tableau
   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);

Une fois que nous avons analysé toutes les lignes du tableau et atteint la fin du calendrier, nous devons afficher les événements sur le graphique. Si l'événement est dans le futur, je veux afficher une ligne verticale, et s'il est dans le passé, aucune ligne ne sera affichée.

// Afficher les événements à fort impact, le cas échéant
lasttime = NULL;
for(cntr = 0; cntr < MaxDailyEvents; cntr++)
{
   if(StringLen(DailyEvents[cntr].time) == 0) break;
      
   // Créer un marqueur d'événement sur le graphique si le dernier marché n'était pas à la même heure
   if(lasttime != DailyEvents[cntr].time)
   {
      res = cntr;
      // Si nous avons un 'pm' dans la chaîne, ajouter 12 heures à l'heure
      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 + ")");
      }
      
      // Créer une ligne verticale si l'événement est dans le futur
      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;
}

Pour les événements futurs, je veux notifier l'utilisateur d'un événement à venir s'il se trouve dans les 5 minutes suivant l'heure actuelle et supprimer la ligne verticale. Cela se fait en ajoutant un code dans votre fonction start() de l'EA ou de l'indicateur.

//+------------------------------------------------------------------+
//| Fonction de démarrage de l'Expert                                             |
//+------------------------------------------------------------------+
void start()
{
   string   event = NULL;
   
   // Y a-t-il un événement à fort impact dans les 5 prochaines 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)
      {
         // Événement dans 5 minutes...
         event += DailyEvents[i].title + " (" + DailyEvents[i].currency + "), ";
         DailyEvents[i].displayed = true;
         
         // Supprimer la ligne verticale associée à l'événement
         if(ObjectFind("VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete("VLine" + DoubleToStr(i, 0));
      }  
   }
   
   // Y a-t-il quelque chose à afficher ?
   if(StringLen(event) != 0)
   {
      event += "dans 5 minutes.";
      Alert(event);
   }
}

Enfin, nous devons récupérer les événements quotidiens. Cela se fait en ajoutant une ligne dans votre fonction OnInit().

//+------------------------------------------------------------------+
//| Fonction d'initialisation de l'Expert                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Obtenir les événements du jour
   GetHighImpactEvents();
   
   return(INIT_SUCCEEDED);
}

Simple et efficace ! Bien sûr, vous pouvez modifier le code pour afficher tous les événements pour la paire de devises ou ajouter des paramètres d'entrée à votre indicateur ou EA pour spécifier quel impact afficher (élevé, moyen ou faible) et, bien entendu, ajouter une vérification pour le changement de jour afin d'obtenir une nouvelle liste d'événements quotidiens, mais je vous laisse jouer avec ça :)


À bientôt !

-Claude.

Liste
Commentaire 0