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:
co-authored by
Claude Opus 5
parent
874ee16e00
commit
2cdd1ba0e8
@@ -3661,7 +3661,60 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
49 % Treffer) bei Gewicht 0,5 — der einzige konsistent falsche Beitrag.
|
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)
|
**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.
|
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 47–50 %; die eigene Schwelle dort lautet **„< ~3 bp
|
||||||
|
ist von den Kosten gefressen"** — gemessen sind es 0,2–1,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=15–30 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
|
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
|
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` —
|
`font:<weight> Npx/…`-**Shorthand** (3×: `.ms-chip`/`.ms-bos-lbl`/`.sqm-badge` —
|
||||||
|
|||||||
@@ -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,2–1,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** (Jan–Apr / Apr–Aug)
|
||||||
|
|
||||||
|
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 h−1 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
@@ -694,6 +694,20 @@ class TradingEngine:
|
|||||||
except Exception as re_: log.warning(f"rec_outcomes: {re_}")
|
except Exception as re_: log.warning(f"rec_outcomes: {re_}")
|
||||||
# Wirtschaftskalender (self-throttled ~1 h, außerhalb des mt5_lock
|
# Wirtschaftskalender (self-throttled ~1 h, außerhalb des mt5_lock
|
||||||
# unkritisch — reiner HTTP-Fetch mit Timeout)
|
# 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()
|
try: self.calendar.maybe_refresh()
|
||||||
except Exception as ke: log.warning(f"calendar.refresh: {ke}")
|
except Exception as ke: log.warning(f"calendar.refresh: {ke}")
|
||||||
self._run_analysis()
|
self._run_analysis()
|
||||||
@@ -2974,7 +2988,20 @@ class TradingEngine:
|
|||||||
imb = w.get("imb5")
|
imb = w.get("imb5")
|
||||||
if isinstance(imb, (int, float)) and abs(imb) >= _OB_IMB_MIN:
|
if isinstance(imb, (int, float)) and abs(imb) >= _OB_IMB_MIN:
|
||||||
ov = 1 if imb > 0 else -1
|
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}"
|
odet = f"Imbalance {imb:+.2f}"
|
||||||
elif isinstance(imb, (int, float)):
|
elif isinstance(imb, (int, float)):
|
||||||
odet = f"Imbalance {imb:+.2f} (zu schwach)"
|
odet = f"Imbalance {imb:+.2f} (zu schwach)"
|
||||||
@@ -3090,6 +3117,17 @@ class TradingEngine:
|
|||||||
self._align_ts = now
|
self._align_ts = now
|
||||||
return getattr(self, "_align_cache", None)
|
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:
|
def _block_mix_cached(self) -> dict | None:
|
||||||
"""WELCHE Gates blocken heute, und wie oft? (2026-08-06)
|
"""WELCHE Gates blocken heute, und wie oft? (2026-08-06)
|
||||||
|
|
||||||
@@ -3726,6 +3764,7 @@ class TradingEngine:
|
|||||||
(self.news.sentiment or {}).get("score")),
|
(self.news.sentiment or {}).get("score")),
|
||||||
"alignment": self._alignment_cached(),
|
"alignment": self._alignment_cached(),
|
||||||
"block_mix": self._block_mix_cached(),
|
"block_mix": self._block_mix_cached(),
|
||||||
|
"hl_ctx": getattr(self, "_hl_ctx", None),
|
||||||
"rec_track": self._rec_track_cached(),
|
"rec_track": self._rec_track_cached(),
|
||||||
# Kennzahlen der MANUELLEN Trades für die gleichnamige Karte
|
# Kennzahlen der MANUELLEN Trades für die gleichnamige Karte
|
||||||
# (2026-08-04). Rein deskriptiv; ~120 s gecacht, damit der heiße
|
# (2026-08-04). Rein deskriptiv; ~120 s gecacht, damit der heiße
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ log = get_logger("hlwalls")
|
|||||||
|
|
||||||
_TIMEOUT_S = 2.0 # der MT5-Loop darf nicht am HTTP hängen
|
_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)
|
_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
|
_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
|
_STALE_GRACE_S = 120.0 # nach einem Fehlschlag den letzten guten Stand so lange
|
||||||
# weiterreichen (Blink-Fix — s. Kommentar in `walls()`)
|
# weiterreichen (Blink-Fix — s. Kommentar in `walls()`)
|
||||||
@@ -47,6 +53,58 @@ class HLWalls:
|
|||||||
self._cache: dict | None = None
|
self._cache: dict | None = None
|
||||||
self._cache_ts = 0.0
|
self._cache_ts = 0.0
|
||||||
self._fail_logged = False
|
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:
|
def walls(self) -> dict | None:
|
||||||
"""{'bid','bid_sz','ask','ask_sz','basis','imb5'} auf MT5-Preisniveau —
|
"""{'bid','bid_sz','ask','ask_sz','basis','imb5'} auf MT5-Preisniveau —
|
||||||
|
|||||||
+23
@@ -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) ───────────
|
// ── Warum WARTEN? Verteilung der blockierenden Gates (heute) ───────────
|
||||||
const blkEl = $("vd-blocks");
|
const blkEl = $("vd-blocks");
|
||||||
if (blkEl) {
|
if (blkEl) {
|
||||||
|
|||||||
+7
-2
@@ -6,7 +6,7 @@
|
|||||||
<meta name="theme-color" content="#0d1117">
|
<meta name="theme-color" content="#0d1117">
|
||||||
<title>Oil · MT5</title>
|
<title>Oil · MT5</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
<link rel="stylesheet" href="style.css?v=144">
|
<link rel="stylesheet" href="style.css?v=145">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Modul-Menü (ganz oben) -->
|
<!-- Modul-Menü (ganz oben) -->
|
||||||
@@ -141,6 +141,11 @@
|
|||||||
<div class="pos-stophint hidden" id="pos-stophint"></div>
|
<div class="pos-stophint hidden" id="pos-stophint"></div>
|
||||||
<div class="news-conflict hidden" id="news-conflict"></div>
|
<div class="news-conflict hidden" id="news-conflict"></div>
|
||||||
<div class="news-conflict hidden" id="cal-note"></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.
|
<!-- Auto-Flip-Close: schließt eine Position, wenn die Empfehlung dreht.
|
||||||
⚠ GEMESSEN in BEIDEN Halbjahren negativ (−92/−160 R,
|
⚠ GEMESSEN in BEIDEN Halbjahren negativ (−92/−160 R,
|
||||||
backtest_flipclose2.py), läuft auf ausdrücklichen User-Wunsch. Hatte
|
backtest_flipclose2.py), läuft auf ausdrücklichen User-Wunsch. Hatte
|
||||||
@@ -340,6 +345,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="toast" class="toast hidden"></div>
|
<div id="toast" class="toast hidden"></div>
|
||||||
|
|
||||||
<script src="app.js?v=144"></script>
|
<script src="app.js?v=145"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -557,3 +557,8 @@ main{padding-bottom:74px} /* Platz für die fixe Leiste */
|
|||||||
zurückgenommen, statt zwei scheinbar gleichrangige Felder zu zeigen. */
|
zurückgenommen, statt zwei scheinbar gleichrangige Felder zu zeigen. */
|
||||||
.mg-field.muted { opacity: .45; }
|
.mg-field.muted { opacity: .45; }
|
||||||
.mg-field.muted input { border-style: dashed; }
|
.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}
|
||||||
|
|||||||
Reference in New Issue
Block a user