From 7427c369221820ef19edc863a78fa4f335c80f29 Mon Sep 17 00:00:00 2001 From: Axel Hocks Date: Sat, 1 Aug 2026 09:31:01 +0200 Subject: [PATCH] Hyperliquid-Kurs neben dem Broker-Kurs + G/V-Schaetzung bei geschlossenem Markt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User: "wenn Pepperstone closed ist trotzdem Kurs und Liquiditaet von Hyperliquid einbinden" -> nachgeschaerft zu "blende den HL-Kurs NEBEN den Pepperstone-Kurs ein" (ehrlicher als ein stiller Tausch) -> plus "bei geschlossenem Markt auch den G/V mit HL berechnen". Snapshot: hl_live {mid_mt5, hl_mid, basis, age_s, bid/ask, bid_sz/ask_sz, imb5, trend, slope_per_h, vs_mt5} - IMMER befuellt. mid_mt5 = HL-Mid + gemessene Basis, also direkt mit dem Broker-Kurs vergleichbar. Dazu market_closed, tick_age_s, pnl_hl. core/hl_walls.py liefert jetzt zusaetzlich hl_mid/mid_mt5/age_s. Dashboard v=129: eigene Header-Box "HL" neben KURS mit Tooltip (Rohkurs, Basis, Alter, Abweichung). Bei geschlossenem Markt: Label "KURS · ZU", Session-Zeile "MARKT ZU", und das G/V wechselt auf die HL-Schaetzung, mit "≈" markiert. MT5 v1.34: HL;;;;; -> bernsteinfarbenes Label unter Kurs und G/V (InpShowHL/InpHLColor). DREI SACKGASSEN dokumentiert, damit sie niemand wiederholt: 1) tick_local_ts ist die ABHOLZEIT, nicht das Tick-Alter. 2) tick_server_ts minus _broker_offset_s() ist ZIRKULAER - die Offset-Funktion leitet den Versatz selbst aus dem letzten Tick ab und misst bei geschlossenem Markt die Veraltung (-7,41 h statt +3 h); das Alter hebt sich auf (-347 s). 3) pnl / Kursbewegung als EUR-je-Punkt ergab 155 statt ~86, weil trader.pnl den Wochenend-Swap enthaelt. Verwendet wird stattdessen: Markt zu = der Kurs hat sich seit 180 s nicht BEWEGT (_last_bid/_last_bid_move_ts). Und der G/V nutzt die vorhandene, korrekte trader.live_pnl(bid, ask) mit dem HL-Kurs +- halbem Spread. Live verifiziert: market_closed=True nach 198 s, Broker 86.333 eingefroren, HL 86.349 (7 s alt), Broker-P&L -15,02 -> HL-Schaetzung -14,37 EUR. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 42 ++++++++++++++++++ core/engine.py | 104 +++++++++++++++++++++++++++++++++++++++++++++ core/hl_walls.py | 16 ++++++- mql5/SR_Levels.mq5 | 42 +++++++++++++++++- web/app.js | 54 +++++++++++++++++++++-- web/index.html | 10 +++-- web/style.css | 5 +++ 7 files changed, 264 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 493ac32..c13b045 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2139,6 +2139,48 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche: + Chart-`fontSize` in `app.js`. Bei künftigen globalen Font-Änderungen die Shorthand nicht vergessen. +## Hyperliquid-Kurs neben dem Broker-Kurs (2026-08-01) + +**User-Wunsch:** „wenn Pepperstone geschlossen ist trotzdem den aktuellen Kurs und die +Liquidität von Hyperliquid einbinden" → nachgeschärft zu „blende den HL-Kurs **neben** +den Pepperstone-Kurs ein" (ehrlicher: man sieht die Abweichung, statt dass still +getauscht wird) → plus „bei geschlossenem Markt auch den **G/V** mit HL berechnen". + +- **Snapshot:** `hl_live {mid_mt5, hl_mid, basis, age_s, bid, ask, bid_sz, ask_sz, + imb5, trend, slope_per_h, vs_mt5}` — IMMER befüllt, nicht nur am Wochenende. + `mid_mt5` = HL-Mid + gemessene Basis (HL `xyz:CL` notiert wegen anderem Kontrakt + ~0,45 $ unter dem CFD; die Basis kommt serverseitig aus dem HL-Projekt als Median + über 60 Snapshots) → direkt mit dem Broker-Kurs vergleichbar. + Dazu `market_closed`, `tick_age_s`, `pnl_hl`. +- **Dashboard (v=129):** eigene Header-Box **HL** neben KURS; Tooltip nennt HL-Rohkurs, + Basis, Alter und Abweichung. Bei geschlossenem Markt heißt das Kurs-Label + „KURS · ZU", die Session-Zeile zeigt „🔒 MARKT ZU", und das **G/V wechselt auf die + HL-Schätzung** (mit `≈` markiert, Tooltip nennt den eingefrorenen Broker-Wert). +- **MT5 (Indikator v1.34):** `HL;;;;;` → + bernsteinfarbenes Label unter Kurs und G/V (`InpShowHL`/`InpHLColor`). + +⚠ **DREI Sackgassen bei der „Markt zu"-Erkennung — dokumentiert, damit sie niemand +wiederholt:** +1. **`tick_local_ts`** ist die lokale **ABHOLZEIT**, nicht das Tick-Alter — sie + erneuert sich bei jedem Abruf, auch wenn der Broker denselben alten Tick liefert. +2. **`tick_server_ts` − `trader._broker_offset_s()`** ist **ZIRKULÄR**: die + Offset-Funktion leitet den Zeitzonen-Versatz selbst aus dem letzten Tick ab + (`off = tick.time − now`). Bei geschlossenem Markt misst sie die Tick-Veraltung + statt der Zeitzone (real **−7,41 h** statt +3 h) — das Alter hebt sich rechnerisch + auf (Ergebnis: **−347 s**). +3. **`pnl / Kursbewegung`** als EUR-je-Punkt-Faktor ergab **155 statt ~86 EUR** je + 1,00 und Lot, weil `trader.pnl = profit + swap` den über das Wochenende + aufgelaufenen Swap enthält. +**Verwendet wird stattdessen:** Markt zu = **der Kurs hat sich seit `_TICK_STALE_S` +(180 s) nicht BEWEGT** (`_last_bid`/`_last_bid_move_ts`) — kein Zeitzonen-, Kalender- +oder Feiertagswissen nötig, deckt Wochenende, Feiertag und Broker-Ausfall gleich ab. +Und der G/V nutzt die vorhandene, korrekte Umrechnung **`trader.live_pnl(bid, ask)`** +(`tick_size`/`tick_value` inkl. Swap und Währung), gefüttert mit dem HL-Kurs ± halbem +Spread. ⚠ Bleibt eine **Schätzung** (anderer Kontrakt, Montags-Open-Spread unbekannt) — +deshalb das `≈` in der Anzeige. +⚠ Nach einem Server-Neustart braucht die Erkennung 180 s, bis sie greift (der +Bewegungs-Zeitstempel startet beim ersten Snapshot). + ## Web-API (server.py) `GET /api/snapshot` (inkl. `verdict`-Aggregat) `/api/health` `/api/logs` `/api/stats` `/api/news` `/api/bars?tf=&n=` (Charts, read-only) `/api/squeeze_monitor` (B4-Monitor, read-only, Engine-Cache 60 s) · `WS /ws` · `POST /api/order|auto|trail|emergency|takeprofit|sltp|srclose|srclose_min|autosqueeze|autosignal|auth/check`. diff --git a/core/engine.py b/core/engine.py index 9cda53a..58c9907 100644 --- a/core/engine.py +++ b/core/engine.py @@ -81,6 +81,9 @@ _SQUEEZE_REENTRY_COOLDOWN_S = 180.0 # nach JEDEM Close eines Trades (Notfall/SL # gegen die Open→Instant-Close-Kaskade bei zu engem Stop # (real 2026-07-27 15:39: −3-€-Stop killte Entry #1 in 16 s, # Squeeze noch aktiv → sofortiger Re-Entry; 2026-07-28) +_TICK_STALE_S = 180 # kein Tick seit X s → Markt gilt als geschlossen. + # Absichtlich tick-basiert statt kalenderbasiert: deckt + # Wochenende, Feiertage UND Broker-Ausfall mit einer Regel. _TRADE_MARKS = 6 # so viele letzte Trades im MQL5-Chart markieren # (Kerze umranden: Eröffnung hellgrün, Close dunkelgrün) _STARTUP_GRACE_S = 60.0 # nach Bot-Start schließt der Bot 60 s lang KEINEN @@ -321,6 +324,10 @@ class TradingEngine: self._open_pos_dir = None # Richtung der aktuell offenen Position (LONG/SHORT) self._pos_close_ts = 0.0 # Zeit + Richtung des letzten Positions-Close (JEDE self._news_block_logged = None # Dedup für die News-Blackout-Logzeile + # Markt-zu-Erkennung über die letzte KURSBEWEGUNG (s. `snapshot`) — die + # Tick-Zeitstempel taugen dafür nicht (Abholzeit bzw. zirkulärer Offset). + self._last_bid = None + self._last_bid_move_ts = 0.0 # Auto-Flip-Close (User-Wunsch 2026-07-31) — ⚠ GEMESSEN NEGATIV in beiden # Hälften (`backtest_flipclose2.py`), s. `_check_flip_close`. Default-Schwelle # 0,5×ATR = die mildeste der gemessenen Varianten. @@ -2367,6 +2374,20 @@ class TradingEngine: f"Konsens {_b:+.2f}") except Exception: pass + # ── HYPERLIQUID-ERSATZKURS bei geschlossenem Markt (User 2026-08-01): + # HL;;;;; — der Indikator + # zeigt ihn UNTER dem (eingefrorenen) MT5-Kurs, sobald kein Tick mehr + # kommt. HL (`xyz:CL`) handelt 24/7, Pepperstone nicht; ohne das sieht man + # am Wochenende einen Freitags-Kurs und merkt es nicht. + try: + _w = self.hl_walls.walls() + if _w and _w.get("mid_mt5") is not None: + _tr = (_w.get("trend") or {}).get("dir") + lines.append(f"HL;{_w['mid_mt5']:.3f};{float(_w.get('age_s') or 0):.0f};" + f"{_w.get('bid')};{_w.get('ask')};" + f"{'U' if _tr == 'up' else 'D' if _tr == 'down' else '-'}") + except Exception: + pass # G/V der offenen Position, direkt unter dem Kurs (User-Wunsch 2026-07-30): # PL;wert;waehrung. **NETTO** wie im Dashboard — bei Gewinn abzüglich der # WHT-Quellensteuer, die der Broker einbehält (`[trading] wht_pct`); bei @@ -2999,6 +3020,74 @@ class TradingEngine: stop_approach = self._stop_approach_hint(market, position, wave_snap) # einmal holen — Verdict-Stimme UND Snapshot-Feld nutzen dasselbe Objekt _pat_snap = self.patterns.snapshot() + # ── Marktstatus + Hyperliquid-Kurs (User 2026-08-01) ───────────────── + # ⚠ ZWEI Sackgassen bei der Markt-zu-Erkennung, beide verworfen: + # (1) `tick_local_ts` ist die lokale ABHOLZEIT — erneuert sich bei jedem + # Abruf, auch wenn der Broker denselben alten Tick liefert. + # (2) `tick_server_ts` minus `trader._broker_offset_s()` ist ZIRKULÄR: die + # Offset-Funktion leitet den Zeitzonen-Versatz selbst aus dem letzten + # Tick ab (`off = tick.time - now`). Bei geschlossenem Markt misst sie + # damit die Tick-Veraltung statt der Zeitzone (real −7,41 h statt +3 h) + # und das Alter hebt sich rechnerisch auf (Ergebnis: −347 s). + # Verwendet wird daher der direkte Beleg: **wann hat sich der Kurs zuletzt + # BEWEGT?** Kein Zeitzonen-, Kalender- oder Feiertagswissen nötig. + _now = time.time() + try: + _b = (market or {}).get("bid") + if _b is not None: + if self._last_bid is None or abs(float(_b) - self._last_bid) > 1e-9: + self._last_bid = float(_b) + self._last_bid_move_ts = _now + except Exception: + pass + _tick_age = (round(_now - self._last_bid_move_ts) + if self._last_bid_move_ts else None) + _mkt_closed = bool(_tick_age is not None and _tick_age > _TICK_STALE_S) + + # HL-Kurs IMMER mitliefern (User: „blende den Hyperliquid-Kurs NEBEN den + # Pepperstone-Kurs ein") — nicht nur bei geschlossenem Markt. So sieht man + # laufend die Abweichung; am Wochenende ist es der einzige lebende Kurs. + _hl_live = None + try: + _w = self.hl_walls.walls() + if _w and _w.get("mid_mt5") is not None: + _hl_live = { + "mid_mt5": _w["mid_mt5"], "hl_mid": _w.get("hl_mid"), + "basis": _w.get("basis"), "age_s": _w.get("age_s"), + "bid": _w.get("bid"), "ask": _w.get("ask"), + "bid_sz": _w.get("bid_sz"), "ask_sz": _w.get("ask_sz"), + "imb5": _w.get("imb5"), + "trend": (_w.get("trend") or {}).get("dir"), + "slope_per_h": (_w.get("trend") or {}).get("slope_per_h"), + "vs_mt5": (round(_w["mid_mt5"] - float(market["bid"]), 3) + if (market or {}).get("bid") else None), + } + except Exception: + pass + + # ── G/V mit HL-Kurs, wenn der Broker eingefroren ist (User 2026-08-01) ── + # Bei geschlossenem Markt steht `position.pnl` still. Die Schätzung setzt den + # HL-Kurs (basis-korrigiert, also MT5-Niveau) in `trader.live_pnl()` ein — die + # BEREITS VORHANDENE, korrekte Umrechnung über `tick_size`/`tick_value` inkl. + # Swap und Währungsumrechnung. + # ⚠ Erster Versuch leitete den EUR-je-Punkt-Faktor aus `pnl / Kursbewegung` + # ab — das ergab 155 statt ~86 EUR je 1,00 und Lot, weil `pnl` den über das + # Wochenende aufgelaufenen SWAP enthält. Eine Kennzahl aus einer anderen + # Kennzahl zurückzurechnen ist hier schlicht falsch, wenn zusätzliche Terme + # drinstecken. + # ⚠ Bleibt eine SCHÄTZUNG: HL ist ein anderer Kontrakt (Basis herausgerechnet, + # aber nicht exakt), und der Spread am Montags-Open ist unbekannt. + _pnl_hl = None + try: + if _mkt_closed and _hl_live and position and position.get("ticket"): + _mid = float(_hl_live["mid_mt5"]) + _sp = float((market or {}).get("spread") or 0.0) + _v = self.trader.live_pnl(_mid - _sp / 2.0, _mid + _sp / 2.0) + if _v is not None: + _pnl_hl = round(_v, 2) + except Exception: + pass + snap = { "ts": time.time(), "connected": self._connected, @@ -3085,6 +3174,21 @@ class TradingEngine: # Wirtschaftskalender: {blackout, next, enabled, n} — Anzeige + Grund, # warum der Bot gerade keine autonome Order eröffnet. "calendar": self.calendar.snapshot(), + # ── MARKT ZU + HYPERLIQUID-ERSATZKURS (User-Wunsch 2026-08-01) ────── + # Pepperstone handelt WTI nicht am Wochenende; der Snapshot zeigt dann + # den EINGEFRORENEN Freitags-Kurs, ohne dass man es sieht (der grüne + # Punkt im Header ist die VERBINDUNG, nicht der Marktstatus). Hyperliquid + # (`xyz:CL`) läuft dagegen 24/7 weiter. + # `market_closed` wird NICHT aus dem Kalender abgeleitet, sondern aus dem + # ALTER DES LETZTEN TICKS — das deckt Wochenende, Feiertage und + # Broker-Ausfälle mit derselben Regel ab, ohne Kalenderpflege. + # `hl_live.mid_mt5` = HL-Mid + gemessene Basis (HL notiert ~0,45 $ unter + # dem CFD, anderer Kontrakt) → direkt mit dem MT5-Kurs vergleichbar. + "market_closed": _mkt_closed, + "tick_age_s": _tick_age, + "hl_live": _hl_live, + # G/V-Schaetzung auf HL-Basis, nur bei geschlossenem Markt (sonst None) + "pnl_hl": _pnl_hl, } # ── Entry-Checkliste je Richtung (User-Vorgabe 2026-07-30: „blende einen # Hinweis ein, wenn die Checkliste gegen meine Eröffnung ist"). Wird im diff --git a/core/hl_walls.py b/core/hl_walls.py index 2a7c005..9f67201 100644 --- a/core/hl_walls.py +++ b/core/hl_walls.py @@ -79,7 +79,21 @@ class HLWalls: # gewichteten Wand-Schwerpunkt): {t1,p1,t2,p2,dir,slope_per_h} # — Zeiten sind LOKALE Epoch, der Aufrufer rechnet sie in # Broker-Zeit um (MT5-Charts brauchen Broker-Zeit). - "trend": d.get("trend")} + "trend": d.get("trend"), + # ── Ergänzt 2026-08-01 (User: „blende den Hyperliquid- + # Kurs neben den Pepperstone-Kurs ein"): der HL-MITTELKURS + # auf MT5-Niveau. HL `xyz:CL` notiert wegen anderem + # Kontrakt/Contango ~0,45 $ unter dem CFD — `basis` ist die + # serverseitig gemessene Differenz (Median über 60 + # Snapshots), `mid_mt5` also direkt mit dem Broker-Kurs + # vergleichbar. Nützlich vor allem am Wochenende: HL + # handelt 24/7, Pepperstone nicht. + "hl_mid": (float(d["hl_mid"]) + if d.get("hl_mid") is not None else None), + "mid_mt5": (round(float(d["hl_mid"]) + + float(d.get("basis") or 0.0), 3) + if d.get("hl_mid") is not None else None), + "age_s": round(age, 1)} self._fail_logged = False except Exception as e: if not self._fail_logged: # nur 1× melden, nicht jeden Tick diff --git a/mql5/SR_Levels.mq5 b/mql5/SR_Levels.mq5 index ec0dcb7..1204136 100644 --- a/mql5/SR_Levels.mq5 +++ b/mql5/SR_Levels.mq5 @@ -12,7 +12,11 @@ //| 4) Der Bot muss laufen (schreibt die CSV alle ~5 s). | //+------------------------------------------------------------------+ #property copyright "Oil Trading Bot" -#property version "1.33" +#property version "1.34" +// v1.34 (2026-08-01): HYPERLIQUID-KURS (HL;...) unter Kurs und G/V oben rechts, +// bernstein. HL handelt 24/7, Pepperstone nicht - am Wochenende der einzige +// lebende Kurs; die Basis (~0,45 $ Kontrakt-Differenz) ist herausgerechnet, +// der Wert also direkt mit dem Broker-Kurs vergleichbar. InpShowHL/InpHLColor. // v1.33 (2026-07-31): Konsens-Pfeil (K) per Default AUS + Pfeile kuerzer (8 statt // 14 Bars). Grund: L und K starten am selben Punkt und zeigten oft in // ENTGEGENGESETZTE Richtungen - zwei divergierende Linien aus einem Punkt @@ -185,6 +189,8 @@ input color InpArrConsensus = C'139,148,158'; // Konsens der Module (NICHT kali input bool InpShowConsensus = false; // Konsens-Pfeil zusaetzlich zeichnen input int InpArrBars = 8; // Pfeil-Laenge in Bars (kuerzer = Spitze sichtbar) input color InpConeColor = C'139,148,158'; // Kegel-Farbe (neutral grau - bewusst KEINE Richtungsfarbe) +input bool InpShowHL = true; // Hyperliquid-Kurs unter dem Broker-Kurs +input color InpHLColor = C'232,160,0'; // HL-Kurs (bernstein, klar unterscheidbar) input bool InpShowPnL = true; // G/V der offenen Position unter dem Kurs input color InpPnLUpColor = C'0,255,127'; // G/V im Plus (neongruen) input color InpPnLDownColor = C'255,69,0'; // G/V im Minus (rot) @@ -798,6 +804,40 @@ void Redraw() ObjectSetString(0, atn, OBJPROP_TEXT, " " + a_txt); continue; } + // HYPERLIQUID-KURS unter dem Broker-Kurs: HL;;;;; + // HL (`xyz:CL`) handelt 24/7, Pepperstone nicht - am Wochenende der einzige + // lebende Kurs. Bereits basis-korrigiert, also direkt vergleichbar. + if(typ == "HL") + { + if(k < 6) continue; + if(!InpShowHL) continue; + double hlp = StringToDouble(p[1]); + if(hlp <= 0) continue; + int hage = (int)StringToInteger(p[2]); + string htr = p[5]; + string hn = PFX + "HLPX"; + if(ObjectFind(0, hn) < 0) + { + ObjectCreate(0, hn, OBJ_LABEL, 0, 0, 0); + ObjectSetInteger(0, hn, OBJPROP_CORNER, CORNER_RIGHT_UPPER); + ObjectSetInteger(0, hn, OBJPROP_XDISTANCE, 12); + // unter Kurs (14) und G/V (14+PriceSize+6) einreihen + ObjectSetInteger(0, hn, OBJPROP_YDISTANCE, 14 + InpPriceSize + 6 + InpPriceSize - 4); + ObjectSetInteger(0, hn, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER); + ObjectSetInteger(0, hn, OBJPROP_SELECTABLE, false); + ObjectSetString (0, hn, OBJPROP_FONT, "Arial"); + } + ObjectSetInteger(0, hn, OBJPROP_FONTSIZE, (int)MathMax(10, InpPriceSize - 7)); + ObjectSetInteger(0, hn, OBJPROP_COLOR, InpHLColor); + ObjectSetString (0, hn, OBJPROP_TEXT, + "HL " + DoubleToString(hlp, (int)_Digits) + + (htr == "U" ? " ^" : htr == "D" ? " v" : "")); + ObjectSetString (0, hn, OBJPROP_TOOLTIP, + "Hyperliquid xyz:CL, basis-korrigiert auf MT5-Niveau - " + + IntegerToString(hage) + " s alt. Waende " + + p[3] + " / " + p[4]); + continue; + } // AKTUELLER KURS oben rechts, fett (User-Wunsch): PX;bid if(typ == "PX") { diff --git a/web/app.js b/web/app.js index 53bea5c..732d065 100644 --- a/web/app.js +++ b/web/app.js @@ -429,9 +429,15 @@ function render(d) { const storm = (d.news_storm || {}).level; if (storm === "storm") stxt = `📰 NEWS-STURM · ${stxt}`; else if (storm === "elevated") stxt = `📰 viele News · ${stxt}`; + // Marktstatus VOR die Session-Zeile: bei geschlossenem Markt ist die Phase + // ("Wochenende") allein zu leise — der eingefrorene Kurs sah live aus. + if (d.market_closed) { + stxt = `🔒 MARKT ZU · ${stxt}`; // HL-Kurs steht jetzt im Header + } $("session").textContent = stxt; $("session").className = "session-line " + - (storm === "storm" ? "warn" + (d.market_closed ? "warn" + : storm === "storm" ? "warn" : (_h === 21 || _h === 22) ? "warn" : ses.just_opened ? "warn" : (ses.active && ses.active.length) ? "ok" : "dim"); @@ -464,16 +470,56 @@ function render(d) { } // ── Header: Kurs (färbt sich nahe S/R) + G/V der offenen Position (netto) ── + // ⚠ MARKT ZU (User 2026-08-01): Pepperstone handelt WTI nicht am Wochenende, der + // Kurs friert dann auf dem Freitags-Stand ein — sichtbar war das NICHT (der grüne + // Punkt im Header ist die VERBINDUNG, nicht der Marktstatus). Hyperliquid läuft + // 24/7 weiter, also zeigen wir dessen Kurs (basis-korrigiert = MT5-vergleichbar) + // statt des eingefrorenen — deutlich als „HL" gekennzeichnet, damit niemand ihn + // für einen Broker-Kurs hält. + // ⚠ Der BROKER-Kurs bleibt der Hauptkurs (erster Entwurf ersetzte ihn bei + // geschlossenem Markt durch den HL-Kurs — der User wollte stattdessen BEIDE + // nebeneinander, was ehrlicher ist: man sieht die Abweichung statt einer + // stillen Vertauschung). $("hdr-price").textContent = m.bid != null ? fmt(m.bid) : "—"; $("hdr-price").className = priceCls; + $("hdr-price-lbl").textContent = d.market_closed ? "KURS · ZU" : "KURS"; + $("hdr-price-lbl").title = d.market_closed + ? `Pepperstone geschlossen — letzter Tick vor ${Math.round((d.tick_age_s || 0) / 60)} min` + : ""; + + // Hyperliquid daneben: basis-korrigiert (= MT5-Niveau), mit Abweichung im Tooltip. + const hl = d.hl_live || null; + const hlEl = $("hdr-hl"); + if (hl && hl.mid_mt5 != null) { + const arr = hl.trend === "up" ? "▲" : hl.trend === "down" ? "▼" : ""; + hlEl.textContent = fmt(hl.mid_mt5) + (arr ? " " + arr : ""); + const dv = hl.vs_mt5; + hlEl.className = d.market_closed ? "hl-price" + : (dv != null && Math.abs(dv) >= 0.15) ? "hl-price" : ""; + hlEl.title = `Hyperliquid xyz:CL ${fmt(hl.hl_mid)} + gemessene Basis ` + + `${hl.basis >= 0 ? "+" : ""}${fmt(hl.basis, 3)} = ${fmt(hl.mid_mt5)} · ` + + `${fmt(hl.age_s, 0)} s alt` + + (dv != null ? ` · ggü. Broker ${dv >= 0 ? "+" : ""}${fmt(dv, 3)}` : ""); + } else { + hlEl.textContent = "—"; hlEl.className = ""; hlEl.title = ""; + } + const hpos = d.position || {}; if (hpos.ticket) { const wht = d.wht_pct || 0; - const raw = hpos.pnl || 0; + // ⚠ Bei geschlossenem Markt steht der Broker-P&L still (der Kurs ist eingefroren). + // Dann die HL-SCHÄTZUNG zeigen (User 2026-08-01) — klar als Schätzung markiert: + // Swap/Kommission der Wochenendtage fehlen und HL ist ein anderer Kontrakt. + const useHl = d.market_closed && d.pnl_hl != null; + const raw = useHl ? d.pnl_hl : (hpos.pnl || 0); const netHdr = raw > 0 ? raw * (1 - wht / 100) : raw; - $("hdr-pnl").textContent = (netHdr >= 0 ? "+" : "") + cs + fmt(netHdr, 2); + $("hdr-pnl").textContent = (useHl ? "≈" : "") + (netHdr >= 0 ? "+" : "") + cs + fmt(netHdr, 2); $("hdr-pnl").className = netHdr > 0 ? "up" : netHdr < 0 ? "down" : ""; - } else { $("hdr-pnl").textContent = "—"; $("hdr-pnl").className = ""; } + $("hdr-pnl").title = useHl + ? `Schätzung auf Basis des Hyperliquid-Kurses — der Broker-Kurs ist eingefroren ` + + `(Broker-P&L ${fmt(hpos.pnl || 0, 2)} ${cs}). Ohne Swap/Kommission des Wochenendes.` + : ""; + } else { $("hdr-pnl").textContent = "—"; $("hdr-pnl").className = ""; $("hdr-pnl").title = ""; } // ── S/R-Annäherungs-Warnung (Position-Kachel) — NUR wenn kein reicherer // Positions-Hint (pos-srhint) läuft, sonst doppeltes „nähert sich Widerstand". diff --git a/web/index.html b/web/index.html index ed3bfc2..88fe806 100644 --- a/web/index.html +++ b/web/index.html @@ -6,7 +6,7 @@ Oil · MT5 - + @@ -34,7 +34,11 @@
-
+
+ +
@@ -244,6 +248,6 @@ - + diff --git a/web/style.css b/web/style.css index 6800c08..bc9a92e 100644 --- a/web/style.css +++ b/web/style.css @@ -484,3 +484,8 @@ main{padding-bottom:74px} /* Platz für die fixe Leiste */ .sqm-row b.up{ color:var(--up); } .sqm-row b.down{ color:var(--down); } .sqm-exp{ font-size:15px; color:var(--dim); margin-top:6px; } .sqm-note{ font-size:16px; color:var(--dim); margin-top:8px; line-height:1.4; } + +/* Kurs aus Hyperliquid (Markt bei Pepperstone geschlossen) - bewusst ANDERS + gefaerbt als der Broker-Kurs, damit man ihn nicht verwechselt. */ +#hdr-price.hl-price{color:var(--accent)} +#hdr-price-lbl{letter-spacing:.3px}