Files
AH-Oil-Trader/CLAUDE.md
T
Axel HocksandClaude Opus 5 365a0584e5 Prognose-Kegel war unsichtbar: Indikator landete im falschen MT5-Terminal
Der Kegel wurde heute frueh gebaut, exportiert (CN;30/60/120 stehen korrekt
in der CSV) und kompiliert - war aber nie zu sehen. Ursache: unter
%APPDATA%\MetaQuotes\Terminal\ liegen VIER Instanz-Ordner. Meine
Kopier-Zeile bestimmte das Ziel ueber "hat MQL5\Indicators" +
Select-Object -First 1 und traf 0BA5CADA..., waehrend der Bot nach
D0E8209F... schreibt und der Chart dort laeuft.

Folge: der Chart lief seit heute frueh weiter auf v1.29 - ohne
Prognose-Kegel UND ohne die Konsolidierungs-Beschriftung (v1.30), obwohl
beide "gebaut und mit 0 Fehlern kompiliert" gemeldet waren.

Behoben: v1.31 in das Terminal kopiert und kompiliert, das die CSV
schreibt. Verifiziert: #property version 1.31, ex5 frisch, CN-Handler und
TCONSOL-Label im Terminal-Quelltext vorhanden.

CLAUDE.md: Fallstrick dokumentiert samt der richtigen Ziel-Ermittlung (ueber
die vom Bot geschriebene CSV, nicht ueber die blosse Existenz von
MQL5\Indicators) und der Gegenprobe nach jedem Kompilieren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 18:39:06 +02:00

185 KiB
Raw Blame History

CLAUDE.md — Oil Trading Bot (MT5, WTI)

Projektleitfaden für Claude Code. Antworten/UI-Texte auf Deutsch.

🔄 Pflege-Regel: Diese Datei nach jeder inhaltlichen Änderung mitaktualisieren (geänderte Logik/Werte, neue Module/Endpoints, UI-/Alarm- Verhalten, Config-Schalter, Workflows, Asset-Version v=N). Kein separater Auftrag nötig — Teil jeder Aufgabe.

