Hyperliquid geprueft: Orderbuch-Stimme raus, Funding gemessen (traegt nicht),

Kontext in die Meldungen (v=145)

Direkt gegen die HL-API geprueft statt aus dem Code geschlossen.

ANGEBOT: 4 Oel-Maerkte (2 liquide: xyz:CL OI 3,07 Mio, xyz:BRENTOIL 2,25 Mio),
je Markt mark/oracle/funding/open_interest/day_volume + l2Book (20 Level je
Seite). Historie: fundingHistory 5.095 Stundenwerte ueber 7 Monate inkl.
premium. Open Interest hat KEINE Historie -> waere sammelpflichtig.

Netz-Frage geklaert: config sagt testnet (leeres Buch, 0 Bids/0 Asks), aber es
sind zwei Schalter — [hyperliquid] network steuert das Handeln (aus),
[sim] price_network die Daten (mainnet, live bestaetigt).

(1) Mehr Orderbuch-Daten: NEIN. Zweimal unabhaengig gemessen — bookflow_report
    0,2-1,0 bp gegen eine ~3-bp-Schwelle und KIPPT; Lead-Lag: Pepperstone
    fuehrt, HL trifft nach 6 s zu 51 %.
(2) Modul "Orderbuch" Gewicht 0,5 -> 0. Ueber 2.688 Episoden beidhaelftig
    negativ (-0,054/-0,066, 49 % Treffer). Chip bleibt.
(3) analyze_hl_funding.py: Funding/Premium gegen den CFD, 2 Haelften.
    ⚠ Der erste Lauf meldete mehrere "robuste" Buckets und war FALSCH —
    ueberlappende Forward-Fenster (aus n=506 werden ~21 unabhaengige Faelle)
    und global gebildete Quintile (Bucket mit der Zeit konfundiert). Dass
    Funding- und Premium-Tabelle fast identisch waren, war der dritte Hinweis:
    HL rechnet das Funding aus dem Premium. Entueberlappt haelt kein Bucket.
(4) hl_ctx in den Meldungen (#hl-note) als reine Anzeige.
    ⚠ Zwei Bau-Fallen behoben: der Aufruf erbte den 2-s-Timeout der Waende und
    lief still ins Leere (braucht real 7,2 s), und er haette den Trend-Loop
    blockiert -> Daemon-Thread wie beim Wirtschaftskalender.

Live verifiziert: hl_ctx befuellt, Orderbuch weight=0 bei erhaltenem Chip,
v=145 ausgeliefert, eine Instanz auf Port 8000.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-06 23:38:01 +02:00
co-authored by Claude Opus 5
parent 874ee16e00
commit 2cdd1ba0e8
7 changed files with 375 additions and 4 deletions
+54 -1
View File
@@ -3661,7 +3661,60 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
49 % Treffer) bei Gewicht 0,5 — der einzige konsistent falsche Beitrag.
**Muster** (+1,27/+0,67, 58 %, n=88) und **Liq-Trend** (+0,20/+0,32, n=132)
sehen gut aus, sind aber zu dünn. Alle übrigen kippen zwischen den Hälften.
- Asset-Version aktuell **v=144** (in `web/index.html` hochzählen, siehe Workflows).
- **⚠⚠ HYPERLIQUID: WAS ES LIEFERT UND WAS DAVON TRÄGT (2026-08-06, User-Frage
„können wir mehr HL-Daten nutzen?").** Direkt gegen die API geprüft, nicht aus
dem Code geschlossen.
**Angebot:** vier Öl-Märkte, zwei mit echter Liquidität — `xyz:CL` (unser Feed,
OI 3,07 Mio, Tagesvolumen 316 Mio) und `xyz:BRENTOIL` (OI 2,25 Mio); `flx:OIL`
und `cash:WTI` sind tot (OI 0). Je Markt `mark_px` · **`oracle_px`** ·
**`funding`** · **`open_interest`** · `day_volume`, dazu `l2Book` mit 20 Levels
je Seite. **Historie:** `fundingHistory` gibt **5.095 Stundenwerte über 7 Monate**
(inkl. `premium`), `candleSnapshot` H1-Kerzen, `predictedFundings` venue-übergreifend.
**Open Interest hat KEINE Historie** — nur der Momentanwert; OI wäre
sammelpflichtig und bleibt offen.
**Netz-Frage geklärt (sah zuerst nach einem Defekt aus):** `config.ini` sagt
`network = testnet`, und **Testnet hat ein LEERES Buch** (0 Bids/0 Asks, OI 2,55
gegen 3,07 Mio). Es sind aber **zwei** Schalter: `[hyperliquid] network` steuert
das **Handeln** (bewusst aus), `[sim] price_network` die **Daten** und steht per
Default auf mainnet — live bestätigt (`/api/market` meldet `network: mainnet`).
⚠ Bleibt eine Falle: ein Wort in der falschen Sektion, und der Bot zeichnet
stillschweigend Wände aus einem leeren Buch.
**(1) MEHR ORDERBUCH-DATEN = NEIN, zweimal unabhängig gemessen.** Das HL-Projekt
selbst (`bookflow_report.txt`): Bid/Ask-Druck auf den CFD 0,61/0,52 bp und
**KIPPT**; Wände halten in 4750 %; die eigene Schwelle dort lautet **„< ~3 bp
ist von den Kosten gefressen"** — gemessen sind es 0,21,0 bp. Dazu der
Lead-Lag-Befund: **Pepperstone führt** (Peak k=1 ≈ 6 s), HL-Richtung trifft nach
6 s zu **51 %** (n=545). Alles Preis-Abgeleitete von HL läuft hinterher.
**(2) MODUL „ORDERBUCH" ENTMACHTET — Gewicht 0,5 → 0.** Unabhängige Bestätigung
aus `analyze_verdict_modules.py`: über **2.688 Episoden beidhälftig NEGATIV**
(0,054/0,066 ×ATR, 49 % Treffer) — der einzige konsistent falsche Beitrag im
Feld. Chip bleibt, Stimme entfällt. Zurück: `ow = 0.5`.
**(3) FUNDING/PREMIUM GEMESSEN = TRÄGT NICHT (`analyze_hl_funding.py`).**
Positionierung statt Preis, also nicht vom Lead-Lag-Einwand betroffen — und dank
`fundingHistory` sofort prüfbar. 5.095 Stundenwerte, 3.626 mit passender H1-Bar,
gegen den **Pepperstone-CFD**, 2 Hälften, gegen die Drift.
⚠⚠ **Der erste Lauf meldete mehrere „robuste" Buckets — und war falsch.** Zwei
Fehler in meinem eigenen Skript: **(a) überlappende Forward-Fenster** (stündliche
Beobachtungen, 4/12/24-h-Horizont → aufeinanderfolgende Zeilen teilen fast ihr
ganzes Fenster; aus n=506 werden ~21 unabhängige Fälle) und **(b) global
gebildete Quintile**, wodurch die Bucket-Zugehörigkeit mit der Zeit konfundiert
war (Q5 hatte 506 Fälle in H1, aber 219 in H2 = Regimewechsel, nicht Merkmal).
⚠ Dritter Hinweis, der stutzig machte: **Funding- und Premium-Tabelle waren
nahezu identisch** — HL rechnet das Funding AUS dem Premium; es war eine
Messung, doppelt berichtet.
**Entüberlappt und mit Quintilen je Hälfte hält KEIN Bucket** die Regel; die
verbleibenden ✅ sitzen bei n=1530 und sind Rauschen. **Kein Verdict-Gewicht.**
**(4) HL-KONTEXT IN DEN MELDUNGEN (reine Anzeige, v=145).** `hl_walls.market()`
(lokales Dashboard, keine neue externe Abhängigkeit) → Snapshot **`hl_ctx`** →
Zeile **`#hl-note`**: „Perp 0,03 $ zum Oracle · Funding 0,0083 %/h · OI
3,07 Mio". Kein Gewicht, kein Trigger; der Tooltip nennt die Messung.
**Zwei Bau-Fallen, beide behoben:** der Aufruf lief zunächst immer ins Leere,
weil er den **2-s-Timeout der Wände** erbte — `/api/market` fragt HL live ab und
braucht real **7,2 s** (eigener `_MARKET_TIMEOUT_S=12`); und der stille `except`
machte daraus ein wortloses `None`. Danach hätte er den **Trend-Loop 7 s
blockiert** → läuft jetzt im **Daemon-Thread**, wie der Wirtschaftskalender und
aus demselben Grund.
- Asset-Version aktuell **v=145** (in `web/index.html` hochzählen, siehe Workflows).
Schriftgrößen 2026-07-24 global **+4px** (2× je +2px auf User-Wunsch; Body-Basis
14→18px). ⚠ Betrifft in `style.css` sowohl `font-size:Npx` (71×) ALS AUCH die
`font:<weight> Npx/…`-**Shorthand** (3×: `.ms-chip`/`.ms-bos-lbl`/`.sqm-badge`
+188
View File
@@ -0,0 +1,188 @@
#!/usr/bin/env python3
"""Sagt die Hyperliquid-POSITIONIERUNG (Funding / Premium) den CFD voraus?
ANLASS (2026-08-06, User: „koennen wir mehr HL-Daten nutzen?"). Die Order-Flow-
Klasse ist zweimal unabhaengig gemessen und traegt nicht (`bookflow_report.txt`:
0,21,0 bp gegen eine ~3-bp-Kostenschwelle, KIPPT; `analyze_verdict_modules.py`:
Modul „Orderbuch" ueber 2.688 Episoden beidhaelftig negativ). Ungetestet ist eine
ANDERE Klasse: **Positionierung statt Preis.**
⚠ WARUM DAS NICHT AM LEAD-LAG SCHEITERT. Gemessen fuehrt **Pepperstone** (Peak bei
k=1 ≈ 6 s), HL-Richtung trifft nach 6 s zu 51 %. Damit ist alles PREIS-Abgeleitete
von HL erledigt. Funding und Premium sind aber keine Preisprognose, sondern der
Preis dafuer, eine Position zu HALTEN — eine Bestandsgroesse. Der Lead-Lag-Einwand
greift dort nicht.
✅ UND ES IST SOFORT MESSBAR: `fundingHistory` liefert fuer `xyz:CL` **5.095
Stundenwerte ueber 7 Monate** (inkl. `premium`) — kein wochenlanges Sammeln noetig,
anders als beim Bookflow-Recorder.
⚠ **Open Interest ist NICHT dabei**: die HL-Info-API hat keinen OI-History-
Endpunkt (`metaAndAssetCtxs` liefert nur den Momentanwert). OI waere also
sammelpflichtig und bleibt hier offen.
GEMESSEN WIRD gegen den **Pepperstone-CFD** (das ist, was gehandelt wird), nicht
gegen den HL-Preis:
· Forward-Return ueber 4 / 12 / 24 h, ATR-normiert
· **gegen die DRIFT gelesen** — sonst faerbt das Regime alle Buckets ein
· Buckets nach Funding bzw. Premium (Quintile)
· **2 Haelften** (JanApr / AprAug)
VORAB FIXIERTE ENTSCHEIDUNGSREGEL:
Tragfaehig nur, wenn ein Bucket in BEIDEN Haelften denselben Vorzeichen-
Ueberschuss zeigt UND der Betrag > 0,1×ATR liegt (B3-Huerde). Ein Effekt, der
zwischen den Haelften kippt, ist Rauschen — daran sind 23 Signal-Ideen
gescheitert.
Aufruf: python analyze_hl_funding.py
"""
import bisect
import sys
import time
from datetime import datetime, timedelta, timezone
import MetaTrader5 as mt5
sys.path.insert(0, r"c:/Users/ah/Downloads/HyperLiquid-WTI Trader")
from core.hl_info import post, url_for # noqa: E402
_COIN = "xyz:CL"
_BROKER_OFF = 3 * 3600 # MT5-Bar-Zeit ist Broker-Wallclock (UTC+3)
_HORIZONTE = (4, 12, 24) # Stunden
_HUERDE = 0.10 # B3
def hole_funding() -> list[dict]:
"""Blaettert `fundingHistory` zurueck (500 je Antwort), dedupliziert."""
u = url_for("mainnet")
jetzt = int(time.time() * 1000)
start = jetzt - 400 * 86400000
aus: dict[int, dict] = {}
for _ in range(15):
r = post(u, {"type": "fundingHistory", "coin": _COIN,
"startTime": start}, timeout=20)
if not r:
break
for x in r:
aus[int(x["time"])] = x
if len(r) < 500:
break
start = int(r[-1]["time"]) + 1
return [aus[k] for k in sorted(aus)]
def _atr(H, L, C, n=14):
tr = [0.0] + [max(H[i] - L[i], abs(H[i] - C[i - 1]), abs(L[i] - C[i - 1]))
for i in range(1, len(C))]
out, s = [0.0] * len(C), 0.0
for i in range(1, len(C)):
s += tr[i]
if i > n:
s -= tr[i - n]
out[i] = s / min(i, n)
return out
def quintile(werte: list[float]) -> list[float]:
s = sorted(werte)
return [s[int(q * len(s))] for q in (0.2, 0.4, 0.6, 0.8)]
def main():
fh = hole_funding()
if len(fh) < 500:
print(f"zu wenig Funding-Historie ({len(fh)})"); return 1
if not mt5.initialize():
print("MT5 nicht erreichbar"); return 1
sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD")
if mt5.symbol_info(c)), None)
bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_H1, 0, 20000)
mt5.shutdown()
H = [float(b["high"]) for b in bars]; L = [float(b["low"]) for b in bars]
C = [float(b["close"]) for b in bars]
# Bar-Zeit → ECHTE UTC-Epoch (die Rohwerte sind Broker-Wallclock)
EP = [int(b["time"]) - _BROKER_OFF for b in bars]
A = _atr(H, L, C)
# ── Beobachtungen bauen ──────────────────────────────────────────────
beob = []
for x in fh:
ts = int(x["time"]) // 1000
j = bisect.bisect_right(EP, ts) - 1
if j < 20 or j + max(_HORIZONTE) >= len(C) or A[j] <= 0:
continue
if abs(EP[j] - ts) > 2 * 3600: # keine Bar in der Naehe (Wochenende)
continue
beob.append({"ts": ts, "j": j,
"fund": float(x["fundingRate"]),
"prem": float(x["premium"]),
"atr": A[j]})
if len(beob) < 400:
print(f"zu wenige verwertbare Beobachtungen ({len(beob)})"); return 1
f = lambda s: datetime.fromtimestamp(s, timezone.utc).strftime("%d.%m.%Y")
print("=" * 100)
print(f" HL-POSITIONIERUNG gegen den Pepperstone-CFD ({sym})")
print("=" * 100)
print(f" {len(fh)} Funding-Stundenwerte · {len(beob)} mit passender H1-Bar")
print(f" {f(beob[0]['ts'])} bis {f(beob[-1]['ts'])} · 2 Hälften · "
f"gegen die Drift gelesen · B3-Hürde {_HUERDE:.2f}×ATR")
mitte = len(beob) // 2
for feld, lbl in (("fund", "FUNDING-RATE"), ("prem", "PREMIUM (mark oracle)")):
print()
print("=" * 100)
print(f" {lbl}")
print("=" * 100)
namen = ["Q1 (am negativsten)", "Q2", "Q3 (neutral)", "Q4",
"Q5 (am positivsten)"]
for h in _HORIZONTE:
# ⚠⚠ ENTÜBERLAPPEN. Die Beobachtungen kommen STÜNDLICH, das Fenster ist
# h Stunden lang — aufeinanderfolgende Zeilen teilen sich h1 Stunden
# ihres Forward-Returns. Ungefiltert ist das kein n=506, sondern ~n/h
# unabhängige Fälle, und jede „Robustheit" daraus ist Autokorrelation.
# Deshalb nur jede h-te Beobachtung.
print(f" ── Horizont {h} h (entüberlappt: jede {h}. Beobachtung) "
+ "" * 22)
print(f" {'Bucket':<22}{'H1 Übersch.':>14}{'H2 Übersch.':>14}"
f"{'n H1/H2':>12} Urteil")
for q in range(5):
zeile = []
for lo, hi in ((0, mitte), (mitte, len(beob))):
# ⚠ Quintile JE HÄLFTE. Global gebildet wandern die Grenzen mit
# dem Funding-Regime, und die Bucket-Zugehörigkeit wäre mit der
# Zeit konfundiert (real: Q5 hatte 506 Fälle in H1, aber nur 219
# in H2 — das misst den Regimewechsel, nicht das Merkmal).
alle = beob[lo:hi:h]
if len(alle) < 50:
zeile.append((None, 0)); continue
gr = quintile([b[feld] for b in alle])
bucket = lambda v: sum(1 for g in gr if v > g)
grp = [b for b in alle if bucket(b[feld]) == q]
if len(grp) < 15:
zeile.append((None, len(grp))); continue
r = lambda b: (C[b["j"] + h] - C[b["j"]]) / b["atr"]
m = sum(r(b) for b in grp) / len(grp)
drift = sum(r(b) for b in alle) / len(alle)
zeile.append((m - drift, len(grp)))
(u1, n1), (u2, n2) = zeile
if u1 is None or u2 is None:
print(f" {namen[q]:<22}{'':>14}{'':>14}{f'{n1}/{n2}':>12}")
continue
robust = (u1 > 0) == (u2 > 0) and min(abs(u1), abs(u2)) > _HUERDE
print(f" {namen[q]:<22}{u1:>+14.3f}{u2:>+14.3f}"
f"{f'{n1}/{n2}':>12} {'✅ robust' if robust else ''}")
print()
print("=" * 100)
print(" LESART: Überschuss = Kursbewegung MINUS der allgemeinen Drift der")
print(" jeweiligen Hälfte. ✅ nur, wenn das Vorzeichen in BEIDEN Hälften gleich")
print(" ist UND der Betrag über der Kostenhürde liegt.")
print(" ⚠ Open Interest fehlt: die HL-Info-API hat dafür keine Historie.")
print(" ⚠ `xyz:CL` ist mit ~3 Mio OI ein winziger Markt gegen NYMEX-CL — dass")
print(" seine Positionierung einen globalen Benchmark vorhersagt, ist a priori")
print(" unwahrscheinlich. Genau deshalb wird gemessen statt vermutet.")
return 0
if __name__ == "__main__":
sys.exit(main())
+40 -1
View File
@@ -694,6 +694,20 @@ class TradingEngine:
except Exception as re_: log.warning(f"rec_outcomes: {re_}")
# Wirtschaftskalender (self-throttled ~1 h, außerhalb des mt5_lock
# unkritisch — reiner HTTP-Fetch mit Timeout)
# HL-Kontext (Funding/OI/Premium) — reine Anzeige.
# ⚠⚠ IM DAEMON-THREAD, nicht inline: der Aufruf fragt die
# HL-API live nach allen Öl-Märkten und braucht real ~7 s.
# Inline würde er den Trend-Loop bei jedem Fälligwerden
# (~5 min) so lange anhalten — dieselbe Begründung, aus der
# der Wirtschaftskalender im Thread läuft. `market()` ist
# selbst gedrosselt und thread-sicher, ein zweiter Aufruf
# während der erste läuft liefert einfach den Cache.
try:
if not getattr(self, "_hl_ctx_busy", False):
self._hl_ctx_busy = True
threading.Thread(target=self._hl_ctx_refresh,
daemon=True).start()
except Exception as he: log.debug(f"hl market: {he}")
try: self.calendar.maybe_refresh()
except Exception as ke: log.warning(f"calendar.refresh: {ke}")
self._run_analysis()
@@ -2974,7 +2988,20 @@ class TradingEngine:
imb = w.get("imb5")
if isinstance(imb, (int, float)) and abs(imb) >= _OB_IMB_MIN:
ov = 1 if imb > 0 else -1
ow = 0.5
# ⚠⚠ GEWICHT AUF 0 (2026-08-06). Das Orderbuch-Modul ist aus
# ZWEI unabhängigen Richtungen als nicht tragfähig gemessen:
# · `analyze_verdict_modules.py` (15.544 Zeilen): über **2.688
# Episoden beidhälftig NEGATIV** (0,054/0,066 ×ATR, 49 %
# Treffer) — der einzige konsistent falsche Beitrag im Feld.
# · Das HL-Projekt selbst (`bookflow_report.txt`): Bid/Ask-Druck
# auf den CFD übertragen 0,61/0,52 bp und KIPPT; die eigene
# Schwelle dort lautet „< ~3 bp ist von den Kosten gefressen".
# Dazu der Lead-Lag-Befund: **Pepperstone führt** (Peak k=1 ≈ 6 s),
# HL-Richtung trifft nach 6 s zu 51 % (n=545) — alles
# Preis-Abgeleitete von HL läuft hinterher.
# Der CHIP bleibt (Imbalance ist als Kontext lesbar), nur die
# Stimme entfällt. Zurück: `ow = 0.5`.
ow = 0.0
odet = f"Imbalance {imb:+.2f}"
elif isinstance(imb, (int, float)):
odet = f"Imbalance {imb:+.2f} (zu schwach)"
@@ -3090,6 +3117,17 @@ class TradingEngine:
self._align_ts = now
return getattr(self, "_align_cache", None)
def _hl_ctx_refresh(self):
"""Holt den HL-Kontext im Hintergrund (s. Aufrufstelle im Trend-Loop)."""
try:
d = self.hl_walls.market()
if d:
self._hl_ctx = d
except Exception as e:
log.debug(f"hl market: {e}")
finally:
self._hl_ctx_busy = False
def _block_mix_cached(self) -> dict | None:
"""WELCHE Gates blocken heute, und wie oft? (2026-08-06)
@@ -3726,6 +3764,7 @@ class TradingEngine:
(self.news.sentiment or {}).get("score")),
"alignment": self._alignment_cached(),
"block_mix": self._block_mix_cached(),
"hl_ctx": getattr(self, "_hl_ctx", None),
"rec_track": self._rec_track_cached(),
# Kennzahlen der MANUELLEN Trades für die gleichnamige Karte
# (2026-08-04). Rein deskriptiv; ~120 s gecacht, damit der heiße
+58
View File
@@ -33,6 +33,12 @@ 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)
_MARKET_TTL_S = 300.0 # Funding/OI aendern sich stuendlich — 5 min genuegt
# ⚠ EIGENER, laengerer Timeout: `/api/market` fragt die HL-API live nach ALLEN
# Oel-Maerkten (4 Stueck) und braucht deutlich laenger als der Waende-Endpunkt,
# der aus einer lokalen DB liest. Mit dem kurzen Waende-Timeout lief der Aufruf
# immer ins Leere — und der stille `except` machte daraus ein wortloses None.
_MARKET_TIMEOUT_S = 12.0
_MAX_AGE_S = 60.0 # älter = HL-Feed steht → nicht mehr zeichnen
_STALE_GRACE_S = 120.0 # nach einem Fehlschlag den letzten guten Stand so lange
# weiterreichen (Blink-Fix — s. Kommentar in `walls()`)
@@ -47,6 +53,58 @@ class HLWalls:
self._cache: dict | None = None
self._cache_ts = 0.0
self._fail_logged = False
self._mkt_cache: dict | None = None
self._mkt_ts = 0.0
def market(self) -> dict | None:
"""HL-KONTEXT je Oel-Markt: Funding, Open Interest, Oracle-Premium.
⚠⚠ REINE ANZEIGE — kein Verdict-Gewicht, kein Trade-Trigger. Gemessen
(`analyze_hl_funding.py`, 2026-08-06, 5.095 Funding-Stundenwerte ueber
7 Monate gegen den Pepperstone-CFD): **entueberlappt haelt KEIN Bucket**
die 2-Stichproben-Regel. Der erste Lauf sah nach mehreren robusten
Effekten aus — das war Autokorrelation (stuendliche Beobachtungen,
4/12/24-h-Fenster teilen sich fast ihre ganze Laenge).
Deshalb steht das hier als Kontext in den Meldungen und NICHT in der
Empfehlung.
Quelle ist das LOKALE Dashboard (Port 8001), nicht die HL-API direkt —
keine neue externe Abhaengigkeit im Trading-Bot. Eigene, laengere
Drosselung (5 min): Funding aendert sich stuendlich, das braucht nicht
den 5-s-Takt der Waende. Fail-safe: bei Fehlern None.
"""
if not self.enabled:
return None
now = time.time()
with self._lock:
if (self._mkt_cache is not None
and now - self._mkt_ts < _MARKET_TTL_S):
return self._mkt_cache
aus = None
try:
url = self.url.replace("/api/walls", "/api/market")
with urllib.request.urlopen(url, timeout=_MARKET_TIMEOUT_S) as r:
d = json.loads(r.read().decode())
if d.get("ok"):
for m in (d.get("markets") or []):
# Nur der Markt, aus dem auch die Waende kommen.
if m.get("market") != "xyz:CL":
continue
mark, orac = m.get("mark_px"), m.get("oracle_px")
aus = {"funding": m.get("funding"),
"open_interest": m.get("open_interest"),
"mark": mark, "oracle": orac,
"premium": (float(mark) - float(orac))
if (mark and orac) else None,
"day_volume": m.get("day_volume"),
"network": d.get("network")}
break
except Exception:
aus = None # still — Kontext darf nie stoeren
with self._lock:
if aus is not None:
self._mkt_cache, self._mkt_ts = aus, now
return self._mkt_cache
def walls(self) -> dict | None:
"""{'bid','bid_sz','ask','ask_sz','basis','imb5'} auf MT5-Preisniveau —
+23
View File
@@ -202,6 +202,29 @@ function renderVerdict(v, snap) {
}
}
// ── HL-Kontext (Funding / OI / Premium) — reine Anzeige ───────────────
// ⚠ Gemessen ohne Prognosewert (analyze_hl_funding.py): entüberlappt hält
// kein Bucket die 2-Stichproben-Regel. Steht deshalb neutral in den
// Meldungen und NICHT in der Empfehlung. Null-sicher (Cache-Regel).
const hlEl = $("hl-note");
if (hlEl) {
const h = snap && snap.hl_ctx;
if (h && h.premium != null) {
const fr = (h.funding != null) ? (h.funding * 100).toFixed(4) + " %" : "—";
const oi = (h.open_interest != null)
? (h.open_interest / 1e6).toFixed(2) + " Mio" : "—";
hlEl.classList.remove("hidden");
hlEl.textContent = `⛓ Hyperliquid: Perp ${h.premium >= 0 ? "+" : ""}`
+ `${fmt(h.premium, 3)} $ zum Oracle · Funding ${fr}/h · OI ${oi}`;
hlEl.title = "Kontext vom Hyperliquid-Öl-Perp (xyz:CL). Positives Premium = "
+ "der Perp notiert über dem Index, Longs zahlen. ⚠ Gemessen über 5.095 "
+ "Funding-Stundenwerte (7 Monate) gegen den CFD: kein belastbarer "
+ "Prognosewert — deshalb ohne Stimme in der Empfehlung.";
} else {
hlEl.classList.add("hidden");
}
}
// ── Warum WARTEN? Verteilung der blockierenden Gates (heute) ───────────
const blkEl = $("vd-blocks");
if (blkEl) {
+7 -2
View File
@@ -6,7 +6,7 @@
<meta name="theme-color" content="#0d1117">
<title>Oil · MT5</title>
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="style.css?v=144">
<link rel="stylesheet" href="style.css?v=145">
</head>
<body>
<!-- Modul-Menü (ganz oben) -->
@@ -141,6 +141,11 @@
<div class="pos-stophint hidden" id="pos-stophint"></div>
<div class="news-conflict hidden" id="news-conflict"></div>
<div class="news-conflict hidden" id="cal-note"></div>
<!-- HL-Kontext (Funding/Open Interest/Oracle-Premium). ⚠ REINE ANZEIGE:
gemessen (`analyze_hl_funding.py`, 5.095 Stundenwerte, 7 Monate)
hält entüberlappt KEIN Bucket die 2-Stichproben-Regel. Kein
Verdict-Gewicht, kein Trigger. -->
<div class="hl-note hidden" id="hl-note"></div>
<!-- Auto-Flip-Close: schließt eine Position, wenn die Empfehlung dreht.
⚠ GEMESSEN in BEIDEN Halbjahren negativ (92/160 R,
backtest_flipclose2.py), läuft auf ausdrücklichen User-Wunsch. Hatte
@@ -340,6 +345,6 @@
</div>
<div id="toast" class="toast hidden"></div>
<script src="app.js?v=144"></script>
<script src="app.js?v=145"></script>
</body>
</html>
+5
View File
@@ -557,3 +557,8 @@ main{padding-bottom:74px} /* Platz für die fixe Leiste */
zurückgenommen, statt zwei scheinbar gleichrangige Felder zu zeigen. */
.mg-field.muted { opacity: .45; }
.mg-field.muted input { border-style: dashed; }
/* HL-Kontext in den Meldungen — neutral, weil gemessen ohne Prognosewert. */
.hl-note{font-size:13px;color:var(--dim);font-family:var(--mono);
padding:5px 0;border-top:1px solid var(--line);margin-top:5px}
.hl-note.hidden{display:none}