[SERVICE DESK] Fehler beim Abrufen der Zeit der älteren TF im Timer! - Seite 7

 
Ihor Herasko:

Ja, genau. In OnInit() rufen Sie einfach die erforderlichen TFs auf, ohne das Ergebnis zu überprüfen (Sie können sich dort nicht darauf verlassen), und in OnCalculate rufen Sie die Funktion IsTFDataReady() auf. Sobald für alle angeforderten TFs true zurückgegeben wird, können Sie mit der Ausführung des Algorithmus des Indikators beginnen.

Okay, wir haben das geklärt. Aber wir müssen die Dokumentation deutlich hinzufügen, sonst wird der schnelle Timer eine Menge Fragen an die Entwickler verursachen.

 
Ihor Herasko:

Welche Art von Problem wird im Allgemeinen gelöst, für das das Vorhandensein eines Terminalanschlusses so entscheidend ist? Ich verstehe den Indikator als ein Instrument zur Visualisierung von Daten. Die Daten, die verfügbar sind. Wenn neue Daten eintreffen, wird die Visualisierung aktualisiert. Es sollte nicht erforderlich sein, die Aktualität der Daten zu überprüfen. Dies ist die Aufgabe des Terminals.

Die Aufgabe besteht darin, die Daten der älteren TF so schnell wie möglich zu erhalten.Vitaly Gorbunov erinnerte mich an IsConnected().

 
Alexey Kozitsyn:

Oh, Mann... Diesen Punkt haben wir bereits überschritten. Siehe Ihr eigenes Protokoll:

Sequenz. Zuerst überprüfen wir die Verbindung. Sobald die Verbindung hergestellt ist, erhalten wir die Uhrzeit. Erklären Sie mir bitte, warum erst der Fehler 4066 zurückgegeben wird und dann nicht mehr! Was hat sich in den 20 ms seit dem letzten Aufruf geändert?

Der Fehler 4066 zeigt an, dass keine Daten, sondern eine Aktualisierungsanforderung gesendet wurde.

Sobald die Anfrage gesendet wurde, wird keine weitere Anfrage mehr gesendet, daher wird der Fehler 4066 nicht ausgelöst. Dies wurde bereits mehrfach erörtert.

Warum starten Sie einen Timer in der Anzeige? Es ist so klein. Sie müssen wissen, dass in MT4 die Indikatoren in einem Schnittstellen-Thread laufen. Der Schnittstellen-Thread ist der Ort, an den alle Windmeldungen gehen

 
Slava:

Fehler 4066 zeigt an, dass keine Daten vorhanden sind, eine Aktualisierungsanforderung wurde gesendet.

Sobald eine Anforderung gesendet wurde, wird keine weitere Anforderung mehr gesendet, so dass der Fehler 4066 nicht ausgelöst wird. Dies wurde bereits mehrfach erörtert.

Warum startet man einen Timer in einem Indikator? Es ist so klein. Sie müssen wissen, dass die Indikatoren in MT4 im Schnittstellen-Thread arbeiten. Alle Windmeldungen laufen über den Schnittstellen-Thread

Schön, dass Sie sich an der Diskussion beteiligen.

Es ist nicht mein erster Tag im Forum + mehrere Leute haben hier kommentiert, die auch nicht den ersten Tag im Forum sind. Niemand hat etwas darüber gesagt:

Sobald eine Anfrage gesendet wurde, wird keine weitere Anfrage mehr gesendet, so dass der Fehler 4066 nicht ausgelöst wird. Dies wurde bereits mehrfach erörtert.

Danke, wir werden es wissen. Ich würde dies wirklich gerne in der Hilfe sehen. Der Fehler wird also nur "ausgelöst", wenn das Ereignis OnTick()/OnCalculate() eintritt?

Warum starten Sie den Timer in der Anzeige? Es ist so klein.

Sie müssen Daten von einigen wenigen Zeichen erhalten. So schnell wie möglich. Leider haben weder MT4 noch MT5 den Empfang von Ereignissen über die Ankunft von Kursen eines beliebigen Symbols implementiert (es ist unmöglich, eine solche Aktualisierung zu abonnieren), daher ist der einzige Ausweg (soweit ich weiß) die Abfrage der erforderlichen Symbole im Timer.

Sie sollten wissen, dass die Indikatoren in MT4 im Schnittstellen-Thread arbeiten. Alle Windmeldungen laufen über den Schnittstellen-Thread

OK, sie kommen, aber was dann? Können Sie erläutern, inwiefern dies schlecht/gut ist/wie es den Betrieb der Zeitschaltuhr beeinflusst?
 

Das ist schon oft diskutiert worden. 12 Seiten pro Anfrage "Fehler 4066".

Und es wurde Ihnen richtig geraten, die Anfrage in OnInit zu senden und in OnCalculate zu analysieren.

Wozu brauchen Sieeinen Millisekunden-Timer? Sie verhindern, dass das Client-Terminal normal gestartet werden kann. Es sind nicht die Windnachrichten, die Ihren Timer stören, sondern Ihr Timer stört alle. Noch einmal: Die Indikatoren im MT4-Terminal des Kunden arbeiten im Schnittstellen-Potenzial.

 
Slava:

Das ist schon oft diskutiert worden. 12 Seiten zu "Fehler 4066".

Lesen Sie es, danke. Nur bei der Arbeit in OnCalculate() oder OnTick() gibt es kein Problem, das Problem liegt in OnTimer(). Und auf die Anfrage "error 4066 timer" habe ich nur Ergebnisse aus diesem Zweig erhalten :(

Und es wurde Ihnen richtig geraten, eine Anfrage an OnInit zu senden und sie in OnCalculate zu analysieren.

Ich habe den Rat befolgt, aber das ändert nichts an den Eigenheiten der Timer-Behandlung, die in der Dokumentation nicht erwähnt werden.

Warum brauchen Sie einen Millisekunden-Timer? Sie verhindern, dass der Client-Terminal durch Ihre Aktionen normal aufsteigt. Es sind nicht die Windmeldungen, die Ihren Timer stören, sondern Ihr Timer, der die Timer der anderen stört. Noch einmal: Die Indikatoren im MT4-Terminal des Kunden funktionieren im INTERFACE POCKET.

Noch einmal: Der Millisekunden-Timer dient dazu, so schnell wie möglich Informationen von mehreren Symbolen zu erhalten! Das heißt, der Algorithmus ist wie folgt: Der Indikator wird geladen, erhält so schnell wie möglich Daten von hohen TFs und überwacht dann die Bits der benötigten Symbole im Millisekunden-Timer. Gibt es eine andere Möglichkeit, das Überwachungsproblem zu lösen, als den Timer zu verwenden?

Fassen wir alles zusammen, was hier geschrieben wurde- korrigieren Sie mich, wenn ich falsch liege:

1. Aufgabe: Holen Sie Angebote für mehrere Symbole über einen Timer ein:

Implementierung: Wenn Sie mit einem Hochfrequenz-Timer arbeiten, müssen Sie beim Laden des Terminals in OnCalculate() warten, bis IsConnected() mit dem Server hergestellt ist, erst dann können Sie auf den Timer zugreifen;

2. Ziel: Daten der höheren TFs so schnell wie möglich nach dem Start des Indikators erhalten (der Indikator verwendet einen schnellen Timer);

Implementierung: zuerst fordern wir die notwendigen Daten in OnInit() an, dann warten wir auf die Verbindung IsConnected() in OnCalculate(), dann holen wir die Daten der höheren TFs auch in OnCalculate();

3. Verlangsamt das Starten eines Hochfrequenz-Timers den Schnittstellen-Thread und damit den Computer, und ist es besser, ihn gar nicht zu starten? Wie löst man dann Aufgabe 1?

4. Ziel: Laden aktueller Daten aus älteren TFs.

Implementierung: Verwenden Sie hierfür keinen Hochfrequenz-Timer, da die Datenabfragefunktionen nicht für die Arbeit mit einem solchen Timer ausgelegt sind? Wir verwenden nur OnCalculate()?

5. Wenn ein Fehler 4066 empfangen und dann zurückgesetzt wird, aktiviert OnCalculate() ihn bei jedem Tick?

6. Funktioniert OnTimer() in MT5 nicht im Interface-Thread?

@Slava, bitte antworten Sie auch Punkt für Punkt;

 

1. Normalerweise haben Sie den IsConnected-Status beim zweiten Aufruf von OnCalculate. Erster Aufruf unmittelbar nach dem Start des Terminals, zweiter Aufruf bei Eintreffen der historischen Daten

2. Verwenden Sie keinen schnellen Timer. Prüfen Sie zunächst, welcher Zeitpunkt für Sie akzeptabel ist. Sie kann 100 oder 500 Millisekunden betragen. Es ist kein Zufall, dass wir ursprünglich den Sekunden-Timer eingeführt haben, SetMillisecondsTimer wurde nur 3 oder 4 Jahre später in five(!) eingeführt. Aber die Architektur von five ist anders.

3.1 Besorgen Sie sich einen leistungsstarken Computer, der Warteschlangen für Sofortnachrichten verarbeiten kann.

3.2 Starten Sie den Millisekunden-Timer nicht sofort, sondern spätestens nach dem ersten OnCalculate. Oder besser: im ersten OnCalculate einen zweiten Timer starten (was, wenn es keine Verbindung gibt oder der Tag frei ist), damit man die Umgebung analysieren kann. Und dann, wenn Sie sicher sind, dass alle Daten geladen sind, eine Verbindung besteht und alles in Ordnung ist, schalten Sie den zweiten Timer aus und starten den Millisekunden-Timer. Dann werden Sie sicher durch die schmale Eingangstür springen. Im besten Fall (und davon gibt es 99 Prozent) verlieren Sie beim Start 2 bis 5 Sekunden.

4. Ein Timer ist möglich. Aber nicht sofort (siehe 3.2). Und ich denke, 50 Millisekunden sind gut genug. Sie bieten doch nicht etwa HFT an, oder?

5. Die Zahl 4066 erscheint nur bei der ersten Anfrage nach Daten zu einem anderen Perioden-Zeichen. Bei der nächsten Anfrage für denselben Zeichenzeitraum wird 4066 nicht mehr erhalten

6. Im MT5 werden die Indikatoren in einem separaten Symbolverarbeitungs-Thread gezählt. Wenn Sie also mehr als ein Diagramm zu diesem Symbol haben (oder es gibt andere Indikatoren zu diesem Symbol), können Sie diese verlangsamen. Aber es ist immer noch kein Schnittstellen-Thread

 
Slava:

1. Normalerweise haben Sie den IsConnected-Status beim zweiten Aufruf von OnCalculate. Erster Aufruf unmittelbar nach dem Start des Terminals, zweiter Aufruf bei Eintreffen der historischen Daten

2. Verwenden Sie keine Schnellschaltuhr. Prüfen Sie zunächst, welcher Zeitpunkt für Sie akzeptabel ist. Sie kann 100 oder 500 Millisekunden betragen. Es ist kein Zufall, dass wir ursprünglich den Sekunden-Timer eingeführt haben, SetMillisecondsTimer wurde nur 3 oder 4 Jahre später in five(!) eingeführt. Aber die Architektur von five ist anders.

3.1 Besorgen Sie sich einen leistungsstarken Computer, der Warteschlangen für Sofortnachrichten verarbeiten kann.

3.2 Starten Sie den Millisekunden-Timer nicht sofort, sondern spätestens nach dem ersten OnCalculate. Oder besser: im ersten OnCalculate einen zweiten Timer starten (was, wenn keine Verbindung besteht oder der Tag frei ist), damit man die Umgebung analysieren kann. Und dann, wenn Sie sicher sind, dass alle Daten geladen sind, eine Verbindung besteht und alles in Ordnung ist, schalten Sie den zweiten Timer aus und starten den Millisekunden-Timer. Dann kommen Sie sicher durch die schmale Eingangstür. Im besten Fall (und davon gibt es 99 Prozent) verlieren Sie beim Start 2 bis 5 Sekunden.

4. Ein Timer ist möglich. Aber nicht sofort (siehe 3.2). Und ich denke, 50 Millisekunden sind gut genug. Sie bieten doch nicht etwa HFT an, oder?

5. Die Zahl 4066 erscheint nur bei der ersten Anfrage nach Daten zu einem anderen Perioden-Zeichen. Bei der nächsten Anfrage für das gleiche Periodenzeichen werden Sie nicht mehr 4066 erhalten.

6. Im MT5 werden die Indikatoren in einem separaten Symbolverarbeitungs-Thread gezählt. Wenn Sie also mehr als ein Diagramm zu diesem Symbol haben (oder es gibt andere Indikatoren zu diesem Symbol), können Sie diese verlangsamen. Aber es ist immer noch kein Schnittstellen-Thread

1. genau so funktioniert es;

2. Genau hier liegt das Problem. Je schneller, desto besser. Und die Bewertung ist bereits erfolgt. Der Indikator ist für die Arbitrage (oder besser gesagt für die Arbitrage-Forschung) entwickelt worden, d.h. jede Millisekunde ist wichtig und je schneller eine Notierung eintrifft, desto besser;

3.1. und jetzt das System ist ziemlich mächtig: 8600k CPU, SSD-Terminals, 16gb DDR4 RAM;

3.2. Wow... OK, ich habe es zur Kenntnis genommen;

4. Die Schlichtungsaufgabe steht höchstwahrscheinlich im Zusammenhang mit HFT;

5. Ursprünglich war es genau das, was mich gestresst hat. Hätte ich die Fehlermeldung weiterhin erhalten und gewusst, dass die Daten noch nicht fertig sind, wäre es nicht zu diesem Thread gekommen;

6. Ich verstehe.

Vielen Dank für die ausführliche Antwort.

 
Igor Makanu:

Wenn es nicht zu viel Mühe, hier ist das Thema des Themas - korrekte Geschichte Laden von der älteren TF, hier ist der Indikator: "Ich brauche, um die MA" von der älteren TF auf die Balken des jüngeren TF zu zeichnen, ich tat es innerhalb von 5 Minuten, es wird für 98% korrekt funktionieren, wo in diesem Code 2% "Fallstricke", die Fehler verursachen wird?

Ja, aber nur, was das Thema betrifft. Und das alles ist hier geregelt.

Bevor Sie auf Zeitreihen anderer TFs/Symbole verweisen, sollten Siezunächst prüfen, ob die Daten verfügbar sind (siehe IsTFDataReady() Funktion oben). Im obigen Code orientieren Sie sich nur an dem Ergebnis von CopyClose. Aber sie weiß nichts über Geschichtsbelastung. Vergewissern Sie sich also zunächst, dass die Daten verfügbar sind, und fordern Sie sie erst dann an.

Zweitens istder Aufruf einer Funktion als Argument einer anderen Funktion nicht immer gerechtfertigt. Und im oben genannten Fall ist sie grundsätzlich nicht akzeptabel. Schließlich muss auch das Ergebnis des Aufrufs von iBars überprüft werden. Zunächst wird also iBars aufgerufen, das Ergebnis zwischengespeichert und geprüft und dann nur der empfangene Wert an CopyClose() übergeben.

Drittens wird nach dem Aufruf von CopyClose nicht geprüft, ob alle angeforderten Daten vorhanden sind. Immerhin kann die Funktion 1 oder 2 Takte zurückgeben, und es wurde z.B. 10 verlangt. Ich würde ein solches Ergebnis für einen Fehler halten.

Viertens liegt ein Fehler in der Idee des Ansatzes selbst. Die Schleife geht davon aus, dass sie mit Balken einer anderen TF arbeitet, aber sie verwechselt die Berechnungen mit der Variable rates_total, deren Wert sich auf die aktuelle TF bezieht. Hier sind zwei Ansätze möglich, die ich in diesem oder jenem Fall verwende:

  1. Schleife durch die Balken des aktuellen TF und Umwandlung des Index des Balkens des aktuellen TF in den Balkenindex eines anderen TF vor der Datenabfrage (dieser Ansatz wird im folgenden Code verwendet).
  2. Zyklus durch die Takte einer anderen TF. Aber dann müssen wir eine zusätzliche Schleife für den Fall einbauen, dass die aktuelle TF der anderen untergeordnet ist. Denn ein Balken des älteren TFs entspricht mehreren Balken des aktuellen TFs.

Ich bin an einem korrekten Code für MT4 interessiert

In Anbetracht dieser vier Punkte sollte es so aussehen (ich habe es nicht überprüft, ich habe es von Hand gemacht, aber der Sinn sollte klar sein):

   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;

Übrigens, ich habe es überprüft:


 
Ihor Herasko:

Ja, das ist das Thema des Threads. Und hier ist schon alles geklärt.

Stellen Siezunächst sicher, dass die Daten verfügbar sind, bevor Sie auf andere TF/Symbol-Zeitreihen verweisen (siehe IsTFDataReady() Funktion oben). Im obigen Code orientieren Sie sich nur an dem Ergebnis von CopyClose. Aber sie weiß nichts über Geschichtsbelastung. Vergewissern Sie sich also zunächst, dass die Daten verfügbar sind, und fordern Sie sie erst dann an.

Zweitens istder Aufruf einer Funktion als Argument einer anderen Funktion nicht immer gerechtfertigt. Und im oben genannten Fall ist sie grundsätzlich nicht akzeptabel. Schließlich sollte auch das Ergebnis des Aufrufs von iBars überprüft werden. Zunächst wird also iBars aufgerufen, das Ergebnis zwischengespeichert und geprüft und dann nur der empfangene Wert an CopyClose() übergeben.

Drittens wird nach dem Aufruf von CopyClose nicht geprüft, ob alle angeforderten Daten vorhanden sind. Immerhin kann die Funktion 1 oder 2 Takte zurückgeben, und es wurde z.B. 10 verlangt. Ich würde ein solches Ergebnis für einen Fehler halten.

Viertens liegt ein Fehler in der Idee des Ansatzes selbst. Die Schleife geht davon aus, dass sie mit Balken einer anderen TF arbeitet, aber sie verwechselt die Berechnungen mit der Variable rates_total, deren Wert sich auf die aktuelle TF bezieht. Hier sind zwei Ansätze möglich, die ich in diesem oder jenem Fall verwende:

  1. Schleife durch die Balken des aktuellen TF und Umwandlung des Balkenindex des aktuellen TF in den Balkenindex eines anderen TF vor der Datenabfrage (dieser Ansatz wird im folgenden Code verwendet).
  2. Zyklus durch die Takte einer anderen TF. Aber dann müssen wir eine zusätzliche Schleife für den Fall einbauen, dass die aktuelle TF der anderen untergeordnet ist. Schließlich entspricht ein Balken des älteren TFs mehreren Balken des aktuellen TFs.

In Anbetracht dieser vier Punkte sollte es so sein (ich habe es nicht überprüft, ich habe es von Hand gemacht, aber der Sinn sollte klar sein):

Übrigens, ich habe es überprüft:


1. nahm es in die Hand! Danke!

2. goldene Worte! Früher habe ich so geschrieben, aber mit der Zeit, beim Lesen der Codes anderer Leute, die nach Kompaktheit streben... Ich achte mehr auf "Kürze ist die Schwester des Talents" .... und verbringe meine Zeit mit der Suche nach den Fehlern, die ich gefunden habe.

4. "Die Kürze ist die Schwester des Talents"... Sie haben Recht!

3. interessanter Punkt der Analyse, was gibt CopyClose(), ich habe es selbst überprüft, wenn es keine .hst-Datei für angeforderte TF, CopyClose() gibt nie mehr als 2048 - d.h. dies ist der maximale Wert, der heruntergeladen werden kann?

Grund der Beschwerde: