[SERVICE DESK] Errore nell'ottenere il tempo del TF senior nel timer! - pagina 7

 
Ihor Herasko:

Sì, esattamente. In OnInit() chiamate semplicemente i TF richiesti senza controllare il risultato (non potete farci affidamento), e in OnCalculate chiamate la funzione IsTFDataReady(). Una volta che true viene restituito per tutti i TF richiesti, è possibile iniziare ad eseguire l'algoritmo dell'indicatore.

Ok, abbiamo risolto il problema. Ma dobbiamo aggiungere chiaramente la documentazione, altrimenti il timer veloce causerà molte domande agli sviluppatori.

 
Ihor Herasko:

In generale, che tipo di problema si sta risolvendo per cui la presenza di una connessione terminale è così cruciale? Da quanto ho capito, l'indicatore è uno strumento di visualizzazione dei dati. I dati che sono disponibili. Quando arrivano nuovi dati, aggiorna la visualizzazione. Non dovrebbe essere richiesto di controllare la pertinenza dei dati. Questo è il compito del terminale.

Il compito è quello di ottenere i dati della TF senior il più presto possibile.Vitaly Gorbunov mi ha ricordato IsConnected().

 
Alexey Kozitsyn:

Oh, cavolo... Abbiamo già superato quel punto. Vedi il tuo diario di bordo:

Sequenza. Prima controlliamo la connessione. Una volta stabilita la connessione, otteniamo l'ora. Spiegatemi, per favore, perché diavolo viene restituito prima l'errore 4066 e poi non viene restituito!? Cosa è cambiato in 20ms dall'ultima chiamata?

L'errore 4066 dice che non ci sono dati, richiesta di aggiornamento inviata.

Una volta che la richiesta è stata inviata, un'altra richiesta non viene più inviata, quindi l'errore 4066 non viene innescato. Questo è già stato discusso molte volte.

Perché si avvia un timer nell'indicatore? È così piccolo. Dovete capire che in MT4 gli indicatori girano in un thread di interfaccia. Il thread di interfaccia è dove vanno tutti i messaggi di vento

 
Slava:

L'errore 4066 indica che non ci sono dati, è stata inviata una richiesta di aggiornamento.

Una volta che una richiesta è stata inviata, un'altra richiesta non viene più inviata, quindi l'errore 4066 non viene sollevato. Questo è già stato discusso molte volte.

Perché si avvia un timer in un indicatore? È così piccolo. Dovete capire che in MT4 gli indicatori lavorano nel filo dell'interfaccia. Tutti i messaggi del vento passano attraverso il filo dell'interfaccia

Mi fa piacere che ti sia unito alla discussione.

Non è il mio primo giorno sul forum + diverse persone hanno commentato qui che non sono anche il primo giorno sul forum. Nessuno ha detto nulla a riguardo:

Una volta che una richiesta è stata inviata, un'altra richiesta non viene più inviata, quindi l'errore 4066 non viene innescato. Questo è già stato discusso molte volte.

Grazie, lo sapremo. Mi piacerebbe davvero vedere questo nella guida. Quindi, sicuramente l'errore viene "sollevato" solo quando si verifica l'evento OnTick()/OnCalculate()?

Perché si avvia il timer nell'indicatore? È così piccolo.

È necessario ottenere dati da alcuni personaggi. Il più velocemente possibile. Sfortunatamente, né MT4 né MT5 hanno implementato la ricezione di eventi di arrivo delle quotazioni di qualsiasi simbolo (è impossibile sottoscrivere un tale aggiornamento), quindi l'unica via d'uscita (per quanto ne so) è interrogare i simboli giusti nel timer.

Dovresti capire che in MT4 gli indicatori lavorano nel filo dell'interfaccia. Tutti i messaggi del vento passano attraverso il filo dell'interfaccia

Ok, stanno arrivando, ma poi? Puoi spiegare come questo sia un male/buono/come influisce sul funzionamento del timer?
 

È stato discusso molte volte. 12 pagine per richiesta "errore 4066".

Ed è stato correttamente consigliato di inviare la richiesta in OnInit e analizzarla in OnCalculate.

