Início Negociação Sistemática Postagem

Como Integrar Eventos de Alto Impacto do ForexFactory no Seu EA para MetaTrader 4

Anexo
15505.zip (2.86 KB, Baixar 1 vezes)

Oi, pessoal! Hoje vamos falar sobre como integrar eventos de alto impacto do ForexFactory.com ao seu Expert Advisor (EA) para o MetaTrader 4. Estou desenvolvendo um EA focado em Petróleo Bruto e Brent e precisava saber exatamente quando sairia o relatório de 'Inventário de Petróleo'. Normalmente, esse relatório é divulgado às quartas-feiras às 10h30 (horário de Brasília), mas, em feriados, a data pode mudar. Para garantir que meu EA esteja sempre atualizado, a melhor solução foi usar um serviço online para validar a data de lançamento.

A primeira coisa que você precisa fazer é adicionar o site nas configurações do seu EA. Vá até a aba OPÇÕES | EXPERT ADVISOR e insira o endereço http://www.forexfactory.com/ (veja a imagem abaixo).

Agora, vamos definir uma estrutura no seu código para armazenar os eventos. Você pode colocar isso no topo do código, declarando DailyEvents como uma variável global, com o número máximo de eventos armazenados definido pela variável MaxDailyEvents.

// Definindo a estrutura dos eventos
struct EVENTOS
{
   string   time;
   string   title;
   string   currency;
   bool     displayed;
};

#define     MaxDailyEvents       20    // Aumente este número se você espera mais de 20 eventos de alto impacto.
EVENTOS      DailyEvents[MaxDailyEvents];

Em seguida, precisamos recuperar o código HTML do ForexFactory.com e analisá-lo. Se você não entende de código HTML, não se preocupe, vou te guiar por isso :)

Primeiro, vamos construir a URL para o WebRequest. Como só quero o calendário para hoje, vamos definir o parâmetro day da requisição para a data de hoje e enviar a requisição.

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

Depois, enviamos a requisição, verificamos o código de erro (se houver) e convertemos o array de caracteres retornado em uma string. Isso facilita a análise do código HTML.

// Enviando a requisição web
   ResetLastError();
   res = WebRequest("GET", url, cookie, NULL, timeout, post, 0, result, headers);

   // Verificando erros
   if(res == -1)
   {
      Print("Erro na WebRequest. Código de erro = ", GetLastError());
      MessageBox("Adicione o endereço 'http://forexfactory.com/' na
lista de URLs permitidas na" +
        " aba 'Expert Advisors'", "Erro", MB_ICONINFORMATION);
      return(false);
   }

Se não houver erro, convertemos o array de caracteres result em uma string para facilitar a análise.

// Convertendo array de caracteres para string
HTML = CharArrayToString(result);

Agora que temos uma string, podemos usar a função StringFind para localizar elementos HTML. O primeiro passo é garantir que o HTML retornado seja realmente da data de hoje e cortar qualquer coisa antes dessa tag HTML. A função GetHTMLElement é usada para analisar o código HTML e retornar o valor entre as tags HTML especificadas. Veja abaixo a sua definição.

// Calendário carregado, certifique-se de que seja para a data de hoje
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);

Agora que garantimos que o calendário retornado é para a data de hoje, vamos começar a analisar cada linha da tabela e extrair os elementos que precisamos: horário do evento, moeda, impacto e título do evento. Faremos isso para cada linha da tabela até o final do calendário ou até que o MaxDailyEvents seja alcançado.

Uma vez que os dados de cada linha tenham sido extraídos, adicionamos à estrutura DailyEvents.

// Agora, obtenha as linhas da tabela para cada evento
lasttime = NULL;
cnrt = 0;
date = DoubleToStr(Year(), 0) + "." + DoubleToStr(Month(), 0) + "." + DoubleToStr(Day(), 0) + " ";
do
{
   // Obtendo informações do 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>");
         
   // Este é um evento de alto impacto?
   if(StringFind(Symbol(), currency) != -1 && impact == "High")
   {
      // Adicionando à estrutura de eventos diários
      DailyEvents[cntr].displayed = false;
      DailyEvents[cntr].time = time;
      DailyEvents[cntr].title = title;
      DailyEvents[cntr++].currency = currency;
   }
              
   // Cortando a string HTML para a próxima linha da tabela
   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);

Após analisarmos todas as linhas da tabela e chegarmos ao final do calendário, precisamos exibir os eventos no gráfico. Se o evento for no futuro, quero que uma linha vertical seja exibida, e se for no passado, nada será exibido.

// Exibindo os eventos de alto impacto, se houver
lasttime = NULL;
for(cntr = 0; cntr < MaxDailyEvents; cntr++)
{
   if(StringLen(DailyEvents[cntr].time) == 0) break;
      
   // Criando o marcador do evento no gráfico se o último mercado não for o mesmo horário
   if(lasttime != DailyEvents[cntr].time)
   {
      res = cntr;
      // Se tivermos um 'pm' na string, adicione 12 horas ao tempo
      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 + ")");
      }
      
      // Criando a linha vertical se o evento for no 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 os eventos estiverem no futuro, quero notificar o usuário sobre um evento que está prestes a acontecer, se estiver dentro de 5 minutos do horário atual, e remover a linha vertical. Isso é feito adicionando um código na sua função start() do EA ou indicador.

//+------------------------------------------------------------------+
//| Função de início do Expert                                             |
//+------------------------------------------------------------------+
void start()
{
   string   event = NULL;
   
   // Existe um evento de alto impacto nos próximos 5 minutos?
   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 em 5 minutos...
         event += DailyEvents[i].title + " (" + DailyEvents[i].currency + "), ";
         DailyEvents[i].displayed = true;
         
         // Deletando a linha vertical associada ao evento
         if(ObjectFind("VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete("VLine" + DoubleToStr(i, 0));
      }  
   }
   
   // Algo para exibir?
   if(StringLen(event) != 0)
   {
      event += "em 5 minutos.";
      Alert(event);
   }
}

E finalmente, precisamos obter os eventos diários. Isso é feito adicionando uma linha na sua função OnInit().

//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Obtendo os eventos de hoje
   GetHighImpactEvents();
   
   return(INIT_SUCCEEDED);
}

Simples assim! Você pode, claro, modificar o código para exibir todos os eventos para o par de moedas ou adicionar parâmetros de entrada ao seu indicador ou EA para especificar qual impacto exibir (alto, médio ou baixo) e, claro, adicionar um controle para a virada da meia-noite para obter uma nova lista de eventos diários, mas vou deixar você brincar com isso :)


Um abraço!

- Claude.

Publicações relacionadas

Comentário (0)