Charts-Tab komplett entfernt (User-Vorgabe)
Entfernt: Tab-Button, #view-charts, der gesamte app.js-Chart-Block (Kartenaufbau, renderChart, loadCharts, 20-s-Refresh, Resize-Handler), die Chart-CSS-Regeln, die vendorte Bibliothek web/lightweight-charts.standalone.production.js (164 KB) samt script-Tag - und die Backend-Kette dahinter: /api/bars und engine.get_bars (60 Zeilen). Beide existierten ausschliesslich fuer dieses Tab; geprueft, dass es keinen anderen Aufrufer gibt. Nicht betroffen (sahen nur aehnlich aus): die Chartmuster-Karte (Verdict-Gewicht 0,25, im Tab "SIG Live"), der MQL5-Indikator samt sr_levels.csv-Export (eigener Pfad ueber _write_levels_file) und die Analyse-Module structure/patterns/cone - die speisen den Snapshot, nicht das Chart. Der MT5-Chart bleibt voll bedient. Ein veralteter Kommentar in trader.py, der auf engine.get_bars verwies, wurde auf core/gaps.py umgehaengt. Verifiziert am laufenden Server: /api/bars -> 404, Bibliothek -> 404, data-view="charts" und id="view-charts" nicht mehr im ausgelieferten HTML, 6 Tabs zu 6 Views paarig, keine verwaisten JS-Referenzen, Klammern-Balance ok, keine Fehler im Log. v=142. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6ff3c15b1d
commit
a1a5d560b9
@@ -2213,7 +2213,7 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
`pnl>0`-Gate (`history`) noch vom 5-Min-Cooldown betroffen.
|
`pnl>0`-Gate (`history`) noch vom 5-Min-Cooldown betroffen.
|
||||||
|
|
||||||
## Mobile-UI (web/) & Alarme
|
## Mobile-UI (web/) & Alarme
|
||||||
- Aufbau: **Tab-Navigation ganz oben** (sticky: Dashboard/**SIG Live**/**SIG Anzeige**/Logs/Statistik/**Charts**/News),
|
- Aufbau: **Tab-Navigation ganz oben** (sticky: Dashboard/**SIG Live**/**SIG Anzeige**/Logs/Statistik/News),
|
||||||
darunter Header.
|
darunter Header.
|
||||||
- **Design-System (`style.css`, Pass 2026-07-15, KEIN Framework — Tailwind bewusst
|
- **Design-System (`style.css`, Pass 2026-07-15, KEIN Framework — Tailwind bewusst
|
||||||
verworfen wegen WireGuard/Offline + kein Node):** Tokens in `:root` — Flächen-Leiter
|
verworfen wegen WireGuard/Offline + kein Node):** Tokens in `:root` — Flächen-Leiter
|
||||||
@@ -2246,164 +2246,24 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
der Zeile. Titel „aktueller Trade läuft"; Richtung/Lots/Einsatz = Anzeige-Boxen
|
der Zeile. Titel „aktueller Trade läuft"; Richtung/Lots/Einsatz = Anzeige-Boxen
|
||||||
(`.tb-val`), Rest editierbar — alle im selben `.tb-field`-Look. Position-Kachel hält
|
(`.tb-val`), Rest editierbar — alle im selben `.tb-field`-Look. Position-Kachel hält
|
||||||
nur noch `cur-near`-Warnung + `pos-srhint`. (`.emg*`/`.sr-toggle`-CSS entfernt.)
|
nur noch `cur-near`-Warnung + `pos-srhint`. (`.emg*`/`.sr-toggle`-CSS entfernt.)
|
||||||
- **Charts-Tab** (`#view-charts`): **M1/M5/M15/M30/H1 untereinander**, je ein
|
- ⚠⚠ **CHARTS-TAB KOMPLETT ENTFERNT (User-Vorgabe 2026-08-05, v=142).** Weg sind:
|
||||||
Candlestick-Chart mit **EMA12 (blau) + EMA50 (amber)**-Overlay und Trend-Header
|
Tab-Button, `#view-charts`, der gesamte `app.js`-Chart-Block (Kartenaufbau,
|
||||||
(▲/▼/→ nach EMA12-vs-EMA50 mit Totband). Framework **TradingView Lightweight
|
`renderChart`, `loadCharts`, 20-s-Refresh, Resize-Handler), die Chart-CSS-Regeln,
|
||||||
Charts v4.2.3 — lokal vendored** (`web/lightweight-charts.standalone.production.js`,
|
die **vendorte Bibliothek** `web/lightweight-charts.standalone.production.js`
|
||||||
KEIN CDN wegen WireGuard/Offline). Daten via `GET /api/bars?tf=&n=` →
|
(164 KB) samt `<script>`-Tag — und die Backend-Kette dahinter: **`/api/bars`**
|
||||||
`engine.get_bars` (OHLC+EMA+Trend unter `mt5_lock`). `app.js`: `loadCharts`/
|
und **`engine.get_bars`** (60 Zeilen). Beide existierten ausschliesslich für
|
||||||
`renderChart`, Charts nur bei sichtbarem Tab geladen + Auto-Refresh 20 s
|
dieses Tab (geprüft: kein anderer Aufrufer).
|
||||||
(schont den Lock). Broker-Zeit (UTC+3) → UTC via `broker_utc_offset`. **Gitternetz
|
⚠ **Nicht betroffen** — sie sahen nur ähnlich aus: die **Chartmuster**-Karte
|
||||||
dezent** (2026-07-27, User „dunkler/unauffälliger": `grid`-Farbe `#161b22`→`#10151c`,
|
(`#card-patterns`, Verdict-Gewicht 0,25, jetzt im Tab „SIG Live"), der
|
||||||
näher am Hintergrund `#0d1117`). **Chartmuster-Overlay (nur M30)** — s. Chartmuster-
|
**MQL5-Indikator** samt `sr_levels.csv`-Export (eigener Pfad über
|
||||||
Kachel: die 2 stärksten M30-Muster als Trigger-/Ziel-Preislinien.
|
`_write_levels_file`, unabhängig von `get_bars`) und alle Analyse-Module
|
||||||
**Regressionskanal-Overlay (nur M30, 2026-07-20):** `get_bars` liefert bei M30
|
(`structure.py`, `patterns.py`, `cone.py`) — die speisen den Snapshot, nicht das
|
||||||
`channel {dir, mid[], upper[], lower[]}` (Arrays deckungsgleich mit den Bars,
|
Chart. Der MT5-Chart bleibt also vollständig bedient.
|
||||||
`structure.channel_series` — Regression über 60 abgeschl. Bars, linear über die
|
Verifiziert am laufenden Server: `/api/bars` → **404**, Bibliothek → **404**,
|
||||||
volle Breite extrapoliert). Frontend zeichnet 3 LineSeries (oben/unten gestrichelt,
|
`data-view="charts"` und `id="view-charts"` nicht mehr im ausgelieferten HTML,
|
||||||
Mitte gepunktet, grau). Dieselbe Kanal-Definition wie die Marktstruktur-Kachel —
|
6 Tabs zu 6 Views paarig, keine verwaisten JS-Referenzen, Klammern-Balance ok.
|
||||||
REINE Anzeige (Signalvariante gemessen verworfen, s. `backtest_structure.py`).
|
Zurückholen: alles liegt in der Git-Historie (Commit davor).
|
||||||
**S/R-Overlay & Dashboard-Kachel = EINE Quelle** (`_draw_levels`; die Position-Kachel
|
|
||||||
`sr-res`/`sr-sup` speist jetzt via `_dash_sr` daraus statt aus dem Misch-Set
|
|
||||||
`_sr_levels` — vorher wichen Chart und Kachel ab, User-Feedback 2026-07-15). `_sr_levels`
|
|
||||||
bleibt intern für Strategie/Konfidenz. **„Klebrige" Hysterese** in `_draw_levels`
|
|
||||||
(`_draw_last`, verschärft 2026-07-21): die gezeichnete Linie **bleibt stehen, bis der
|
|
||||||
Kurs sie WIRKLICH durchbricht** (bid > R+0,1×ATR bzw. bid < S−0,1×ATR) — ein neuer,
|
|
||||||
näherer M5-Pivot löst KEINEN Wechsel mehr aus (das war die Zitter-Quelle: auf M5
|
|
||||||
bilden sich laufend neue Pivots, die alte 0,25×ATR-Regel sprang darauf an). Ausnahme:
|
|
||||||
ist die alte Linie >1,5×ATR weit weg UND ein deutlich näheres Level existiert, wird
|
|
||||||
refresht (sonst bliebe sie irrelevant hängen). Gilt für PWA-Chart UND MQL5-CSV (eine
|
|
||||||
Quelle).
|
|
||||||
**Level-Auswahl nach Kursposition statt Entstehungstyp (Fix 2026-07-23, User-Frage
|
|
||||||
„Widerstand/Support-Retest von der falschen Seite"):** vorher kam Widerstand NUR aus
|
|
||||||
`ph` (Swing-Hochs) und Support NUR aus `pl` (Swing-Tiefs) — ein gebrochenes Level blieb
|
|
||||||
für IMMER im falschen Topf hängen. 2 von 4 Retest-Varianten hatten dadurch NIE eine
|
|
||||||
Durchbruchwahrscheinlichkeit: (1) Widerstand von unten ✓ funktionierte, (2) **Support-
|
|
||||||
Retest von unten** (Kurs unter einem gebrochenen Support, nähert sich von unten wieder)
|
|
||||||
✗ kein Hinweis, (3) Support von oben ✓ funktionierte, (4) **Widerstand-Retest von oben**
|
|
||||||
(Kurs über einem gebrochenen Widerstand, nähert sich von oben wieder) ✗ kein Hinweis.
|
|
||||||
Fix: `ph`/`pl` bleiben GETRENNT geclustert (unverändert granular — ein erster Versuch,
|
|
||||||
beide Rohpools VOR dem Clustern zusammenzulegen, erzeugte in dichten Zonen Ketten-Mega-
|
|
||||||
Cluster durch die verdoppelte Punktdichte, >1×ATR breit, verworfen), aber NACH dem
|
|
||||||
Clustern werden beide fertigen Linien-Listen zusammengeführt und die Wahl erfolgt rein
|
|
||||||
per `min/max` relativ zu `bid` — nicht mehr nach Topf-Zugehörigkeit. Verifiziert: Fall 1
|
|
||||||
bei Live-Daten (bid 90,951) und ein dichter Kontrollfall liefern exakt dieselben Level
|
|
||||||
wie vorher (keine Regression); Fälle 2+4 (synthetische Retest-Szenarien) finden jetzt
|
|
||||||
das nahe, vorher übersehene Level statt eines weit entfernten Ersatzlevels. Betrifft
|
|
||||||
`_draw_levels` direkt und damit ALLE Konsumenten (PWA-Chart, MQL5-CSV, Dashboard-
|
|
||||||
Kachel, `_sr_close_hint`/Auto-Close) — eine Quelle, ein Fix.
|
|
||||||
**⚠ LEVEL-TF M5→M30 umgestellt (2026-07-30, gemessen `backtest_level_tf.py`):**
|
|
||||||
Auslöser war die User-Beobachtung „die S/R-Linien liegen oft sehr nahe beieinander" —
|
|
||||||
quantifiziert stimmte das: **71 % der M5-Level lagen näher als 1×ATR** (Median-Abstand
|
|
||||||
nur 0,61×ATR). Gemessen über 80k M5-Bars in 2 Halbjahren (Trades bleiben M5, nur die
|
|
||||||
LEVEL-Quelle variiert; Live-Exit + Echtkosten). **M30 gewinnt in BEIDEN Hälften:**
|
|
||||||
Abstand **1,95×ATR** (nur 28 % eng) · AUC out-of-sample **0,721** (M15 0,725, M5 0,710)
|
|
||||||
· R-Ertrag der P(break)-Close-Regel **rund doppelt** (+12.424/+13.047 vs +6.698/+7.749
|
|
||||||
bei P<0,55). M15 lag dazwischen; M30 gewählt wegen des klar besten R-Ertrags und der
|
|
||||||
weitesten Level. **Das P(break)-Modell wurde dafür NACHTRAINIERT** (`_PB_MU/_SD/_W`
|
|
||||||
in `engine.py`): out-of-sample validiert (H1→H2), dann auf allen 80k Bars final
|
|
||||||
gefittet — 34.771 Touches, Basisrate 39,4 %, Kalibrierung trifft (pred/real 23/25 ·
|
|
||||||
38/36 · 58/59 · 86/87). Die **Merkmale bleiben M5** (mom6/mom3 auf M5-Bars), nur die
|
|
||||||
Level sind M30. Quelle live: `wave.pb_levels30` (M30-H/L aus dem 15-s-Turn-Fetch,
|
|
||||||
k=3, letzte 50 Bars = trainingsgleich zum 300-M5-Lookback), Fallback `pb_levels` (M5)
|
|
||||||
beim Kaltstart. ⚠ **NICHT mitverändert: das Entry-Raum-Gate** (`wave._room_gate`) nutzt
|
|
||||||
weiter die M5-`pb_levels` — `entry_room_atr=0.6` ist darauf kalibriert, eine Umstellung
|
|
||||||
dort wäre ungemessen. Alte M5-Modellwerte stehen als Kommentar über `_PB_MU` (Rückweg).
|
|
||||||
Real nach der Umstellung: R/S 84,617/83,722 = 2,9×ATR Abstand (vorher 0,28×ATR).
|
|
||||||
**S/R-Overlay:** `get_bars` liefert `levels {res, sup}` aus **`engine._draw_levels`**
|
|
||||||
= echte Kursstruktur (rohe M30-Pivots aus `wave.pb_levels30`, geclustert ~0,5×ATR,
|
|
||||||
**nur die NÄCHSTE je Seite = 2 Linien total, deckungsgleich mit Dashboard
|
|
||||||
sr-res/sr-sup** — mehr Linien tauchten beim Kurslauf laufend auf/ab, User-Feedback
|
|
||||||
2026-07-14; identisch zur Auto-Close-Logik). ⚠ Bugfix 2026-07-14: vorher
|
|
||||||
kamen die Linien aus `_sr_levels` (stale [zones]-Config + Tageslevel + Gaps) —
|
|
||||||
gezeichnet wurden Uralt-Level (81,24/82,64) statt aktueller Struktur. Farben
|
|
||||||
**blau** (User-Wunsch): Widerstand #1f6feb, Support #58a6ff. **Beschriftung**
|
|
||||||
(2026-07-14): PWA-Achsenlabel „Widerstand"/„Unterstützung" (+Nummer ab 2);
|
|
||||||
MQL5 zusätzlich sichtbares OBJ_TEXT-Label je Linie („Widerstand 78.65",
|
|
||||||
~8 Kerzen vor dem rechten Rand, in Linienfarbe).
|
|
||||||
⚠ **Kein MT5-Terminal-Zeichnen aus Python:** das `MetaTrader5`-Paket hat KEINE
|
|
||||||
`object_create`/`OBJ_HLINE`/`chart_*`-Funktionen (nur MQL5). S/R-Linien daher im
|
|
||||||
PWA-Chart. **Für das Desktop-Terminal: Datei-Bridge** — `engine._write_levels_file`
|
|
||||||
(im `_run_analysis`, ~5 s, `[trading] export_mql5_levels=true`) schreibt atomar
|
|
||||||
`<terminal>\MQL5\Files\sr_levels.csv` (`SYM;…` / `R;preis` / `S;preis` / **`CH;<U|M|L>;
|
|
||||||
t1;p1;t2;p2`** = Regressionskanal-Anker / **`LQ;<B|A>;preis;size;<U|D>;<1|0>`** = ECHTE
|
|
||||||
Liquiditäts-Wand + Pfeilrichtung + Dominanz (⚠ seit MQL5 v1.14 zeichnet der
|
|
||||||
Indikator davon NUR noch den PFEIL, rechtsbündig am aktuellen Rand — Linie und
|
|
||||||
Text-Label sind auf User-Wunsch raus, Details stehen im Tooltip) / **`LT;t1;p1;t2;p2;<U|D>`** =
|
|
||||||
Liquiditäts-Trendlinie, s. u.); Quelle **`_draw_levels`** (S/R) +
|
|
||||||
**`structure.channel_line`** (Kanal) + **`self.hl_walls`** (Liquidität),
|
|
||||||
Indikator-Farben blau DodgerBlue/DeepSkyBlue, Wände grün/orangerot.
|
|
||||||
⚠ **Chartmuster-Linien (`PT;…`) 2026-07-30 auf User-Wunsch ENTFERNT** („entferne die
|
|
||||||
chartmuster linien aus dem mt5" — Chart war zu voll); die Muster-Kachel + das
|
|
||||||
PWA-Chart-Overlay bleiben unverändert, nur der MT5-Export/Indikator-Handler ist raus.
|
|
||||||
**ECHTE Liquiditäts-Wände im MT5-Chart (User-Wunsch 2026-07-30 „zeichne mir die
|
|
||||||
liquiditätslinien in den mt5 ein"):** `core/hl_walls.py` holt vom **HL-Dashboard**
|
|
||||||
(`GET http://127.0.0.1:8001/api/walls`, `[trading] export_hl_walls=true`) das
|
|
||||||
**größte L2-Orderbuch-Level je Seite** — die einzigen Linien im Chart, die NICHT aus
|
|
||||||
Pivots geschätzt sind, sondern **tatsächlich ruhende Orders** zeigen (Pepperstone =
|
|
||||||
Market Maker, liefert kein Buch). ⚠ **Basis-Korrektur zwingend:** HL `xyz:CL` notiert
|
|
||||||
**~0,45 $ unter** dem CFD (anderer Kontrakt/Contango) — die Umrechnung passiert
|
|
||||||
serverseitig im HL-Projekt (Median über 60 Snapshots), hier kommt schon
|
|
||||||
`bid_mt5`/`ask_mt5` an; fehlt die Basis, wird NICHT gezeichnet. ⚠ **`127.0.0.1`, nicht
|
|
||||||
`localhost`** (IPv6-Auflösung → 2066 ms statt 19–46 ms, lief in den 2-s-Timeout) und
|
|
||||||
der HL-Endpoint liest **nur seine DB** (live-`fetch_l2_book` dauerte ~2 s = Timeout).
|
|
||||||
**Pfeil + Liquiditäts-Trendlinie (User-Wunsch 2026-07-30, Indikator v1.13):**
|
|
||||||
(a) Jede Wand bekommt einen **Pfeil in ihrer Wirkrichtung** (Wingdings 233/234) —
|
|
||||||
Lesart **„die Wand HÄLT"**: Nachfrage-Wand stützt von unten (▲), Angebots-Wand
|
|
||||||
deckelt (▼); die **größere** der beiden wird dicker gezeichnet + „<<" im Label
|
|
||||||
(`dominant` aus dem Endpoint). ⚠ **Die Pfeilrichtung ist INTERPRETATION, nicht
|
|
||||||
gemessen** — die Gegenthese („Liquidity Grab": der Kurs läuft ZUR Wand, um sie
|
|
||||||
abzuräumen) ist genauso verbreitet. Welche stimmt, beantwortet `analyze_bookflow.py`
|
|
||||||
(Frage 3) nach genug Daten; bis dahin ist der Pfeil eine Lese-Hilfe, kein Signal.
|
|
||||||
(b) **Pinke Liquiditäts-Trendlinie** (`OBJ_TREND`, nach rechts verlängert,
|
|
||||||
`InpShowLiqTrend`/`InpLiqTrendColor`): lineare Regression über den **volumen-
|
|
||||||
gewichteten Wand-Schwerpunkt** `(bid_px·bid_sz + ask_px·ask_sz)/(bid_sz+ask_sz)`
|
|
||||||
der letzten **60 min** (≥20 Punkte nötig). ⚠ Sie zeigt etwas ANDERES als eine
|
|
||||||
Kurs-Trendlinie: **wohin das Gewicht der RUHENDEN Orders wandert**, nicht wohin der
|
|
||||||
gehandelte Preis läuft — steigt sie, ziehen die Käufer ihre großen Gebote hoch.
|
|
||||||
Zeiten werden im Bot in **Broker-Zeit** umgerechnet (`trader._broker_offset_s()`),
|
|
||||||
weil MT5-Charts die brauchen; Preise sind bereits basis-korrigiert.
|
|
||||||
Fail-safe: HL-Server aus → keine Linien, kein Fehler (Log 1×, dann still), Cache 10 s,
|
|
||||||
Daten älter als 60 s werden verworfen. **REINE ANZEIGE** — ob HL-Buch-Signale auf den
|
|
||||||
CFD übertragbar sind, wird gerade gemessen (`analyze_bookflow.py` im HL-Projekt,
|
|
||||||
Datensammlung seit 2026-07-30, Urteil in ~2 Wochen). Der Indikator
|
|
||||||
**`mql5/SR_Levels.mq5`** (**v1.29** — `LQ`-Handler zeichnet seit v1.14 **nur noch
|
|
||||||
den PFEIL**, rechtsbündig am aktuellen Rand (in `RepositionLabels()` nachgeführt,
|
|
||||||
bleibt beim Scrollen rechts; Details im **Tooltip**) — Linie und Text-Label sind
|
|
||||||
auf User-Wunsch raus („Chart zu voll"). **v1.15 = CHART-THEME** (User „Farben im
|
|
||||||
MT5 wie im Bild"): `ApplyTheme()` setzt beim Start Hintergrund/Gitter/Kerzenfarben
|
|
||||||
auf die Dashboard-Palette — Bull **#3B82F6**, Bear **#EF4444**, BG **#0D1117**,
|
|
||||||
Gitter **#10151C** (dezent), Text #8B949E; Liquiditäts-Pfeile **Gold #F59E0B**
|
|
||||||
(= „Liquiditätszone" der Legende). ⚠ Das ändert das Chart **dauerhaft** (bleibt
|
|
||||||
auch nach Entfernen des Indikators) → `InpApplyTheme=false` schaltet es ab, alle
|
|
||||||
Farben sind einzeln als Inputs überschreibbar. Schalter: `InpShowWalls`/
|
|
||||||
`InpWallBidColor`/`InpWallAskColor`/`InpShowLiqTrend`/`InpLiqTrendColor`;
|
|
||||||
PT-Handler entfernt; in `MQL5\Indicators\`, **braucht
|
|
||||||
`OnCalculate` als No-op** sonst Compile-Error, F7-kompilieren, auf den Chart ziehen)
|
|
||||||
liest die S/R-Linien per Timer (OBJ_HLINE) UND den **M30-Regressionskanal als 3
|
|
||||||
diagonale Trendlinien** (OBJ_TREND, nach rechts verlängert, oben/unten gestrichelt/
|
|
||||||
Mitte gepunktet grau; `InpShowChannel`/`InpChanColor`, Default an) — Anker in
|
|
||||||
Broker-Zeit (= Server-Zeit im Terminal), zeichnet **nur bei Datei-Änderung neu**
|
|
||||||
(Inhalts-Cache `g_last` gegen Flackern). Der Kanal ist dieselbe M30-Definition wie
|
|
||||||
PWA-Overlay + Marktstruktur-Kachel; ⚠ nach dem Update den Indikator **neu F7-
|
|
||||||
kompilieren** (v1.10). Die dynamische Handels-Range (`DrawRange`, Hoch/Tief
|
|
||||||
der letzten `InpRangeBars` Kerzen) ist **per Default AUS** (`InpShowRange=false`,
|
|
||||||
User-Wunsch 2026-07-14) — bei Bedarf über die Indikator-Eingaben aktivierbar. (Die
|
|
||||||
statischen `[zones]`-Config werden NICHT mehr in die CSV geschrieben — waren stale
|
|
||||||
WTI-Level, füllten den Chart.)
|
|
||||||
**Architektur bewusst: Python = Gehirn (Analyse/Strategie/PWA/News/LLM/Reports),
|
|
||||||
MQL5 = nur dünne Zeichen-Schicht.** Kein Full-Rewrite in MQL5 (PWA/Backtests/
|
|
||||||
Integrationen wären dort nicht/kaum machbar). **Sym-Zeile:** Symbol links · rechts `hdr-clock`
|
|
||||||
(**Srv = Broker-Wallclock** aus `market.server_time` via `getUTC*`, **Lok** =
|
|
||||||
Browser) + **Session** (`#session`; zeigt 21–22 Uhr lokal „🕘 PRIME-TIME" —
|
|
||||||
gemessen die stärksten Stunden — und bei Headline-Burst „📰 NEWS-STURM"/„viele
|
|
||||||
News" aus `news.storm_state()` → Snapshot `news_storm` {level: normal/elevated/
|
|
||||||
storm, fresh, base_per_h}; Headline-Rate letzte Stunde vs Basisrate, Basis-Fenster
|
|
||||||
min. 6 h verankert. Beides reine Anzeige) + Verbindungspunkt. Darunter Balance ·
|
|
||||||
**Tag P/L** · Equity. **Kein** Bid/Ask/Spread (Kurs steht in der Position-Kachel,
|
|
||||||
färbt sich nahe S/R). **Tag P/L** (`day-pl`) = realisiert heute
|
|
||||||
(`stats_overview("today")`) + offene Position; grün/rot
|
|
||||||
(`day_pl{realized,open,total}` im Snapshot).
|
|
||||||
- **Gesamtempfehlung** (`#card-verdict`, ganz oben): grafische Aggregation aller
|
- **Gesamtempfehlung** (`#card-verdict`, ganz oben): grafische Aggregation aller
|
||||||
Module — Konfidenz-Ring (conic-gradient = `conf_pct`), Bias-Balken mit Nadel
|
Module — Konfidenz-Ring (conic-gradient = `conf_pct`), Bias-Balken mit Nadel
|
||||||
(SHORT↔LONG) und Modul-Chips (Welle/M30/H1/KI/Elliott/**Squeeze**, je grün/rot/grau; **TU
|
(SHORT↔LONG) und Modul-Chips (Welle/M30/H1/KI/Elliott/**Squeeze**, je grün/rot/grau; **TU
|
||||||
@@ -3272,7 +3132,7 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
Signal → **Hinweis-Dialog „trotzdem eröffnen?"** (überschreibbar). CLOSE bei
|
Signal → **Hinweis-Dialog „trotzdem eröffnen?"** (überschreibbar). CLOSE bei
|
||||||
**negativem** P&L → Sicherheitsabfrage; im Plus/Breakeven direkt. Sonst keine
|
**negativem** P&L → Sicherheitsabfrage; im Plus/Breakeven direkt. Sonst keine
|
||||||
Token-Dialoge (`require_token=false`). Audio braucht 1× Nutzer-Tap.
|
Token-Dialoge (`require_token=false`). Audio braucht 1× Nutzer-Tap.
|
||||||
- Asset-Version aktuell **v=141** (in `web/index.html` hochzählen, siehe Workflows).
|
- Asset-Version aktuell **v=142** (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` —
|
||||||
|
|||||||
@@ -757,66 +757,6 @@ class TradingEngine:
|
|||||||
self._save_emergency_state() # Handeingabe neustart-fest (Fix 2026-07-17)
|
self._save_emergency_state() # Handeingabe neustart-fest (Fix 2026-07-17)
|
||||||
return self._takeprofit
|
return self._takeprofit
|
||||||
|
|
||||||
def get_bars(self, tf_label: str, n: int = 90) -> dict:
|
|
||||||
"""OHLC-Bars + EMA12/50 + Trend je Timeframe für den Charts-Tab. Läuft unter
|
|
||||||
`mt5_lock`. Trend = EMA12 vs EMA50 mit Totband (_TREND_DEADBAND×ATR)."""
|
|
||||||
import MetaTrader5 as mt5
|
|
||||||
from core.mt5_utils import mt5_lock
|
|
||||||
from core.wave_rec import _ema_series, _atr, _EMA_FAST, _EMA_SLOW, _TREND_DEADBAND
|
|
||||||
tf_map = {"M1": mt5.TIMEFRAME_M1, "M5": mt5.TIMEFRAME_M5, "M15": mt5.TIMEFRAME_M15,
|
|
||||||
"M30": mt5.TIMEFRAME_M30, "H1": mt5.TIMEFRAME_H1}
|
|
||||||
tf = tf_map.get(tf_label); sym = self.data.symbol
|
|
||||||
if tf is None or not sym:
|
|
||||||
return {"tf": tf_label, "bars": [], "error": "kein TF/Symbol"}
|
|
||||||
n = max(30, min(int(n), 200))
|
|
||||||
try:
|
|
||||||
with mt5_lock(timeout=5) as got:
|
|
||||||
if not got:
|
|
||||||
return {"tf": tf_label, "bars": [], "error": "busy"}
|
|
||||||
rates = mt5.copy_rates_from_pos(sym, tf, 0, n + _EMA_SLOW)
|
|
||||||
except Exception as e:
|
|
||||||
return {"tf": tf_label, "bars": [], "error": str(e)}
|
|
||||||
if rates is None or len(rates) == 0:
|
|
||||||
return {"tf": tf_label, "bars": [], "error": "keine Daten"}
|
|
||||||
closes = [float(b["close"]) for b in rates]
|
|
||||||
highs = [float(b["high"]) for b in rates]
|
|
||||||
lows = [float(b["low"]) for b in rates]
|
|
||||||
e12 = _ema_series(closes, _EMA_FAST); e50 = _ema_series(closes, _EMA_SLOW)
|
|
||||||
atr = _atr(highs, lows, closes) or 0.0
|
|
||||||
d = e12[-1] - e50[-1]
|
|
||||||
dead = _TREND_DEADBAND * atr if atr else 0.0
|
|
||||||
trend = "flat" if abs(d) <= dead else ("up" if d > 0 else "down")
|
|
||||||
k = min(n, len(rates))
|
|
||||||
bars = [{"t": int(b["time"]), "o": float(b["open"]), "h": float(b["high"]),
|
|
||||||
"l": float(b["low"]), "c": float(b["close"])} for b in rates[-k:]]
|
|
||||||
# S/R-Linien fürs Chart-Overlay: echte Pivot-Struktur (`_draw_levels`,
|
|
||||||
# identisch zum Auto-Close-System) — NICHT mehr die stale [zones]-Config.
|
|
||||||
try:
|
|
||||||
dl = self._draw_levels()
|
|
||||||
levels = {"res": dl.get("res", []), "sup": dl.get("sup", []), "zones": []}
|
|
||||||
except Exception:
|
|
||||||
levels = {"res": [], "sup": [], "zones": []}
|
|
||||||
# Regressionskanal — nur M30 (dort ist die Marktstruktur berechnet), als
|
|
||||||
# Linien-Arrays deckungsgleich mit den Bars (Overlay im Charts-Tab).
|
|
||||||
channel = None
|
|
||||||
patterns = []
|
|
||||||
if tf_label == "M30":
|
|
||||||
try:
|
|
||||||
from core.structure import channel_series
|
|
||||||
channel = channel_series(closes, atr, k)
|
|
||||||
except Exception:
|
|
||||||
channel = None
|
|
||||||
# Visuelle Chartmuster (M30) fürs Overlay — Trigger-/Ziel-Preislinien.
|
|
||||||
try:
|
|
||||||
patterns = (self.patterns.snapshot() or {}).get("patterns") or []
|
|
||||||
except Exception:
|
|
||||||
patterns = []
|
|
||||||
return {"tf": tf_label, "symbol": sym, "trend": trend, "bars": bars,
|
|
||||||
"ema12": [round(x, 3) for x in e12[-k:]],
|
|
||||||
"ema50": [round(x, 3) for x in e50[-k:]],
|
|
||||||
"levels": levels, "channel": channel, "patterns": patterns,
|
|
||||||
"broker_utc_offset": 3 * 3600}
|
|
||||||
|
|
||||||
def _in_startup_grace(self) -> bool:
|
def _in_startup_grace(self) -> bool:
|
||||||
"""True in den ersten `_startup_grace_s` s nach Bot-Start — dann schließt der
|
"""True in den ersten `_startup_grace_s` s nach Bot-Start — dann schließt der
|
||||||
Bot keinen laufenden Trade selbst (Daten noch nicht stabil nach Neustart)."""
|
Bot keinen laufenden Trade selbst (Daten noch nicht stabil nach Neustart)."""
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ def _retcode_msg(res) -> str:
|
|||||||
|
|
||||||
# ── Broker-Zeitzone ───────────────────────────────────────────────────────────
|
# ── Broker-Zeitzone ───────────────────────────────────────────────────────────
|
||||||
# Pepperstone liefert Broker-Zeit UTC+3 (ganzjährig) — dieselbe Konstante nutzt
|
# Pepperstone liefert Broker-Zeit UTC+3 (ganzjährig) — dieselbe Konstante nutzt
|
||||||
# `engine.get_bars` bereits für die Chart-Umrechnung (`broker_utc_offset`).
|
# `core/gaps.py` nutzt dieselbe Konstante fuer die Datums-Zuordnung.
|
||||||
_BROKER_OFF_DEFAULT_S = 3 * 3600
|
_BROKER_OFF_DEFAULT_S = 3 * 3600
|
||||||
# Nur ein FRISCHER Tick darf den Offset (neu) bestimmen. Begründung s.
|
# Nur ein FRISCHER Tick darf den Offset (neu) bestimmen. Begründung s.
|
||||||
# `_broker_offset_s` — die Schwelle liegt unter dem halben Rundungsraster
|
# `_broker_offset_s` — die Schwelle liegt unter dem halben Rundungsraster
|
||||||
|
|||||||
@@ -214,12 +214,6 @@ def news():
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/bars")
|
|
||||||
def bars(tf: str = "M5", n: int = 90):
|
|
||||||
"""OHLC-Bars + EMA12/50 + Trend je Timeframe (Charts-Tab). Read-only, kein Token."""
|
|
||||||
return JSONResponse(content=_json_safe(app.state.engine.get_bars(tf, n)))
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/squeeze_monitor")
|
@app.get("/api/squeeze_monitor")
|
||||||
def squeeze_monitor():
|
def squeeze_monitor():
|
||||||
"""Auto-Squeeze-B4-Monitor: Live-Trades (echt) + Mechanik (Entry-Edge isoliert)
|
"""Auto-Squeeze-B4-Monitor: Live-Trades (echt) + Mechanik (Entry-Edge isoliert)
|
||||||
|
|||||||
-137
@@ -1423,7 +1423,6 @@ function showView(name) {
|
|||||||
if (name === "logs") loadLogs();
|
if (name === "logs") loadLogs();
|
||||||
if (name === "stats") loadStats();
|
if (name === "stats") loadStats();
|
||||||
if (name === "news") loadNews();
|
if (name === "news") loadNews();
|
||||||
if (name === "charts") loadCharts();
|
|
||||||
}
|
}
|
||||||
// Nur echte View-Tabs registrieren — NICHT den Mute-Button (der trägt .tab nur
|
// Nur echte View-Tabs registrieren — NICHT den Mute-Button (der trägt .tab nur
|
||||||
// fürs Styling; ohne [data-view]-Filter überschrieb das hier seinen onclick und
|
// fürs Styling; ohne [data-view]-Filter überschrieb das hier seinen onclick und
|
||||||
@@ -1572,146 +1571,10 @@ async function loadNews() {
|
|||||||
} catch (e) { bEl.innerHTML = '<div class="down">Netzwerkfehler</div>'; }
|
} catch (e) { bEl.innerHTML = '<div class="down">Netzwerkfehler</div>'; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Charts (Lightweight Charts): M1/M5/M15/M30/H1 untereinander mit Trend ──
|
|
||||||
const CHART_TFS = ["M1", "M5", "M15", "M30", "H1"];
|
|
||||||
const _charts = {}; // tf → {chart, candle, s12, s50}
|
|
||||||
const _TREND_TXT = { up: ["▲ Aufwärts", "up"], down: ["▼ Abwärts", "down"], flat: ["→ Seitwärts", "flat"] };
|
|
||||||
|
|
||||||
function _ensureChartCard(tf) {
|
|
||||||
if (document.getElementById("chart-" + tf)) return;
|
|
||||||
const card = document.createElement("div");
|
|
||||||
card.className = "chart-card"; card.id = "chart-" + tf;
|
|
||||||
card.innerHTML =
|
|
||||||
`<div class="chart-head"><span class="chart-tf">${tf}</span>` +
|
|
||||||
`<span class="chart-trend" id="ctr-${tf}">—</span>` +
|
|
||||||
`<span class="chart-last" id="clast-${tf}">—</span></div>` +
|
|
||||||
`<div class="chart-cv" id="ccv-${tf}"></div>`;
|
|
||||||
$("charts-body").appendChild(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _makeChart(tf) {
|
|
||||||
const el = document.getElementById("ccv-" + tf);
|
|
||||||
// Explizite Größe statt autoSize: autoSize hängt an ResizeObserver und lieferte
|
|
||||||
// auf Mobil-Browsern teils 0×0-Charts (leerer Tab). clientWidth ist gesetzt,
|
|
||||||
// weil loadCharts erst nach dem Einblenden des Tabs läuft.
|
|
||||||
const chart = LightweightCharts.createChart(el, {
|
|
||||||
width: el.clientWidth || 320, height: 200,
|
|
||||||
layout: { background: { color: "#0d1117" }, textColor: "#8b949e", fontSize: 15 },
|
|
||||||
grid: { vertLines: { color: "#10151c" }, horzLines: { color: "#10151c" } },
|
|
||||||
timeScale: { borderColor: "#30363d", timeVisible: true, secondsVisible: false },
|
|
||||||
rightPriceScale: { borderColor: "#30363d" },
|
|
||||||
crosshair: { mode: LightweightCharts.CrosshairMode.Normal },
|
|
||||||
handleScale: { axisPressedMouseMove: false },
|
|
||||||
});
|
|
||||||
const candle = chart.addCandlestickSeries({
|
|
||||||
upColor: "#3fb950", downColor: "#f85149", borderVisible: false,
|
|
||||||
wickUpColor: "#3fb950", wickDownColor: "#f85149",
|
|
||||||
});
|
|
||||||
const line = (color) => chart.addLineSeries(
|
|
||||||
{ color, lineWidth: 1, priceLineVisible: false, lastValueVisible: false, crosshairMarkerVisible: false });
|
|
||||||
const s12 = line("#58a6ff"), s50 = line("#d29922"); // EMA12 blau, EMA50 amber
|
|
||||||
// Regressionskanal (nur M30 bekommt Daten): oben/unten gestrichelt, Mitte gepunktet
|
|
||||||
const chLine = (color, style) => chart.addLineSeries(
|
|
||||||
{ color, lineWidth: 1, lineStyle: style, priceLineVisible: false,
|
|
||||||
lastValueVisible: false, crosshairMarkerVisible: false });
|
|
||||||
const chU = chLine("#8b949e", 2), chM = chLine("#8b949e66", 1), chL = chLine("#8b949e", 2);
|
|
||||||
_charts[tf] = { chart, candle, s12, s50, chU, chM, chL };
|
|
||||||
return _charts[tf];
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderChart(tf, d) {
|
|
||||||
const off = d.broker_utc_offset || 0;
|
|
||||||
const B = d.bars || [];
|
|
||||||
if (d.error || !B.length) {
|
|
||||||
const tr = document.getElementById("ctr-" + tf);
|
|
||||||
if (tr) { tr.textContent = d.error ? "⚠ " + d.error : "keine Daten"; tr.className = "chart-trend flat"; }
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const candles = B.map(b => ({ time: b.t - off, open: b.o, high: b.h, low: b.l, close: b.c }));
|
|
||||||
const em = (arr) => (arr || []).map((v, i) => (B[i] ? { time: B[i].t - off, value: v } : null)).filter(Boolean);
|
|
||||||
const c = _charts[tf] || _makeChart(tf);
|
|
||||||
c.candle.setData(candles);
|
|
||||||
c.s12.setData(em(d.ema12));
|
|
||||||
c.s50.setData(em(d.ema50));
|
|
||||||
// Regressionskanal (M30) — 3 Linien deckungsgleich mit den Bars; sonst leeren
|
|
||||||
if (c.chU) {
|
|
||||||
const ch = d.channel;
|
|
||||||
if (ch && ch.upper) {
|
|
||||||
c.chU.setData(em(ch.upper)); c.chM.setData(em(ch.mid)); c.chL.setData(em(ch.lower));
|
|
||||||
} else {
|
|
||||||
c.chU.setData([]); c.chM.setData([]); c.chL.setData([]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// S/R-Linien + Zonen (Ranges) als horizontale Preislinien einzeichnen
|
|
||||||
(c.lines || []).forEach(pl => { try { c.candle.removePriceLine(pl); } catch (e) {} });
|
|
||||||
c.lines = [];
|
|
||||||
const addLine = (p, color, style, title) => {
|
|
||||||
if (p == null) return;
|
|
||||||
c.lines.push(c.candle.createPriceLine({ price: p, color, lineWidth: 1,
|
|
||||||
lineStyle: style, axisLabelVisible: true, title: title || "" }));
|
|
||||||
};
|
|
||||||
const LV = d.levels || {};
|
|
||||||
// Verständliche Labels: nächstes Level ausgeschrieben, weitere nummeriert
|
|
||||||
(LV.res || []).forEach((p, i) =>
|
|
||||||
addLine(p, "#1f6feb", 2, i === 0 ? "Widerstand" : `Widerstand ${i + 1}`));
|
|
||||||
(LV.sup || []).forEach((p, i) =>
|
|
||||||
addLine(p, "#58a6ff", 2, i === 0 ? "Unterstützung" : `Unterstützung ${i + 1}`));
|
|
||||||
(LV.zones || []).forEach(z => {
|
|
||||||
addLine(z.hi, "#1f6feb", 1, "Zone"); addLine(z.lo, "#1f6feb", 1, "");
|
|
||||||
});
|
|
||||||
// Chartmuster-Overlay (nur M30): Trigger = kräftige Linie (grün bull / rot bear),
|
|
||||||
// Ziel = gepunktete Linie gleicher Farbe. Nur die 2 stärksten, sonst wird's voll.
|
|
||||||
(d.patterns || []).slice(0, 2).forEach(p => {
|
|
||||||
const bull = p.dir === "bull";
|
|
||||||
const col = bull ? "#3fb950" : (p.dir === "bear" ? "#f85149" : "#8b949e");
|
|
||||||
c.lines.push(c.candle.createPriceLine({
|
|
||||||
price: p.trigger, color: col, lineWidth: 2, lineStyle: 0,
|
|
||||||
axisLabelVisible: true, title: (p.status === "confirmed" ? "▶ " : "◌ ") + p.name }));
|
|
||||||
if (p.target != null)
|
|
||||||
c.lines.push(c.candle.createPriceLine({
|
|
||||||
price: p.target, color: col, lineWidth: 1, lineStyle: 1,
|
|
||||||
axisLabelVisible: true, title: "Ziel" }));
|
|
||||||
});
|
|
||||||
c.chart.timeScale().fitContent();
|
|
||||||
const tr = document.getElementById("ctr-" + tf);
|
|
||||||
const [txt, cls] = _TREND_TXT[d.trend] || ["—", "flat"];
|
|
||||||
tr.textContent = txt; tr.className = "chart-trend " + cls;
|
|
||||||
document.getElementById("clast-" + tf).textContent = candles[candles.length - 1].close.toFixed(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadCharts() {
|
|
||||||
if (typeof LightweightCharts === "undefined") {
|
|
||||||
$("charts-body").innerHTML = '<div class="dim" style="padding:14px">Chart-Framework nicht geladen (Seite neu laden).</div>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const tf of CHART_TFS) {
|
|
||||||
_ensureChartCard(tf);
|
|
||||||
try {
|
|
||||||
const d = await (await fetch(`api/bars?tf=${tf}&n=100`)).json();
|
|
||||||
renderChart(tf, d);
|
|
||||||
// Breite nachziehen (Rotation/Resize seit Erstellung)
|
|
||||||
const c = _charts[tf], el = document.getElementById("ccv-" + tf);
|
|
||||||
if (c && el && el.clientWidth > 0) c.chart.applyOptions({ width: el.clientWidth });
|
|
||||||
} catch (e) {
|
|
||||||
// Fehler SICHTBAR machen statt stumm schlucken (war: leere Kacheln ohne Grund)
|
|
||||||
const tr = document.getElementById("ctr-" + tf);
|
|
||||||
if (tr) { tr.textContent = "⚠ " + (e && e.message ? e.message : "Fehler"); tr.className = "chart-trend flat"; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.addEventListener("resize", () => {
|
|
||||||
for (const tf of CHART_TFS) {
|
|
||||||
const c = _charts[tf], el = document.getElementById("ccv-" + tf);
|
|
||||||
if (c && el && el.clientWidth > 0) c.chart.applyOptions({ width: el.clientWidth });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("logs-reload").onclick = loadLogs;
|
$("logs-reload").onclick = loadLogs;
|
||||||
$("stats-reload").onclick = loadStats;
|
$("stats-reload").onclick = loadStats;
|
||||||
$("news-reload").onclick = loadNews;
|
$("news-reload").onclick = loadNews;
|
||||||
$("charts-reload").onclick = loadCharts;
|
|
||||||
// Auto-Refresh nur solange der Charts-Tab sichtbar ist (schont den mt5_lock)
|
// Auto-Refresh nur solange der Charts-Tab sichtbar ist (schont den mt5_lock)
|
||||||
setInterval(() => { if (!$("view-charts").classList.contains("hidden")) loadCharts(); }, 20000);
|
|
||||||
|
|
||||||
// Sofort einmal per REST laden, dann auf den Live-Stream umschalten
|
// Sofort einmal per REST laden, dann auf den Live-Stream umschalten
|
||||||
fetch("api/snapshot").then(r => r.json()).then(_applySnapshot).catch(() => {});
|
fetch("api/snapshot").then(r => r.json()).then(_applySnapshot).catch(() => {});
|
||||||
|
|||||||
+2
-12
@@ -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=141">
|
<link rel="stylesheet" href="style.css?v=142">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Modul-Menü (ganz oben) -->
|
<!-- Modul-Menü (ganz oben) -->
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
<button class="tab" data-view="siganzeige">SIG Anzeige</button>
|
<button class="tab" data-view="siganzeige">SIG Anzeige</button>
|
||||||
<button class="tab" data-view="logs">Logs</button>
|
<button class="tab" data-view="logs">Logs</button>
|
||||||
<button class="tab" data-view="stats">Statistik</button>
|
<button class="tab" data-view="stats">Statistik</button>
|
||||||
<button class="tab" data-view="charts">Charts</button>
|
|
||||||
<button class="tab" data-view="news">News</button>
|
<button class="tab" data-view="news">News</button>
|
||||||
<button class="tab mute-tab" id="mute-btn" title="Töne an/aus">🔊</button>
|
<button class="tab mute-tab" id="mute-btn" title="Töne an/aus">🔊</button>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -262,14 +261,6 @@
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Charts: M1/M5/M15/M30/H1 untereinander mit Trend (Lightweight Charts) -->
|
|
||||||
<section id="view-charts" class="view hidden">
|
|
||||||
<div class="view-head">
|
|
||||||
<h2>Charts</h2>
|
|
||||||
<button class="reload" id="charts-reload">↻</button>
|
|
||||||
</div>
|
|
||||||
<div id="charts-body"></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- News -->
|
<!-- News -->
|
||||||
<section id="view-news" class="view hidden">
|
<section id="view-news" class="view hidden">
|
||||||
@@ -321,7 +312,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="toast" class="toast hidden"></div>
|
<div id="toast" class="toast hidden"></div>
|
||||||
|
|
||||||
<script src="lightweight-charts.standalone.production.js?v=114"></script>
|
<script src="app.js?v=142"></script>
|
||||||
<script src="app.js?v=141"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
-11
@@ -26,7 +26,7 @@ body{
|
|||||||
-webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
|
-webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
|
||||||
}
|
}
|
||||||
/* Zahlen-lastige Werte in Mono (aligned, Trading-Terminal-Optik) */
|
/* Zahlen-lastige Werte in Mono (aligned, Trading-Terminal-Optik) */
|
||||||
#hdr-price,#hdr-pnl,.px span,.tb-val,.tb-field input,.chart-last,
|
#hdr-price,#hdr-pnl,.px span,.tb-val,.tb-field input,
|
||||||
.hdr-clock,.gap-zone,.trade .p{font-family:var(--mono)}
|
.hdr-clock,.gap-zone,.trade .p{font-family:var(--mono)}
|
||||||
|
|
||||||
/* ── Header (scrollt unter den Tabs) ────── */
|
/* ── Header (scrollt unter den Tabs) ────── */
|
||||||
@@ -342,16 +342,6 @@ main{padding-bottom:74px} /* Platz für die fixe Leiste */
|
|||||||
.stx-c b {font-size:18px;color:var(--text-bright);margin-left:3px}
|
.stx-c b {font-size:18px;color:var(--text-bright);margin-left:3px}
|
||||||
|
|
||||||
/* Charts-Tab: M1/M5/M15/M30/H1 untereinander (Lightweight Charts) */
|
/* Charts-Tab: M1/M5/M15/M30/H1 untereinander (Lightweight Charts) */
|
||||||
#charts-body {display:flex;flex-direction:column;gap:12px;padding:10px}
|
|
||||||
.chart-card {background:var(--surface-2);border:1px solid var(--border);border-radius:10px;overflow:hidden}
|
|
||||||
.chart-head {display:flex;align-items:center;gap:10px;padding:8px 12px;border-bottom:1px solid var(--line)}
|
|
||||||
.chart-tf {font-weight:800;font-size:19px;color:var(--text-bright);letter-spacing:.5px}
|
|
||||||
.chart-trend {font-weight:700;font-size:17px}
|
|
||||||
.chart-trend.up {color:#3fb950}
|
|
||||||
.chart-trend.down {color:#f85149}
|
|
||||||
.chart-trend.flat {color:var(--dim)}
|
|
||||||
.chart-last {margin-left:auto;font-variant-numeric:tabular-nums;color:var(--text-bright);font-size:18px}
|
|
||||||
.chart-cv {height:200px;width:100%}
|
|
||||||
|
|
||||||
/* Kurslücken (Gaps): offene Fill-Magnete */
|
/* Kurslücken (Gaps): offene Fill-Magnete */
|
||||||
.gaps-list {display:flex;flex-direction:column;gap:6px}
|
.gaps-list {display:flex;flex-direction:column;gap:6px}
|
||||||
|
|||||||
Reference in New Issue
Block a user