Fix: Broker-Offset bei geschlossenem Markt (-9,5 h statt +3 h)
`_broker_offset_s()` leitete die Zeitzone aus `tick.time - now` ab. Das misst die Zeitzone nur bei FRISCHEM Tick; steht der Markt, misst es die Veraltung. Real am 01.08. (letzter Tick Fr 23:54): -34210 s -> gerundet -34200 (-9,5 h) statt +10800. Die Pruefung [-12h,+14h] liess das durch. Folgen (die Laufzeit-Uhr war nur das Sichtbare): - open_time 12,5 h in der Zukunft -> Laufzeit 0:00 - Time-Stop-Alter (trailing.py:504) negativ -> 120-min-Stop haette nicht ausgeloest - deal.time-Umrechnung beim externen Close, alle MQL5-Chart-Anker Fix: Offset nur noch aus frischem Tick bestimmen, sonst letzter gueltiger Wert (vorbelegt UTC+3 = dieselbe Konstante wie engine.broker_utc_offset). Frische am bereits bekannten Offset gemessen -> nicht zirkulaer. Schwelle 900 s < halbes Rundungsraster. Zeitzonen-Wechsel wird uebernommen und geloggt. Ausserdem: - market_closed greift sofort nach Neustart: _last_bid_move_ts wird aus dem echten Tick-Alter vorbelegt statt bei null zu starten (vorher 180 s blind) - pollSnapshot: der stille catch umschloss render() -> Render-Fehler wurden lautlos verschluckt, das Dashboard fror ohne Konsolen-Fehler ein. Jetzt ist nur noch der fetch im try. - Header-Labels ausgeschrieben: "PEPPERSTONE KURS" / "HYPERLIQUID KURS" - v=131, CLAUDE.md (Deployment-Drift Fall 4) Verifiziert: market_closed sofort True, tick_age gegen die Rohwerte 0 s Abweichung, open_time -> 31.07. 22:54 (Laufzeit +15,8 h). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2ea17ce3e0
commit
b8bb1d260f
+46
-7
@@ -50,6 +50,16 @@ def _retcode_msg(res) -> str:
|
||||
return _RETCODE_MSG.get(rc, f"Order-Fehler (retcode={rc})")
|
||||
|
||||
|
||||
# ── Broker-Zeitzone ───────────────────────────────────────────────────────────
|
||||
# Pepperstone liefert Broker-Zeit UTC+3 (ganzjährig) — dieselbe Konstante nutzt
|
||||
# `engine.get_bars` bereits für die Chart-Umrechnung (`broker_utc_offset`).
|
||||
_BROKER_OFF_DEFAULT_S = 3 * 3600
|
||||
# Nur ein FRISCHER Tick darf den Offset (neu) bestimmen. Begründung s.
|
||||
# `_broker_offset_s` — die Schwelle liegt unter dem halben Rundungsraster
|
||||
# (1800/2 = 900 s), damit die 30-min-Rundung immer auf den echten Offset fällt.
|
||||
_BROKER_TICK_FRESH_S = 900
|
||||
|
||||
|
||||
class TradeManager:
|
||||
def __init__(self):
|
||||
self.ticket = self.order_type = None
|
||||
@@ -57,6 +67,11 @@ class TradeManager:
|
||||
self.sl = self.tp = self.margin = 0.0
|
||||
self.open_time = 0.0 # Öffnungszeit als ECHTE Epoch (Broker-Offset korrigiert)
|
||||
self.symbol = None
|
||||
# Zuletzt als GÜLTIG erkannter Broker-Offset (s. `_broker_offset_s`).
|
||||
# Vorbelegt mit der bekannten Zeitzone, damit auch ein Start bei
|
||||
# geschlossenem Markt (Wochenende) sofort richtig rechnet.
|
||||
self._boff = _BROKER_OFF_DEFAULT_S
|
||||
self._boff_logged = None
|
||||
self.last_error = ""
|
||||
self._lock = threading.Lock()
|
||||
self.history: 'HistoryLogger | None' = None
|
||||
@@ -503,9 +518,26 @@ class TradeManager:
|
||||
(z.B. UTC+3 → 10800). MT5 liefert deal.time/tick.time in
|
||||
Broker-Zeit, NICHT in UTC — ohne Korrektur landen Timestamps
|
||||
3 h verschoben in der DB.
|
||||
Außerhalb der Handelszeiten kann der letzte Tick alt sein →
|
||||
Ergebnis wird auf plausiblen Bereich [-12h, +14h] geprüft,
|
||||
sonst 0 (keine Korrektur).
|
||||
|
||||
⚠ BUGFIX 2026-08-01 (Wochenende, real gemessen): `tick.time - now`
|
||||
misst die Zeitzone NUR, solange der Tick frisch ist. Steht der Markt,
|
||||
friert `tick.time` ein und die Differenz misst die **Veraltung**.
|
||||
Real am 01.08. um 11:25: letzter Tick Fr 23:54 → `tick.time - now =
|
||||
-34210` → gerundet **-34200 (−9,5 h)** statt +10800. Die alte
|
||||
Plausibilitätsprüfung `[-12h, +14h]` ließ das durch, weil eine
|
||||
Wochenend-Veraltung genau in dieses Fenster fällt.
|
||||
Folgen waren real sichtbar: `open_time` 12,5 h in der ZUKUNFT
|
||||
(Laufzeit-Uhr stand auf 0:00), und still betroffen waren auch
|
||||
Time-Stop-Alter (`trailing`), `deal.time`-Umrechnung beim externen
|
||||
Close und alle MQL5-Chart-Anker (Kanal/Liquiditäts-Trendlinie/
|
||||
Trade-Marker).
|
||||
|
||||
Neu: Der Offset wird **nur von einem frischen Tick** (neu) bestimmt;
|
||||
sonst gilt der zuletzt gültige Wert (`self._boff`, vorbelegt mit der
|
||||
bekannten Zeitzone UTC+3). Die Frische wird am bereits bekannten
|
||||
Offset gemessen — nicht am Tick selbst, das wäre zirkulär.
|
||||
Ein echter Zeitzonen-Wechsel (DST des Brokers) wird beim ersten
|
||||
frischen Tick übernommen und geloggt.
|
||||
"""
|
||||
try:
|
||||
# `sym` explizit übergebbar: beim Adoptieren einer Position ist
|
||||
@@ -514,12 +546,19 @@ class TradeManager:
|
||||
sym = sym or self.symbol
|
||||
tick = mt5.symbol_info_tick(sym) if sym else None
|
||||
if tick and tick.time:
|
||||
off = round((tick.time - time.time()) / 1800) * 1800
|
||||
if -12 * 3600 <= off <= 14 * 3600:
|
||||
return int(off)
|
||||
now = time.time()
|
||||
off = round((tick.time - now) / 1800) * 1800
|
||||
# Veraltung, gemessen am bisher bekannten Offset (nicht zirkulär).
|
||||
stale = (now + self._boff) - tick.time
|
||||
if stale <= _BROKER_TICK_FRESH_S and -12 * 3600 <= off <= 14 * 3600:
|
||||
if off != self._boff and self._boff_logged != off:
|
||||
log.info(f"Broker-Zeitzone neu erkannt: "
|
||||
f"{self._boff / 3600:+.1f} h → {off / 3600:+.1f} h")
|
||||
self._boff_logged = off
|
||||
self._boff = int(off)
|
||||
except Exception:
|
||||
pass
|
||||
return 0
|
||||
return int(self._boff)
|
||||
|
||||
def _log_external_close(self, ticket: int,
|
||||
fallback_pnl: float | None = None,
|
||||
|
||||
Reference in New Issue
Block a user