Artikel

MetaTrader-Zeit sieht nach UTC aus. Es ist die Brokeruhr.

7 Min. Lesezeit

Wenn du in Python Kerzen aus MetaTrader 5 abrufst, sieht die Spalte time wie ein Unix-Zeitstempel aus. Sie ist keiner. Sie enthält die Serveruhr des Brokers, geschrieben als Sekunden seit 1970 auf genau dieser Uhr. Gib sie an pd.to_datetime(unit="s") weiter, und deine Kerzen landen zwei oder drei Stunden neben ihrem tatsächlichen Zeitpunkt.

Die Verwirrung beginnt in der Dokumentation. Die offizielle Seite zu copy_rates_from sagt, die vom Terminal gelieferten Daten seien in UTC (MQL5-Dokumentation (Externe Website)). In einem Forenthread von 2021 mit dem Titel „python api does not return UTC times“ bestätigte ein Moderator, dass die Python-Doku der MQL5-Doku widerspricht, und sagte, die Zeiten seien Serverzeit des Brokers (MQL5-Forum, 2021 (Externe Website)). Im Oktober 2026 kam die Frage wieder, mit rohen Tick-Zeiten, die etwa 10.799 Sekunden vor UTC lagen, und derselben Antwort eines Moderators (MQL5-Forum, 2026 (Externe Website)).

Ich habe dafür eine kleine Python-Bibliothek veröffentlicht, brokerclock (Externe Website). Vor der API zuerst, warum der übliche Einzeiler nicht hält.

Die Uhr, die du nicht siehst

Viele Forex-Broker stellen ihren Server so ein, dass Mitternacht auf 17:00 Uhr in New York fällt, das übliche Ende des Forex-Handelstags. Damit liegen sie im New Yorker Winter auf GMT+2 und im New Yorker Sommer auf GMT+3 und stellen die Uhr an den US-Terminen um, nicht an den europäischen (Erklärung zur Serverzeit von Brokern (Externe Website)).

Das Python-Paket von MetaTrader hat keinen Aufruf, der den Versatz des Brokers oder die Regel dahinter liefert. Also wird einer fest eingetragen.

Ein fester Wert +3 ist den ganzen Winter falsch. Ein fester Wert +2 ist den ganzen Sommer falsch. Eine europäische Sommerzeitregel wirkt den größten Teil des Jahres richtig und bricht dann zweimal, weil die USA und Europa ihre Uhren an verschiedenen Sonntagen umstellen: etwa drei Wochen im März, nachdem die USA umgestellt haben und bevor Europa folgt, und eine Woche um Anfang November. 2025 stellten die USA am 9. März um und Europa am 30. März. Jede Kerze in diesem Zeitraum liegt eine Stunde daneben, und nichts meldet einen Fehler.

Das gilt auch in die andere Richtung. Die Datumsargumente von copy_rates_range und copy_ticks_range sowie das Feld expiration einer Order werden als Serverzeit gelesen. Ein naives datetime läuft auf dem Weg hinein durch die lokale Zeitzone des PCs, und damit kommt eine dritte Uhr ins Spiel.

Eine Uhr ist eine Regel, keine Zahl

Die Lösung ist, keinen Versatz mehr zu speichern, sondern die Regel. brokerclock bildet die Serveruhr als IANA-Zeitzone plus Versatz ab. Die übliche Brokeruhr, GMT+2/+3 nach US-Terminen, ist die New Yorker Ortszeit plus sieben Stunden:

from brokerclock import ServerZone

zone = ServerZone.us()    # GMT+2/+3 (US daylight saving)
zone.to_utc(1751371200)   # 2025-07-01 12:00 on the server clock
# datetime(2025, 7, 1, 9, 0, tzinfo=timezone.utc)

Jede Umrechnung fragt die Zeitzonendatenbank nach dem Versatz, der in diesem Moment gilt, sodass die Lücke im März und die Woche im November ohne Sonderfälle stimmen. ServerZone.eu(), ServerZone.au() und ServerZone.fixed(0) decken die anderen üblichen Varianten ab. Jede andere Uhr ist ein IANA-Schlüssel plus ein Versatz in 15-Minuten-Schritten.

Die Stunde, die sich am Ende der Sommerzeit wiederholt, ist wirklich mehrdeutig, deshalb löst to_utc einen AmbiguousTimeError aus, außer du übergibst ambiguous="earlier" oder "later". Die im Frühjahr übersprungene Stunde löst NonexistentTimeError aus. Mir ist eine Exception lieber als eine Kerze, die sich still verschiebt.

Die Regel aus der Kurshistorie finden

Zu wissen, dass du eine Regel brauchst, sagt dir noch nicht, welche dein Broker nutzt. Du kannst den Support fragen. Die Kurshistorie ist der bessere Zeuge.

Die Forex-Woche endet freitags um 17:00 Uhr New Yorker Zeit. In der Kerzenhistorie ist dieser Schluss die letzte Kerze vor einer Lücke von 40 Stunden oder mehr. Ihr Endzeitpunkt auf der Serveruhr, verglichen mit dem echten Freitag 17:00 Uhr, ergibt den Versatz des Servers in dieser Woche. Ein Jahr Wochenschlüsse ist ein Jahr Versätze. Jede Kandidatenuhr (fest oder mit US-, EU- oder australischer Sommerzeit bei beliebigem Grundversatz) sagt einen Teil davon voraus, und die beste Vorhersage gewinnt.

import MetaTrader5 as mt5
import brokerclock

mt5.initialize()
rates = mt5.copy_rates_from_pos("EURUSD", mt5.TIMEFRAME_H1, 0, 6500)
result = brokerclock.detect(rates["time"], timeframe=3600)
print(result.zone)  # GMT+2/+3 (US daylight saving)
print(f"{result.matched} of {result.total} weeks agree")

detect liefert seine Belege mit der Antwort. Wochen, die nicht zur Gewinneruhr passen, meist frühe Schlüsse an Feiertagen, kommen als outliers zurück. Wenn die Daten zwei Uhren nicht trennen können, etwa reine Sommerkerzen, bei denen US- und EU-Regel übereinstimmen, ist zone gleich None und candidates listet den Gleichstand. Das ist die ehrliche Antwort, und die Lösung ist ein längerer Datenzeitraum.

Broker schließen um 17:00 Uhr oder früher, nie später, deshalb wird jeder Wochenversatz auf die nächsten 15 Minuten aufgerundet. H1-Kerzen sind die sicherste Eingabe, weil die letzte H1-Kerze der Woche trotzdem um 17:00 Uhr endet.

Mit Live-Ticks prüfen

Die Historie nennt dir die Regel. Ein Live-Tick sagt dir, ob sie heute noch gilt:

tick = mt5.symbol_info_tick("EURUSD")
brokerclock.check(zone, [tick.time_msc / 1000])

check rechnet den Tick mit der Zone um und vergleicht ihn mit der PC-Uhr. Ein Tick aus der Zukunft löst ZoneMismatchError aus. Ein frischer, passender Tick liefert True. Ein alter liefert False, weil ein geschlossener Markt nichts bestätigen kann. Ohne Zone liefert measure_offset den aktuellen Versatz und löst StaleTickError aus, statt zu raten, wenn der Tick alt ist.

Ganze Spalten und der Weg zurück

Mit dem pandas-Extra nimmt frame_to_utc das strukturierte Array aus copy_rates_* und liefert einen DataFrame, dessen Spalte time zeitzonenbewusstes UTC enthält. Für Abfragen und Ablaufzeiten macht zone.server_timestamp(instant) aus einem UTC-datetime die Ganzzahl auf der Serveruhr, die MetaTrader erwartet, und hält so auch die Zeitzone des PCs aus der Anfrage heraus.

pip install "brokerclock[pandas]"

Die Bibliothek importiert MetaTrader5 nie. Sie braucht nur die Standardbibliothek, unter Windows zusätzlich tzdata, und läuft und testet deshalb unter Linux und macOS, wo sich das Terminal-Paket nicht installieren lässt. Die Testsuite hat 260 Tests auf Python 3.10 bis 3.14.

Andere Wege

In MQL5 wurde daran schon gearbeitet. Amr Alis Bibliothek TimeGMT schätzt den Serverversatz aus der ersten H1-Kerze nach jedem Wochenende, vor allem um TimeGMT() im Strategietester zu korrigieren (TimeGMT (Externe Website)). Der Artikel von Kabelo Frans Mampa erkennt den Sommerzeitplan an der Volatilität der Non-Farm Payrolls in M15-Kerzen und kann im Strategietester nicht laufen, weil der Wirtschaftskalender dort keine Daten liefert (Monochronic Trading, Teil 1 (Externe Website)).

Beide leben im Terminal. brokerclock beantwortet dieselbe Frage in Python, liefert die Regel selbst, sodass auch künftige Zeiten umgerechnet werden, und deckt den Weg zurück zu MetaTrader ab.

Was sie nicht löst

Wann ein Broker die Uhr bei rund um die Uhr gehandelten Krypto-CFDs umstellt, entscheidet der Broker, deshalb können Kerzen direkt an einer Umstellung noch eine Stunde daneben liegen. Metalle und Indizes folgen den Zeiten ihrer Börse, deshalb sollte die Erkennung an einem Forex-Major laufen. Demo- und Live-Server eines Brokers können unterschiedliche Uhren haben. Und ein Broker, der seine Uhr ändert, schreibt seine Historie womöglich in der neuen Uhr neu, deshalb solltest du nach einer Änderung erneut erkennen lassen.

Wenn du MT5-Daten schon speicherst, würde ich zuerst eine Woche prüfen: Ende März. Leg deine Kerzen neben eine andere Quelle. Liegen sie eine Stunde daneben, wurde der Versatz als Zahl gespeichert, wo eine Regel nötig war.

Quellen

Artikel teilen