English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Construindo um negociante de notícias automático

Construindo um negociante de notícias automático

MetaTrader 5Negociação | 26 março 2014, 13:30
2 288 0
laplacianlab
[Excluído]

Introdução

Como a Investopedia explica, um negociante de notícias é "um negociante ou investidor que toma decisões de negociação ou investimento baseadas em anúncios de notícias". De fato, relatos econômicos como o PIB de um país, índices de confiança do consumidor e dados de emprego dos países, entre outros, frequentemente produzem movimentos significantes nos mercados de moeda corrente. Você já compareceu a um lançamento da folha de pagamento dos empregos não agrícolas nos EUA? Se já, você já sabe que esses relatórios podem determinar o futuro recente das moedas correntes e agir como catalisadores para as reversões das tendências.

Jornais B&W

Figura 1. Jornais B&W. Imagem distribuída sob uma licença Creative Commons no Flickr

1. Vamos programar o nosso CE


1,1. A ideia do sistema de negociação

A ideia por trás desse sistema é o que discutimos acima. Isso parece ótimo, mas como podemos implementar esse fato provado no mundo da programação? Principalmente estamos confiando em dois aspectos do MQL5. Por um lado, estamos utilizando o indicador de momento (Momentum) para medir o impacto do dado conjunto de notícias em um par de moedas correntes. Por outro lado, trabalharemos com as funções do arquivo do MQL5 para armazenar nosso calendário de notícias favorito no sistema de arquivos. O formato de arquivo escolhido é CSV. Vamos programar esse robô sob o paradigma orientado a objeto, claro, com a abordagem conceitual discutida em Outra classe OOP do MQL5. Nosso projeto orientado a objeto carregará o CSV na memória do computador de forma que o CE possa tomar decisões baseado em tal informação.


1,2. O esqueleto OOP do robô

De agora em diante estamos concebendo os nossos CEs do ponto de vista de conceitos, como se eles fossem criaturas vivas. Somos agora pessoas OOP, você se lembra? Graças a essa visão podemos compor nosso consultor especialista de várias partes como o cérebro, algo que chamamos evolução, um conjunto de indicadores e um conjunto de notícias. Vou esclarecer isso abaixo.

//+---------------------------------------------------------------------+
//|                                               ExpertNewsWatcher.mq5 |
//|                    Copyright © 2013, laplacianlab, Jordi Bassagañas | 
//+---------------------------------------------------------------------+

#property copyright     "Copyright © 2013, laplacianlab. Jordi Bassagañas"
#property link          "https://www.mql5.com/en/articles"
#property version       "1.00"
#property tester_file   "news_watcher.csv"  

#include <..\Experts\NewsWatcher\CNewsWatcher.mqh>

input ENUM_TIMEFRAMES   Period=PERIOD_M1;
input int               StopLoss=400;
input int               TakeProfit=600;
input double            LotSize=0.01;
input string            CsvFile="news_watcher.csv";
 
MqlTick tick;
CNewsWatcher* NW = new CNewsWatcher(StopLoss,TakeProfit,LotSize,CsvFile);

int OnInit(void)
  {
   NW.Init();
   NW.GetTechIndicators().GetMomentum().SetHandler(Symbol(), Period, 13, PRICE_CLOSE);
   return(0);
  }

void OnDeinit(const int reason)
  {
   delete(NW);
  }

void OnTick()
  {
   SymbolInfoTick(_Symbol, tick);              
   NW.GetTechIndicators().GetMomentum().UpdateBuffer(2);
   NW.OnTick(tick.ask,tick.bid);
  }
//+------------------------------------------------------------------+

CNewsWatcher é a classe principal do CE. Vamos dar uma olhada no código.

//+---------------------------------------------------------------------+
//|                                                    CNewsWatcher.mqh |
//|                                  Copyright © 2013, Jordi Bassagañas |
//+---------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Mine\Enums.mqh>
#include <..\Experts\NewsWatcher\CBrain.mqh>
#include <..\Experts\NewsWatcher\CEvolution.mqh>
#include <..\Experts\NewsWatcher\CTechIndicators.mqh>
//+---------------------------------------------------------------------+
//| CNewsWatcher Class                                                  |
//+---------------------------------------------------------------------+
class CNewsWatcher
  {
protected:
   //--- Custom types
   CBrain               *m_brain;
   CEvolution           *m_evolution;
   CTechIndicators      *m_techIndicators; 
   //--- MQL5 types
   CTrade               *m_trade;
   CPositionInfo        *m_positionInfo;
public:
   //--- Constructor and destructor methods
                        CNewsWatcher(int stop_loss,int take_profit,double lot_size,string csv_file);
                        ~CNewsWatcher(void);
   //--- Getter methods
   CBrain               *GetBrain(void);
   CEvolution           *GetEvolution(void);
   CTechIndicators      *GetTechIndicators(void);
   CTrade               *GetTrade(void);
   CPositionInfo        *GetPositionInfo(void);
   //--- CNewsWatcher methods
   bool                 Init();
   void                 Deinit(void);
   void                 OnTick(double ask,double bid);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CNewsWatcher::CNewsWatcher(int stop_loss,int take_profit,double lot_size, string csv_file)
  {
   m_brain=new CBrain(stop_loss,take_profit,lot_size,csv_file);
   m_evolution=new CEvolution(DO_NOTHING);
   m_techIndicators=new CTechIndicators;
   m_trade=new CTrade();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CNewsWatcher::~CNewsWatcher(void)
  {
   Deinit();
  }
//+------------------------------------------------------------------+
//| GetBrain                                                         |
//+------------------------------------------------------------------+
CBrain *CNewsWatcher::GetBrain(void)
  {
   return m_brain;
  }
//+------------------------------------------------------------------+
//| GetEvolution                                                     |
//+------------------------------------------------------------------+
CEvolution *CNewsWatcher::GetEvolution(void)
  {
   return m_evolution;
  }
//+------------------------------------------------------------------+
//| GetTechIndicators                                                |
//+------------------------------------------------------------------+
CTechIndicators *CNewsWatcher::GetTechIndicators(void)
  {
   return m_techIndicators;
  }  
//+------------------------------------------------------------------+
//| GetTrade                                                         |
//+------------------------------------------------------------------+
CTrade *CNewsWatcher::GetTrade(void)
  {
   return m_trade;
  }
//+------------------------------------------------------------------+
//| GetPositionInfo                                                  |
//+------------------------------------------------------------------+
CPositionInfo *CNewsWatcher::GetPositionInfo(void)
  {
   return m_positionInfo;
  }
//+------------------------------------------------------------------------+
//| CNewsWatcher OnTick                                                    |
//| Checks momentum's turbulences around the time of the news release      |
//+------------------------------------------------------------------------+
void CNewsWatcher::OnTick(double ask,double bid)
  {
//--- are there some news to process?  
   if(GetBrain().GetNewsContainer().GetCurrentIndex() < GetBrain().GetNewsContainer().GetTotal())
   {     
      double momentumBuffer[];
      
      GetTechIndicators().GetMomentum().GetBuffer(momentumBuffer, 2);
      
      //--- Number of seconds before the news releases. GMT +- timeWindow is the real time from which the robot starts 
      //--- listening to the market. For instance, if there is a news release programmed at 13:00 GMT you can set TimeWindow 
      //--- to 900 seconds so that the EA starts listening to the market fifteen minutes before that news release. 
      int timeWindow=600;
      
      CNew *currentNew = GetBrain().GetNewsContainer().GetCurrentNew();      
      int indexCurrentNew = GetBrain().GetNewsContainer().GetCurrentIndex();
            
      if(TimeGMT() >= currentNew.GetTimeRelease() + timeWindow)
      {
         GetBrain().GetNewsContainer().SetCurrentIndex(indexCurrentNew+1);
         return;
      }
      
      //--- is there any open position?
      if(!m_positionInfo.Select(_Symbol))
      {
         //--- if there is no open position, we try to open one
         bool timeHasCome = TimeGMT() >= currentNew.GetTimeRelease() - timeWindow && TimeGMT() <= currentNew.GetTimeRelease() + timeWindow;
             
         if(timeHasCome && momentumBuffer[0] > 100.10)
         {
            GetEvolution().SetStatus(SELL);
            GetBrain().GetNewsContainer().SetCurrentIndex(indexCurrentNew+1);
         }
         else if(timeHasCome && momentumBuffer[0] < 99.90)
         {
            GetEvolution().SetStatus(BUY);
            GetBrain().GetNewsContainer().SetCurrentIndex(indexCurrentNew+1);
         }
      }
      //--- if there is an open position, we let it work the mathematical expectation
      else 
      {
         GetEvolution().SetStatus(DO_NOTHING);         
      }  
      
      double tp;
      double sl; 

      switch(GetEvolution().GetStatus())
      {      
         case BUY:
            tp = ask + m_brain.GetTakeProfit() * _Point;
            sl = bid - m_brain.GetStopLoss() * _Point;
            GetTrade().PositionOpen(_Symbol,ORDER_TYPE_BUY,m_brain.GetSize(),ask,sl,tp);
            break;

         case SELL:
            sl = ask + m_brain.GetStopLoss() * _Point;
            tp = bid - m_brain.GetTakeProfit() * _Point;
            GetTrade().PositionOpen(_Symbol,ORDER_TYPE_SELL,m_brain.GetSize(),bid,sl,tp);
            break;

         case DO_NOTHING:
            // Nothing...
            break;
      }
   }   
//--- we exit when all the container's news have been processed
   else return;
  }
//+------------------------------------------------------------------+
//| CNewsWatcher initialization                                      |
//+------------------------------------------------------------------+
bool CNewsWatcher::Init(void)
  {
// Initialization logic here...
   return true;
  }
//+------------------------------------------------------------------+
//| CNewsWatcher deinitialization                                    |
//+------------------------------------------------------------------+
void CNewsWatcher::Deinit(void)
  {
   delete(m_brain);
   delete(m_evolution);
   delete(m_techIndicators);
   delete(m_trade);
   Print("CNewsWatcher deinitialization performed!");
   Print("Thank you for using this EA.");
  }
//+------------------------------------------------------------------+

Por enquanto, não se preocupe se você não ver as coisas claramente, é normal. Primeiro, você precisa estudar todas as partes desse consultor especialista para compreender como tudo funciona. Recomendo que você primeiro leia superficialmente esse artigo e então faça uma segunda e uma terceira leituras mais profundas. De qualquer forma, tentarei explicar nesse momento algumas partes chave do CNewsWatcher.

Á parte mais importante do CE é claro o método OnTick onde você verá que CNewsWatcher utiliza um recipiente de notícias OO para funcionar. Essa peça, que pode ser vista como um jornal do mundo real, contém as notícias que o usuário do CE quer negociar. 

Observe que recuperamos o recipiente de notícias assim:

GetBrain().GetNewsContainer();

E recuperamos a notícia atual para ser processada dessa forma:

CNew *currentNew = GetBrain().GetNewsContainer().GetCurrentNew();   

Isso é feito através do CBrain. Lembre-se que o CBrain é um ponto central importante em nosso projeto orientado a objeto contendo aquelas coisas necessárias para que o CE possa funcionar apropriadamente, é como uma memória somente de leitura (ROM).

//+------------------------------------------------------------------+
//|                                                       CBrain.mqh |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+
#include <..\Experts\NewsWatcher\CNewsContainer.mqh>
//+------------------------------------------------------------------+
//| CBrain Class                                                     |
//+------------------------------------------------------------------+
class CBrain
  {
protected:
   double               m_size;                 // The size of the positions
   int                  m_stopLoss;             // Stop loss
   int                  m_takeProfit;           // Take profit
   CNewsContainer       *m_news_container;      // The news container

public:
   //--- Constructor and destructor methods
                        CBrain(int stopLoss,int takeProfit,double size,string csv);
                        ~CBrain(void);
   //--- Getter methods
   double               GetSize(void);
   int                  GetStopLoss(void);
   int                  GetTakeProfit(void);
   CNewsContainer       *GetNewsContainer(void);
   //--- Setter methods
   void                 SetSize(double size);
   void                 SetStopLoss(int stopLoss);
   void                 SetTakeProfit(int takeProfit);
   //--- CBrain specific methods
   bool                 Init();
   void                 Deinit(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CBrain::CBrain(int stopLoss,int takeProfit,double size,string csv)
  {
   m_size=size;
   m_stopLoss=stopLoss;
   m_takeProfit=takeProfit;
   m_news_container=new CNewsContainer(csv);   
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CBrain::~CBrain(void)
  {
   Deinit();
  }
//+------------------------------------------------------------------+
//| GetSize                                                          |
//+------------------------------------------------------------------+
double CBrain::GetSize(void)
  {
   return m_size;
  }
//+------------------------------------------------------------------+
//| GetStopLoss                                                      |
//+------------------------------------------------------------------+
int CBrain::GetStopLoss(void)
  {
   return m_stopLoss;
  }
//+------------------------------------------------------------------+
//| GetTakeProfit                                                    |
//+------------------------------------------------------------------+
int CBrain::GetTakeProfit(void)
  {
   return m_takeProfit;
  }
//+------------------------------------------------------------------+
//| GetNewsContainer                                                 |
//+------------------------------------------------------------------+
CNewsContainer *CBrain::GetNewsContainer(void)
  {
   return m_news_container;
  }
//+------------------------------------------------------------------+
//| SetSize                                                          |
//+------------------------------------------------------------------+
void CBrain::SetSize(double size)
  {
   m_size=size;
  }
//+------------------------------------------------------------------+
//| SetStopLoss                                                      |
//+------------------------------------------------------------------+
void CBrain::SetStopLoss(int stopLoss)
  {
   m_stopLoss=stopLoss;
  }
//+------------------------------------------------------------------+
//| SetTakeProfit                                                    |
//+------------------------------------------------------------------+
void CBrain::SetTakeProfit(int takeProfit)
  {
   m_takeProfit=takeProfit;
  }
//+------------------------------------------------------------------+
//| CBrain initialization                                            |
//+------------------------------------------------------------------+
bool CBrain::Init(void)
  {
// Initialization logic here...
   return true;
  }
//+------------------------------------------------------------------+
//| CBrain deinitialization                                          |
//+------------------------------------------------------------------+
void CBrain::Deinit(void)
  {
   delete(m_news_container);
   Print("CBrain deinitialization performed!");
  }
//+------------------------------------------------------------------+

CNewsWatcher está basicamente lendo as notícias armazenadas uma a uma no recipiente (o jornal). Se naquele momento há uma aceleração forte no preço então ela coloca uma ordem no mercado.

Com relação a compra ou venda de lotes o robô é programado em uma forma reativa. Digamos, quando um movimento ascendente forte acontece, o CE presume que o preço recuará e, portanto, vende. Similarmente, quando há um movimento descendente forte, o robô coloca uma posição de compra no mercado pensando que o preço recuará em breve. Isso pode ser melhorado, claro, nesse artigo não há espaço o suficiente para desenvolver um negociador de notícias automático altamente eficiente, como dito antes, o objetivo é dar a vocês o básico técnico de forma que você continue avançando em seus próprios desenvolvimentos.

Robô no rio Taff

Figura 2. Robô no rio Taff. Imagem distribuída sob licença Creative Commons no Flickr


1,3. Um recipiente orientado a objeto para indicadores técnicos


Mais uma vez, como decidimos abordar nossos aplicativos da perspectiva de conceitos, é interessante programar os nossos próprios empacotadores orientados a objeto para indicadores técnicos aderirem ao novo paradigma. Assim esse pedaço do quebra cabeça se encaixa muito melhor com tudo. Digamos que nessa parte do nosso desenvolvimento aproveitamos pra construir algo como uma estrutura orientada a objeto de forma que possamos trabalhar mais confortavelmente com aquelas coisas do MQL5 não muito orientadas a objeto fora da caixa.

Nesse ponto, é interessante observar que há a biblioteca padrão do MQL5. Essa biblioteca é projetada para facilitar a escrita de programas (indicadores, scripts, especialistas) para usuários finais, fornecendo acesso conveniente a maioria das funções internas do MQL5. De fato, no exercício de hoje vamos utilizar alguma funcionalidade da biblioteca padrão porque, como foi dito, é muito mais confortável do ponto de vista da programação orientada a objeto. Um exemplo claro é o recipiente de notícias que vou explicar um pouco mais tarde, vamos utilizar a classe CArrayObj do MQL5 lá para armazenar na RAM do computador as nossas notícias orientadas a objeto personalizadas do tipo complexo.

Por favor, leia a documentação oficial nomeada Biblioteca padrão para saber mais sobre esse tópico e observe que a biblioteca padrão já vem com algumas classes para trabalhar com indicadores. Esse artigo discute a necessidade de trabalhar com material orientado a objeto através de alguns exemplos simples para propósitos de ensino.

1.3.1. CTechIndicators, o recipiente dos indicadores técnicos


//+------------------------------------------------------------------+
//|                                              CTechIndicators.mqh |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+
#include <..\Experts\NewsWatcher\CMomentum.mqh>
//+------------------------------------------------------------------+
//| CTechIndicators Class                                            |
//+------------------------------------------------------------------+
class CTechIndicators
  {
protected:
   CMomentum               *m_momentum;
                  
public:
   //--- Constructor and destructor methods
                           CTechIndicators(void);
                           ~CTechIndicators(void);
   //--- Getter methods
   CMomentum               *GetMomentum(void);
   //--- CTechIndicators specific methods
   bool                 Init();
   void                 Deinit(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+   
CTechIndicators::CTechIndicators(void)
  {
   m_momentum = new CMomentum; 
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+               
CTechIndicators::~CTechIndicators(void)
  {
   Deinit();
  }
//+------------------------------------------------------------------+
//| GetMomentum                                                      |
//+------------------------------------------------------------------+        
CMomentum* CTechIndicators::GetMomentum(void)
  {
   return m_momentum;
  }
//+------------------------------------------------------------------+
//| CTechIndicators initialization                                   |
//+------------------------------------------------------------------+
bool CTechIndicators::Init(void)
  {
// Initialization logic here...
   return true;
  }
//+------------------------------------------------------------------+
//| CTechIndicators deinitialization                                 |
//+------------------------------------------------------------------+
void CTechIndicators::Deinit(void)
  {
   delete(m_momentum);
   Print("CTechIndicators deinitialization performed!");
  }
//+------------------------------------------------------------------+

1.3.2. CMomentum, um empacotador (wrapper) orientado a objeto para iMomentum

//+------------------------------------------------------------------+
//|                                                    CMomentum.mqh |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| CMomentum Class                                                  |
//+------------------------------------------------------------------+

class CMomentum
  {
protected:   
   int m_handler;
   double m_buffer[];
               
public:
   //--- Constructor and destructor methods
                           CMomentum(void);
                           ~CMomentum(void);
   //--- Getter methods
   int                     GetHandler(void);
   void                    GetBuffer(double &buffer[], int ammount);
   //--- Setter methods
   bool                    SetHandler(string symbol,ENUM_TIMEFRAMES period,int mom_period,ENUM_APPLIED_PRICE mom_applied_price);
   bool                    UpdateBuffer(int ammount);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+   
CMomentum::CMomentum(void)
  {
   ArraySetAsSeries(m_buffer, true);   
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+               
CMomentum::~CMomentum(void)
  {
   IndicatorRelease(m_handler);
   ArrayFree(m_buffer);
  }
//+------------------------------------------------------------------+
//| GetHandler                                                       |
//+------------------------------------------------------------------+        
int CMomentum::GetHandler(void)
  {
   return m_handler;
  }
//+------------------------------------------------------------------+
//| GetBuffer                                                        |
//+------------------------------------------------------------------+
void CMomentum::GetBuffer(double &buffer[], int ammount)
  {
   ArrayCopy(buffer, m_buffer, 0, 0, ammount);
  }
//+------------------------------------------------------------------+
//| SetHandler                                                       |
//+------------------------------------------------------------------+      
bool CMomentum::SetHandler(string symbol,ENUM_TIMEFRAMES period,int mom_period,ENUM_APPLIED_PRICE mom_applied_price)
  {   
   if((m_handler=iMomentum(symbol,period,mom_period,mom_applied_price))==INVALID_HANDLE)
   {
      printf("Error creating Momentum indicator");
      return false;
   }
   return true;
  }
//+------------------------------------------------------------------+
//| UpdateBuffer                                                     |
//+------------------------------------------------------------------+   
bool CMomentum::UpdateBuffer(int ammount)
  {   
   if(CopyBuffer(m_handler, 0, 0, ammount, m_buffer) < 0)
   { 
      Alert("Error copying Momentum buffers, error: " , GetLastError());
      return false;
   }
   return true;
  }
//+------------------------------------------------------------------+


1.4. Um recipiente orientado a objeto para as notícias

As notícias em abstrato são uma peça fundamental com o qual o nosso CE tem que lidar. Podemos pensar nessa peça chave como se fosse um jornal de forma a concluir que é uma boa ideia encapsular ele em um recipiente orientado a objeto de notícias. De forma simples, esse recipiente orientado a objeto, chamado CNewsContainer, é o jornal. E claro, se podemos imaginar um jornal com notícias também devemos modelar o conceito de notícias que no nosso domínio de coisas é chamado CNew. Esse é o nosso tipo orientado a objeto personalizado representando as notícias do mundo real.

1.4.1. CNewsContainer, o recipiente de notícias

//+------------------------------------------------------------------+
//|                                               CNewsContainer.mqh |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+
#include <Files\FileTxt.mqh>
#include <Arrays\ArrayObj.mqh>
#include <..\Experts\NewsWatcher\CNew.mqh>
//+------------------------------------------------------------------+
//| CNewsContainer Class                                             |
//+------------------------------------------------------------------+
class CNewsContainer
  {
protected:
   string               m_csv;                  // The name of the csv file
   CFileTxt             m_fileTxt;              // MQL5 file functionality
   int                  m_currentIndex;         // The index of the next news to be processed in the container
   int                  m_total;                // The total number of news to be processed
   CArrayObj            *m_news;                // News list in the computer's memory, loaded from the csv file

public:
   //--- Constructor and destructor methods
                        CNewsContainer(string csv);
                        ~CNewsContainer(void);
   //--- Getter methods
   int                  GetCurrentIndex(void);
   int                  GetTotal(void);
   CNew                 *GetCurrentNew();
   CArrayObj            *GetNews(void);
   //--- Setter methods
   void                 SetCurrentIndex(int index);
   void                 SetTotal(int total);
   void                 SetNews(void);
   //--- CNewsContainer methods
   bool                 Init();
   void                 Deinit(void);
  };
//+------------------------------------------------------------------+
//| Constuctor                                                       |
//+------------------------------------------------------------------+
CNewsContainer::CNewsContainer(string csv)
  {
   m_csv=csv;
   m_news=new CArrayObj;
   SetNews();
   }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CNewsContainer::~CNewsContainer(void)
  {
   Deinit();
  }
//+------------------------------------------------------------------+
//| GetCurrentIndex                                                  |
//+------------------------------------------------------------------+
int CNewsContainer::GetCurrentIndex(void)
  {   
   return m_currentIndex;
  }
//+------------------------------------------------------------------+
//| GetTotal                                                         |
//+------------------------------------------------------------------+
int CNewsContainer::GetTotal(void)
  {   
   return m_total;
  }
//+------------------------------------------------------------------+
//| GetNews                                                          |
//+------------------------------------------------------------------+
CArrayObj *CNewsContainer::GetNews(void)
  {   
   return m_news;
  }
//+------------------------------------------------------------------+
//| GetCurrentNew                                                    |
//+------------------------------------------------------------------+
CNew *CNewsContainer::GetCurrentNew(void)
  {   
   return m_news.At(m_currentIndex);
  }
//+------------------------------------------------------------------+
//| SetCurrentIndex                                                  |
//+------------------------------------------------------------------+
void CNewsContainer::SetCurrentIndex(int index)
  {
   m_currentIndex=index;
  }
//+------------------------------------------------------------------+
//| SetTotal                                                         |
//+------------------------------------------------------------------+
void CNewsContainer::SetTotal(int total)
  {
   m_total=total;
  }
//+------------------------------------------------------------------+
//| SetNews                                                          |
//+------------------------------------------------------------------+
void CNewsContainer::SetNews(void)
  {
   //--- let's first init some vars!
   SetCurrentIndex(0);
   string sep= ";";
   ushort u_sep;
   string substrings[];   
   u_sep=StringGetCharacter(sep,0);   
   //--- then open and process the CSV file
   int file_handle=m_fileTxt.Open(m_csv, FILE_READ|FILE_CSV);
   if(file_handle!=INVALID_HANDLE)
   {
      while(!FileIsEnding(file_handle))
      {               
         string line = FileReadString(file_handle);         
         int k = StringSplit(line,u_sep,substrings);         
         CNew *current = new CNew(substrings[0],(datetime)substrings[1],substrings[2]);         
         m_news.Add(current);
      }
      FileClose(file_handle);
      //--- and finally refine and count the news
      m_news.Delete(0); // --- here we delete the CSV's header!
      SetTotal(m_news.Total());
   }
   else
   {
      Print("Failed to open the file ",m_csv);
      Print("Error code ",GetLastError());
   }   
  }
//+------------------------------------------------------------------+
//| CNewsContainer initialization                                    |
//+------------------------------------------------------------------+
bool CNewsContainer::Init(void)
  {
// Initialization logic here...
   return true;
  }
//+------------------------------------------------------------------+
//| CNewsContainer deinitialization                                  |
//+------------------------------------------------------------------+
void CNewsContainer::Deinit(void)
  {
   m_news.DeleteRange(0, m_total-1);
   delete(m_news);
   Print("CNewsContainer deinitialization performed!");
  }
//+------------------------------------------------------------------+

SetNews é o método mais importante para CNewsContainer. Esse método lê o arquivo CSV e carrega ele na RAM do computador na forma de objetos do tipo CNew. A propósito, eu ainda não disse, os arquivos CVS devem ser armazenados em data_folder\MQL5\FILES\. Por favor leia as Funções dos arquivos para uma compreensão mais profunda das funções utilizadas em SetNews.

1.4.2. CNew, as notícias em si


//+------------------------------------------------------------------+
//|                                                         CNew.mqh |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+
#include <Object.mqh>
//+------------------------------------------------------------------+
//| CNew Class                                                       |
//+------------------------------------------------------------------+
class CNew : public CObject
  {
protected:
   string            m_country;           // The country's name
   datetime          m_time_release;      // The date and time of the news
   string            m_name;              // The name of the news
   
public:
   //--- Constructor and destructor methods
                     CNew(string country,datetime time_release,string name);
                    ~CNew(void);
   //--- Getter methods
   string            GetCountry(void);
   datetime          GetTimeRelease(void);
   string            GetName(void);
   //--- Setter methods
   void              SetCountry(string country);
   void              SetTimeRelease(datetime time_release);
   void              SetName(string name);
   //--- CNew specific methods
   bool              Init();
   void              Deinit(void);
  };
//+------------------------------------------------------------------+
//| Constuctor                                                       |
//+------------------------------------------------------------------+
CNew::CNew(string country,datetime time_release,string name)
  {
   m_country=country;
   m_time_release=time_release;
   m_name=name;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CNew::~CNew(void)
  {
   Deinit();
  }
//+------------------------------------------------------------------+
//| GetCountry                                                       |
//+------------------------------------------------------------------+
string CNew::GetCountry(void)
  {
   return m_country;
  }  
//+------------------------------------------------------------------+
//| GetTimeRelease                                                   |
//+------------------------------------------------------------------+
datetime CNew::GetTimeRelease(void)
  {
   return m_time_release;
  }
//+------------------------------------------------------------------+
//| GetName                                                          |
//+------------------------------------------------------------------+
string CNew::GetName(void)
  {
   return m_name;
  }
//+------------------------------------------------------------------+
//| SetCountry                                                       |
//+------------------------------------------------------------------+
void CNew::SetCountry(string country)
  {
   m_country=country;
  }
//+------------------------------------------------------------------+
//| SetTimeRelease                                                   |
//+------------------------------------------------------------------+
void CNew::SetTimeRelease(datetime timeRelease)
  {
   m_time_release=timeRelease;
  }
//+------------------------------------------------------------------+
//| SetName                                                          |
//+------------------------------------------------------------------+
void CNew::SetName(string name)
  {
   m_name=name;
  }
//+------------------------------------------------------------------+
//| CNew initialization                                              |
//+------------------------------------------------------------------+
bool CNew::Init(void)
  {
//--- initialization logic here...
   return true;
  }
//+------------------------------------------------------------------+
//| CNew deinitialization                                            |
//+------------------------------------------------------------------+
void CNew::Deinit(void)
  {
//--- deinitialization logic here...
   Print("CNew deinitialization performed!");
  }
//+------------------------------------------------------------------+


2. Teste retrospectivo de ExpertNewsWatcher.mq5


2,1. Anexos

ExpertNewsWatcher é composto dos seguintes arquivos:

  • Enums.mqh
  • CBrain.mqh
  • CEvolution.mqh
  • CMomentum.mqh
  • CNew.mqh
  • CNewsContainer.mqh
  • CNewsWatcher.mqh
  • CTechIndicators.mqh
  • ExpertNewsWatcher.mq5
  • news_watcher.txt

2,2. Instruções de instalação

Primeiramente, você precisa criar a pasta MQL5\Include\Mine para armazenar as suas coisas personalizadas, então por favor copie o arquivo Enums.mqh nela. Logo após isso, você precisa criar a pasta MQL5\Experts\NewsWatcher e copiar os arquivos abaixo:

  • CBrain.mqh
  • CEvolution.mqh
  • CMomentum.mqh
  • CNew.mqh
  • CNewsContainer.mqh
  • CNewsWatcher.mqh
  • CTechIndicators.mqh
  • ExpertNewsWatcher.mq5

Observação muito importante! Finalmente, por favor pegue news_watcher.txt, renomeie ele para news_watcher.csv e o coloque em data_folder\MQL5\FILES\. No momento da publicação desse documento, o formulário de submissão do MQL5 não permite enviar arquivos .csv, mas permite enviar arquivos .txt.

Não esqueça de compilar. A partir desse ponto, você pode fazer um teste retrospectivo de ExpertNewsWatcher como você faria com qualquer outro consultor especialista.


2,3. Resultados do teste retrospectivo

ExpertNewsWatcher foi executado com esses parâmetros de entrada iniciais.

  • Período = 1 minuto
  • StopLoss = 400
  • TakeProfit = 600
  • Tamanho do lote = 0.01
  • Arquivo Csv = news_watcher.csv

Inicialmente utilizei os seguintes dados fantasmas contendo um conjunto de notícias fictícias espaçadas no tempo para ver como o robô se comportava em um ambiente controlado. O motivo é porque estes períodos satisfazem as pré-condições estabelecidas, isto é, nas horas que o momento (Momentum) é grande o suficiente para acionar as ações de compra ou venda. Você pode pegar essa folha de entradas para testar qualquer coisa que você considerar.

Alguns dados fantasmas para armazenar em news_watcher.csv:

Country;Time;Event
USD;2013.06.03 17:19:00;A. Momentum equals 100.47
USD;2013.06.13 17:09:00;B. Momentum equals 100.40
USD;2013.06.21 18:52:00;C. Momentum equals 100.19
USD;2013.07.01 17:32:00;D. Momentum equals 100.18 
USD;2013.07.08 15:17:00;E. Momentum equals 100.18
USD;2013.07.16 10:00:00;F. Momentum equals 99.81
USD;2013.07.24 09:30:00;G. Momentum equals 100.25


Resultados obtido com dados fantasmas

Figura 3. Resultados obtido com dados fantasmas

O gráfico acima contendo notícias fictícias ajudará você a entender como esse robô pode se comportar no ambiente real. Por favor pegue os seguintes dados reais tomados do DailyFX, coloque-os em news_watcher.csv e execute ExpertNewsWatcher novamente.

Alguns dados reais para armazenar em news_watcher.csv:

Country;Time;Event
USD;2013.07.15 12:00:00;USD Fed's Tarullo Speaks on Banking Regulation in Washington 
USD;2013.07.15 12:30:00;USD Advance Retail Sales (JUN) and others
USD;2013.07.15 14:00:00;USD USD Business Inventories (MAY)
USD;2013.07.15 21:00:00;USD EIA Gasoline and Diesel Fuel Update
USD;2013.07.16 12:30:00;USD Several Consumer Price Indexes 
USD;2013.07.16 13:00:00;USD USD Net Long-term TIC Flows (MAY) & USD Total Net TIC Flows (MAY)
USD;2013.07.16 13:15:00;USD Industrial Production (JUN) and others
USD;2013.07.16 14:00:00;USD NAHB Housing Market Index (JUL)
USD;2013.07.16 18:15:00;USD Fed's George Speaks on Economic Conditions and Agriculture
USD;2013.07.22 12:30:00;USD Chicago Fed Nat Activity Index (JUN)
USD;2013.07.22 14:00:00;USD Existing Home Sales (MoM) (JUN) & Existing Home Sales (JUN)
USD;2013.07.22 21:00:00;USD EIA Gasoline and Diesel Fuel Update
USD;2013.07.23 13:00:00;USD House Price Index (MoM) (MAY)
USD;2013.07.23 14:00:00;USD Richmond Fed Manufacturing Index (JUL)
USD;2013.07.24 11:00:00;USD MBA Mortgage Applications (JUL 19)
USD;2013.07.24 12:58:00;USD Markit US PMI Preliminary (JUL)
USD;2013.07.24 14:00:00;USD USD New Home Sales (MoM) (JUN) & USD New Home Sales (JUN)
USD;2013.07.24 14:30:00;USD USD DOE U.S. Crude Oil Inventories (JUL 19) and others



Resultados obtido com dados reais

Figura 4. Resultados obtido com dados reais

Esse simples processador de notícias pode apenas responder a uma única notícia que acontece em um certo tempo. É por essa razão que um tempo específico, por exemplo, 2013.07.15 12:30:00, pode conter diversas notícias. Se diversas notícias importantes estiverem acontecendo em um dado tempo, por favor escreva uma única entrada no arquivo CSV.

Com isso dito, observe que o CE apenas coloca três operações no mercado quando trabalhando com dados reais. Isso é porque na vida real algumas notícias irão se sobrepor, ao contrário do conjunto anterior de notícias fictícias espaçado no tempo. Nosso robô é programado para primeiro fechar a primeira operação que veio da série, ignorando uma notícia que chega quando já existe uma posição em aberto.

       double momentumBuffer[];
      
      GetTechIndicators().GetMomentum().GetBuffer(momentumBuffer, 2);
      
      //--- Number of seconds before the news releases. GMT +- timeWindow is the real time from which the robot starts 
      //--- listening to the market. For instance, if there is a news release programmed at 13:00 GMT you can set TimeWindow 
      //--- to 900 seconds so that the EA starts listening to the market fifteen minutes before that news release. 
      int timeWindow=600;
      
      CNew *currentNew = GetBrain().GetNewsContainer().GetCurrentNew();      
      int indexCurrentNew = GetBrain().GetNewsContainer().GetCurrentIndex();
            
      if(TimeGMT() >= currentNew.GetTimeRelease() + timeWindow)
      {
         GetBrain().GetNewsContainer().SetCurrentIndex(indexCurrentNew+1);
         return;
      }
      
      //--- is there any open position?
      if(!m_positionInfo.Select(_Symbol))
      {
         //--- if there is no open position, we try to open one
         bool timeHasCome = TimeGMT() >= currentNew.GetTimeRelease() - timeWindow && TimeGMT() <= currentNew.GetTimeRelease() + timeWindow;
             
         if(timeHasCome && momentumBuffer[0] > 100.10)
         {
            GetEvolution().SetStatus(SELL);
            GetBrain().GetNewsContainer().SetCurrentIndex(indexCurrentNew+1);
         }
         else if(timeHasCome && momentumBuffer[0] < 99.90)
         {
            GetEvolution().SetStatus(BUY);
            GetBrain().GetNewsContainer().SetCurrentIndex(indexCurrentNew+1);
         }
      }
      //--- if there is an open position, we let it work the mathematical expectation
      else 
      {
         GetEvolution().SetStatus(DO_NOTHING);         
      }  


Conclusão

Isso foi a continuação do artigo Outra classe orientada a objeto do MQL5, que mostrou a você como construir um CE orientado a objeto simples do inicio e deu a você algumas dicas sobre programação orientada a objeto. Seguindo a mesma linha, esse texto forneceu a você as ferramentas necessárias para ajudar você a construir seus próprios negociantes de notícias. Cobrimos a implementação de recipientes orientados a objeto e empacotadores orientados a objeto de forma a trabalharmos confortavelmente com nossos projetos orientados a objeto. Também discutimos a biblioteca padrão do MQL5 e as funções do MQL5 para trabalhar com o sistema de arquivos.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/719

Arquivos anexados |
cbrain__2.mqh (4.82 KB)
cevolution__2.mqh (2.07 KB)
cmomentum.mqh (3.35 KB)
cnew.mqh (4.32 KB)
enums__2.mqh (0.92 KB)
news_watcher.txt (1.27 KB)
cnewscontainer.mqh (5.95 KB)
cnewswatcher.mqh (7.61 KB)
Assistente MQL5: Como ensinar um EA a abrir ordens pendentes a qualquer preço Assistente MQL5: Como ensinar um EA a abrir ordens pendentes a qualquer preço
O artigo descreve um método de modificação do código de um módulo do sinal de negociação para implementação da funcionalidade que permite que você configure ordens pendentes a qualquer distância do preço atual: podendo ser preço de abertura ou fechamento da barra anterior ou do valor da média móvel. Há uma enorme quantidade de opções. O importante é que você possa definir qualquer preço de abertura para uma ordem pendente. Esse artigo será útil para negociadores que negociam com ordens pendentes.
Criando EAs de rede neural usando o assistente do MQL5 e o gerador EA Hlaiman Criando EAs de rede neural usando o assistente do MQL5 e o gerador EA Hlaiman
O artigo descreve um método de criação automatizada de EAs de rede neural usando o assistente do MQL5 e o gerador EA Hlaiman. Ele mostra como você pode facilmente começar a trabalhar com redes neurais, sem ter que aprender todo o corpo de informações teóricas, e escrever o seu próprio código.
Surpreenda seus clientes MQL5 com um coquetel prático de tecnologias! Surpreenda seus clientes MQL5 com um coquetel prático de tecnologias!
O MQL5 fornece programadores com um conjunto muito completo de funções e IPA baseado em objetos graças aos quais eles podem fazer tudo o que quiserem dentro do ambiente MetaTrader. No entanto, Tecnologia Web é uma ferramenta extremamente versátil hoje em dia que pode vir para o resgate em algumas situações quando você precisa fazer algo muito específico, seja para surpreender seus clientes com algo diferente ou simplesmente por você não ter tempo suficiente para dominar uma parte específica da Biblioteca Padrão MT5. O exercício de hoje o leva através de um exemplo prático de como você pode gerenciar a duração de desenvolvimento, ao mesmo tempo que você também cria um coquetel tecnológico incrível.
Outra classe OOP do MQL5 Outra classe OOP do MQL5
Este artigo mostra como construir um Expert Advisor orientado a objeto desde o começo, desde conceber a ideia da negociação teórica até a programação de um MQL EA que torne esta ideia real no mundo empírico. Aprender fazendo é, na minha opinião, uma abordagem sólida para o sucesso, então, mostro em um exemplo prático para que você veja como pode organizar suas ideias para finalmente codificar seus robôs Forex. Meu objetivo é convidá-lo a aderir aos princípios de OO.