🧱 5-Layer-Prozess bei jeder Änderung (Daueregel, in dieser Reihenfolge): L1 Kontext, Befunde & Risiko/Auswirkung (offene Befunde hier · „erst messen" bei Strategie · was kostet/ändert es — EUR-Risiko/Trade, reversibel?) · L2 Code-Analyse & Design (Datenquelle, Quelle der Wahrheit, wo lebt die Logik) · L3 UI-Design (Module klar in Text und Grafik, auf dem geklärten Datenmodell) · L4 Implementieren, Verifizieren & Rollout (py_compile · JS-Klammern · Backtest/Test · Version-Bump v=N · Aktivierungsweg restart_server.bat · Backup vor destruktiven Schritten, v. a. DB) · L5 Doku aktualisieren (docs/ und CLAUDE.md, zuletzt).

Layer an die Größe der Änderung skalieren — nicht jede Aufgabe braucht alle 5. Strategie-Änderung = alle 5 (inkl. Backtest); reine Anzeige = L2L5 light (kein Backtest); Doku-Korrektur = nur L5. Prozess soll helfen, nicht zur Bürokratie werden.

🔬 Track B — Strategie-Lebenszyklus (ZUSÄTZLICH zu L1L5, für ALLES, was den Edge berührt: Signal, Risk/Sizing, Exit, Gate, Filter). Track A = L1L5 (Code/UI/Infra) bleibt unverändert; Track B läuft parallel für Strategie-Ideen: B1 Hypothese + Hebel-Check — welcher Hebel? Signal = klein (6× belegt: Filter tragen kaum → höhere Beweislast, im Zweifel gar nicht bauen) vs. Sizing/Exit = groß (dort liegt das Geld). · B2 2-Stichproben-Backtest — IMMER ≥2 Zeiträume/ Regime, nie eine (Dead-Hour-Lektion: Std 13 war in einer Stichprobe „profitabel", in der zweiten Rauschen; backtest_hourly_split.py). · B3 Kosten-Check — Ø-Edge netto > ~0,1×ATR (real Spread+Komm.)? sonst raus. · B4 Live-klein + Monitor — ausrollen, dann Live-WR/PF/Verhältnis (Statistik-live-Kachel stats_compact + Flip-Zähler) gegen die Backtest-Erwartung halten; Kadenz wöchentlich (Termin, keine Stufe). · B5 Behalten oder Verwerfen — driftet es live weg (Regimewechsel) → zurückbauen, kein Ego. B4/B5 = die Verfall-Erkennung, die im reinen „Änderung machen"-Prozess fehlt (Trading ≠ Software: Edge kann verfallen).

🧾 B0 — Handels-Checkliste (Mensch, vor jedem manuellen Trade): (1) nicht gegen das Signal (gemessen WR 14 %); (2) Notfall-Stop gesetzt?; (3) Gewinner läuft das Trailing (nicht früh kappen — Ø-Verlust ≫ Ø-Gewinn ist die Kern-Leckage). Steuert die eigentliche Verlustquelle (diskretionäre Abweichungen), die kein Code-Layer erreicht.

Was das ist

Algorithmischer WTI-Öl-Trading-Bot auf MetaTrader 5. (Brent-Umstellung am 2026-07-09 auf User-Wunsch noch am selben Tag zurückgenommen — falls je wieder Brent: Pepperstone-Symbol heißt SpotBrent, kein „UKOIL"; breakout_k=0,3 wurde dort bereits nachvalidiert, ØR +0,305.) Eine Oberfläche:

  • server.py + core/engine.py — headless FastAPI-Web-Backend für die Mobile-PWA in web/ (Zugang vom Handy via WireGuard, 192.168.188.100:8000).

Das frühere Tkinter-Widget (oil_trading_agent.py, ui/, single_instance.py) wurde entfernt — nur noch der Server. ⚠ Immer nur EINE Server-Instanz gegen dasselbe MT5-Terminal laufen lassen (zwei TrailingManager = Konflikt).

Architektur (core/)

  • mt5data.py Preis/Trend/Konto · trader.py Orders+SL/TP · trailing.py Trailing/Teil-Exit · wave_rec.py Empfehlung · elliott.py EW/FVG · tu_rating.py TradersUnion · agent.py KI-Copilot (LLM) · daily_levels.py Tages-Prognose (Web) · gaps.py D1-Kurslücken · mailer.py Graph-E-Mail · structure.py Marktstruktur (M30: HH/HL/LH/LL, BOS, Regressionskanal — reine Anzeige, kein Signal) · candle_logger.py M1-Candle-Log (Daten-Sammlung → candles_m1) · market_hours.py Sessions · history.py SQLite · config.py Konstanten+ oil_widget_config.ini-Loader · mt5_utils.py globaler mt5_lock.
  • engine.py = headless Motor: instanziiert die core-Objekte, fährt Loops als Threads, liefert snapshot() für /api/snapshot + WebSocket /ws. _verdict() aggregiert die Module zur Gesamtempfehlung (verdict im Snapshot) — Doku: docs/gesamtempfehlung.md.

Harte Fakten / Stolpersteine

  • MT5 ist Windows-only (MetaTrader5-Wheel). Backend läuft auf Windows neben dem Terminal; nur Reverse-Proxy/HTTPS könnte auf Linux/Docker.
  • Brokerzeit = UTC+3. deal.time/tick.time immer via _broker_offset_s() bzw. Live-Offset in UTC/Lokalzeit umrechnen.
  • mt5_lock (global, nicht reentrant): alle MT5-Calls darüber, mit Timeout. Nicht aus einem bereits-gehaltenen Lock erneut close() (Deadlock). ⚠ Auch Thread-Pool-Jobs müssen den Lock nehmen: M15Analyzer.analyze() läuft im Executor → eigener mt5_lock-Wrapper in mt5data._fetch_trend_locked (sonst Race). sr.detect() läuft inline unter dem bereits gehaltenen Lock. Ebenso: mt5data.reconnect() (shutdown/initialize) und trader._log_open-delayed_log (positions_get im Thread) laufen jetzt unter mt5_lock (waren Races).
  • Steuer: Broker behält WHT 26,375 % (DE-Abgeltungst.+Soli) je Gewinn ein (WHT #…-Buchungen), erstattet via tägl. „Tax settlement". Stats sind brutto; [trading] wht_pct zeigt eine Netto-Schätzung.
  • Python: C:\Users\ah\AppData\Local\Programs\Python\Python312\python.exe (hat fastapi/uvicorn/MetaTrader5). System32 fehlte mal in der PATH → Skripte nutzen absolute Pfade.
  • LLM-Provider (Stand aktuell): DeepSeek ([deepseek]) ist der aktive Copilot-Provider ([agent] provider=deepseek, 2026-07-20). api.deepseek.com, Modell deepseek-v4-flash (/models listet flash + pro; alte Namen deepseek-chat/-reasoner gibt es NICHT mehr). ⚠ v4-flash ist ein Reasoning-Modell (content nach reasoning_contentmax_tokens=4000 in _call_deepseek, sonst leer; temperature 0.3 ok, schnell ~6 s). ⚠ KEINE Web-Suche → NICHT für daily_levels nutzbar. Fallback-Kette kimi→zai→local greift, wenn der Key ausfällt. Kimi/Moonshot ([kimi], kimi-k2.6) bleibt als Provider verfügbar. Key nur auf dem internationalen Endpoint api.moonshot.ai gültig (.cn = „Invalid Authentication"). Modell kimi-k2.6 (/v1/models listet auch k2.7-code/k3; k3 = thinking-only). ⚠ Zwei Fallstricke: (1) temperature MUSS 1 sein (andere Werte → HTTP 400); (2) k2.6 ist ein Reasoning-Modell → schreibt VARIABLE ~10001200 reasoning_tokens (in message.reasoning_content) VOR dem contentmax_tokens großzügig (4000, _call_kimi), sonst frisst das Reasoning das Budget und content bleibt leer (2000 war teils leer). Moonshot cached den System-Prompt (cached_tokens) → günstiger bei Wiederholung. Kimi ist CN-Modell → CJK-Drift möglich, vom _has_cjk-Retry abgedeckt. Frühere Option z.ai/GLM ([zai], glm-4.5-flash, kostenlos) bleibt reaktivierbar; ⚠ GLM ist Thinking-Modell → IMMER "thinking":{"type":"disabled"}. ⚠ _active_provider-Fix 2026-07-20: zai/kimi waren vorher NICHT in der avail/orders-Map → provider=zai fiel still auf local (qwen) zurück (die [local]-Logzeilen!). Jetzt beide routbar. OpenAI/Gemini-Keys = kein Guthaben (429).
    • KI-Copilot (agent.py): [agent] provider=deepseek. CN-/lokale Modelle (DeepSeek, Kimi, GLM, qwen) driften ins Chinesische → _has_cjk-Erkennung + 1× Retry deckt local, zai, kimi UND deepseek ab. (alle bleiben als Provider- Optionen wählbar.)
    • daily_levels.py bleibt auf z.ai (2026-07-20, gemessen): Die Tagesprognose BRAUCHT Live-Web-Suche. DeepSeek hat keine; Kimi-Web-Suche ($web_search-builtin) läuft nur über einen Tool-Loop, ist >2 min langsam und lief im Test in finish=length (Web-Ergebnisse+Reasoning sprengen selbst 4000 Tokens → leerer Content). z.ai macht es in EINEM sauberen web_search-Call → kein Wechsel (Kontext-Feature, kein Edge). ⚠ S/R-Kontext-Fix 2026-07-15: _tool_zones füttert dem LLM jetzt die echten M5-Pivots (wave.pb_levels, geclustert, nächste 3 je Seite) statt der stale [zones]-Config — plus Prompt-Leitplanke „nutze NUR die übergebenen Level, erfinde keine runden Marken". Reiner Kontext-Fix (keine Strategie): macht die Kommentar-Level aktuell/konsistent zum Chart, macht die LLM-Einschätzung aber NICHT validierter (Copilot bleibt unbelegte Verdict-Stimme, Gewicht nur bei Bias).
    • Tages-Prognose (daily_levels.py): z.ai + Web-Suche, 1×/Tag 07:30 Berlin.

Workflows / Befehle

  • Änderungen aktivieren: restart_server.bat (lädt core neu). Auto-Start: Aufgabe OilTradingServer (Login, versteckt via VBS). ⚠ Startet seit 2026-07-30 BEIDE Server (User-Vorgabe): erst das Hyperliquid-Dashboard (Port 8001, versteckt via dessen start_hidden.vbs, wartet max. 10 s aufs Lauschen), dann das Oil-Backend (8000) im Vordergrund. Grund + behobener Bug: die Kill-Zeile trifft mit *server.py* BEIDE Prozesse — vorher wurde der HL-Server bei jedem MT5-Neustart still mit-erschlagen und nie wieder gestartet. Das riss die Lücken in die Lead-Lag-/Order-Flow-Datensammlung (72 h Spanne, aber nur 2292 Samples) UND ließ die Liquiditätslinien im Chart verschwinden. Fail-safe: fehlt das HL-Projekt (..\HyperLiquid-WTI Trader), startet nur 8000 mit Hinweis. Auto-Start des HL-Servers separat: Aufgabe HyperliquidDashboard (Login).
  • ⚠ MQL5-Indikator: das RICHTIGE Terminal treffen (Fallstrick, 2026-07-31). Unter %APPDATA%\MetaQuotes\Terminal\ liegen mehrere Instanz-Ordner. Wer das Ziel über „hat MQL5\Indicators" + Select-Object -First 1 bestimmt, erwischt leicht den falschen — real passiert: v1.30 und v1.31 landeten in 0BA5CADA…, während der Bot in D0E8209F… schreibt und der Chart dort läuft. Folge: der Kegel und die Konsolidierungs-Beschriftung waren einen halben Tag lang „gebaut und kompiliert", aber unsichtbar — der Chart lief weiter auf v1.29. Richtig: das Ziel über die CSV bestimmen, die der Bot tatsächlich schreibt:
    $term = Get-ChildItem "$env:APPDATA\MetaQuotes\Terminal" -Directory |
            Where-Object { Test-Path "$($_.FullName)\MQL5\Files\sr_levels.csv" } |
            Sort-Object { (Get-Item "$($_.FullName)\MQL5\Files\sr_levels.csv").LastWriteTime } -Descending |
            Select-Object -First 1
    
    Gegenprobe nach jedem Kompilieren: #property version im Terminal-.mq5 und der Zeitstempel der .ex5 müssen zum erwarteten Stand passen.
  • Web-Assets: Browser cacht hart → in web/index.html ?v=N hochzählen bei jeder JS/CSS-Änderung; Server sendet Cache-Control: no-store. Hängt der Handy-Cache: Inkognito oder Seite mit frischem ?xN öffnen.
  • Empfehlungs-Edge messen: python backtest_signal.py [TF] [N] [K] (ereignisbasiert, nutzt die echte _build-Logik). Ø-Edge>0 = trägt.
  • Ausführungs-Kalibrierung: python analyze_execution.py — (A) echtes Spread-Profil je Berlin-Stunde aus dem Bar-spread-Feld, (B) Slippage bei SL-Closes, (C) MAE/MFE der Live-Trades. Kern-Befund 2026-07-13: Spread ist absolut konstant (0,0225), aber relativ Ø 0,265×ATR — die alte Kostenannahme 0,1×ATR war v. a. in Niedrig-Vola-Phasen 2,5× zu optimistisch (erklärt Live-PF < Backtest-Erwartung). Stunden 1517 am günstigsten (0,13), Nacht 07 = Kostenfalle (0,320,50×ATR). Slippage-Tail real: die 35/54- Desaster hatten 0,75 Slippage ÜBER den Initial-SL hinaus (harter SL deckelt in schnellen Märkten nicht). MAE/MFE live: Exits validiert (nur 7 % der Verlierer waren je ≥1,3×ATR im Plus → Breakeven-Schwelle passt; Gewinner-MAE Median 0,28). ⚠ Künftige B3-Checks mit stunden-echten Kosten rechnen, nicht pauschal 0,1. (WR/PF/Verhältnis/Worst je KW, Ausrichtungs-Split mit/gegen/ohne) gegen die Backtest-Erwartung (WR68 % · PF1,3 · Verh0,55) und flaggt Leckagen (Gegen-Signal- Anteil, WR-Verfall, PF<1, Einzelverlust). Wöchentlich laufen lassen (B4/B5).
  • Vor „fertig": immer python -m py_compile <datei>; JS grob via Klammern- Balance prüfen (kein node im Env).
  • Konsole: UTF-8 erzwingen (PYTHONIOENCODING=utf-8, -X utf8).
  • Uvicorn-Access-Log AUS (access_log=False in uvicorn.run, 2026-07-22): seit dem 4-s-REST-Polling + WS-Push flutete GET /api/snapshot … 200 OK die Konsole. Betrifft NUR Uvicorns eigenes Zugriffs-Log, nicht die oil.*-Logger (eigene Hierarchie, core/logger.py, unverändert in Konsole + Datei).

Empfehlungs- & Trade-Logik (Stand aktuell)

  • Richtung = EMA12 vs EMA50 (wave_rec.py), NICHT mehr ZigZag-Momentum (das hatte ~0 Edge). Totband (Chop→WARTEN), Anti-Überdehnung (_STRETCH_MAX=3,5×ATR), +S/R-Konfidenz, +Session-Konfidenz. (TU entfernt — s. u.)
  • Volatilitäts-Squeeze-Breakout = ADDITIVER SETUP, UMGESETZT (User-Idee „Breakouterkennung" 2026-07-14, gemessen backtest_breakout_squeeze.py): struktureller Ausbruch aus einer Kompression (Box = Spanne der letzten _SQ_N=10 abgeschlossenen M5-Bars ≤ _SQ_MULT=2,5×ATR) um _SQ_K=0,1×ATR — NICHT der EMA-Trend-Breakout. 2-Stichproben-positiv (ØR +0,227/+0,141 netto Echtkosten, PF 1,35/1,20, 173/413 Trades; schlägt den Ausbruch aus beliebiger Box 0,045/+0,161 in BEIDEN Hälften) & robust über Box 1020 / k 0,10,2 (alle 8 Kombis positiv, kein Parameter-Zufall). Andere Signalklasse als die Welle → komplementär. Umsetzung: wave._squeeze_one(highs,lows,closes,atr) (M5). Erkennungs-Latenz ~5 s (Variante A, 2026-07-21): der Squeeze läuft auf einem EIGENEN, schnellen 60-Bar-M5-Fetch (_sq_due/_SQ_REFRESH_S=5.0, entkoppelt von der 15-s-TF-Ampel-Drossel) → Ausbruch wird ~15 s→5 s schneller erkannt, dann ~1 s Handeln (_pos_loop). Gleiche validierte M5-Regel, reine Infra (kein Backtest nötig). Variante B (Squeeze auf M1) = OFFEN/UNBELEGT — erst backtesten, wenn der M1-Logger (candles_m1, seit 2026-07-21) ab ~2027-01 genug History hat. Snapshot wave.squeeze {state, dir, level, box_atr}: active = Ausbruch (echtes Signal LONG/SHORT) · armed = komprimiert, Ausbruch steht bevor · None = keine Kompression (transient — der Ausbruch weitet die Box, Signal klärt sich selbst). Verdict-Modul „Squeeze" (_verdict, Gewicht 2,0, nur bei active; unter der Welle=3,0). UI Welle-Kachel (#wave-squeeze): grün/rot bei active („🚀 Squeeze-Breakout ▲ LONG @ …"), blau bei armed („🎯 Kompression … Ausbruch steht bevor"), grau sonst. ⚠ Nur der ENTRY — der User-Teil „Gegen-Trade schließen
    • Stop-&-Reverse" ist NICHT gebaut (nicht validiert, verdoppelt Kosten, Chop-Risiko). Läuft normal über SL/Trailing/Notfall-Stop. Caveats: modeste Stichprobe (Box>12 = 1222 Trades = Rauschen), Frequenz ~23/Woche → B4-Wochenmonitor (Live-ØR/PF gegen +0,14…+0,23), Runner-abhängig (43 % Treffer). Verwerfen, wenn Live wegdriftet (B5).
  • Momentum-Continuation als Auto-Setup = VERWORFEN (gemessen backtest_momentum.py, 2026-07-17): Kandidat für Autonomie (Einstieg in Richtung eines frischen Momentum-Schubs, mom_N kreuzt ±X×ATR; seq. Sim, Live-Exit, Echtkosten). Fällt durch den 2-Stichproben-Test: fast alle N/X in H1 negativ (0,03…−0,22), in H2 positiv (+0,02…+0,07) → regime-abhängig. Einzige „beide positiv"-Kombi (N=24/X=2,0) ist H1 +0,002 / PF 1,00 = Breakeven-Rauschen, nicht der Squeeze-Maßstab (+0,14…+0,23). Grund: Momentum-Continuation IST Trendfolge — erbt die Regime- Anfälligkeit des Wave-Signals, kein distinkter Edge wie die Kompression→Ausbruch- Klasse. Autonomie-Fazit: der Squeeze bleibt der EINZIGE validierte Auto-Entry. (P(break)-Level-Bounce als Entry ist separat schon verworfen, s. „Range-Einstieg".)
  • Opening Range Breakout (ORB) als Auto-Setup = VERWORFEN (gemessen backtest_orb.py, 2026-07-17, Recherche-Kandidat): Box = erste 15/30 min nach EU-Open (10:00 Brk) bzw. US-Open (16:30 Brk), Ausbruch ±0,1×ATR, one-shot, Live- Exit, Echtkosten. 3 von 4 Varianten kippen zwischen den Hälften (US-Open H1 0,19…−0,27!); einzig EU-15min ist beidseitig positiv, aber nur ØR +0,069/+0,027 (PF 1,11/1,04) = Rauschen unter dem Kosten-Puffer, und die Nachbar-Parameter kippen (keine Robustheit — beim Squeeze waren ALLE 8 Kombis positiv). ⚠ Lehrstück: erster Lauf zeigte EU-Open ØR +1,3/PF 10 — war ein Selektions-Artefakt (ATR- Skip statt Floor ließ in der Niedrig-Vola-H1 nur 9 Morgen durch); mit Floor verschwand der „Edge". Zeit-Anker ersetzt keinen Struktur-Anker.
  • ATR-Breakout-Bestätigung (wave._confirm_breakout, live [trading] breakout_k=0.3 — Split-validiert, s. u.; 0=aus): ein Richtungssignal wird erst durchgelassen, wenn der Kurs k×ATR in Signalrichtung gelaufen ist („X dynamisch"); läuft er vorher k×ATR DAGEGEN/ Timeout → neu verankern, solange WARTEN (Grund „warte auf Breakout …", snap.breakout). Stateful (_pend), reset bei TF-Wechsel. Gemessen (backtest_breakout.py): hebt Ø-Edge/Trade ~2× (+0,185→+0,36 bei k=1,0), Treffer 43→47 %, ~halb so viele Trades → netto klar besser (halbe Spread-/ Komm.-Kosten; lohnt ab Kosten >0,037×ATR, real ~0,1×ATR). = die „Zwei-Konten- Hedge"-Idee des Users, auf EINEM Konto ohne doppelte Kosten. k=0,3 seit 2026-07-08 (Split-validiert, 80k Bars in 2 Halbjahren): k=0,3 ist in BEIDEN Hälften das Beste — H1: ØR +0,119/netto +339 (0,5: +0,055/831; 1,0: +0,046/805 — beide netto negativ!), H2: +0,362/+4239 (0,5: +3308; 1,0: +3838). Grund: 0,3 filtert Fehlstarts, behält aber den besseren Einstiegspreis (höheres k = späterer Einstieg, Anfang des Moves verschenkt). ⚠ Ein-Stichproben-Lauf hatte „1,0 besser" gezeigt — Split-Prüfung drehte das (B2!). Nebeneffekt: kürzere „warte auf Breakout"-Phasen.
  • Entry-Raum-Gate (AKTIV, [trading] entry_room_atr=0.6 — kurz 1,0, am selben Tag zurück auf 0,6, s. u.; gemessen backtest_entryroom.py 2026-07-16): Richtungssignal → WARTEN, wenn das Gegenlevel (M5-Pivot in Trade-Richtung, trainingsgleich zum S/R-Auto-Close) näher als X×ATR_M5 liegt. Befund (seq. Sim MIT S/R-Close-Exit, Echtkosten, 2 Halbjahre): monoton in BEIDEN Hälften — Raum <0,3: ØR 0,119/0,067 (PF 0,42/0,66!) · 0,30,6: 0,100/0,059 (⚠ 7982 % WR und trotzdem PF<1 = Klein-Close-Falle) · 0,61,0: 0,123/0,060 · ≥1,0 bzw. „kein Gegenlevel" positiv. Kosten-Arithmetik, kein Signal-Timing (deshalb robust, anders als die 9 verworfenen Filter): Ertrag am Level gedeckelt (63 % Containment) 0,265×ATR Kosten < 0. Auslöser: Live-Trades mit Sofort-/Klein-Close (0-min-Trade +0,08 direkt am Level; 4 der 5 sr_closes desselben Tages waren dagegen RETTER — Exit NICHT anfassen). Umsetzung: wave._room_gate (in refresh_market VOR _confirm_breakout; set_entry_room, Grund „kein Raum: Widerstand X nur 0,4×ATR entfernt …"). Backtests via _build bleiben gate-frei (kein pb_levels-State). 0,6→1,0→0,6 (2026-07-24): kurz auf 1,0 erhöht (gemessen in BEIDEN Hälften besser, H1 +415/ H2 +266 R; Live-Kurzcheck: S/R-Closes seit 16.07. +925 € bei nur 28 % Klein-Closes) — aber der User empfand im gemischten Regime (M15/M30 ab, M5/H1 auf) zu viel WARTEN und stellte noch am selben Tag auf 0,6 zurück. ⚠ Lehr-Fall dabei festgehalten: „kein LONG trotz steigendem Kurs" lag NICHT am Raum-Gate, sondern am M30-Gegen-Trend-Filter (M30 ab → LONG unterdrückt, gewollt); das Raum-Gate mutete nur den daraus resultierenden SHORT (Support 0,09×ATR entfernt). 0,6 vs 1,0 ist reiner Frequenz-gegen-Edge-Kompromiss (gemessen 1,0 netto besser). ⚠ P(break)-Freigabe des Gates = VERWORFEN (gemessen backtest_entryroom_pbreak.py, 2026-07-24): Idee war, Raum<1,0-Signale durchzulassen, wenn P(break)@Entry hoch (Level bricht eh → Ertrag nicht gedeckelt). Das Modell TRENNT zwar auch am Entry (Freigabe-Gruppen klar besser als der Rest), aber JEDE Schwelle kippt zwischen den Hälften (p≥0,5: 0,016/+0,083 · p≥0,6: +0,089/0,006 · p≥0,7: +0,076/0,029) → nicht robust, reines Distanz-Gate bleibt. 13. verworfener Signal-Eingriff. (Nebenbefund: geblockte Gruppe in beiden Hälften klar negativ, 436/251 ΣR — bestätigt die 1,0-Erhöhung.)
  • Mindest-Konfidenz-Gate (_MIN_CONF=55): Signal < 55 % → WARTEN. Gemessen (backtest_conf.py): Band 4054 % = negativer Edge (0,025), ≥55 % = +0,058; Gate hebt Ø-Edge ~+50 % und den Gesamtertrag (entfernt die schwachen Setups, bei denen zu viele Strafen gestapelt sind — typisch der Lagging-Short am Boden).
  • Signalhäufigkeit (backtest_dist.py): ~57 % der Zeit LONG/SHORT, ~43 % WARTEN. WARTEN-Treiber: M30-Gegen-Trend (~27 % der Bars, gewollt, Edge×2) + Überdehnung
    • Totband. _STRETCH_MAX 2,5→3,5 angehoben (backtest_stretch.py: +26 % Signale, Gesamtertrag steigt; ab 3,5×ATR kippt der Edge negativ).
  • Higher-TF-Gegen-Trend-Filter: Signal wird verworfen (→WARTEN), wenn der übergeordnete M30-Trend (EMA12/50, Totband _HTF_DEADBAND=0,15×ATR) klar dagegen steht — kein Short im M30-Aufwärtstrend & umgekehrt. Nur für Basis-TF < M30 aktiv (_htf_sign, holt M30-Bars im selben mt5_lock). Per Backtest belegt: Ø-Edge ×2 (+0,012→+0,027), Treffer 52→54 %. Mess-Tool: python backtest_htf_filter.py M5 M30 4000 0.15.
  • Einstiegsqualität (nur Konfidenz/Score, NICHT Richtung): nach gemessenem Edge (backtest_pullback.py) gestaffelt — tiefer Pullback (Kurs durch die EMA zurück, near<0) = bestes CRV (+15, „ tiefer Pullback"); laue Zone direkt an der EMA (00,3×ATR) = schwächster Edge (3); Trend-Momentum (12×ATR) +8. Kein Spitzen-Gate: ein hartes „nur an Wellenspitze"-Filter senkte den Gesamtertrag (80 % Trades), darum verworfen. Konfidenz blockt NICHT das Ordern (nur WARTEN/Gegen-Signal tut das).
  • Multi-TF-Konfluenz (nur Konfidenz/Anzeige): M30 und H1 bestätigen die Richtung → +12, „ Konfluenz M30+H1"; H1 dagegen → 8. Per Backtest belegt: Ø-Edge ×3,5 (+0,016 nur-M30 → +0,056 M30+H1). _htf_sign holt zusätzlich H1-Bars. Mess-Tool: python backtest_improve.py 8000.
  • Tageszeit-Gate = AUS geschaltet (User-Vorgabe 2026-07-22, [trading] dead_hours= leer — bewusst GEGEN die Messung). Jetzt config-steuerbar (wave.set_dead_hours, Komma-Liste von Stunden; leer=aus). Gemessener Default im Code = 0,1,2,3,4,5,6,7,12,16 (die ini überschreibt auf leer). ⚠ 12/16 waren zuletzt am 2026-07-21 (backtest_hourly_split.py) noch beidhälftig negativ — der User schaltet das Gate trotzdem ab. Reaktivieren = ini-Stunden eintragen. Der EIA-Blackout (Mi 15:3016:30) bleibt separat aktiv (eigenes Event-Gate, nicht Teil des dead_hours). Historie/ Messung (Gate war 1114 → 12+16 → aus → zurück → jetzt wieder aus): Nach der Echtkosten-Messung (backtest_realcosts.py, Kosten = Bar-Spread/ATR statt pauschal 0,1×ATR — Ø real 0,265!): Nacht 07 = Kostenfalle (konstanter Spread ÷ niedriger Nacht-ATR = 0,320,50×ATR, in beiden Hälften negativ; reine Arithmetik) + 12/16 Uhr 3× unabhängig negativ. Politik „07+12" verbessert BEIDE Hälften (H1 4038→−1870, H2 +100→+1191). Robust positiv nur 2122 Uhr. ⚠ Die „15 robusten Negativ-Stunden" NICHT blocken — in-sample-zirkulär (Overfit). breakout_k=0,3 auch unter Echtkosten bestätigt (H1 einziges positives k). Historie (Gate war 1114, dann 12+16, dann auf User-Wunsch aus, jetzt gezielt zurück):
    • Von 1114 auf 12+16 umgestellt (gemessen+verifiziert, backtest_hourly.py + backtest_hourly_split.py, 80k M5 in 2 Halbjahren): Netto-R je Stunde zeigt 12 Uhr (0,11/0,12) und 16 Uhr (0,17/0,10) in BEIDEN Hälften negativ; Std 13 kippt das Vorzeichen (0,048/+0,039 = Rauschen), 11/14 ~breakeven. Das alte Pauschal-Gate 1114 blockte harmlose Stunden und ließ die real schlechte 16 laufen. Gate 12+16 schlägt 1114 im Gesamt-Netto-R in beiden Zeiträumen (H1 1357→−1253, H2 +1562→+1799) und handelt dabei mehr Trades. Intraday-Edge generell dünn; Löwenanteil in US-Session 2122 Uhr (+0,25/+0,49).
    • Reversal-Ausnahme vom Gate = VERWORFEN (gemessen, backtest_deadhour.py): Reversal in der Dead-Hour nur +0,062×ATR brutto (vs +0,190 außerhalb) → nach Kosten (~0,1×ATR) negativ. Trade-①-Gewinner war Varianz. Gate gilt auch für Reversal.
  • EIA-Blackout (kausales Event-Gate, AKTIV): Mittwoch 15:3016:30 Berlin (Vorlauf der EIA-Lagerdaten 16:30 = 10:30 ET, Offset ganzjährig 6 h) → hartes WARTEN („EIA-Blackout …"). Gemessen (backtest_events.py, 2 Halbjahre): dieses Fenster in BEIDEN Hälften netto negativ (0,147/0,088 vs rest) — deckt sich mit dem alten „16 Uhr"-Befund. eia_post/api_pre/api_post NICHT robust → nicht geblockt. Nur im Live-Pfad (hour≠None), Backtests bleiben gate-frei. Best-Practice „Event-Blackout" statt Pauschal-Gate.
  • Wirtschaftskalender-Blackout (core/econ_calendar.py, 2026-07-30, [trading] news_blackout=true, ±15 min): Erweiterung der EIA-Idee auf ALLE High-Impact- Termine (FOMC/Zinsentscheid/NFP/CPI/GDP/PCE + alle Oil-/OPEC-Titel). Quelle Forex Factory JSON (nfs.faireconomy.media, kostenlos, kein Key, mit impact-Feld); geholt werden beide Wochen (thisweek+nextweek — „thisweek" endet samstags, der Markt öffnet aber Sonntag 23:00 → sonst blinder Fleck), 1×/h im Daemon-Thread (ein hängender HTTP-Call darf den Trend-Loop nicht blockieren), dedupliziert über (ts, title). Filter: impact=High + country=USD, ODER Titel enthält crude oil/opec/oil inventories/petroleum (der EIA-Report läuft bei FF teils als Low/Medium). ⚠ NICHT gemessen — Events sind zu selten für eine 2-Stichproben-Aussage, das ist die Handbuch-Regel („keine Trades 15 Min. vor High-Impact-News"), kein belegter Edge. Deshalb bewusst asymmetrisch verdrahtet: sperrt nur die AUTONOMEN Entries (_check_auto_squeeze + _check_auto_signal, jeweils OHNE Dedup-Marker → nach dem Fenster feuert das Setup, falls noch aktiv) und erscheint in der Entry-Checkliste nur als „warn", nicht „fail" (soll den Verdict nicht allein auf stop kippen); manuelle Orders bleiben frei. Der gemessene EIA-Blackout bleibt unabhängig davon aktiv — er greift auch, wenn der Kalender kein Netz hat (Fail-safe: ohne Daten → kein Blackout, Log 1×, dann still). Snapshot calendar {enabled, n, blackout{title,impact,ccy,minutes}, next, age_min}, Frontend #cal-note (Meldungen-Karte, bernstein: laufendes Fenster bzw. Vorwarnung ≤60 min). Abschalten news_blackout=false; Fenster via news_blackout_before_min/ _after_min. Mit 4 synthetischen Szenarien getestet (5 min vor/nach Event, 50 min davor = kein Blackout, disabled) + Live-Fetch verifiziert (EIA lag korrekt auf Mi 16:30 Berlin).
  • Winkel-vs-EMA-Warnung (nur Konfidenz): Regressions-Winkel der Basis-TF gegen die EMA-Richtung → 10 „⚠ Winkel gegen EMA (mögliche Wende)" (nachlaufende EMA!); dafür → +5. backtest_angle.py: dafür/neutral +0,055 vs dagegen +0,025; als Gate aber Gesamtertrag-negativ → bewusst nur Konfidenz/Warnung (Hilfe fürs manuelle Überspringen der Lagging-Shorts).
  • Höher-TF-Winkel-Filter (M30+H1-Winkel) = VERWORFEN (gemessen, backtest_htf_angle.py): Signal verwerfen, wenn M30/H1-Regressionswinkel gegen die Richtung steht → in JEDER Schwelle/Variante schlechter. Die entfernten Signale (Short bei aufwärts-Winkel) haben höheren Edge (+0,040,05) als die behaltenen (+0,02) — es ist der profitable Pullback-Setup. Filter kostet ⅔ des Gesamtertrags (+287→+70). Gegen-Winkel-Shorts NICHT filtern; einzelne große Verluste (z. B. 37 an einem H1-Auf-Tag) sind Varianz, Schutz über Notfall-Stop/ Sizing, nicht über Signal-Filter.
    • Auch als Konfidenz-STRAFE verworfen (backtest_confluence_angle.py): statt Hard-Filter den Konfluenz-Bonus streichen/Konf senken, wenn M30/H1-Winkel dagegen → borderline-Signale fallen unters 55-Gate. Ergebnis: in JEDER Variante schlechter2500…−3467 R); die entfernten Gegen-Winkel-Signale haben ØR +0,26…+0,32 (die BESTEN), die behaltenen +0,12. 3× gemessen (M5-Winkel, Höher-TF-Winkel-Filter, Konfluenz-Strafe): „nicht gegen den Winkel shorten" macht den Bot IMMER schlechter. Nicht mehr am Signal drehen — Edge ist klein & varianzlastig; der Hebel ist Sizing (risiko-basiert) + viele Trades, nicht der Filter.
    • H1-STÄRKE-Filter (nicht Winkel!) = VERWORFEN (gemessen backtest_short_h1filter.py, 2 Halbjahre, 2026-07-15): Motiviert durch Live-Befund „SHORT-Empfehlungen 31 % WR in Aufwärts-Regime" (LONG 62 %, SHORT 31 %, letzte 40 MIT-Trades). Idee: Signal verwerfen, wenn es gegen einen starken H1-Trend (|H1 EMA12EMA50| > thr×ATR_H1) läuft. Fällt durch: die weggefilterten Signale flippen das Vorzeichen zwischen den Hälften — thr 0,5: ØR H1 0,198 / H2 +0,001; thr 1,0: 0,069 / +0,013; thr 1,5: +0,029 / 0,063. In KEINER Schwelle robust negativ in BEIDEN → Filter hätte in H2 (positive/breakeven drops) Geld gekostet. 7× belegt: die 31 %-SHORT- Schwäche ist REGIME (aktueller Uptrend), kein Signalfehler — in H2 tragen dieselben Gegen-H1-Shorts. Kein Filter; der Hebel bleibt Sizing + Notfall-Stop + Diskretion (User-WARTEN-Übersteuerungen liefen 68 % WR / +259 €).
    • ER-Chop-Gate = VERWORFEN (gemessen, backtest_chopgate.py, 2 Halbjahre): Signal→WARTEN wenn Efficiency Ratio der letzten N Bars < X. Chop-Signale sind NICHT robust schlechter — Effekt kippt: H1 Trend leicht besser (Ø-R +0,070 vs +0,053), H2 umgekehrt (Chop +0,138 vs +0,129). Gate wirft zudem ~70 % (profitables) Volumen weg (ΣR +2299→+836). Das Totband filtert Extrem-Chop schon (ER-0,02-Tag = 71 % WARTEN); Rest-Signale = Varianz. 5× belegt: Signal-Filter tragen nicht.
  • Vola-Abzug (nur Konfidenz): hohes ATR (oberes Terzil, _ATR_HIGH≈0,27) = schwächster/negativer Edge → 8 „hohe Vola". Schwelle regime-abhängig → kein Gate.
  • Reversal-Lockout/-Persistenz = VERWORFEN (gemessen, backtest_revlock.py): Gegen-Signale kurz nach einem Reversal sind sogar besser als normale (+0,072 vs +0,018 bei N≤6) → Reversal-Signale NICHT sperren/halten. Einzelne Verluste (Bottom-Short nach REV) sind Varianz, kein Muster.
  • Rec-Logging: engine._run_analysishistory.log_recommendation (Throttle intern) füllt die recommendations-Tabelle (Signal/Score/Conf/Winkel/Setup) für Tages-Reviews (analyze_today.py rekonstruiert sonst aus M5-Bars).
  • Reversal-/BOUNCE-Einstieg (antizyklisch, markiertes ZWEITsignal): überdehnt (|stretch|≥_REVERSAL_STRETCH=3,0, entkoppelt von Anti-Überdehnung _STRETCH_MAX=3,5) UND Regressions-Winkel hat gedreht → Einstieg in Winkel-Richtung, gegen die EMA (überverkauft + Winkel auf → LONG; überkauft + Winkel ab → SHORT). Setup WAVE_REV_*, Grund „🔄 Reversal"; hebt Anti-Überdehnung und M30-Filter bewusst auf. Schwelle 3,5→3,0 gesenkt (User wollte mehr Bounces; backtest_bounce.py): Ø-R +0,185, PF 1,35, Treffer 70 %, Worst 2×ATR (SL-gedeckelt), ~1,5× mehr Bounces als 3,5 — profitabel, aber schwächer als Trend & regime-anfällig (trägt in Seitwärts/Mean-Reversion, blutet in starken Trends). Nachrangiges, markiertes Setup. Bounce-Status — Multi-TF im Wave- Snapshot (wave.bounce = {state, dir, tf}): scannt M1/M5/M15/M30 (_bounce_one, Aggregat in refresh_market, ~15 s-Throttle via TF-Ampel-Fetch), nimmt den stärksten (aktiv>erwartet, dann größte Überdehnung). expected = überdehnt (≥_REVERSAL_STRETCH), Winkel noch NICHT gedreht · active = + Winkel gedreht. dir LONG (überverkauft) / SHORT (überkauft), tf = Quelle. Frontend #wave-bounce als „Überdehnung"-Warn-Gauge (NICHT „Bounce/Signal"): grau „keine" · bernstein „⚠ überdehnt … Reaktion nach oben ↑ / nach unten ↓ möglich" · kräftiger bei active (+ TF). Kein grün/rot (kein Trade-Trigger). Reversal-Konfidenz-Boni = GEPRÜFT & BEHALTEN (gemessen backtest_revconf.py, 2 Halbjahre, 2026-07-15): Befund war, dass „starker Trend" (+10) und „ tiefer Pullback" (+15) beim Reversal semantisch GEGEN das Signal stehen und Reversals so leichter durchs 55er-Gate kommen. Korrektur (Boni beim REV streichen) fällt durch: die dadurch rausfallenden Reversals kippen das Vorzeichen — H1 ØR 0,323 (127 St., Fix ok), H2 ØR +0,109/PF 1,16 (1608 St., Fix hätte die BESSEREN gekappt, WR 45 %). Nicht robust → Konfidenz-Berechnung bleibt. 8. verworfener Signal-Eingriff. Die hohe REV-Conf-Anzeige (~7580 %) ist also kein Gate-Fehler; wer will, liest die Reason-Liste („Reversal" + „hohe Vola") als Risiko-Kontext. Gemessen (backtest_bounce_reliability.py): Richtungs-Trefferquote der „aktiv"-Anzeige ~50 % (Münzwurf), Ø-Vorlauf ~0×ATR über alle TF & H1-Regime → reiner Überdehnungs-Kontext, KEIN Signal. (Die früheren „70 %" aus backtest_bounce.py waren exit-getrieben, nicht Richtungs-Vorhersage.)
  • ⚠⚠ TF-CHURN-FIX (2026-07-31, zwei Eingriffe) — Ursache für „93 % WARTEN statt 43 %": Auslöser war die User-Frage „warum hat der Bot die Treppe nicht erkannt und long eröffnet?" zur Rally am 31.07. (82,5 → 84,4 in 2 h). Befund: in dem Fenster gab es 99× WARTEN und 1× SHORT — und dieser SHORT wurde am Tief autonom eröffnet (AUTOSIG, 26,31 €, per adverse15 geschlossen); den LONG machte der User um 11:56 von Hand gegen die Empfehlung. Der WARTEN-Anteil live ist strukturell zu hoch:
    WARTEN
    Backtest-Erwartung (backtest_dist.py) ~43 %
    Live letzte 24 h 93,2 %
    Live letzte 7 Tage 88,0 %
    Live gesamt (93.599 Zeilen) 78,6 %
    MECHANISMUS (im Log belegt): _choose_tf setzt den Score einer TF **hart auf
    0,0**, sobald sie überdehnt ist (`raw = sep if (sep>=deadband and stretch<=_STRETCH_MAX)
    else 0.0`) — genau das passiert M5 IM Trend. Real am 31.07.: M5 sprang zwischen
    0,00 und 1,93, die TF wechselte 33× am Tag, Median-Abstand 5 min. Die
    vorhandene 1,2×-Hysterese ist dagegen wirkungslos (gegen 0,0 kommt jeder Wert durch).
    Und set_timeframe() verwarf bei JEDEM Wechsel die laufende Breakout-Bestätigung
    (_pend = None) und verankerte sie beim AKTUELLEN Kurs neu. Bei breakout_k=0,3 und
    ATR_M30≈0,53 braucht sie ~0,16 , der Kurs lief ~0,08 je 5 min → **die Bestätigung
    konnte rechnerisch nie fertig werden.** Dazu: landet die Heuristik im Trend auf M30,
    braucht das EMA-Kreuz dort Stunden — eine 2-h-Bewegung wird nie zum Signal.
    Gleicher Fehlertyp wie beim P(break)-Modell am selben Tag: backtest_breakout.py
    hat k=0,3 auf einer FESTEN Zeitebene validiert; live wandert sie — die Bedingung,
    unter der die Messung gilt, existiert im Betrieb nicht.
    FIX 1 (wave_rec.set_timeframe): _pend wird NICHT mehr zurückgesetzt. Der Anker
    gehört zum Signal, nicht zur Zeitebene; dreht die Richtung, verankert
    _confirm_breakout ohnehin neu (p.get("dir") != d). Das Level behält den ATR der
    alten TF — bewusst, eine Neuberechnung wäre wieder ein Reset.
    FIX 2 (engine._tf_loop): Mindest-Verweildauer [trading] tf_min_dwell_s=900
    (0 = aus). Gibt einer TF Zeit, ihr Signal überhaupt fertig zu bestätigen.
    Verifiziert mit synthetischen Szenarien: Fix 1 — Bestätigung überlebt den Wechsel
    M5→M30 und feuert LONG, Richtungswechsel verankert korrekt neu; Fix 2 — an der ECHTEN
    Score-Folge vom 31.07. nachgespielt: 4 Wechsel → 2.
    Ehrlich zur Beweislage: das ist NICHT backtestbar — Backtests laufen
    grundsätzlich auf einer festen TF, das Churning existiert dort per Konstruktion nicht.
    Begründung ist also nicht „gemessen besser", sondern „stellt die Bedingung her, unter
    der die vorhandene Messung gilt". Erfolgskontrolle = der WARTEN-Anteil: er muss
    sich Richtung der gemessenen ~43 % bewegen (Abfrage s. Tabelle oben).
    Nicht behoben (bewusst): der 0,0-Einbruch des Scores bei Überdehnung selbst —
    das wäre eine Änderung der TF-Bewertung und damit messpflichtig. Fix 2 halbiert das
    Churning, verhindert aber nicht den ersten Absturz auf M30.
  • Timeframe: [trading] tf_select=heuristicengine._choose_tf wählt jede Minute die TF mit klarstem Trend aus dem Band [tf_min … tf_max] (leichter Höher-TF-Bias). Einstellung: tf_min=M5, tf_max=M30 (M1 raus: gemessen ~0 Edge; M30 zugelassen, damit der Bot in einem M30-Trend nicht festhängt, wenn M5/M15 gegen-Bouncen — sonst Patt: Long geblockt, Short fehlt). H1 bleibt nur Kontext (Filter/Konfluenz). Start-TF wird ins Band geklemmt. agent = LLM wählt; M1..H1 = fest. Der Agent steuert die TF nicht mehr.
  • Positionsgröße = margin-basiert 95 % (User-Vorgabe 2026-07-28, risk_pct=0, margin_buffer_pct=95): calc_lots setzt die Lots auf ~95 % der freien Margin. Verlauf 90→95→75→(1,5 % risiko, wenige Stunden am 2026-07-20)→80 %→95 % margin (2026-07-28) — der User hat die Margin-Wahl damit mehrfach bewusst getroffen (nicht ungefragt umstellen). ⚠ 95 % ist noch aggressiver als die 80 %-Referenz unten. ⚠ Aggressiv: der 95,48-€-Nacht-Trade 2026-07-20 (News-ATR → SL ~1,0 $ breit × 1,03 Margin-Lots ≈ 11 % Konto) ist der Referenzfall; mit risk_pct=1.5 wären es ~0,15 Lots / ~14 € gewesen (backtest_sizing.py: Margin-Sizing bis 36 % Quasi-Ruin, 12 % = 0 %). Risiko-Modus bleibt gebaut & abgesichert (Guards s. u.), Umschalten = risk_pct=1.5. Mechanik: trader._send_locked bestimmt erst den SL; bei risk_pct>0 → risiko-basiert (calc_lots_risk, Verlust ≈ risk_pct % Equity, Margin als Deckel) = der gemessene Fix gegen die Verlust-Asymmetrie. Umschalten via [trading] risk_pct (z. B. 1.5 = überlebbar).Risiko-Modus-Guards (Fix 2026-07-19): calc_lots_risk rundet NICHT mehr auf volume_min auf (unter Mindestlot → 0.0 statt still mehr Risiko), und _send_locked fällt bei risk_pct>0 NICHT mehr still auf Margin-Sizing zurück (75 % wäre ein Vielfaches des gewollten Risikos) — der Trade wird stattdessen mit Fehlermeldung abgelehnt. Bei risk_pct=0 (aktuell) unverändert margin-basiert. Harter Broker-SL immer mitgeschickt; adoptierte Fremd-Trades bekommen Schutz-SL.
    • Sizing-Simulation (backtest_sizing.py): 90 % Margin = Wachstums-optimal, ABER 36 % P(DD>80 %) = Ruin-Risiko. Risiko 12 %/Trade = überlebbar (0 % Quasi-Ruin). Exit-Asymmetrie gemessen backtest_exit2.py (Live-Exit Trail 1,5 ist OK; Problem war Sizing + manuelles Gewinner-Kappen, NICHT die Exit-Logik).
  • SL: Band 1,82,2×ATR (Ziel 2,0; INIT_SL_MIN/MAX_ATR). Breakeven ab +1,3×ATR (_BREAKEVEN_ATR; war 0,6 → 21 % Breakeven-Scratches, gemessen backtest_exit.py be: 1,3 = Plateau-Optimum → Scratch 5 %, Ø-R +15 %, kein Tail-Risiko). Früh-Ausstieg = AUS (_ADVERSE_EXIT_ATR=0). Trailing Init/Trail/Lock. Teil-Exit AUS (_PARTIAL_TP_FRAC=0, User-Vorgabe) → am TP wird der komplette Trade geschlossen (kein 50 %-Runner mehr).
    • Früh-Ausstieg NUR bei Trades OHNE Signal-Deckung = VERWORFEN (gemessen backtest_adverse_nosignal.py, 2026-07-23, Auslöser 57,34-€-Trade: manueller LONG gegen WARTEN, KEIN Squeeze/Signal-Flip beteiligt): Hypothese war, dass ein Adverse-Exit bei signal-ungedeckten Trades (Totband/WARTEN-Zone, B0 zeigt live 39 % WR dort) helfen könnte, auch wenn er pauschal auf ALLE Trades schadet. Fällt durch — bei JEDER Schwelle (0,5/0,75/1,0/1,5×ATR), in BEIDEN Populationen (SIG/ NOSIG), fast durchgehend in BEIDEN Hälften negativ (einzige Ausnahme: SIG H1 X=1,5 knapp +11 R, aber H2 dort 46). WR bricht von ~3843 % auf 1826 % ein — der Früh-Ausstieg kappt zwar einige Trades vor dem vollen SL, schneidet aber weit öfter Trades ab, die sich erholt hätten; NOSIG-H2 war ohne Eingriff sogar leicht profitabel (ΣR +80, PF 1,15) und wird durch jede Adverse-Schwelle verschlechtert. Hypothese „schwächere Population profitiert eher" widerlegt. Keine Änderung.
    • Trailing-Optimierung geprüft = KEINE Änderung (gemessen, backtest_trailing.py, 2 Halbjahre, echte Phasen-Sim): Die Live-Config (_TRAIL_START_ATR=0,3 · mult 1,5 M5 · Breakeven 1,3) hat die beste Verlustseite (bestes H1, Worst nur 1,5×ATR). Trailing trägt klar: ohne Trailing ΣR 1313/Worst 2,0 vs. Live +1777/ Worst 1,5 (~+3000 R und kleinerer Einzelverlust). Breiter ziehen (mult 2,02,5) oder Trail später starten (0,3→1,0) macht H1 schlechter/Worst größer; der frühe Trail-Start ist netto schützend (holt „läuft-schief"-Trades billiger raus). Einzige mithaltende Variante (start0,6) kippte zwischen den Läufen = Rauschen. → Ausschütteln ist Varianz, nicht Logikfehler.
    • Time-Stop (AKTIV, gemessen backtest_timestop.py): Position wird geschlossen, wenn sie nach 120 min noch in Phase „Init" hängt (HW-Profit nie ≥0,3×ATR = Whipsaw-Opfer; trailing._TIMESTOP_MIN=120, 0=aus, closed_by=timestop). Verbessert BEIDE Hälften (H1 +98→+162, H2 +2191→+2298 R), Worst unverändert; kürzere Fenster (30/60 min) kippten zwischen den Hälften = Rauschen. Dank Phasen-Ratsche ist „Init nach 2 h" exakt „nie Trail-Start erreicht".
    • ATR-Floor 0,12→0,06 gesenkt (gemessen, backtest_atrfloor.py, 2 Halbjahre): Die reale Vola fiel unter den alten Floor (H1: 81 % der Signale ATR<0,12 → Floor band dauernd, Exit-Distanzen künstlich ~1,31,6× breit, dazu ~35k Log-Warnungen je 5-MB-Rotation). Floor 0,06 in beiden Hälften besser (H1 153→−27 Pts, H2 +512→+554); ganz ohne Floor nur marginal besser → 0,06 als Schutz behalten. Floor-Warnung jetzt gedrosselt (max. 1×/5 min).
    • Befund B — umgesetzt (Exit-Simulation backtest_exit.py, Doku docs/exit-simulation.md): altes Band 1,21,5 war zu eng (MAE ~1,7×ATR, 3137 % Frühstopps). 2,0×ATR hebt Ø-R +32 %, PF 1,33→1,39, Frühstopps →25 %, Worst-Case auf 2,0×ATR gedeckelt. Breiter (34×ATR) wäre im Schnitt noch besser, aber Tail-/Drawdown-Risiko → verworfen. ⚠ Da Sizing margin-basiert (90 %, nicht risiko-basiert), schlägt die SL-Breite voll auf den EUR-Verlust durch. Qualität-abhängiger SL NICHT belegt (MAE über alle Buckets gleich).
    • S/R-Close (am Level schließen) = pauschal 2× VERWORFEN, als GEMESSENES Segment aber AKTIV: Pauschal (backtest_srclose.py, Echtkosten, 79k Signale) verdoppelt Close@Level die WR (35→67 %), verschlechtert aber PF/ΣR in BEIDEN Hälften (0,78→0,67 · 0,88→0,76) = Gewinner-Kappen. ABER (backtest_srbreak.py, 47k Touches, User-Idee „P(Durchbruch)>60 % → laufen lassen"): Basisrate P(break)=3637 %; das Anlauf-Momentum trennt robust in beiden Hälften — Kurs KRIECHT ans Level (letzte 6 Bars <0,3×ATR) → P(break) nur 26 %, Close schlägt Laufenlassen Ø +0,12 R; mit Schwung (≥0,3) → laufen lassen (4143 %). Volumen/Touch-Zahl trennen NICHT robust.
    • Kalibriertes P(Durchbruch)-Modell (2026-07-13, analyze_srwaves.py + backtest_srclose_prob.py): Containment-Befund — ~68 % der Wellen erreichen das gegenüberliegende Level, davon brechen nur ~37 % durch → ~63 % prallen ab (robust beide Hälften). P(break) ist vorhersagbar & kalibriert: Logit auf 4 Merkmalen (Anlauf-Momentum 6/3 Bars ·d, mit-Trend, Level-Distanz), auf H1 trainiert, auf H2 AUC 0,71 + Kalibrierung trifft (pred 17→21 %, 49→50 %, 69→76 %). Dominant = 3-Bar-Beschleunigung (_PB_W mom3 +0,78). R-Ertrag (Echtkosten): Regel „close wenn P(break) < X" schlägt reines Trailing in BEIDEN Hälften massiv (+6000/+7600 R); User-Schwelle 0,60 im Optimum-Plateau (0,500,60 ~gleich), validiert. ⚠ Impliziert Strategiewechsel: ~90 % der Level-Touches werden geschlossen (Trendfolger→Level-Scalper) — trägt, weil echte Kosten (0,265× ATR) + 63 % Containment das Laufenlassen teuer machen.
    • S/R-Close SIGNAL-gegated („bei mit-Trend halten statt schließen") = VERWORFEN (gemessen backtest_srclose_signal.py, 2026-07-22, User-Idee): Vorschlag war, den S/R-Close zu unterdrücken, solange die Empfehlung noch in Trade-Richtung zeigt (halten bis WARTEN). Fällt klar durch — in BEIDEN Hälften ~5300…−5700 R schlechter als der reine P(break)-Close. Grund/Datenbeleg: ~85 % ALLER Level- Touches passieren, WÄHREND die (nachlaufende) EMA noch „in Richtung" zeigt (23,8k/20,1k von 27,8k/26,2k Touches) — genau dort HÄLT das Level aber. Diese Touches geschlossen = ΣR +11703/+13606, geHALTEN = nur +5978/+8347. Die Trend-Empfehlung lagt → sie „bestätigt" ausgerechnet am Abpraller. Das kalibrierte P(break)-Modell (hat „mit-Trend" als Merkmal) macht das schon richtig; es mit dem groben EMA-Signal zu übersteuern kostet ~⅔ des S/R-Close-Edges. 12. verworfener Signal-Eingriff.
    • ⚠⚠ AUTO-FLIP-CLOSE = TROTZ NEGATIVER MESSUNG GEBAUT (User-Vorgabe 2026-07-31 „schließe den Trade automatisch beim Close-Signal"), [trading] auto_flip_close=true, auto_flip_close_min_r=0.5. Dreht die Empfehlung GEGEN die offene Position und steht sie ≥0,5×ATR im Plus → trader.close(reason="flip_close"). NEU GEMESSEN mit dem ECHTEN Exit (backtest_flipclose2.py, 80k M5, 2 Halbjahre, Echtkosten, Exit aus core/exit_model.py) — bestätigt das alte Urteil, deutlicher:
      Variante Δ H1 Δ H2
      Flip ab 0,0×ATR 126 221
      Flip ab 0,3×ATR 77 216
      Flip ab 0,5×ATR 92 160 ← mildeste, deshalb Default
      Flip auch im Minus 205 364
      Basis ohne Flip: H1 ΣR 537 · H2 140. **JEDE Variante ist in BEIDEN Hälften
      schlechter.** Mechanik: Trefferquote steigt 39 → 45 %, Ertrag fällt =
      Gewinner-Kappen (die nachlaufende EMA dreht oft mitten im Pullback).
      Warum überhaupt neu gemessen: das alte backtest_flipclose.py nutzte ein
      VIERTES Exit-Modell (Trail fest 1,5 · KEINE Lock-Phase · KEIN Time-Stop ·
      KEIN Initial-TP · _MAXH 288 · Phasen über den Bar-Close statt über das
      High-Water) — auf dieser Grundlage wäre das Urteil für den Live-Betrieb nicht
      bindend gewesen. Für die Neumessung bekam exit_model.simulate() einen
      stop_when-Hook (+ ret_bar), damit die Phasen-Mechanik NICHT wieder kopiert
      werden musste; Rückwärtskompatibilität verifiziert (ohne Hook bitgenau identisch).
      **NACHRANG gegenüber dem S/R-Close (gemessen backtest_exit_combo.py,
      2026-07-31, auto_flip_close_subordinate=true):** Beide Exits konkurrieren um
      dieselben Trades — wer zuerst feuert, gewinnt. Die S/R-Freigabe lief OHNE
      Flip-Close, die Baseline existierte also nach dem Einbau nicht mehr. Gemessen auf
      IDENTISCHEN Entries (5 Varianten, 2 Halbjahre, Echtkosten, Exit-Kern):
      Variante Δ H1 Δ H2
      --- --- ---
      nur S/R-Close +59 14
      nur Flip-Close 1 43
      BEIDE +56 50
      BEIDE, Flip nachrangig +62 49
      Kollision belegt: der Flip nahm dem S/R-Close 28 bzw. 32 Trades weg (511 %) —
      genau die, für die dieser validiert ist. Mit Nachrang ist es in BEIDEN Hälften
      besser als ohne. Umsetzung: liegt ein S/R-ZIEL ≤0,6×ATR entfernt (dieselbe
      Schwelle wie der Live-Hinweis), hält der Flip sich zurück. Mit 4 Szenarien
      getestet (in/außer Reichweite · kein Level · Nachrang aus).
      Ehrlich dazu: auch MIT Nachrang kostet der Flip in H2 rund 35 R gegenüber
      „nur S/R-Close" (49 vs 14). Der Nachrang begrenzt den Schaden, er dreht ihn
      nicht um. Abschalten des Features bleibt auto_flip_close=false.
      Methodik-Fehler beim Bau, korrigiert: der erste Lauf ließ die sequentielle
      Sim nach dem Exit bei xb+1 weiterlaufen — dadurch hatte JEDE Variante eine
      ANDERE Trade-Folge (sobald eine früher aussteigt, verschiebt sich alles
      Nachfolgende) und die Zahlen waren nicht vergleichbar. Jetzt feste, geteilte
      Entry-Liste wie in backtest_pbreak_rvalue.py.
      Umsetzung engine._check_flip_close im _pos_loop: nur im PLUS, 1× je Ticket,
      Startup-Schonfrist beachtet, Log 🔄 + Telegram, Snapshot flip_close/
      flip_close_min_r/flip_close_count. Mit 10 synthetischen Szenarien getestet
      (beide Richtungen · aus · unter Schwelle · gleichgerichtet · WARTEN · im Minus ·
      flat · Schonfrist · Ticket-Dedup). Der Alarm (Blinken/Ton/Telegram) bleibt
      unabhängig davon. **B4/B5-Pflicht: Live-Ertrag gegen die Erwartung halten —
      driftet es weg, auto_flip_close=false.**
    • Auto-Flip-Close = VERWORFEN (gemessen backtest_flipclose.py, 2 Halbjahre, sequentielle 1-Positions-Sim, 2026-07-16): User-Taktik-Kern „Position im Plus automatisch schließen, wenn die Empfehlung dreht" (heute nur Alarm). KEINE Variante (minR 0/0,3/0,5×ATR, auch-im-Minus) hält in beiden Hälften ØR & ΣR ≥ Basis: H1 ΣR 278→−280…−417, H2 +174→+119…+144 (kostet 1732 % des Ertrags). Mechanik: WR steigt 43→50 %, Ø-Gewinn schrumpft = Gewinner-Kappen — die nachlaufende EMA dreht oft mitten im Pullback, der Trade wäre weitergelaufen. Flip bleibt Alarm + menschliche Entscheidung (User-Übersteuerungen 68 % WR). Der Rest der User-Taktik (Ziel=nächstes S/R, weiterlaufen wenn stark) IST der P(break)-Auto-Close; der „3 %-Margin-Anker" = EUR-Schwelle, Klasse „verliert".
    • Mindestgewinn für den S/R-Close = VERWORFEN (gemessen backtest_srclose_prob.py, Mindestgewinn-Sektion): „nur closen wenn ≥minR im Plus" verliert monoton in BEIDEN Hälften (minR 0,2: 444/213 · 0,5: 1425/854 R vs minR=0). Die vielen kleinen Gewinne SIND der Edge — übersprungene Klein-Closes prallen am (haltenden!) Level ab und enden schlechter. Kleine EUR-Beträge = Positionsgröße, kein Exit-Thema. 2 Halbjahre, Echtkosten):** LONG an Support / SHORT an Resistance, gegated mit P(Level hält), Ziel = Gegenlevel — verliert in BEIDEN Hälften (FIX H1 3393/ H2 2242, +Trailing/-nur-Trailing ebenso negativ; WR 4653 %, PF<1). Asymmetrie: P(break) taugt zum EXIT (Trade schon mit-Trend im Plus am Gegenlevel → kassieren), nicht zum ENTRY (antizyklisch am Extrem = Münzwurf-Richtung, 6× belegt). Einstieg bleibt mit-Trend (Pullback). Trailing bleibt — nicht mehr Standard-Exit (das ist der S/R-Close), aber Manager für die ~10 % Durchbruch-Runner (P≥Schwelle) + Fallback für Trades ohne erreichbares Gegenlevel.
    • Umsetzung: engine._p_break(mom6,mom3,wt,dist) (eingebettete _PB_MU/SD/W); wave_rec.snapshot liefert pb_feats {mom6, mom3, ema_diff, atr} — FEST aus M5 (aus dem ~15-s-Turn-Fetch gecacht, ATR-Floor 0,12 wie im Training). ⚠ Bugfix 2026-07-13: vorher kamen die Features aus der Wave-TF (Heuristik bis M30 → mom6 war 3-h- statt 30-min-Momentum, ATR 23× → P falsch skaliert) und das Level aus dem Misch-Set _sr_levels (Zonen/Gaps/Tageslevel). 2. Bugfix gleicher Tag: die M15-Cluster-Level (market.sr, SR_MIN_TOUCHES) sind in frischen Trends oft LEER → Hint verschwand komplett. Jetzt trainingsgleiche Level: wave.pb_levels = rohe M5-Pivots (k=3, ~300 Bars) aus dem Turn-Fetch (M5 dafür 320 Bars tief), Highs in _m5_hl gecacht. Am Rally-Hoch gibt es für LONGs korrekt KEIN Gegenlevel → kein Hint (nichts zu closen). ⚠ 3. Bugfix 2026-07-15: das Close-Level kommt jetzt aus _draw_levels (dieselbe geclusterte+Hysterese-Linie wie Chart & Dashboard) statt aus den rohen pb_levels — sonst feuerte die Meldung an einem anderen Level als die gezeichnete Linie (User: „passt nicht zusammen"). P(break)- Features (M5) unverändert, nur level/dist verschieben sich um Cents. _sr_close_hint (Anzeige ≠ Auslösung, Fix 2026-07-14 — das 0,15×ATR_M5-Fenster ≈ 0,03 $ war als reine Anzeige unsichtbar klein): Hinweis erscheint ab ≤0,6×ATR Annäherung (blaue „nähert sich"- Vorwarnung mit Live-P(break) + gap_atr); Auslösung close=true nur AM Level (≤0,15×ATR = gemessener Touch) und p_break < [trading] sr_close_pbreak (Code-Default 0,60, Band 0,300,90; ini seit 2026-07-24 = 0,55 auf User-Wunsch — liegt im validierten Optimum-Plateau 0,500,60, Hysterese-Zone damit 50/60). Snapshot sr_close_hint {level, p_break, at_level, gap_atr, close, confirm}. Hinweis existiert NUR mit offener Position. confirm = Bruch-BESTÄTIGUNGS-Preis (Fix 2026-07-22, User-Frage nach einem Trade, der am Level geschlossen wurde, obwohl der Kurs „durchgebrochen" war): level ± 0,5×ATR in Trade-Richtung — dieselbe Definition wie beim Modell- TRAINING (_BRK_ATR=0,5/_BRK_W=12 in backtest_srclose_prob.py/ analyze_srwaves.py). Ein Docht, der die nackte Levelzahl nur um wenige Cent überschreitet, zählt NICHT als Durchbruch — reales Fallbeispiel 2026-07-22: Close bei Level 85,943 (P(break) 31 %), Kurs wischte auf 85,994 (< Bestätigung 86,017 = Level+0,5×ATR) und fiel zurück → nach Modell-eigener Definition eine ABLEHNUNG, keine Bestätigung; die Vorhersage war korrekt. confirm jetzt in der Log-Zeile („— Bestätigung erst ab X") UND im Frontend-Hinweistext (#pos-srhint, alle 3 Zweige: Vorwarnung/Close/Laufen) sichtbar — macht den Unterschied „Kurs > Levelzahl" vs. „strukturell bestätigter Bruch" auf einen Blick klar. Live-Prognose-Tracking (2026-07-23, User-Wunsch „mitloggen wie oft richtig/ falsch"): jeder frische Level-Touch (at_level False→True) loggt EINMAL die aktuelle Vorhersage (bounce wenn P(break)<Schwelle, sonst break) in die neue Tabelle pbreak_predictions (history.log_pbreak_prediction, Felder u. a. predicted, confirm_price, reject_price, atr). Auswertung läuft separat, self-throttled ~5 min im _trend_loop (engine._evaluate_pbreak_predictions): prüft gegen candles_m1, ob der Kurs binnen 60 min zuerst confirm_price (→ outcome break) oder reject_price (→ bounce) erreicht — exakt dieselbe Definition wie beim Modell-TRAINING (_BRK_ATR=0,5/_BRK_W=12 M5-Bars=60 min). Kein Treffer binnen 60 min → Timeout, zählt wie im Training als bounce. correct = predicted==outcome. Broker-Zeit-Offset (trader._broker_offset_s()) korrekt berücksichtigt (pbreak_predictions.ts = lokale Epoch, candles_m1.time = rohe Broker-Zeit — Ausnahme, s. „Auch beachten"). Abfrage: history.pbreak_accuracy (period) bzw. GET /api/pbreak_accuracy?period=today|week|all (read-only, kein Token) → {n, accuracy, break_accuracy, bounce_accuracy, pending, …}. Getestet mit synthetischen Szenarien (break/bounce/Gegenteil-falsch/Timeout) — alle 4 exakt wie erwartet. Reine Messung, kein Signal-/Exit-Eingriff — noch keine UI-Karte (Datensammlung; B4-artige Auswertung später möglich, wenn genug Zeilen vorliegen). Gegen-/Stop-Seiten-Anzeige stop_approach (2026-07-24, User-Frage „Kurs nähert sich Support, aber keine Durchbruchwahrscheinlichkeit angezeigt"): Der reguläre sr_close_hint beobachtet nur das Ziel-Level (LONG→Resistance, SHORT→Support) und wirkt nur im Plus — nähert sich der Kurs dem Gegen-/Stop-Level (LONG→Support darunter, SHORT→Resistance darüber, typ. Verlust-Trade), war die App bewusst still. Neu: engine._stop_approach_hint liefert für GENAU dieses Level eine reine Anzeige von P(Durchbruch) — Break-Richtung -d (gegen den Trade), Feature-/ 60-s-Glättung (_stop_pb_state) identisch zu _sr_close_hint. KEIN Auto-Close. Snapshot stop_approach {level, side, p_break, at_level, gap_atr, confirm, reject}, Frontend #pos-stophint (grün „Level hält wahrscheinlich" bei P<50, rot „bricht wahrscheinlich durch" bei ≥50; nur wenn KEIN Ziel-sr_close_hint läuft; v=109). Vorher gemessen (backtest_pbreak_calibration.py, 2026-07-24, Gate „erst messen, dann bauen"): Das kalibrierte P(break)-Modell (auf Ziel-Seite trainiert) hält auch auf der Gegen-/Stop-Seite — AUC 0,68/0,72 out-of-sample in BEIDEN Hälften (≈ Ziel-Seite 0,67/0,71), im niedrigen P-Bereich sauber kalibriert (der praktisch wichtige „hält der Support?"-Fall). ⚠ Einzige Schwäche: im HOHEN Bereich (P≥0,5) GEGEN den Trend unterschätzt es die Bruch-Rate ~1013 Pp (predicted 58 % → echt 71 %) — also konservativ (warnt eher zu wenig vor einem Bruch), kein Kalibrierungs-Bruch. Deshalb reine Anzeige, kein Trade-Trigger. Anti-Flattern (2026-07-14, gemessen analyze_pbreak_flicker.py: mom3 der laufenden M5-Kerze ließ P 715 Pp/Bar springen, Max 77 Pp; 8 % der Annäherungen hatten ≥2 Schwellen-Flips): (1) P zeit-geglättet (~60-s-EMA in _pb_state, Reset bei Level-Wechsel/flat; angezeigtes p_break = geglättet) · (2) Hysterese ±5 Pp um die Schwelle — close↔laufen wechselt erst bei klarem Durchbruch (55/65 bei Default 0,60, liegt im Optimum-Plateau 0,500,60). Dashboard-Schalter in der Position-Kachel (#srclose-btn, grün=AN) → POST /api/srclose (Toggle, engine.set_sr_autoclose); Zustand snapshot.auto_sr_close. AUTO-Close (_check_sr_close im _pos_loop, auto_sr_close=true): schließt nur im PLUS (pnl>0) wenn close=True, 1×/ Ticket, wirkt bei gesperrtem Handy. Optionaler Mindestgewinn ([trading] sr_close_min_gain Default 0=aus · UI #srmin-input · POST /api/srclose_min · set_sr_close_min_gain · Snapshot sr_close_min_gain): unter der EUR-Schwelle wird am Level NICHT geschlossen. ⚠ Gemessen ist OHNE besser (Verworfen-Eintrag) — Opt-in auf User-Wunsch, UI-Status warnt. Automatisch auf X % des Einsatzes ([trading] sr_close_min_gain_pct) — Stand 2026-07-29 wieder AUS (=0, User-Wunsch „gewinn close und notfall stop wieder auf leer beim Eröffnen") (Verlauf: 1,0→3,0 am 07-23 · 0 am 07-24 früh „nichts beim Öffnen setzen" · 3,0 am 07-24 abends zurück · 0 am 07-29 — gilt NUR für den Gewinn-Close, der Auto-Notfall-Stop bleibt AUS). Bei pct>0 wird bei JEDER echt neuen Position (nicht beim Wiedererkennen nach Neustart) sr_close_min_gain frisch auf pct% × Margin dieser Position gesetzt (_check_auto_close, retry-sicher via _sr_close_min_gain_armed_ticket — Margin aus trader.refresh() im selben _pos_loop-Tick, jeden Tick erneut versucht bis Margin>0; persistiert via _save_runtime_state, Log „Gewinn-Close armiert … +X (N% Margin Y)"). Bei pct=0 wird beim Öffnen NICHTS gesetzt — dann bleibt der manuell im UI gesetzte/gemerkte sr_close_min_gain maßgeblich. ⚠ Umstellen auf 0 braucht Neustart: _sr_close_ min_gain_pct lebt im Speicher; solange der alte Wert (3,0) läuft, re-armt JEDER neue Trade erneut — die ini-Änderung greift erst nach restart_server.bat. Beim 0-Stellen zusätzlich den persistierten Alt-Wert in runtime_state.json nullen (sr_close_min_gain) UND emergency_state.json loss (Erb-Falle, sonst restauriert der Neustart den Alt-Wert). Gate verifiziert (2026-07-23, User-Nachfrage „darf nicht schließen bevor der Wert erreicht wurde"): _check_sr_close prüft pnl < sr_close_min_gain → return bevor _sr_close_hint/trader.close überhaupt aufgerufen werden — isoliert mit 6 synthetischen Szenarien getestet (unter/exakt-auf/über Schwelle, P(break) hoch trotz Profit, Schwelle aus, Verlust-Trade) → alle korrekt. Dabei echten Bug gefunden & gefixt: die 1%-Berechnung lief nur EINMALIG beim Ticket-Wechsel (if ticket != self._last_pos_ticket); war order_calc_margin genau in diesem einen Tick 0/nicht verfügbar (Broker-Race direkt nach Order-Fill), blieb sr_close_min_gain für die GESAMTE Laufzeit der Position auf dem STALEN Wert der vorherigen Position hängen (der Ticket-Wechsel-Zweig feuert nur 1×, keine zweite Chance) — im ungünstigen Fall ein zu NIEDRIGER Alt-Wert, der den Trade dann exakt zu früh schließt. Fix: neuer State _sr_close_min_gain_armed_ticket (getrennt vom Notfall-Stop/TP-Restore-Zweig) — die %-Berechnung läuft jetzt JEDEN _pos_loop-Tick erneut, bis sie für das aktuelle Ticket einmal erfolgreich war (Margin>0), statt nur im Ticket-Wechsel-Moment. Wiederhergestellte Positionen nach Neustart markieren sich sofort als „armiert" (kein Überschreiben des persistierten Werts) — mit Test verifiziert. Log 🎯 S/R-AUTO-CLOSE + Telegram + Toast (sr_close_count), closed_by=sr_close. UI Position-Kachel: bernstein „Durchbruch nur X% → Bot schließt" bzw. grün „Durchbruch X% wahrscheinlich → läuft weiter". Abschalten auto_sr_close=false / set_sr_autoclose(False); Schwelle via sr_close_pbreak. Kein pauschaler S/R-Close (2× verworfen) — nur mit P(break)-Gate.
    • S/R-verankertes TRAILING = GEMESSEN, NICHT gebaut (backtest_trailing_sr.py, 2026-07-31, User-Idee „Trailing TP und SL auf die S/R-Linien anpassen"): Die Idee zerfällt in drei Teile — Initial-SL an S/R (schon verworfen, s. u.), fester TP am Gegenlevel (schon 2× verworfen, backtest_srclose.py) und Trailing-SL ans Level nachziehen = der einzig offene Teil (bisher wurden nur ATR-Abstände variiert). Aufbau identisch zu backtest_trailing.py (echte Phasen-Mechanik, Breakeven 1,3), Level = M30-Pivots k=3, kausal (Pivot erst 3 M30-Bars später bekannt), Deckel [0,5…2,0]×ATR gegen den 11,4×ATR-Fall; 80k Bars, ~19,7k Signale je Hälfte. Ergebnis: schadet nicht, trägt aber zu wenig. Basis (ATR-Trail 1,5) H1 0,020 / H2 +0,064; 3 von 5 Varianten schlagen sie in BEIDEN Hälften (Puffer 0,10: +0,009/+0,004 · Puffer 0,50: +0,003/+0,014 · Hybrid „engerer von beiden": +0,006/+0,006, WR 37→43 % bzw. 40→43 %). Trotzdem nicht gebaut, zwei Gründe: (a) Effektgröße 0,0060,014 R/Trade = eine Größenordnung unter der B3-Hürde (~0,1×ATR netto); (b) nicht parameter-robust — Puffer 0,10 besteht, 0,25 fällt durch (H1 0,023), 0,50 besteht wieder; ein Parameter, dessen Nachbar das Vorzeichen kippt, ist Rauschen (dasselbe Kriterium, an dem ORB und die SMC-Sweeps starben — beim Squeeze waren ALLE 8 Kombis positiv). Positiv-Befund: der Worst-Case bleibt in ALLEN Varianten 2,00×ATR — der Deckel funktioniert, S/R-Verankerung fügt kein Tail-Risiko hinzu (das war die Sorge aus backtest_sl_method.py). ⚠ Die KONTROLLVARIANTE „TP am Gegenlevel" reproduziert den alten Befund exakt (WR 40→54 %, ΣR H2 +1261→+740 = Gewinner-Kappen) — damit ist die Simulation gegen backtest_srclose.py validiert und der TP-Teil endgültig erledigt. NACHTEST auf NUR Squeeze-Entries (--squeeze, 2026-07-31, Echtkosten): ERLEDIGT — dort ist der S/R-Trail nicht nur zu klein, sondern klar SCHLECHTER. Basis H1 +0,102/H2 +0,108; keine einzige Variante besteht (S/R 0,10: +0,096/+0,093 · 0,25: +0,083/+0,098 · 0,50: +0,052/+0,092 · Hybrid: +0,093/+0,122 = kippt · Hybrid weit: +0,091/+0,084). Anders als im Wave-Lauf ist das kein Rauschen: der reine S/R-Trail wird monoton schlechter, je breiter der Puffer (in BEIDEN Hälften) — sauberer monotoner Verlauf, nur gegen die Idee. Mechanismus: der Squeeze lebt von wenigen Läufern (43 % Treffer, Ertrag im Tail); ein an das nächstgelegene Level gebundener Stop holt genau dort raus, wo der Lauf beginnt. Bei Wave-Signalen fällt das kaum auf (selten große Runner) — daher das umgekehrte Vorzeichen zwischen beiden Läufen. ⚠ Stärkster Gewinner-Kappen-Beleg des Projekts: die Kontrollvariante (fester TP am Gegenlevel) dreht den Squeeze von +0,102/+0,108 auf 0,066/0,004 = Edge vollständig zerstört. ⚠ Abgrenzung gegen den laufenden S/R-Auto-Close: der ist P(break)-gegated (schließt nur, wenn das Level wahrscheinlich HÄLT) und war auf Squeeze-Trades separat gemessen ein Wash (backtest_squeeze_srclose.py, +0,190→+0,224 / +0,394→+0,377). Das Gate ist der Unterschied zwischen „Wash" und „Edge zerstört" — ein ungegateter Level-TP ist etwas grundlegend anderes. Damit ist die User-Idee in allen DREI Teilen durchgemessen; der Live-Exit-Stack bleibt unverändert.
    • S/R-verankerter SL = KEIN Edge (gemessen, backtest_sl_method.py): Pivot+Band vs. „S/R ∓ ATR/0,10-Puffer" vs. fest 2,0×ATR — gedeckelt alle identisch (Ø-R 0,1960,201, PF 1,381,39, Worst 2,2×ATR): der Band-Cap [1,82,2]×ATR dominiert, die Verankerung ist Rauschen. Nur ungedeckelt sieht S/R besser aus (Ø-R 0,249) — aber Worst-Case 11,4×ATR (Kontokiller bei 90 %-Sizing) → verworfen. Aktuelle SL-Logik bleibt.
    • SL-ATR-Timeframe bei Squeeze-Trades (M5-Signal, aber SL_TF fix M15) = GEPRÜFT, KEINE Änderung (gemessen backtest_sl_tf_mismatch.py, 2026-07-23, Auslöser 89,36-€-Nacht-Trade): _calc_sl_tp sizt den Initial-SL IMMER aus M15-ATR, unabhängig vom Signal-TF — bei Squeeze (M5-Signal) kann das stark divergieren (real: M5-ATR fiel 0,29→0,10 — genau die Kompression, die den Squeeze auslöste — während M15-ATR noch bei ~0,36 lag → SL 0,787 statt ~0,22 bei M5-Sizing). Der validierte Squeeze-Backtest (backtest_breakout_squeeze.py) nutzt durchgehend M5-ATR für den SL — Live weicht hier vom Backtest ab. 2-Stichproben-Test der Umstellung auf M5-ATR-SL bei Squeeze-Trades: GEMISCHT — H1 leicht besser (ØR +0,167 vs +0,064, ΣR +35 vs +13), H2 (größere, aktuellere Stichprobe) klar SCHLECHTER (WR 51 % vs 59 %, ΣR +281 vs +323) → fällt nach der beidhälftig- robust-Regel durch. Der breitere M15-SL kassiert gelegentlich einen vollen Verlust wie diese Nacht, verhindert aber mehr vorzeitige Ausstoppungen bei normalen Rücksetzern — netto vorteilhaft. Keine Änderung.
  • Inter-Market (Brent-Bestätigung / DXY-Gegenwind) = VERWORFEN (gemessen backtest_intermarket.py, 2026-07-19, letzte ungetestete Indikator-Klasse): 1366 Trades, seq. Sim, Live-Exit, Echtkosten, 2 Halbjahre; Buckets nach Zustand am Entry (Symbole: SpotBrent, USDX). Beide Hypothesen kippen zwischen den Hälften: (A) Brent-Trend dagegen H1 0,002 vs H2 0,187 (H1 sogar BESSER als „dafür"!), Brent-Mom-1h dagegen H1 +0,311/H2 0,233 = Flip; (B) DXY-Gegenwind H1 0,13…−0,19 (schlechter, wie vermutet) aber H2 +0,13…+0,17 = BESSER als Rückenwind — komplett invertiert, klassische Regime-Abhängigkeit (wie H1-Stärke- Filter/Momentum). Einzig Brent-Mom-3h ist richtungs-konsistent, aber winzig (Δ~0,060,14) und die Schwester-Varianten kippen → nach der vorab festgelegten Verdict-Regel (beide Hälften UND Varianten-robust) kein Einbau. Damit ist auch die letzte orthogonale Indikator-Klasse durch: am Signal ist nichts mehr zu holen — Hebel bleiben Sizing/Exit/Verhalten (nicht gegen das Signal handeln: live gemessen 39 % WR / 166 € vs. mit 55 % / +65 €). backtest_confluence.py — MACD/ADX-Richtung praktisch neutral, ADX-Stärke leicht negativ, ein MACD+ADX-Gate senkt den Edge (78 % Trades). RSI bestätigend ist kontraproduktiv (RSI gegen Richtung = doppelter Edge = der Pullback-Effekt, den der „ tiefer Pullback"-Bonus schon nutzt). Standard-Oszillatoren also nicht draufsatteln. Mehrquellen-Redundanz läuft bereits über die Gesamtempfehlung.
  • TradersUnion (TU) aus der Empfehlung ENTFERNT (User-Vorgabe 2026-07-06): TU ist Standard-Indikator-Konsens (MA/Oszillator-Ratings einer Website) — dieselbe Klasse wie MACD/ADX/RSI = kein Edge, plus Latenz (5m „Strong Buy" während 4h/1d „Strong Sell") und nicht backtestbar (Live-Scrape, keine History). Floss vorher als Konfidenz-Faktor (_tu_check ±6/8 je 5m/15m) UND als Verdict-Stimme ein — beides neutralisiert (wave_rec._build zieht _tu_check nicht mehr; _verdict ohne TU-Vote). ⚠ Nebenbefund: der Konfidenz-Pfad hatte keinen _STALE_S-Check (nur trade_signal hatte ihn) — mit der Entfernung erledigt. TU bleibt reine Anzeige (Snapshot tu); _tu_check/_TU_* als Code erhalten (reaktivierbar). Fetch war auf 5 min gedrosselt (_TU_S=300); Loop seit 2026-07-19 ganz stillgelegt (_tu_loop nicht mehr in start() — TU ist aus Empfehlung/Verdict/Copilot raus UND die Kachel ausgeblendet, der Scrape lief für niemanden; reaktivieren = Loop wieder in die Liste). Elliott loggt nur noch bei Änderung (vorher ~6k identische Zeilen/Logrotation).
  • Order ohne Empfehlung = bestätigbarer HINWEIS, kein Block: Bei WARTEN/ Gegen-Signal zeigt das Frontend einen Bestätigungs-Dialog („… trotzdem eröffnen?") — bestätigen = Trade läuft, Abbrechen = kein Trade. Kein hartes Blockieren (überschreibbar). engine._open blockt nicht (loggt nur). ⚠ Log-Quellen-Attribution (Fix 2026-07-29): _open(fn, want, source) bekommt jetzt eine source (Default "manuell"); der Auto-Squeeze ruft open_long/short (source="auto_squeeze"). Vorher schrieb _open bei JEDEM Auftrag gegen die Empfehlung „— vom User bestätigt" — auch bei autonomen Squeeze-Entries (der User fragte, ob ein Trade auto/manuell war; die Zeile log fälschlich „User"). Jetzt: autonome Orders → „autonom vom Auto-Squeeze eröffnet", manuelle → wie bisher. Die 🚀 AUTO-SQUEEZE-ENTRY-Zeile bleibt die eindeutige Quelle der Wahrheit.
  • Entry-Checkliste im Order-Dialog (engine._entry_checklist, User-Vorgabe 2026-07-30 „blende einen Hinweis ein wenn die Checkliste gegen meine Eröffnung ist", v=120): Vor JEDER manuellen Eröffnung prüft der Server 7 Punkte mit LIVE-Daten und zeigt die verletzten im Bestätigungs-Dialog. Blockt nicht, macht aber sichtbar, was dagegen spricht — und zwar auch dann, wenn ein Signal vorliegt (der alte Dialog kam nur bei WARTEN/Gegen-Signal). Punkte: (1) Signal-Deckung (die gemessene Kern-Leckage), (2) HTF-Trend M30+H1 („nur mit dem HTF-Trend, niemals dagegen"), (3) Entry-Raum zum Gegenlevel (<0,6×ATR = gemessen negativ), (4) News-Konflikt (|Sentiment|≥0,5 gegen die Richtung), (5) Kosten (Spread/ATR, ab 0,32 = Kostenfalle), (6) Mental-Check: Verlust-Serie heute („nach 2 Losses Session beenden" — zeigt Anzahl, Tages-P&L und %-Anteil am Konto), (7) Nacht-Stunde 07 Uhr. verdict: stop (≥2 „fail") · warn · ok. Snapshot checklist {long, short} — nutzt nur bereits berechnete Snapshot-Teile; die DB-Abfrage für die Verlust-Serie ist ~120 s gecacht (_loss_streak_today). ⚠ Die Gewichtung ist NICHT backtest-optimiert, sondern aus den im Projekt gemessenen Leckagen + der User-Checkliste abgeleitet (Entscheidungshilfe, kein validiertes Signal). Real beim Einbau (30.07. abends): beide Richtungen stop — „keine Empfehlung" · „HTF unklar/dagegen" · „11 Verluste heute (261 € = 80 % des Kontos)".
  • Liquiditäts-Sweeps (SMC: Equal Highs/Lows, Swing Liquidity) = VERWORFEN (gemessen backtest_liquidity_sweep.py, 2026-07-30, User-Vorgabe mit Chart- Beispielen + WTI-Praxisregeln): Getestet, weil der Sweep (Fehlausbruch: Level kurz durchstochen, Close zurück in der Zone) eine ANDERE Mechanik ist als der schon verworfene Nackenlinien-Bruch (backtest_doubletop.py). Achsen: 3 Muster × Level-TF (M5/M30/H1, die „Liquidität auf höherem TF"-Regel) × 2 Exits × 2 Halbjahre, plus Session-Filter (NY 1416 / Asia 24 Uhr Berlin). Kernbefunde: (a) Der SMC-eigene Exit („Stop über dem Sweep-Docht, Ziel = Gegen-Liquidität") ist in ALLEN 9 Kombinationen negativ — die Lehre steht und fällt mit ihm, er trägt nicht; mit dem generischen Live-Trailing sieht dasselbe Setup besser aus (derselbe Exit-Artefakt wie bei backtest_patterns.py). (b) Equal Highs/Lows fallen fast überall durch (Vorzeichen kippt zwischen den Hälften). (c) Einziger Treffer: „Swing-Liquidity, M30-Level, Live-Exit" (+0,241/+0,358) — aber die Nachbar-TFs kippen (M5 0,152/+0,247 · H1 0,111/+0,692) = nicht parameter-robust, exakt das ORB-Muster von 2026-07-17. (d) Session-Filter: zu wenige Trades (n=331) für eine Aussage. Kein Einbau in die Gesamtempfehlung. 16. verworfener Signal- Eingriff. ⚠ Die DXY-Korrelations-Regel wurde bewusst NICHT erneut getestet — die Inter-Market-Klasse ist 2026-07-19 gemessen durchgefallen.
  • „Erst messen, dann umbauen": Strategie-Änderungen per Backtest belegen, nicht raten. Gegen-Trend verliert; nicht bei WARTEN handeln. Stichproben ~28 Tage — ein Trend-Regime; Befunde später auf mehr/andere History gegenprüfen.
  • Wave-Auto-Trader (Dry-Run) KOMPLETT ENTFERNT (2026-07-23, Code-Review-Fund): war seit Langem Verlierer (WR 29 % / PF 0,64) vs. manuelle Trades (WR 5676 %); UI-Toggle bereits vorher entfernt (Dashboard-Button steuert seitdem Auto-Squeeze), lief aber weiter dormant bei jedem Tick mit (toter Ballast). core/auto_trader.py gelöscht (Sicherung: .removed_backup/), engine.self.auto + alle 4 Aufrufstellen (_price_loop, _run_analysis, toggle_auto, Snapshot-Keys auto/min_conf) sowie die tote auto-Referenz in TradingAgent.__init__ entfernt, /api/auto gelöscht. min_conf (Frontend-Warnschwelle „Order ohne Signal") lebt jetzt als eigene Konstante _MIN_CONF_DISPLAY=70 in engine.py. Die intended_trades-DB- Tabelle + history.intended_*-Methoden bleiben (historische Daten, kein Schreiber mehr aktiv). Manuelles Handeln bleibt der validierte Edge auf dem Wave-Signal.
    • RE-TEST 2026-07-30 (User-Wunsch „Trades bei Empfehlung automatisch eröffnen") = ERNEUT VERWORFEN, gemessen backtest_auto_signal.py: Auto-Entry auf dem Wave- Signal mit den HEUTIGEN Gates, echte _build-Logik (kein Nachbau), M30-/H1-Trend aus M5 aggregiert und in _build gefüttert, sequentielle 1-Positions-Sim, Live-Exit (SL 2,0/Trail 1,5/BE 1,3/Time-Stop 120 min), Echtkosten (Bar-Spread/ATR), 80k M5-Bars in 2 Halbjahren. ALLE 8 Varianten fallen durch (Konf-Schwelle 55/65/70/75 × Nacht-Sperre an/aus): H1 durchgehend NEGATIV (ØR 0,076…−0,182, PF 0,780,90), H2 durchgehend positiv (+0,112…+0,167) → klassisches Regime-Kippen, n=7181167 je Hälfte (keine Stichproben-Frage). ⚠ Kontroll-Beleg, dass es am SIGNAL liegt und nicht an der Sim: der Squeeze läuft durch DIESELBE Exit-/Kosten-Maschinerie und ist in H1 +0,187/PF 1,29 — die Simulation funktioniert also, nur das Wave-Signal trägt in H1 nicht. Deckt sich exakt mit dem Live-Dry-Run (WR 29 %/PF 0,64). Nebenbefunde: (a) höhere Konfidenz hilft NICHT monoton (75 schlechter als 65) — bestätigt analyze_verdict_calibration.py (conf_pct ist NICHT kalibriert, in H2 invertiert), ein „nur bei hoher Konfidenz"-Auto-Entry ist damit auch erledigt; (b) die Nacht-Sperre verbessert konsistent (H1 0,172→−0,123), reicht aber nicht; (c) ⚠ Methodik-Lehre: ein Vorlauf mit nur 6k Bars zeigte „Konf≥65+Nacht TRÄGT" — der 80k-Lauf drehte das komplett (n war 6099/Hälfte = Rauschen). Kleine Stichprobe hätte hier zum Fehl- Einbau geführt. Warum manuelle „MIT Signal"-Trades trotzdem profitabel sind (+118 €/WR 56 %, analyze_entries-Auswertung 2026-07-30): menschliche AUSWAHL unter den Signalen (Kontext/Tageszeit/Marktlage), nicht „alle nehmen" — die Grundgesamtheit ALLER Signale ist der Verlierer. 14. verworfener Signal-Eingriff.
  • Auto-Signal-Entry = TROTZDEM GEBAUT auf ausdrücklichen User-Wunsch (2026-07-30, „probieren wir es trotzdem mal"), [trading] auto_signal, Default FALSE.Der Backtest direkt darüber sagt NEIN (H1 durchgehend negativ) — der User hat das nach vollständiger Information (inkl. Live-Dry-Run-Historie WR 29 %/PF 0,64) bewusst entschieden. Gebaut mit den gemessen BESTEN Parametern, nicht mit Default-Raten: auto_signal_min_conf=75 (mit Nacht-Sperre H1 0,053 = mildester Verlust, H2 +0,141 = bestes Netto; ⚠ NICHT weil „mehr Konfidenz besser" — conf_pct ist unkalibriert, 75 ist empirisch) und auto_signal_skip_night=true (verbessert JEDE Variante). Mechanik (engine._check_auto_signal im _pos_loop, 1 s, NACH den Close-Checks): eröffnet nur FLAT, nur bei wave.signal() LONG/SHORT mit conf_pct ≥ min_conf, 1× je Signal-Episode (Dedup _signal_last_sig, re-armt bei WARTEN/Flip — nicht über den Preis wie beim Squeeze, weil das Signal keine Level-Marke hat); erbt die Squeeze-Guards: Circuit-Breaker, Nacht-Sperre, S/R-Close-Cooldown, allgemeine Wiedereinstiegs-Sperre. Kein Nachkauf bei gleichgerichteter Position, kein Drehen einer Gegen-Position (unbelegt, wie Squeeze-Reverse). Log 🎯 AUTO-SIGNAL- ENTRY + Telegram, Setup-Tag AUTOSIG_<dir> (macht die Trades in der DB separierbar → B4-Monitor). Snapshot auto_signal/auto_signal_min_conf/signal_entry_count, Toggle POST /api/autosignal = Dashboard-Button 🎯 SIG (bernstein statt blau, weil gemessen nicht tragfähig; zeigt die Schwelle an), neustart-fest via runtime_state.json. B5-Pflicht: Live-ØR/PF gegen die Backtest-Erwartung halten (H2-Regime +0,14 vs H1-Regime 0,05) — driftet es weg, zurückbauen (=false).
  • 15-Minuten-Regel ([trading] adverse_15min_atr=0.5, AKTIV, User-Wunsch 2026-07-30 „wenn der Trade nach 15 Minuten gegen die Richtung läuft schließe ihn"): steht ein vom BOT eröffneter Trade 15 min nach Entry ≥ X×ATR_M5 gegen die Richtung → schließen (engine._check_adverse15, closed_by=adverse15, Log ⏱ + Telegram). ⚠ Schwelle GEMESSEN kalibriert, NICHT die ursprüngliche Vorgabe (backtest_auto_ signal.py, 15-Min-Achse): „sobald im Minus" (0,0) ist die SCHLECHTESTE Variante (WR bricht 39→31 %, Netto-ØR 0,067 vs +0,026 ohne Regel) — sie kappt Trades, die sich erholt hätten. 0,5×ATR ist die beste Regel-Variante (H1 0,111→−0,079). Netto über beide Hälften bringt die Regel ~nichts (+0,001 vs +0,026 ohne) → sie ist ein REGIME-Schutz (hilft im schlechten Regime, kostet im guten), bewusst als Sicherheit akzeptiert. 2. unabhängige Bestätigung von backtest_adverse_nosignal.py (dort fiel der Adverse-Exit bei JEDER Schwelle durch). Greift NICHT bei manuellen Trades (_bot_open_ticket-Marker — dort bleibt die Diskretion beim User, gemessen sein Vorteil) und nicht in der Startup-Schonfrist; 1× je Ticket geprüft (_adverse15_done_ticket) genau beim 15-min-Zeitpunkt. Snapshot adverse15_atr/ adverse15_count. 0 = aus. Mit 18 synthetischen Szenarien getestet (9 Entry: Konf-Gate, Dedup, WARTEN-Re-Arm, Nachkauf, Gegen-Position, Cooldown, Toggle, Nacht-Sperre · 9 Adverse: über/unter Schwelle, zu früh, im Plus, SHORT-Richtung, manueller Trade, aus, 1×-je-Ticket, Startup-Grace) — alle korrekt.
  • Auto-Squeeze-Entry = LIVE AUTONOM (User-Vorgabe 2026-07-16, [trading] auto_squeeze=true, Default FALSE): der Bot eröffnet selbständig eine echte Order, sobald der gemessen-validierte Squeeze-Ausbruch feuert (wave.squeeze. state=='active') UND flat ist — NICHT auf dem Wave-Signal (das ist der Dry-Run-Verlierer), sondern nur auf dem 2-Stichproben-positiven Squeeze. engine._check_auto_squeeze im _pos_loop (1 s): 1× je Ausbruch (Dedup über (dir, level); re-armt, wenn der Squeeze klärt), öffnet via open_long/short (→ Trailing an, Emergency-Stop armiert 2 % beim nächsten Tick), Log 🚀 AUTO-SQUEEZE- ENTRY + Telegram + Fehlschlag-Push. Snapshot auto_squeeze/squeeze_entry_count; Toggle POST /api/autosqueeze (set_auto_squeeze) = Dashboard-Button 🚀 BRK (blau=AN, ersetzt den alten Dry-Run-AUTO-Button). Dead-Hour-Guard = AN (User-Vorgabe 2026-07-24, [trading] auto_squeeze_skip_night=true): der Bot eröffnet nachts 07 Uhr KEINE Squeeze-Trades (_SQUEEZE_NIGHT=(0..7), _squeeze_skip_night_check_auto_squeeze return; kein Entry UND kein Reverse). Doppelt begründet: (1) gemessen unrentabel (backtest_realcosts.py, Spread÷Nacht- ATR 0,320,50×ATR, beide Halbjahre negativ = Kostenfalle) und (2) kein Trade soll unbeaufsichtigt nachts feuern, während der User schläft — Auslöser: „müsste automatisch schließen wenn ich nicht da bin, z. B. nachts". Der Guard LÖST das, indem er den Trade gar nicht erst öffnet; tagsüber (User eher erreichbar) läuft der bestehende Auto-Close-Stack (Broker-SL 2×ATR broker-seitig + Trailing + Time-Stop + S/R-Close). ⚠ Historie: bis 2026-07-17 war der Guard AUS (User wollte rund um die Uhr), am 2026-07-24 auf User-Wunsch zurück auf AN. =false schaltet ihn wieder aus (dann auch nachts, unbeaufsichtigt). Einen engen Schutz-%-Stop NUR für Squeeze wurde bewusst NICHT gebaut (enger %-Stop unter Margin-Sizing wird vom Squeeze- Rauschen ausgelöst, 48,94-€-Tag — der Squeeze braucht Raum). Stop-&-Reverse = AUS (Default, [trading] auto_squeeze_reverse=false, _squeeze_reverse; User-Vorgabe 2026-07-17): War kurz scharf, dann abgeschaltet — nur der flat-Entry ist gemessen-validiert, der Reverse ist unbelegt, verdoppelt Kosten und dreht am Ausbruch-Extrem (real 2026-07-17 18:55: WAVE_REV_SHORT gegen einen News-Rally-LONG-Ausbruch bei 29,64 € geschlossen, dann LONG am Erschöpfungs-Top 82,32 — Elliott „impulse_up/5 exhausted" im selben Moment). Bei false bleibt ein Gegen-Trade unangetastet (Drehen = manuelle Entscheidung); _squeeze_last_sig wird dann NICHT gesetzt → schließt der Gegen-Trade (SL/manuell), kann der flat-Entry auf denselben Ausbruch noch feuern. Bei true (historisch, reaktivierbar): läuft ein Trade GEGEN den Ausbruch (auch manueller/Fremd-Trade!) → sofort close(reason= "squeeze_reverse") (Log 🔄 + Telegram, Dedup _squeeze_reverse_sig), nächster flat-Tick dreht. ⚠ NICHT gemessen (der Squeeze-Backtest nahm flat-Entry an) — deshalb Default aus. Exit-only-Variante („Gegen-Position beim Ausbruch schließen, OHNE Re-Entry") = VERWORFEN (gemessen backtest_squeeze_exit.py, 2026-07-22, User-Idee „Breakout schneller schließen"): die sicherere Halb-Variante (nur schließen, nicht drehen) fällt ebenfalls durch — in BEIDEN Hälften schlechter als der Live-Exit (SL 2×ATR+Trailing): ΔΣR H1 15 (immer)/5 (nur im Minus), H2 27/29. Grund: der Gegen-Ausbruch ist oft ein Fehlausbruch/Whipsaw → die Position prallt zurück, der frühe Close kappt Trades, die sich erholt hätten. Der 07:38-Fall (LONG lief zum SL während SHORT-Ausbruch) war Varianz. Fazit: Squeeze taugt als ENTRY (validiert), NICHT als Gegen-EXIT. Der einzige Speed-Hebel bleibt die schnellere Erkennung (Variante A, ~5 s). Re-Test unter Vola-Regimen = ERNEUT VERWORFEN (gemessen backtest_squeeze_exit_vol.py, 2026-07-24, User-Frage „Markt gerade sehr volatil — wirklich nicht profitabel?"): Verschärfter Test mit echten SQUEEZE-Entries (statt EMA-Crosses), 4 Varianten (immer/nur-im-Minus/nur-Verlust>0,5×ATR), ATR-Terzil-Split je Hälfte + Extra-Fenster letzte ~30 Tage. Ergebnis: Effektgröße überall ~0 (±0,0020,005 R/Trade bei ~1150 Trades/Hälfte), Vorzeichen kippt zwischen den Regimen (MODL: H1-Hochvola 1,6 / H2-Hochvola +3,0 / letzte 30 Tage 0,3) → nach der vorab festgelegten Regel (beide Hälften UND Hoch-Vola-Terzil ≥ BASE) fällt JEDE Variante durch. Kernbefund: Worst-Case ist in ALLEN Varianten identisch (2,33/2,47 = SL-Deckel) — der Gegen-Squeeze-Exit reduziert das Tail-Risiko um exakt 0, weil bei echten schnellen Brüchen immer der SL zuerst greift; er kappt nur langsame Kriecher, von denen sich >50 % erholt hätten. (Methodik-Hinweis: absolute ØR pessimistischer als im validierten Squeeze-Backtest — Entry am Bar-Close statt am Level, keine Flat-Bedingung; für den Varianten-VERGLEICH neutral, da alle Exits denselben Entries folgen.) 3. Messung derselben Idee (Reverse · Exit-only · Vola-Regime-Re-Test) — gleiche Antwort. S/R-Close kappt Squeeze-Runner? = GEPRÜFT, KEINE Änderung (gemessen backtest_squeeze_srclose.py, 2026-07-24, User-Beobachtung „Squeeze wird direkt am nächsten S/R geschlossen"): Der Log bestätigt, dass Auto-Squeeze-Trades regelmäßig vom P(break)-S/R-Auto-Close am nächsten Gegen-Level geschlossen werden (der Squeeze wurde mit reinem Trailing validiert, ist runner-abhängig — Verdacht: Runner gekappt). Direkter Vergleich NUR auf Squeeze-Entries (Box≤2,5×ATR, k=0,1): Exit A = nur Trailing (validiert) vs. Exit B = +S/R-Close (aktuell live) = Wash, kein robuster Schaden — H1 ØR +0,190→+0,224 (ΣR +40→+47, B besser), H2 ØR +0,394→+0,377 (ΣR +290→+278, B marginal schlechter) = Δ ±0,02 R/Trade (Rauschen). Warum unkritisch: der S/R-Close ist P(break)-gegated (schließt nur wenn Level wahrscheinlich HÄLT, P<60 %) → echte, starke Ausbrüche haben hohe P(break) und laufen weiter; PF/Runner-Tail bleiben erhalten (H2 PF 1,58=1,58), nur die WR steigt (50→55 %, Abpraller früher als Klein-Gewinn kassiert). Squeeze-Trades vom S/R-Close auszunehmen ist also NICHT belegt. (Reaktivierbar per Toggle, falls der User trotzdem die Runner nie kappen will — kostet gemessen ~nichts, ist aber Präferenz, kein Edge.) S/R-Close-Cooldown (2026-07-17, Koordinations-Fix, kein Backtest): nach einem S/R-Auto-Close eröffnet der Auto-Squeeze ~3 min (_SQUEEZE_SR_COOLDOWN_S=180) nicht in GLEICHER Richtung wieder. Grund: der S/R-Close ging von „Level hält" (P(break)<Schwelle) aus, ein sofortiger Gleichrichtungs-Squeeze („Level bricht") war der widersprüchliche 1-s-Roundtrip (LONG-Close +15 → 1 s später neuer LONG, doppelter Spread; real beobachtet 2026-07-17 14:17). _check_sr_close merkt Zeit+Richtung (_sr_close_ts/_sr_close_dir), der Entry-Pfad prüft sie; _squeeze_last_sig wird NICHT gesetzt → nach Ablauf feuert der Ausbruch, falls noch aktiv. Der Reverse (Gegenrichtung) bleibt unberührt — nur der Gleichrichtungs-Wiedereinstieg wird verzögert. Allgemeine Wiedereinstiegs-Sperre nach JEDEM Close (2026-07-28, Koordinations-Fix, kein Backtest): nach dem Schließen eines Trades durch Notfall-Stop / Broker-SL / Time-Stop / manuell eröffnet der Auto-Squeeze ~3 min (_SQUEEZE_REENTRY_COOLDOWN_S= 180) nicht in GLEICHER Richtung wieder. Grund: real am 2026-07-27 15:39 killte ein zu enger manueller 3-€-Notfall-Stop (Sub-Spread bei Margin-Sizing) den Auto- Squeeze-Entry #1 nach 16 s; der Squeeze war noch active → sofortiger Re-Entry #2 (Open→Instant-Close-Kaskade, doppelter Spread). _check_auto_close erfasst den Flat- Übergang (_pos_close_ts/_pos_close_dir, Richtung via _open_pos_dir solange offen), der Squeeze-Entry-Pfad prüft ihn NACH dem S/R-Cooldown; _squeeze_last_sig wird NICHT gesetzt → nach Ablauf feuert der Ausbruch, falls noch aktiv. Gegenrichtung/Reverse unberührt. Deckt alle Close-Arten außer dem S/R-Close ab (der hat seinen eigenen Marker). ⚠ Behebt das Symptom; der eigentliche Auslöser war der Sub-Spread-Stop (emergency_min_eur=3-Guard fängt <3 € ab, 3 € genau auf der Grenze war zulässig).
  • TF-Wechsel nicht mehr persistiert: engine._apply_wave_tf merkt den Heuristik-TF nur im Speicher (kein save_config mehr) — sonst würde die Secrets-ini bei jedem Switch neu geschrieben (Kommentar-Verlust/Churn). Beim Neustart wählt die Heuristik den TF binnen 1 min neu.
  • Circuit Breaker (Tagesverlust-Stopp) = gebaut, aktuell AUS [trading] daily_loss_limit_pct=0 (User schaltete ihn am 2026-07-27 wenige Stunden nach dem Einbau wieder ab). Kurz auf 8 aktiv (Überlebens-Basis, mit dem Autonomie-Ziel reaktiviert nach jahrelanger Ablehnung), dann =0. Reaktivieren = ini auf z. B. 8. Mechanik bei >0: erreicht der Tages-P&L (realisiert heute + offene Position) pct % der Balance, schließt der Bot die Position (closed_by=circuit_breaker) und sperrt neue Auto-Trades bis zum nächsten Tag (_check_auto_squeeze prüft _circuit_halted()). _check_circuit_ breaker im _pos_loop (1 s, unter Startup-Grace pausiert), realisierter Tages-P&L ~30 s gecacht (_day_realized_cached), Berlin-Datum als Trip-Marker (_circuit_ tripped_date) → automatischer Reset am neuen Tag. Log 🛑 + Telegram (eigener, nicht vom Close-Gate betroffen). Snapshot circuit_breaker {enabled, limit_pct, limit_eur, day_total, tripped}, Frontend #circuit-banner (rot bei ausgelöst, bernstein ab 60 % des Limits, v=115). ⚠ 80 %-Margin-Sizing bleibt (User- Entscheidung, 3.+ Mal bestätigt; risk_pct=0) → der 8 %-Tagesstopp schützt v. a. gegen die Verlust-Serie/-Kaskade, NICHT vollständig gegen den Einzeltrade (dessen 2×ATR-SL unter 80 % Margin allein schon >8 % verlieren kann). 0 = aus. Mit 5 synthetischen Szenarien getestet (nicht-zu-früh · Trip+Close · kein Doppel-Close · aus · Auto-Squeeze-Block). ⚠ Der frühere „NICHT einbauen"-Grund gilt nicht mehr — Ziel hat sich zu autonomem Handel verschoben, und ein unbeaufsichtigter Agent braucht die Notbremse im Code.
  • Notfall-Stop = AUS beim Öffnen (Stand 2026-07-24, auto_emergency_margin_pct=0, auto_emergency_pct=0, auto_emergency_loss=0). User-Vorgabe 2026-07-24: „gewinn close und notfall close … nicht setzen beim Eröffnen" → alle drei Auto-Arm-Modi 0, beim Öffnen einer Position wird KEIN Notfall-Stop gesetzt. Nur ein manuell im UI-Feld eingegebener Wert armiert (bleibt bis zum nächsten Positionswechsel). ⚠ Vertipper-Schutz [trading] emergency_min_eur=3 (Fix 2026-07-27): ein manuell gesetzter Notfall-Stop UNTER diesem Minimum wird als „aus" behandelt (nicht scharfgestellt) + Log-Warnung. Grund: ein Sub-Spread-Wert schließt den Trade sofort UND vererbt sich per _emergency_remember auf ALLE Folge-Trades — real am 2026-07-27 setzte der User versehentlich 1 € → jeder neue Trade wurde in Sekunden per Notfall-Close gekillt (Tickets 48504360/48504814 u. a., „sofort geschlossen"). Guard in set_emergency (greift NUR auf die manuelle Eingabe; die %-Auto-Arm-Pfade sind eh 0). 0 = kein Floor. Kurz-Historie des margin-%-Modus: 2026-07-17 komplett raus (2 % ≈ 0,76×ATR zerschoss die Squeeze-Trades, 48,94-€-Tag) · 2026-07-20 wenige Stunden als 3-%-GAP-NETZ (Balance-Basis) mit risk_pct=1.5 · 2026-07-23 kurz margin-basiert =3.0 (dritter Modus, ausgelöst durch zwei Notfall-Closes am selben Abend 11,20 €/20,47 €, wobei die Schwelle beim ersten Trade noch auf einem händischen UI-Restwert von 5 € hing) · 2026-07-24 auf User-Wunsch wieder ganz AUS. Der margin-%-Modus bleibt im Code (retry-sicheres Armieren via _emergency_margin_armed_ticket, hat Vorrang vor Balance-%/Fixwert wenn >0), reaktivierbar per ini. ⚠ Kopplungs-Regel (falls reaktiviert): unter Margin-Sizing kann ein enger %-Stop schneller greifen als der 2×ATR-SL. Schutz-Stack aktuell: Broker-SL 2×ATR + Trailing + Time-Stop (der Auto-Notfall-Stop ist inaktiv). UI-Feld (#emg-input, User-Vorgabe 2026-07-22, v=105) in der Trade-Leiste (rot, neben Gewinn-Close), Enter blurrt nur (kein Doppel-Send/ungewolltes 0, gleicher Fix wie Mindestgewinn 2026-07-22) — ein am Handy gesetzter Wert überschreibt den Auto-Arm für den laufenden Trade und bleibt bis zum nächsten echten Positionswechsel maßgeblich (mit Test verifiziert). ⚠ Server-seitig: wirkt nur bei laufendem Server (Update-Reboot-Lücke → „Auch beachten"). Der Server schließt die Position sofort, sobald P&L ≤ Wert (engine._check_emergency im _pos_loop, 1 s; wirkt auch bei gesperrtem Handy). Auto-Arm — drei Modi (Priorität: margin-% > Balance-% > Fixwert): (a) NEU — % der Einsatz-Margin dieser Position (aktiv, User-Vorgabe 2026-07-23): [trading] auto_emergency_margin_pct=3.0 → Schwelle = pct% × Margin (dieselbe Margin wie beim Gewinn-Close, aus trader.refresh()). Retry-sicher (Fix 2026-07-23, gleiches Muster wie beim Gewinn-Close): läuft NICHT nur einmalig beim Ticket-Wechsel, sondern jeden _pos_loop-Tick erneut, bis order_calc_margin einmal >0 liefert (_emergency_margin_armed_ticket-Retry-Schutz) — verhindert, dass bei einem Broker-Race im ersten Tick nach dem Öffnen dauerhaft ein stalen Wert der vorherigen Position hängen bleibt. Mit 4 synthetischen Szenarien verifiziert (sofort verfügbare Margin · verzögerte Margin/Retry · manuelles Überschreiben bleibt erhalten · Neustart überschreibt NICHT). Snapshot emergency_margin_pct. (b) % des Kontos (Fallback, wenn margin-%=0): [trading] auto_emergency_pct=2.0 → bei jeder neuen Position wird die Schwelle auf pct% × Balance gesetzt (_emergency_pct, skaliert mit dem Konto; z. B. 2 % von 831 € = 16,62 € ≈ 0,4×ATR; 1× auf 1 % getestet, war zu eng → 2 %). UI-Feld zeigt im Flat-Zustand den dynamischen Wert (Frontend rechnet pct%×balance, Snapshot emergency_pct). (c) Fixwert (Fallback, wenn beide %-Modi aus): Schwelle = zuletzt genutzter Wert (_emergency_remember, Startwert [trading] auto_emergency_loss Default 10, 0 = aus). Setzt der User im UI einen neuen Wert, wird der gemerkt und ab dem nächsten Trade übernommen. Aktiver Stop verfällt nach Auslösen UND bei Positions-Close, der gemerkte Wert bleibt. Neustart-fest (Fix 2026-07-17, emergency_state.json): Der aktive Notfall-Stop/TP wird mit dem Ticket persistiert (_save/_load_emergency_ state, atomarer Write; bei Auto-Arm UND manuellem Set). Erkennt der Server dieselbe offene Position nach einem restart_server.bat wieder, stellt er den persistierten Wert wieder her (_check_auto_close: ticket == _emergency_state_ticket → restore, Log „Auto-Close wiederhergestellt") statt auf die pct-Automatik zurückzuarmieren. Grund: real am 2026-07-17 14:30 setzte ein Neustart bei offenem Trade die von Hand gesetzten 25 € auf 19,42 € (2 %) zurück → Notfall-Close bei 19,64 statt bei 25. Eine echt neue Position (anderes Ticket) armiert normal aus pct/Merkwert und persistiert neu. ⚠ Trailing-Zustand ebenfalls neustart-fest (Fix 2026-07-29): emergency_state.json persistiert jetzt zusätzlich trail (= trail.enabled) per-Ticket. Erkennt der Server dieselbe Position wieder und war das Trailing vor dem Neustart AN, reaktiviert er es automatisch (_check_auto_close-Restore-Zweig → trail.toggle, Log „Trailing wiederhergestellt … nach Neustart"). Grund: real am 2026-07-29 lief eine Auto-Squeeze- Position nach mehreren Server-Neustarts nur mit dem Broker-SL (Trailing/Breakeven/ Time-Stop weg), weil trail.enabled nur im Speicher lebte und die Wiedererkennung (magic-match) es NIE reaktivierte — der User musste es von Hand einschalten. War das Trailing AUS (z. B. nach manuellem SL/TP via /api/sltptrail.deactivate), bleibt es aus (der persistierte Zustand entscheidet — kein Überschreiben eines manuellen TP). Der Zustand wird bei jeder Änderung persistiert (Change-Detection im _pos_loop, fängt auch die Selbst-Deaktivierung des Trailings bei manueller SL/TP-Erkennung). „aus"-Button schaltet auch den Auto-Arm ab (setzt _emergency_remember=0 — vorher blieb der gemerkte Wert und re-armte beim nächsten Trade, „aus" wirkte nur bis dahin; Bug gefixt 2026-07-07). Gilt genauso fürs Gewinn-Ziel. (Auto-Arm 1× auf manuell-only gestellt, nach Fehl-Trade wieder reaktiviert — echter Schutz gegen falsche Empfehlungen; Signal-Filter dagegen 4× gemessen wirkungslos/schädlich, s. backtest_rev_htf.py.) engine.set_emergency() · POST /api/emergency {value} · snapshot.emergency_loss. Das ist KEIN automatischer Circuit-Breaker, sondern ein manueller Hard-Stop (vom User gewünscht). Benachrichtigung IMMER (Ausnahme vom „Close-Push nur im Plus"): bei Erfolg „🚨 Notfall-Close", bei Fehlschlag „⚠ Notfall-Close FEHLGESCHLAGEN — manuell schließen!" (Schwelle bleibt dann aktiv, nächster Tick versucht erneut). Eigener send_telegram, nicht vom pnl>0-Gate (history) noch vom 5-Min-Cooldown betroffen.

Mobile-UI (web/) & Alarme

  • Aufbau: Tab-Navigation ganz oben (sticky: Dashboard/Logs/Statistik/Charts/News), darunter Header.
  • Design-System (style.css, Pass 2026-07-15, KEIN Framework — Tailwind bewusst verworfen wegen WireGuard/Offline + kein Node): Tokens in :root — Flächen-Leiter --bg < --surface-2 < --card, --border/--line, Text --dim/--bright (+--text-*-Aliasse, waren undefiniert = Bug gefixt), Radien --r-sm/-r/-r-lg, --shadow(-sm), --mono. Font: UI = System-Sans + tabular-nums; Zahlen-Werte (Kurs/PnL/Felder/Logs) = --mono. Karten mit Elevation-Schatten, Fokus-Ringe auf Feldern, Transitions auf Tabs/Buttons. Neutrale Hex-Literale → Tokens (Konsistenz).
  • Trade-Leiste (#trade-bar, über der Gesamtempfehlung, nur bei offener Position, 2026-07-15): Laufzeit-Uhr (2026-07-30, User-Wunsch „Uhr … wie lange diese schon läuft"): trader.snapshot() liefert open_time = Öffnungszeit als echte Epoch (Broker-Offset korrigiert, aus position.time); Frontend zeigt sie als Feld #tb-dur und kompakt im Kachel-Titel (#tb-runtime, „⏱ 1:23:45"). Der Ticker läuft eigenständig 1×/s (_tickTradeDuration), zählt also flüssig zwischen den Snapshots; ab 2 h bernstein (Time-Stop-Nähe: 120 min in Phase „Init"). ⚠ Zwei Fallen beim Bau: (1) _broker_offset_s() liest self.symbol, die beim Adoptieren einer Position noch NICHT gesetzt ist → Offset 0 → Zeit lag 3 h in der Zukunft; die Funktion nimmt jetzt sym als Parameter (_broker_offset_s(pos_sym)). (2) Selbst- heilung: liegt open_time >60 s in der Zukunft, wird sie neu berechnet; beim Close auf 0 zurückgesetzt (kein stale Wert für den Folge-Trade). Berechnung nur 1× je Position (nicht je 1-s-Refresh). Weiter in der Zeile: Richtung (▲LONG/▼SHORT) · Lots · Einsatz · 3 Eingabefelder .tb-field (Label über Feld, rot=.stop/grün=.gain): SL · TP · Gewinn-Close (#srmin-input) (Notfall-Close-Feld 2026-07-17 entfernt — Notfall-Stop ganz aus). SL/TP: Enter/Verlassen → POST /api/sltp → setzt am Broker und schaltet Trailing ab (trail.deactivate); Vorbefüllung aus position.sl/tp, Broker-Ablehnung → Toast. Gewinn-Close (2026-07-15 aus der Position-Kachel hierher verschoben, User-Vorgabe — gleiches Design) behält ID/Handler (/api/srclose_min). Auch der Auto-Close-Schalter (#srclose-btn, jetzt .tb-btn-Box, AN/AUS grün/grau) sitzt in 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 nur noch cur-near-Warnung + pos-srhint. (.emg*/.sr-toggle-CSS entfernt.)
  • Charts-Tab (#view-charts): M1/M5/M15/M30/H1 untereinander, je ein Candlestick-Chart mit EMA12 (blau) + EMA50 (amber)-Overlay und Trend-Header (▲/▼/→ nach EMA12-vs-EMA50 mit Totband). Framework TradingView Lightweight Charts v4.2.3 — lokal vendored (web/lightweight-charts.standalone.production.js, KEIN CDN wegen WireGuard/Offline). Daten via GET /api/bars?tf=&n=engine.get_bars (OHLC+EMA+Trend unter mt5_lock). app.js: loadCharts/ renderChart, Charts nur bei sichtbarem Tab geladen + Auto-Refresh 20 s (schont den Lock). Broker-Zeit (UTC+3) → UTC via broker_utc_offset. Gitternetz dezent (2026-07-27, User „dunkler/unauffälliger": grid-Farbe #161b22#10151c, näher am Hintergrund #0d1117). Chartmuster-Overlay (nur M30) — s. Chartmuster- Kachel: die 2 stärksten M30-Muster als Trigger-/Ziel-Preislinien. Regressionskanal-Overlay (nur M30, 2026-07-20): get_bars liefert bei M30 channel {dir, mid[], upper[], lower[]} (Arrays deckungsgleich mit den Bars, structure.channel_series — Regression über 60 abgeschl. Bars, linear über die volle Breite extrapoliert). Frontend zeichnet 3 LineSeries (oben/unten gestrichelt, Mitte gepunktet, grau). Dieselbe Kanal-Definition wie die Marktstruktur-Kachel — REINE Anzeige (Signalvariante gemessen verworfen, s. backtest_structure.py). 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 < S0,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_levelsentry_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-Bridgeengine._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 1946 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.29LQ-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 2122 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 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 entfernt). ⚠ Bias-Fix 2026-07-15: stimmberechtigt nur Module MIT Aussage — Squeeze (nur active), Elliott (nur mit Ziel), KI (nur mit Bias) haben sonst Gewicht 0 (vorher dämpfte das fast immer neutrale Squeeze-w=2,0 die Nadel permanent ~×0,8); agree/total zählt nur noch die ANDEREN stimmberechtigten Module (Welle zählte sich selbst mit). ⚠ Bias-Fix ZWEITER TEIL 2026-07-30 (Review „Gesamtempfehlung komplett prüfen"): Die Regel „ohne Aussage = Gewicht 0" galt bis dahin für Squeeze/Elliott/KI, NICHT für die Welle selbst — sie stand mit w=3,0 permanent im Nenner, auch bei WARTEN. Das wog schwer: ~91 % der letzten 2000 Empfehlungen sind WARTEN (Range-Regime), die Nadel war also fast immer künstlich zur Mitte gezogen (realer Fall: bias +0,312 statt +0,625, Faktor ~2). Jetzt weight=0 bei WARTEN. Zweiter Fix: agree nutzte als Referenz immer die Wellen-Richtung → bei WARTEN stand dort zwangsläufig „0/N", obwohl sich die anderen Module einig waren (real „0/4" bei 2 einigen Modulen). Jetzt Referenz = Wellen-Richtung, ersatzweise die Bias- Richtung (real: „2/3"). Beides REINE ANZEIGE — Order-Logik unberührt. Mit 6 synthetischen Szenarien verifiziert (alle einig · Rest dagegen · alles neutral · WARTEN+alle SHORT · Welle+Squeeze). ⚠ Bias-Fix DRITTER TEIL 2026-07-31 (Anlass: User-Frage „H1 aus der Gesamt- empfehlung entfernen, da wir jetzt mit M30 arbeiten?"): Antwort NEIN — die Prämisse vermischt zwei Dinge (auf M30 umgestellt wurde die S/R-Level-Quelle, nicht die Zeitebenen-Logik; H1 war nie Basis-TF, tf_max=M30). Und die vermutete Doppelzählung ist gemessen schwach (verdict_votes, n=7.074): bei gerichteter Welle stimmt M30 nur zu 14,9 % mit ihr überein, H1 zu 47 %, M30 und H1 untereinander nur zu 33,8 % — keine redundanten Stimmen (Reversals heben den M30-Filter bewusst auf, und M30 ist meist gar nicht gerichtet). H1 fließt zwar auch als Konfluenz-Bonus in die Konfidenz — aber in eine ANDERE Kennzahl (Konfidenz-Ring vs. Bias-Nadel), nicht zweimal in dieselbe. DER ECHTE DEFEKT lag woanders und ist behoben: add("M30", …)/add("H1", …) hatten Gewicht 1,5 UNBEDINGT — auch bei Stimme 0. Derselbe Fehler wie beim Wellen-Modul (Teil 2), hier übersehen. Eine 0-Stimme heißt „EMA-Abstand im Totband" = keine Aussage, nicht „neutral". Gemessen: M30 ist in 57,9 % der Fälle ohne Aussage (H1 nur 1,8 %) → Ø-Bias-Betrag 0,371 → 0,441, Median-Verstärkung 1,30×, in 33,3 % der Zeilen deutlich stärkere Nadel. Jetzt 1.5 if vote != 0 else 0.0; others filtert bereits auf weight>0, die „x/y einig"-Zählung zieht mit. Live verifiziert: M30 „flach" → Gewicht 0,00, bias 1,5/4,5 = 0,333 statt 1,5/6,0 = 0,250. REINE ANZEIGE. ⚠ MODUL-AUDIT 2026-07-31 (User: „überprüfe alle Module auf Inkonsistenzen"): systematisch alle Verdict-Module gegen die Regel „keine Aussage → Gewicht 0" geprüft, dazu Config-, Frontend- und Level-Quellen. 5 Befunde, alle behoben: (1) KI-Copilot — der größte Rest des Musters. Ein explizites „NEUTRAL" zählte als echte Stimme mit Gewicht 1,0. Gemessen (verdict_votes, n=7.084): das ist in 93,1 % der Fälle der Zustand (Elliott: 1,3 %) — also der Normalzustand des Copiloten, kein abgewogenes Urteil. Damit hatte ausgerechnet das Modul mit der schwächsten Beleglage (analyze_verdict_calibration.py: nicht robust prädiktiv) den GRÖSSTEN dämpfenden Einfluss. Jetzt 1.0 if av != 0 else 0.0. (2) Elliott analog: Gewicht nur bei gerichtetem Ziel (1,3 % der Zeilen). Kumulierte Wirkung aller Gewichts-Fixes des Tages: Ø|bias| 0,370 → 0,441 → 0,569 (= 1,54×), betrifft 79,5 % der Zeilen. Live verifiziert: KI „NEUTRAL" → Gewicht 0,00, bias 2,5/4,5 = 0,556 statt 2,5/5,5 = 0,455. (3) Stale [zones] speisten die Wellen-Konfidenz — entfernt. _sr_levels zog beide Kanten jeder [zones]-Zone als S/R-Linien heran: 16 Kanten aus einem ~10 $ TIEFEREN Regime (72,9077,00 bei Kurs 85,3). Aus dem CHART waren sie am 14.07. schon entfernt worden, WEIL sie stale sind — in die Konfidenz liefen sie weiter. Realer Audit-Fall: market.sr hatte GAR KEINE Widerstände (M15-Cluster sind in frischen Trends oft leer) → der „nächste Widerstand" kam aus der fvg-Zone bei 88,00 (2,66 weg), der echte lag bei **85,315** (0,03 weg). Der Abzug „dicht unter Widerstand" (12) greift nur innerhalb 0,5×ATR und feuerte deshalb nie. Entfernen ist keine Strategieänderung, sondern das Streichen von Fremdregime-Daten; parse_zones bleibt in config.py, die ini-Sektion bleibt (reaktivierbar). (4) Tote Config entfernt (Backup oil_widget_config.ini.bak-2026-07-31): [trading] trail_timeframe = M1 (nirgends gelesen, Name suggeriert fälschlich, er steuere die Trailing-TF) und die komplette [setups]-Sektion (11 Schlüssel, vollständig tot). (5) raise StopIteration als Sprung innerhalb eines breiten except Exception (Trade-Marker-Export) durch ein if ersetzt — funktionierte, wäre aber fragil, sobald dort jemand Logging ergänzt (Phantom-Fehler im ~5-s-Takt). Sauber: Frontend↔Backend (0 verwaiste Element-IDs), alle übrigen Verdict-Gewichte, alle anderen Config-Schlüssel. ⚠ KONSENS-ZEILE korrigiert (2026-07-31, User-Fund „4/4 Module — dabei haben wir doch 9"): In vd-consensus steckten ZWEI Fehler. (a) Falscher Bezug: der Text lautete … Module für ${sig} mit der HEADLINE als Bezug. Seit dem ref-Fix vom 30.07. zählt agree bei WARTEN aber die Übereinstimmung mit der Bias-Richtung — deshalb stand real dort „stark LONG · 4/4 Module für WARTEN". Die Richtung kommt jetzt als verdict.ref_dir vom Backend, statt im Frontend aus bias nachgebaut zu werden (dort galt ein ±0,05-Totband, im Backend bias > 0 — die Nachbildung wäre am Rand auseinandergelaufen; dieselbe Sorte Divergenz wie die fünf Deployment-Drift-Fälle desselben Tages). (b) Anderer Nenner als die sichtbaren Chips: total zählt nur Module MIT Aussage (Gewicht > 0, ohne die Welle). Nach den Gewichts-Fixes des Tages schweigen deutlich mehr Module → „4/4" bei 9 sichtbaren Chips. Neu ist verdict.silent (Module mit Gewicht 0) dabei, sodass die Summe aufgeht. Live: „3 von 5 stimmberechtigten für LONG (4 ohne Aussage)" — 5 + 4 = 9 . Bei gar keiner Aussage: „kein Modul mit klarer Aussage". v=125. ⚠ „WARUM WARTEN?" jetzt an der Headline (2026-07-31, v=126, User-Fund „WARTEN, aber Konsens stark LONG"): Der scheinbare Widerspruch entstand, weil die Welle in aller Regel eine RICHTUNG hat und nur an einem Gate hängt — der Grund stand aber ausschliesslich als Textzeile in der Meldungen-Karte, also weit weg von der Stelle, an der die Frage aufkommt. wave.breakout {pending, dir, level, need} wurde berechnet und gespeichert, vom Frontend jedoch nirgends gerendert. Jetzt hängt es direkt an der Headline: „◌ WARTEN · M15 · LONG, noch 0.02 bis zur Bestätigung". ⚠ Erste Auswertung der neuen block_reason-Telemetrie (3 h): breakout_pending 63 % · entry_room 20 % · min_conf 18 % — und kein einziges Mal Totband oder HTF-Gegen-Trend. Das beantwortet die offene Frage aus dem TF-Churn-Fix: die 93 % WARTEN kommen NICHT daher, dass die Welle richtungslos wäre, sondern von den Gates — allen voran der Breakout-Bestätigung (die bis zum Fix desselben Tages gar nicht fertig werden konnte). ⚠ Offen (dokumentiert, nicht geändert): (0) Wellen-Konfidenz aus _draw_levels speisen statt aus dem Misch-Set — würde den 12-Abzug tatsächlich auslösen, also Konfidenz senken und das 55%-Gate verschieben. Strategieänderung → messpflichtig. (a) Drei divergierende Level-Quellen seit der M30-Umstellung: _draw_levels (M30 → Chart/S/R-Close), pb_levels (M5 → Entry- Raum-Gate), _sr_levels (Misch-Set → Wellen-Konfidenz); real wichen die Supports um 0,65 $ ab. Bewusst so (jedes Gate ist auf seine Quelle kalibriert), aber eine Stolperfalle. (b) tu wird noch als Parameter durchgereicht, seit 2026-07-06 ungenutzt. Formel/Details: docs/gesamtempfehlung.md. Headline = validierte Welle (steuert Order) + Zeitebene (verdict.tf, z. B. „▲ LONG · M5" — TF, für die die Empfehlung gilt); Rest = nur Konsens-Anzeige. Backend engine._verdictverdict im Snapshot; Render renderVerdict (app.js). Details: docs/gesamtempfehlung.md. ⚠ Konfidenz ist NICHT kalibriert (gemessen analyze_verdict_calibration.py, 2026-07-24, „Gesamtempfehlung verbessern"-Paket): conf_pct gegen Forward-Return (2 h, ×ATR, 1604 gesampelte Signale aus recommendations, 2 Hälften) — H1 (MaiJun) perfekt monoton (conf 85100: WR 68 %/ØR +1,13; <55 klar negativ), H2 (JunJul) komplett INVERTIERT (conf 85100: WR 40 %/ØR 0,90; mittlere Bins besser). Hohe Konf = starker Trend + Konfluenz — im Chop-/Hochvola-Regime sind genau das die Überdehnungen vor der Wende. Konsequenzen: conf-Anzeige NICHT als P(Erfolg) aufwerten; Konfidenz-Sizing-Idee VERWORFEN (hätte in H2 die schlechtesten Signale am größten gesized); Ring bleibt, was er ist (Score-Aggregat). Copilot-Bias in derselben Messung nicht robust prädiktiv (n klein bzw. ØR ~0) — für die datenbasierte Entscheidung (behalten/Gewicht/raus wie TU) loggt jetzt verdict_votes (neue DB-Tabelle, history.log_verdict_votes, 1×/60 s aus _run_analysis: headline/conf/bias/tf + Modul-Votes Welle/M30/H1/KI(+w)/ Elliott(+w)/Squeeze + news_score) — Auswertung nach ein paar Wochen analog analyze_verdict_calibration.py. Live-Kosten-Chip (2026-07-24): Snapshot cost_ratio = (askbid)/ATR_M5 (pb_feats.atr, Floor 0,06) → in der vd-consensus-Zeile „Kosten 0,14×ATR günstig / · normal / ⚠ teuer" (Schwellen 0,20/0,32 aus backtest_realcosts.py: Ø 0,265, Nacht 0,320,50 = Falle, 1517 Uhr ~0,13). Reine Info — die ehrliche Alternative zum abgeschalteten Dead-Hours-Gate. Ausrichtungs-Split im Order-Dialog (2026-07-24, Verhaltens-Hebel/B0): Der „trotzdem eröffnen?"-Dialog zeigt jetzt die EIGENEN Zahlen aus der DB (history.alignment_stats(40) → Snapshot alignment, Engine-Cache ~120 s): „📊 Deine Trades OHNE Signal: 42 % Trefferquote · 423 € (n36) / Mit Signal: …" (Gruppen <5 Trades werden ausgeblendet). Real bei Einbau: 36 der letzten 40 Trades liefen OHNE Signal-Deckung mit 423 € — exakt die dokumentierte Kern-Leckage, jetzt im Moment der Entscheidung sichtbar. News-Konflikt-Chip (2026-07-24, Auslöser 23.07.: zwei Shorts gegen einen +0,98-Sentiment-Burst): Snapshot news_sentiment (Score 1..+1 aus news.sentiment); Frontend #news-conflict (Meldungen-Karte, bernstein) warnt bei |Score|≥0,5 gegen offene Position bzw. aktives Signal („📰 News-Flow stark bullisch (+0,98) — steht gegen deine SHORT-Position"). Reiner Kontext — Prädiktivität unbelegt (Kalibrier-Messung: H2 nur n=4/6); dafür wird recommendations.news_score seit 2026-07-24 wieder BEFÜLLT (war auf None degradiert) → in ein paar Monaten messbar.
  • Karten (Dashboard, von oben): Gesamtempfehlung · Meldungen · Marktstruktur · KI-Copilot · Letzte Trades · Kurslücken · Statistik (live) ganz unten. (Tagesziele-Kachel entfernt 2026-07-13. Welle-Karte komplett entfernt 2026-07-15 — TF-Ampel wanderte in die Gesamtempfehlung, die Wellen-Meldungen [Squeeze/Überdehnung/Setup/Lauf/Gründe] in die „Meldungen"-Karte (#card-pos, ex-„Position"); das Wave-Signal ist eh die Verdict-Headline. Trailing-Karte ausgeblendet 2026-07-22#card-trail.hidden per CSS, User-Vorgabe; Backend/ Trailing-Logik + Snapshot-Felder trail.* unverändert aktiv, nur die Anzeige raus, wieder einblendbar durch Entfernen der hidden-Klasse in index.html.)
  • Auto-Squeeze-Monitor (B4) (#sqm-box, oben im Statistik-Tab, 2026-07-20): zwei Blöcke — Entry-Edge · Mechanik (engine.squeeze_monitor rechnet die Squeeze- Regel mit Live-Params auf ~30 Tagen M5 NEU, Backtest-Exit → isoliert den Einstieg, ØR/PF gegen Erwartung +0,14…+0,23 · PF>1) und Live-Trades · echt (SQUEEZE_*- Trades aus der DB, Gesamtsystem inkl. realer Exits: n/WR/Ø-Gew/-Verl/Verhältnis/ΣEUR/ Tag-Nacht; ØR-Näherung via SL-Distanz). Verdict-Badge (trägt/dünn/driftet→B5) aus der Mechanik. Kernaussage der Ansicht: klaffen Mechanik (Edge lebt) und Live (echtes Geld) auseinander → es liegt am Exit/Verhalten, nicht am Signal (real 2026-07-20: Mechanik ØR +0,414/PF 1,64, Live ØR 0,07/2,41 € — der alte Notfall- Stop + Nacht-Trades fraßen den Edge, jetzt behoben → sollte konvergieren). Endpoint /api/squeeze_monitor (Cache 60 s), lädt beim Öffnen des Statistik-Tabs (loadStats).
  • Statistik-live-Kachel (#card-stats-live): kompakt Woche + Gesamt — Trades, WR, PF, Ø-Gewinn/-Verlust, Verhältnis (Øgew/Øverl, <1 = Verlust- Schiefe), PnL. Quelle engine._compact_statssnapshot.stats_compact. Zum objektiven Verfolgen der Stichprobe (statt Bauchgefühl pro Einzeltrade). TradersUnion- und Elliott/FVG- Einzelkacheln ausgeblendet. Elliott/FVG fließt weiter in die Gesamtempfehlung (_verdict); TU ist ganz raus aus Empfehlung, Verdict UND KI-Copilot-Kontext (agent._tool_market ohne tradersunion/tu_consensus — war die letzte Hintertür, da der Copilot eine Verdict-Stimme ist; nur noch Snapshot-Anzeige).
  • TF-Wende-Ampel (#wave-turns, jetzt IN der Gesamtempfehlung): Chips M1/M5/M15/M30/H1 (H1 neu 2026-07-15 — im turn_data-Fetch, aber NICHT im Bounce-Scan, der bleibt M1M30), je grün(auf)/rot(ab) nach EMA12/50-Stand; frische Kreuzung (≤3 Bars) blinkt + zeigt ⟳ + Richtungspfeil + Bars-seit-Wende. Quelle: wave.tf_turns (Backend WaveRecommender._turn_state mit Totband _TREND_DEADBAND×ATR → kein Geblinke bei seitwärts laufenden EMAs). 4-TF-Fetch ist gedrosselt (~15 s) via _turn_due (spart Lock-Zeit; letzter Stand in _last_tf_turns gehalten). REINE Anzeige — ändert die Empfehlung NICHT.
  • Marktstruktur-Kachel (#card-structure, 2026-07-20, User-Idee „Pro-Chart- Setup-Erkennung"): zeigt die Price-Action-Struktur auf M30 — Swing-Folge HH/HL/LH/LL (Chips grün=bullisch/rot=bärisch), letzter BOS (Break of Structure, Richtung + gebrochenes Level + Bars her) und den Regressionskanal (Richtung + Position des Kurses im Kanal 0100 % als Balken+Punkt). Quelle core/structure.py (MarketStructure, Pivots k=3, Kanal = LS-Regression über 60 Bars ± max. Abweichung, ~30 s gedrosselt im Trend-Loop unter mt5_lock), Snapshot structure. REINE ANZEIGE — kein Trade-Trigger, kein Verdict-Gewicht, KEINE Prognose/Pfeil. Signalvariante DIREKT gemessen & VERWORFEN (backtest_structure.py, 2026-07-20, 60k M30-Bars/5 J, 2 Halbjahre, dieselbe structure.py-Logik kausal): ALLE Varianten in BEIDEN Hälften negativ — (A) Kanal-Pullback „Kauf am unteren Kanaldrittel/Demand-Zone" = der orange Pfeil: ØR 0,05…−0,11, PF<1, WR 4043 % (der Kanalrand HÄLT nicht zuverlässig — antizyklisch am Extrem = Münzwurf, P(break)- Klasse); (A2) +Swing-Filter (HH/HL) macht es nicht besser (0,06/0,07); (B) BOS- Continuation = breakeven-negativ (0,011/0,005, Momentum-Klasse). Damit ist auch die Struktur-Idee empirisch durch — die Kachel bleibt Ist-Zustand-Anzeige (wie TF-Ampel/Squeeze), steuert nichts.
  • ⚠⚠ P(break) LIVE-AUSWERTUNG (analyze_pbreak_live.py, 2026-07-31, 2275 ausgewertete Vorhersagen seit 23.07.): DAS MODELL HÄLT LIVE NICHT, WAS DER BACKTEST VERSPRACH — B5-Fall. Fällige Messung aus dem Reminder, jetzt erledigt.
    Gesamt M5-Level (bis 29.07.) M30-Level (ab 30.07.) entkoppelt
    n 2275 1850 425 307
    AUC 0,539 0,570 0,399 0,443
    Treffer Modell 58,5 % 58,7 % 57,6 % 56,7 %
    „immer Abprall" 59,0 % 57,7 % 64,7 % 59,9 %
    Überschuss 0,5 Pp +1,0 Pp 7,1 Pp 3,3 Pp
    Backtest-Erwartung war AUC 0,71. Kalibrierung systematisch nach unten verzerrt:
    Bucket 019 % (n=1234, über die Hälfte!) sagt 8 % voraus, real 39,1 %; Bucket
    65100 % sagt 74,5 %, real 48,0 % (invertiert). Im Mittel prognostiziert das Modell
    23 % Durchbruch, real sind es 41 %, und es sagt nur in 8 % der Fälle „break".
    DER KERNBEFUND — das Gate gatet nicht: die **Bruchrate der GESCHLOSSENEN Gruppe
    ist bei JEDER Schwelle 3840 %**, also identisch zur Basisrate (thr 20 → 39,1 % ·
    thr 35 → 37,8 % · thr 55 → 40,5 %). Es findet live keinerlei Auswahl statt. Bei der
    ini-Schwelle 0,55 werden 91,2 % aller Level-Berührungen geschlossen → der
    „P(break)-gegatete Close" ist faktisch zum pauschalen S/R-Close degeneriert, und
    DER ist 2× gemessen und verworfen (backtest_srclose.py: WR verdoppelt, PF/ΣR in
    beiden Hälften schlechter = Gewinner-Kappen). **Das erklärt die kontrafaktische
    Live-Messung vom Vortag** (analyze_srclose_live.py: 8 €/Trade, 43 % klar zu früh
    geschlossen, nur 26 % klar richtig) — Symptom und Ursache passen zusammen.
    ⚠⚠ **URSACHE GEFUNDEN (2026-07-31, backtest_pbreak_touches.py + Rekonstruktion aus
    candles_m1): das Modell ist NICHT verfallen — es bekommt live eine ANDERE
    Merkmalsverteilung, als es trainiert wurde.** Beweiskette in drei Schritten:
    (1) Der Backtest reproduziert die 0,71 (M30-Level, 4 Merkmale, Fit H1 → **AUC
    out-of-sample H2 0,715**) → Modell und Pipeline sind in Ordnung.
    (2) Die Populations-Hypothese ist widerlegt: live nach Berührungszahl
    aufgeschlüsselt ist ausgerechnet die 1. Berührung (= die trainierte Situation) mit
    AUC 0,445 die SCHLECHTESTE Gruppe, die Chop-Fälle (5.+) mit 0,577 die beste.
    Der Versatz „Modell sagt 2325 %, real 4042 %" ist in JEDER Teilmenge gleich groß
    (~17 Pp) — Signatur eines Merkmals-Problems, nicht eines Edge-Verfalls.
    (3) Merkmale aus candles_m1 rekonstruiert (n=2275) — der Versatz ist messbar:
    Merkmal Live-Mittel Training-µ Differenz
    --- --- --- ---
    mom3 0,149 1,4523 1,303
    mom6 0,181 1,6565 1,476
    Daraus rechnet sich der z-Versatz exakt: mom3 → 1,433×(1,303)/2,418 = 0,772,
    mom6 → 0,275, zusammen 1,05. Aus der Trainings-Basisrate 39,4 % (z=0,429)
    wird damit ~19 % — beobachtet werden 23 %. **Erklärt praktisch die gesamte
    Fehlkalibrierung.**
    DER MECHANISMUS: Im Training ist der Touch-Bar jt der Moment, in dem der Kurs
    nach einem ECHTEN ANLAUF (Level bei Entry ≥0,3×ATR entfernt fixiert) zum ersten Mal
    ans Level stößt → mom3 ≈ 1,45×ATR = ein Schub. **Live wählt _draw_levels das
    nächstgelegene Level JEDE SEKUNDE NEU** (mit Hysterese) — der Kurs steht also oft
    neben einem Level, das gerade erst zum nächstgelegenen WURDE, ohne je darauf
    zugelaufen zu sein → mom3 ≈ 0,15. Gleicher Code, gleiche Formeln, aber **Training =
    Level bei Entry fixiert, Live = Level wandert mit.** Konsequenz: das Modell antwortet
    live konsistent „kein Schub → kein Durchbruch → 23 %", liegt damit IMMER unter der
    Schwelle 0,55 → das Gate war seit Inbetriebnahme faktisch nie aktiv.
    Zwei Reparaturwege (beide ungemessen, erst prüfen): (a) Ziel-Level beim Öffnen
    der Position FIXIEREN statt laufend neu zu wählen (macht Live = Training), oder
    (b) das Modell auf einer live-spiegelnden Stichprobe NEU trainieren (bei jedem Bar
    im 0,15×ATR-Band um das dynamisch nächste Level sampeln, ohne Anlauf-Bedingung).
    TOUCH-ZAHL im Backtest (2 Halbjahre, backtest_pbreak_touches.py): hebt die AUC
    nur von 0,715 auf 0,725, Gewicht +0,176 für die 2.4. Berührung (User-Vorzeichen
    bestätigt), aber der R-Ertrag ist nicht robust (H1 +131, H2 43). ⚠ Im Trainings-
    Datensatz sind 76 % Erst-Berührungen und es gibt KEINE 5+-Fälle (live sind 63 %
    fünfte oder später) — das live beobachtete umgekehrte U lässt sich dort nicht einmal
    abbilden. Kleine Verbesserung, nicht der Hebel.
    Pipeline gegen das Training geprüft, KEIN Bug gefunden: dist ist in beiden
    entry-basiert (abs(levelentry)/atr, backtest_srclose_prob.py:86), mom6/mom3
    in beiden am Touch-Bar jt, confirm/reject dieselbe ±0,5×ATR-Definition, Timeout
    zählt in beiden als Abprall. Plausibelste Ursache = andere Stichproben-Population:
    live werden 2275 Berührungen geloggt, entkoppelt (max. 1 je Level und Stunde) bleiben
    nur 307 — dieselbe Position pendelt vielfach um dasselbe Level, live dominieren
    also Chop-am-Level-Fälle. ⚠ Das entlastet das Modell NICHT: entkoppelt ist die AUC mit
    0,443 sogar schlechter. ⚠ Der M30-Teil (AUC 0,399) ist mit n=425 über 2 Tage zu klein,
    um die Umstellung als Ursache zu belegen — die Wiedervorlage (≥30 S/R-Closes auf
    M30-Leveln) läuft weiter.
    **TOUCH-ZAHL als fehlendes Merkmal (User-Idee 2026-07-31 „je öfter der Kurs die Linie
    berührt, desto wahrscheinlicher der Durchbruch") — auf den Live-Daten BESTÄTIGT, aber
    mit Umkehr:** Bruchrate nach n-ter Berührung desselben Levels im 30-min-Fenster, in
    BEIDEN Live-Hälften dasselbe Muster — 1. Berührung 38,3/41,7 % · 2. 40,8/45,6 % ·
    3. 43,2/45,1 % · 4. 45,1/47,4 % (monoton, +6/+4 Pp über Basis) · **5.+ fällt
    zurück auf 37,8/41,8 %** (UNTER Basis, und mit n≈1400 die größte Gruppe). Also ein
    umgekehrtes U, kein monotoner Anstieg: 24 Berührungen = Level wird mürbe, ab 5 in
    30 min = Range, das Level HÄLT. ⚠ Das Modell sieht davon nichts (sagt über alle
    Berührungszahlen konstant ~23 % voraus) → echte orthogonale Information. ⚠ Belastbarkeit
    begrenzt: die beiden „Hälften" liegen nur 4 Tage auseinander (kein Regimewechsel),
    Buckets n=82139; und backtest_srbreak.py fand die Touch-Zahl früher „nicht robust"
    (allerdings ohne Fenster-Definition und ohne die 5+-Umkehr). **Nächster Schritt: als
    5. Merkmal in backtest_srclose_prob.py aufnehmen und über die 34.771 Touches / 2
    echten Halbjahre neu fitten** — dort ist messbar, ob die AUC steigt.
    BEHOBEN am selben Tag (Weg b, User-Entscheidung): MODELL NEU TRAINIERT.
    backtest_pbreak_retrain.py erzeugt eine live-spiegelnde Stichprobe — Level
    dynamisch mit Hysterese wie _draw_levels, gesampelt an JEDEM Bar im 0,15×ATR-Band
    (KEINE Anlauf-Bedingung), Ausgang/Fenster wie live. Kontrolle: die Merkmalsmittel
    dieser Stichprobe (mom6 0,203 · mom3 0,202) treffen die live rekonstruierten Werte
    (0,181 · 0,149) — sie bildet den Live-Pfad also wirklich ab.
    ALT-Modell NEU-Modell
    --- --- ---
    AUC auf live-spiegelnder Stichprobe (H2, oos) 0,368 0,654
    Ø-Vorhersage vs. real 19,2 % vs 39,4 % kalibriert
    R-Ertrag (backtest_pbreak_rvalue.py, Echtkosten, Baseline = nur Trailing): NEU
    schlägt ALT in BEIDEN Hälften bei JEDER Schwelle; gegen die Baseline gewinnt es
    bei 0,35/0,45/0,55 in beiden (bei 0,60 kippt H1). Bestwert 0,35 — H1 149 vs
    Baseline 506 (+357), H2 +1308 vs 110 (+1418). ⚠ Nebenbefund: das ALTE
    Modell war in H1 schlechter als gar kein Auto-Close (653 vs 506), in H2 besser
    (+576 vs 110) — genau die Regime-Abhängigkeit, die live als 8 €/Trade sichtbar war.
    Eingebaut: neue _PB_MU/_SD/_W in engine.py (final auf allen 80k Bars gefittet,
    n=76.542, Basisrate 37,8 %, nachdem H1→H2 validiert war; alte Werte als Kommentar für
    den Rückweg) + sr_close_pbreak=0.35 (Config-Wächter-Anker mitgezogen).
    Verifiziert: Chart-Linien zeigen jetzt 43 %/36 % statt 815 %.
    ⚠⚠ DAS NEUE MODELL INVERTIERT EINE ALTE PROJEKT-REGEL — bewusst so: das Gewicht
    von mom3 dreht das Vorzeichen (+1,4330 → 0,5420). Der alte Befund
    (backtest_srbreak.py) lautete „Kurs KRIECHT ans Level → P(break) nur 26 %, mit
    Schwung → laufen lassen (4143 %)". Das neue Modell sagt das Gegenteil: Anlauf-Schub
    → 26,5 % (das Level ABSORBIERT den Schub und hält), Schwung weg vom Level → 51 %.
    Beides gilt in seiner eigenen Population — die alte Messung betraf den Anlauf zu
    einem FIXIERTEN Level, die neue das Verweilen an einem DYNAMISCH gewählten. Für den
    Live-Pfad gilt die neue Lesart; die alte Faustregel weiter oben im Text bezieht sich
    auf die Anlauf-Situation und ist dort nicht widerlegt.
    Weiterhin offen: auch das neue Modell schließt bei 0,35 noch ~9497 % der
    Positionen (es wählt vor allem den BESSEREN Moment, ist also kein wirklich selektives
    Gate). Und die Touch-Zahl bringt im neuen Modell nichts mehr (AUC 0,652 vs 0,654)
    — die dynamische Level-Wahl erfasst denselben Effekt bereits; die User-Idee hat auf
    den Fehler GEZEIGT, die Ursache lag eine Ebene tiefer. B4/B5-Pflicht: Live-AUC in
    ~2 Wochen gegen 0,65 halten (Reminder pbreak_accuracy_v2, 800 Vorhersagen ab 01.08.).
  • P(Trendumkehr) = GEMESSEN, NICHT BERECHENBAR (analyze_reversal.py, 2026-07-31, User-Frage „können wir die Trendumkehr-Wahrscheinlichkeit berechnen?"): Aufgebaut exakt wie das erfolgreiche P(break)-Modell — mechanisch scharfes Barriere-Rennen (erreicht der Kurs zuerst X×ATR GEGEN oder +X×ATR MIT dem Trend?), logistische Regression auf 8 kausalen Merkmalen (Überdehnung · Regressionswinkel · mom3/mom6 · Trendstärke · Trendalter · Abstand zum M30-Gegenlevel · Vola-Regime), Fit auf H1, AUC + Kalibrierung gemessen auf H2. 80k M5-Bars, ~18,3k/18,5k Stichproben. Ergebnis: Münzwurf in JEDER von 5 Ereignis-Definitionen.
    Barriere / Fenster Basisrate AUC oos AUC in-sample
    0,5×ATR / 60 min 54,0 % 0,509 0,521
    1,0×ATR / 120 min 50,8 % 0,506 0,523
    1,0×ATR / 360 min 51,0 % 0,507 0,523
    1,5×ATR / 180 min 49,7 % 0,499 0,530
    2,0×ATR / 240 min 47,8 % 0,501 0,524
    Die diagnostisch wichtigste Zahl ist die IN-SAMPLE-AUC (0,520,53): das Modell
    erklärt nicht einmal seine eigenen Trainingsdaten. Das ist NICHT Overfitting (da wäre
    in-sample 0,70+ und oos bräche ein) — es ist schlicht keine Information vorhanden.
    Einzelmerkmale allein: alle zwischen AUC 0,489 und 0,515. Basisrate ~50 % → der Trend
    hat auf diesen Skalen keine Persistenz. Kleines kohärentes Muster: kurz (0,5×ATR/
    60 min) leichte Mean-Reversion (54 %), lang (2,0×ATR/240 min) leichte Trendpersistenz
    (47,8 %) — aber 24 Pp und unbedingt (das WANN ist nicht vorhersagbar).
    Warum P(break) funktioniert und das hier nicht — die Kern-Lehre: P(break) fragt
    nicht „wohin geht der Kurs", sondern „hält diese konkrete Struktur?" — bedingt auf
    ein reales Objekt (Level mit Orders dahinter). „Trendumkehr" ist die UNBEDINGTE
    Richtungsfrage, überall im Chart gestellt, ohne Struktur zum Festmachen. Genau die
    Klasse, an der das Projekt 18× gescheitert ist. **Die kalibrierte umkehr-nahe Größe
    existiert bereits: stop_approach** (P(break) auf dem Gegen-/Stop-Level, AUC 0,68/
    0,72) — strukturgebunden statt frei schwebend. Kein Modul gebaut.
  • **Wahrscheinlichkeits-Kegel „Erwartete Spanne" (core/cone.py + Kachel #card-cone
    • MT5 CN;…, 2026-07-31): STREUUNG, NICHT RICHTUNG — und out-of-sample kalibriert.** Der User wollte ein „Kursvorhersagemodul, das mögliche Verläufe in MT5 einzeichnet". Eingezeichnete PFADE wurden bewusst NICHT gebaut (suggerieren eine Präzision, die es nicht gibt — die Lehre aus analyze_verdict_calibration.py, wo conf_pct in H2 invertiert war). Stattdessen: wie WEIT der Kurs in 30/60/120 min plausibel gelaufen sein kann. Gemessen (analyze_cone.py, 80k M5, r(h)=(C[i+h]C[i])/ATR[i], Fit auf H1 → Abdeckung gemessen auf H2):
      Band 30 min 60 min 120 min
      80 % nominal 76,7 % 76,6 % 75,3 %
      90 % nominal 87,5 % 87,2 % 86,5 %
      ⚠ Die Bänder sind konsistent ~35 Pp ZU ENG (H2 war relativ zum ATR volatiler).
      Das wird NICHT weggefittet — Kachel und Tooltip nennen die REAL gemessene
      Abdeckung („trifft 77 %"), nicht den Nennwert. Damit ist der Kegel nach dem
      P(break)-Modell die zweite kalibriert geprüfte Komponente im Projekt. Quantile
      final auf allen 80k Bars gefittet (_CONE in core/cone.py; gleiches Vorgehen wie
      beim P(break)-Modell: erst out-of-sample validieren, dann voll fitten), ATR-normiert
      → regime-übergreifend gültig. **Zentriert auf den AKTUELLEN Kurs, KEINE Drift
      addiert** (Median lag bei ±0,0…0,16×ATR = klein gegen die Bandbreite; eine
      Drift-Korrektur wäre eine Richtungsaussage und genau die ist nicht belegt).
      Snapshot cone {atr, price, levels[{minutes,bars,band,lo,hi,coverage}]}; MT5-Export
      CN;<minuten>;<lo>;<hi> (nur 80 %-Band) → Indikator v1.31 zeichnet zwei sich
      öffnende, gepunktete Pfade, verkettet über 30→60→120 (g_coneT/g_coneLo/g_coneHi,
      je Redraw zurückgesetzt; Startpunkt aus der PX-Zeile, die deshalb g_conePx auch
      dann setzt, wenn InpShowPrice aus ist). Farbe neutral grau (InpConeColor) —
      bewusst keine Richtungsfarbe. InpShowCone=false schaltet ab. **Kein Signal, kein
      Verdict-Gewicht.**
  • Kerzen-Anatomie (core/candles.py + Kachel #card-candles, 2026-07-31, User-Vorgabe „Kerzengröße und Dochtlänge … im Kontext"): REINE ANZEIGE — und die Kachel widerspricht bewusst der Lehrbuch-Deutung. Erkennt mechanisch aus M5-OHLCV: Marubozu · Langer Körper · Langer Docht oben/unten · Spinning Top · Doji · Engulfing (Schwellen identisch zum Backtest, damit Anzeige und Messung dieselbe Sprache sprechen); Refresh ~20 s im Trend-Loop unter mt5_lock, Snapshot candle_anat {tf, items[], vol_hot_x}. GEMESSEN (backtest_candles.py, 80k M5, 2 Halbjahre, Forward-Return 60 min): die gängige Deutung ist in BEIDEN Hälften INVERTIERT. ⚠ Methodik-Kern: gerichtete Klassen werden gegen die DRIFT-NULL (bm×E[d]) gelesen, nicht gegen die Baseline — sonst liest man reine Regime-Drift als Edge (H1 war Abwärts-, H2 Aufwärts-Regime). Überschuss-Befunde: „Langer Körper = Fortsetzung" → 0,059/0,076 (Kurs läuft GEGEN die Kerze); „im Trend = Fortsetzung" → 0,132/0,042 (es ist die KLIMAX-, nicht die Fortsetzungskerze); „2× Volumen = echt" → 0,117/0,204 vs 0,065/0,035 bei normalem Volumen (monoton in die falsche Richtung — mehr Volumen = stärkere Gegenbewegung); „Docht am Level zuverlässig" → in BEIDEN Hälften SCHLECHTER als in der Range-Mitte; „mit/gegen Trend" beim Docht kippt (0,102/+0,089) = Rauschen. Folgetest als Handelssignal = ERNEUT VERWORFEN (backtest_candle_fade.py, Live-Exit SL 2,0/Trail 1,5/BE 1,3/Time-Stop 120', Echtkosten): der Fade der Klimax-Kerze fällt durch — Kontrolle (ohne Volumen-Filter) 0,080/0,046; Vol≥2,0 0,059/+0,103; Vol≥2,5 +0,144/0,080; Vol≥3,0 +0,113/0,064 → benachbarte Schwellen exakt gegenläufig = Rauschmuster. Einzige beidseitig positive Zelle (Vol≥2,0+Marubozu +0,036/+0,043) hat n=91/118 bei 7 getesteten Varianten = Mehrfachvergleich-Artefakt. ⚠ Methodisch die wichtigste Lehre des Laufs: Informations-Überschuss ≠ handelbarer Edge. Dieselbe 2,0-Schwelle liefert im Forward-Fenster 0,117/0,204 (also +0,12/+0,20 beim Fade), im echten Trade aber 0,059/+0,103 — die Gegenbewegung ist diffus, der 2×ATR-Stop wird unterwegs getroffen (WR nur 3540 %). Der Weg zum Ziel zählt, nicht nur das Ziel. 18. verworfener Signal-Eingriff.Konsequenz für die UI: die Kachel ist bewusst NEUTRAL gefärbt (keine grün/rot-Ampel) und der Hinweistext nennt die gemessene Lesart („⚠ Klimax-Kerze — der Kurs läuft danach eher GEGEN die Kerze"), nicht die Lehrbuch-Lesart — eine Richtungsampel würde hier systematisch falsch stupsen. Gleiche Korrektur wie bei der Bounce-Anzeige (heißt deshalb „Überdehnung", bernstein statt grün/rot). Kein Verdict-Gewicht, kein Trade-Trigger.
  • Chart-Muster (Doppeltop/-boden) als Signal = VERWORFEN (gemessen backtest_doubletop.py, 2026-07-20, User-Idee „Mustererkennung SKS/Doppeltop"): das am saubersten mechanisch definierbare Umkehrmuster (2 ~gleiche Swing-Pivots + Nackenlinien-Bruch, aus derselben Pivot-Erkennung; Einstieg beim Bruch, Live-Exit, 60k M30-Bars, 2 Halbjahre). ALLE Toleranzen (0,3/0,6/1,0×ATR) fallen durch: WR nur 4045 %, ØR 0,01…−0,15, PF<1; die einzige leicht positive Zelle (H1 tol 0,3 +0,044) kippt in H2 auf 0,150 = Rauschen/ Regime, kein Edge. Deckt sich mit der schwachen Empirie (Lo/Mamaysky/Wang 2000: Effekt klein & kaum handelbar; NY Fed: SKS nicht profitabel; out-of-sample schwach) UND der Struktur-Klasse (Muster = Swings+Trendlinien = die gerade verworfene Klasse). 11. verworfener Signal-Eingriff — am Signal ist nichts zu holen.
  • Konsolidierungs-Setups (False Breakout · Distribution · Accumulation · Retest) = VERWORFEN (gemessen backtest_consolidation.py, 2026-07-30, User-Vorgabe „lerne für die Gesamtempfehlung die Konsolidierungen", 3 Chart-Beispiele): Alle auf DERSELBEN Box wie der validierte Squeeze (10 M5-Bars ≤2,5×ATR), 80k Bars, 2 Halbjahre, Live-Exit + Echtkosten. · A) False Breakout / Liquidity Sweep (Ausbruch kehrt zurück → Gegenrichtung): fällt in JEDER Variante durch (Rückkehr-Fenster 1/2/3 Bars × Live-/Setup-Exit × Session) — H1 durchgehend negativ (0,127…−0,252), H2 leicht positiv = Regime-Kippen. Der Setup-eigene Exit („Stop hinter dem Docht, Ziel = Gegenseite der Range") ist in ALLEN 6 Kombinationen negativ — dieselbe Beobachtung wie bei den SMC-Sweeps und den Chartmustern: der Lehrbuch-Exit trägt nicht, der Ertrag kommt (wenn überhaupt) vom generischen Trailing. ⚠ Wertvoller Nebenbefund: 54 % aller Box-Ausbrüche kehren binnen 3 Bars in die Box zurück — der Squeeze-Ausbruch scheitert also mehrheitlich (deckt sich mit seiner 43 %-Trefferquote). Die Gegenrichtung zu handeln rettet das aber NICHT. · B/C) Distribution/Accumulation (Ausbruchsrichtung aus dem Trend VOR der Box vorhersagbar?): die Basisrate widerlegt es direkt — nur 48 % der Boxen nach Aufwärtstrend brechen nach unten, 52 % bei Accumulation (Zufall = 50 %). „Distribution" sah mit ØR +0,168/+0,270 zunächst tragfähig aus; der KONTROLLTEST (derselbe Vor-Trend, aber Bruch in die GEGENrichtung = Trendfortsetzung) liefert in H2 mit +0,364 sogar MEHR als die Distribution-Hypothese (H1: 0,021). Beide Varianten sind Box-Ausbrüche mit Trailing; welche führt, wechselt mit dem Regime. Kein Richtungs-Edge aus dem Vor-Trend. · Retest-Einstieg (statt beim Bruch am zurücklaufenden Level einsteigen): in BEIDEN Hälften schlechter als der direkte Bruch (Distribution 0,071/+0,010, Accumulation 0,184/0,131) — der Retest kostet den besseren Einstiegspreis. Fazit: nichts davon in die Gesamtempfehlung. Der Squeeze bleibt die einzige validierte Box-Verwertung. 17. verworfener Signal-Eingriff. ⚠ Methodisch wichtig: Der Kontrolltest („trägt die Hypothese mehr als ein beliebiger Ausbruch?") ist genau der, der bei backtest_patterns.py noch fehlt — hier hat er die Idee gekippt.
  • Volume Profile / „Liquiditätslinien" (POC/HVN/LVN, Value Area) = VERWORFEN (gemessen backtest_volume_profile.py, 2026-07-30, User-Frage „System zur besseren Vorhersage — Liquiditätsnachfragelinien / wahrsch. Verkaufslinie?"): Getestet, WEIL es die einzige Klasse mit einer anderen Datenquelle war (nicht „wo war ein Docht" = Pivots/Swings, sondern wo wurde tatsächlich gehandelt = Volumen) — SMC/ICT- „Order Blocks"/Liquidity-Linien selbst sind strukturell Pivot-Zonen und damit dieselbe 5× verworfene Klasse. Aufbau: feste Preis-Bins 0,05 $, rollierendes 24-h-Fenster (288 M5-Bars), Bar-Volumen (tick_volume — CFD liefert real_volume=0) gleichmäßig über [low, high], Value Area 70 %; 80k M5-Bars, 2 Halbjahre, Live-Exit + Echtkosten. Ergebnis: nichts trägt. Am eindeutigsten fällt genau die Kern-Idee durch: Reversion am POC („der Kurs prallt an der Liquiditätslinie ab") ist in BEIDEN Hälften negativ (ØR 0,178/0,121, PF 0,79/0,84, n≈400 je Hälfte) — der POC hält NICHT. HVN-Reversion kippt (0,067/+0,044), LVN-Momentum ist Breakeven-Rauschen (0,031/+0,003). Informations-Test (Teil 1, Forward-Return 2 h ohne Exit/Kosten, relativ zur mid-Baseline gelesen — H1 war Abwärts-, H2 Aufwärts-Regime, absolute Werte sind daher Drift-verzerrt): KEIN Bucket weicht konsistent ab — LVN H1 0,11 / H2 +0,09 relativ, HVN H1 +0,08 / H2 0,06 → beide kippen. Tiefere Einsicht: die Volume-Profile-Position ist ein TREND-PROXY, keine unabhängige Information („außerhalb Value Area" = Ausbruch läuft = folgt dem Regime: H2 +0,304 vs +0,092 in VA, H1 umgekehrt 0,122 vs 0,057) — sie erbt damit exakt die Regime-Anfälligkeit von Momentum/Struktur. 15. verworfener Signal-Eingriff. ⚠ Was BLEIBT: das bereits validierte P(break)-Modell ist die einzige belegt-prädiktive „Liquiditäts"-Aussage im Projekt (AUC 0,71 out-of-sample, kalibriert; ~63 % der Level-Touches prallen ab) — und auch das trägt nur als EXIT, nicht als Entry. Einzige noch ungetestete Klasse wäre echter Order-Flow/L2-Orderbuch (Pepperstone = Market Maker, liefert keins; Hyperliquid hätte l2Book — bräuchte erst wochenlange Datensammlung UND einen Beleg, dass HL-Orderbuch-Signale auf den CFD übertragbar sind).
  • Chartmuster-Kachel #card-patterns (core/patterns.py, 2026-07-27, User-Idee „Visuelle Muster-Erkennung"): REINE ANZEIGE, KEIN Signal. Erkennt mechanisch aus den M30-Swing-Pivots (k=3, wie structure.py): Doppeltop/-boden, Kopf-Schulter/ inverse SKS, Tasse+Henkel/invers (heuristisch), auf-/absteigendes + symmetrisches Dreieck. Je Muster: Richtung (bull/bear/neutral), Nackenlinie/Trigger, Measured- Move-Ziel, Status (bildet sich / bestätigt / ungültig→raus), Güte (Extrem-Symmetrie), Bars-her. Refresh ~30 s im Trend-Loop unter mt5_lock; Snapshot patterns {patterns[], atr, cur}. Nur AKTIVE, kursnahe Muster (2026-07-27, _detect-Filter): abgearbeitete Muster (Ziel bereits erreicht) UND zu weit entfernte (_MAX_DIST_ATR=5,0, Trigger >5×ATR vom Kurs) werden ausgeblendet — sonst zeigte die Kachel alte, nicht mehr handelbare Muster. Grafische Darstellung (2026-07-27, User „grafisch darstellen"): (a) Muster-Karte zeigt je Item eine kompakte SVG-Skizze der Form (_patternSvg, viewBox 56×32, farbcodiert grün/rot/grau) — Form auf einen Blick; (b) im Charts-Tab (M30) werden die 2 stärksten Muster als Preislinien gezeichnet: Trigger = kräftige Linie (grün bull/rot bear, Label „▶ bestätigt"/„◌ bildet sich"), Ziel = gepunktete Linie gleicher Farbe. Dazu liefert get_bars bei M30 jetzt patterns (aus patterns.snapshot). Frontend zeigt Karte + Disclaimer „kein Signal". ⚠ Signal- Einfluss ERST nach Backtest (backtest_patterns.py, noch zu bauen) — die Muster-KLASSE ist bereits 2× als Signal verworfen (backtest_doubletop.py oben + backtest_structure.py), also hohe Beweislast; die Kachel macht das Muster nur sichtbar (was ein Kommentator meint), steuert nichts. v2-Kandidaten (Flags/Wimpel, Rechteck, Rundung) dokumentiert, noch nicht gebaut. Web-Recherche (strike.money, IG, Axi): Umkehr (Doppel-, SKS, Rundung) vs. Fortsetzung (Dreieck, Flag, Tasse); Kursziel stets = Muster-Höhe ab Ausbruch projiziert — überall mit dem Caveat „keine Garantie, nur Indikation". Backtest gebaut & gemessen (backtest_patterns.py, 2026-07-27, 80k M30, 2 Halbjahre, Einstieg beim Trigger-Bruch, Live-Exit+Echtkosten): Mehrere Typen sehen ØR-positiv in BEIDEN Hälften aus (Doppeltop +0,43/+0,23 · Tasse +0,35/+0,26 · inv. Tasse +0,36/+0,58 · aufst. Dreieck +0,16/+0,10). ⚠ ABER das ist ein Exit-Artefakt, KEIN Muster-Edge: die Ziel-Trefferquote (Measured-Move vor SL) ist nur 1338 % — die eigene Muster-Prognose trifft also in ~⅔ der Fälle NICHT. Der positive ØR kommt vom Trailing-Exit auf einem Momentum-Bruch (Trigger-Bruch = Breakout, und Breakout+Trailing hat generisch Edge — s. Squeeze), nicht von der Muster-Vorhersage. Deckt sich mit backtest_doubletop.py (dort mit Ziel-/Fix-Exit → negativ) — der Unterschied ist NUR der Exit. Fazit: NICHT reif für Signal-Einfluss — es fehlt die Kontrolle „generischer Breakout + gleicher Exit" (isoliert den Muster-Beitrag, wie Squeeze vs. beliebige Box); ohne die ist „Muster wirkt" nicht belegt. Muster bleiben reine Anzeige. Ziel%-Spalte = der ehrliche Muster-Check (1338 % = Muster sagen den Kursverlauf kaum voraus).
  • MQL5-Chart-Erweiterungen 2026-07-30 (Indikator v1.16v1.18, alles REINE ANZEIGE): · Trade-Marker TR;<O|C>;<broker_time> — die Kerze der Eröffnung wird HELLGRÜN, die des Close DUNKELGRÜN umrandet (OBJ_RECTANGLE über Bar-Spanne + High/Low, iBarShift → sitzt auf jeder Chart-TF korrekt). Quelle: offene Position (trader.open_time) + die letzten _TRADE_MARKS=6 geschlossenen Trades. · Liquiditätszonen EQ;<H|L>;lo;hi;<broker_time>Equal Highs / Equal Lows aus den M30-Pivots (zwei Pivots innerhalb _EQ_TOL_ATR=0,15×ATR, 240 Bars auseinander) als goldenes Band + gestrichelte Kante, nach rechts verlängert (Darstellung nach User-Referenzbild). Berechnung in wave_rec (_liq_zones, Snapshot liq_zones), Mindesthöhe _EQ_MIN_H_ATR=0,10×ATR. ⚠ Als SIGNAL gemessen und verworfen (backtest_liquidity_sweep.py) — nur Kontext. · Aktueller Kurs PX;bid — fett oben rechts (OBJ_LABEL, CORNER_RIGHT_UPPER, Arial Black, InpShowPrice/InpPriceSize/InpPriceColor). · ⚠ Zwei Fallen beim Pfeil-Bug („Pfeile werden nicht angezeigt", v1.17): (1) ANCHOR_LEFT ist für OBJ_ARROW UNGÜLTIG — erlaubt sind nur ANCHOR_TOP/ ANCHOR_BOTTOM; (2) die Pfeile sitzen rechts NEBEN der letzten Kerze → ohne CHART_SHIFT=true gibt es dort keinen sichtbaren Bereich. Beides im Theme/ Handler behoben. · ⚠ Blink-Fix in core/hl_walls.py („Pfeile blinken nur manchmal auf"): bei einem Fehlschlag (HTTP-Timeout, HL-Server kurz busy) wurde der Cache auf None gesetzt → LQ-Zeilen fehlten in der CSV → der Indikator löschte die Pfeile beim Redraw. Jetzt wird der letzte gute Stand _STALE_GRACE_S=120 s weitergereicht; erst danach verschwinden die Pfeile (echter Ausfall).
  • Kurslücken-Kachel (#card-gaps): offene D1-Gaps des laufenden Jahres (gaps.GapAnalyzer, Refresh ~10 min im Trend-Loop unter mt5_lock). Je Gap: Richtung, Zone, Fill-Level, Abstand zum Kurs. Die Fill-Level fließen als S/R-Magnete in _sr_levels → damit in die Wellen-Konfidenz (set_sr_context, _SR_BONUS/_SR_PENALTY), Close-Alarme und Verdict-Kontext — und so indirekt in den Autotrader (der auf die Welle hört). Keine eigene Handelsrichtung. Snapshot gaps. Mess-/Einzeltool: find_gaps.py.
    • Gap-Magnet als Handelssignal = VERWORFEN (gemessen, backtest_gaps.py): Signale WEG vom nächsten offenen Gap haben +0,094 Ø-Edge, ZUM Gap nur +0,014 — der Magnet zieht NICHT (das Gap blieb offen, weil der Trend von ihm weglief). „Richtung Gap handeln" wäre schädlich; „weg" ist nur Trendbestätigung (macht die Welle schon). Gaps bleiben reiner Kontext.
  • Tagesziele — Dashboard-Kachel ENTFERNT (2026-07-13): Das Frontend zeigt die Web-Prognose nicht mehr. Das Modul daily_levels läuft unverändert weiter: die Level fließen als S/R-Kandidaten in _sr_levels (Anzeige/Close/Verdict-Kontext) und in den 07:30-Tagesreport. snapshot.daily_levels bleibt befüllt (nur ohne UI).
  • Täglicher Report (07:30 Berlin, engine._send_daily_report): Web-Prognose + Vortags-Bilanz (stats_overview("yesterday")) → Telegram-Push + E-Mail (via mailer.send_graph_mail, [graph]-Creds, Absender [graph] sender= mailagent@hocks.eu). Empfänger: [graph] report_to (kommagetrennt, Default trading@hocks.eu, axel@hocks.eu). Ersetzt scripts/send_daily_report.ps1 (das hier nie lief — Microsoft.Graph-PS-Modul fehlt; Python nutzt Graph-REST direkt). ⚠ Graph/Exchange-Zustellung kann mehrere Minuten verzögert sein (202 = nur angenommen). Fail-safe: kein Provider/Graph → Report übersprungen. Versand-Status persistiert (report_state.json, _load/_save_report_state) — vorher schickte jeder Server-Neustart nach 07:30 den Report ERNEUT (real 3× am 07.07.); gilt für Tages- UND Wochenreport.
  • B4-Wochenreport (automatisch, engine._send_weekly_report): montags ab 07:30 Berlin, 1×/Woche (gleicher _daily_loop, _weekly_last_run=(ISO-Jahr,KW)) → E-Mail + Telegram. Ruft weekly_review.build_report(m5=…) (Live-Stats vs. Backtest-Erwartung, Leckage-Flags — Track B/B4) und schickt es als <pre> (Betreff „Oil Wochenreport (B4) — KW…", Empfänger = [graph] report_to). Squeeze-Breakout- B4-Monitor (_squeeze_section): rechnet die Squeeze-Regel mit den Live-Params auf den letzten ~30 Tagen M5 NEU (mechanischer Setup → Live-Perf. = Neuberechnung, keine Trade-Attribution nötig) und hält ØR/PF gegen +0,14…+0,23. M5-Bars holt die Engine unter mt5_lock und reicht sie durch (build_report(m5=…); standalone lädt via _fetch_m5, schließt MT5 nur bei Eigen-Init). Fail-safe wie der Tagesreport. Manuell jederzeit: python weekly_review.py.
  • Position-Kachel zeigt SL/TP + Einsatz (pos-sl/pos-margin; trader.snapshot() liefert sl/tp/margin). Kopfzeile der Kachel (.pos-top, 2026-07-15, User-Vorgabe): Kurs · G/V in EINER Zeile (18-px). Das G/V (#pnl) zeigt NUR NETTO (Brutto entfernt, kein „n."-Präfix): bei Gewinn P&L × (1 [trading] wht_pct/100) = abzgl. WHT-Quellensteuer, bei Verlust unverändert (keine Steuer). Snapshot wht_pct; Tooltip nennt den Satz. Swap ist bereits im P&L (trader.pnl = profit + swap), Kommission beim Standard-Konto 0. Einsatz/SL/TP/Richtung stehen in der Trade-Leiste, S/R im Chart (aus der Kachel entfernt); emg-lbl-Beschriftungen ausgeblendet (Felder self-labeln via Platzhalter/Button-Text). Fehlender SL → rot „⚠ kein SL gesetzt!". „Einsatz" = gebundene Margin (order_calc_margin). Notfall-Stop- Feld (#emg-input + setzen/aus): manueller Verlust-Wert → Server schließt sofort (s. „Notfall-Stop"). Feld wird mit aktivem bzw. gemerktem Wert (emergency_loss/emergency_remember) vorbefüllt (außer beim Tippen); Enter/„Go" löst „setzen" wie der Button aus. Status #emg-state: „aktiv: schließt bei −…" (rot) bzw. „vorgemerkt −… (aktiv beim Öffnen)". Gewinn-Feld („Gewinn mitnehmen bei") aus dem Dashboard ENTFERNT (User-Vorgabe 2026-07-14) — das Backend bleibt vollständig erhalten (engine.set_takeprofit, kombinierter _check_auto_close, POST /api/takeprofit, Telegram „💰 Gewinn mitgenommen", Config [trading] auto_takeprofit Default 0=aus), ist ohne UI aber schlafend; der P(break)-S/R-Auto-Close übernimmt die Gewinnmitnahme-Rolle.
  • Blinken: LONG/SHORT-Button blinkt bei jeder Richtungs-Empfehlung (nicht mehr an 70 % gekoppelt). Ton bei Empfehlung (beepRecommendation): sofort beim Signal-Wechsel (WARTEN→LONG/SHORT oder Flip, 3-s-Flacker-Schutz) + Erinnerungs- Ton alle 30 s (_REC_REBEEP_MS), solange der Button blinkt — nur wenn flat (keine Position). LONG = aufsteigend, SHORT = absteigend (unterscheidbar vom Close-Alarm). Audio erst nach 1× Nutzer-Tap aktiv — ist es noch gesperrt, zeigt ein einmaliger Toast „🔇 Ton gesperrt — einmal tippen". Kein Ton bei offener Position. Mute-Button (#mute-btn, 🔊/🔇 rechts in der Tab-Leiste) schaltet ALLE Töne (Gate in _tone + beiden beep-Funktionen), persistiert via localStorage("oil_muted"). CLOSE blinkt + Ton NUR wenn pnl > sr_close_min_gain (Feld leer/0 → pnl>0 wie bisher; deckt sich mit dem Auto-Close-Gate — unter der Schwelle schließt der Bot ohnehin nicht, also auch kein Alarm; Frontend gainOK, gilt für Flip-Close UND S/R-Close-Blink/Ton). Der Telegram-Flip-Push (_check_close_ alert, Backend) bleibt bei pnl>0. Flip-Close = Signal-Flip gegen die Position. S/R-Ziel-Close-Hinweis ENTFERNT (stupste zum verfrühten Gewinner-Kappen → Verlust-Schiefe; Gewinner führt das Trailing). Bei Verlust-Trade: kein Close-Alarm. Jeder echte Auslöser loggt 🔔 Flip-Close-Alarm #N + Zähler snapshot.close_alert_count (zum objektiven Nachzählen, statt aus Trades/Recs zu rekonstruieren). Engine: _check_close_alert (Telegram max. 1×/5 min, _CLOSE_ALERT_COOLDOWN_S — kein Spam, wenn der Kurs ums Level pendelt). ⚠ Cooldown ist ticket-basiert (_close_alert_ticket): Reset NUR bei echter neuer Position; ein kurz flackerndes Ticket (transient leeres positions_get) setzt den Cooldown NICHT mehr zurück (war die Spam-Ursache). Frontend: flipClose || srTarget. Kein Auto-Close an S/R (Backtest).
  • Trade-Abschluss-Telegram ENTFERNT (history.log_trade_close sendet kein Telegram mehr; Import bereinigt). Close-bezogene Telegrams kommen jetzt nur noch aus der Engine: 🔔 CLOSE-Signal (echter Signal-Flip, _check_close_ alert) + 🚨 Notfall-Close / 💰 Gewinn-Close (armierter Auto-Close, _check_auto_close). Frontend-Blink/Ton weiterhin nur bei Flip im Plus.
  • Order-Bestätigungen: Kein hartes Blockieren mehr. Eröffnen bei WARTEN/Gegen- Signal → Hinweis-Dialog „trotzdem eröffnen?" (überschreibbar). CLOSE bei negativem P&L → Sicherheitsabfrage; im Plus/Breakeven direkt. Sonst keine Token-Dialoge (require_token=false). Audio braucht 1× Nutzer-Tap.
  • Asset-Version aktuell v=126 (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 — die wurden zuerst übersehen, weil das erste Bump-Skript nur font-size erfasste)
    • Chart-fontSize in app.js. Bei künftigen globalen Font-Änderungen die Shorthand nicht vergessen.

Web-API (server.py)

GET /api/snapshot (inkl. verdict-Aggregat) /api/health /api/logs /api/stats /api/news /api/bars?tf=&n= (Charts, read-only) /api/squeeze_monitor (B4-Monitor, read-only, Engine-Cache 60 s) · WS /ws · POST /api/order|auto|trail|emergency|takeprofit|sltp|srclose|srclose_min|autosqueeze|autosignal|auth/check. /api/sltp {sl,tp} = manuelles SL/TP der offenen Position → engine.set_sltptrader.modify_sltp (TRADE_ACTION_SLTP, prüft Seite/Mindestabstand) und deaktiviert das Trailing (trail.deactivate — sonst zöge es SL/TP beim nächsten Tick zurück, User-Vorgabe). ⚠ Extern-Erkennung (Fix 2026-07-17): Setzt der User SL/TP direkt im MT5-Terminal (nicht über die App), greift deactivate() nicht — das Trailing überschrieb die Handeingabe (real: TP 90,000 → 81,484). trailing._do_modify vergleicht jetzt den Broker-SL/TP mit dem zuletzt selbst gesetzten (_last_sl/_last_tp, tol = Modify-Schwellwert): weicht er ab → Trailing schaltet sich ab, Handeingabe bleibt stehen (Log „Manuelle SL/TP-Änderung erkannt"). _last_sl/_last_tp werden bei Aktivierung genullt (kein Altwert-Fehlalarm); Erkennung erst ab dem 2. Modify. Token via [web] api_token; bei require_token=false ist die Token-Pflicht aus (Zugang nur via WireGuard).

  • Snapshot-Cache: /api/snapshot UND /ws liefern engine.snapshot_cached() (TTL _SNAP_TTL_S=0,8 s) — EIN berechneter Snapshot wird über alle Geräte geteilt, SQLite/Verdict-Last bleibt unabhängig von der Client-Anzahl.
  • WS-Wakeup nach Sperrbildschirm/Hintergrund (Fix 2026-07-22, User-Meldung „G/V großer Lag"): Backend-Pipeline ist schnell (_pos_loop 1 s · Snapshot-Cache 0,8 s · WS-Push 1 s; gemessen: MT5-Lock-Last selbst im Worst-Case nur ~25 ms, 0 Lock-Timeouts/_pos_loop-Fehler im Log) — die Ursache lag im Frontend: mobile Browser pausieren WS+Timer beim Sperren/Backgrounding, ohne visibilitychange-Handling zeigte die Seite bis zu einem zufälligen Reconnect den STALEN Stand (Minuten alt). Fix: visibilitychange/pageshow/focus-Listener (_wakeRefresh in app.js) holen beim Zurückkommen sofort einen frischen REST-Snapshot UND bauen die WS-Verbindung hart neu auf (statt auf den evtl. hängenden alten Socket zu warten). REST-Polling als Sicherheitsnetz (2026-07-22, User-Wunsch „JSON-Feed"): zusätzlich zum WS-Push pollt app.js alle POLL_MS=4000 ms /api/snapshot — fängt den Fall auf, dass der WS still hängt (kein onclose, keine Zustellung mehr, z. B. schwaches WireGuard-Signal) OHNE auf einen Reconnect zu warten; pausiert bei document.hidden (Akku/Daten). lastTs-Dedup (_applySnapshot, vergleicht engine.snapshot_cached().ts — dieselbe Quelle für WS UND REST): nur die jeweils NEUERE Quelle rendert → kein Flackern/Doppel-Render, wenn beide fast gleichzeitig eintreffen. Alle Snapshot-Konsumenten (initialer Load, Wake-Refresh, Poll, WS) laufen jetzt über _applySnapshot statt direkt render. v=108. GET /api/snapshot ist ohnehin öffentlich/token-frei nutzbar — externe Tools (Shortcuts, Home Assistant, …) können ihn direkt pollen.

⚠ Deployment-Drift — die strukturelle Schwachstelle (2026-07-31)

Track B schützt gegen OVERFITTING (ein Edge existiert gar nicht). Es schützt nicht gegen DEPLOYMENT-DRIFT: ein real existierender Edge wird unter anderen Bedingungen BETRIEBEN als VALIDIERT. An EINEM Tag wurden drei Fälle gefunden:

# Komponente Gemessen unter Betrieben unter Schaden
1 P(break) Anlauf zu fixiertem Level dynamisch gewähltes Level AUC 0,715 → 0,368
2 breakout_k=0,3 feste Zeitebene TF wechselt 33×/Tag, löscht den Anker 43 % → 93 % WARTEN
3 Trailing mult 1,5 1,53,0 je nach TF H1 ΣR 249 → 1367, Worst 1,50 → 2,50

Keiner wäre durch MEHR Backtesting gefunden worden — die Backtests waren korrekt. Ursachen (strukturell): (a) Backtests sind NACHBAUTEN, keine Nutzer des Live-Codes (sim_run/_ema_series/_atr_series liegen in ≥6 Skripten als Kopie); (b) es gibt Live-only-Gates, die kein Backtest modelliert (Entry-Raum, EIA, Dead-Hours, News-Blackout, Cooldowns, Startup-Grace); (c) Live-Parameter sind kontextabhängig (Trail-mult je TF, SL-ATR fix M15, TF selbst per Heuristik), Backtest-Parameter konstant; (d) es gab keine Telemetrie über die Entscheidung selbst.

Behebung in 3 Stufen (User-Entscheidung 2026-07-31):

  • Stufe 1 — ERLEDIGT: _MULT_BY_TF auf durchgehend 1,5 und _MULT_BREAKOUT_ADD auf 0,0 (core/trailing.py) — der einzige gemessene Wert. ⚠ BEGRÜNDUNG NACHTRÄGLICH KORRIGIERT (beim Stufe-3-Refactor): die zuerst genannte „67 % größerer Einzelverlust" war ein Artefaktbacktest_trailing.py setzt den Initial-SL auf mult×ATR statt fix 2,0, dort war der Worst-Case also per Konstruktion gleich dem Multiplikator. Sauber nachgemessen mit fixem SL (backtest_trailmult.py, core/exit_model.py, 80k Bars, 2 Halbjahre):
    Trail H1 ΣR H2 ΣR Worst
    1,0 73 +1346 2,00
    1,5 (live) 325 +1294 2,00
    2,0 446 +1195 2,00
    2,5 1174 +1223 2,00
    3,0 1088 +1397 2,00
    Der Worst-Case ist bei JEDEM Multiplikator identisch 2,00 (der SL deckelt).
    Die Entscheidung bleibt richtig: 1,5 schlägt 2,0 UND 2,5 in beiden Hälften.
    **➜ TRAIL AUF 1,0 GESETZT (User-Vorgabe „setze alle Vorschläge um", 2026-07-31),
    in core/exit_model.py (LIVE.mult), live verifiziert (AKTIVIERT … mult=1.0x).**
    Voller Sweep (backtest_trailmult.py, fixer SL 2,0, 8 Werte 0,53,0): **enger ist
    MONOTON besser** — Wave-Signal H1/H2 ΣR: 0,5 +1258/+2418 · 0,8 +852/+1668 ·
    1,0 +80/+1360 · 1,5 220/+1305 · 2,0 394/+1198 · 2,5 1072/+1327.
    Optimum am RAND des Suchbereichs = Warnsignal („misst man besser oder nur
    weniger?"). Gegentest auf SQUEEZE-Entries mit Echtkosten (--squeeze) — das
    Setup lebt von LÄUFERN, müsste also dagegenhalten: tut es nicht, auch dort ist
    enger monoton besser (1,0: H1 0,202/H2 +0,010 · 1,5: 0,219/0,032). Deshalb der
    Schritt auf 1,0 — besser als 1,5 in beiden Hälften auf beiden Signalmengen —
    aber nicht auf 0,5 (Randwert). ⚠ Zweiter Grund gegen 0,5: die Sim modelliert
    keine Exit-Slippage; ein engerer Trail löst viel häufiger aus und ist stärker
    betroffen (real gemessen bis 0,75×ATR über den Stop hinaus).
  • Stufe 2 — ERLEDIGT: Entscheidungs-Telemetrie. (a) Jede Empfehlung loggt jetzt einen maschinenlesbaren block_reason (recommendations.block_reason, DB migriert mit Backup): deadband · dead_hour · eia · htf_counter · stretch · min_conf · breakout_pending · entry_room · no_data · stale; NULL = kein Block. Ohne den war nicht feststellbar, WELCHES Gate die 93 % erzeugt. (b) analyze_ divergence.py hält vier Dinge gegen die Backtest-Erwartung: A Signal-Verteilung (Soll ~43 % WARTEN), B Gate-Anteile inkl. Kennzeichnung „im Backtest modelliert?", C TF-Wechsel-Rate (Soll: Median ≥15 min), D0 Modell-Kalibrierung (Ø-Vorhersage vs. echte Rate) und D Merkmals-Drift gegen _PB_MU/_SD. ⚠ Lehre aus dem Bau selbst: die Merkmals-Drift (D) hätte den realen Fehler NICHT gefangen — mom3 lag nur 0,50σ unter µ, bei Gewicht 1,43 wurden daraus aber 0,71 im Logit (23 % statt 41 %). Deshalb ist D0 der schärfere Test und die D-Schwelle auf 0,5σ gesetzt. Erster Lauf nach dem Fix: D0 zeigt 27,0 % vorhergesagt vs. 28,0 % real (vorher 23 vs 41) — die Reparatur ist damit live bestätigt.
  • Stufe 3 — ERLEDIGT (core/exit_model.py): geteilter Exit-Kern. Enthält LIVE: ExitParams (sl 2,0 · trail 1,5 · start 0,3 · be 1,3 · lock 3,5/0,6/1,2 · timestop 24 · tp 3,5 · max_hold 200) als einzige Quellecore/trailing.py importiert sie jetzt von dort (_TRAIL_START_ATR, _BREAKEVEN_ATR, _PHASE4_*, _MULT_BY_TF sind abgeleitet, keine eigenen Zahlen mehr). Ändert jemand LIVE.mult, ändern sich Live-Verhalten UND Messung gemeinsam → Fall 3 ist konstruktiv unmöglich geworden. Dazu die kanonische simulate() für Backtests, mit Flags timestop/use_tp, um Teilmodelle EXPLIZIT zu machen statt zu verstecken. ⚠⚠ BEFUNDE BEIM REFACTOR — schlimmer als angenommen: (1) Es gibt mindestens DREI materiell verschiedene Exit-Modelle in den Backtests: (A) Phasen-Modell ≈ live (_trailing/_exit/_atrfloor/_candle_fade) · (B) EINFACH_TPTRAIL=0.5, kein Breakeven, kein Lock, kein Time-Stop, _MAXH=240 (_hourly, _hourly_split, _bounce, _events, _deadhour, _chopgate) · (C) Phasen mit be_on=1.0 statt 1,3 (_breakout, _confluence_angle). ⇒ Mehrere dokumentierte Befunde (Dead-Hours, EIA-Blackout, Bounce, Chop-Gate, Stunden-Analyse, breakout_k) ruhen auf einem Exit, der dem Live-System NICHT entspricht. Bewusst NICHT stillschweigend umgestellt — das würde historische Schlüsse rückwirkend ändern; markiert als LEGACY_SIMPLE / LEGACY_BE10 in exit_model.py, Neubewertung = eigene Entscheidung. (2) Selbst die „Phasen"-Skripte weichen voneinander ab: _trailing hat TP aber keinen Time-Stop, _candle_fade Time-Stop aber kein TP, _atrfloor liefert Punkte statt R. Live hat BEIDES → nur timestop=True, use_tp=True ist live-treu. (3) backtest_trailing.py koppelt den Initial-SL an mult (sl = entry d*mult*atr) — dadurch war die Stufe-1-Begründung teilweise falsch (s. o.). Äquivalenz verifiziert (500 synthetische Zufalls-Kursreihen je Fall): _candle_fade (timestop=True, use_tp=False) und _atrfloor (timestop=False, use_tp=True, ×ATR) sind bitgenau identisch zur neuen simulate(). Migrations-Regel (in exit_model.py festgehalten): ein Backtest darf nur auf simulate() umgestellt werden, wenn er danach DIESELBEN Zahlen liefert — sonst ist es keine Refaktorierung, sondern eine unbemerkte Änderung der Messgrundlage. LEGACY-RECHECK (backtest_legacy_recheck.py, 2026-07-31): die beiden Befunde nachgerechnet, die live ECHTE Gates steuern. · EIA-Blackout BESTÄTIGT — auch mit dem echten Exit + Echtkosten ist das Fenster Mi 15:3016:30 in BEIDEN Hälften schlechter als der Rest (ØR-Differenz 0,097 / 0,119). Das aktive Gate ist gedeckt. · DEAD-HOURS reproduzieren NICHT als selektiver Befund — mit dem echten Exit sind 19 von 22 Stunden in BEIDEN Hälften negativ, es gibt keine robust positive Stunde. Die alte Analyse hatte 07 sowie 12 und 16 als die schlechten Stunden herausgehoben; wenn fast alles negativ ist, ist diese Auswahl nicht mehr gestützt. (Praktisch folgenlos, weil dead_hours ohnehin leer ist — aber eine Reaktivierung auf der alten Begründung wäre nicht gedeckt.) · ⚠ BOUNCE/Reversal — relative Aussage hält, absolute NICHT. Reversal schlägt Trend in BEIDEN Hälften (H1 0,034 vs 0,174 · H2 +0,029 vs 0,073, also +0,140/+0,102) — robust. Aber die dokumentierte Kennzahl „ØR +0,185 · PF 1,35 · 70 % Treffer" REPRODUZIERT NICHT: mit echtem Exit + Echtkosten liegt das Setup bei ~Breakeven (PF 0,93/1,06). Die alten Werte stammen aus dem vereinfachten Exit OHNE Kosten. Das Setup bleibt sinnvoll als nachrangiges, markiertes Zweitsignal (so ist es live auch eingebaut), aber es ist kein +0,185-Ertragsbringer. · ER-CHOP-GATE — Ablehnung BESTÄTIGT. Alle vier ER-Bänder liegen gleichauf (H1 0,137…−0,172 · H2 0,049…−0,067); die Efficiency Ratio trennt auch mit dem echten Exit nicht. Gate bleibt zu Recht verworfen. ⚠ Einschränkung des Rechecks (selbst benannt): er handelt die ungegatete EMA-Richtung — ohne Mindest-Konfidenz, Breakout-Bestätigung, HTF-Filter und Raum-Gate. Für den VERGLEICH (Fenster gegen Rest, Stunde gegen Stunde) ist das neutral, die absoluten Werte sind aber NICHT das Live-Signal. ⚠ Konsequenz für die Erfolgskontrolle des TF-Churn-Fixes: „WARTEN-Anteil Richtung 43 % bewegen" ist als Zielgröße mit Vorsicht zu lesen — die 43 % stammen aus backtest_dist.py (Signal-HÄUFIGKEIT), sie sind kein Ertragsversprechen. Mehr Signale sind nur dann besser, wenn die freigegebenen Setups auch tragen.

Erwartung: die drei Fälle sind nicht vollständig. Sie wurden bei gezielter Suche in ~20 min gefunden; die Trefferquote spricht für weitere. analyze_divergence.py regelmäßig laufen lassen (Kandidat für den Wochenreport).

Ausstehende Messungen — Erinnerung per Timer

measurement_reminder.py + Windows-Task OilMeasurementReminder (täglich 18:00) meldet per Popup, welche Messung genug Daten hat. Jeder Punkt hat eine PRÜFBARE Fälligkeitsbedingung (Datenmenge/Datum), nicht nur ein Datum — gemeldet wird je Punkt 1× (Marker in .reminders/, gitignoriert; Marker löschen = Wiedervorlage). Status jederzeit: python measurement_reminder.py --status.

Warum es das gibt: mehrere Module sammeln still Daten für „später" — und das blieb liegen. Die P(break)-Prognose-Genauigkeit war seit 2026-07-23 auswertbar und hatte am 2026-07-30 bereits 2213 ausgewertete Zeilen, ohne dass jemand hinsah.

Messung Bedingung Stand 2026-07-31
P(break) erneut auswerten (nach Nachtraining) ≥800 Vorhersagen ab 01.08. 0
Modul-Audit: zweiter Durchgang ≥28 Tage seit dem 1. Audit 1 (2 %)
Verdict-Module auf Prädiktivität (verdict_votes) ≥25 000 Verdicts 7184 (29 %)
Auto-Signal-Entry B4/B5 ≥20 AUTOSIG-Trades 3 (15 %)
M30-Level-Umstellung live gegenprüfen ≥30 S/R-Closes seit 30.07. 13 (43 %)
M1-Squeeze Variante B ≥180 Tage candles_m1 14 (8 %)
News-Score-Prädiktivität ≥90 Tage Sammlung 8 (8 %)

(erledigt und ausgetragen: P(break)-Genauigkeit → analyze_pbreak_live.py 31.07., Modell daraufhin nachtrainiert · Chartmuster-Kontrolltest → 30.07., Muster schlagen die Kontrolle in beiden Hälften, Gewicht 1,0)

Der Task OilMeasurementReminder wurde am 2026-07-31 testweise ausgelöst und lief mit Ergebnis 0 durch (Arbeitsverzeichnis korrekt gesetzt) — ein Erinnerungs- system, das still scheitert, wäre schlimmer als keins.

Verwandte Timer: HyperliquidBookflow (Order-Flow, 2 Stufen ~3 Tage/~2 Wochen), HyperliquidLeadLag (erledigt: Pepperstone führt), Wochenreport montags 07:30 (B4).

WTI-Trading-Handbuch — Abgleich mit dem Gemessenen (2026-07-30)

Der User reichte ein 19-seitiges WTI-Handbuch ein („lerne daraus Kontext für die Empfehlung"). Ergebnis des Abgleichs: der belegbare Teil ist längst umgesetzt, der Rest ist in diesem Projekt bereits gemessen — und fiel durch. Kein Konzept aus dem Handbuch wurde neu ins Signal aufgenommen.

Bereits UMGESETZT (Handbuch bestätigt den Ist-Zustand):

Handbuch im Bot
„Nur mit dem HTF-Trend" M30-Gegen-Trend-Filter (gemessen: Edge ×2) + Entry-Checkliste
„Keine Trades vor EIA" EIA-Blackout Mi 15:3016:30 (gemessen: beidhälftig negativ)
ATR-basierter Stop + Puffer Initial-SL-Band 1,82,2×ATR (gemessen besser als 1,5)
„Nach TP1 trailen" Trailing 1,5×ATR + Breakeven 1,3 (gemessen optimal)
„Nach 3 Losses Pause" Mental-Check in der Entry-Checkliste (Verlust-Serie des Tages)
Journal + Kennzahlen trades-DB, Statistik-Tab, Wochenreport (WR/PF/Verhältnis)
NY-Session am besten gemessen: 2122 Uhr sind die einzig robust positiven Stunden

Bereits GEMESSEN und VERWORFEN (Handbuch empfiehlt es trotzdem): Liquidity Sweeps (Equal Highs/Lows) · Order-Block-Klasse = Pivot-Zonen (6×) · Double Top/Bottom · H&S/Triangle/Flag/Cup (Ziel-Trefferquote nur 1338 %) · Wyckoff Accumulation/Distribution · False Breakout · DXY-Korrelation (backtest_intermarket.py) · Elliott (nur Verdict-Stimme, Gewicht 1,0).

NEU gemessen (die echten Lücken, backtest_handbook.py) — alle durchgefallen:

Konzept H1 H2 Urteil
PDH/PDL Bounce („WTI reagiert extrem stark") 0,335 0,199 beidseitig negativ
PDH/PDL Sweep 0,462 0,184 schlechtestes Ergebnis überhaupt
Asian Range H/L Bounce 0,134 0,005
Asian Range H/L Sweep 0,178 0,040
Discount/Premium-Filter 0,097 (Basis 0,135) +0,041 (Basis +0,053) nicht robust, wirft 70 % Volumen weg
Freitag ab 16:00 CET meiden 0,179 (Basis 0,135) +0,020 (Basis +0,053) verschlechtert BEIDE

⚠ Zwei Befunde sind bemerkenswert: (a) PDH/PDL ist der am klarsten schädliche Level-Typ, den das Projekt je gemessen hat — obwohl das Handbuch ihn als besonders stark bewirbt. (b) Der Freitagnachmittags-Filter verschlechtert beide Hälften, die dort geblockten Trades waren also überdurchschnittlich — dieselbe Lehre wie beim Dead-Hours-Gate: pauschale Zeitfilter kosten mehr, als sie sparen.

Nicht umgesetzt (bewusste User-Entscheidungen, nicht Messfrage): 12 % Risk/Trade und 3 % Tages-Limit (User fährt 95 % Margin, Circuit Breaker am 2026-07-30 erneut abgelehnt) · Mindest-R:R 1:2 (der Bot nutzt Trailing statt festem Ziel — gemessen besser) · Teil-Exit bei 1:1 (_PARTIAL_TP_FRAC=0, User-Vorgabe).

Auch beachten

  • Startup-Schonfrist gegen Sofort-Close nach Neustart (User-Vorgabe 2026-07-20, [trading] startup_close_grace_s=60): In den ersten 60 s nach Bot-Start schließt der Bot keinen laufenden Trade selbst — gilt für S/R-Close (_check_sr_close), Notfall-Stop/Gewinn-Ziel (_check_auto_close, Armieren läuft weiter, nur der Close ist gesperrt), Time-Stop (trailing, via set_no_close_until) und Auto-Squeeze- Reverse. Grund: nach restart_server.bat sind Preis/ATR/P(break)/Level für einen Moment instabil → ein adoptierter Trade, der gerade in S/R-Close- oder Notfall-Nähe liegt, würde sonst in der ersten Sekunde auf halb-initialisierten Daten gekappt. Engine setzt _no_autoclose_until = start + grace, _in_startup_grace() gated die drei _pos_loop-Checks; die Trailing-Instanz bekommt denselben Stichtag. ⚠ Der Broker-SL (2×ATR) bleibt unberührt — er läuft am Broker, kann NICHT verzögert werden (dort ist auch keine Verzögerung erwünscht: ein Stop-Loss muss greifen). 0 = aus.
  • Update-Reboot-Lücke (Root-Cause der Nacht 2026-07-20, 95,48 €): Windows Update rebootete 01:30 (MoUsoCoreWorker/TrustedInstaller, 2×), der Server-Task OilTradingServer hat nur einen Logon-Trigger → Server+MT5 down bis zum Login 07:42; Time-Stop/S/R-Close/Notfall-Stop liefen nicht, nur der Broker-SL (broker-seitig!) schützte. Fix: WU-Policy AUOptions=4, Tag=Sa, 03:00 (HKLM...\WindowsUpdate\AU — Reboots nur noch Samstag früh, Markt zu); Standby/ Hibernate AC+DC=0. ⚠ Offen: nach einem Sa-Reboot startet der Server erst beim nächsten Login — Auto-Logon (netplwiz) wäre die letzte Lücke (So-Nacht-Open), braucht das Windows-Passwort des Users. Server-seitige Schutzschichten sind nur so gut wie die PC-Laufzeit.
  • UI-Einstellungen neustart-fest (runtime_state.json, 2026-07-19): App-gesetzte Werte — 🚀-BRK-Toggle (auto_squeeze), Auto-Close-Schalter (auto_sr_close), Gewinn-Close-Mindestgewinn (sr_close_min_gain) — werden bei jedem set_* atomar persistiert (_load/_save_runtime_state) und überschreiben beim Start die ini-Defaults (nur vorhandene Keys). ⚠ set_sr_close_min_gain vergaß den _save bis 2026-07-22 (Bug, jetzt gefixt) — der am Handy gesetzte Mindestgewinn überlebte Änderungen nicht sauber; zusätzlich schickte Enter auf leerem Feld ungewollt 0 (change+keydown doppelt → Enter blurrt jetzt nur, srclose_min-Endpoint loggt [WEB]).
  • Log-Hygiene: Trail-DEBUG-Zeile (Trail: profit=…) auf 1×/30 s gedrosselt (2026-07-19; vorher ~28k Zeilen je Rotation → 5×5 MB deckten nur ~2 Tage Forensik).
  • DB-Guard: history.log_trade_open verwirft 0-Lot-/Preis-lose Einträge (Reconcile-Artefakte; 6 Alt-Zeilen am 2026-07-19 bereinigt, Backup oil_widget_history.db.bak-2026-07-19).
  • Persönliches Auto-Memory unter C:\Users\ah\.claude\projects\…\memory\ (Beobachtungen/Feedback) ergänzt diese Datei.
  • oil_widget_config.ini enthält Live-Secrets (Keys/Token) — nicht ins Repo/Logs leaken.
  • DB oil_widget_history.db (trades · intended_trades · recommendations · candles_m1 · pbreak_predictions · verdict_votes). Vor jedem Eingriff Backup (*.bak-<datum>); Zeitspalten sind lokale Epoch (Broker-Offset bereits korrigiert) — AUSNAHME candles_m1.time = ROHE Broker-Zeit (UTC+3), deckungsgleich mit copy_rates.
  • M1-Candle-Logger (core/candle_logger.py, 2026-07-21, Daten-Sammlung, kein Strategie-Eingriff): schreibt abgeschlossene M1-Kerzen (OHLC + Spread-in-Preis + tick_volume + symbol) nach candles_m1 (PK time, INSERT OR IGNORE = dedupliziert, self-healing). engine.candles.log(sym) im Trend-Loop, self-throttled ~55 s; erster Lauf backfillt ~3000 Bars, danach die letzten 180. Warum: Broker-M1-History rollt weg (kurz); M1 ist die Master-Auflösung → aus M1 jede höhere TF exakt aggregierbar. ⚠ Ticks/Echtzeit bewusst NICHT geloggt (~85k/Tag = 30M/Jahr, kein Bedarf — Strategien sind M5+, Slippage aus echten Fills gemessen). ~370k Bars/Jahr = vernachlässigbar.