diff --git a/core/engine.py b/core/engine.py index f282b78..9561f38 100644 --- a/core/engine.py +++ b/core/engine.py @@ -3744,8 +3744,13 @@ class TradingEngine: "elliott": elliott, "tu": tu, "agent": agent, - "verdict": self._verdict(market, wave_signal, wave_snap, - tu, agent, elliott, _pat_snap), + # ⚠ `verdict` ist am 2026-08-08 aus dem Snapshot GEFLOGEN (die + # Gesamtempfehlung wurde entfernt). `_verdict()` selbst LEBT WEITER — + # es speist 1×/min die Telemetrie `verdict_votes` (User-Entscheidung: + # weiter sammeln) und den optionalen MQL5-Konsens-Pfeil. Es hier im + # 1-s-Pfad zu rechnen waere Arbeit fuer eine Anzeige, die es nicht + # mehr gibt — genau der Fehler, der beim Konsens-Pfeil schon einmal + # dokumentiert wurde. "daily_levels": self.daily.snapshot(), "gaps": self.gaps.snapshot(), "structure": self.structure.snapshot(), @@ -3767,7 +3772,10 @@ class TradingEngine: "news_sentiment": (lambda sc: round(float(sc), 2) if sc is not None else None)( (self.news.sentiment or {}).get("score")), "alignment": self._alignment_cached(), - "block_mix": self._block_mix_cached(), + # `block_mix` entfallen (2026-08-08): die Zeile `#vd-blocks` gehoerte + # zur Gesamtempfehlung. `_block_mix_cached()` bleibt als Methode + # stehen — die Abfrage ist fuer eine kuenftige Anzeige nuetzlich und + # kostet ungenutzt nichts (sie laeuft nur beim Aufruf). "hl_ctx": getattr(self, "_hl_ctx", None), "rec_track": self._rec_track_cached(), # Kennzahlen der MANUELLEN Trades für die gleichnamige Karte diff --git a/docs/gesamtempfehlung.md b/docs/gesamtempfehlung.md deleted file mode 100644 index 5d13c8e..0000000 --- a/docs/gesamtempfehlung.md +++ /dev/null @@ -1,68 +0,0 @@ -# Gesamtempfehlung (Verdict-Panel) - -Grafischer Empfehlungsbereich ganz oben im Mobile-Dashboard (`web/`), der die -Module zu **einer** Aussage zusammenfasst. - -## Wer berechnet was - -- **Backend (`core/engine.py` → `_verdict`)** baut die Aggregation und legt sie - als `verdict` in den Snapshot (`/api/snapshot`, `/ws`). Eine Quelle der - Wahrheit — das Frontend rendert nur. -- **Frontend (`web/app.js` → `renderVerdict`)** zeichnet Ring, Bias-Balken und - Modul-Chips. Markup in `web/index.html` (`#card-verdict`), Stil in - `web/style.css` (`.vd-*`). - -## Logik - -**Headline = die validierte Welle** (`wave_signal`) — das einzige Modul mit per -Backtest belegtem Edge. Sie bestimmt LONG/SHORT/WARTEN und die Order-Freigabe. -Die übrigen Module bilden nur einen **gewichteten Konsens** (Anzeige, kein -Eingriff in die Order-Logik). - -Votes je Modul: `+1` LONG · `−1` SHORT · `0` neutral. Gewichte: - -| Modul | Gewicht | Quelle | -|-------|---------|--------| -| Welle | **3,0** | `wave_signal.signal` (validierter Edge) | -| M30 | 1,5 | `wave.htf_trend` (EMA12/50 der M30 — exakt das Signal, das die Welle nutzt) | -| H1 | 1,5 | `wave.h1_trend` (EMA12/50 der H1) | -| KI-Copilot | 1,0 *(nur mit Bias)* | `agent.advisory.bias` — ohne advisory/Bias **Gewicht 0** | -| Elliott/FVG | 1,0 *(nur mit Ziel)* | Richtung zum `elliott.target` — ohne Ziel **Gewicht 0** | -| Squeeze | 2,0 *(nur `active`)* | `wave.squeeze` — armed/keine Kompression **Gewicht 0** | - -(TradersUnion wurde 2026-07-06 aus dem Konsens entfernt — nur noch Anzeige.) - -``` -bias = Σ(gewicht · vote) / Σ(gewicht) → −1 … +1 -``` - -⚠ **Stimmberechtigt sind nur Module mit Aussage** (Fix 2026-07-15): Module ohne -anwendbares Signal (Squeeze ohne Ausbruch, Elliott ohne Ziel, KI aus) bekommen -Gewicht 0 und stehen NICHT im Nenner — vorher dämpfte z. B. das fast immer -neutrale Squeeze-Gewicht (2,0) die Nadel dauerhaft um ~×0,8 Richtung Mitte. -„Flach" bei Welle/M30/H1 bleibt dagegen eine ECHTE Neutral-Stimme (mit Gewicht). - -`bias` steuert die **Nadel** im Balken (−1 = ganz SHORT/links, +1 = ganz -LONG/rechts: `left% = (bias+1)/2·100`). `agree/total` = wie viele der **anderen** -stimmberechtigten Module (ohne die Welle selbst — die zählte sich bis 2026-07-15 -mit) die Headline-Richtung teilen. Der **Konfidenz-Ring** zeigt `wave.conf_pct` -als conic-gradient in Richtungsfarbe. - -> ⚠ Wichtig: Für M30/H1 werden die **EMA12/50-Signale der Welle** genutzt -> (`htf_trend`/`h1_trend`), NICHT das Regressions-Winkelmaß `market.angles` — -> die beiden können sich widersprechen, das Panel muss zur Empfehlung passen. - -## Snapshot-Feld `verdict` - -```json -{ - "headline": "SHORT", "conf": 90, "bias": -1.0, "agree": 3, "total": 3, - "votes": [{"name": "Welle", "vote": -1, "weight": 3.0, "detail": "SHORT · 90%"}, …] -} -``` - -## Pflege - -Neues Modul ins Panel → Vote/Gewicht in `_verdict` ergänzen; das Frontend rendert -`votes` generisch. Bei JS/CSS-Änderung Asset-Version `v=N` in `index.html` -hochzählen. Siehe `CLAUDE.md`. diff --git a/web/app.js b/web/app.js index 52bd8a9..e33a6ff 100644 --- a/web/app.js +++ b/web/app.js @@ -130,199 +130,62 @@ function beepRecommendation(sig, isNew) { } // ── Gesamtempfehlung: Konfidenz-Ring + Bias-Balken + Modul-Chips ─────────── -function renderVerdict(v, snap) { - const sig = v.headline || "—"; - const cls = sig === "LONG" ? "long" : sig === "SHORT" ? "short" : ""; - const arr = sig === "LONG" ? "▲" : sig === "SHORT" ? "▼" : "◌"; - $("vd-signal").className = "vd-signal " + cls; - // Zeitebene, für die die Empfehlung gilt (M1/M5/M15/M30/H1) - let head = `${arr} ${sig}` + (v.tf ? ` · ${v.tf}` : ""); - // ⚠ WARUM WARTEN? (2026-07-31, User-Fund „WARTEN, aber Konsens stark LONG"). - // Die Welle HAT meist eine Richtung — sie hängt an einem Gate. Gemessen mit der - // neuen `block_reason`-Telemetrie (3 h): breakout_pending 63 % · entry_room 20 % · - // min_conf 18 %, KEIN einziges Mal Totband oder HTF-Gegen-Trend. Der Grund wurde - // bisher NUR als Textzeile in der Meldungen-Karte gezeigt — also weit weg von der - // Stelle, an der der scheinbare Widerspruch entsteht. Jetzt steht er direkt an der - // Headline: „◌ WARTEN · M15 · LONG, noch 0.11 bis zur Bestätigung". - const bo = (snap && snap.wave && snap.wave.breakout) || null; - const wsig = (snap && snap.wave_signal) || {}; - if (sig === "WARTEN" && bo && bo.pending && bo.dir) { - head += ` · ${bo.dir}, noch ${fmt(bo.need, 2)} bis zur Bestätigung`; - } else if (sig === "WARTEN" && wsig.block) { - // ⚠ ERGÄNZUNG 2026-08-07: bisher stand der Grund NUR bei - // `breakout_pending` an der Headline — bei jedem anderen Gate blieb dort - // ein nacktes „WARTEN", während die Konsens-Zeile darunter „stark LONG" - // meldete. Genau dieser Widerspruch war der Anlass. Der Grund liegt im - // Snapshot (`wave_signal.block`), er wurde nur nie gezeigt. - const G = { - min_conf: `Konfidenz ${wsig.conf_pct || 0} % < 55 % — Setup zu schwach`, - entry_room: "kein Raum bis zum Gegenlevel", - htf_counter: "höhere Zeitebene steht dagegen", - stretch: "Kurs zu weit von der EMA entfernt", - deadband: "Totband — kein klarer Trend", - dead_hour: "gesperrte Handelsstunde", - eia: "EIA-Blackout", - stale: "Kursdaten veraltet", - no_data: "keine Daten", - }; - const g = G[wsig.block] || wsig.block; - if (g) head += ` · ${g}`; - } - $("vd-signal").textContent = head; - - // Konfidenz-Ring (conic-gradient bis conf%, Farbe nach Richtung) - const conf = v.conf || 0; - const col = sig === "LONG" ? "var(--up)" : sig === "SHORT" ? "var(--down)" : "var(--dim)"; - const deg = Math.max(0, Math.min(100, conf)) * 3.6; - $("vd-ring").style.background = - `conic-gradient(${col} ${deg}deg, #21262d ${deg}deg)`; - $("vd-conf").textContent = conf ? conf + "%" : "—"; - - // Konsens-Text + Bias-Nadel (-1..+1 → 0..100 %) - const total = v.total || 0, agree = v.agree || 0; - const bias = typeof v.bias === "number" ? v.bias : 0; - const strength = Math.abs(bias) >= 0.5 ? "stark" : Math.abs(bias) >= 0.2 ? "leicht" : "gemischt"; - const dir = bias > 0.05 ? "LONG" : bias < -0.05 ? "SHORT" : "neutral"; - // Live-Kosten-Chip (Spread/ATR — gemessen Ø 0,265; Nacht 0,32–0,50 = Falle): - // reine Info, die die abgeschaltete Dead-Hours-Sperre ehrlich ersetzt. - const cr = snap && snap.cost_ratio; - let costTxt = ""; - if (cr != null) { - const tag = cr < 0.20 ? "✅ günstig" : cr <= 0.32 ? "· normal" : "⚠ teuer"; - costTxt = ` · Kosten ${fmt(cr, 2)}×ATR ${tag}`; - } - // ⚠ Konsens-Zeile korrigiert (2026-07-31). Zwei Fehler waren drin: - // (1) „… Module für ${sig}" nahm die HEADLINE als Bezug. Seit dem Fix vom 30.07. - // zählt `agree` bei WARTEN aber die Übereinstimmung mit der BIAS-Richtung → - // es stand „stark LONG · 4/4 Module für WARTEN". Die Richtung kommt jetzt als - // `ref_dir` vom Backend, statt hier aus `bias` nachgebaut zu werden. - // (2) `total` zählt nur Module MIT Aussage (Gewicht>0, ohne die Welle) — nach den - // Gewichts-Fixes schweigen mehr Module, während 9 Chips sichtbar bleiben. - // „4/4" las sich dadurch widersprüchlich. Jetzt steht dabei, wie viele - // Module gerade nichts sagen. - const refDir = v.ref_dir || null; - const silent = typeof v.silent === "number" ? v.silent : null; - // ⚠⚠ KORREKTUR 2026-08-07. „stark LONG · 2 von 2 stimmberechtigten" las sich - // wie Einstimmigkeit — dabei sprachen nur 2 von 9 Modulen, und die WELLE, die - // als einzige die Order steuert, war nicht dabei. `bias` ist arithmetisch - // richtig (das gesamte sprechende Gewicht war einig), aber die BASIS war - // winzig. Seit dem Entmachten von Elliott und Orderbuch (06.08.) trat das - // häufiger auf. Jetzt führt die Zeile mit der Basis und nennt die stumme - // Welle ausdrücklich — das löst den scheinbaren Widerspruch zur Headline auf. - const welleStumm = (v.votes || []).some( - m => m.name === "Welle" && !Number(m.weight)); - const nMod = (v.votes || []).filter(m => m.used !== false).length; - let consensus; - if (sig === "—") { - consensus = "keine Daten"; - } else if (!refDir || !total) { - consensus = "Modul-Konsens: kein Modul mit klarer Aussage"; - } else { - // „stark/leicht" nur noch, wenn ueberhaupt die Haelfte der Module spricht — - // sonst beschreibt das Wort die Einigkeit von zwei Nebenstimmen. - const dueneBasis = nMod && total < nMod / 2; - consensus = `Modul-Konsens: ${agree} von ${nMod} Modulen sprechen, ` - + `${agree === total ? "alle" : `${agree} davon`} für ${refDir}` - + (dueneBasis ? "" : ` · ${strength} ${dir}`); - if (welleStumm) consensus += " · ⚠ die Welle (steuert die Order) schweigt"; - } - $("vd-consensus").textContent = consensus + costTxt; - $("vd-needle").style.left = ((bias + 1) / 2 * 100).toFixed(1) + "%"; - - // Modul-Chips - const vote = (x) => x > 0 ? ["long", "▲"] : x < 0 ? ["short", "▼"] : ["flat", "—"]; - // ⚠ NUR Module zeigen, die wirklich in die Empfehlung einfliessen - // (User-Vorgabe 2026-08-06). `used === false` = dauerhaft entmachtet, weil - // gemessen ohne Inhalt (Elliott: 1.384 Episoden flach bei 25,9 % Einfluss; - // Orderbuch: 2.688 Episoden beidhaelftig negativ). Sie bleiben im Snapshot - // und in `verdict_votes` — nur der Chip entfaellt. - // Module mit `weight === 0` bleiben SICHTBAR: die schweigen nur situativ - // (Welle bei WARTEN, Squeeze ohne Ausbruch) und sprechen wieder. - $("vd-modules").innerHTML = (v.votes || []).filter(m => m.used !== false).map(mod => { - const [c, a] = vote(mod.vote); - // Gewicht sichtbar machen: Module OHNE Aussage (w=0) grau, sonst das Gewicht - // anzeigen — so ist erkennbar, dass z. B. Orderbuch/Liq-Trend (0,5, ungemessen) - // schwächer zählen als die Welle (3,0) oder der Squeeze (2,0). - const w = Number(mod.weight || 0); - const cls = w > 0 ? c : "flat mute"; - const wtag = w > 0 ? `${w.toFixed(1).replace(".0", "")}` : ""; - return `
` + - `${mod.name}${wtag}` + - `${a}
` + - `
${mod.detail || ""}
`; - }).join(""); - - // ── Selbst-Kalibrierung: die Karte zeigt ihre eigene Trefferquote ───── +// ══════════════════════════════════════════════════════════════════════════ +// `renderVerdict` ENTFERNT (2026-08-08). Die Gesamtempfehlung aggregierte die +// Module zu Headline, Konfidenz-Ring, Bias-Nadel und Konsens-Zeile — gemessen +// ohne Prognosewert (48–51 % Trefferquote über 1.071 Live-Episoden), und der +// Konfidenz-Ring war nicht kalibriert (in der zweiten Stichprobe invertiert). +// ⚠ Die Order-Logik hing NIE daran: Blinken, Order-Dialog und Entry-Checkliste +// lesen `wave_signal` bzw. `checklist` — das ist unberührt. +// Was in der alten Funktion nur mitlief und hier weiterlebt: +// · Selbst-Kalibrierung (`#kx-selfcal`) — misst das WELLEN-Signal, das bleibt +// · HL-Kontext (`#hl-note`) — schreibt in die Meldungen-Karte, nicht hierher +// Entfallen ist die Block-Grund-Zeile (`#vd-blocks`). +// ══════════════════════════════════════════════════════════════════════════ +function renderKontext(snap) { + // ── Selbst-Kalibrierung: die Empfehlung zeigt ihre eigene Trefferquote ── // ⚠ Gegen 50 % zu lesen, nicht gegen 0 — es ist eine Richtungsaussage. // Ausgangsstand (analyze_signal_live.py, 1.071 Episoden): 48–51 %. - // Bis genug Episoden ausgewertet sind, steht hier ehrlich „sammelt noch". - // Null-sicher (s. Cache-Regel): neue IDs treffen evtl. auf alte, gecachte HTML. - const trkEl = $("vd-selfcal"); - if (trkEl) { - const tr = snap && snap.rec_track; - if (tr && tr.n >= 20 && tr.wr30 != null) { - const d = (x) => (x == null ? "—" : (x >= 0 ? "+" : "") + fmt(x, 3)); - const cls = tr.wr30 >= 55 ? "up" : tr.wr30 <= 45 ? "down" : ""; - trkEl.className = "vd-selfcal " + cls; - trkEl.textContent = - `🎯 eigene Trefferquote (letzte ${tr.n} Episoden): ${tr.wr30} % auf 30′` - + (tr.wr60 != null ? ` · ${tr.wr60} % auf 60′` : "") - + ` · Ø ${d(tr.avg30)}×ATR`; - trkEl.title = "Selbst-Kalibrierung: jede gerichtete Empfehlung wird nach " - + "30 und 60 Minuten gegen den echten Kurs ausgewertet. Gegen 50 % lesen, " - + "nicht gegen 0. Gemessener Ausgangsstand über 1.071 Episoden: 48–51 %."; - } else { - trkEl.className = "vd-selfcal dim"; - trkEl.textContent = `🎯 eigene Trefferquote: sammelt noch` - + (tr && tr.n ? ` (${tr.n} von 20 Episoden ausgewertet)` : ""); - trkEl.title = "Jede gerichtete Empfehlung wird nach 30/60 Minuten gegen " - + "den echten Kurs ausgewertet. Ab 20 ausgewerteten Episoden erscheint " - + "die Quote hier."; - } + const trkEl = $("kx-selfcal"); + const tr = snap && snap.rec_track; + if (tr && tr.n >= 20 && tr.wr30 != null) { + const d = (x) => (x == null ? "—" : (x >= 0 ? "+" : "") + fmt(x, 3)); + const cls = tr.wr30 >= 55 ? "up" : tr.wr30 <= 45 ? "down" : ""; + trkEl.className = "kx-selfcal " + cls; + trkEl.textContent = + `🎯 Trefferquote der Empfehlung (letzte ${tr.n} Episoden): ${tr.wr30} % auf 30′` + + (tr.wr60 != null ? ` · ${tr.wr60} % auf 60′` : "") + + ` · Ø ${d(tr.avg30)}×ATR`; + trkEl.title = "Selbst-Kalibrierung: jede gerichtete Empfehlung wird nach " + + "30 und 60 Minuten gegen den echten Kurs ausgewertet. Gegen 50 % lesen, " + + "nicht gegen 0. Gemessener Ausgangsstand über 1.071 Episoden: 48–51 %."; + } else { + trkEl.className = "kx-selfcal dim"; + trkEl.textContent = `🎯 Trefferquote der Empfehlung: sammelt noch` + + (tr && tr.n ? ` (${tr.n} von 20 Episoden ausgewertet)` : ""); + trkEl.title = "Jede gerichtete Empfehlung wird nach 30/60 Minuten gegen " + + "den echten Kurs ausgewertet. Ab 20 ausgewerteten Episoden erscheint " + + "die Quote hier."; } // ── 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). + // kein Bucket die 2-Stichproben-Regel. Schreibt in die MELDUNGEN-Karte. 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) { - const bm = snap && snap.block_mix; - if (bm && bm.total) { - const pc = (n) => Math.round(100 * n / bm.total); - const top = (bm.top || []).map(x => `${x.grund} ${pc(x.n)} %`).join(" · "); - blkEl.textContent = `⛔ heute ${pc(bm.frei)} % ohne Block` - + (top ? ` · ${top}` : ""); - // ⚠ Schliessendes Anführungszeichen als „ “ (U+201C), NICHT über eine - // Konkatenation mit '"' — die war valide, aber schwer lesbar und lässt - // jeden Quote-Zähler auflaufen (der \n-Scan hat sie als offenes Literal - // gemeldet). - blkEl.title = "Welches Gate hält die Empfehlung gerade zurück — über den " - + "heutigen Tag gezählt. Ohne diese Zeile war „warum gab es so wenige " - + "Empfehlungen?“ nur per Datenbank-Abfrage zu beantworten."; - } else { - blkEl.textContent = ""; - } + 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."; + } else { + hlEl.classList.add("hidden"); } } @@ -535,21 +398,21 @@ function renderCandles(ca) { // mit der REAL gemessenen Abdeckung (~76 %), nicht mit dem Nennwert 80 %. Der Kegel // ist out-of-sample geprüft (analyze_cone.py, Fit H1 → Abdeckung H2) und damit nach // dem P(break)-Modell die zweite kalibrierte Komponente im Projekt. -// ⚠ Seit 2026-08-05 KOMPRIMIERT in der Gesamtempfehlung (`#vd-cone`) statt in einer +// ⚠ Seit 2026-08-08 in der Karte „Marktkontext" (`#kx-cone`) — die frühere // eigenen Karte (User-Vorgabe). Gezeigt wird nur noch das 80 %-Band je Horizont — // das enge 50 %-Band und der Fließtext sind entfallen und stecken im `title`. function renderCone(cn) { - const el = $("vd-cone"); + const el = $("kx-cone"); if (!el) return; // null-sicher (Cache-Regel) const lv = (cn && cn.levels) || []; const b80 = lv.filter(x => x.band === 80) .sort((a, b) => a.minutes - b.minutes); if (!b80.length) { el.innerHTML = ""; return; } const cov = b80[0].coverage != null ? `${fmt(b80[0].coverage, 0)} %` : "~"; - el.innerHTML = `📐 erwartete Spanne` - + b80.map(x => `${x.minutes}′` + el.innerHTML = `📐 erwartete Spanne` + + b80.map(x => `${x.minutes}′` + `${fmt(x.lo, 2)}–${fmt(x.hi, 2)}`).join("") - + `trifft ${cov}`; + + `trifft ${cov}`; // Die Einordnung gehört an die Zahl, nicht in einen Absatz darunter — sonst // liest jemand die Spanne als Richtungsprognose. el.title = "STREUUNG, nicht Richtung: wie WEIT der Kurs plausibel läuft, nicht " @@ -746,7 +609,7 @@ function render(d) { } // ── Gesamtempfehlung (aggregiert) ─────── - renderVerdict(d.verdict || {}, d); + renderKontext(d); renderCircuitBreaker(d.circuit_breaker); renderPatterns(d.patterns); renderCandles(d.candle_anat); diff --git a/web/index.html b/web/index.html index 7cb3379..d3f5d63 100644 --- a/web/index.html +++ b/web/index.html @@ -6,7 +6,7 @@ Oil · MT5 - + @@ -78,44 +78,28 @@ -
-

Gesamtempfehlung

-
- -
- Score -
-
-
◌ —
-
-
-
- -
- -
-
- SHORT -
- LONG -
-
- -
- -
+ +
+

Marktkontext

+ +
+ +
+ +
@@ -143,7 +127,7 @@