[Erro em obter o tempo do TF sênior no temporizador! - página 15

 
Taras Slobodyanik:

Seu indicador não rastreia a atualização dos dados.
Novas barras estão vindo do corretor e você não as verifica.
Acrescentei algumas linhas para mostrar que quando você verifica, tudo é exibido corretamente.

É uma situação de trabalho - verificar o novo bar.

Você não diz! O que o faz pensar que eu tenho que manter o controle de novos bares? Está escrito na documentação? Quero dizer que devo obter o valor da função, e então devo necessariamente compará-lo com o valor anterior? Há uma função, a função é projetada para trabalhar com prazos altos. A função pode retornar um erro quando não tem dados, ou retornar um valor incorreto (igual a 0, neste caso). Isso é tudo. Os programadores não têm que fazer nada para obter um valor 100% correto.

Mas veja o que eu encontrei na documentação da SeriesInfoInteger():

Para obter mais informações sobre o erro, você precisa chamar a função GetLastError().

Você vê GetLastError() no meu código? Aqui está o cheque. Esta verificação deve ser necessária e REALMENTE necessária! Todo o resto são soluções de muletas.
 
Alexey Kozitsyn:

E você olha para o meu primeiro posto. Você vê o erro 4066 aí? Em seguida, erro 0 e retornar dados incorretos. Por que a função (neste caso, SeriesInfoInteger()) não verifica a relevância antes de enviar os dados? Por que ela não define a bandeira de erro? É que eu prefiro esperar um pouco mais para que as verificações internas passem do que procurar por erros mais tarde.

Mas depois disso, recebi muitos conselhos, com os quais ainda não obtive nenhum resultado. E afinal não se tratava nem mesmo do temporizador.

Ok, leia a ajuda)

SérieInfoInteger

Retorna informações sobre o estado dos dados históricos.

A palavra histórico significa o quê?
Se o histórico for carregado - não há erro.


Alexey Kozitsyn:

De jeito nenhum! E o que o faz pensar que eu deveria necessariamente rastrear novas barras? Está escrito na documentação? Quero dizer, devo obter o valor da função, e então devo necessariamente compará-la com a função anterior? Há uma função, a função é projetada para trabalhar com prazos altos. A função pode retornar um erro quando não tem dados, ou retornar um valor incorreto (igual a 0, neste caso). Isso é tudo. Os programadores não têm que fazer nada para obter um valor 100% correto.

Mas veja o que eu encontrei na documentação da SeriesInfoInteger():

Em meu código veja GetLastError()? Aqui está um cheque. Esta verificação deve ser necessária e REAL! Todo o resto são soluções de muletas.

Você não tem que fazer nada).
...corretor lhe envia dados atualizados - se você quiser, use-os para cálculo, se não - sem problema, use o histórico existente).


ps. é o fim de semana, o mercado está fechado, você tem dados incorretos em seu terminal!
e não há erro!!!!)

 
Taras Slobodyanik:

ok, leia a ajuda)

O que significa a palavra história?
Se o histórico for carregado - não há erro.


Você não deve nada).
...o corretor lhe envia dados atualizados - se você quiser usá-los para calcular, se não - sem problema, use o Histórico)

Cada carrapato que entra no terminal já é uma história. E eu quero obter seus valores reais ou erro. Se isso lhe convém - ok.

 
Alexey Kozitsyn:

Cada carrapato que entra no terminal já é uma história. E eu quero receber seus valores reais ou erro. Se isso lhe convém, tudo bem.

Sim, a história é o que já foi baixado ou o que está sendo baixado no passado.
E o que é atualizado somente agora (após a última citação) não é a história, são os novos dados brutos.

 
Taras Slobodyanik:

Verifique o tempo da vela, não o cálculo das barras.
É assim que ele será atualizado corretamente (verificado).

Taras, aqui está o resultado de seu código:

2018.10.08 11:11:39.080 test_isNewDayInOnCalculate GBPUSD,M1: initialized
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия недельного бара = 2018.09.30 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущей недели = 2018.10.01 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего дня = 2018.10.05 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего дня = 2018.10.05 00:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Время открытия текущего часа = 2018.10.05 23:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: test_isNewDayInOnCalculate.mq4: Актуальное время открытия текущего часа = 2018.10.05 23:00. Ошибка #0
2018.10.08 11:11:39.788 test_isNewDayInOnCalculate GBPUSD,M1: OnCalculate: Данные старших ТФ загружены!
 
