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

 
Ihor Herasko:

Sim, exatamente. No OnInit() você simplesmente chama os TFs necessários sem verificar o resultado (você não pode confiar nele), e no OnCalculate chama a função IsTFDataReady(). Uma vez que a verdade seja devolvida para todos os TFs solicitados, você pode começar a executar o algoritmo do indicador.

Ok, já resolvemos o problema. Mas devemos claramente adicionar a documentação, caso contrário o cronômetro rápido causará muitas perguntas aos desenvolvedores.

 
Ihor Herasko:

Em geral, que tipo de problema está sendo resolvido para o qual a presença de uma conexão terminal é tão crucial? Meu entendimento do indicador é que ele é uma ferramenta de visualização de dados. Os dados que estão disponíveis. Quando novos dados chegarem, ele atualizará a visualização. Não deve ser exigido que se verifique a relevância dos dados. Esta é a tarefa do terminal.

A tarefa é obter os dados da TF sênior o mais rápido possível.Vitaly Gorbunov me lembrou sobre IsConnected().

 
Alexey Kozitsyn:

Oh, cara... Já passamos desse ponto. Veja seu próprio diário de bordo:

Sequência. Primeiro verificamos a conexão. Uma vez estabelecida a conexão, temos tempo para isso. Explique-me, por favor, por que diabos o erro 4066 voltou primeiro e depois não voltou!? O que mudou em 20ms desde a última chamada?

Erro 4066 diz que não há dados, pedido de atualização enviado.

Uma vez enviado o pedido, outro pedido não é mais enviado, portanto o erro 4066 não tem mais efeito. Isto já foi discutido muitas vezes.

Por que você inicia um temporizador no indicador? É tão pequeno. Você tem que entender que no MT4 os indicadores são executados em um fio de interface. O fio da interface é para onde vão todas as mensagens de vento

 
Slava:

O erro 4066 indica que não há dados, um pedido de atualização foi enviado.

Uma vez enviado um pedido, outro pedido não é mais enviado, portanto, o erro 4066 não é levantado. Isto já foi discutido muitas vezes.

Por que você inicia um temporizador em um indicador? É tão pequeno. Você deve entender que no MT4 os indicadores funcionam no fio da interface. Todas as mensagens de vento passam pelo fio da interface

Ainda bem que você se juntou à discussão.

Não é o meu primeiro dia no fórum + várias pessoas comentaram aqui que também não são o primeiro dia no fórum. Ninguém disse nada a respeito:

Uma vez enviado um pedido, outro pedido não é mais enviado, portanto o erro 4066 não é mais acionado. Isto já foi discutido muitas vezes.

Obrigado, nós saberemos. Gostaria muito de ver isto na ajuda. Então, certamente o erro só é "levantado" quando ocorre o evento OnTick()/OnCalculate()?

Por que você inicia o temporizador no indicador? É tão pequeno.

Você precisa obter dados de alguns caracteres. O mais rápido possível. Infelizmente, nem o MT4 nem o MT5 implementaram eventos de recebimento de citações de qualquer símbolo (é impossível subscrever tal atualização), portanto a única saída (tanto quanto sei) é interrogar os símbolos necessários no cronômetro.

Você deve entender que no MT4 os indicadores funcionam no fio da interface. Todas as mensagens de vento passam pelo fio da interface

OK, eles estão vindo, mas e depois? Você pode explicar como isso é ruim/bom/ como isso afeta a operação do temporizador?
 

Tem sido discutido muitas vezes. 12 páginas por pedido "erro 4066".

E você foi corretamente aconselhado a enviar o pedido no OnInit e analisá-lo no OnCalculate.

Para que você precisa deum temporizador de milissegundos? Você está impedindo que o terminal do cliente inicie normalmente. Não são as mensagens de vento que interferem no seu timer, é o seu timer que interfere com todos. Mais uma vez: OS INDICADORES NO TRABALHO TERMINAL MT4 DO CLIENTE EM POTENCIAL INTERFACE.

 
Slava:

Tem sido discutido muitas vezes. 12 páginas em "erro 4066".

Leia-o, obrigado. Somente com o trabalho em OnCalculate() ou OnTick() não há problema, o problema está em OnTimer(). E a pedido "erro 4066 timer" obtive resultados somente deste ramo :(

E você foi corretamente aconselhado a enviar um pedido ao OnInit e analisá-lo no OnCalculate.

Ouvi os conselhos, mas isso não muda as peculiaridades do manuseio do temporizador que não são mencionadas na documentação.

Por que você precisa de um temporizador de milissegundos? Você está impedindo o terminal do cliente de subir normalmente por suas ações. Não são as mensagens de vento que interferem no seu timer, é o seu timer que interfere com o de todos os outros. Mais uma vez: OS INDICADORES NO TERMINAL MT4 DO CLIENTE TRABALHAM EM BOLSAS DE INTERFACE.

Mais uma vez, o timer de milissegundos é para obter informações de vários símbolos o mais rápido possível! Isto é, o algoritmo é o seguinte: o indicador é carregado, recebe dados de TFs altos o mais rápido possível, depois monitora bits dos símbolos necessários no temporizador de milissegundos. Existe alguma outra maneira de resolver o problema de monitoramento além de usar o temporizador?

Vamos resumir tudo o que foi escrito aqui, corrijam-me se eu estiver errado:

1. Tarefa: obter citações para vários símbolos através de um temporizador:

Implementação: Ao trabalhar com um timer de alta freqüência, você tem que esperar que IsConnected() seja estabelecido com o servidor em OnCalculate() ao carregar o terminal, somente então você pode acessar o timer;

2. Objetivo: obter dados dos TFs superiores o mais rápido possível após o início do indicador (o indicador usa temporizador rápido);

Implementação: primeiro solicitamos os dados necessários em OnInit(), depois esperamos a conexão IsConnected() em OnCalculate(), depois obtemos dados das TFs superiores também em OnCalculate();

3. Iniciar um temporizador de alta freqüência retarda o fio da interface e, conseqüentemente, o computador, e é melhor não iniciar de forma alguma? Como resolver a tarefa nº 1 então?

4. Objetivo: carregar dados reais de TFs mais antigos.

Implementação: não usar temporizador de alta freqüência para isso, já que as funções de recuperação de dados não são projetadas para funcionar em um temporizador desse tipo? Usamos apenas OnCalculate()?

5. Caso um erro 4066 seja recebido e depois reiniciado, a OnCalculate() o arma em cada carrapato?

6. O OnTimer() no MT5 não funciona em linha de interface?

@Slava, por favor, responda também ponto por ponto;

 

1. Normalmente, você terá o estado IsConnected na segunda chamada para a OnCalculate. Primeira chamada imediatamente após o início do terminal, segunda chamada na chegada dos dados históricos

2. Não usar temporizador rápido. Primeiro avalie qual é o momento aceitável para você. Pode ser de 100 milissegundos ou 500. Não foi por acaso que introduzimos originalmente o temporizador de segundos, SetMillisecondsTimer foi introduzido em cinco(!) apenas 3 ou 4 anos mais tarde. Mas a arquitetura é diferente em cinco.

3.1 Obtenha um computador potente que possa lidar com filas de mensagens instantâneas.

3.2 Não lance o temporizador de milissegundos imediatamente, mas pelo menos após o primeiro OnCalculate. Ou melhor: no primeiro OnCalculate iniciar um segundo timer (caso não haja conexão ou o dia de folga), para que você possa analisar o ambiente. E então, quando você tiver certeza de que todos os dados estão carregados, há uma conexão e tudo está bem, mate o segundo timer e inicie o timer de milissegundos. Então você saltará com segurança pela estreita porta frontal. No melhor dos casos (e haverá 99 por cento deles) você perderá de 2 a 5 segundos no início

4. Um temporizador é possível. Mas não imediatamente (ver 3.2). E eu acho que 50 milissegundos é suficiente. Você não está fornecendo o HFT, está?

5. 4066 só aparece na primeira solicitação de dados sobre o período de outra pessoa - o personagem. No próximo pedido para o mesmo período de caracteres 4066 não receberá mais

6. No MT5, os indicadores são contados em um fio de processamento de símbolos separado. Portanto, se você tiver mais de um gráfico neste símbolo (ou se houver outros indicadores neste símbolo), você pode desacelerá-los. Mas ainda assim não é um fio de interface

 
Slava:

1. Normalmente, você terá o estado IsConnected na segunda chamada para a OnCalculate. Primeira chamada imediatamente após o início do terminal, segunda chamada na chegada dos dados históricos

2. Não usar temporizador rápido. Primeiro avalie qual é o momento aceitável para você. Pode ser de 100 milissegundos ou 500. Não foi por acaso que introduzimos originalmente o temporizador de segundos, SetMillisecondsTimer foi introduzido em cinco(!) apenas 3 ou 4 anos mais tarde. Mas a arquitetura é diferente em cinco.

3.1 Obtenha um computador potente que possa lidar com filas de mensagens instantâneas.

3.2 Não lance o temporizador de milissegundos imediatamente, mas pelo menos após o primeiro OnCalculate. Ou melhor: no primeiro OnCalculate iniciar um segundo timer (e se não houver conexão ou o dia de folga), para que você possa analisar o ambiente. E então, quando você tiver certeza de que todos os dados estão carregados, há uma conexão e tudo está bem, mate o segundo timer e inicie o timer de milissegundos. Então você conseguirá atravessar com segurança a estreita porta frontal. No melhor dos casos (e haverá 99 por cento deles) você perderá de 2 a 5 segundos no início

4. Um temporizador é possível. Mas não imediatamente (ver 3.2). E eu acho que 50 milissegundos é suficiente. Você não está fornecendo o HFT, está?

5. 4066 só aparece na primeira solicitação de dados sobre o período de outra pessoa - o personagem. Na próxima solicitação para o mesmo personagem do período, você não receberá 4066 novamente.

6. No MT5, os indicadores são contados em um fio de processamento de símbolos separado. Portanto, se você tiver mais de um gráfico neste símbolo (ou se houver outros indicadores neste símbolo), você pode desacelerá-los. Mas ainda assim não é um fio de interface

1. é exatamente assim que funciona;

2. É aqui que reside o problema. Quanto mais rápido, melhor. E a avaliação foi feita. O indicador é escrito para arbitragem (ou melhor, pesquisa sobre arbitragem), ou seja, cada milissegundo é importante e quanto mais rápido uma cotação for recebida - melhor;

3.1. e agora o sistema é bastante poderoso: CPU 8600k, terminais SSD, 16gb DDR4 RAM;

3.2. uau... ok, tomei nota;

4. A tarefa de arbitragem está muito provavelmente relacionada ao HFT;

5. Inicialmente, isto era exatamente o que me estava estressando. Se eu tivesse continuado a receber o erro e soubesse que os dados ainda não estavam prontos, este tópico não teria acontecido;

6. Estou vendo.

Obrigado pela elaborada resposta.

 
Igor Makanu:

Se não for muito incômodo, aqui está o tópico do tópico - carregamento correto do histórico do TF mais velho, aqui está o indicador: "Eu preciso tirar o MA" do TF mais velho nas barras do TF mais novo, eu o fiz em 5 minutos, ele funcionará por 98% corretamente, onde neste código 2% "armadilhas" que causarão bugs?

Sim, apenas sobre o assunto do tópico. E tudo isso está resolvido aqui.

Primeiro, antes de qualquer referência a séries temporais de outros TFs/símbolos, certifique-se de verificar se os dados estão disponíveis (veja a função IsTFDataReady() acima). No código acima, você é guiado apenas pelo resultado de CopyClose. Mas não sabe nada sobre a carga histórica. Portanto, primeiro - certifique-se de que os dados estejam disponíveis e só depois os solicite.

Em segundo lugar, a chamada de uma função como argumento de outra função nem sempre é justificada. E no caso acima, é, em princípio, inaceitável. Afinal de contas, o resultado da chamada de iBars também deve ser verificado. Assim, primeiro é chamado iBars, o resultado é colocado em cache e verificado e depois somente o valor recebido é transferido para CopyClose().

Em terceiro lugar, após a chamada do CopyClose, não há verificação para obter todos os dados solicitados. Afinal de contas, a função pode retornar 1 ou 2 barras, e foi solicitada, por exemplo, 10. Eu consideraria tal resultado um erro.

Em quarto lugar, há um erro na própria idéia da abordagem. O loop assume que opera com barras de outra TF, mas mistura os cálculos com a variável rate_total cujo valor se refere à TF atual. Aqui são possíveis duas abordagens que eu utilizo neste ou naquele caso:

  1. Para percorrer as barras do TF atual e converter o índice da barra do TF atual para o índice de barras de outro TF antes da solicitação de dados (esta abordagem é usada no código abaixo).
  2. Ciclo através das barras de outra TF. Mas então precisamos incluir um laço adicional para o caso quando o atual TF é júnior ao outro. Porque uma barra do TF mais antigo corresponderá a várias barras do TF atual.

Estou interessado no código correto para o MT4

À luz destes quatro pontos, deveria parecer assim (eu não verifiquei, eu fiz à mão, mas o sentido deveria ser claro):

   if (!IsTFDataReady(TimeFrame))
      return 0;

   int i,limit;

   static int nOldBars = 0;
   int nBars = iBars(_Symbol, TimeFrame);
   if (nBars == 0)
      return 0;
      
   if (nOldBars == 0 || nBars - nOldBars > 1)
   {
      if(nBars < MAPeriod)
      {
         Comment("Большой период МА!!!, в истории доступно ", nBars," баров");
         return 0;
      }
      
      limit = nBars - fmin(MAPeriod, nBars);
   }
   else
      limit = nBars - nOldBars;  // здесь всегда будет 0 или 1
   
   nOldBars = nBars;
   datetime dtTime = iTime(NULL, TimeFrame, limit);
   if (dtTime == 0)
      return 0;

   limit = iBarShift(NULL, PERIOD_CURRENT, dtTime);

// основной цикл расчета индикатора
   for(i = limit; i >= 0 && !IsStopped(); i--)
   {
      int nOtherTFBarIndex = iBarShift(NULL, TimeFrame, time[i]);
      if (nOtherTFBarIndex < 0 || nOtherTFBarIndex >= nBars)
         continue;
      
      BufMA[i] = iMA(_Symbol,TimeFrame,MAPeriod,0,MODE_SMA,PRICE_CLOSE,nOtherTFBarIndex);
   }
//---
   return rates_total;

A propósito, eu o verifiquei:


 
Ihor Herasko:

Sim, esse é o tópico da linha. E tudo isso já está resolvido aqui.

Primeiro, antes de qualquer referência a outras séries de tempos TF/símbolo, certifique-se de que os dados estejam disponíveis (veja a função IsTFDataReady() acima). No código acima, você é guiado apenas pelo resultado de CopyClose. Mas não sabe nada sobre a carga histórica. Portanto, primeiro - certifique-se de que os dados estejam disponíveis e só depois os solicite.

Em segundo lugar, a chamada de uma função como argumento de outra função nem sempre é justificada. E no caso acima, é, em princípio, inaceitável. Afinal de contas, o resultado da chamada de iBars também deve ser verificado. Assim, primeiro é chamado iBars, o resultado é colocado em cache e verificado e depois somente o valor recebido é transferido para CopyClose().

Em terceiro lugar, após a chamada do CopyClose, não há verificação para obter todos os dados solicitados. Afinal de contas, a função pode retornar 1 ou 2 barras, e foi solicitada, por exemplo, 10. Eu consideraria tal resultado um erro.

Em quarto lugar, há um erro na própria idéia da abordagem. O loop assume que opera com barras de outra TF, mas mistura os cálculos com a variável rate_total cujo valor se refere à TF atual. Aqui são possíveis duas abordagens que eu utilizo neste ou naquele caso:

  1. Para percorrer as barras do TF atual e converter o índice da barra do TF atual para o índice de barras de outro TF antes da solicitação de dados (esta abordagem é usada no código abaixo).
  2. Ciclo através das barras de outra TF. Mas então precisamos incluir um laço adicional para o caso quando o atual TF é júnior ao outro. Afinal, uma barra do TF mais antigo corresponderá a várias barras do TF atual.

luz destes quatro pontos, é assim que deve ser (eu não verifiquei, eu estava fazendo à mão, mas o sentido deve ser claro):

A propósito, eu o verifiquei:


1. Obrigado!

2. palavras de ouro! Eu costumava escrever assim, mas com o tempo, lendo os códigos de outras pessoas, que estão perseguindo a compacidade... Presto mais atenção à "brevidade é a irmã do talento" .... e passo meu tempo procurando os bugs que encontrei.

4. "brevidade é a irmã do talento"... Você está certo!

3. ponto de análise interessante, o que retorna CopyClose(), eu mesmo verifiquei, se não há arquivo .hst para TF solicitado, CopyClose() nunca retorna mais de 2048 - ou seja, este é o valor máximo que pode ser baixado?

Razão: