
Simplificando a negociação com base em notícias (Parte 4): Aumentando o desempenho
Introdução
No artigo anterior, analisamos os processos de execução de operações considerando o impacto das notícias. Embora tenhamos cumprido essa tarefa com sucesso, a principal limitação do código apresentado foi a velocidade relativamente baixa dos testes em histórico. Isso se deve principalmente ao acesso frequente ao banco de dados na memória durante o teste da estratégia. Para resolver esse problema, reduziremos a quantidade de acessos ao banco de dados durante o backtest. Para isso, obtemos, de uma só vez, todas as informações necessárias para o dia atual diretamente da base de dados em memória. Ou seja, faremos apenas uma consulta por dia, idealmente.
Outro método que usaremos para aumentar o desempenho é agrupar os eventos de notícias por hora. Isso significa que, para cada hora do dia, teremos um array contendo apenas as informações dos eventos daquela hora específica. Quando precisarmos das informações referentes ao horário atual (caso existam), utilizaremos um operador switch para acessar o array que armazena os eventos correspondentes ao horário em questão. Esses métodos reduzirão significativamente o tempo de execução do EA, especialmente se houver muitos eventos em um determinado dia ou horário. Neste artigo, implementaremos os blocos fundamentais para essas soluções. Nas próximas partes, desenvolveremos as soluções completas, pois, caso contrário, o texto ficaria excessivamente extenso.
Classe Time Variables
Anteriormente, essa classe era utilizada para declarar um array de 2000 índices com tamanho fixo, destinado a armazenar o horário das velas. Esse horário era usado na classe Candle Properties para verificar se correspondia ao horário da vela atual e determinar se uma nova vela havia se formado. Agora, vamos expandi-la, declarando enumerações para tempo e funções que convertam valores inteiros para qualquer uma das enumerações declaradas. Isso permitirá um método controlado para manipular segundos, minutos e horas em outras classes que a incluam.
A disposição da classe é mostrada abaixo:
//+------------------------------------------------------------------+ //| NewsTrading | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/kaaiblo | //+------------------------------------------------------------------+ //--- Enumeration For Hours in a Day enum HOURLY { H1=1,//01 H2=2,//02 H3=3,//03 H4=4,//04 H5=5,//05 H6=6,//06 H7=7,//07 H8=8,//08 H9=9,//09 H10=10,//10 H11=11,//11 H12=12,//12 H13=13,//13 H14=14,//14 H15=15,//15 H16=16,//16 H17=17,//17 H18=18,//18 H19=19,//19 H20=20,//20 H21=21,//21 H22=22,//22 H23=23,//23 H24=0//00 }; //--- Enumeration For Minutes in an Hour enum MINUTELY { M0,//00 M1,//01 M2,//02 M3,//03 M4,//04 M5,//05 M6,//06 M7,//07 M8,//08 M9,//09 M10,//10 M11,//11 M12,//12 M13,//13 M14,//14 M15,//15 M16,//16 M17,//17 M18,//18 M19,//19 M20,//20 M21,//21 M22,//22 M23,//23 M24,//24 M25,//25 M26,//26 M27,//27 M28,//28 M29,//29 M30,//30 M31,//31 M32,//32 M33,//33 M34,//34 M35,//35 M36,//36 M37,//37 M38,//38 M39,//39 M40,//40 M41,//41 M42,//42 M43,//43 M44,//44 M45,//45 M46,//46 M47,//47 M48,//48 M49,//49 M50,//50 M51,//51 M52,//52 M53,//53 M54,//54 M55,//55 M56,//56 M57,//57 M58,//58 M59//59 }; //--- Enumeration For Seconds Pre-event datetime enum PRESECONDLY { Pre_S30=30//30 }; //--- Enumeration For Seconds in a Minute enum SECONDLY { S0,//00 S1,//01 S2,//02 S3,//03 S4,//04 S5,//05 S6,//06 S7,//07 S8,//08 S9,//09 S10,//10 S11,//11 S12,//12 S13,//13 S14,//14 S15,//15 S16,//16 S17,//17 S18,//18 S19,//19 S20,//20 S21,//21 S22,//22 S23,//23 S24,//24 S25,//25 S26,//26 S27,//27 S28,//28 S29,//29 S30,//30 S31,//31 S32,//32 S33,//33 S34,//34 S35,//35 S36,//36 S37,//37 S38,//38 S39,//39 S40,//40 S41,//41 S42,//42 S43,//43 S44,//44 S45,//45 S46,//46 S47,//47 S48,//48 S49,//49 S50,//50 S51,//51 S52,//52 S53,//53 S54,//54 S55,//55 S56,//56 S57,//57 S58,//58 S59//59 }; //+------------------------------------------------------------------+ //|TimeVariables class | //+------------------------------------------------------------------+ class CTimeVariables { private: //--- Array to store candlestick times datetime CandleTime[2000]; public: CTimeVariables(void); //--- Set datetime value for an array index void SetTime(uint index,datetime time); //--- Get datetime value for an array index datetime GetTime(uint index); //--- Convert Integer to the Enumeration HOURLY HOURLY Hourly(uint Hour); //--- Convert Integer to the Enumeration MINUTELY MINUTELY Minutely(uint Minute); //--- Convert Integer to the Enumeration SECONDLY SECONDLY Secondly(uint Second); }; //+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CTimeVariables::CTimeVariables() { //--- Set default datetime values for all indexes in array CandleTime for(uint i=0; i<CandleTime.Size(); i++) { CandleTime[i]=D'1970.01.01'; } } //+------------------------------------------------------------------+ //|Set datetime value for an array index in array CandleTime | //+------------------------------------------------------------------+ void CTimeVariables::SetTime(uint index,datetime time) { if(index>=0&&index<CandleTime.Size()) { CandleTime[index] = time; } } //+------------------------------------------------------------------+ //|Get the datetime value for an array index in array CandleTime | //+------------------------------------------------------------------+ datetime CTimeVariables::GetTime(uint index) { return (index>=0&&index<CandleTime.Size())?CandleTime[index]:datetime(0); } //+------------------------------------------------------------------+ //|Convert Integer to the Enumeration HOURLY | //+------------------------------------------------------------------+ HOURLY CTimeVariables::Hourly(uint Hour) { return (Hour>23)?HOURLY(0):HOURLY(Hour); } //+------------------------------------------------------------------+ //|Convert Integer to the Enumeration MINUTELY | //+------------------------------------------------------------------+ MINUTELY CTimeVariables::Minutely(uint Minute) { return (Minute>59)?MINUTELY(0):MINUTELY(Minute); } //+------------------------------------------------------------------+ //|Convert Integer to the Enumeration SECONDLY | //+------------------------------------------------------------------+ SECONDLY CTimeVariables::Secondly(uint Second) { return (Second>59)?SECONDLY(0):SECONDLY(Second); } //+------------------------------------------------------------------+
O código abaixo define uma enumeração chamada HOURLY. Uma enumeração (enum) é um tipo de dado definido pelo usuário, composto por um conjunto de constantes inteiras nomeadas. Ela é frequentemente utilizada quando é necessário representar um conjunto específico de valores usando nomes significativos, tornando o código mais legível.
enum HOURLY { H1=1, // Represents Hour 01 H2=2, // Represents Hour 02 H3=3, // Represents Hour 03 H4=4, // Represents Hour 04 H5=5, // Represents Hour 05 H6=6, // Represents Hour 06 H7=7, // Represents Hour 07 H8=8, // Represents Hour 08 H9=9, // Represents Hour 09 H10=10, // Represents Hour 10 H11=11, // Represents Hour 11 H12=12, // Represents Hour 12 H13=13, // Represents Hour 13 H14=14, // Represents Hour 14 H15=15, // Represents Hour 15 H16=16, // Represents Hour 16 H17=17, // Represents Hour 17 H18=18, // Represents Hour 18 H19=19, // Represents Hour 19 H20=20, // Represents Hour 20 H21=21, // Represents Hour 21 H22=22, // Represents Hour 22 H23=23, // Represents Hour 23 H24=0 // Represents Hour 00 (Midnight) };
Valores:
Cada valor na enumeração corresponde a uma hora específica do dia, começando com H1=1 para a primeira hora, H2=2 e assim por diante, até H23=23 para a 23ª hora. H24=0 é usado para representar a meia-noite (00:00 horas). Você pode utilizar nomes como H1, H2 e assim por diante, tornando o trabalho com dados relacionados ao tempo mais intuitivo. Em vez de usar apenas números para as horas, eu prefiro utilizar os valores da enumeração HOURLY.
Exemplo de uso:
HOURLY current_hour = H10; // Setting the current hour to 10:00 AM if (current_hour == H10) { Print("The current hour is 10:00 AM"); }
No exemplo acima, current_hour recebe o valor H10 e verifica se a hora atual é H10, exibindo uma mensagem correspondente. Isso facilita a leitura e a compreensão do código, especialmente ao lidar com inúmeras operações relacionadas ao tempo.
Enumeração para minutos - MINUTELY.
Essa enumeração define constantes para cada minuto da hora, de M0 (00) até M59 (59).
enum MINUTELY
{
M0, M1, M2, M3, ..., M59
};
Em vez de trabalhar exclusivamente com números inteiros (por exemplo, 0, 1, 2), utilizamos rótulos significativos, como M0, M1 e assim por diante.
Exemplo:
- M0 representa o minuto 00.
- M30 representa o trigésimo minuto.
Enumeração de segundos antes do evento - PRESECONDLY.
Essa enumeração define os segundos antes de um evento. Por exemplo, Pre_S30 é usado para indicar 30 segundos antes do início de um evento de notícias. O valor é fixado para o momento prévio à entrada em um evento. Por exemplo, se uma notícia será divulgada às 14:00, consideraremos a possibilidade de abrir uma operação apenas às 13:59:30. Isso significa que a antiga possibilidade de entrar em uma operação 5 segundos antes do evento não estará mais disponível.
A alteração que implementei tem seus prós e contras.
Principal desvantagem:
- A menor flexibilidade de configuração é um ponto negativo, pois o usuário/trader pode preferir abrir operações apenas cinco segundos antes do evento, devido à volatilidade aleatória que ocorre pouco antes de um anúncio importante. Isso significa que um stop-loss pode ser acionado apenas pelo momento exato em que você decide entrar antes do evento. Assim, alguns segundos podem impactar significativamente a lucratividade no trading de notícias.
Principal vantagem:
- Agenda fixa: É uma vantagem, pois permite configurar o EA para verificar a possibilidade de entrada em uma operação a cada 30 segundos, melhorando significativamente a velocidade do backtest. Com isso, não precisamos utilizar os recursos do computador com tanta frequência, reduzindo o tempo de teste. Se quisermos entrar em uma operação cinco segundos antes do evento, o EA teria de verificar a cada cinco segundos, ou até a cada um segundo, se é o momento adequado para enviar a ordem. Isso consome recursos do computador, tornando o teste histórico mais lento.
Outro fator a ser considerado é a liquidez. Quanto mais próximo chegamos de uma notícia importante, tem menos líquido se torna o ativo afetado por ela. Isso significa que a entrada na operação, de forma geral, torna-se menos vantajosa.
Aqui estão os fatores que tornam desfavorável a entrada em operações com ativos ilíquidos ou em mercados de baixa liquidez:
- Slippage: O preço do ativo ou símbolo muda com frequência extrema, fazendo com que o preço desejado pelo usuário/trader para entrar ou sair do mercado não esteja mais disponível, sendo executado a um preço menos vantajoso. A imprevisibilidade é a principal desvantagem do slippage.
- Spreads: Spreads largos ocorrem com mais frequência, reduzindo o potencial de lucratividade do trader.
- Ausência/indisponibilidade de cotações: As negociações podem ser totalmente interrompidas, o que significa que o trader perde a oportunidade de aproveitar um movimento potencialmente lucrativo do ativo ou mercado.
Ao entrar na operação com 30 segundos de antecedência à divulgação da notícia, temos mais chances de evitar a falta de liquidez em comparação a uma entrada 5 segundos antes ou em qualquer quantidade de segundos menor que 30.
enum PRESECONDLY { Pre_S30 = 30 // 30 seconds before an event };
Enumeração para segundos – SECONDLY.
Semelhante à MINUTELY, essa enumeração representa cada segundo de um minuto, variando de S0 (00 segundos) até S59 (59 segundos).
enum SECONDLY
{
S0, S1, S2, ..., S59
};
Exemplo:
- S0 representa o segundo 00.
- S30 representa o trigésimo segundo.
A função abaixo converte um valor inteiro de hora (Hour) no respectivo valor da enumeração HOURLY. Ela garante que o valor passado (na variável Hour) seja válido (entre 0 e 23) e, em seguida, retorna o valor correspondente da enumeração HOURLY.
- Tipo de retorno: HOURLY – a função retorna um valor da enumeração HOURLY, que discutimos anteriormente. Essa enumeração contém os valores correspondentes às 24 horas do dia, onde H1=1, H2=2, ..., H23=23 e H24=0.
- Nome da função: Hourly. Esse método pertence à classe CTimeVariables, o que é indicado pelo operador de resolução de escopo (::). Portanto, ele faz parte da classe CTimeVariables.
- Parâmetros:
- uint Hour – número inteiro sem sinal que representa a hora, passado para a função como parâmetro.
HOURLY CTimeVariables::Hourly(uint Hour) { return (Hour>23)?HOURLY(0):HOURLY(Hour); }
Lógica da função:
Nesta linha, é usado o operador ternário (? :), que é uma forma abreviada do operador if-else. O operador ternário verifica uma condição e retorna um de dois valores, dependendo de a condição ser verdadeira ou falsa.
Condição: (Hour > 23)
- Verifica se o valor da hora excede 23. Como o intervalo válido de horas vai de 0 a 23 (24 horas por dia), qualquer valor maior que 23 é inválido.
- Se Hour > 23 (valor de hora inválido), a função retornará HOURLY(0), que corresponde a H24=0 (meia-noite ou 00:00).
Se false: HOURLY(Hour)
- Se Hour estiver dentro do intervalo válido (de 0 a 23), ele converte o número inteiro Hour no valor correspondente da enumeração HOURLY. Por exemplo, se Hour = 10, a função retornará HOURLY(10), que corresponde a H10.
return (Hour>23)?HOURLY(0):HOURLY(Hour);
Exemplo:
- Ao chamar Hourly(10), a função retorna HOURLY(10) (que é o valor da enumeração para 10:00).
- Se Hourly(25), como 25 não é uma hora válida, a função retorna HOURLY(0) (que corresponde a 00:00 ou meia-noite).
Pontos-chave:
- Tratamento de valores inválidos de hora: A função garante que, se o valor Hour estiver fora do intervalo permitido (maior que 23), o padrão será HOURLY(0), equivalente à meia-noite.
- Conversão: a função converte de forma eficiente o valor inteiro da hora em um valor da enumeração HOURLY, facilitando seu uso em lógicas baseadas no tempo.
Função auxiliar para converter inteiros em MINUTELY.
A função converte um número inteiro (de 0 a 59) em um valor da enumeração MINUTELY. Se o valor inteiro de entrada for maior que 59, a função define M0 (minuto 0) como padrão.
MINUTELY CTimeVariables::Minutely(uint Minute) { return (Minute>59)?MINUTELY(0):MINUTELY(Minute); }
Se o valor de minuto exceder 59, M0 será retornado como alternativa de segurança para evitar erros.
Função auxiliar para converter um número inteiro em SECONDLY.
This function performs a similar task for seconds. Ela converte um número inteiro (de 0 a 59) em um valor da enumeração SECONDLY. Se o valor inteiro exceder 59, o padrão será S0 (segundo 0).
SECONDLY CTimeVariables::Secondly(uint Second) { return (Second>59)?SECONDLY(0):SECONDLY(Second); }
Se o valor de segundos exceder 59, S0 será retornado para garantir o tratamento correto de entradas inválidas.
Principais conclusões:
Precisão temporal: A classe TimeVariables simplifica o gerenciamento de tempo em sistemas de trading, facilitando o controle da precisão no nível de minutos e segundos, o que é essencial para estratégias de trading em notícias.
Flexibilidade: Ao utilizar enumerações, os desenvolvedores podem ajustar facilmente o momento de execução das operações em relação aos eventos de notícias, sem precisar codificar manualmente os horários para cada cenário.
Aplicação prática: No trading em notícias, a capacidade de reagir rapidamente a oportunidades urgentes, como a volatilidade causada por divulgações econômicas, pode aumentar significativamente a eficiência das operações.
Previsões e ideias:
Diferentes condições de mercado influenciarão a utilidade da classe TimeVariables. Por exemplo:
- Em mercados instáveis, especialmente durante notícias importantes (como a divulgação do Payroll não agrícola ou discursos de representantes de bancos centrais), a precisão até o nível de segundos torna-se criticamente importante, já que mudanças significativas nos preços podem ocorrer em milissegundos.
- Em condições de baixa volatilidade, pode ser suficiente uma precisão no nível de minutos para o envio das ordens, pois os movimentos de preços tendem a ser mais lentos.
Simplificação do acesso ao banco de dados
No artigo anterior, utilizamos um banco de dados em memória para armazenar informações sobre eventos, ajudando nosso EA a identificar o momento certo para abrir uma operação com base no horário do evento. O processo de acesso ao banco de dados é mostrado a seguir.
- No início de cada novo dia, carregamos todos os eventos de notícias que, idealmente, ocorreram ou irão ocorrer no dia atual. Esses dados ficam armazenados em um array de estruturas, no qual o programa exibe os objetos de eventos no gráfico, mostrando o horário, o nome e outras informações.
- Quando um evento já ocorreu ou está acontecendo, o EA consulta novamente o banco de dados em memória para obter informações sobre o próximo evento do mesmo dia, caso exista.
O processo descrito acima não é o mais eficiente, pois, se em um único dia houver vários eventos em horários diferentes, o acesso ao banco de dados será frequente para obter as informações sobre o próximo evento. Uma solução simples seria usar o mesmo array de estruturas, que é atualizado diariamente, e iterar sobre ele até encontrar uma data que coincida com a data atual e a do evento, para então abrir a operação no momento correto, sem precisar acessar o banco de dados mais de uma vez apenas para obter informações do próximo evento.
Essa solução simples certamente melhoraria a velocidade de execução do EA, mas cria outro problema: ao iterarmos sobre o mesmo array de estruturas para verificar coincidências de datas, podemos encontrar datas de eventos que já passaram. Verificar essas datas desnecessárias tornará o EA mais lento. O mesmo vale para datas de eventos que ocorrerão muito depois da data atual.
Por exemplo, suponha que em nosso array abaixo existam os seguintes valores de horário.
time[0] = '14:00' time[1] = '14:15' time[2] = '14:30' time[3] = '14:45' time[4] = '14:50' time[5] = '14:55' time[6] = '15:00' time[7] = '15:05' time[8] = '15:10' time[9] = '15:15' time[10] = '15:30' time[11] = '15:45' time[12] = '15:55'
Se o horário atual for 11:00, não faz sentido verificar se ele coincide com 14:00, e a iteração constante sobre esse array a cada novo tick no gráfico, quando o horário dos eventos ainda não foi alcançado, afetará ainda mais a velocidade de execução do EA. Considerando isso, uma solução simples para o problema seria, pelo menos, dividir o array em diferentes horas do dia, de forma que o EA percorra apenas o array correspondente à hora atual. Assim, o EA economizaria tempo verificando apenas os eventos cujo horário coincida pelo menos com a mesma hora da data atual.
Estudo de caso:
Vamos analisar um exemplo real para demonstrar como essa otimização pode aumentar o desempenho:
- Cenário: Um trader utiliza um EA que monitora divulgações de notícias importantes, por exemplo, a publicação do relatório de emprego não agrícola (Non-Farm Payrolls, NFP) nos EUA, programada para as 14:30. O EA está programado para posicionar uma ordem stop de compra ou venda dependendo do resultado da notícia. Sem otimização, o EA acessa continuamente o banco de dados a cada segundo durante todo o dia, verificando a existência do próximo evento. No momento da divulgação do NFP, o EA pode apresentar um atraso na reação às notícias devido ao excesso de consultas ao banco de dados, reduzindo as chances de encontrar os pontos ideais de entrada.
- Solução com redução de acessos ao banco de dados: Em vez de consultar o banco de dados constantemente, o EA carrega todos os eventos do dia às 00:00 e os segmenta por hora. Quando o horário se aproxima das 14:00, o EA verifica apenas os eventos dentro do intervalo de tempo das 14:00, ignorando verificações de eventos fora desse intervalo. Assim, quando chega às 14:30, o EA está pronto para reagir imediatamente à divulgação do NFP, enviando a ordem no momento exato.
Criaremos no projeto uma nova pasta chamada TimeSeries. Nessa pasta, serão armazenadas duas classes responsáveis por criar e recuperar arrays para cada hora do dia.
Classe TimeByHour
O código abaixo define a classe CTimeByHour, que é projetada para gerenciar e recuperar dados sobre horários e eventos para cada hora do dia. A classe utiliza vários componentes, como estruturas, arrays e conceitos de programação orientada a objetos (POO). O objetivo dessa classe é criar objetos de array para cada hora do dia no formato de 24 horas, ou seja, serão declarados 24 objetos de array. Esses objetos de array armazenarão variáveis inteiras Hour e Minute, bem como a variável estrutural de calendário myEData (essa variável conterá todas as informações do evento para a hora e minuto específicos em que ele ocorrerá durante o dia). A estrutura declarada TimeDate armazenará a hora e o minuto da data, enquanto o array myTimeData armazenará os dados de forma paralela ao array estrutural myEvents.
//+------------------------------------------------------------------+ //| TimeByHour.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #include <Object.mqh> #include <Arrays\ArrayObj.mqh> #include "../TimeVariables.mqh" #include "../CommonVariables.mqh" #include "../TimeManagement.mqh" //--- Structure to store time data in Hour and Minute struct TimeDate { int Hour; int Minute; } myTimeData[]; //--- Structure array to store event data in parallel with myTimeData array Calendar myEvents[]; //+------------------------------------------------------------------+ //|TimeByHour class | //+------------------------------------------------------------------+ class CTimeByHour:public CObject { private: //--- classes' object declarations CTimeManagement CTime; CTimeVariables CTV; protected: //--- class constructor with parameters CTimeByHour(HOURLY myHour,MINUTELY myMinute,Calendar &myEventData): //--- Assign integer variables Hour and Minute with time data from myHour and myMinute respectively Hour(int(myHour)),Minute(int(myMinute)) { //--- Assign variable myEData with event info from variable myEventData myEData = myEventData; } virtual void myTime(Calendar &myNews[]); //--- Array object declarations for each hour of the day CArrayObj *myH1,*myH2,*myH3,...,*myH24; //--- Integer variables to store time data in hour and minute format int Hour; int Minute; //--- Calendar structure variable to store event info Calendar myEData; public: //--- class constructor without parameters CTimeByHour(void) { } //--- Array object variable CArrayObj *getmyTime; //--- Retrieve array object for an individual hour CObject *getTime(HOURLY myHour) { switch(myHour) { case H1: //--- retrieve array obj for 01 Hour return myH1; break; case H2: //--- retrieve array obj for 02 Hour return myH2; break; case H3: //--- retrieve array obj for 03 Hour return myH3; break; // ... default: //--- retrieve array obj for 24|00 Hour return myH24; break; } } //--- class pointer variable CTimeByHour *myClass; //--- class destructor ~CTimeByHour(void) { //--- delete all pointer variables delete getmyTime; delete myClass; delete myH1; delete myH2; delete myH3; // ... } //--- Function to retrieve timedata and calendar info for a specific hour of the day via parameters passed by reference void GetDataForHour(HOURLY myHour,TimeDate &TimeData[],Calendar &Events[]) { //--- Clean arrays ArrayRemove(TimeData,0,WHOLE_ARRAY); ArrayRemove(Events,0,WHOLE_ARRAY); //--- retrieve array object for the specific hour getmyTime = getTime(myHour); // Iterate through all the items in the list. for(int i=0; i<getmyTime.Total(); i++) { // Access class obj via array obj index myClass = getmyTime.At(i); //Re-adjust arrays' sizes ArrayResize(TimeData,i+1,i+2); ArrayResize(Events,i+1,i+2); //--- Assign values to arrays' index TimeData[i].Hour = myClass.Hour; TimeData[i].Minute = myClass.Minute; Events[i] = myClass.myEData; } } }; //+------------------------------------------------------------------+
Estruturas:
- TimeDate – estrutura para armazenar dados de tempo com os campos Hour e Minute como valores inteiros.
- myTimeData[] – array da estrutura TimeDate para armazenar dados de tempo para várias horas.
struct TimeDate { int Hour; int Minute; } myTimeData[];
- myEvents[] – array do tipo Calendar para armazenar dados de eventos paralelamente ao myTimeData.
Calendar myEvents[];
Declaração da classe CTimeByHour:
- CTimeByHour – classe que estende CObject. Classe que gerencia os dados de tempo e eventos por hora.
class CTimeByHour:public CObject
Membros privados:
- CTimeManagement e CTimeVariables – objetos de classes personalizadas (CTimeManagement, CTimeVariables), incluídas de TimeManagement.mqh e TimeVariables.mqh, que gerenciam dados e variáveis relacionadas ao tempo.
private:
CTimeManagement CTime;
CTimeVariables CTV;
Construtor:
- Construtor parametrizado da classe. Inicializa duas variáveis inteiras (Hour e Minute) utilizando as enumerações HOURLY e MINUTELY, e atribui as informações do evento (myEventData) a myEData.
protected: CTimeByHour(HOURLY myHour, MINUTELY myMinute, Calendar &myEventData): Hour(int(myHour)), Minute(int(myMinute)) { myEData = myEventData; }
Membros de dados:
- myH1 ... myH24 – ponteiros para objetos CArrayObj, cada um correspondente a uma hora específica do dia (de 01 a 24). Cada CArrayObj contém um array de objetos para a hora correspondente.
- Hour e Minute – variáveis inteiras para armazenar o horário.
- myEData – objeto de calendário que armazena as informações do evento.
CArrayObj *myH1, *myH2, ..., *myH24; int Hour; int Minute; Calendar myEData;
Métodos públicos:
- CTimeByHour(void) – construtor padrão, que não inicializa nada.
- getmyTime – ponteiro para um objeto de array que contém dados de horário para uma hora específica.
public: CTimeByHour(void) {} CArrayObj *getmyTime;
Recuperar o objeto de array para Hour:
- getTime(HOURLY myHour) – método que utiliza o operador switch para recuperar o objeto CArrayObj correspondente a uma hora específica do dia, com base na enumeração HOURLY. Cada caso corresponde a uma hora (por exemplo, H1, H2, ... H24).
CObject *getTime(HOURLY myHour) { switch(myHour) { case H1: return myH1; case H2: return myH2; ... case H24: return myH24; } }
Destrutor:
- ~CTimeByHour(void) – o destrutor limpa a memória alocada dinamicamente, chamando delete para os ponteiros CArrayObj (myH1 ... myH24), bem como para outros ponteiros da classe.
~CTimeByHour(void) { delete getmyTime; delete myClass; delete myH1, myH2, ..., myH24; }
Obter dados para uma hora específica:
- GetDataForHour – método que recupera os dados de horário e eventos para uma hora específica (myHour).
- ArrayRemove – limpa os arrays (TimeData[], Events[]).
- getmyTime = getTime(myHour) – obtém o objeto de array para a hora especificada.
- for loop – percorre todos os elementos no CArrayObj recuperado (ou seja, os dados de horário e eventos de cada registro).
- ArrayResize – redimensiona dinamicamente os arrays (TimeData[], Events[]) para acomodar os novos dados.
- myClass – referência para o objeto atual sendo processado no array.
Para cada objeto, o método atribui Hour, Minute e myEData ao índice correspondente nos arrays TimeData[] e Events[].
void GetDataForHour(HOURLY myHour, TimeDate &TimeData[], Calendar &Events[]) { ArrayRemove(TimeData, 0, WHOLE_ARRAY); ArrayRemove(Events, 0, WHOLE_ARRAY); getmyTime = getTime(myHour); for(int i = 0; i < getmyTime.Total(); i++) { myClass = getmyTime.At(i); ArrayResize(TimeData, i + 1); ArrayResize(Events, i + 1); TimeData[i].Hour = myClass.Hour; TimeData[i].Minute = myClass.Minute; Events[i] = myClass.myEData; } }
Classe TimeByDay
Essa classe será responsável por atribuir valores aos objetos de array declarados anteriormente no arquivo de cabeçalho TimeByHour, bem como por recuperar esses valores e classificá-los por hora e minuto específicos, armazenados no respectivo objeto de array. O código começa com a importação de outros arquivos: TimeByHour.mqh, que lida com dados de horário no nível de horas, e CommonVariables.mqh, que contém constantes e variáveis comuns. A classe CTimeByDay herda de CTimeByHour. Classe que processa dados de horário por dia e permite a interação com dados horários gerenciados pelo CTimeByHour.
//+------------------------------------------------------------------+ //| TimeByDay.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #include "TimeByHour.mqh" #include "../CommonVariables.mqh" //+------------------------------------------------------------------+ //|TimeByDay class | //+------------------------------------------------------------------+ class CTimeByDay:private CTimeByHour { private: //--- Function to clear all array objects void Clear(); //--- Function to clean array dates in accordance to the current minute void DatePerMinute(TimeDate &TData[],Calendar &EData[],MINUTELY min,TimeDate &TimeData[],Calendar &EventData[]) { //--- Iterate through all the idexes in TData array for(uint i=0;i<TData.Size();i++) { //--- Check if Minutes match if(TData[i].Minute==int(min)) { //--- Resize arrays ArrayResize(TimeData,TimeData.Size()+1,TimeData.Size()+2); ArrayResize(EventData,EventData.Size()+1,EventData.Size()+2); //--- Assign data from each array to the other TimeData[TimeData.Size()-1] = TData[i]; EventData[EventData.Size()-1] = EData[i]; } } } public: //--- Function to set time for array objects based on calendar array myNews void SetmyTime(Calendar &myNews[]) { //--- Clear previous data stored in array objects Clear(); //--- clean arrays in parallel declared in TimeByHour header file ArrayRemove(myTimeData,0,WHOLE_ARRAY); ArrayRemove(myEvents,0,WHOLE_ARRAY); //--- Set new values to each array object accordingly myTime(myNews); } //--- Function to get time for the specific hour and minute for news events void GetmyTime(HOURLY myHour,MINUTELY myMinute,TimeDate &TimeData[],Calendar &Events[]) { //--- clean arrays in parallel declared in TimeByHour header file ArrayRemove(myTimeData,0,WHOLE_ARRAY); ArrayRemove(myEvents,0,WHOLE_ARRAY); //--- Declare temporary arrays to get news data for a specific hour TimeDate myTData[]; Calendar myData[]; //--- Get Data for the specific hour of the day GetDataForHour(myHour,myTData,myData); //--- Filter the Data for a specific Minute of the hour DatePerMinute(myTData,myData,myMinute,TimeData,Events); //--- Clear data from the temporary array variables ArrayRemove(myTData,0,WHOLE_ARRAY); ArrayRemove(myData,0,WHOLE_ARRAY); } public: //--- Class constructor CTimeByDay(void) { //--- Initialize array objects myH1 = new CArrayObj(); myH2 = new CArrayObj(); myH3 = new CArrayObj(); //... } //--- Class destructor ~CTimeByDay(void) { } }; //+------------------------------------------------------------------+ //|Add data to Array Objects for each Hour of the day | //+------------------------------------------------------------------+ void CTimeByHour::myTime(Calendar &myNews[]) { //--- Iterate through myNews calendar array for(uint i=0;i<myNews.Size();i++) { //--- Assign datetime from myNews calendar array datetime Date = datetime(myNews[i].EventDate); //--- Assign HOURLY Enumeration value from datetime variable Date HOURLY myHour = CTV.Hourly(CTime.ReturnHour(Date)); //--- Assign MINUTELY Enumeration value from datetime variable Date MINUTELY myMinute = CTV.Minutely(CTime.ReturnMinute(Date)); //--- Switch statement to identify each value scenario for myHour switch(myHour) { case H1: //--- add array obj values for 01 Hour myH1.Add(new CTimeByHour(myHour,myMinute,myNews[i])); break; case H2: //--- add array obj values for 02 Hour myH2.Add(new CTimeByHour(myHour,myMinute,myNews[i])); break; case H3: //--- add array obj values for 03 Hour myH3.Add(new CTimeByHour(myHour,myMinute,myNews[i])); break; //... default: //--- add array obj values for 24|00 Hour myH24.Add(new CTimeByHour(myHour,myMinute,myNews[i])); break; } } } //+------------------------------------------------------------------+ //|Clear Data in Array Objects | //+------------------------------------------------------------------+ void CTimeByDay::Clear(void) { //--- Empty all array objects myH1.Clear(); myH2.Clear(); myH3.Clear(); //... } //+------------------------------------------------------------------+
Funções privadas:
- Essa função é utilizada para limpar (ou redefinir) todos os objetos de array que armazenam dados horários.
void Clear();
A função abaixo ordena os dados de horário (TData[]) e os eventos do calendário (EData[]), mantendo apenas os registros que correspondem a um minuto específico (fornecido como argumento min).
- Ela percorre TData[] e, para cada elemento, verifica se o minuto corresponde ao valor de min. Caso sejam iguais, os arrays TimeData[] e EventData[] são redimensionados e recebem os dados correspondentes de TData[] e EData[].
void DatePerMinute(TimeDate &TData[], Calendar &EData[], MINUTELY min, TimeDate &TimeData[], Calendar &EventData[]);
Funções públicas:
A função abaixo redefine e atribui novos dados de horário e eventos do dia. Ela utiliza o método myTime de CTimeByHour, que processa os dados horários com base nos eventos de notícias fornecidos em myNews[].
- Primeiro, ela limpa os dados de horário e eventos previamente salvos usando Clear().
- Em seguida, remove todos os dados dos arrays paralelos (myTimeData e myEvents) e define os novos valores por meio da função myTime(), herdada de CTimeByHour.
void SetmyTime(Calendar &myNews[]);
A função abaixo recupera dados de horário para uma hora (myHour) e minuto (myMinute) específicos.
- Primeiro, ela limpa os arrays myTimeData e myEvents.
- Arrays temporários myTData[] e myData[] são declarados para armazenar os dados de horário e eventos.
- GetDataForHour() é chamado para preencher os arrays temporários com os dados da hora especificada.
- Esses dados são então filtrados para o minuto exato por meio de DatePerMinute().
void GetmyTime(HOURLY myHour, MINUTELY myMinute, TimeDate &TimeData[], Calendar &Events[]);
Construtor:
- O construtor inicializa os objetos de array para cada hora do dia (de 1 a 24). Esses objetos armazenarão os dados de horário e eventos correspondentes a cada hora específica.
CTimeByDay(void) { // Initialize array objects for each hour myH1 = new CArrayObj(); myH2 = new CArrayObj(); // (Initializes for all 24 hours) }
CTimeByHour::myTime()
Função definida em CTimeByHour e herdada por CTimeByDay. Ela processa o array myNews[] e associa os eventos a horas específicas do dia.
- Para cada evento em myNews[], são extraídos a hora e o minuto do evento.
- A função utiliza um operador switch para determinar qual objeto de array horário (por exemplo, myH1, myH2 e assim por diante) deverá armazenar os dados de horário e evento.
- Cada evento temporário é adicionado como um objeto CTimeByHour ao respectivo objeto de array.
for(uint i=0; i<myNews.Size(); i++) { datetime Date = datetime(myNews[i].EventDate); HOURLY myHour = CTV.Hourly(CTime.ReturnHour(Date)); MINUTELY myMinute = CTV.Minutely(CTime.ReturnMinute(Date)); // Switch case to handle different hours }
Função Clear()
- A função limpa todos os objetos de array horário (myH1, myH2 e assim por diante), redefinindo os dados de horário armazenados para cada hora.
void CTimeByDay::Clear(void) { // Clears all array objects myH1.Clear(); myH2.Clear(); // (Clears all 24 hours) }
Conclusão
O artigo apresentou métodos para aumentar o desempenho do EA, segmentando os horários dos eventos em arrays separados para cada hora do dia e reduzindo a frequência de acesso ao banco de dados de calendário em memória. Ao estruturar os valores de tempo como enumerações (MINUTELY, SECONDLY), o código torna-se mais fácil de gerenciar e interpretar, reduzindo o risco de erros lógicos.
As enumerações MINUTELY, SECONDLY e PRESECONDLY representam, respectivamente, minutos, segundos e o tempo antes do evento, oferecendo melhor legibilidade e controle sobre os intervalos de tempo. As funções de conversão simplificam o uso de números inteiros como entrada, garantindo sua conversão em valores enumerados significativos. A classe CTimeByHour fornece um mecanismo para armazenar, recuperar e gerenciar dados de horário e eventos para cada hora do dia. Esses métodos serão implementados nas próximas partes da série.
Principais conclusões:
- Acesso eficiente ao banco de dados: Os eventos são carregados apenas uma vez ao dia e mantidos em memória, reduzindo o número de consultas desnecessárias ao banco de dados.
- Segmentação por hora: Ao dividir os eventos em intervalos horários, o EA verifica apenas os eventos relevantes, aumentando a velocidade e diminuindo a carga sobre o processador.
- Escalabilidade: O método proposto é escalável para dias com um grande número de eventos, garantindo desempenho estável durante todo o pregão.
- Maior velocidade de reação: Ao focar apenas nos eventos dentro do intervalo de tempo relevante, o EA consegue reagir mais rapidamente a acontecimentos do mercado, algo essencial para estratégias baseadas em notícias.
Obrigado pela atenção! Até a próxima matéria!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15878
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.





- 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
Olá,
Obrigado por este artigo. Você poderia me ajudar a adicionar um filtro (filter.csv) contendo apenas as notícias que eu gostaria de negociar?
Olá,
Obrigado por este artigo. Você poderia me ajudar a adicionar um filtro (filter.csv) contendo apenas as notícias que eu gostaria de negociar?
Olá Hamid Rabia, Obrigado por seu interesse neste artigo. Esse tópico de filtragem de notícias será abordado nos próximos artigos, mas gostaria que você fosse paciente.