A cosa vi serveun timer al millisecondo? State impedendo al terminale client di avviarsi normalmente. Non sono i messaggi del vento che interferiscono con il tuo timer, è il tuo timer che interferisce con tutti. Ancora una volta: GLI INDICATORI NEL TERMINALE MT4 DEL CLIENTE LAVORANO IN POTENZIALE DI INTERFACCIA.

 
Slava:

È stato discusso molte volte. 12 pagine su "errore 4066".

Leggilo, grazie. Solo con il lavoro in OnCalculate() o OnTick() non ci sono problemi, il problema è in OnTimer(). E su richiesta "errore 4066 timer" ho ottenuto risultati solo da questo ramo :(

Ed è stato correttamente consigliato di inviare una richiesta a OnInit e analizzarla in OnCalculate.

Ho ascoltato il consiglio, ma non cambia le peculiarità della gestione dei timer che non sono menzionate nella documentazione.

Perché avete bisogno di un timer al millisecondo? Con le vostre azioni state impedendo al terminale client di alzarsi normalmente. Non sono i messaggi del vento che interferiscono con il tuo timer, è il tuo timer che interferisce con quello degli altri. Ancora una volta: GLI INDICATORI NEL TERMINALE MT4 DEL CLIENTE FUNZIONANO NELLA TASCA DELL'INTERFACCIA.

Ancora una volta, il timer di millisecondi serve per ottenere informazioni da più simboli il più velocemente possibile! Cioè, l'algoritmo è il seguente: l'indicatore viene caricato, ottiene i dati dei TF alti il più presto possibile, poi controlla i bit dei simboli necessari nel timer dei millisecondi. C'è un altro modo per risolvere il problema del monitoraggio oltre all'uso del timer?

Riassumiamo tutto quello che è stato scritto qui, correggetemi se sbaglio:

1. Compito: ottenere quotazioni per diversi simboli attraverso un timer:

Implementazione: quando si lavora con un timer ad alta frequenza, bisogna aspettare che IsConnected() sia stabilito con il server in OnCalculate() quando si carica il terminale, solo allora si può accedere al timer;

2. Obiettivo: ottenere i dati dei TF superiori il più presto possibile dopo l'avvio dell'indicatore (l'indicatore utilizza un timer veloce);

Implementazione: prima richiediamo i dati necessari in OnInit(), poi aspettiamo la connessione IsConnected() in OnCalculate(), poi otteniamo i dati dei TF superiori anche in OnCalculate();

3. L'avvio di un timer ad alta frequenza rallenta il thread dell'interfaccia, e di conseguenza il computer, ed è meglio non avviarlo affatto? Come risolvere il compito n. 1 allora?

4. Obiettivo: caricare i dati attuali dai vecchi TF.

Implementazione: non usare un timer ad alta frequenza per questo, poiché le funzioni di recupero dei dati non sono progettate per lavorare in un tale timer? Usiamo solo OnCalculate()?

5. Nel caso in cui un errore 4066 venga ricevuto e poi resettato, OnCalculate() lo arma ad ogni tick?

6. OnTimer() in MT5 non funziona nel thread dell'interfaccia?

@Slava, per favore rispondi anche punto per punto;

 

1. Tipicamente avrete lo stato IsConnected sulla seconda chiamata a OnCalculate. Prima chiamata subito dopo l'avvio del terminale, seconda chiamata all'arrivo dei dati storici

2. Non usare il timer veloce. Per prima cosa valutate quale tempistica è accettabile per voi. Può essere 100 millisecondi o 500. Non è un caso che abbiamo introdotto originariamente il timer di secondi, SetMillisecondsTimer non è stato introdotto in cinque(!) fino a 3 o 4 anni dopo. Ma l'architettura è diversa in cinque.

3.1 Procuratevi un computer potente che possa gestire code di messaggi istantanei.

3.2 Non lanciare il timer dei millisecondi immediatamente, ma almeno dopo il primo OnCalculate. O meglio: nel primo OnCalculate avviare un secondo timer (nel caso in cui non ci sia connessione o il giorno di riposo), in modo da poter analizzare l'ambiente. E poi, quando sei sicuro che tutti i dati sono stati caricati, che c'è una connessione e che tutto è a posto, spegni il secondo timer e fai partire il timer dei millisecondi. Allora riuscirai tranquillamente a passare la stretta porta d'ingresso. Nel migliore dei casi (e ce ne saranno il 99 per cento) perderete da 2 a 5 secondi all'inizio

4. Un timer è possibile. Ma non immediatamente (vedi 3.2). E penso che 50 millisecondi siano sufficienti. Non sta fornendo HFT, vero?

5. 4066 appare solo alla prima richiesta di dati sul carattere del periodo di qualcun altro. Alla prossima richiesta per lo stesso carattere-periodo 4066 non otterrà più

6. In MT5 gli indicatori sono contati in un thread separato di elaborazione dei simboli. Quindi se hai più di un grafico su quel simbolo (o ci sono altri indicatori su quel simbolo), puoi rallentarli. Ma ancora non è un filo di interfaccia

 
Slava:

1. Tipicamente avrete lo stato IsConnected sulla seconda chiamata a OnCalculate. Prima chiamata subito dopo l'avvio del terminale, seconda chiamata all'arrivo dei dati storici

2. Non usare il timer veloce. Per prima cosa valutate quale tempistica è accettabile per voi. Può essere 100 millisecondi o 500. Non è un caso che abbiamo introdotto originariamente il timer di secondi, SetMillisecondsTimer è stato introdotto in cinque(!) solo 3 o 4 anni dopo. Ma l'architettura è diversa in cinque.

3.1 Procuratevi un computer potente che possa gestire le code di messaggi istantanei.

3.2 Non lanciare il timer dei millisecondi immediatamente, ma almeno dopo il primo OnCalculate. O meglio: nel primo OnCalculate avviare un secondo timer (cosa succede se non c'è connessione o il giorno libero), in modo da poter analizzare l'ambiente. E poi, quando sei sicuro che tutti i dati sono stati caricati, che c'è una connessione e che tutto è a posto, uccidi il secondo timer e fai partire il timer dei millisecondi. Allora salterai tranquillamente attraverso la stretta porta d'ingresso. Nel migliore dei casi (e ce ne saranno il 99 per cento) perderete da 2 a 5 secondi all'inizio

4. Un timer è possibile. Ma non immediatamente (vedi 3.2). E penso che 50 millisecondi siano sufficienti. Non sta fornendo HFT, vero?

5. 4066 appare solo alla prima richiesta di dati sul carattere del periodo di qualcun altro. Alla prossima richiesta per lo stesso carattere di periodo, non otterrete di nuovo 4066.

6. In MT5 gli indicatori sono contati in un thread separato di elaborazione dei simboli. Quindi se hai più di un grafico su questo simbolo (o ci sono altri indicatori su questo simbolo) puoi rallentarli. Ma ancora non è un filo di interfaccia

1. È esattamente così che funziona;

2. È qui che si trova il problema. Più veloce è, meglio è. E la valutazione è stata fatta. L'indicatore è scritto per l'arbitraggio (o piuttosto per la ricerca sull'arbitraggio), cioè ogni millisecondo è importante e più velocemente si riceve una quotazione - meglio è;

3.1. e ora il sistema è abbastanza potente: CPU 8600k, terminali SSD, 16gb DDR4 RAM;

3.2. wow... Ok, ho preso nota;

4. È probabile che il compito dell'arbitrato si riferisca all'HFT;

5. All'inizio era proprio questo che mi stressava. Se avessi continuato a ricevere l'errore e avessi saputo che i dati non erano ancora pronti, questo thread non sarebbe successo;

6. Capisco.

Grazie per la risposta elaborata.

 
Igor Makanu:

Se non è troppo disturbo, ecco l'argomento del topic - caricamento corretto della storia dal TF più vecchio, ecco l'indicatore: "Ho bisogno di disegnare la MA" dal TF più vecchio sulle barre del TF più giovane, l'ho fatto in 5 minuti, funzionerà per il 98% correttamente, dove in questo codice 2% "insidie" che causeranno bug?

Sì, solo per quanto riguarda l'argomento. Ed è tutto risolto qui.

In primo luogo, prima di qualsiasi riferimento a serie temporali di altri TF/simboli, assicuratevi di controllare che i dati siano disponibili (vedi la funzione IsTFDataReady() sopra). Nel codice di cui sopra siete guidati solo dal risultato di CopyClose. Ma non sa nulla del carico della storia. Quindi prima - assicurati che i dati siano disponibili e solo allora richiedili.

In secondo luogo, chiamare una funzione come argomento di un'altra funzione non è sempre giustificato. E nel caso di cui sopra, è inaccettabile per principio. Dopo tutto, anche il risultato della chiamata di iBars dovrebbe essere controllato. Quindi, prima viene chiamato iBars, il risultato viene memorizzato nella cache e controllato e poi solo il valore ricevuto viene trasferito a CopyClose().

In terzo luogo, dopo la chiamata di CopyClose non c'è nessun controllo per ottenere tutti i dati richiesti. Dopo tutto, la funzione può restituire 1 o 2 barre, ed è stato richiesto, per esempio, 10. Considererei un tale risultato un errore.

In quarto luogo, c'è un errore nell'idea stessa dell'approccio. Il ciclo presume di operare con le barre di un altro TF ma confonde i calcoli con la variabile rates_total il cui valore si riferisce al TF corrente. Qui sono possibili due approcci che uso in questo o quel caso:

  1. Per eseguire un ciclo attraverso le barre del TF corrente e convertire l'indice della barra del TF corrente nell'indice della barra di un altro TF prima della richiesta di dati (questo approccio è usato nel codice qui sotto).
  2. Ciclo attraverso le barre di un altro TF. Ma allora abbiamo bisogno di includere un ulteriore ciclo per il caso in cui il TF corrente è junior dell'altro. Perché una barra del vecchio TF corrisponderà a diverse barre del TF attuale.

Sono interessato al codice corretto per MT4

Alla luce di questi quattro punti dovrebbe apparire così (non l'ho controllato, l'ho fatto a mano, ma il senso dovrebbe essere chiaro):

   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 proposito, ho controllato:


 
Ihor Herasko:

Sì, questo è l'argomento del thread. E qui è già tutto risolto.

In primo luogo, prima di qualsiasi riferimento ad altre serie temporali TF/simbolo, assicuratevi che i dati siano disponibili (vedi la funzione IsTFDataReady() sopra). Nel codice di cui sopra siete guidati solo dal risultato di CopyClose. Ma non sa nulla del carico della storia. Quindi prima - assicurati che i dati siano disponibili e solo allora richiedili.

In secondo luogo, chiamare una funzione come argomento di un'altra funzione non è sempre giustificato. E nel caso di cui sopra, è inaccettabile per principio. Dopo tutto, anche il risultato della chiamata di iBars dovrebbe essere controllato. Quindi, prima viene chiamato iBars, il risultato viene memorizzato nella cache e controllato e poi solo il valore ricevuto viene trasferito a CopyClose().

In terzo luogo, dopo la chiamata di CopyClose non c'è nessun controllo per ottenere tutti i dati richiesti. Dopo tutto, la funzione può restituire 1 o 2 barre, ed è stato richiesto, per esempio, 10. Considererei un tale risultato un errore.

In quarto luogo, c'è un errore nell'idea stessa dell'approccio. Il ciclo presume di operare con le barre di un altro TF ma confonde i calcoli con la variabile rates_total il cui valore si riferisce al TF corrente. Qui sono possibili due approcci che uso in questo o quel caso:

  1. Per eseguire un ciclo attraverso le barre del TF corrente e convertire l'indice della barra del TF corrente nell'indice della barra di un altro TF prima della richiesta di dati (questo approccio è usato nel codice qui sotto).
  2. Ciclo attraverso le barre di un altro TF. Ma allora abbiamo bisogno di includere un ulteriore ciclo per il caso in cui il TF corrente è junior dell'altro. Dopo tutto, una barra del vecchio TF corrisponderà a diverse barre del TF attuale.

Alla luce di questi quattro punti questo è come dovrebbe essere (non l'ho controllato, lo stavo facendo a mano, ma il senso dovrebbe essere chiaro):

A proposito, ho controllato:


1. l'ha preso in mano, grazie!

2. parole d'oro! Scrivevo così, ma col tempo, leggendo i codici degli altri, che inseguono la compattezza... Faccio più attenzione a "la brevità è la sorella del talento" .... e passo il mio tempo a cercare i bug che ho incontrato.

4. "la brevità è la sorella del talento"... Hai ragione!

3. punto interessante di analisi, cosa restituisce CopyClose(), l'ho controllato io stesso, se non c'è un file .hst per il TF richiesto, CopyClose() non restituisce mai più di 2048 - cioè questo è il valore massimo che può essere scaricato?

Motivazione: