![Costruire un trader automatico di notizie](https://c.mql5.com/i/articles/overlay.png)
Costruire un trader automatico di notizie
Introduzione
Come afferma Investopedia, un trader di notizie è "un trader o un investitore che prende decisioni di trading o di investimento basate su annunci di notizie". In effetti, i rapporti economici come il PIL di un paese, gli indici di fiducia dei consumatori e i dati sull'occupazione dei paesi, tra gli altri, spesso producono movimenti significativi nei mercati valutari. Hai mai frequentato un U.S. Rilascio di non farm payrolls? In tal caso, sai già che questi rapporti possono determinare il futuro recente delle valute e fungere da catalizzatori per le inversioni di tendenza.
Figura 1. Quotidiani B/N Immagine distribuita sotto licenza Creative Commons su Flickr
1. Programmiamo il nostro EA
1.1. L'idea del sistema di trading
L'idea alla base di questo sistema è quella di cui abbiamo discusso sopra. Sembra fantastico, ma come possiamo implementare questo fatto comprovato nel mondo della programmazione? Principalmente ci affidiamo a due aspetti MQL5. Da un lato, stiamo usando l'indicatore Momentum per misurare l'impatto del dato insieme di notizie in una coppia di valute. D'altra parte, lavoreremo con le funzioni di file MQL5 per memorizzare il nostro calendario di notizie preferito nel filesystem. Il formato di file scelto è CSV. Programeremo questo robot sotto il paradigma orientato agli oggetti, ovviamente, con l'approccio concettuale discusso in Un'altra classe OOP MQL5. Il nostro design orientato agli oggetti caricherà il CSV nella memoria del computer in modo che l'EA possa prendere decisioni basate su tali informazioni.
1.2. Lo scheletro OOP del robot
D'ora in poi stiamo concependo i nostri EA come concetti, come se fossero creature viventi. Ora siamo persone OOP, ti ricordi? Grazie a questa visione possiamo comporre il nostro Expert Advisor di diverse parti come un cervello, qualcosa che chiamiamo evoluzione, un insieme di indicatori e una serie di notizie. Chiarirò tutto questo di seguito.
//+---------------------------------------------------------------------+ //| ExpertNewsWatcher.mq5 | //| Copyright © 2013, laplacianlab, Jordi Bassagañas | //+---------------------------------------------------------------------+ #property copyright "Copyright © 2013, laplacianlab. Jordi Bassagañas" #property link "https://www.mql5.com/it/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 è la classe principale di EA. Diamo un'occhiata al codice.
//+---------------------------------------------------------------------+ //| 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."); } //+------------------------------------------------------------------+
Per ora, non preoccuparti se non vedi le cose molto chiaramente, è normale. Innanzitutto, devi studiare tutte le parti di questo Expert Advisor per capire come funziona tutto. Ti consiglio di leggere prima superficialmente questo articolo e poi fare una seconda e una terza lettura più approfondita. Ad ogni modo, cercherò di spiegare in questo momento alcune parti chiave di CNewsWatcher.
La parte più importante dell'EA è ovviamente il metodo OnTick in cui vedrai che CNewsWatcher utilizza un contenitore di notizie OO per funzionare. Questo pezzo, che può essere visto come un giornale del mondo reale, contiene le notizie che l'utente EA vuole scambiare.
Si noti che recuperiamo il contenitore di notizie in questo modo:
GetBrain().GetNewsContainer();
E recuperiamo le notizie attuali da elaborare in questo modo:
CNew *currentNew = GetBrain().GetNewsContainer().GetCurrentNew();
Questo viene fatto tramite CBrain. Ricorda che CBrain è un importante punto centrale nel nostro design orientato agli oggetti contenente quelle cose necessarie affinché l'EA possa funzionare correttamente, è qualcosa come una memoria di sola lettura (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 sta fondamentalmente leggendo una per una le notizie memorizzate nel contenitore (il giornale). Se in quel momento c'è una forte accelerazione nel prezzo, allora inserisce un ordine sul mercato.
Per quanto riguarda l'acquisto o la vendita di lotti il robot è programmato in modo reattivo. Diciamo, quando si verifica un forte movimento al rialzo, l'EA presume che il prezzo si ritirerà e quindi vende. Allo stesso modo, quando c'è un forte movimento verso il basso, il robot posiziona una posizione lunga sul mercato pensando che il prezzo tornerà in breve. Questo può essere migliorato, ovviamente, in questo articolo non c'è spazio sufficiente per sviluppare un trader di notizie automatiche altamente efficiente, come detto prima, l'obiettivo è darti le basi tecniche per continuare a progredire nei tuoi sviluppi.
Figura 2. Robot sul Taff. Immagine distribuita sotto licenza Creative Commons su Flickr
Ancora una volta, poiché abbiamo deciso di affrontare le nostre app dal punto di vista dei concetti, è interessante programmare i nostri wrapper orientati agli oggetti per indicatori tecnici per aderire al nuovo paradigma. Quindi questo pezzo del puzzle si adatta molto meglio a tutto. Diciamo che in questa parte del nostro sviluppo approfittiamo per costruire qualcosa come un framework orientato agli oggetti in modo da poter lavorare più comodamente con quella roba MQL5 non molto OO fuori dalla scatola.
A questo punto, è interessante notare che esiste il MQL5 Standard Library. Questa libreria è progettata per facilitare la scrittura di programmi (indicatori, script, esperti) agli utenti finali, fornendo un comodo accesso alla maggior parte delle funzioni interne di MQL5. In effetti, nell'esercizio di oggi stiamo usando alcune funzionalità di Standard Library perché, come è stato detto, è molto più comodo dal punto di vista della programmazione OO. Un chiaro esempio è il contenitore di notizie che spiegherò un po 'più tardi, useremo la classe MQL5 CArrayObj lì per memorizzare nella RAM del computer le nostre notizie personalizzate orientate agli oggetti di tipo complesso.
Per favore, dai un'occhiata alla documentazione ufficiale intitolata Libreria standard per saperne di più su questo argomento e nota che la Libreria standard viene già fornita con alcune classi per lavorare con gli indicatori. Questo articolo discute la necessità di lavorare con materiale orientato agli oggetti attraverso alcuni semplici esempi per scopi didattici.
//+------------------------------------------------------------------+ //| 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, un involucro orientato agli oggetti per 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. Un contenitore orientato agli oggetti per le notizie
La notizia in abstract è un tassello fondamentale con cui la nostra EA deve fare i conti. Possiamo pensare in questo pezzo chiave come se fosse un giornale per concludere che è una buona idea incapsularlo in un contenitore di notizie orientato agli oggetti. In parole povere, questo contenitore OO, chiamato CNewsContainer, è il giornale. E naturalmente se possiamo immaginare un giornale con notizie dobbiamo anche modellare il concetto di notizia che nel nostro dominio delle cose si chiama CNew. Questo è il nostro tipo personalizzato orientato agli oggetti che rappresenta le notizie del mondo reale.
1.4.1. CNewsContainer, il contenitore delle notizie
//+------------------------------------------------------------------+ //| 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 è il metodo più importante di CNewsContainer. Questo metodo legge il file CSV e lo carica nella RAM del computer sotto forma di oggetti di tipo CNew. A proposito, non ho ancora detto, i file CSV devono essere memorizzati in data_folder \ MQL5 \ FILES \. Si prega di dare un'occhiata a Funzioni file per una comprensione più approfondita delle funzioni utilizzate in SetNews.
1.4.2. CNew, le notizie stesse
//+------------------------------------------------------------------+ //| 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. Backtesting ExpertNewsWatcher.mq5
2.1. Allegati
ExpertNewsWatcher è composto dai seguenti file:
- Enums.mqh
- CBrain.mqh
- CEvolution.mqh
- CMomentum.mqh
- CNew.mqh
- CNewsContainer.mqh
- CNewsWatcher.mqh
- CTechIndicators.mqh
- ExpertNewsWatcher.mq5
- news_watcher.txt
2.2. Istruzioni per l'installazione
Prima di tutto, devi creare la cartella MQL5 \ Include \ Mine per archiviare le tue cose personalizzate, quindi copia il file Enums.mqh lì. Subito dopo, è necessario creare la cartella MQL5\Experts\NewsWatcher e copiare i file seguenti:
- CBrain.mqh
- CEvolution.mqh
- CMomentum.mqh
- CNew.mqh
- CNewsContainer.mqh
- CNewsWatcher.mqh
- CTechIndicators.mqh
- ExpertNewsWatcher.mq5
Nota molto importante! Infine, prendi ,news_watcher.txt,news_watcher.txt, rinominalo in news_watcher.csv e inseriscilo in data_folder \ MQL5 \ FILES \. Al momento della pubblicazione di questo documento, l'invio del modulo MQL5 non consente l'invio di file .csv, ma consente l'invio di file .txt.
Non dimenticare di compilare. Da questo punto, puoi eseguire il backtest di ExpertNewsWatcher come faresti con qualsiasi altro Expert Advisor.
2.3. Risultati del test
ExpertNewsWatcher è stato eseguito con questi parametri di input iniziali.
- Periodo = 1 minuto
- StopLoss = 400
- TakeProfit = 600
- Dimensione del lotto = 0,01
- CsvFile = news_watcher.csv
Inizialmente ho usato i seguenti dati fittizi contenenti una serie di notizie fittizie distanziate nel tempo per vedere come si comportava il robot in un ambiente controllato. Questo perché quei periodi soddisfano le precondizioni stabilite, cioè in quei momenti lo slancio è abbastanza grande da innescare le azioni di acquisto o vendita. Puoi prendere questo foglio di voci per testare qualsiasi cosa tu consideri.
Alcuni dati fittizi da memorizzare in 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
Figura 3. Risultati ottenuti con dati fittizi
Il grafico sopra contenente notizie fittizie ti aiuterà a capire come questo robot potrebbe comportarsi in un ambiente reale. Si prega di prendere i seguenti dati reali presi da DailyFX, inserirli in news_watcher.csv ed eseguire nuovamente ExpertNewsWatcher.
Alcuni dati reali da memorizzare in 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
Figura 4. Risultati ottenuti con dati reali
Questo semplice elaboratore di notizie può rispondere solo a una singola notizia che si svolge in un determinato tempo. È per questo motivo che un orario specifico, ad esempio 2013.07.15 12:30:00, può contenere diverse notizie. Se si verificano diverse notizie importanti in un dato momento, si prega di scrivere una singola voce nel file CSV.
Detto questo, osserva che l'EA mette solo tre operazioni sul mercato quando lavora con dati reali. Questo perché nella vita reale alcune notizie si sovrapporranno, a differenza della precedente serie di notizie fittizie distanziate nel tempo. Il nostro robot ha in programma di chiudere prima la prima operazione che proveniva dalla serie, ignorando una notizia in arrivo quando c'è già una posizione aperta.
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); }
Conclusione
Questa è stata la continuazione di un altro articolo sulla classe OOP MQL5, che ha mostrato come costruire un semplice EA OO da zero e ti ha dato alcuni suggerimenti sulla programmazione orientata agli oggetti. Seguendo la stessa linea, questo testo ti ha fornito gli strumenti necessari per aiutarti a costruire i tuoi trader di notizie. Abbiamo coperto l'implementazione di contenitori orientati agli oggetti e involucri orientati agli oggetti per poter lavorare comodamente con i nostri progetti OO. Abbiamo anche discusso mqL5 Standard Library e mql5 funzioni per lavorare con il file system.
Tradotto dall’inglese da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/en/articles/719
![MQL5 Wizard: Come insegnare a un EA ad aprire ordini pendenti a qualsiasi prezzo](https://c.mql5.com/2/0/Pending_Orders_Trading_MQ5_Wizard_signals.png)
![Creazione di EA di reti neurali utilizzando MQL5 Wizard e Hlaiman EA Generator](https://c.mql5.com/2/0/HLAIMAN.png)
![Stupisci i tuoi clienti MQL5 con un cocktail di tecnologie!](https://c.mql5.com/2/0/cocktails.png)
![Un'altra classe OOP MQL5](https://c.mql5.com/2/0/hand.png)
![MQL5 - Linguaggio delle strategie di trading integrato nel client terminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso