
建立自动新闻交易程序
简介
如 Investopedia(投资百科)所述,新闻交易者是“依据新闻进行交易或投资决定的交易者或投资者”。事实上,经济报告,例如一个国家的 GDP、消费者信心指数、就业数据等,经常造成货币市场的大幅波动。您曾经出席过美国非农数据发布会吗?如果出席过,您已经知道这些报告可能决定货币的近期走势并且是趋势反转的催化剂。
图 1. 黑白报纸。依据知识共享许可在 Flickr 上发布的图像
1. 让我们编写我们的 EA
1.1. 交易系统的理念
此系统后面的理念是我们在前面已经讨论过的。这听起来不错,但是我们如何在编程世界中实施这个已经得到证明的事实呢?我们主要依靠 MQL5 的两个方面。一方面,我们使用动量指标来衡量给定的新闻对货币对的影响。另一方面,我们使用 MQL5 文件功能,在文件系统中存储我们喜欢的新闻日历。选定的文件格式为 CSV。当然,我们依据面向对象编程范例来对这个自动交易进行编程,并采用在 Another MQL5 OOP class(另一个 MQL5 OOP 类)一文中讨论的概念性方法。我们的面向对象设计会将 CSV 载入计算机的内存,从而让 EA 能够依据此类信息做出决定。
1.2. 自动交易的 OOP 框架
从现在起,我们从概念开始构思我们的 EA,如同它们是活的生物一样。现在,我们是 OOP 人了,您还记得吗?感谢这一愿景,我们可以将 EA 分为几个部分,例如大脑,我们称为进化的东西,一组指标及一组新闻。我们将在下面对这些进行一一解释。
//+---------------------------------------------------------------------+ //| 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 是 EA 的主类。我们来看看代码。
//+---------------------------------------------------------------------+ //| 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."); } //+------------------------------------------------------------------+
现在,如果您没有将事情看清楚,不要担心,这是正常的。首先,您必须研究这个 EA 的所有部分以理解所有一切是如何运行的。我建议您首先浏览一下本文,然后再进行第二次和第三次更加深入的阅读。无论如何,这次我都将尝试解释 CNewsWatcher 的某些关键部分。
EA 最重要的部分当然是方法 OnTick,在其中,您将看到 CNewsWatcher 使用一个面向对象的新闻容器来工作。这个组件可以看作是现实世界的报纸,包含 EA 用户要依据其进行交易的新闻。
注意,我们按以下方式获取新闻容器:
GetBrain().GetNewsContainer();
并且我们按以下方式获取要处理的当前新闻:
CNew *currentNew = GetBrain().GetNewsContainer().GetCurrentNew();
这通过 CBrain 来完成。记住,在我们的面向对象设计中,CBrain 是一个重要的中心点,包含 EA 能够正确运行所需的东西,它如同只读存储器 (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 基本上逐个读取存储在容器(报纸)中的新闻。如果此时价格有强加速,则在市场中下单。
就手数的买入或卖出而言,是以一种反应性方式进行自动交易编程的。比方说,当出现强势上扬时,EA 假定价格将反抽,因此要卖出。类似的,当出现强势下行时,考虑到价格将在短期内反抽,自动交易在市场中下买入持仓订单。当然,这是可以改进的,在本文中没有足够的空间来开发一个非常高效的自动新闻交易程序,如前文所述,目标是向您提供技术基础,让您能够继续改进您自己的开发。
图 2. Taff 上的自动交易.依据知识共享许可在 Flickr 上发布的图像
再一次指出,因为我们已经决定从概念的观点解决我们的应用,所以有兴趣对我们自己的面向对象的技术指标包装器进行编程以遵循新的范例。因此,这部分的难题更适合所有情况。比方说,在这部分的开发中,我们利用建立某样东西(例如一个面向对象的框架的优势),从而让我们能够更加舒适地处理 MQL5 资料,而不是现成的特别 OO。
此时,注意存在一个 MQL5 标准库,这很有趣。这个库设计用于加快最终用户编写程序(指标、脚本、 EA 交易程序)的速度,让他们能够方便地使用 MQL5 的大多数内部函数。事实上,在今天的练习中,我将使用标准库的某些功能,因为如前所述,从面向对象的编程角度而言,这更加舒适。我将在后面解释的新闻容器就是一个明显的例子;我将在其中使用 MQL5 类 CArrayObj ,在计算机的 RAM 中存储定制的面向对象的复杂类型新闻。
请参考名为“标准库”的官方说明文档,以更加详细地了解这个主题,并注意,标准库已经含有某些用于处理指标的类。本文通过几个简单的例子,从教学角度讨论了处理面向对象的资料的需要。
1.3.1. CTechIndicators,技术指标的容器//+------------------------------------------------------------------+ //| 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,一个面向对象的 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. 一个面向对象的新闻容器
抽象而言,新闻是我们的EA必须处理的基础部分。在这个关键部分中,我们可以将其视为一张报纸,从而得出这样的结论:将其封装在一个面向对象的新闻容器中是一个好的想法。简而言之,这个面向对象的容器,名为 CNewsContainer,是一张报纸。当然,如果我们能够想象一张含有新闻的报纸,我们也必须对新闻概念建立模型,在我们的例子中称为 CNew。这是我们表示现实世界的新闻的面向对象的自定义类型。
1.4.1. CNewsContainer,新闻的容器
//+------------------------------------------------------------------+ //| 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 是 CNewsContainer 的最重要的方法。此方法读取 CSV 文件并以对象类型 CNew 的形式将其加载到计算机的 RAM。顺便说一句,CSV 文件必须存储在 data_folder\MQL5\FILES\ 中。请看一看文件函数以更加深入地理解在 SetNews 中使用的函数。
1.4.2. CNew,新闻本身
//+------------------------------------------------------------------+ //| 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. 回测 ExpertNewsWatcher.mq5
2.1. 附件
ExpertNewsWatcher 由以下文件组成:
- Enums.mqh
- CBrain.mqh
- CEvolution.mqh
- CMomentum.mqh
- CNew.mqh
- CNewsContainer.mqh
- CNewsWatcher.mqh
- CTechIndicators.mqh
- ExpertNewsWatcher.mq5
- news_watcher.txt
2.2. 安装说明
首先,您必须创建 MQL5\Include\Mine 文件夹以存储您的自定义资料,然后,请将文件 Enums.mqh 复制到其中。之后,必须创建 MQL5\Experts\NewsWatcher 文件夹并复制以下文件:
- CBrain.mqh
- CEvolution.mqh
- CMomentum.mqh
- CNew.mqh
- CNewsContainer.mqh
- CNewsWatcher.mqh
- CTechIndicators.mqh
- ExpertNewsWatcher.mq5
非常重要的事项! 最后,请将 news_watcher.txt 重命名为 news_watcher.csv,然后将其放在 data_folder\MQL5\FILES\ 中。在发表本文的时候,MQL5 表单提交不允许发送 .csv 文件,但允许发送 .txt 文件。
不要忘记编译。此时,您可以回测 ExpertNewsWatcher,如您对其它 EA 做的一样。
2.3. 回测结果
用以下初始输入参数运行 ExpertNewsWatcher。
- Period = 1 Minute
- StopLoss = 400
- TakeProfit = 600
- LotSize = 0.01
- CsvFile = news_watcher.csv
我最初使用以下包含一组在时间上有间隔的假想新闻的伪数据来查看自动交易在受控环境中的行为。这是因为这些周期满足已经确定的先决条件,即在这些时间动量足够大,能够触发买入或卖出操作。您可以用这些数据测试您的案例。
要存储在 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
图 3. 用伪数据得到的结果
包含假想新闻的上图将帮助您理解这个自动交易在现实环境中的行为。请使用来自 DailyFX 的以下现实数据,将其放在 news_watcher.csv 中并再次运行 ExpertNewsWatcher。
要存储在 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
图 4. 用现实数据得到的结果
这个简单的新闻处理程序只能响应在某个时间发生的一条新闻。正是这个原因,某个时间,例如 2013 年 7 月 15 日 12:30:00,可能发生几条新闻。如果几条重要的新闻碰巧在指定时间发生,请在 CSV 文件中各自单独写一个条目。
即观察到:EA 在处理现实数据时仅在市场中进行三个操作。这是因为在现实生活中,某些新闻将会重叠,与前一组在时间上有间隔的假想新闻不同。我们的自动交易设计为首先关闭序列中的每一个操作,在已经有未平仓位时忽略即将到来的新闻。
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); }
总结
这是 "Another MQL5 OOP"(另一个 MQL5 OOP 类)一文的续篇,该文向您展示了如何从头建立一个简单的面向对象的 EA 交易程序并向您提供了有关面向对象编程的某些提示。在同一行的后面,文字向您提供了必要的工具来帮助您建立您自己的新闻交易程序。我们已经介绍了面向对象的容器和面向对象的包装器的实施,让我们能够舒服地处理我们的面向对象设计。我们还讨论了 MQL5 标准库和用于处理文件系统的 MQL5 函数。
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/719
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.




很高兴能为我们提供必要的工具,帮助我们建立自己的新闻交易员。谢谢
亲爱的 Jordi、
您的文章很精彩,但在附加 EA 时,我看到了这样的情况(在下面的文件附件中)。
这是怎么回事?出了什么问题?
感谢您的创新分享。
你好. 请问mt4的话. 新闻操作有什么方法?