자동 뉴스 거래자 구축
소개
Investopedia에 따르면 뉴스 거래자는 "뉴스 발표에 따라 거래 또는 투자 결정을 내리는 거래자 또는 투자자"입니다. 실제로 한 국가의 GDP, 소비자 신뢰 지수 및 국가의 고용 데이터와 같은 경제 보고서는 종종 통화 시장에서 상당한 움직임을 생성합니다. 미국에 가본 적이 있습니까? 비농업 급여 발표? 그렇다면 이러한 보고서가 통화의 최근 미래를 결정하고 추세 반전의 촉매 역할을 할 수 있음을 이미 알고 있습니다.
그림 1. B&W 신문. Flickr의 Creative Commons License에 따라 배포된 이미지
1. EA를 프로그래밍해봅시다
1.1. 거래 시스템의 아이디어
이 시스템의 이면에 있는 아이디어는 위에서 논의한 것입니다. 이것은 훌륭하게 들리지만 프로그래밍 세계에서 입증된 사실을 어떻게 구현할 수 있습니까? 주로 우리는 두 가지 MQL5 측면에 의존하고 있습니다. 한편으로는 모멘텀 지표를 사용하여 통화 쌍에서 주어진 뉴스 세트의 영향을 측정합니다. 반면에 MQL5 파일 기능을 사용하여 즐겨찾는 뉴스 캘린더를 파일 시스템에 저장합니다. 선택한 파일 형식은 CSV입니다. 물론 또 다른 MQL5 OOP 클래스에서 논의된 개념적 접근을 사용하여 객체 지향 패러다임에서 이 로봇을 프로그래밍할 것입니다. 우리의 객체 지향 설계는 CSV를 컴퓨터 메모리에 로드하여 EA가 이러한 정보를 기반으로 결정을 내릴 수 있도록 합니다.
1.2. 로봇의 OOP 스켈레톤
이제부터 우리는 EA를 마치 살아있는 생물처럼 개념의 관점에서 생각하고 있습니다. 우리는 이제 OOP 직원이 되었습니다. 기억하십니까? 이 비전 덕분에 우리는 두뇌, 진화라고 부르는 것, 지표 세트 및 뉴스 세트와 같은 여러 부분에 대한 Expert Advisor를 구성할 수 있습니다. 저는 이 모든 것을 아래에서 명확히 할 것입니다.
//+---------------------------------------------------------------------+ //| ExpertNewsWatcher.mq5 | //| Copyright © 2013, laplacianlab, Jordi Bassagañas | //+---------------------------------------------------------------------+ #property copyright "Copyright © 2013, laplacianlab. Jordi Bassagañas" #property link "https://www.mql5.com/ko/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."); } //+------------------------------------------------------------------+
지금은 상황이 매우 명확하지 않은 경우 걱정하지 마십시오. 정상입니다. 먼저 모든 것이 어떻게 작동하는지 이해하려면 이 Expert Advisor의 모든 부분을 연구해야 합니다. 먼저 이 글을 피상적으로 읽은 다음 두 번째 및 세 번째 더 깊이 읽을 것을 권장합니다. 여하튼 이 시간에 CNewsWatcher의 몇 가지 핵심 부분을 설명하려고 합니다.
EA의 가장 중요한 부분은 물론 CNewsWatcher가 OO 뉴스 컨테이너를 사용하여 작동하는 것을 볼 수 있는 OnTick 방법입니다. 현실의 신문이라고 볼 수 있는 이 글에는 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의 Creative Commons License에 따라 배포된 이미지
다시 한 번, 개념의 관점에서 앱을 다루기로 결정했기 때문에 기술 지표에 대한 자체 객체 지향 래퍼를 프로그래밍하여 새로운 패러다임을 고수하는 것이 흥미로웠습니다. 따라서 이 퍼즐 조각은 모든 것에 훨씬 더 잘 맞습니다. 개발의 이 부분에서 객체 지향 프레임워크와 같은 것을 구축하는 이점을 활용하여 즉시 사용 가능하지 않은 MQL5 항목으로 보다 편안하게 작업할 수 있다고 가정해보겠습니다.
이 시점에서 MQL5 표준 라이브러리가 있다는 점에 주목할 필요가 있습니다. 이 라이브러리는 최종 사용자가 프로그램(지표, 스크립트, Expert)을 쉽게 작성할 수 있도록 설계되어 대부분의 MQL5 내부 기능에 편리하게 액세스할 수 있습니다. 사실, 오늘의 연습에서 우리는 말했듯이 OO 프로그래밍의 관점에서 훨씬 더 편안하기 때문에 일부 표준 라이브러리의 기능을 사용하고 있습니다. 명확한 예는 나중에 설명할 뉴스 컨테이너입니다. 여기서 MQL5 클래스 CArrayObj 를 사용하여 컴퓨터의 RAM에 복잡한 유형의 사용자 정의 객체 지향 뉴스를 저장합니다.
이 주제에 대해 자세히 알아보려면 표준 라이브러리라는 제목의 공식 문서를 살펴보고 표준 라이브러리에는 이미 지표 작업을 위한 일부 클래스가 포함되어 있습니다. 이 글에서는 교육 목적을 위한 몇 가지 간단한 예를 통해 객체 지향 자료로 작업해야 할 필요성에 대해 설명합니다.
//+------------------------------------------------------------------+ //| 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. iMomentum용 객체 지향 래퍼 CMomentum
//+------------------------------------------------------------------+ //| 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라는 이름의 이 OO 컨테이너는 신문입니다. 물론 뉴스가 있는 신문을 상상할 수 있다면 우리의 영역에서 CNew라는 이름의 뉴스 개념도 모델링해야 합니다. 이것은 실제 세계의 뉴스를 나타내는 우리의 사용자 정의 객체 지향 유형입니다.
1.4.1. CNewsContainer, 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 파일 전송은 허용합니다.
컴파일하는 것을 잊지 마십시오. 이 시점부터 다른 Expert Advisor와 마찬가지로 ExpertNewsWatcher를 백테스트할 수 있습니다.
2.3. 백테스트 결과
ExpertNewsWatcher는 이러한 초기 입력 매개변수로 실행되었습니다.
- 기간 = 1분
- 손절매 = 400
- 이익실현 = 600
- 랏 크기 = 0.01
- CSV 파일 = 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.07.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); }
결론
이것은 처음부터 간단한 OO EA를 구축하는 방법을 보여주고 객체 지향 프로그래밍에 대한 몇 가지 팁을 제공한 또 다른 MQL5 OOP 클래스 글의 연속이었습니다. 같은 줄을 따라 이 텍스트는 자신의 뉴스 거래자를 구축하는 데 도움이 되는 필요한 도구를 제공했습니다. OO 디자인으로 편안하게 작업할 수 있도록 객체 지향 컨테이너와 객체 지향 래퍼의 구현을 다루었습니다. 또한 파일 시스템과 함께 작동하는 MQL5 표준 라이브러리 및 MQL5 기능에 대해서도 논의했습니다.
MetaQuotes 소프트웨어 사를 통해 영어가 번역됨
원본 기고글: https://www.mql5.com/en/articles/719