Files
AH-Oil-Trader/core/hl_walls.py
T
Axel HocksandClaude Opus 4.8 7f2285ddb3 MT5-Chart: echte Liquiditaets-Waende statt Chartmuster-Linien (Indikator v1.12)
User-Wunsch: "zeichne mir die liquiditaetslinien in den mt5 ein. entferne die
chartmuster linien aus dem mt5".

- core/hl_walls.py: holt GET /api/walls vom HL-Dashboard (groesstes L2-Level je
  Seite, basis-korrigiert auf CFD-Niveau). Fail-safe: HL aus -> keine Linien, kein
  Fehler; Cache 10s, Daten >60s alt werden verworfen, Log nur 1x.
- engine._write_levels_file: PT-Zeilen raus, LQ;<B|A>;preis;size rein.
- SR_Levels.mq5 v1.12: PT-Handler entfernt, LQ-Handler (dick gestrichelt +
  Groessen-Label), InpShowWalls/InpWallBidColor/InpWallAskColor. Kompiliert.
- config: export_hl_walls=true, hl_walls_url.

Zwei Fallen dokumentiert: (1) Basis-Differenz HL vs CFD ~0,45$ -- ungerechnet laegen
die Linien falsch. (2) 127.0.0.1 statt localhost (IPv6 -> 2066ms statt 19-46ms, lief
in den 2s-Timeout).

Verifiziert: LQ-Zeilen erscheinen in sr_levels.csv (B 83.619/3120, A 83.665/1721),
plausibel zwischen R 83.721 und S 83.516.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 15:16:19 +02:00

81 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""core/hl_walls.py — ECHTE Liquiditäts-Wände von Hyperliquid für den MT5-Chart.
Holt vom HL-Dashboard (Port 8001, `GET /api/walls`) das größte L2-Orderbuch-Level je
Seite — **basis-korrigiert auf das Pepperstone-Preisniveau** — und stellt es dem
Level-Export (`engine._write_levels_file` → `sr_levels.csv` → `SR_Levels.mq5`) bereit.
WARUM (User-Wunsch 2026-07-30): Alle S/R-Linien im Projekt sind aus **Pivots
geschätzt** („wo war mal ein Docht"). Das hier ist die einzige Quelle mit
**tatsächlich ruhenden Orders** — Pepperstone ist Market Maker und liefert kein
Orderbuch, Hyperliquid schon (20 Levels je Seite).
⚠ Zwei Dinge im Blick behalten:
1. **Basis-Differenz**: HL `xyz:CL` notiert ~0,45 $ unter dem CFD (anderer
Kontrakt/Contango). Die Umrechnung passiert SERVERSEITIG im HL-Projekt
(Median über die letzten 60 Snapshots) — hier kommt schon `bid_mt5`/`ask_mt5`
an. Fehlt die Basis (zu wenige Snapshots), wird NICHT gezeichnet.
2. **Anzeige, KEIN Signal.** Ob HL-Orderbuch-Signale auf den CFD übertragbar sind,
ist eine offene Frage und wird gerade gemessen (`analyze_bookflow.py` im
HL-Projekt). Bis dahin fließt hier nichts in Empfehlung/Trade ein.
Fail-safe: kurzer Timeout, Ergebnis gecacht; ist der HL-Server aus, liefert
`walls()` einfach None und der Chart bleibt unverändert.
"""
from __future__ import annotations
import json
import threading
import time
import urllib.request
from core.logger import get_logger
log = get_logger("hlwalls")
_TIMEOUT_S = 2.0 # der MT5-Loop darf nicht am HTTP hängen
_TTL_S = 10.0 # Cache — die Wände wandern langsamer als der Export-Takt (~5 s)
_MAX_AGE_S = 60.0 # älter = HL-Feed steht → nicht mehr zeichnen
class HLWalls:
def __init__(self, url: str = "http://127.0.0.1:8001/api/walls",
enabled: bool = False):
self.url = url
self.enabled = bool(enabled)
self._lock = threading.Lock()
self._cache: dict | None = None
self._cache_ts = 0.0
self._fail_logged = False
def walls(self) -> dict | None:
"""{'bid','bid_sz','ask','ask_sz','basis','imb5'} auf MT5-Preisniveau —
oder None (aus / HL nicht erreichbar / Basis unbekannt / Daten zu alt)."""
if not self.enabled:
return None
now = time.time()
with self._lock:
if self._cache is not None and now - self._cache_ts < _TTL_S:
return self._cache
data = None
try:
with urllib.request.urlopen(self.url, timeout=_TIMEOUT_S) as r:
d = json.loads(r.read().decode())
if d.get("ok") and d.get("bid_mt5") and d.get("ask_mt5"):
# Feed-Alter prüfen: ein stehengebliebenes Buch darf nicht als
# aktuelle Liquidität gezeichnet werden.
age = now - float(d.get("ts") or 0)
if age <= _MAX_AGE_S:
data = {"bid": float(d["bid_mt5"]), "ask": float(d["ask_mt5"]),
"bid_sz": float(d.get("bid_sz") or 0),
"ask_sz": float(d.get("ask_sz") or 0),
"basis": d.get("basis"), "imb5": d.get("imb5")}
self._fail_logged = False
except Exception as e:
if not self._fail_logged: # nur 1× melden, nicht jeden Tick
log.info(f"HL-Wände nicht abrufbar ({e}) — Chart bleibt ohne "
f"Liquiditätslinien (HL-Dashboard auf 8001 läuft nicht?)")
self._fail_logged = True
with self._lock:
self._cache = data
self._cache_ts = now
return data