Alexey Kozitsyn:

Taras, aqui está o resultado de seu código:

Sim, é o primeiro tick, aquele que produz a história acabada, aquele que está disponível.
Após este tick (se houver novas barras), imediatamente vem o segundo tick, no qual meu código atualiza suas variáveis e elas mostram os dados corretos.

ps. você pode inserir sua própria função para verificar a nova barra, ela será a mesma.

Eu, eu mesmo, verifico constantemente o número de barras, se o número mudou por mais de 1, significa que você precisa recalcular tudo novamente, se o número mudou por 1, significa apenas uma nova barra. E eu verifico apenas os erros mais críticos, e não vejo este atraso-erro.

 
Taras Slobodyanik:

Sim, este é o primeiro tique, aquele que dá a história pronta.
Após este tick (se houver novas barras), imediatamente vem o segundo tick, no qual meu código atualiza suas variáveis e elas mostram os dados corretos.

Pc. você pode inserir sua própria função para verificar a nova barra, ela será a mesma.

Eu, eu mesmo, verifico constantemente o número de barras, se o número mudou por mais de 1, significa que você precisa recalcular tudo novamente, se o número mudou por 1, significa apenas uma nova barra. E eu verifico apenas os erros mais críticos, e não vejo este atraso-erro.

E aqui, a propósito, há outro argumento a favor de que o erro aconteça. É ERROR no cálculo no indicador! Eu escrevi um consultor especializado:

#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//--- Время открытия текущего часа, дня и недели
datetime _weekOpenTime = 0;
datetime _hourOpenTime = 0;
datetime _dayOpenTime=0;
//--- Вести лог журнала
const bool inpFileLog=true;
//--- Количество секунд в одном дне
const int SEC_PER_DAY=86400;
//--- Флаг работоспособности индикатора
bool _isWorking=true;
//--- Флаг соединения с торговым сервером (для таймера, получаем в OnCalculate())
bool _isConnected=false;
//---
bool _firstLaunch = true;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Устанавливаем флаг первого запуска
   _firstLaunch = true;
//--- Сбрасываем время открытия текущего часа, дня и недели
   _weekOpenTime= 0;
   _dayOpenTime = 0;
   _hourOpenTime= 0;
//--- Устанавливаем флаг работоспособности
   _isWorking=true;
//--- Сбрасываем флаг установки соединения
   _isConnected=false;
////--- Запускаем таймер
//   if(!EventSetMillisecondTimer(20))
//     {
//      Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": таймер с частотой 20 не установлен!");
//      //--- Устанавливаем флаг неработоспособности индикатора
//      _isWorking=false;
//     }
//--- Запрос данных
   SeriesInfoInteger(_Symbol,PERIOD_W1,SERIES_LASTBAR_DATE);
   SeriesInfoInteger(_Symbol,PERIOD_D1,SERIES_LASTBAR_DATE);
   SeriesInfoInteger(_Symbol,PERIOD_H1,SERIES_LASTBAR_DATE);
//---
   return( INIT_SUCCEEDED );
  }
//+------------------------------------------------------------------+
//|                                                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
////--- Выключаем таймер
//   EventKillTimer();
  }
////+------------------------------------------------------------------+
////|                                                                  |
////+------------------------------------------------------------------+
//void OnTimer()
//  {
////---
//   if(!_isWorking)
//      return;
////---
//   if(!_isConnected)
//      return;
////---
//   Print(__FUNCTION__,": Данные старших ТФ загружены!");
////--- Отключаем таймер
//   EventKillTimer();
//  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Проверяем связь с сервером
   if(!IsConnected())                              // Если не удалось установить связь с сервером
     {
      //--- Сбрасываем флаг соединения с сервером
      _isConnected=false;
      //--- Выходим
      return;
     }
        //--- Проверяем первый запуск эксперта
        if( _firstLaunch )
                {
            //--- Проверяем, записано ли время открытия текущей недели
            if(!CheckCurrentWeekOpenTime())                              // Если время не записано
              return;                                                // Выходим
            //--- Проверяем, записано ли время открытия текущего дня
            if(!CheckCurrentDayOpenTime())                              // Если время не записано
              return;                                                // Выходим
            //--- Проверяем, записано ли время открытия текущего часа
            if(!CheckCurrentHourOpenTime())                              // Если время не записано
              return;                                                // Выходим
            ////--- Устанавливаем флаг соединения с сервером для запуска таймера
            //_isConnected=true;
            //---
            Print(__FUNCTION__,": Данные старших ТФ загружены!");
            //--- Сбрасываем флаг первого запуска
            _firstLaunch = false;
                }
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
bool CheckCurrentWeekOpenTime()
  {
//--- Проверяем, записано ли время
   if(_weekOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия недельного бара
      ResetLastError();
      const datetime weekBarOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_W1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия недельного бара = "+TimeToString(weekBarOpenTime)+". Ошибка #",err);
        }
      //--- Проверяем, получено ли время открытия недельного бара
      if(weekBarOpenTime==0 || err!=0) // Если время бара не получено или история обновляется
         return(false);                              // Возвращаем ложь
      //--- Запоминаем время открытия текущей недели (время открытия недельного бара - воскресенье)
      _weekOpenTime=weekBarOpenTime+SEC_PER_DAY;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущей недели = "+TimeToString(_weekOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия недели ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего дня                  |
//+------------------------------------------------------------------+
bool CheckCurrentDayOpenTime()
  {
//--- Проверяем, записано ли время
   if(_dayOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия дневного бара
      ResetLastError();
      const datetime tempDayOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_D1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего дня = "+TimeToString(tempDayOpenTime)+". Ошибка #",err);
        }
      //--- Проверяем, получено ли время открытия дневного бара
      if(tempDayOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //--- Сохраняем в глобальную переменную значение открытия текущего дня
      _dayOpenTime=tempDayOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего дня = "+TimeToString(_dayOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия дня ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего часа              |
//+------------------------------------------------------------------+
bool CheckCurrentHourOpenTime()
  {
//--- Проверяем, записано ли время
   if(_hourOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия часового бара
      ResetLastError();
      const datetime tempHourOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_H1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего часа = "+TimeToString(tempHourOpenTime)+". Ошибка #",err);
        }
      //--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //---
      _hourOpenTime=tempHourOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего часа = "+TimeToString(_hourOpenTime)+". Ошибка #",err);
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия часа ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+

Funciona a partir do mesmo gráfico que o indicador. Vamos ver os resultados:

2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: OnTick: Данные старших ТФ загружены!
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущего часа = 2018.10.09 06:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия текущего часа = 2018.10.09 06:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущего дня = 2018.10.09 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия текущего дня = 2018.10.09 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Актуальное время открытия текущей недели = 2018.10.08 00:00. Ошибка #0
2018.10.09 08:45:42.627 test_isNewDayInOnTick GBPUSD,M1: test_isNewDayInOnTick.mq4: Время открытия недельного бара = 2018.10.07 00:00. Ошибка #0
2018.10.09 08:45:41.479 test_isNewDayInOnTick GBPUSD,M1: initialized

2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentHourOpenTime: Время открытия текущего часа = 2018.10.08 11:00
2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentDayOpenTime: Время открытия текущего дня = 2018.10.08 00:00
2018.10.09 08:45:40.822	GBPUSD,M1: CheckCurrentWeekOpenTime: Время открытия текущей недели = 2018.10.08 00:00
2018.10.09 08:45:40.064	GBPUSD,M1: initialized

2018.10.09 08:45:40.022 Expert Other\test_isNewDayInOnTick GBPUSD,M1: loaded successfully

O que vemos. Vemos que tudo está bem. Todos carregados, e note que não há erros, os dados são imediatamente atualizados! A questão principal é por que os dados GMT podem ser obtidos normalmente, enquanto o indicador deve "brincar com os diamantes"? Os programas não deveriam funcionar igualmente? Por que o mesmo código funciona de maneira diferente em um indicador e em um Expert Advisor? Este não deve ser o caso.

 
Alexey Kozitsyn:

E aqui, a propósito, há outro argumento a favor da ocorrência de um erro. É o ERROR no cálculo no indicador! Escrevi um consultor especializado:

Funciona a partir do mesmo gráfico que o indicador. Vamos ver os resultados:

O que vemos. Vemos que tudo está bem. Todos carregados, e note que não há erros, os dados são imediatamente atualizados! A questão principal é por que os dados GMT podem ser obtidos normalmente, enquanto o indicador deve "brincar com os diamantes"? Os programas não deveriam funcionar igualmente? Por que o mesmo código funciona de maneira diferente em um indicador e em um Expert Advisor? Este não deve ser o caso.

Todos os indicadores estão em um único fio, e nada de novo acontecerá até o final do fluxo (na verdade, até a próxima chamada da OpsulCalcuter). O Expert Advisor está em sua própria linha separada, portanto, quando inicia, é permitido adiar sua partida para atualizações de dados, atualizar dados - tudo o mais no terminal não é afetado. Tem sido assim desde o nascimento e não há como consertá-lo, pois o ambiente do metatrader4 foi enterrado.

 
Unicornis:

Como cabe ao terminal conectar e fazer algo com o carregamento, verificação, etc., todos os indicadores estão em uma única linha, e nada de novo acontece até que tudo na linha termine (na verdade, até a próxima chamada do OpCalculate), ou seja, estando nesta linha, você não receberá nada mais rápido do que o final da linha de qualquer maneira. O Expert Advisor está em sua própria linha separada, portanto, quando inicia, é permitido adiar seu início para atualizações de dados, atualizar dados - tudo o mais no terminal não é afetado. Tem sido assim desde o nascimento e não há como consertá-lo, pois o ambiente do metatrader4 foi enterrado.

Estou ciente do fato de que todos os indicadores de um símbolo estão em um fio enquanto cada especialista tem seu próprio fio. Mas este não é o caso. Os desenvolvedores são os próprios desenvolvedores que corrigem erros em suas criações. Os programas não devem funcionar de maneira diferente! Se os indicadores falharam alguma coisa, é um erro e não há problema. O Expert Advisor recebeu, de alguma forma, os dados corretos sem erros! Assim, podemos implementá-lo. @Slava, você pode dar sua opinião sobre se o comportamento obviamente errôneo será corrigido? Ou, pelo menos, adição de documentação (que com pré-cálculo = 0 não é possível obter dados corretos de TFs sênior)?

 
Alexey Kozitsyn:

Sim, estou ciente de que todos os indicadores de um símbolo estão em um fio, e um fio diferente é atribuído a cada especialista. Mas este não é o caso. Os desenvolvedores são os desenvolvedores que corrigem erros em suas criações. Os programas não devem funcionar de maneira diferente! Se os indicadores falharam alguma coisa, é um erro e não há problema. O Expert Advisor recebeu, de alguma forma, os dados corretos sem erros! Assim, podemos implementá-lo. @Slava, você pode dar sua opinião sobre se o comportamento obviamente errôneo será corrigido? Ou pelo menos é um acréscimo à documentação (que não podemos obter dados corretos de alta TF quando pré_calculados = 0)?

A documentação diz que o Expert Advisor tem até 5 segundos antes de começar a receber dados e durante esse tempo o terminal tenta receber dados para o Expert Advisor. O indicador não recebe tal possibilidade e da mesma forma que não deve solicitar atualização do histórico, não é crítico para ele, se for crítico, então deve ser calculado em um Consultor Especialista. A idéia principal é que a situação desejada não é possível na implementação atual. Basicamente, os TFs são temporizadores e há períodos em que estes múltiplos temporizadores coincidem em um momento - este é um processo 100% coincidente (exceto o tempo de abertura/fecho), porque o primeiro tique do minuto do TF atual coincide com o primeiro minuto de cinco minutos, hora, etc. - é simplesmente escrever o mesmo valor em várias variáveis, e é lógico definir um conjunto de TFs necessários e obter todos os dados necessários de uma só vez. Não sei por que os desenvolvedores fizeram isso e não o contrário, não sei. Talvez, isso não possa (não será) feito no modelo de operação do terminal existente por causa da divisão cliente-servidor, como se agora permitirmos que os especialistas usem indicadores, eles irão pendurar o terminal.

Você pode ver no final do dia, se estiver interessado, como funciona a chamada de indicador, indicador chama outro indicador, indicador de chamada de especialista(_asktfexp)(_asktf_sample) indicador de chamada(_asktf). Ao chamar um indicador de um especialista, o timer no indicador não começará, portanto as soluções com um timer no indicador são apenas para os casos em que este indicador só ficará pendurado no gráfico e não será chamado (o que é lógico em geral).

Arquivos anexados: