Como Ignorar os Fins de Semana e o Futuro em Datetime

 

Oi pessoal! Tem uma parte do meu código que pede ao usuário para estabelecer um limite de análise temporal dos candles, o que irá fornecer dados para CopyTime, CopyClose etc.
Durante a semana tudo parecia funcionar bem, mas quando chegou no fim de semana os dados datetime  apontaram para a abertura do mercado na semana seguinte o que gerou uma série de erros na coleta de dados para a análise.


Por exemplo, o usuário fornece o horário de início da análise:

O usuário fornece Hora: 20

O usuário fornece Minutos: 15

Resultado do primeiro resultado em CopyTime durante a semana: AnoAtual.MêsAtual,DiaAtual 20:15:00

Resultado do primeiro resultado em CopyTime no fim de semana: AnoAtual.MêsAtual,DiadaSemanaSeguinte 23:24 (???)


O processo que eu sigo é simples: eu concateno como string os dois valores fornecidos pelo usuário e depois converto com a função StringToTime e o Metatrader 5 automaticamente entende que a hora fornecida se refere ao dia atual. NO ENTANTO, quando chega no fim de semana ele joga para frente e não tenho como trabalhar no código a não ser que forneça uma data específica.


Alguma solução para o MT5 considerar apenas os dias úteis nas funções CopyTime, CopyClose etc? No caso, se estivesse no fim de semana, ele consideraria a sexta-feira.

 
israeltandrade:

Oi pessoal! Tem uma parte do meu código que pede ao usuário para estabelecer um limite de análise temporal dos candles, o que irá fornecer dados para CopyTime, CopyClose etc.


Alguma solução para o MT5 considerar apenas os dias úteis nas funções CopyTime, CopyClose etc? No caso, se estivesse no fim de semana, ele consideraria a sexta-feira.

Olá Israel,

hummm  não caiu a ficha.... faz um script do código demostrando o erro e cola aqui.

 
israeltandrade:

Oi pessoal! Tem uma parte do meu código que pede ao usuário para estabelecer um limite de análise temporal dos candles, o que irá fornecer dados para CopyTime, CopyClose etc.
Durante a semana tudo parecia funcionar bem, mas quando chegou no fim de semana os dados datetime  apontaram para a abertura do mercado na semana seguinte o que gerou uma série de erros na coleta de dados para a análise.


Por exemplo, o usuário fornece o horário de início da análise:

O usuário fornece Hora: 20

O usuário fornece Minutos: 15

Resultado do primeiro resultado em CopyTime durante a semana: AnoAtual.MêsAtual,DiaAtual 20:15:00

Resultado do primeiro resultado em CopyTime no fim de semana: AnoAtual.MêsAtual,DiadaSemanaSeguinte 23:24 (???)


O processo que eu sigo é simples: eu concateno como string os dois valores fornecidos pelo usuário e depois converto com a função StringToTime e o Metatrader 5 automaticamente entende que a hora fornecida se refere ao dia atual. NO ENTANTO, quando chega no fim de semana ele joga para frente e não tenho como trabalhar no código a não ser que forneça uma data específica.


Alguma solução para o MT5 considerar apenas os dias úteis nas funções CopyTime, CopyClose etc? No caso, se estivesse no fim de semana, ele consideraria a sexta-feira.

O tipo MqlDate tem um campo que é o dia da semana, só validar. Domingo começa em 1 e sábado é 7. 
 
//+------------------------------------------------------------------+
//| DECLARAÇÃO DE ENUMERAÇÕES                                        |
//+------------------------------------------------------------------+
enum HORA
  {
   UMA            	= 01,    //01
   DUAS           	= 02,    //02
   TRES           	= 03,    //03
   QUATRO         	= 04,    //04
   CINCO          	= 05,    //05
   SEIS           	= 06,    //06
   SETE           	= 07,    //07
   OITO          	= 08,    //08
   NOVE          	= 09,    //09
   DEZ            	= 10,    //10
   ONZE		  	= 11,    //11
   DOZE           	= 12,    //12
   TREZE          	= 13,    //13
   QUATORZE       	= 14,    //14
   QUINZE         	= 15,    //15
   DEZESSEIS      	= 16,    //16
   DEZESSETE      	= 17,    //17
   DEZOITO        	= 18,    //18
   DEZENOVE       	= 19,    //19
   VINTE          	= 20,    //20
   VINTE_E_UM     	= 21,    //21
   VINTE_E_DOIS   	= 22,    //22
   VINTE_E_TRES   	= 23,    //23
   VINTE_E_QUATRO 	= 24     //24
  };

enum MINUTO
  {
   ZERO_M               = 00,    //00
   QUINZE_M             = 15,   //15
   TRINTA_M             = 30,   //30
   QUARENTA_E_CINCO_M   = 45    //45
  };

//+------------------------------------------------------------------+
//| DECLARAÇÃO DE VARIÁVEIS INPUT                                    |
//+------------------------------------------------------------------+
input  HORA     horaInicio_analise          = VINTE;                    //Horário de Início da Análise
input  MINUTO   minutoInicio_analise        = QUINZE_M;                 //Minuto de Início da Análise
input  HORA     horaFim                     = VINTE;                    //Horário de FIM das Operações
input  MINUTO   minutoFim                   = QUARENTA_E_CINCO_M;       //Minuto de FIM das Operações

//+------------------------------------------------------------------+
//| DECLARAÇÃO DE VARIÁVEIS E ARRAYS GLOBAIS                                  |
//+------------------------------------------------------------------+
//--- Concatenação do horário de início da análise
string         horarioInicio_conc = IntegerToString(horaInicio_analise) + ":" + IntegerToString(minutoInicio_analise);

//--- Concatenação do horário de fim das operações
string         horarioFim_conc = IntegerToString(horaFim) + ":" +  IntegerToString((minutoFim);

//--- Declaração de Array tipo data e hora que armazenará o período dos candles a serem analisados
datetime       periodoCandles[];

//+------------------------------------------------------------------+
//| FUNÇÃO DE INICIALIZAÇÃO DO EA                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Função de criação de timer
   EventSetTimer(1);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| FUNÇÃO DE REMOÇÃO DO EA                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   //--- Desmontar o timer
   EventKillTimer();
  }

//+------------------------------------------------------------------+
//| FUNÇÃO DE MOVIMENTAÇÃO DO PREÇO                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
    
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   //--- Declaração de Variável para calcular a diferença de tempo entre o início da análise e o fim das operações
   int diferencaTempo = 60;
   
   //--- Função que retornará o tempo de fechamento dos candles de acordo com o tempo estabelecido na Função e Array anteriores   
   CopyTime(_Symbol,_Period,StringToTime(horarioInicio_conc),diferencaTempo,periodoCandles);

   //--- Função que irá imprimir na tela os dados armazenados no Array periodoCandles
   ArrayPrint(periodoCandles,Digits(),NULL,0,WHOLE_ARRAY,ARRAYPRINT_MINUTES);

Deveria apresentar uma hora de análise no Timeframe M1.

Durante a semana os horários começam do local correto, nos fins de semana ele projeta para segunda-feira e o horário fica errado.

Coloquei aqui apenas o que acredito ser necessário para o que estou comentando, tem outras coisas que não tem relação direta com o problema (tanto que o algorítmo funciona mesmo quando estas últimas são transformadas em comentário).

 
Jonathan Pereira:
O tipo MqlDate tem um campo que é o dia da semana, só validar. Domingo começa em 1 e sábado é 7. 

No caso eu criaria uma função condicional? Onde eu faria essa validação? (desculpe a ignorância, estou começando em programação)

Um palpite... Seria na variável periodoCandles? (ao invés de uma variável simples datetime) Mas nesse caso, como permitir a entrada de hora apenas e ao mesmo tempo estabelecer uma validação restrita de dias de semana? (no caso, quando fosse sábado ou domingo, gostaria que o EA trabalhasse o dia de sexta-feira e não ficasse tentando prever o futuro, num possível e futuro backing test, ele simplesmente ignoraria os finais de semana)

 
israeltandrade:


Sim agora entendi sua dúvida,  você esqueceu apenas de ler o manual:

Existe três variações para chamanda de COPYTIME() e você está usando a segunda.

CopyTime

Ao solicitar dados através da data de início e do número de elementos requeridos, somente dados cuja data seja menor (anterior) ou igual a data especificada são retornados. Isso significa que a hora de abertura de qualquer barra, para cujo valor é retornado (volume, spread, valor no buffer de indicador, preços de Abertura, Máximo, Mínimo, Fechamento ou Hora de Abertura) é sempre menor ou igual ao valor especificado.

Quando não tem cotação ( Feriados e finais de semana) seu código ira buscar 60 barras anteriores a hora 20:15.

Eu simplifiquei o código para você rodar verificar rapidamente o resultado das 3 variantes.


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
input  string     horarioInicio = "20:15";
input  string     horarioFim = "22:00";
input  int        qtdBarras = 60;
datetime          periodoCandles[];
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   ZeroMemory(periodoCandles);
   Print("\nVariante (01):  Copiar as últimas ", qtdBarras, " barras");
   if(CopyTime(_Symbol, _Period, 0, qtdBarras, periodoCandles) > 0)
      ArrayPrint(periodoCandles, Digits(), NULL, 0, WHOLE_ARRAY, ARRAYPRINT_HEADER | ARRAYPRINT_INDEX | ARRAYPRINT_LIMIT | ARRAYPRINT_ALIGN);
   ZeroMemory(periodoCandles);
   Print("\nVariante (02):  Copiar as últimas ", qtdBarras, " barras anteriores a: ", StringToTime(horarioInicio));
   if(CopyTime(_Symbol, _Period, StringToTime(horarioInicio), qtdBarras, periodoCandles) > 0)
      ArrayPrint(periodoCandles, Digits(), NULL, 0, WHOLE_ARRAY, ARRAYPRINT_HEADER | ARRAYPRINT_INDEX | ARRAYPRINT_LIMIT | ARRAYPRINT_ALIGN);
   ZeroMemory(periodoCandles);
   Print("\nVariante (03):  Copiar as barras entre: ",  StringToTime(horarioInicio), "  e  ", StringToTime(horarioInicio));
   Print("Inicio: ", StringToTime(horarioInicio), "   Fim: ", StringToTime(horarioInicio));
   if(CopyTime(_Symbol, _Period, StringToTime(horarioInicio), StringToTime(horarioFim), periodoCandles) > 0)
      ArrayPrint(periodoCandles, Digits(), NULL, 0, WHOLE_ARRAY, ARRAYPRINT_HEADER | ARRAYPRINT_INDEX | ARRAYPRINT_LIMIT | ARRAYPRINT_ALIGN);
  }
//+------------------------------------------------------------------+
 
israeltandrade:

No caso eu criaria uma função condicional? Onde eu faria essa validação? (desculpe a ignorância, estou começando em programação)

Um palpite... Seria na variável periodoCandles? (ao invés de uma variável simples datetime) Mas nesse caso, como permitir a entrada de hora apenas e ao mesmo tempo estabelecer uma validação restrita de dias de semana? (no caso, quando fosse sábado ou domingo, gostaria que o EA trabalhasse o dia de sexta-feira e não ficasse tentando prever o futuro, num possível e futuro backing test, ele simplesmente ignoraria os finais de semana)

eu havia dito algo como isso:

void OnStart()
 {
//---
  MqlDateTime teste;
  TimeTradeServer(teste);
  Print("dia da semana: ", teste.day_of_week);
 }

Mas a resposta do @Rogerio Giannetti Torres é muito mais elaborada e provavelmente muito mais próximo do que vc esta tentando fazer.

 
Rogerio Giannetti Torres:

Sim agora entendi sua dúvida,  você esqueceu apenas de ler o manual:

Existe três variações para chamanda de COPYTIME() e você está usando a segunda.

CopyTime

Ao solicitar dados através da data de início e do número de elementos requeridos, somente dados cuja data seja menor (anterior) ou igual a data especificada são retornados. Isso significa que a hora de abertura de qualquer barra, para cujo valor é retornado (volume, spread, valor no buffer de indicador, preços de Abertura, Máximo, Mínimo, Fechamento ou Hora de Abertura) é sempre menor ou igual ao valor especificado.

Quando não tem cotação ( Feriados e finais de semana) seu código ira buscar 60 barras anteriores a hora 20:15.

Eu simplifiquei o código para você rodar verificar rapidamente o resultado das 3 variantes.


Oi! Muito obrigado pela resposta.

Na verdade eu havia lido o manual sobre essa função e conferi alguns tópicos aqui no fórum antes de colocar minha dúvida. Eu havia feito várias tentativas com as variações de entrada (inclusive já havia utilizado as três que compartilhou), mas não obtive sucesso com os horários que eram apresentados, por isso vim perguntar aqui.

A terceira variante era a que eu já imaginava ser a que atende aos meus propósitos, e, aqui no horário local 08:30 (horário do servidor 14:30) ela não atende o critério do if do script que compartilhou, portanto não apresenta resultados. No entanto, se eu mudo o horário para barras já presentes no gráfico do dia (por exemplo 14:00 e 14:30), funciona normalmente. A novidade aqui foi a função ZeroMemory que, se não estou enganado, é a responsável por não mostrar resultados caso esteja fora do horário (antes ele buscava o fim de semana anterior).

Obrigado pelos apontamentos! Agora me resta colocar uma condição para que, quando isso ocorrer, o Script/EA irá buscar no último dia útil anterior que contenha o horário estabelecido. Apenas para fins de teste de programação (tem muita coisa ainda a ser desenvolvida no meu projeto), para backing test, ausência de valores é perfeito.
 
Jonathan Pereira:

eu havia dito algo como isso:

Mas a resposta do @Rogerio Giannetti Torres é muito mais elaborada e provavelmente muito mais próximo do que vc esta tentando fazer.

Muito obrigado pela respota!

É um outro caminho interessante para verificar a validade do período de análise. Vou focar na função MqlDateTime para estabelecer um ajuste diário como comentei acima.

 

Hoje (sábado 05:50 da manhã), fiz o seguinte teste:

datetime   periodoCandles[];

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ZeroMemory(periodoCandles);
   
   //--- Função que retornará o tempo de fechamento dos candles de acordo com o tempo estabelecido na Função e Array anteriores   
   if(CopyTime(_Symbol,_Period,StringToTime("21:05"),5,periodoCandles) > 0)
   
   ArrayPrint(periodoCandles, Digits(), NULL, 0, WHOLE_ARRAY, ARRAYPRINT_HEADER | ARRAYPRINT_INDEX | ARRAYPRINT_LIMIT | ARRAYPRINT_ALIGN);
  }

Obtendo os seguintes resultados:

2020.07.10 23:50:00 2020.07.10 23:51:00 2020.07.10 23:52:00 2020.07.10 23:53:00 2020.07.10 23:54:00


Note que eles não tem nada a ver com o horário que coloquei. O que houve de errado?

 
israeltandrade:

Hoje (sábado 05:50 da manhã), fiz o seguinte teste:

Obtendo os seguintes resultados:

2020.07.10 23:50:00 2020.07.10 23:51:00 2020.07.10 23:52:00 2020.07.10 23:53:00 2020.07.10 23:54:00


Note que eles não tem nada a ver com o horário que coloquei. O que houve de errado?

olhando por cima me parece errada a sua chamada, olhei a documentação e notei que vc esta sobrecarregando a função com a segunda variante.

int  CopyTime(
   string           symbol_name,     // nome do ativo
   ENUM_TIMEFRAMES  timeframe,       // período
   datetime         start_time,      // data e hora de início
   int              count,           // quantidade de dados para copiar
   datetime         time_array[]     // array destino para copiar horas de abertura
   );
Razão: