Negociação de Notícias Simplificada (Parte 1): Criando um Banco de Dados
Introdução
Neste artigo, aprenderemos a criar um banco de dados no qual armazenaremos dados do Calendário Econômico do MQL5. Esses dados podem ser usados posteriormente, em artigos futuros, para negociar com base nas notícias. Também exploraremos como executar consultas SQL básicas para recuperar certas informações organizadas desse banco de dados. Todo o processo será realizado no IDE do MQL5.
Os traders mantêm um olhar atento nas fontes de notícias em busca de informações que possam impactar os mercados. Isso inclui eventos geopolíticos, anúncios de lucros corporativos, eventos políticos e relatórios econômicos como crescimento do PIB ou dados de emprego. Os traders agem rapidamente para responder a lançamentos de notícias significativas, buscando lucrar com as mudanças resultantes no mercado. Dependendo de como a notícia é interpretada, pode ser necessário comprar ou vender ativos. Neste artigo, focaremos em eventos econômicos, pois eles estão prontamente disponíveis para nós através do Calendário Econômico do MQL5.
Por Que Criar um Banco de Dados
Um banco de dados é uma coleção estruturada de dados que é armazenada e acessada eletronicamente. Os bancos de dados podem gerenciar e armazenar eficientemente grandes quantidades de dados, permitindo várias atividades, como análise de dados, armazenamento e gestão. No MQL5, trabalhamos com bancos de dados SQLite que são criados e gerenciados pelo motor de banco de dados SQLite. Os bancos de dados SQLite podem ter qualquer extensão de arquivo, mas geralmente são arquivos de disco único com extensões .sqlite, .sqlite3 ou .db. Esses arquivos contêm todos os dados e estruturas presentes nos bancos de dados, incluindo tabelas, gatilhos, índices e outros metadados.
Os bancos de dados são perfeitos para lidar com grandes conjuntos de dados e simplificam o processo de recuperação de dados de uma data ou evento específico, sem a necessidade de loops complexos. Além disso, o calendário econômico do MQL5 é inacessível no testador de estratégias. Então, se você quiser testar sua estratégia com base em notícias, como faria isso?
A resposta é usar um banco de dados. Para mais informações sobre bancos de dados, confira esses slides da palestra e, de preferência, este artigo MQL5. Além disso, adicionarei um excelente tutorial de SQLite.
Moedas no Calendário Econômico do MQL5
No | Símbolo | Nome |
---|---|---|
1. | NZD | Dólar Neozelandês |
2. | EUR | Euro |
3. | JPY | Iene Japonês |
4. | CAD | Dólar Canadense |
5. | AUD | Dólar Australiano |
6. | CNY | Yuan Chinês |
7. | SGD | Dólar de Singapura |
8. | BRL | Real Brasileiro |
9. | MXN | Peso Mexicano |
10. | ZAR | Rand Sul-Africano |
11. | HKD | Dólar de Hong Kong |
12. | INR | Rúpia Indiana |
13. | NOK | Coroa Norueguesa |
14. | USD | Dólar dos Estados Unidos |
15. | GBP | Libra Esterlina |
16. | CHF | Franco Suíço |
17. | KRW | Won Sul-Coreano |
18. | SEK | Coroa Sueca |
A tabela acima não está em nenhuma ordem específica.
Existem várias moedas disponíveis no calendário do MQL5, mas algumas delas não são comumente usadas por corretores ou facilmente acessíveis para traders. Por exemplo, o Real Brasileiro e o Won Sul-Coreano não estão amplamente disponíveis. Mesmo que você consiga encontrar um corretor que trabalhe com essas moedas exóticas, os spreads geralmente são desfavoráveis para negociação. Eu falo por experiência própria.
Criando o Banco de Dados
Antes de criarmos o banco de dados, precisamos primeiro considerar o horário de verão e por que isso afetaria nossos testes retrospectivos.Horário de Verão (DST) é a prática de adiantar o relógio em uma hora durante os meses mais quentes do ano, tipicamente da primavera ao outono, para melhor aproveitamento da luz do dia e economia de energia.
Em áreas onde o horário de verão é observado, a hora local pode mudar em uma hora durante os períodos de transição da primavera e do outono. Isso pode ter um impacto nos horários de abertura e fechamento dos mercados financeiros. Por exemplo, se o horário de verão começar e os relógios forem adiantados em uma hora, o mercado pode abrir mais cedo no horário local. Em contrapartida, quando o horário de verão termina e os relógios são atrasados em uma hora (horário normal), o horário de abertura do mercado pode parecer mais tarde no horário local. Também devemos reconhecer que diferentes regiões do mundo podem ter seu próprio horário de verão para se adaptar às suas estações.
Por exemplo, os EUA têm seu próprio horário de verão que normalmente começa no segundo domingo de março de cada ano e termina no primeiro domingo de novembro do mesmo ano. Os países europeus também são conhecidos por terem seu próprio horário de verão que normalmente começa no último domingo de março de cada ano e termina no último domingo de outubro do mesmo ano. A Austrália é outro país conhecido por praticar o horário de verão, cujo cronograma geralmente começa no primeiro domingo de outubro e termina no primeiro domingo de abril do ano seguinte.
Para levar em conta os ajustes do horário de verão, algumas bolsas e mercados financeiros podem modificar seus horários de negociação ou fuso horário. As bolsas podem divulgar horários de negociação revisados para contabilizar as mudanças de horário locais ou ajustar seu fuso horário de acordo com o cronograma do horário de verão que praticam, garantindo uniformidade e clareza para os participantes do mercado.
Pelo que observei, se um corretor, por exemplo, adotar o horário de verão dos EUA, o fuso horário antes do horário de verão seria GMT+2, e quando o horário de verão dos EUA começar, o fuso horário mudará para GMT+3. Você não perceberá a diferença de horário entre os lançamentos de notícias dos EUA no horário do servidor do corretor antes ou durante o horário de verão dos EUA, pois estarão sincronizados. Então, um exemplo que usaremos é o evento NFP dos EUA (Non-Farm Payrolls) para ilustrar; vamos supor que o NFP seja divulgado às 14h no horário do servidor do corretor antes do horário de verão dos EUA, o horário permanecerá o mesmo às 14h durante o horário de verão dos EUA, embora o fuso horário tenha mudado para GMT+3.
Por outro lado, se o comunicado de emprego do Reino Unido for às 8h antes do horário de verão do Reino Unido e dos EUA, quando o corretor mudar o fuso horário ao iniciar o horário de verão dos EUA, e o comunicado de emprego do Reino Unido ocorrer antes de o horário de verão do Reino Unido (UE) começar, o comunicado de emprego do Reino Unido seria às 7h no horário do corretor. Quando o horário de verão do Reino Unido começar e coincidir com o horário de verão dos EUA, o comunicado de emprego do Reino Unido voltará para as 8h.
Eu sei que tudo isso é muito confuso, mas, felizmente, implementaremos isso em nosso banco de dados para que tenhamos datas precisas de quando os eventos ocorrem para testes retrospectivos mais tarde. Precisaremos determinar se o corretor usa o horário de verão dos EUA, o horário de verão do Reino Unido (UE), o horário de verão da Austrália ou se não usa horário de verão algum. Também criaremos tabelas de calendário econômico para cada tipo de horário de verão, para que possamos alterar qual cronograma utilizar nos testes retrospectivos para fins educativos.
Implementação
Teremos três Classes de Horário de Verão:
- DaylightSavings_AU
- DaylightSavings_UK
- DaylightSavings_US
class CDaylightSavings_AU:CObject { private: CTimeManagement Time; CDaylightSavings_AU(datetime startdate,datetime enddate); CObject *List() { return savings;}//Gets the list of Daylight savings time datetime StartDate; datetime EndDate; CArrayObj *savings; CArrayObj *getSavings; CDaylightSavings_AU *dayLight; public: CDaylightSavings_AU(void); ~CDaylightSavings_AU(void); bool isDaylightSavings(datetime Date);//This function checks if a given date falls within Daylight Savings Time. bool DaylightSavings(int Year,datetime &startDate,datetime &endDate);//Check if Daylight Savings Dates are available for a certain Year void adjustDaylightSavings(datetime EventDate,string &AdjustedDate);//Will adjust the date's time zone depending on Daylight Savings };
Vamos criar uma classe chamada:
CDaylightSavings_AU
que herda de
CObject
Esta classe consistirá em criar uma lista que armazenará todas as datas de horário de verão a partir de 2007, pois esta é a data mais antiga armazenada no calendário econômico do MQL5.
CDaylightSavings_AU::CDaylightSavings_AU(void) { savings = new CArrayObj(); //Daylight savings dates to readjust dates in the database for accurate testing in the strategy tester savings.Add(new CDaylightSavings_AU(D'2006.10.29 03:00:00',D'2007.03.25 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2007.10.28 03:00:00',D'2008.04.06 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2008.10.05 03:00:00',D'2009.04.05 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2009.10.04 03:00:00',D'2010.04.04 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2010.10.03 03:00:00',D'2011.04.03 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2011.10.02 03:00:00',D'2012.04.01 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2012.10.07 03:00:00',D'2013.04.07 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2013.10.06 03:00:00',D'2014.04.06 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2014.10.05 03:00:00',D'2015.04.05 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2015.10.04 03:00:00',D'2016.04.03 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2016.10.02 03:00:00',D'2017.04.02 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2017.10.01 03:00:00',D'2018.04.01 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2018.10.07 03:00:00',D'2019.04.07 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2019.10.06 03:00:00',D'2020.04.05 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2020.10.04 03:00:00',D'2021.04.04 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2021.10.03 03:00:00',D'2022.04.03 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2022.10.02 03:00:00',D'2023.04.02 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2023.10.01 03:00:00',D'2024.04.07 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2024.10.06 03:00:00',D'2025.04.06 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2025.10.05 03:00:00',D'2026.04.05 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2026.10.04 03:00:00',D'2027.04.04 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2027.10.03 03:00:00',D'2028.04.02 02:00:00')); savings.Add(new CDaylightSavings_AU(D'2028.10.01 03:00:00',D'2029.04.01 02:00:00')); }
Em seguida, usaremos a função booleana
bool isDaylightSavings(datetime Date);//Esta função verifica se uma data específica cai dentro do horário de verão.
Para determinar se um parâmetro de data está dentro das datas de horário de verão.
bool CDaylightSavings_AU::isDaylightSavings(datetime Date) { // Initialize a list to store daylight savings periods. getSavings = List(); // Iterate through all the periods in the list. for(int i=0; i<getSavings.Total(); i++) { // Access the current daylight savings period. dayLight = getSavings.At(i); // Check if the given date is within the current daylight savings period. if(Time.DateIsInRange(dayLight.StartDate,dayLight.EndDate,Date)) { // If yes, return true indicating it is daylight savings time. return true; } } // If no period matches, return false indicating it is not daylight savings time. return false; }
Também utilizaremos outra função booleana.
bool DaylightSavings(int Year,datetime &startDate,datetime &endDate);//Adjusts time when it is daylight savings an hour behind if outside
Para determinar se o ano está dentro da lista de datas de horário de verão que inicializamos anteriormente, então adicionaremos a data de início e a data de término às variáveis startDate e endDate.
bool CDaylightSavings_US::DaylightSavings(int Year,datetime &startDate,datetime &endDate) { // Initialize a list to store daylight savings periods. getSavings = List(); bool startDateDetected=false,endDateDetected=false; // Iterate through all the periods in the list. for(int i=0; i<getSavings.Total(); i++) { dayLight = getSavings.At(i); if(Year==Time.ReturnYear(dayLight.StartDate))//Check if a certain year's date is available within the Daylight Savings start dates in the List { startDate = dayLight.StartDate; startDateDetected = true; } if(Year==Time.ReturnYear(dayLight.EndDate))//Check if a certain year's date is available within the Daylight Savings end dates in the List { endDate = dayLight.EndDate; endDateDetected = true; } if(startDateDetected&&endDateDetected)//Check if both Daylight Savings start and end dates are found for a certain Year { return true; } } startDate = D'1970.01.01 00:00:00';//Set a default start date if no Daylight Saving date is found endDate = D'1970.01.01 00:00:00';//Set a default end date if no Daylight Saving date is found return false; }
Nossa função pública final nesta classe
void adjustDaylightSavings(datetime EventDate,string &AdjustedDate);//Will adjust the date's time -zone depending on Daylight Savings
Modificará uma variável string AdjustedDate por referência com a EventDate.
void CDaylightSavings_AU::adjustDaylightSavings(datetime EventDate,string &AdjustedDate) { if(isDaylightSavings(TimeTradeServer()))//Check if the current trade server time is already within the Daylight Savings Period { if(isDaylightSavings(EventDate))//Checks if the event time is during daylight savings { AdjustedDate = TimeToString(EventDate);//storing normal event time } else { AdjustedDate = TimeToString((datetime)(EventDate-Time.HoursS()));//storing event time and removing an hour for DST } } else { if(isDaylightSavings(EventDate))//Checks if the event time is during daylight savings { AdjustedDate = TimeToString((datetime)(Time.HoursS()+EventDate));//storing event time and adding an hour for DST } else { AdjustedDate = TimeToString(EventDate);//storing normal event time } } }
Agora passaremos para nosso próximo arquivo de cabeçalho neste projeto, dedicado a manipulações de tempo.
CTimeManagement
que é uma classe no mesmo projeto.
class CTimeManagement { private: MqlDateTime today;//private variable MqlDateTime timeFormat;//private variable public: bool DateIsInRange(datetime FirstTime,datetime SecondTime,datetime compareTime);//Checks if a date is within two other dates bool DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd);//Check if two dates(Start&End) are within CompareStart & CompareEnd bool DateisToday(datetime TimeRepresented);//Checks if a date is within the current day int SecondsS(int multiple=1);//Returns seconds int MinutesS(int multiple=1);//Returns Minutes in seconds int HoursS(int multiple=1);//Returns Hours in seconds int DaysS(int multiple=1);//Returns Days in seconds int WeeksS(int multiple=1);//Returns Weeks in seconds int MonthsS(int multiple=1);//Returns Months in seconds int YearsS(int multiple=1);//Returns Years in seconds int ReturnYear(datetime time);//Returns the Year for a specific date datetime TimeMinusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an subtraction offset in seconds datetime TimePlusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an addition offset in seconds };
A função chamada anteriormente
Time.DateIsInRange(dayLight.StartDate,dayLight.EndDate,Date)
é uma função simples que verifica se uma única data está entre duas outras datas.
bool CTimeManagement::DateIsInRange(datetime FirstTime,datetime SecondTime,datetime compareTime) { if(FirstTime<=compareTime&&SecondTime>compareTime) { return true; } return false; }
O mesmo nome de função com parâmetros diferentes
bool DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd);
também é simples; essa função verificará se duas datas estão entre outras duas datas.
bool CTimeManagement::DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd) { if(Start<=CompareStart&&CompareEnd<End) { return true; } return false; }
Precisaremos de uma função para saber se uma determinada data é hoje, por isso declarei
bool DateisToday(datetime TimeRepresented);//Checks if a date is within the current day
que comparará o ano, mês e dia da hora atual com o 'TimeRepresented' datetime.
bool CTimeManagement::DateisToday(datetime TimeRepresented) { MqlDateTime TiM; TimeToStruct(TimeRepresented,TiM); TimeCurrent(today); if(TiM.year==today.year&&TiM.mon==today.mon&&TiM.day==today.day) { return true; } return false; }
Para obter um datetime com um deslocamento, temos duas funções.
datetime TimeMinusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an subtraction offset in seconds
e
datetime TimePlusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an addition offset in seconds
Quando queremos obter uma data com um deslocamento negativo de uma hora (ou qualquer unidade de tempo), usaremos
datetime CTimeManagement::TimeMinusOffset(datetime standardtime,int timeoffset) { standardtime-=timeoffset; return standardtime; }
Por outro lado, se quisermos uma data com um deslocamento positivo, usaremos
datetime CTimeManagement::TimePlusOffset(datetime standardtime,int timeoffset) { standardtime+=timeoffset; return standardtime; }
Decidi criar um arquivo de inclusão que armazenará variáveis globais e estruturas, bem como tipos enum para serem usados em diferentes classes e no expert no futuro.
Esse arquivo de inclusão é chamado CommonVariables e armazenará variáveis comuns.
string broker=AccountInfoString(ACCOUNT_COMPANY);//Getting brokers name via AccountInfoString int Str = StringReplace(broker," ","");//Removing or replacing any spaces in the broker's name with an empty string int Str1 = StringReplace(broker,".","");//Removing or replacing any dots in the broker's name with an empty string int Str2 = StringReplace(broker,",","");//Removing or replacing any commas in the broker's name with an empty string #define BROKER_NAME broker//Broker's Name #define NEWS_TRADING_FOLDER "NewsTrading"//Name of main folder in common/files #define NEWS_CALENDAR_FOLDER StringFormat("%s\\NewsCalendar",NEWS_TRADING_FOLDER)//name of subfolder in NewsTrading #define NEWS_CALENDAR_BROKER_FOLDER StringFormat("%s\\%s",NEWS_CALENDAR_FOLDER,BROKER_NAME)//Name of subfolder in NewsCalendar #define NEWS_DATABASE_FILE StringFormat("%s\\Calendar.sqlite",NEWS_CALENDAR_BROKER_FOLDER)//Name of sqlite file in subfolder in "Broker's Name" #define NEWS_TEXT_FILE StringFormat("%s\\CalendarOpen.txt",NEWS_CALENDAR_BROKER_FOLDER)//Name of text file to indicate Calendar is open. struct Calendar { ulong EventId;//Event Id string CountryName;//Event Country string EventName;//Event Name string EventType;//Event Type string EventImportance;//Event Importance string EventDate;//Event Date string EventCurrency;//Event Currency string EventCode;//Event Code string EventSector;//Event Sector string EventForecast;//Event Forecast Value string EventPreval;//Event Previous Value string EventImpact;//Event Impact string EventFrequency;//Event Frequency }; enum DST_type { US_DST,//US Daylight Savings UK_DST,//UK(EU) Daylight Savings AU_DST,//AU Daylight Savings DST_NONE//No Daylight Savings Available };
Quando criarmos arquivos na pasta Common Files, gostaria de organizar os arquivos por pastas, para que seja fácil coordenar através da pasta Common Files.
Então, criei uma classe
class CFolders
que criará as pastas na pasta Common Files em sequência: NewsTrading/NewsCalendar/Broker. O construtor da classe realizará essa tarefa.
class CFolders { private: bool CreateFolder(string FolderPath);//Will create a folder with the FolderPath string parameter public: CFolders(void);//Class's constructor };
dentro do construtor
CFolders::CFolders(void) { if(CreateFolder(NEWS_TRADING_FOLDER))//Will create the NewsTrading Folder { if(CreateFolder(NEWS_CALENDAR_FOLDER))//Will create the NewsCalendar Folder { if(!CreateFolder(NEWS_CALENDAR_BROKER_FOLDER))//Will create the Broker Folder { Print("Something went wrong with creating folder: ",NEWS_CALENDAR_BROKER_FOLDER); } } } }
Função sendo chamada no construtor para criar as pastas individuais
bool CFolders::CreateFolder(string FolderPath) { //--- attempt to create a folder relative to the MQL5\Files path if(FolderCreate(FolderPath,FILE_COMMON)) { //--- successful execution return true; } else { PrintFormat("Failed to create the folder %s. Error code %d",FolderPath,GetLastError()); } //--- execution failed return false; }
Os candlesticks são muito importantes; precisaremos reunir informações sobre os preços de High, Low, Open e Close de um candle específico. Para fazer isso, criaremos outra classe para reunir essas informações para nós quando necessário em outros programas do projeto. O nome da classe será
class CCandleProperties
Agora declararemos as funções nesta classe.
class CCandleProperties { private: CTimeManagement Time; public: double Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle OpenPrice double Close(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle ClosePrice double High(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle HighPrice double Low(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle LowPrice bool IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL);//Determine if one candle is larger than two others };
Vamos dar uma olhada rápida em
double Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Open Price
Nesta função, retornaremos o preço de abertura de um candle com base no parâmetro inteiro CandleIndex e no timeframe do candle, bem como no símbolo do candle.
double CCandleProperties::Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL) { return iOpen(((SYMBOL==NULL)?Symbol():SYMBOL),Period,CandleIndex);//return candle open price }
Para verificar se um evento econômico aconteceu em uma data específica, visto que os corretores podem alterar seus fusos horários. Obteremos a data de um evento econômico e, com essa data, analisaremos o candle M15 para esse horário. Em seguida, calcularemos a altura do candle (iHigh-iLow) e compararemos essa altura com o candle M15 uma hora antes do evento e uma hora depois. Como os eventos econômicos normalmente são muito voláteis nos preços do mercado, devemos notar um candle muito longo quando o evento ocorrer. Usaremos o candle M15 para dar ao mercado tempo suficiente para formar esse candle longo. Se o corretor tiver alterado seu fuso horário, a data do evento armazenada no Calendário Econômico MQL5 pode não corresponder à volatilidade do candle na hora específica no candle do corretor, mas essa volatilidade pode estar presente uma hora depois ou uma hora antes da data especificada. A função que usaremos para fazer essa verificação de validação será
bool IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL);//Determine if one candle is larger than two others
Esta função verificará se a altura do candle em uma data específica é maior do que o candle com um deslocamento de tempo antes e depois dessa data especificada.
bool CCandleProperties::IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL) { int CandleIndex = iBarShift(SYMBOL,PERIOD_M15,CandleTime);//Assign candle index of candletime int CandleIndexMinusOffset = iBarShift(SYMBOL,PERIOD_M15,Time.TimeMinusOffset(CandleTime,Offset));//Assign candle index of candletime minus time offset int CandleIndexPlusOffset = iBarShift(SYMBOL,PERIOD_M15,Time.TimePlusOffset(CandleTime,Offset));//Assign candle index of candletime plus time offset double CandleHeight = High(CandleIndex,PERIOD_M15,SYMBOL)-Low(CandleIndex,PERIOD_M15,SYMBOL);//Assign height of M15 candletime in pips double CandleHeightMinusOffset = High(CandleIndexMinusOffset,PERIOD_M15,SYMBOL)-Low(CandleIndexMinusOffset,PERIOD_M15,SYMBOL);//Assign height of M15 candletime minus offset in Pips double CandleHeightPlusOffset = High(CandleIndexPlusOffset,PERIOD_M15,SYMBOL)-Low(CandleIndexPlusOffset,PERIOD_M15,SYMBOL);//Assign height of M15 candletime plus offset in Pips //--Determine if candletime height is greater than candletime height minus offset and candletime height plus offset if(CandleHeight>CandleHeightMinusOffset&&CandleHeight>CandleHeightPlusOffset) { return true;//Candletime is likely when the news event occurred } return false;//Candletime is unlikely when the real news data was released }
Vamos passar para a classe News; essa classe trabalhará diretamente com a obtenção de valores do MQL5 calendário econômico e armazenando
os valores em um banco de dados para teste e, eventualmente, negociação
class CNews { //Private Declarations Only accessible by this class/header file private: CTimeManagement Time;//TimeManagement Object declaration CDaylightSavings_UK Savings_UK;//DaylightSavings Object for the UK and EU CDaylightSavings_US Savings_US;//DaylightSavings Object for the US CDaylightSavings_AU Savings_AU;//DaylightSavings Object for the AU CCandleProperties Candle;//CandleProperties Object string CurrencyBase,CurrencyProfit,EURUSD;//String variables declarations for working with EURUSD bool EurusdIsSelected,EurusdIsFound,is_Custom;//Boolean variables declarations for working with EURUSD bool timeIsShifted;//Boolean variable declaration will be used to determine if the broker changes it's time zone datetime DaylightStart,DaylightEnd;//Datetime variables declarations for start and end dates for Daylight Savings //Structure Declaration for DST struct DST { bool result; datetime date; }; bool AutoDetectDST(DST_type &dstType);//Function will determine Broker DST DST_type DSTType;//variable of DST_type enumeration declared in the CommonVariables class/header file bool InsertIntoTable(int db,DST_type Type,Calendar &Evalues[]);//Function for inserting Economic Data in to a database's table void CreateAutoDST(int db);//Function for creating and inserting Recommend DST for the Broker into a table bool CreateTable(int db,string tableName,bool &tableExists);//Function for creating a table in a database void CreateRecords(int db);//Creates a table to store records of when last the Calendar database was updated/created bool UpdateRecords();//Checks if the main Calendar database needs an update or not void EconomicDetails(Calendar &NewsTime[]);//Gets values from the MQL5 economic Calendar //Public declarations accessable via a class's Object public: ~CNews(void);//Deletes a text file created when the Calendar database is being worked on void CreateEconomicDatabase();//Creates the Calendar database for a specific Broker datetime GetLastestNewsDate();//Gets the latest/newest date in the Calendar database };
Há muito a se entender aqui; primeiro, daremos uma olhada em
bool AutoDetectDST(DST_type &dstType);//Function will determine Broker DST
Pelo nome desta função, seu principal objetivo é obter o cronograma de DST que o corretor utiliza. Vamos recuperar essa informação por meio da enumeração
enum DST_type { US_DST,//US Daylight Savings UK_DST,//UK(EU) Daylight Savings AU_DST,//AU Daylight Savings DST_NONE//No Daylight Savings Available };
passada por referência na função AutoDectectDST; essa função retornará falso se o cronograma de DST do corretor for conhecido ou não puder ser reconhecido.
bool CNews::AutoDetectDST(DST_type &dstType) { MqlCalendarValue values[];//Single array of MqlCalendarValue type string eventtime[];//Single string array variable to store NFP(Nonfarm Payrolls) dates for the 'United States' from the previous year int lastyear = Time.ReturnYear(Time.TimeMinusOffset(iTime(Symbol(),PERIOD_CURRENT,0),Time.YearsS()));//Will store the previous year into an integer datetime lastyearstart = StringToTime(StringFormat("%s.01.01 00:00:00",(string)lastyear));//Will store the start date for the previous year datetime lastyearend = StringToTime(StringFormat("%s.12.31 23:59:59",(string)lastyear));//Will store the end date for the previous year if(CalendarValueHistory(values,lastyearstart,lastyearend,"US"))//Getting last year's calendar values for CountryCode = 'US' { for(int x=0; x<(int)ArraySize(values); x++) { if(values[x].event_id==840030016)//Get only NFP Event Dates { ArrayResize(eventtime,eventtime.Size()+1,eventtime.Size()+2);//Increasing the size of eventtime array by 1 eventtime[eventtime.Size()-1] = TimeToString(values[x].time);//Storing the dates in an array of type string } } } datetime ShiftStart=D'1970.01.01 00:00:00',ShiftEnd=D'1970.01.01 00:00:00';//datetime variables to store the broker's time zone shift(change) DST previousresult,currentresult;//Variables of structure type DST declared at the beginning of the class EURUSD="";//String variable assigned empty string EurusdIsSelected = false;//Boolean variable assigned value false EurusdIsFound = false;//Boolean variable assigned value false for(int i=0;i<SymbolsTotal(true);i++)//Will loop through all the Symbols inside the Market Watch { string SymName = SymbolName(i,true);//Assign the Symbol Name of index 'i' from the list of Symbols inside the Market Watch CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE);//Assign the Symbol's Currency Base CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT);//Assign the Symbol's Currency Profit SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker) //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker) if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom) { EURUSD = SymName;//Assigning the name of the EURUSD Symbol found inside the Market Watch EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker break;//Will end the for loop } } if(!EurusdIsFound)//Check if EURUSD Symbol was already Found in the Market Watch { for(int i=0; i<SymbolsTotal(false); i++)//Will loop through all the available Symbols outside the Market Watch { string SymName = SymbolName(i,false);//Assign the Symbol Name of index 'i' from the list of Symbols outside the Market Watch CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE); CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT); SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker) //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker) if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom) { EurusdIsSelected = SymbolSelect(SymName,true);//Adding the EURUSD Symbol to the Market Watch if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { EURUSD = SymName;//Assigning the name of the EURUSD Symbol found outside the Market Watch EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker break;//Will end the for loop } } } } if(!EurusdIsFound)//Check if EURUSD Symbol was Found in the Trading Terminal for your Broker { Print("Cannot Find EURUSD!"); Print("Cannot Create Database!"); Print("Server DST Cannot be Detected!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } for(uint i=0;i<eventtime.Size();i++) { currentresult.result = Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD);//Store the result of if the event date is the larger candlestick currentresult.date = (datetime)eventtime[i];//Store the eventdate from eventtime[i] timeIsShifted = ((currentresult.result!=previousresult.result&&i>0)?true:false);//Check if there is a difference between the previous result and the current result //--- Print Event Dates and if the event date's candle is larger than the previous candle an hour ago and the next candle an hour ahead Print("Date: ",eventtime[i]," is Larger: ",Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD)," Shifted: ",timeIsShifted); if(timeIsShifted)//Check if the Larger candle has shifted from the previous event date to the current event date in eventtime[i] array { if(ShiftStart==D'1970.01.01 00:00:00')//Check if the ShiftStart variable has not been assigned a relevant value yet { ShiftStart=currentresult.date;//Store the event date for when the time shift began } ShiftEnd=previousresult.date;//Store the event date timeshift } previousresult.result = currentresult.result;//Store the previous result of if the event date is the larger candlestick previousresult.date = currentresult.date;//Store the event date from eventtime[i] } if(ShiftStart==D'1970.01.01 00:00:00'&&eventtime.Size()>0)//Check if the ShiftStart variable has not been assigned a relevant value and the event dates are more than zero { Print("Broker ServerTime unchanged!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } if(Savings_AU.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For AU DST"); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = AU_DST;//Assigning enumeration value AU_DST, Broker has AU DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For AU"); Print("Year: %d Cannot Be Found!",lastyear); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(Savings_UK.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For UK DST"); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = UK_DST;//Assigning enumeration value UK_DST, Broker has UK/EU DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For UK"); Print("Year: %d Cannot Be Found!",lastyear); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(Savings_US.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For US DST"); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = US_DST;//Assigning enumeration value US_DST, Broker has US DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For US"); Print("Year: %d Cannot Be Found!",lastyear); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } Print("Cannot Detect Broker ServerTime Configuration!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found }
Ok, a função acima é longa; vamos dividi-la. Na primeira parte, reuniremos as datas dos eventos econômicos para NFP do ano anterior, então, se o ano atual for 2024, reuniremos todas as datas de 2023, pois precisamos analisar o ano inteiro para obter com sucesso o provável cronograma de DST do corretor. Essas datas serão armazenadas em nossa única matriz de strings eventtime.
MqlCalendarValue values[];//Single array of MqlCalendarValue type string eventtime[];//Single string array variable to store NFP(Nonfarm Payrolls) dates for the 'United States' from the previous year int lastyear = Time.ReturnYear(Time.TimeMinusOffset(iTime(Symbol(),PERIOD_CURRENT,0),Time.YearsS()));//Will store the previous year into an integer datetime lastyearstart = StringToTime(StringFormat("%s.01.01 00:00:00",(string)lastyear));//Will store the start date for the previous year datetime lastyearend = StringToTime(StringFormat("%s.12.31 23:59:59",(string)lastyear));//Will store the end date for the previous year if(CalendarValueHistory(values,lastyearstart,lastyearend,"US"))//Getting last year's calendar values for CountryCode = 'US' { for(int x=0; x<(int)ArraySize(values); x++) { if(values[x].event_id==840030016)//Get only NFP Event Dates { ArrayResize(eventtime,eventtime.Size()+1,eventtime.Size()+2);//Increasing the size of event time array by 1 eventtime[eventtime.Size()-1] = TimeToString(values[x].time);//Storing the dates in an array of type string } } }
Depois, precisaremos usar essas datas no símbolo EURUSD, porque XAUUSD (OURO) e outros índices como US30 (Dow Jones) são muito voláteis, mesmo sem eventos de notícias; EURUSD é mais estável e se torna realmente volátil durante eventos econômicos, o que facilita a detecção de quando um evento econômico ocorreu, pois o mercado provavelmente disparará devido ao evento. Essa também é a razão pela qual nos concentraremos nos eventos de NFP, pois eles regularmente criam esses picos de preços no mercado. Com essa informação, precisaremos do símbolo EURUSD; primeiro, verificaremos todos os símbolos disponíveis no corretor para encontrar o EURUSD e selecioná-lo. Se não encontrarmos o EURUSD, retornaremos falso.
EURUSD="";//String variable assigned empty string EurusdIsSelected = false;//Boolean variable assigned value false EurusdIsFound = false;//Boolean variable assigned value false for(int i=0;i<SymbolsTotal(true);i++)//Will loop through all the Symbols inside the Market Watch { string SymName = SymbolName(i,true);//Assign the Symbol Name of index 'i' from the list of Symbols inside the Market Watch CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE);//Assign the Symbol's Currency Base CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT);//Assign the Symbol's Currency Profit SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker) //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker) if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom) { EURUSD = SymName;//Assigning the name of the EURUSD Symbol found inside the Market Watch EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker break;//Will end the for loop } } if(!EurusdIsFound)//Check if EURUSD Symbol was already Found in the Market Watch { for(int i=0; i<SymbolsTotal(false); i++)//Will loop through all the available Symbols outside the Market Watch { string SymName = SymbolName(i,false);//Assign the Symbol Name of index 'i' from the list of Symbols outside the Market Watch CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE); CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT); SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker) //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker) if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom) { EurusdIsSelected = SymbolSelect(SymName,true);//Adding the EURUSD Symbol to the Market Watch if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { EURUSD = SymName;//Assigning the name of the EURUSD Symbol found outside the Market Watch EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker break;//Will end the for loop } } } } if(!EurusdIsFound)//Check if EURUSD Symbol was Found in the Trading Terminal for your Broker { Print("Cannot Find EURUSD!"); Print("Cannot Create Database!"); Print("Server DST Cannot be Detected!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found }
Depois de encontrar o EURUSD, iteraremos por todas as datas de NFP e encontraremos os candlesticks M15 para cada data individual e compararemos a altura do candle com as datas de deslocamento de uma hora antes e depois do evento para detectar se o evento provavelmente ocorreu. Se as datas do evento não corresponderem à volatilidade nos candlesticks, armazenaremos a primeira data do evento em que essa discrepância ocorrer e quando ela terminar nas variáveis ShiftStart e ShiftEnd.
for(uint i=0;i<eventtime.Size();i++) { currentresult.result = Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD);//Store the result of if the event date is the larger candlestick currentresult.date = (datetime)eventtime[i];//Store the event date from eventtime[i] timeIsShifted = ((currentresult.result!=previousresult.result&&i>0)?true:false);//Check if there is a difference between the previous result and the current result //--- Print Event Dates and if the event date's candle is larger than the previous candle an hour ago and the next candle an hour ahead Print("Date: ",eventtime[i]," is Larger: ",Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD)," Shifted: ",timeIsShifted); if(timeIsShifted)//Check if the Larger candle has shifted from the previous event date to the current event date in eventtime[i] array { if(ShiftStart==D'1970.01.01 00:00:00')//Check if the ShiftStart variable has not been assigned a relevant value yet { ShiftStart=currentresult.date;//Store the event date for when the time shift began } ShiftEnd=previousresult.date;//Store the event date timeshift } previousresult.result = currentresult.result;//Store the previous result of if the event date is the larger candlestick previousresult.date = currentresult.date;//Store the event date from eventtime[i] }
Uma vez que tenhamos as datas ShiftStart e ShiftEnd, verificaremos se essas datas correspondem a alguma das datas de início e término do DST. Se houver uma correspondência, atribuiremos o cronograma de DST na variável dstType e retornaremos true. Se não tivermos uma data de ShiftStart (ShiftStart=D'1970.01.01 00:00:00') e o tamanho da matriz eventtime for maior que zero, saberemos que o corretor não segue nenhum cronograma de DST.
if(ShiftStart==D'1970.01.01 00:00:00'&&eventtime.Size()>0)//Check if the ShiftStart variable has not been assigned a relevant value and the event dates are more than zero { Print("Broker ServerTime unchanged!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } if(Savings_AU.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For AU DST"); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = AU_DST;//Assigning enumeration value AU_DST, Broker has AU DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For AU"); Print("Year: %d Cannot Be Found!",lastyear); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(Savings_UK.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For UK DST"); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = UK_DST;//Assigning enumeration value UK_DST, Broker has UK/EU DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For UK"); Print("Year: %d Cannot Be Found!",lastyear); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(Savings_US.DaylightSavings(lastyear,DaylightStart,DaylightEnd)) { if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd)) { Print("Broker ServerTime Adjusted For US DST"); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = US_DST;//Assigning enumeration value US_DST, Broker has US DST(Daylight Savings Time) return true;//Returning True, Broker's DST schedule was found successfully } } else { Print("Something went wrong!"); Print("Cannot Find Daylight-Savings Date For US"); Print("Year: %d Cannot Be Found!",lastyear); if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found } if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch { SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch } Print("Cannot Detect Broker ServerTime Configuration!"); dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time) return false;//Returning False, Broker's DST schedule was not found }
Depois de detectar o cronograma de DST, precisamos armazenar essas informações para implementação posterior ao testar os eventos econômicos, assim saberemos qual calendário usar.
void CreateAutoDST(int db);//Function for creating and inserting Recommend DST for the Broker into a table
Um único registro será armazenado na tabela AutoDST.
void CNews::CreateAutoDST(int db) { bool failed=false;//boolean variable if(!DatabaseTableExists(db,"AutoDST"))//Checks if the table 'AutoDST' exists in the databse 'Calendar' { //--- create the table AutoDST if(!DatabaseExecute(db,"CREATE TABLE AutoDST(DST STRING NOT NULL);"))//Will attempt to create the table 'AutoDST' { Print("DB: create the AutoDST table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return;//Exits the function if creating the table failed } } else { return;//Exits the function if the table AutoDST table already exists } //Sql query/request to insert the recommend DST for the Broker using the DSTType variable to determine which string data to insert string request_text=StringFormat("INSERT INTO 'AutoDST'(DST) VALUES ('%s')",((DSTType==US_DST)?"Data_US": (DSTType==UK_DST)?"Data_UK":(DSTType==AU_DST)?"Data_AU":"Data_None")); if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query { Print(GetLastError()); PrintFormat("INSERT INTO 'AutoDST'(DST) VALUES ('%s')",((DSTType==US_DST)?"Data_US": (DSTType==UK_DST)?"Data_UK":(DSTType==AU_DST)?"Data_AU":"Data_None"));//Will print the sql query if failed failed=true;//assign true if the request failed } if(failed) { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); } }
Precisamos de uma função que crie nossas tabelas de calendário, para que possamos reutilizar essa função para criar nossos calendários individuais ajustados para diferentes cronogramas de DST.
bool CreateTable(int db,string tableName,bool &tableExists);//Function for creating a table in a database
Nesta função CreateTable, criaremos apenas as tabelas 'Data_UK' para o DST do Reino Unido, 'Data_US' para o DST dos EUA, 'Data_AU' para o DST da Austrália e 'Data_None' para nenhum DST. O string tableName será o parâmetro para o sufixo do nome da tabela, exemplo 'US'.
bool CNews::CreateTable(int db,string tableName,bool &tableExists) { if(DatabaseTableExists(db,StringFormat("Data_%s",tableName)))//Checks if a table 'Data_%s' exists in the database 'Calendar' { tableExists=true;//Assigns true to tableExists variable if(!DatabaseExecute(db,StringFormat("DROP TABLE Data_%s",tableName)))//We will drop the table if the table already exists { //If the table failed to be dropped/deleted PrintFormat("Failed to drop table Data_%s with code %d",tableName,GetLastError()); DatabaseClose(db);//Close the database return false;//will terminate execution of the rest of the code below and return false, when the table cannot be dropped } } if(!DatabaseTableExists(db,StringFormat("Data_%s",tableName)))//If the database table 'Data_%s' doesn't exist { //--- create the table 'Data' with the following columns if(!DatabaseExecute(db,StringFormat("CREATE TABLE Data_%s(" "ID INT NOT NULL," "EVENTID INT NOT NULL," "COUNTRY STRING NOT NULL," "EVENTNAME STRING NOT NULL," "EVENTTYPE STRING NOT NULL," "EVENTIMPORTANCE STRING NOT NULL," "EVENTDATE STRING NOT NULL," "EVENTCURRENCY STRING NOT NULL," "EVENTCODE STRING NOT NULL," "EVENTSECTOR STRING NOT NULL," "EVENTFORECAST STRING NOT NULL," "EVENTPREVALUE STRING NOT NULL," "EVENTIMPACT STRING NOT NULL," "EVENTFREQUENCY STRING NOT NULL," "PRIMARY KEY(ID));",tableName)))//Checks if the table was successfully created { Print("DB: create the Calendar table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return false;//Function returns false if creating the table failed } } return true;//Function returns true if creating the table was successful }
Agora precisamos inserir dados nessas tabelas que criamos, mas primeiro precisamos obter esses dados. Nossa próxima função
void EconomicDetails(Calendar &NewsTime[]);//Gets values from the MQL5 economic Calendar
Recuperará todos os eventos econômicos disponíveis por referência na matriz NewsTime Calendar.
void CNews::EconomicDetails(Calendar &NewsTime[]) { int Size=0;//to keep track of the size of the events in the NewsTime array MqlCalendarCountry countries[]; int count=CalendarCountries(countries);//Get the array of country names available in the Calendar string Country_code=""; for(int i=0; i<count; i++) { MqlCalendarValue values[]; datetime date_from=0;//Get date from the beginning datetime date_to=(datetime)(Time.MonthsS()+iTime(Symbol(),PERIOD_D1,0));//Date of the next month from the current day if(CalendarValueHistory(values,date_from,date_to,countries[i].code)) { for(int x=0; x<(int)ArraySize(values); x++) { MqlCalendarEvent event; ulong event_id=values[x].event_id;//Get the event id if(CalendarEventById(event_id,event)) { ArrayResize(NewsTime,Size+1,Size+2);//Readjust the size of the array to +1 of the array size StringReplace(event.name,"'","");//Removing or replacing single quotes(') from event name with an empty string NewsTime[Size].CountryName = countries[i].name;//storing the country's name from the specific event NewsTime[Size].EventName = event.name;//storing the event's name NewsTime[Size].EventType = EnumToString(event.type);//storing the event type from (ENUM_CALENDAR_EVENT_TYPE) to a string NewsTime[Size].EventImportance = EnumToString(event.importance);//storing the event importance from (ENUM_CALENDAR_EVENT_IMPORTANCE) to a string NewsTime[Size].EventId = event.id;//storing the event id NewsTime[Size].EventDate = TimeToString(values[x].time);//storing normal event time NewsTime[Size].EventCurrency = countries[i].currency;//storing event currency NewsTime[Size].EventCode = countries[i].code;//storing event code NewsTime[Size].EventSector = EnumToString(event.sector);//storing event sector from (ENUM_CALENDAR_EVENT_SECTOR) to a string if(values[x].HasForecastValue())//Checks if the event has a forecast value { NewsTime[Size].EventForecast = (string)values[x].forecast_value;//storing the forecast value into a string } else { NewsTime[Size].EventForecast = "None";//storing 'None' as the forecast value } if(values[x].HasPreviousValue())//Checks if the event has a previous value { NewsTime[Size].EventPreval = (string)values[x].prev_value;//storing the previous value into a string } else { NewsTime[Size].EventPreval = "None";//storing 'None' as the previous value } NewsTime[Size].EventImpact = EnumToString(values[x].impact_type);//storing the event impact from (ENUM_CALENDAR_EVENT_IMPACT) to a string NewsTime[Size].EventFrequency = EnumToString(event.frequency);//storing the event frequency from (ENUM_CALENDAR_EVENT_FREQUENCY) to a string Size++;//incrementing the Calendar array NewsTime } } } } }
Uma vez que tenhamos nossos dados, precisamos inseri-los nas tabelas de calendário.
bool InsertIntoTable(int db,DST_type Type,Calendar &Evalues[]);//Function for inserting Economic Data in to a database's table
A função InsertIntoTable ajudará a realizar essa tarefa. Ela tem três parâmetros.
1. Este parâmetro de entrada é o valor inteiro do banco de dados.
int db
2. Este parâmetro de entrada é o cronograma de DST.
DST_type Type
3. Esta referência de matriz é uma entrada dos eventos do calendário que teríamos recuperado da nossa função anterior, EconomicDetails.
Calendar &Evalues[]
Nesta função, mudaremos as datas individuais dos eventos se estiverem dentro do cronograma de DST. Adicionaremos uma hora à data do evento; se a hora atual do servidor estiver no cronograma de DST, removeremos uma hora da data do evento. Em seguida, armazenaremos todos os dados dos eventos econômicos na tabela de calendário Data_%s.
bool CNews::InsertIntoTable(int db,DST_type Type,Calendar &Evalues[]) { string tableName;//will store the table name suffix for(uint i=0; i<Evalues.Size(); i++)//Looping through all the Economic Events { string Date;//Will store the date for the economic event switch(Type)//Switch statement to check all possible 'case' scenarios for the variable Type { case DST_NONE://if(Type==DST_NONE) then run code below Date = Evalues[i].EventDate;//Assign the normal Economic EventDate tableName = "None";//Full table name will be 'Data_None' break;//End switch statement case US_DST://if(Type==US_DST) then run code below Savings_US.adjustDaylightSavings(StringToTime(Evalues[i].EventDate),Date);//Assign by Reference the Economic EventDate adjusted for US DST(Daylight Savings Time) tableName = "US";//Full table name will be 'Data_US' break;//End switch statement case UK_DST://if(Type==UK_DST) then run code below Savings_UK.adjustDaylightSavings(StringToTime(Evalues[i].EventDate),Date);//Assign by Reference the Economic EventDate adjusted for UK DST(Daylight Savings Time) tableName = "UK";//Full table name will be 'Data_UK' break;//End switch statement case AU_DST://if(Type==AU_DST) then run code below Savings_AU.adjustDaylightSavings(StringToTime(Evalues[i].EventDate),Date);//Assign by Reference the Economic EventDate adjusted for AU DST(Daylight Savings Time) tableName = "AU";//Full table name will be 'Data_AU' break;//End switch statement default://if(Type==(Unknown value)) then run code below Date = Evalues[i].EventDate;//Assign the normal Economic EventDate tableName = "None";//Full table name will be 'Data_None' break;//End switch statement } string request_text = StringFormat("INSERT INTO 'Data_%s'(ID,EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTDATE,EVENTCURRENCY,EVENTCODE," "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY)" "VALUES (%d,%d,'%s','%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s')", tableName, i, Evalues[i].EventId, Evalues[i].CountryName, Evalues[i].EventName, Evalues[i].EventType, Evalues[i].EventImportance, Date, Evalues[i].EventCurrency, Evalues[i].EventCode, Evalues[i].EventSector, Evalues[i].EventForecast, Evalues[i].EventPreval, Evalues[i].EventImpact, Evalues[i].EventFrequency);//Inserting all the columns for each event record if(!DatabaseExecute(db, request_text))//Checks whether the event was inserted into the table 'Data_%s' { Print(GetLastError()); PrintFormat("INSERT INTO 'Data_%s'(ID,EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTDATE,EVENTCURRENCY,EVENTCODE," "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY)" "VALUES (%d,%d,'%s','%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s')", tableName, i, Evalues[i].EventId, Evalues[i].CountryName, Evalues[i].EventName, Evalues[i].EventType, Evalues[i].EventImportance, Date, Evalues[i].EventCurrency, Evalues[i].EventCode, Evalues[i].EventSector, Evalues[i].EventForecast, Evalues[i].EventPreval, Evalues[i].EventImpact, Evalues[i].EventFrequency);//Will print the sql query to check for any errors or possible defaults in the query/request return false;//Will end the loop and return false, as values failed to be inserted into the table } } return true;//Will return true, all values were inserted into the table successfully }
Depois de criarmos nossas tabelas e inserirmos os dados econômicos nelas, precisaremos de um carimbo de data/hora de quando essa ação foi realizada. Isso serve para saber quando atualizar a tabela.
void CreateRecords(int db);//Creates a table to store records of when last the Calendar database was updated/created
Vamos criar uma tabela chamada Records e armazenar a hora atual do servidor nesta tabela toda vez que criarmos ou atualizarmos as tabelas de calendário.
void CNews::CreateRecords(int db) { bool failed=false; if(!DatabaseTableExists(db,"Records"))//Checks if the table 'Records' exists in the databse 'Calendar' { //--- create the table if(!DatabaseExecute(db,"CREATE TABLE Records(RECORDEDTIME INT NOT NULL);"))//Will attempt to create the table 'Records' { Print("DB: create the Records table failed with code ", GetLastError()); DatabaseClose(db);//Close the database return;//Exits the function if creating the table failed } } //Sql query/request to insert the current time into the 'RECORDEDTIME' column in the table 'Records' string request_text=StringFormat("INSERT INTO 'Records'(RECORDEDTIME) VALUES (%d)",(int)TimeCurrent()); if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query { Print(GetLastError()); PrintFormat("INSERT INTO 'Records'(RECORDEDTIME) VALUES (%d)",(int)TimeCurrent()); failed=true;//assign true if the request failed } if(failed) { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); } }
Agora basicamente temos todas as nossas funções prontas; há mais três em que quero me concentrar. A primeira
bool UpdateRecords();//Checks if the main Calendar database needs an update or not
Esta função retornará falso quando o registro máximo na tabela chamada Records estiver dentro da data atual (o que significa que as tabelas de calendário já foram criadas ou atualizadas no dia atual e nenhuma atualização adicional precisa ser realizada hoje). A função retornará verdadeiro se as tabelas de calendário não existirem ou se o banco de dados de calendário não existir ou se o registro máximo na tabela chamada Records não estiver dentro da data atual (dia).
bool CNews::UpdateRecords() { //--- open/create int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READONLY|DATABASE_OPEN_COMMON);//try to open database Calendar if(db==INVALID_HANDLE)//Checks if the database was able to be opened { //if opening the database failed if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if the database Calendar exists in the common folder { return true;//Returns true when the database was failed to be opened and the file doesn't exist in the common folder } } if(!DatabaseTableExists(db,"Records"))//If the database table 'Records' doesn't exist { DatabaseClose(db); return true; } int recordtime=0;//will store the maximum date recorded in the database table 'Records' string request_text="SELECT MAX(RECORDEDTIME) FROM Records";//Sql query to determine the lastest or maximum date recorded int request=DatabasePrepare(db,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead() if(request==INVALID_HANDLE)//Checks if the request failed to be completed { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseClose(db); return true; } for(int i=0; DatabaseRead(request); i++)//Will read all the results from the sql query/request { if(!DatabaseColumnInteger(request, 0, recordtime))//Will assign the first column value to the variable 'recordtime' { Print(i, ": DatabaseRead() failed with code ", GetLastError()); DatabaseFinalize(request);//Removes a request created in DatabasePrepare() DatabaseClose(db);//Closes the database return true; } } DatabaseFinalize(request);//Removes a request created in DatabasePrepare() DatabaseClose(db);//Closes the database if(!Time.DateisToday((datetime)recordtime))//Checks if the recorded time/date is today(current day) { return true; } return false; }
A segunda função em que quero me concentrar é
datetime GetLastestNewsDate();//Gets the lastest/newest date in the Calendar database
Esta função é semelhante à última chamada UpdateRecords, mas a diferença é que GetLastestNewsDate apenas retornará o tempo máximo registrado na tabela Records. Isso será usado posteriormente para notificar o usuário se ele tentar testar uma data no strategy tester que seja posterior a essa data. Diremos ao usuário/trader que não há eventos econômicos para testar após essa data.
datetime CNews::GetLastestNewsDate() { //--- open the database 'Calendar' in the common folder int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READONLY|DATABASE_OPEN_COMMON); if(db==INVALID_HANDLE)//Checks if 'Calendar' failed to be opened { if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if 'Calendar' database exists { return 0;//Will return the earliest date which is 1970.01.01 00:00:00 } } string eventtime="1970.01.01 00:00:00";//string variable with the first/earliest possible date in MQL5 //Sql query to determine the lastest or maximum recorded time from which the database was updated. string request_text="SELECT MAX(RECORDEDTIME) FROM Records"; int request=DatabasePrepare(db,request_text); if(request==INVALID_HANDLE) { Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError()); DatabaseClose(db); return true; } for(int i=0; DatabaseRead(request); i++)//Will read all the results from the sql query/request { if(!DatabaseColumnText(request, 0,eventtime))//Will assign the first column(column 0) value to the variable 'eventtime' { Print(i, ": DatabaseRead() failed with code ", GetLastError()); DatabaseFinalize(request);//Finalize request DatabaseClose(db);//Closes the database 'Calendar' return 0;//Will end the for loop and will return the earliest date which is 1970.01.01 00:00:00 } } DatabaseFinalize(request); DatabaseClose(db);//Closes the database 'Calendar' return StringToTime(eventtime);//Returns the string eventtime converted to datetime }
Agora passaremos para a função que criará o banco de dados do Calendário, bem como chamará todas as outras funções que criamos anteriormente para criar as tabelas neste banco de dados e inserir valores nessas tabelas.
void CreateEconomicDatabase();//Creates the Calendar database for a specific Broker
Esta é a função que chamaremos quando o expert advisor for anexado ao gráfico, para criar nosso banco de dados.
void CNews::CreateEconomicDatabase() { Print("Please wait..."); if(FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Check if the database exists { if(!UpdateRecords())//Check if the database is up to date { return;//will terminate execution of the rest of the code below } } else { if(!AutoDetectDST(DSTType))//Check if AutoDetectDST went through all the right procedures { return;//will terminate execution of the rest of the code below } } if(FileIsExist(NEWS_TEXT_FILE,FILE_COMMON))//Check if the database is open { return;//will terminate execution of the rest of the code below } Calendar Evalues[];//Creating a Calendar array variable bool failed=false,tableExists=false; int file=INVALID_HANDLE; datetime lastestdate=D'1970.01.01 00:00:00'; //--- open/create the database 'Calendar' int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE| DATABASE_OPEN_COMMON);//will try to open/create in the common folder if(db==INVALID_HANDLE)//Checks if the database 'Calendar' failed to open/create { Print("DB: ",NEWS_DATABASE_FILE, " open failed with code ", GetLastError()); return;//will terminate execution of the rest of the code below } else { file=FileOpen(NEWS_TEXT_FILE,FILE_WRITE|FILE_ANSI|FILE_TXT|FILE_COMMON);//try to create a text file 'NewsDatabaseOpen' in common folder if(file==INVALID_HANDLE) { DatabaseClose(db);//Closes the database 'Calendar' if the News text file failed to be created return;//will terminate execution of the rest of the code below } } DatabaseTransactionBegin(db);//Starts transaction execution Print("Please wait..."); //-- attempt to create the calendar tables if(!CreateTable(db,"None",tableExists)||!CreateTable(db,"US",tableExists) ||!CreateTable(db,"UK",tableExists)||!CreateTable(db,"AU",tableExists)) { FileClose(file);//Closing the file 'NewsDatabaseOpen.txt' FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Deleting the file 'NewsDatabaseOpen.txt' return;// } EconomicDetails(Evalues);//Retrieving the data from the Economic Calendar if(tableExists)//Checks if there is an existing table within the Calendar Database { //if there is an existing table we will notify the user that we are updating the table. PrintFormat("Updating %s",NEWS_DATABASE_FILE); } else { //if there isn't an existing table we will notify the user that we about to create one PrintFormat("Creating %s",NEWS_DATABASE_FILE); } //-- attempt to insert economic event data into the calendar tables if(!InsertIntoTable(db,DST_NONE,Evalues)||!InsertIntoTable(db,US_DST,Evalues) ||!InsertIntoTable(db,UK_DST,Evalues)||!InsertIntoTable(db,AU_DST,Evalues)) { failed=true;//Will assign true if inserting economic vaules failed in any of the Data tables } if(failed)//Checks if the event/s failed to be recorded/inserted into the database table 'Data_%s' { //--- roll back all transactions and unlock the database DatabaseTransactionRollback(db); PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError()); FileClose(file);//Close the text file 'NEWS_TEXT_FILE' FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Delete the text file, as we are reverted/rolled-back the database ArrayRemove(Evalues,0,WHOLE_ARRAY);//Removes the values in the array } else//if all the events were recorded or inserted into the tables 'Data_%s' { if(tableExists) { //Let the user/trader know that the database was updated PrintFormat("%s Updated",NEWS_DATABASE_FILE); } else { //Let the user/trader know that the database was created PrintFormat("%s Created",NEWS_DATABASE_FILE); } CreateRecords(db);//Will create the 'Records' table and insert the current time CreateAutoDST(db);//Will create the 'AutoDST' table and insert the broker's DST schedule FileClose(file);//Close the text file 'NEWS_TEXT_FILE' FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Delete the text file, as we are about to close the database ArrayRemove(Evalues,0,WHOLE_ARRAY);//Removes the values in the array } //--- all transactions have been performed successfully - record changes and unlock the database DatabaseTransactionCommit(db); DatabaseClose(db);//Close the database }
Agora passamos para o expert advisor, que executará todo o código que criamos em todas as diferentes classes e arquivos que criamos neste Projeto NewsTrading.
//+------------------------------------------------------------------+ //| NewsTrading.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "News.mqh" CNews NewsObject; #include "TimeManagement.mqh" CTimeManagement CTM; #include "WorkingWithFolders.mqh" CFolders Folder();//Calling the class's constructor //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if(!MQLInfoInteger(MQL_TESTER))//Checks whether the program is in the strategy tester { //Checks whether the database file exists and whether it has been modified in the current date if((!CTM.DateisToday((datetime)FileGetInteger(NEWS_DATABASE_FILE,FILE_MODIFY_DATE,true)))||(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))) { /* In the Do while loop below, the code will check if the terminal is connected to the internet. Se o programa for interrompido, o loop será interrompido. Se o programa não for interrompido e o terminal estiver conectado à Internet, a função CreateEconomicDatabase será chamada a partir do objeto do arquivo de cabeçalho News.mqh chamado NewsObject e o loop será interrompido quando chamado. */ bool done=false; do { if(IsStopped()) { done=true; } if(!TerminalInfoInteger(TERMINAL_CONNECTED)) { Print("Waiting for connection..."); Sleep(500); continue; } else { Print("Connection Successful!"); NewsObject.CreateEconomicDatabase();//calling the database create function done=true; } } while(!done); } } else { //Checks whether the database file exists if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON)) { Print("Necessary Files Do not Exist!"); Print("Run Program outside of the Strategy Tester"); Print("Necessary Files Should be Created First"); return(INIT_FAILED); } //Checks whether the lastest database date includes the time and date being tested datetime lastestdate = CTM.TimePlusOffset(NewsObject.GetLastestNewsDate(),CTM.DaysS());//Day after the lastest recorded time in the database if(lastestdate<TimeCurrent()) { Print("Necessary Files OutDated!"); Print("Database Dates End at: ",lastestdate); Print("Dates after %s will not be available for backtest",lastestdate); Print("To Update Files:"); Print("Run Program outside of the Strategy Tester"); } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
Agora, tudo o que resta é compilar os arquivos, bem como o expert advisor, adicionar o expert advisor a um gráfico e começar a analisar o que codificamos.
E, mais importante, ver o que o Calendário Econômico tem a oferecer.
Estes são nossos arquivos do projeto:
MQL5 Descrição do Calendário Econômico
Depois de tudo compilado, abriremos o terminal de negociação e localizaremos a janela Navigator e abriremos nossa pasta NewsTrading.
Agora anexaremos o Expert Advisor a um gráfico de sua escolha, não habilitaremos "Allow Algo Trading" neste artigo porque nenhuma negociação será realizada. Basta pressionar OK e anexar o Expert.
Depois que o Expert for anexado ao gráfico, você deverá ver um texto impresso na guia Experts na parte inferior do terminal, informando ao usuário que o banco de dados foi criado com sucesso.
Agora você terá que localizar o botão IDE na seção superior do terminal de negociação, depois de localizar o botão, pressione-o e você verá outra janela aberta separada
do terminal de negociação. Localize o botão Arquivo na seção superior esquerda do IDE e selecione Abrir Pasta de Dados Comum.
Seu diretório de arquivos deve ser semelhante a esta imagem acima, que mostrará os arquivos nesta pasta chamada Arquivos.
Você verá que a pasta NewsTrading foi criada e muitas outras.
Depois de abrir todas as pastas, você encontrará o banco de dados separado do Calendário SQLite do seu corretor.
Agora voltaremos ao MQL5 IDE.
Selecione o ícone da Pasta na parte superior esquerda do IDE e você deve ser direcionado para a Pasta Comum da MetaQuotes.
Em seguida, localizaremos o banco de dados do Calendário SQLite do corretor e o abriremos.
Você deve ver o conteúdo do banco de dados na janela Navigator, clicaremos com o botão direito do mouse na primeira tabela e selecionaremos "Open Table".
A tabela será aberta e todos os registros (*) de 'AutoDST' serão exibidos. Haverá apenas um registro nesta tabela, pois esta será a tabela de calendário recomendada de DST do corretor.
Uma vez aberta a tabela 'Data_AU', a tabela exibirá todos os registros nela, bem como todas as colunas.
SQL query:
SELECT None.EVENTNAME, DATE(REPLACE(None.EVENTDATE,'.','-')) as Date, TIME(REPLACE(None.EVENTDATE,'.','-')) as Time_None, TIME(REPLACE(US.EVENTDATE,'.','-')) as Time_US, TIME(REPLACE(UK.EVENTDATE,'.','-')) as Time_UK, TIME(REPLACE(AU.EVENTDATE,'.','-')) as Time_AU FROM 'Data_None' None INNER JOIN 'Data_US' US on US.ID=None.ID INNER JOIN 'Data_UK' UK on UK.ID=None.ID INNER JOIN 'Data_AU' AU on AU.ID=None.ID WHERE Date BETWEEN '2023-01-01' AND '2024-01-01' AND None.EVENTID='840100001';
Propósito: Esta consulta é para exibir o nome do evento com o id de evento = '840100001' e a data do evento como 'Date' e a hora como 'Time_None' nas datas entre '2023-01-01' e '2024-01-01' da tabela 'Data_None', assim como selecionar o mesmo id de evento das tabelas 'Data_UK', 'Data_US', 'Data_AU', mas exibindo apenas a hora dos eventos dessas tabelas como 'Time_UK', 'Time_US', 'Time_AU'. Nesta consulta, queremos mostrar a diferença de tempo entre as diferentes tabelas de calendário para o mesmo evento durante todo o ano de 2023.
Na consulta SQL acima, damos à tabela 'Data_None' um alias chamado None, à tabela 'Data_US' um alias chamado US, também damos à tabela 'Data_UK' um alias chamado UK, e à tabela 'Data_AU' é dado o alias AU.
Nós SELECT
None.EVENTNAME
da tabela 'Data_None'.
Na Função SQL
REPLACE(None.EVENTDATE,'.','-')
Os caracteres de ponto ('.') no valor de None.EVENTDATE são substituídos por caracteres de hífen ('-'). Isso porque a SQL
DATE()
A função só aceita datas no formato datetime com um hífen como separador de caracteres e não datas no formato datetime com pontos como separador de caracteres. Essa função converte datetime em data.
TIME()
Esta função SQL acima converte datetime para hora.
SQL query:
SELECT Distinct(COUNTRY) FROM 'Data_None';
Propósito: Esta consulta nos fornece todos os países únicos que têm registros na tabela de calendário 'Data_None'.
Se você quiser manter os resultados de suas consultas SQL para análise posterior, pode simplesmente clicar com o botão direito em um dos resultados e exportar o arquivo CSV, que pode ser convertido em um arquivo Excel
para uma análise mais detalhada.
SQL query:
SELECT * FROM 'Data_None' where COUNTRY='New Zealand';
Propósito: Esta consulta nos fornece todos os registros para um país específico. Neste caso, esse país é a Nova Zelândia.
SQL query:
SELECT Distinct(EVENTID), COUNTRY, EVENTNAME,EVENTTYPE, EVENTSECTOR, EVENTIMPORTANCE, EVENTFREQUENCY, EVENTCURRENCY, EVENTCODE FROM 'Data_None' where COUNTRY='New Zealand';
Propósito: Esta consulta recupera todos os IDs de eventos únicos para um país específico e seleciona colunas específicas, como "EVENTNAME" e "EVENTSECTOR", entre outras.
Mas especificamente não "EVENTDATE", pois cada "EVENTID" tem uma "EVENTDATE" diferente. Tentar incluir "EVENTDATE" nesta consulta retornará erros.
SQL query:
SELECT Distinct(EVENTID), COUNTRY, EVENTNAME, EVENTTYPE, EVENTIMPORTANCE FROM 'Data_None' where COUNTRY='New Zealand' and EVENTSECTOR='CALENDAR_SECTOR_PRICES';
Propósito: Esta consulta recupera todos os IDs de eventos únicos para um "PAÍS" e "SETOR DE EVENTOS" específicos.
SQL query:
SELECT COUNTRY,EVENTNAME, EVENTIMPORTANCE FROM 'Data_None' where EVENTIMPORTANCE='CALENDAR_IMPORTANCE_HIGH' UNION SELECT COUNTRY,EVENTNAME, EVENTIMPORTANCE FROM 'Data_None' where EVENTIMPORTANCE='CALENDAR_IMPORTANCE_HIGH';
Propósito: Esta consulta recupera todos os registros únicos para Importância do Evento que é "CALENDAR_IMPORTANCE_HIGH".
Conclusão
Há muito o que absorver neste artigo; espero que você tenha aprendido algo novo e obtido novas ideias após ler este artigo. Neste artigo, abordamos por que usar um banco de dados foi a escolha certa e alguns benefícios de usar um banco de dados. Também abordamos todas as moedas fornecidas pelo Calendário Econômico MQL5 e o conceito de DST (horário de verão). Além disso, codificamos vários arquivos essenciais para criar o banco de dados do Calendário e verificar se devemos atualizar ou criar o banco de dados.
Finalmente, passamos pela localização dos arquivos do banco de dados depois que eles foram criados e extraímos dados específicos usando consultas SQL básicas para manipular a tabela. No próximo artigo, abordaremos a gestão de risco. Até a próxima.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14324
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso