Bibliotheken: OnTickMulti - Seite 5

 
Stanislav Korotky #:

Für einen umfassenden Testfall müsste ich die praktische Aufgabe verstehen – handeln wir ausschließlich mit Ticks, deren Zeitangaben auf die Millisekunde genau übereinstimmen?

Nein. Die Aufgabe besteht darin, stets eine aktuelle Umgebung für alle Symbole zu haben. In meinem Beispiel ist die Aktualitätsbedingung in OnTimer immer erfüllt. Das Eröffnen einer Position dient lediglich der Veranschaulichung.
 
fxsaber #:
Nein. Das Ziel ist es, stets eine aktuelle Umgebung für alle Symbole zu haben. In meinem Beispiel ist die Aktualitätsbedingung im OnTimer immer erfüllt. Das Eröffnen einer Position dient lediglich der Veranschaulichung.

Gut.

Bislang ist unklar, wo die Implementierung im Ereignis „OnTickMulti“ einen Tick „verliert“ oder, mit anderen Worten, wie es dazu kommt, dass SymbolInfoTick nicht die erwarteten Kurse zurückgibt (ich hatte zuvor vermutet, dass es wahrscheinlich eine Verzögerung aufgrund der Vermittlung von benutzerdefinierten Ereignissen aus dem Indikator gibt) – ich würde es zur Reinheit des Experiments ohne den Spion-Indikator testen – einfach SymbolInfoTick/CopyTicks für alle Symbole aus dem normalen OnTick, zumindest für denselben Zeitstempel.

Was OnTimer betrifft, so wirft dies bei mir Fragen auf (bitte korrigiert mich, wenn ich mich irre):

void OnTimer()
{
  if (TimeMsc++ == 1759280400081) // 01.10.2025 01:00:00.081
    PositionOpen();
}

Wir haben keine Garantie, dass der Handler schneller als eine Millisekunde ausgeführt wird, daher garantiert ein einfaches Inkrementieren des Zählers nicht, dass die ursprüngliche Synchronisation erhalten bleibt, d. h. muss der Abgleich mit der Serverzeit eigentlich jedes Mal in Echtzeit erfolgen (nach dem Eröffnen einer Position oder anderen Berechnungen, die komplexer sind als eine einfache Inkrementierung, falls solche vorliegen). Mit anderen Worten: Der hier vorgestellte verfeinerte Ansatz wird nicht funktionieren, wenn viele Positionen eröffnet werden müssen.

Außerdem ist auch die anfängliche Synchronisation (Initialisierung des Zählers) meiner Meinung nach nicht zu 100 % einwandfrei.

ulong TimeMsc = TimeTradeServer() * 1000 + (inTimer && EventSetMillisecondTimer(1));

Nehmen wir an, im Tester beginnt die Serverzeit tatsächlich ohne Millisekunden, aber wie würde solcher Code online funktionieren? Und warum addieren wir 1 Millisekunde hinzu? Ich würde die Serverzeit dennoch aus den Ticks beziehen.

Das ist kein Haarspalterei, sondern lediglich Zweifel daran, dass die „Aktualitätsbedingung immer erfüllt ist“.

 
Stanislav Korotky #:

Ein einfaches Inkrementieren des Zählers garantiert nicht, dass die ursprüngliche Synchronisation erhalten bleibt

Im Tester ist dies gewährleistet.

Aber wie soll ein solcher Code online funktionieren?

Online gibt es dieses Problem nicht, da alle Daten, die am Terminal ankommen, nur indikativ sind: Sie sind aufgrund von Verzögerungen nicht aktuell.

Und warum addieren wir 1 Millisekunde hinzu?

Weil der allererste OnTimer erst nach einem festgelegten Intervall aufgerufen wird und nicht sofort.

 
Stanislav Korotky #:

Bislang ist unklar, wo die Implementierung im Ereignis „OnTickMulti“ einen Tick „verliert“ – oder anders ausgedrückt: Wie kommt es, dass „SymbolInfoTick“ nicht die erwarteten Preise zurückgibt?

OnTickMulti hat definitiv nichts damit zu tun, da die standardmäßige SymbolInfoTick-Funktion für eines der Symbole den richtigen Tick zurückgibt, für andere Symbole jedoch nicht.


Der Grund liegt ausschließlich in der Reihenfolge der Tick-Übermittlung.

Forum zu Trading, automatisierten Handelssystemen und dem Testen von Handelsstrategien

Bibliotheken: OnTickMulti

fxsaber, 30.09.2025, 09:24

Ticks mit derselben Zeitangabe kommen nicht gleichzeitig an. Sie folgen nacheinander. Und wenn ein Tick für EURUSD mit der größeren Zeitangabe zuerst eintrifft, ist zu diesem Zeitpunkt noch nichts über den Tick mit derselben Zeitangabe für GBPUSD bekannt, der als Zweiter eintreffen wird. Daher gibt es zum Zeitpunkt des Eintreffens des ersten EURUSD-Ticks den zweiten GBPUSD-Tick einfach noch nicht, sondern nur die Daten des vorherigen GBPUSD-Ticks.
 
fxsaber #:

Denn der allererste OnTimer wird erst nach einer festgelegten Zeitspanne aufgerufen und nicht sofort.

Ich habe mir eine schnelle Methode ausgedacht, um alle Daten zu aktualisieren.

#include <fxsaber\OnTickMulti\OnTickMulti.mqh> // https://www.mql5.com/de/code/47647

#include <MT4Orders.mqh> // https://www.mql5.com/de/code/16006

void PositionOpen()
{
  for (uint i = ArraySize(OnTickMultiObject.Symbols); (bool)i--;)
  {
    const string SymbName = OnTickMultiObject.Symbols[i];
    
    OrderSend(SymbName, OP_BUY, 1, SymbolInfoDouble(SymbName, SYMBOL_ASK), 0, 0, 0);
  }
}

long CurrentTime = 0;

// OnTick mit mehreren Zeichen.
void OnTickMulti( const string &Symb, const uint &Index )
{  
  MqlTick Tick;
  
  if (SymbolInfoTick(Symb, Tick) && (Tick.time_msc > CurrentTime))
  {
    CurrentTime = Tick.time_msc;
    
    EventSetMillisecondTimer(1);
  }  
}

void OnTimer()
{
  if (CurrentTime == 1759280400081) // 01.10.2025 01:00:00.081
    PositionOpen();
    
  EventKillTimer();
}

Ein solcher Mechanismus ermöglicht es, selbst im normalen Modus (Ein-Währungs-Modus ohne OnTickMulti) ausschließlich mit aktuellen Daten zu arbeiten. Beispielsweise gibt es für EURUSD mehrere Ticks mit identischer Zeitangabe. Durch die Aktualisierung kann man mit dem aktuellen Tick arbeiten – dem letzten in dieser Folge.


PS: Dies ist ein weiterer Grund, benutzerdefinierte Symbole zu erstellen – um nur den letzten Tick aus Sequenzen mit identischer Zeit in den Verlauf aufzunehmen. In diesem Fall wird im Ein-Währungs-Modus die Aktualisierung stets gewährleistet.

Библиотеки: TicksShort
Библиотеки: TicksShort
  • 2025.09.26
  • www.mql5.com
Статьи и техническая библиотека по автоматическому трейдингу: Библиотеки: TicksShort
 
Rorschach #:

Aber bei den Eröffnungskursen ist es doch genauso, obwohl die Öffnungszeiten für alle Wertpapiere gleich sind.

Und aufgrund dieses Verhaltens lassen sich einige Systeme nicht ordnungsgemäß testen.

Ich habe mir den Testmodus mit Eröffnungskursen noch einmal ins Gedächtnis gerufen. Der Clou dabei ist, dass der Tester in diesem Modus – trotz der Bezeichnung – 4 OHLC-Ticks generiert und nicht nur 1, wie man intuitiv aufgrund des Namens erwarten würde. Von diesen 4 Kontrollpunkten wird für Expert Advisors nur der erste (O) herangezogen und „OnTick“ aufgerufen, während für Indikatoren zusätzlich für HLC oder LHC (je nach Richtung des Balkens) dreimal „OnCalculate“ mit Ticks für die entsprechenden Preise aufgerufen wird. Die Zeitpunkte für diese drei zusätzlichen Punkte werden künstlich auf die letzten drei Sekunden des Balkens festgelegt. Das bedeutet, dass der Spion-Indikator für die Symbole mehrere Ereignisse statt nur eines sendet. Dies sollte wahrscheinlich von denjenigen berücksichtigt werden, die den Modus mit Eröffnungskursen verwenden.

Außerdem beobachte ich einen Artefakt (nachdem ich Debugging-Funktionen in meinen analogen Spion-Indikator aus dem Buch eingefügt habe), dass das Ereignis zum Tick des zusätzlichen Symbols aus dem vorherigen Balken aus irgendeinem Grund im neuen Balken wiederholt wird, erst dann wird `OnCalculate` des Spion-Indikators aufgerufen und es kommt ein Ereignis zum neuen Tick des zusätzlichen Symbols mit aktualisiertem Kurs. Um den aktuellen Kurs für zusätzliche Symbole zu erhalten, muss man daher in den Ereignissen selbst einen Zeitstempel haben und bereits verarbeitete Ereignisse nicht erneut verarbeiten. Ich mache das bei mir beim Senden so:

int OnCalculate(const int rates_total, const int prev_calculated, const int, const double &price[])
{
   MqlTick tick;
   SymbolInfoTick(_Symbol, tick);
   EventChartCustom(Chart, Message, Index, (double)tick.time_msc, NULL);
  
   return rates_total;
}

Und beim Empfang (hier wird der Fall eines zusätzlichen Symbols gezeigt, für mehrere benötigt man ein Array „timestamp[]“!):

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_CUSTOM + Message)
   {
      static long timestamp;
      long event = (long)dparam;
      if(event > timestamp)
      {
         OnSymbolTick((int)lparam);
         timestamp = event;
      }
   }
}

Es ist zu beachten, dass bei Ticks mit identischen Millisekunden der erste davon ausgeführt wird und nicht der letzte.

 
Rorschach #:
Die einfachste Methode zur Synchronisation
Ich dachte, die Synchronisation von Zeitreihen sei ein gut erforschtes Problem und es gäbe fertige Algorithmen, also habe ich im Internet nachgeschaut, aber dort war nichts zu finden