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:
Axel Hocks
2026-08-01 14:44:25 +02:00
co-authored by Claude Opus 5
parent 2ea17ce3e0
commit b8bb1d260f
5 changed files with 149 additions and 20 deletions
+11 -4
View File
@@ -491,7 +491,7 @@ function render(d) {
// Rest normal weiter, nur die neuen Felder fehlen, bis die HTML nachgeladen ist.
const lblEl = $("hdr-price-lbl");
if (lblEl) {
lblEl.textContent = d.market_closed ? "KURS · ZU" : "KURS";
lblEl.textContent = d.market_closed ? "PEPPERSTONE KURS · ZU" : "PEPPERSTONE KURS";
lblEl.title = d.market_closed
? `Pepperstone geschlossen — letzter Tick vor ${Math.round((d.tick_age_s || 0) / 60)} min`
: "";
@@ -903,10 +903,17 @@ function connect() {
const POLL_MS = 4000;
async function pollSnapshot() {
if (document.hidden) return; // seite unsichtbar → spart Akku/Daten, Wake-Handler holt beim Zurückkommen sofort nach
let d;
try {
const d = await (await fetch("api/snapshot")).json();
_applySnapshot(d);
} catch (e) { /* still — WS-Reconnect kümmert sich, das ist nur der Fallback */ }
d = await (await fetch("api/snapshot")).json();
} catch (e) { return; } // still — Netz-/WS-Aussetzer, dafür IST der Fallback da
// ⚠ NICHT mit ins try oben (Fix 2026-08-01): der Poll-`catch` umschloss früher
// auch `_applySnapshot` → `render`. Ein Render-Fehler wurde damit LAUTLOS
// verschluckt: der Poll feuerte weiter alle 4 s, jeder Durchlauf starb still,
// das Dashboard fror auf dem letzten guten Stand ein und die Konsole blieb
// leer. Genau diese Kombination hat eine Fehlersuche unnötig lang gemacht.
// Netzfehler bleiben still (die sind erwartbar), Render-Fehler werden laut.
_applySnapshot(d);
}
setInterval(pollSnapshot, POLL_MS);