- Richtung des Indizierens in Feldern, Puffern und Zeitreihen
- Datenzugriff organisieren
- SeriesInfoInteger
- Bars
- BarsCalculated
- IndicatorCreate
- IndicatorParameters
- IndicatorRelease
- CopyBuffer
- CopyRates
- CopySeries
- CopyTime
- CopyOpen
- CopyHigh
- CopyLow
- CopyClose
- CopyTickVolume
- CopyRealVolume
- CopySpread
- CopyTicks
- CopyTicksRange
- iBars
- iBarShift
- iClose
- iHigh
- iHighest
- iLow
- iLowest
- iOpen
- iTime
- iTickVolume
- iRealVolume
- iVolume
- iSpread
Datenzugriff organisieren
In diesem Abschnitt werden die Fragen behandelt, die mit Erfassung, Aufbewahren und Anforderung der Preisdaten (Timeserien) verbunden sind.
Datenerfassung vom Handelsserver
Bevor Preisdaten im Terminal MetaTrader 5 zugaenglich sind, muessen sie erfasst und verarbeitet werden. Für Datenerfassung ist der Anschluss an den Handelsserver MetaTrader 5 erforderlich. Daten werden vom Server erfasst auf Anfrage des Terminals in der Form der gepackten Blocks der Minutenbars.
Der Mechanismus der Serverreferenz hängt nicht davon ab, wie die Anfrage initiiert wurde - vom Benutzer bei der Navigation durch Chart oder vom Programm in der Sprache MQL5.
Aufbewahren der Zwischendaten
Die vom Server erfassten Daten werden verpackt und im spezialen Zwischenformat HCC aufbewahren. Daten für jedes Symbol werden in dem gesonderten Verzeichnis Terminalverzeichnis\bases\Name_Servers\history\Name_Symbols geschrieben . Z.B. Daten für Symbol EURUSD vom Handelsserver MetaQuotes-Demo werden sich im VerzeichnisKatalog_Terminals\bases\MetaQuotes-Demo\history\EURUSD\ befinden.
Daten werden in die Dateien mit der Endung .hcc geschrieben, jede Datei bewahrt Daten der Minutenbars für ein Jahr. ZB. due Datei 2009.hcc hat im Verzeichnis EURUSD Minutenbars für Symbol EURUSD für das Jahr 2009. Diese Daten werden für Vorbereitung der Preisdaten für alle Timeframes verwendet und sind nicht für den direkten Zugang bestimmt.
Erhaltung der Daten des notwendigen Timeframes aus den Zwischendaten
Dateien im Format HCC sind Quelle für Bauen der Preisdaten für angeforderte Timeframes im Format HC. Daten im Format HC sind Timeserien, die für den schnellen Zugang am meisten maximal sind. Sie werden nur auf Anfrage des Charts oder des mql5-Programms erzeugt, das Volumen ist nicht mehr als Parameterwert "Max bars in charts", und sie sind für weitere Verwendung in Dateien mit Endung hc aufbewahren.
für Ressourcenökonomie werden Daten des Timeframes gespeichert und aufbewahren im Operativspeicher wenn notwendig, beim langen Fehlen der Aufrufe werden sie aus dem Operativspeicher befreit und in der Datei gespeichert. Für jedes Timeframe werden Daten vorbereiten unabhängig davon, ob es schon fertige Daten für andere Timeframes gibt. Die Regeln des Zusammenstellens und Zugaenglichkeit der Daten sind für alle Timeframes gleich. D.h. Abgesehen davon, dass die Einheit der aufbewahrenen Daten im HCC Format Minutenbar ist, bedeutet das Vorhandensein der Daten im HCC Format nicht das Vorhandensein und Zugaenglichkeit der Daten des Timeframes M1 im HC Format in derselbenn Anzahl.
Erhalten neuer Daten vom Server ruft automatischen Update der verwendeten Preisdaten im HC Format für alle timeframes und Nachkalkulation aller Anzeiger, die die Daten explizit verwenden als Eingabedaten für Berechnung.
Parameter "Max bars in chart"
Parameter "Max bars in charts" beschraenkt die Anzahl der Bars im Format HC, die für Charts, Anzeiger und mql5-Programme zugaenglich sind. Diese Einschraenkung gilt für Daten aller Timeframes und ist in erster Linie für Sparen der Ressourcen bestimmt.
Bei der Einstellung der grossen Werte dieses Parameters muss an sich daran erinnern, dass wenn die Geschichte der Preisdaten für kleine Timeframes tief ist, kann der Speicher für Aufbewahren der Zeitreihen und Puffer hunderte Megabytes sein und Einschraenkungen des Operativspeichers für Programm des Client-Terminals erreichen (2GB für 32-Bit MS Windows-Anwendungen).
Veränderung des Parameters "Max bars in charts" tritt in Kraft nach Wiederanlauf des Client-Terminals. Die Veränderung dieses Parameters selbst führt weder zum Anruf des Servers, um zusaetzliche Daten zu bekommen, noch zur Bildung zusaetzlicher Bars der Zeitreihen. Anforderung der zusaetzlichen Preisdaten und Erneuerung der Zeitreihen unter Beachtung der neuen Einschraenkung erfolgen entweder beim Scrolling des Charts zum Bereich mit den fehlenden Daten oder bei der Anforderung der fehlenden Daten vom mql5-Programm.
Das Volumen der vom Server angeforderten Daten entspricht der erforderlichen Anzahl der Bars des vorgegebenen Timeframes unter Beachtung vom Parameter "Max bars in charts". Einschraenkung, vorgegeben vom Parameter ist nicht strikt, und in einigen Faellen kann die Anzahl der zugaenglichen Daten für Timeframe bisschen groesser sein, als der laufende Wert des Parameters.
Zugaenglichkeit der Daten
Anwesenheit der Daten im HCC Format oder im fertigen für Verwendung HC Format bedeutet nicht, dass diese Daten für Darstellung auf dem Chart oder für Verwendung in mql5-Programmen vollstaendig zugaenglich sind.
Beim Zugang zu Preisdaten oder zu Indikatorwerten aus mql5-Programmen muss man behalten, dass ihrew Zugaenglichkeit für bestimmten Zeitpunket oder seit dem betimmten Zeitpunkt nicht garantiert wird. Das ist damit verbunden, dass zu Zwecken der Ressourcenökonomie wird in MetaTrader 5 nicht die ganze Kopie der erforderlichen Daten für mql5-Programm aufbewahren, sondern es wird ein direkter Zugang zur Datenbank des Terminals gegeben.
Preisgeschichte für alle Timeframes wird aus allgemeinen Daten des HCC Formats gebildet und jedes Update der Daten vom Server führt zum Update der Daten für alle Timeframes und Umbeechnung der Indikatoren. Deswegen kann der Datenzugang zurückgewiesen werden auch wenn diese Daten vor einem Moment zugaenglich waren.
Synchronisierung der Terminaldaten und der Serverdaten #
Da ein mql5-Programm Daten für jedes Symbol und Timeframe aufrufen kann, ist es moeglich,dass Daten der erforderlichen Serie im Terminal noch nicht formiert sind oder Preisdaten mit dem Handelsserver noch nicht synchronisiert sind. In diesem Fall ist Wartezeit schwer vorherzusagen.
Algorithmen, die Wartezeit Zyklen verwenden sind keine beste Entscheidung. der einzige Ausschluss ist in diesem Fall Scripts, denn sie keine andere Algorithmenwahl haben wegen des Fehlens der Ereignisverarbitung. Für Benutzerindikatoren sind solche Algorithmen, wie auch andere Wartezeitzyklen strikt nicht empfohlen, denn sie führen zur Beendigung der Berechnung aller Indikatoren und einer anderen Verarbeitung der Preisdaten für das Symbol.
für Experten und Benutzerindikatoren ist es besser Ereignismodel der Verarbeitung zu verwenden. Wenn es bei der Verarbeitung des Ereignisses OnTick() oder OnCalculate() unmoeglich war, alle erforderlichen Daten der Angeforderten Zeitreihe zu bekommen, muss man Ereignisbearbeiter verlassen und vertrauen auf Datenzugang beim naechsten Aufruf des Bearbeiters.
Beispiel eines Scripts für Laden der Geschichte
Betrachten wir ein Beispiel des Scripts, das Anforderung erfuellt, Geschichte vom Handelsserver für das angegebene Symbol zu erhalten. Script ist dafür bestimmt, das erforderliche Instrument im Chart ablaufen zu lassen, Timeframe ist nicht von Bedeutung, denn, es wurde schon erwaehnt, alle Preisdaten kommen vom Handelsserver als verpackte Minutendaten, aus denen danach jede vorbestimmte Zeitreihe gebildet wird.
Schreiben wir alle Handlungen bezueglich Datenerhaltung als eine gesonderte Funktion CheckLoadHistory(symbol, timeframe, start_date):
int CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period,datetime start_date)
|
Funktion ist CheckLoadHistory() ist als universelle Funktion gedacht, die aus jedem Programm (Expert, Script oder Indikator) aufgerufen werden kann und darum muss sie drei Eingabeparameter haben: Symbolname, Periode und Anfangsdatum, von dem wir Preisgeschichte brauchen.
Geben wir in den Kode der Funktion alle notwendigen Pruefungen ein, bevor wir die fehlende Geschichte fordern. Erstens, überzeugenwir uns, dass Symbolname und Periodenwert korrekt sind:
if(symbol==NULL || symbol=="") symbol=Symbol(); |
Dann überzeugen wir uns davon, dass das angegebene Symbol im Fenster MarketWatch zugaenglich ist, d.h. die Geschichte des angegebenen Symbols auch beim Senden der Anforderung zum Handelsserver zugaenglich ist. Wenn solches Symbol in MarketWatch fehlt fuegen wir das zu durch die Funktion SymbolSelect().
if(!SymbolInfoInteger(symbol,SYMBOL_SELECT)) |
Jetzt ist es notwendig, Anfangsdatum der zugaenglichen Geschichte für das angegebene Paar Symbol/Periode zu erhalten. Der Wert des Eingabeparameters startdate, der der Funktion CheckLoadHistory() übertragen wurde, kann in Interval der schon zugaenglichen Geschichte gelangen und dann ist keine Anforderung zum Handelsserver erforderlich. Für Erhaltung des ersten Datums für Symbol-Periode ist zum jetzigen Zeitpunkt die Funktion SeriesInfoInteger() mit dem Modifikator SERIES_FIRSTDATE bestimmt.
SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE,first_date); |
Die naechste Pruefung ist die Pruefung des Programmtyps, aus dem die Funktion aufgerufen wird. Erinnern wir daran, dass Senden der Anforderung, Zeitreihe mit derselben Periode wie beim Indikator zu update ist gar nicht erwuenschenswert. Unerwuenschtheit der Datenanforderung für das selbe Symbol-Periode, wie beim Indikator ist dadurch bedingt, dass Update der historischen Daten in demselben Thread erfolgt, wo Indikator arbeitet. Darum ist clinch hoechstwarscheinlich. Für die Pruefung verwenden wir die Funktion MQL5InfoInteger() mit dem Modifikator MQL5_PROGRAM_TYPE.
if(MQL5InfoInteger(MQL5_PROGRAM_TYPE)==PROGRAM_INDICATOR && Period()==period && Symbol()==symbol) |
Wenn wir alle Pruefungen erfolgreich durchgelaufen haben, machen wir den letzten Versuch ohne Aufruf des Handelsservers. Zuerst erfahren wir über das Anfangsdatum, für das Minutendaten in HCC Format zugaenglich sind. Rufen wir diesen Wert durch die Funktion SeriesInfoInteger() mit dem Modiofikator SERIES_TERMINAL_FIRSTDATE auf und vergleichen ihn mitdem Parameterwert start_date.
if(SeriesInfoInteger(symbol,PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_date)) |
Wenn nach aller Pruefungen Durchführungsthread im Koerpder der Funktion CheckLoadHistory() noch bleibt, dann bedeutet es, es ist notwendig, die fehlenden Preisdaten vom Handelsserver anzufordern. Vor allem erfahren wir über den Wert "Max bars in chart" durch die Funktion TerminalInfoInteger():
int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); |
Diese Funktion brauchen wir, um eAnforderung von extra Daten vorzubeugen. Dann klaeren wir das erste Datum in der Geschichte des Symbol sauf dem Handelsserver auf (unabhängig von der Periode) durch die schon bekannte Funktion SeriesInfoInteger() mit dem Modifikator SERIES_SERVER_FIRSTDATE.
datetime first_server_date=0; |
Da eine Anforderung eine asynchrone Operation ist, wird die Funktion mit der kleinen Verzoegerung 5 Milisekuden aufgerufen bis die Variable first_server_date den Wert erhaelt oder Zyklusdurchführung vom Benutzer unterbrochen wird (IsStopped(), in diesem Fall gibt den Wert true zurück). Geben wir den korrekten Wert des Anfangsdatums an, von dem wir Preisdaten vom Handelsserver anfordern.
if(first_server_date>start_date) start_date=first_server_date; |
Wenn das Anfangsdatum first_server_date auf dem Server niedriger als Anfangsdatum first_date für Symbol in HCC Format ist, wird im Journal die entsprechende Nachricht ausgegeben werden.
Jetzt sind wir bereit, Anforderung beim Handelsserver zu machen, um fehlende Preisdaten zu bekommen. Anforderung machen wir in Form eines Zyklus und fangen wir an, ihren Koerper auszufuellen:
while(!IsStopped()) |
Die ersten drei Punkte werden durch schon bekannte Methoden realisiert.
while(!IsStopped()) |
Es bleibt der letzter vierte Punkt - unmittelbare Anfirderung der Geschichte. Wir können nicht direkt Serveraufrufen, aber jede Copy-Funktion beim Fehlen der Geschichte in HCC Format initiiert automatisch das Senden dieser Anforderung vom Terminal zum Handelsserver. Da die Zeit des ersten Anfangsdatums in der Variable first_date als das einfachste und natuerlichste Kriterium um Grad der Erfuellung der Anforderung einzuschaetzen, wird es am leichtesten sein, die Funktion CopyTime() zu verwenden.
Beim Aufruf der Funktionen, durch die Kopieren jeder Daten von Zeitreihen erfolgt, muss man bemerken, dass Parameter start (Barnummer, mit der Kopieren der Preisdaten beginnt werden muss) immer innerhalb der zugaenglichen Geschichte des Terminlas sein muss. wenn wir nur 100 Bars haben, ist es sinnlos, 300 Bars zu kopieren versuchen, angefangen mit der Bar mit Index 500. Eine solche Anforderung wird als fehlerhafte angenommen werden und wird nicht verarbeitet, d.h. keine Geschichte vom Handelsserver wird geladen.
Eben darum werden wir 100 Bars kopieren, angefangen mit der Bar mit Index. Das garantiert sanfte Ladung der Geschichte vom Handelsserver, dabei wird mehr als angeforderte 100 Bars ausgeladen werden, Server gibt die Geschichte mit überschuss zurück.
int copied=CopyTime(symbol,period,bars,100,times); |
Nach Kopieren muss man die Anzahl der kopiertenElemente analysieren, wenn der Versuch erfolglos geworden ist, wird der Wert der Variable copied gleich Null sein und der Wert des Counters fail_cnt wird um 1 steigen. Nach 100 erfolglosen Versuche wird die Funktionsarbeit unterbrochen.
int fail_cnt=0;
|
So, ist in der Funktion nicht nur korrekte Verarbeitung der laufenden Situation zu jedem Zeitpunkt der Durchführung organisiert, sondern wird auch Beendigungskode zurückgegeben, den wir nach Aufruf der Funktion CheckLoadHistory() für die Erhaltung der zusaetzlichen Information verarbeiten können. ZB. auf dieser Weise:
int res=CheckLoadHistory(InpLoadedSymbol,InpLoadedPeriod,InpStartDate); |
Der vollstaendige Funktionskode ist in Script angegeben, das richtiges Organisieren des Zuganges zu jeden Daten mit der Verarbeitung des Ergebnisses der Anforderung demonstriert.
Kode:
//+------------------------------------------------------------------+ |