Home Trading Sistematico Post

Come Integrare Eventi di Alta Importanza nel Tuo Expert Advisor in MetaTrader 4

Allegato
15505.zip (2.86 KB, Scarica 2 volte)

Ciao trader! Oggi voglio condividere con voi come recuperare gli eventi economici di alta importanza da ForexFactory.com e integrarli nel vostro Expert Advisor (EA) in MetaTrader 4. Mentre sto sviluppando un EA per il petrolio greggio e il Brent, ho avuto la necessità di ottenere data e ora esatte del rapporto sulle scorte di petrolio. Questo rapporto viene generalmente pubblicato il mercoledì alle 10:30 ora di New York, ma in caso di festività, la data di rilascio può cambiare. È fondamentale per il mio EA, quindi ho deciso di utilizzare un servizio online per validare la data di rilascio.

La prima cosa da fare è aggiungere, nella scheda OPZIONI | EXPERT ADVISOR, il sito web da utilizzare per effettuare la WebRequest, che sarà http://www.forexfactory.com/ (vedi immagine 1).

Successivamente, dobbiamo definire una struttura nel nostro codice per memorizzare gli eventi. Questa struttura andrà posizionata nella parte superiore del codice, dichiarando DailyEvents come variabile globale con un numero massimo di eventi memorizzati definito dalla variabile MaxDailyEvents.

// Definisci la struttura degli eventi
struct EVENTS
{
   string   time;
   string   title;
   string   currency;
   bool     displayed;
};

#define     MaxDailyEvents       20    // Se pensi di avere più di 20 eventi di alta importanza, aumenta questo numero.
EVENTS      DailyEvents[MaxDailyEvents];

Ora dobbiamo recuperare il codice HTML da ForexFactory.com e analizzarlo. Non preoccuparti se non sei esperto di HTML, ti guiderò passo dopo passo :)

Iniziamo a costruire l'URL per la WebRequest. Poiché vogliamo solo il calendario per il giorno attuale e non per l'intera settimana, impostiamo il parametro day della richiesta alla data di oggi e inviamo la richiesta.

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

Dopo aver inviato la richiesta, verifichiamo il codice di errore (se presente) e convertiamo l'array di caratteri restituito in una stringa. Questo facilita l'analisi del codice HTML.

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

   // Controlla eventuali errori
   if(res == -1)
   {
      Print("Errore nella WebRequest. Codice errore = ", GetLastError());
      MessageBox("Aggiungi l'indirizzo 'http://forexfactory.com/' nella
lista degli URL consentiti nella" +
        " scheda 'Expert Advisors'", "Errore", MB_ICONINFORMATION);
      return(false);
   }

Se non ci sono errori, convertiamo l'array di caratteri result in una stringa per una migliore analisi.

// Converti l'array di caratteri in una stringa
HTML = CharArrayToString(result);

Ora che abbiamo una stringa, possiamo utilizzare la funzione StringFind per localizzare gli elementi HTML. Prima di tutto, assicuriamoci che l'HTML restituito sia effettivamente per la data di oggi e tagliamo tutto ciò che precede questo tag HTML. Utilizziamo la funzione GetHTMLElement per analizzare il codice HTML e restituire il valore compreso tra i tag HTML specificati. Ecco la sua definizione.

// Calendario caricato, assicurati che sia per la data di oggi
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);

Adesso che abbiamo confermato che il calendario restituito è per la data di oggi, iniziamo ad analizzare ogni riga della tabella e ad estrarre gli elementi necessari: ora dell'evento, valuta, impatto e titolo dell'evento. Dobbiamo fare questo per ogni riga della tabella presente nel codice HTML fino alla fine del calendario o fino a raggiungere il numero massimo di eventi giornalieri.

Una volta estratti i dati di ciascuna riga, li aggiungiamo alla struttura DailyEvents.

// Ora ottieni le righe della tabella per ogni evento
lasttime = NULL;
cnrt = 0;
date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(), 0) + "." + DoubleToStr(Day(), 0) + " ";
do
{
   // Ottieni informazioni sull'evento
   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>");
         
   // È un evento di alta importanza?
   if(StringFind(Symbol(), currency) != -1 && impact == "High")
   {
      // Aggiungi alla struttura degli eventi giornalieri
      DailyEvents[cntr].displayed = false;
      DailyEvents[cntr].time = time;
      DailyEvents[cntr].title = title;
      DailyEvents[cntr++].currency = currency;
   }
                  
   // Taglia la stringa HTML alla successiva riga della tabella
   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);

Una volta analizzate tutte le righe della tabella e raggiunta la fine del calendario, dobbiamo visualizzare gli eventi sul grafico. Se l'evento è nel futuro, vogliamo visualizzare una linea verticale, mentre in passato non mostriamo nulla.

// Visualizza gli eventi di alta importanza, se presenti
lasttime = NULL;
for(cntr = 0; cntr < MaxDailyEvents; cntr++)
{
   if(StringLen(DailyEvents[cntr].time) == 0) break;
      
   // Crea un marcatore di evento sul grafico se l'ultimo mercato non era alla stessa ora
   if(lasttime != DailyEvents[cntr].time)
   {
      res = cntr;
      // Se abbiamo un 'pm' nella stringa, aggiungi 12 ore all'ora
      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 + ")");
      }
      
      // Crea una linea verticale se l'evento è nel futuro
      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;
}

Se gli eventi sono nel futuro, voglio notificare l'utente riguardo a un evento imminente se è entro 5 minuti dall'ora attuale e rimuovere la linea verticale. Questo si fa aggiungendo un po' di codice nella funzione start() del tuo EA o indicatore.

//+------------------------------------------------------------------+
//| Funzione di avvio dell'Expert                                             |
//+------------------------------------------------------------------+
void start()
{
   string   event = NULL;
   
   // C'è un evento di alta importanza nei prossimi 5 minuti?
   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)
      {
         // Evento tra 5 minuti...
         event += DailyEvents[i].title + " (" + DailyEvents[i].currency + "), ";
         DailyEvents[i].displayed = true;
         
         // Elimina la linea verticale associata all'evento
         if(ObjectFind("VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete("VLine" + DoubleToStr(i, 0));
      }  
   }
   
   // Qualcosa da visualizzare?
   if(StringLen(event) != 0)
   {
      event += "tra 5 minuti.";
      Alert(event);
   }
}

Infine, dobbiamo ottenere gli eventi giornalieri. Questo si fa aggiungendo una riga nella tua funzione OnInit().

//+------------------------------------------------------------------+
//| Funzione di inizializzazione dell'Expert                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Ottieni gli eventi di oggi
   GetHighImpactEvents();
   
   return(INIT_SUCCEEDED);
}

Facile e veloce! Puoi ovviamente modificare il codice per visualizzare tutti gli eventi per la coppia di valute o aggiungere parametri di input al tuo indicatore o EA per specificare quale impatto visualizzare (alto, medio o basso) e, naturalmente, aggiungere un controllo per il cambio di giorno a mezzanotte per ottenere una nuova lista di eventi giornalieri, ma ora lascio a te il divertimento di giocarci! :)


Buon trading!

-Claude.

Post correlati

Commento (0)