Commit Graph
96 Commits
Author SHA1 Message Date
Axel HocksandClaude Opus 5 0966caf1b8 G/V-Trennung geprueft: Adoptions-Sperre riss bei JEDEM Neustart auf
User: "ueberpruefe ob wirklich die G/V und G/V BRK Anzeigen stimmen, besonders
bei gleichzeitig laufenden Trades. Die Anzeige darf jeweils nur den eigenen
Slot anzeigen."

FRONTEND SAUBER: #hdr-pnl liest nur d.position, #hdr-pnl-brk nur
d.position_brk - keine Summe, kein Fallback. Aber das ist die falsche Stelle
zum Suchen: stehen im Backend beide Felder auf derselben Position, kann keine
Anzeige das mehr richten. Geprueft wurde deshalb die AUSWAHL in
TradeManager._refresh_locked.

⚠⚠ FUND 1 - die Sperrliste kannte nur zwei von DREI Quellen eines BRK-Tickets:
  trader_brk.ticket     nur im Speicher
  _pending_tickets      nur im Speicher
  _brk_restore          FEHLTE - und nur das ueberlebt den Neustart
Nach einem Neustart sind die ersten beiden leer, und die Reihenfolge im
_pos_loop besiegelt es: trader.refresh() laeuft DREI Zeilen vor _rebind_brk().
Slot 1 greift die BRK-Position also, bevor sie zurueckgebunden werden kann.
_rebind_brk erkennt das zwar und bricht ab - damit ist der Schaden aber nur
festgestellt, nicht behoben: die BRK-Position haengt am falschen Slot, ihr G/V
steht links statt rechts, und "G/V BRK" zeigt "—". Danach sieht alles normal
aus, was es besonders schwer sichtbar macht.
Behoben ueber getattr(..., None), also unabhaengig davon, WANN das Attribut
gesetzt wird - genau die Reihenfolge-Falle, die in zwei Tagen zweimal
zugeschlagen hat.

 FUND 2 - zwei verschiedene Rechnungen nebeneinander. Bei geschlossenem
Markt zeigt Slot 1 seit dem 01.08. eine HL-Schaetzung (pnl_hl), der BRK-Slot
bekam die nie und zeigte den EINGEFRORENEN Broker-Wert, ohne dass man es der
Anzeige ansieht. Neu pnl_hl_brk, mit ≈ markiert. Geprueft statt angenommen,
dass _tick_size/_tick_value am BRK-Slot gesetzt sind.

 day_pl.open summiert korrekt BEIDE Slots - die Summe gehoert dorthin, die
Trennung in die beiden G/V-Felder.

BELEG - tests/test_slot_gv.py, 6 Tests auf dem ECHTEN TradeManager (Broker
gestubbt): zwei Positionen gleichzeitig je im eigenen Slot · Slot 1 adoptiert
die BRK-Position nicht · Pending-Fill wird nicht weggeschnappt · der BRK-Slot
adoptiert nie · plus die Regressionsprobe, die den alten Zustand festhaelt.
NEUE PIPELINE-STUFE E (tools/check_slots.py): die Sperrliste muss alle drei
Namen erwaehnen. Mutationsprobe: Merker entfernt -> Exit 1.
⚠⚠ Ehrlich zur Arbeitsteilung: der pytest belegt den MECHANISMUS, baut die
Lambda aber selbst nach und bleibt bei der Mutation gruen. Erst die statische
Stufe belegt, dass die ENGINE sie richtig verdrahtet. Keine der beiden allein
haette gereicht.

⚠⚠ NEBENBEFUND, korrigiert: mein Schreib-Helfer hat SECHS Dateien still von
LF auf CRLF gedreht (io.open(...,"w") uebersetzt auf Windows). Mein erster
Check mit `grep -c $'\r$'` meldete faelschlich 0 - erst die BYTE-Zaehlung zeigte
8959 CR in CLAUDE.md. Alle sechs auf LF zurueckgesetzt. core.autocrlf=true
haette es im Repo normalisiert, im Arbeitsbaum aber nicht.

Live verifiziert: Slot 1 T=50396824 (+10,34), BRK flat, day_pl.open 10,34 -
kein gemeinsames Ticket. Deploy mit --feld pnl_hl_brk, alle 5 Schritte gruen.
⚠ Noch nicht beobachtet: ein Neustart MIT offener BRK-Position - der Fall, den
der Fix adressiert.

v=201.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 13:07:16 +02:00
Axel HocksandClaude Opus 5 d881636e1b Close-Knopf je Slot, direkt vor der jeweiligen G/V-Anzeige
User-Wunsch. Zwei Slots heissen zwei Close-Moeglichkeiten - bisher gab es nur
den grossen CLOSE-Knopf, und der schliesst seit heute BEIDE. Neu je ein kleines
✕ vor "G/V" (Slot 1) und vor "G/V · BRK", rechtsbuendig gespiegelt.

BACKEND: `engine.close(slot=None)` - None/"" = beide (Verhalten des grossen
Knopfs, unveraendert), "main" = nur Slot 1, "brk" = nur der Breakout-Autotrader.
`POST /api/order {"side":"close","slot":"brk"}` reicht ihn durch; ohne `slot`
ist das Verhalten bitgleich zu vorher.

⚠ Sicherheitsabfrage NUR im Minus - dieselbe Regel wie beim grossen Knopf: im
Plus direkt schliessen, im Minus nachfragen. Hartes Blockieren ist im Projekt
verworfen, aber ein versehentlicher Klick soll kein Geld kosten.

⚠⚠ EIGENER FEHLER auf dem Weg, gefunden bevor er live ging: mein erster Entwurf
las den P&L aus `_letzterSnap` - eine Variable, die es NICHT gab. Das ist exakt
der ReferenceError, der am 19.08. den halben Render abgeschossen hat, nur
diesmal im Klick-Pfad (er waere erst beim Druecken geknallt, also genau dann,
wenn man schliessen will). Behoben durch `letzterSnap`, das `_applySnapshot`
jetzt fuehrt - die Variable fehlte im Projekt tatsaechlich, Klick-Handler hatten
bisher keinen Zugriff auf den aktuellen Zustand.

Verifiziert: 2 Knoepfe im ausgelieferten HTML, span/div/button ausgeglichen,
keine doppelten IDs, node --check, Render-Probe, 91 Tests und die volle Pipeline
gruen. Deploy verifiziert (v=199).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 11:58:04 +02:00
Axel HocksandClaude Opus 5 14b3fd4f64 Vierter Slot-Durchgang: Chart-Marker deckte den BRK-Slot nicht ab
User-Auftrag (vierte Runde). Diesmal die Bereiche AUSSERHALB von engine.py
geprueft - core/trader.py, server.py, der MQL5-Export und die
Zustandspersistenz.

⑦ BEHOBEN - Trade-Marker im MT5-Chart (`TR;`-Zeilen) lasen nur
   `self.trader.snapshot()`. Eine offene BRK-Position blieb im Chart also
   UNMARKIERT: die hellgruene Umrandung der Einstiegskerze fehlte. Kosmetisch,
   aber dieselbe Klasse wie Deployment-Drift Fall 8 - nicht die Strategie
   driftet, sondern ihre Beobachtbarkeit. Wer den Chart ansieht, soll sehen,
   wo der Bot eingestiegen ist. Jetzt ueber beide Slots.

DREI ENTLASTUNGEN in diesem Durchgang (geprueft, NICHT vermutet):
  - core/trader.py hat als einzige Klassen-Variable `_STEUER_TTL_S` (eine
    Konstante); der Steuer-Cache liegt als `self._steuer_cache` INSTANZWEISE
    vor. Modul-Globale sind nur die zwei Logger. Die beiden TradeManager teilen
    also KEINEN veraenderlichen Zustand - zusammen mit dem Trailing-Befund aus
    Durchgang 3 ist damit beides sauber.
  - server.py routet ueber `eng.close` (deckt seit heute beide Slots),
    `eng.toggle_trail` (ebenfalls) und `eng.set_sltp`.
  - `emergency_state.json` ist per-Ticket und betrifft nur Slot 1 - die drei
    Notfall-Modi stehen ohnehin auf 0, und der Reichweiten-Waechter meldet es,
    falls einer eingeschaltet wird, waehrend BRK eine Position haelt.

⚠ WEITER OFFEN, unveraendert und bewusst: `set_sltp()` (nur Slot 1, braucht eine
UI-Entscheidung) und `_check_auto_m15`, das `_slot()` umgeht. Neu dazu:
`_check_close_alert` (Flip-Alarm) liest ebenfalls nur Slot 1 - das ist ein
Hinweis, keine Schutzhandlung, und der Flip-Close ist aus.

91 Tests gruen, Pipeline inkl. Stufe E gruen, Deploy verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 09:15:48 +02:00
Axel HocksandClaude Opus 5 5e476025d7 Dritter Slot-Durchgang: TRAIL-Knopf und Wiedereinstiegs-Sperre waren blind
User-Auftrag (dritte Runde). Diesmal die Bereiche ausserhalb der
`self.trader.`-Zugriffe geprueft. ZWEI neue Funde, beide behoben:

⑤ toggle_trail() schaltete NUR `self.trail`. Hielt allein der BRK-Slot eine
   Position, liess sich dessen Trailing per Dashboard weder ein- noch
   ausschalten. ⚠ Das ist keine Kosmetik: ohne `trail_brk` laeuft ein BRK-Trade
   in der gemessen DURCHGEFALLENEN SL-only-Variante (backtest_brk_slonly.py,
   alle zehn KI enthalten die Null, Trefferquote faellt 40 -> 21 %).
   Neu: haelt NUR BRK etwas, wird dessen Trailing geschaltet; sonst (auch bei
   zwei offenen Positionen) das von Slot 1 - die Position, die der Nutzer selbst
   geoeffnet hat.

⑥ Die Wiedereinstiegs-Sperre sah den BRK-Slot NICHT. `_check_auto_close` setzt
   `_pos_close_ts`/`_pos_close_dir` aus `self.trader.snapshot()`; schloss eine
   BRK-Position, blieb die Sperre unarmiert und der Squeeze durfte sofort in
   dieselbe Richtung neu eroeffnen. Genau die Open->Instant-Close-Kaskade, gegen
   die _SQUEEZE_REENTRY_COOLDOWN_S am 27.07. gebaut wurde.
   Neu `_check_brk_close_cooldown` im _pos_loop. ⚠ Bewusst DIESELBEN Felder wie
   Slot 1: die Sperre ist eine Aussage ueber den MARKT ("in diese Richtung
   gerade nicht"), nicht ueber einen Slot.

GEPRUEFT UND SAUBER in diesem Durchgang:
  - core/trailing.py hat KEINE Klassen-Variablen und keine veraenderlichen
    Modul-Globalen -> die zwei TrailingManager-Instanzen sind vollstaendig
    unabhaengig. Das war die groesste offene Sorge.
  - _check_close_notify arbeitet ueber history.trade_by_ticket, also DB-basiert
    und slot-unabhaengig.

⚠ WEITER OFFEN, bewusst nicht angefasst: `set_sltp()` wirkt nur auf Slot 1 (die
SL/TP-Felder koennen eine BRK-Position nicht anpassen) - das ist eine
UI-Entscheidung, welches Feld zu welchem Slot gehoert, und braucht eine Vorgabe
statt eines stillen Fixes. Ebenso `_check_auto_m15`, das `self.trader.open_long`
VOR dem `_open`-Aufruf bindet und damit `_slot()` umgeht (funktioniert derzeit
nur, weil beide dasselbe liefern).

91 Tests gruen, Pipeline inkl. der neuen Stufe E gruen, Deploy verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:54:20 +02:00
Axel HocksandClaude Opus 5 2b498fc20e Pipeline Stufe E: Slot-Trennung und Attribut-Reihenfolge (tools/check_slots.py)
User: "Uebernehme die Logikpruefung auf allen Slots in die Deployment pipeline" -
nach dem Ausfall, bei dem der Serverstart komplett abbrach und zwei Minuten lang
kein Close moeglich war.

ZWEI FEHLERKLASSEN, beide binnen zwei Tagen real aufgetreten, beide von KEINER
bestehenden Stufe gefangen (py_compile, ruff F821, ty, pytest: alle gruen):

(A) ATTRIBUT VOR SEINER ZUWEISUNG. `self.trader_brk.history = self.history`
    stand in `__init__` VOR `self.trader_brk = TradeManager(...)`.
    AttributeError im Konstruktor -> Serverstart brach ab -> "Netzwerkfehler" am
    Close-Knopf. Syntaktisch korrekt, und kein Test instanziiert die Engine (sie
    braucht MT5). Gefunden hat es erst deploy.py Schritt 2 - also NACH dem Kill
    des laufenden Servers. Derselbe Fehler am Vortag mit `_margin_brk` vor
    `_load_runtime_state()`, dort sogar still.
    Die Pruefung sammelt je `self.X` die ZEILE der ersten Zuweisung und meldet
    jede Benutzung davor.

(B) SLOT-VERWECHSLUNG. BRK-Pfade (_check_auto_squeeze, _manage_squeeze_pending,
    _check_pending_fill) duerfen den SLOT-ZUSTAND von `self.trader` nicht
    anfassen (close/snapshot/open_*/set_open_context/refresh). ⚠ Bewusst eine
    WEISSE Liste der Pfade - eine schwarze wuerde jede neue Funktion still
    durchlassen. `pending_orders`/`cancel_pending`/`place_stop` sind ausdruecklich
    ERLAUBT: magic-basierte Broker-Abfragen ohne Slot-Zustand (geprueft).
    Dazu die Invariante, dass `TradingEngine.close` beide Slots erwaehnen muss -
    sonst waere eine BRK-Position per Dashboard nicht schliessbar.

DREI RICHTUNGEN VERIFIZIERT: sauber -> gruen; Reihenfolge-Fehler zurueckgebaut ->
"self.trader_brk benutzt, aber erst in Zeile 270 zugewiesen"; Slot-Verwechslung
zurueckgebaut -> "self.trader.close im BRK-Pfad". Danach wieder gruen.

Statisch (AST), kein MT5, Millisekunden. Werkzeugfehler gilt NICHT als sauber.
Laeuft ueber check_nfalle.py im pre-commit-Hook mit.

⚠ Was diese Stufe NICHT kann: ein Startfehler AUSSERHALB von __init__. Dafuer
bliebe ein echter Rauchtest mit gestubbtem MT5 - der ist nicht gebaut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:47:28 +02:00
Axel HocksandClaude Opus 5 a652223a05 Slot-Pruefung: close() traf nur Slot 1, squeeze_reverse den falschen
User: "ueberpruefe die Trade Logiken genau auf weitere Fehler oder Widersprueche,
besonders bezogen auf die 2 Slots". Systematisch alle `self.trader.`-Zugriffe in
engine.py durchgegangen (24 Stellen, nach Funktion gruppiert). VIER Widersprueche,
alle aus dem Umbau vom 19.08.:

① BEHOBEN - `engine.close()` schloss NUR Slot 1. Hielt der BRK-Slot eine Position
   und Slot 1 war leer, tat der CLOSE-Knopf im Dashboard NICHTS. Das ist die
   gefaehrlichste Variante der Luecke: nicht eine Zahl stimmt nicht, sondern eine
   SCHUTZHANDLUNG greift ins Leere. Jetzt ueber beide Slots, Slot 1 zuerst
   (wer CLOSE drueckt, meint meist die selbst geoeffnete Position), Fehler
   gesammelt gemeldet.

③ BEHOBEN - `squeeze_reverse` rief `self.trader.close()`, traf also die MANUELLE
   Position statt der BRK-Position, die der Reverse eigentlich drehen soll.
   Dormant (auto_squeeze_reverse=false), aber falsch verdrahtet.

② GEMELDET, NICHT geaendert - `set_sltp()` wirkt nur auf Slot 1. Die SL/TP-Felder
   der Trade-Leiste koennen eine BRK-Position nicht anpassen. Das ist eine
   UI-Frage (welches Feld gehoert zu welchem Slot?) und braucht eine Entscheidung,
   keinen stillen Fix.

④ GEMELDET - `_check_auto_m15` bindet `self.trader.open_long` VOR dem Aufruf von
   `_open`, umgeht also `_slot(source)`. Funktioniert derzeit nur, weil
   `_slot("auto_m15")` ohnehin `self.trader` liefert. Fragil: bekaeme M15 je
   einen eigenen Slot, waere es still falsch.

GEPRUEFT UND KORREKT: `_manage_squeeze_pending` (pending_orders/cancel_pending/
place_stop sind magic-basierte BROKER-Abfragen, kein Slot-Zustand),
`_broker_offset_s` (Zeitzone), `snapshot()` (position / position_brk getrennt),
Circuit-Breaker (summiert und schliesst beide).

⚠ Beim Bau eine Einrueckung zerschossen - Stufe A der Pipeline hat es sofort
gefangen (IndentationError + ty invalid-syntax + pytest). Genau dafuer ist sie da.

91 Tests gruen, Deploy verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:37:11 +02:00
Axel HocksandClaude Opus 5 c081bdc734 SL/TP nicht mehr am S/R verankert + Squeeze-Market-Fallback auf den BRK-Slot
User: "SL/TP sollte nicht am S/R verankert werden sondern immer dynamisch
berechnet werden" - nach dem Fund, dass Trades wiederholt am Level schlossen.

(1) PIVOT-ANKER DES INITIAL-SL ENTFERNT (`_SL_PIVOT_ANKER = False`).
`_calc_sl_tp` legte den SL an den naechsten M15-Pivot (LONG: pivot_low − Puffer,
SHORT: pivot_high + Puffer) und klemmte ihn erst DANACH auf 1,8–2,2×ATR. Der
Stop lag damit fuer einen LONG direkt unter der UNTERSTUETZUNG. Ueber 69
geloggte Orders war der Pivot in 4 % massgeblich (59 % gekappt, 36 % geweitet) -
und in genau diesen Faellen stand der Stop auf dem Level, an dem der Markt
ohnehin am haeufigsten durchwickt.
⚠ Der TP erbte das INDIREKT: er ist `2,0 × SL-Distanz`, skalierte also mit dem
Pivot-Abstand. Beide sind jetzt rein ATR-dynamisch (Mitte des Bandes = 2,0×ATR).

VORHER GEMESSEN (`backtest_sl_pivot.py`, 60k M5, 2 Halbjahre, gleiche
Einstiege, NUR die SL-Methode variiert, kanonischer Exit, Echtkosten):
    PIVOT  H1 -0,054 / H2 -0,040   PF 0,93 / 0,95
    FIX    H1 -0,040 / H2 +0,004   PF 0,95 / 1,01
FIX ist in BEIDEN Haelften besser (+0,014 / +0,043 R), der Worst-Case wird nicht
groesser - die vorab fixierte Regel ist erfuellt.
⚠ EHRLICH: beide KI enthalten die Null, es ist KEIN belegter Ertragsgewinn. Der
Punkt ist, dass die Verankerung nichts nuetzt UND den Stop auf das Level legt.
Das bestaetigt `backtest_sl_method.py` ("gedeckelt sind alle Methoden
gleichwertig") auf dem heutigen Exit - dort war es nur nie als NACHTEIL sichtbar.
Zurueck: `_SL_PIVOT_ANKER = True`.

(2) LUECKE AUS DEM ZWEI-SLOT-UMBAU, vom Deploy-Schritt 5 aufgedeckt:
"Auto-Squeeze-Entry fehlgeschlagen: Position bereits offen!". `engine.open_long`
routete IMMER auf `self.trader` - der Market-Fallback des Squeeze lief also
weiter ueber Slot 1 und scheiterte, sobald ein manueller Trade lief. FLAT-Check
und Pending-Manager waren gestern umgehaengt, der BESTELLWEG nicht.
Neu `_slot(source)`: auto_squeeze -> trader_brk, alles andere -> trader. Auch
der Bot-Marker (`_bot_open_ticket`) holt das Ticket jetzt vom richtigen Slot.
⚠ Genau die Fehlerklasse von Deployment-Drift Fall 8 - ein Umbau, der den
Bestellweg aendert, muss ALLE Bestellwege mitnehmen.

91 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:32:21 +02:00
Axel HocksandClaude Opus 5 d87bda1461 FIX: setup-Nachtrag bei Pending-Fill scheiterte an einem Rennen
User: "dann sieh dir die Luecke an" (nach "DB-Nachtrag fehlgeschlagen" im Log,
20.08. 07:40:12, T=50371599).

URSACHE - ein Rennen zwischen zwei Pfaden: _check_pending_fill erkennt den Fill
aus trader_brk.snapshot(), die DB-ZEILE schreibt aber trader._refresh_locked ->
log_trade_open. War der noch nicht durch, traf das UPDATE keine Zeile und der
Nachtrag scheiterte STILL. Der Trade blieb setup=NULL und war damit von einem
manuellen nicht unterscheidbar - genau die Buchfuehrungs-Luecke, gegen die
tag_bot_trade ueberhaupt gebaut wurde (Deployment-Drift Fall 8), nur eine Ebene
tiefer. Folge: squeeze_entry_count blieb 0, der Trade fehlte in B4/B5.

BEHOBEN: gescheiterte Nachtraege landen in `_tag_nachtrag` und werden im
_pos_loop wiederholt, bis die Zeile da ist - dasselbe Retry-Muster wie beim
Gewinn-Close (23.07.). Nach 60 Versuchen (~1 min) wird aufgegeben und LAUT
gemeldet: eine Zeile, die nach einer Minute nicht existiert, kommt nicht mehr,
und dann soll es nicht still bleiben.

T=50371599 nachgetragen (DB-Backup oil_widget_history.db.bak-2026-08-20).

 NEBENBEFUND, und zwar ein guter: derselbe Logausschnitt enthaelt
"🧷 BRK-Slot uebernimmt Pending-Fill T=50371599" - das ist der ERSTE
Live-Beleg, dass der Zwei-Slot-Umbau vom 19.08. funktioniert. Der BRK-Slot hat
die gefuellte Pending-Order korrekt uebernommen.

⚠ ZWEITER NEBENBEFUND, NICHT behoben (User-Entscheidung): die Order wurde mit
0,01 Lots platziert. Das ist die direkte Folge von margin_brk = 10 % auf eine
fast erschoepfte freie Margin - die Einstellung wirkt also, nur vermutlich
anders als gedacht. Dazu steht margin_pct in runtime_state auf 95, waehrend die
ini 40 sagt (runtime gewinnt). Beides gemeldet, nichts geaendert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:12:15 +02:00
Axel HocksandClaude Opus 5 f02fd43b39 Telegram: ALLE Trade-Opens und -Closes + Reichweiten-Waechter fuer den 2. Slot
(1) User-Vorgabe: "Alle Trade Closes und Opens sollen per Telegram gemeldet
werden".
 - close_notify_min_eur 50 -> 0, also jeder Close ohne Schwelle
   (Backup oil_widget_config.ini.bak-2026-08-19-tgopen)
 - neuer _check_open_notify: meldet jede Eroeffnung, ueber BEIDE Slots. Der
   BRK-Slot ist ausdruecklich dabei - ein autonomer Entry soll nicht unbemerkt
   bleiben, genau dafuer wurde der zweite Slot gebaut; die Meldung nennt den
   Slot mit.
 - _TG_ERLAUBT um "Trade eroeffnet" erweitert (das Gate ist EINE Filterstelle,
   nicht 17 Einzeleingriffe).
 ⚠ 1x je Ticket ueber _open_notify_gemeldet - ohne den Merker feuerte es im
   1-s-Takt weiter, solange die Position offen ist.
 ⚠ In der Startup-Schonfrist wird nur GEMERKT, nicht gemeldet: nach einem
   Neustart erkennt der Trader eine BESTEHENDE Position wieder, und das ist
   keine Eroeffnung.

(2) Reichweiten-Waechter (_check_slot_reichweite). Gemessener Befund: von den
Schutz-Checks ist NUR _check_circuit_breaker slot-faehig. _check_auto_close
(Notfall-Stop, haengt an 4 Ticket-Variablen), _check_sr_close, _check_adverse15
und _check_flip_close kennen nur Slot 1. Heute folgenlos, weil alle vier AUS
sind - aber wird einer eingeschaltet, waehrend eine BRK-Position laeuft, gilt er
stillschweigend nur fuer Slot 1, und im Dashboard saehe alles normal aus.
Dieselbe Klasse wie Deployment-Drift Fall 8: nicht die Strategie driftet,
sondern ihre REICHWEITE. Der Waechter macht das Loch LAUT (Log-Warnung 1x je
Ticket + Snapshot-Feld `slot_luecke`), bis die vier slot-faehig sind.

⚠ Die volle Parametrisierung der vier Checks steht AUS. _check_auto_close allein
haengt an vier Ticket-Variablen und ist der Notfall-Stop - das gehoert in eine
eigene Sitzung mit Tests, nicht ans Ende einer langen.

⚠ EIGENER FEHLER auf dem Weg: der erste Bauversuch lief per Heredoc und riss das
Telegram-Format-Literal an einem \n auseinander (SyntaxError). Das ist exakt die
im Projekt dokumentierte \n-Falle - "mehrzeilige Strings mit \n NIE per Heredoc
schreiben, den Edit-Weg nehmen". Ich habe die eigene Regel verletzt; engine.py
wurde per git checkout zurueckgesetzt und sauber ueber Edit neu gebaut.

Deploy ueber tools/deploy.py --feld position_brk, alle 5 Schritte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:23:01 +02:00
Axel HocksandClaude Opus 5 a9a6c487d2 Circuit-Breaker und Tages-P&L summieren jetzt BEIDE Positions-Slots
Letzte offene Luecke des Zwei-Slot-Umbaus (User: "ja").

WARUM ES ZWINGEND IST: nach dem Umbau kann BRK parallel zu einer manuellen oder
M15-Position laufen. Haette der Tages-P&L weiter nur den ersten Slot gesehen,
waere eine offene BRK-Position unsichtbar geblieben - der Breaker griffe also
genau dann zu spaet, wenn zwei Positionen gleichzeitig laufen und das Risiko
doppelt ist. Bei 40 % Einsatz je Position sind 80 % der Margin gebunden.

GEAENDERT:
- snapshot(): day_pl["open"] summiert beide Slots
- _check_circuit_breaker(): dieselbe Summe als Ausloeser
- und der Breaker schliesst jetzt BEIDE Positionen - eine Notbremse, die nur
  die Haelfte schliesst, ist keine. Fehlschlag am zweiten Slot wird geloggt,
  nicht verschluckt.

91 Tests gruen, Deploy ueber tools/deploy.py --feld position_brk.

⚠ NEBENBEFUND beim Verifizieren, NICHT von dieser Aenderung verursacht: der
Circuit-Breaker steht auf 8 % (runtime_state cb_limit_pct = 8.0) und hat heute
dreimal ausgeloest (19:17, 20:03, 20:07). Der Tages-P&L liegt bei -178,89 EUR
gegen ein Limit von -55,89 EUR. Damit sind fuer heute KEINE autonomen Trades mehr
moeglich - auch BRK nicht. Manuelle Orders bleiben frei (so gebaut).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 20:10:31 +02:00
Axel HocksandClaude Opus 5 f04ae4d9d9 Fix: Einsatz je Pfad ueberlebte keinen Neustart (Reihenfolge-Fehler)
User: "Einsatz BRK % / Einsatz M15 % hat keine Auswirkung, die Eingabe bleibt
wirkungslos, in den Feldern erscheint 'global'".

URSACHE - mein Fehler beim Bau: die Default-Initialisierung
(self._margin_brk = 0.0) stand in Zeile 631, `_load_runtime_state()` laeuft aber
in Zeile 553. Der geladene Wert wurde also unmittelbar danach mit 0
ueberschrieben. Die Eingabe WIRKTE (POST kam an, Wert stand im Snapshot, wurde
auf Platte geschrieben) - sie war nach dem naechsten Neustart weg, und das Feld
zeigte wieder den Platzhalter "global". Real am 19.08.: BRK 10 / M15 85 gesetzt,
nach dem Deploy beide 0.

Behoben: Defaults stehen jetzt VOR dem Laden. Reihenfolge ist immer
Default setzen -> runtime_state laedt darueber.

⚠ EIGENER FEHLALARM beim Verifizieren, dokumentiert weil er lehrreich ist: mein
Persistenz-Test setzte 55/30, und nach dem Neustart standen 85/10 - ich habe das
als "VERLOREN" und sogar als Vertauschung gelesen. Die Logzeitstempel zeigen
etwas anderes: um 20:06:04 und 20:06:06 hat der Browser des Users zwei weitere
POSTs geschickt (85/30, dann 85/10), waehrend mein Test lief. Persistiert wurde
also korrekt der ZULETZT gesetzte Wert. Lehre: bei einer Live-Verifikation gegen
ein System, das der Nutzer gleichzeitig bedient, gehoert die Logspur mitgelesen
- sonst hält man fremde Eingaben fuer einen Defekt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 20:07:33 +02:00
Axel HocksandClaude Opus 5 9b5b20e713 BRK bekommt einen EIGENEN Positions-Slot - unabhaengig von manuell und M15
User-Vorgabe: "der brk trade soll komplett unabhaengig von m15 oder manuellen
trades laufen". Entwurf: docs/brk-eigener-slot.md

DER BEFUND, DER DEN UMBAU KLEIN MACHT: TrailingManager.__init__ nimmt bereits
SEINEN Trader entgegen und liest ausschliesslich ueber dessen snapshot() - es
haengt also nicht an einer globalen Position. Damit entfaellt der
29-Stellen-Umbau in engine.py. Stattdessen:

    engine.trader      - TradeManager()                 - trail      - manuell + M15
    engine.trader_brk  - TradeManager(nur_ticket=True)  - trail_brk  - nur BRK

Der validierte Pfad bleibt damit vollstaendig unangetastet - kein
Regressionsrisiko auf der gemessen besseren Population (+1,56 gegen -4,71/Lot).

DIE ZWEI KRITISCHEN STELLEN, beide gebaut:
(1) ADOPTION. TradeManager.refresh() greift per Default jede Position auf dem
    Symbol (gewollt: ein von Hand eroeffneter Trade bekommt so den Schutz-Stack).
    Mit zwei Managern wuerden sich BEIDE dieselbe Position schnappen. Neu:
    `nur_ticket=True` sucht sich nichts, und der adoptierende Manager bekommt
    ueber `fremde_tickets` eine Sperrliste (BRK-Ticket + liegende Pendings).
(2) DER FILL. Eine ruhende Order fuellt IM BROKER; der ticket-gebundene Slot
    kann sie nicht finden. Neu `TradeManager.bind(ticket, sym)`, aufgerufen aus
    _check_pending_fill - es sieht direkt am Broker nach, welches der liegenden
    Tickets zu einer Position geworden ist.

WEITER GEAENDERT: _check_auto_squeeze und _manage_squeeze_pending lesen den
EIGENEN Slot (eine manuelle oder M15-Position storniert die Pendings nicht mehr
- real am 19.08. waren es 5 Fenster mit zusammen ~2 min am Markt, 3 davon vom
M15-Trader); trail_brk wird in _price_loop mit Preisen versorgt (ohne das liefe
BRK in der gemessen DURCHGEFALLENEN SL-only-Variante); Snapshot-Feld
`position_brk` macht den zweiten Slot sichtbar - ohne das waere es
Deployment-Drift Fall 8 in neuer Form (nicht die Strategie driftet, sondern
ihre Beobachtbarkeit).

TESTS: 91 gruen. tests/test_pending_fill.py auf den BRK-Slot umgestellt - die
Aussagen bleiben unveraendert (fremde Quelle wird NICHT getaggt, derselbe Fill
zaehlt nur einmal), nur der Slot ist ein anderer. Die Tests wurden NICHT
abgeschwaecht; sie sichern weiter Deployment-Drift Fall 8.

LIVE VERIFIZIERT: Slot 1 fuehrt die offene Position (T=50349215) unveraendert
weiter, Slot 2 ist leer und wartet auf einen Squeeze. Deploy ueber
tools/deploy.py --feld position_brk, alle 5 Schritte.

⚠ OFFEN und bewusst NICHT in diesem Zug: Circuit-Breaker und Tages-P&L summieren
noch nicht BEIDE Slots, und die Dashboard-Zeile fuer den zweiten Slot fehlt. Mit
zwei Positionen sind bei 40 % je Position 80 % der Margin gebunden - der Breaker
(aktuell AUS) waere dann keine Kuer mehr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 20:03:45 +02:00
Axel HocksandClaude Opus 5 a07ad942c1 Gesamtpruefung: drei echte Fehler behoben, alle drei aus meinem eigenen Code
Dritter vollstaendiger Durchlauf nach docs/review-prompt.md (nach 02.08. und
11.08.). Bemerkenswert: alle drei Funde stammen aus Aenderungen der letzten zwei
Tage, und alle drei sind DIESELBE Klasse - ein vorhandenes Muster nicht kopiert,
sondern ein eigenes erfunden.

FUND 1 (kritisch) - DER CONFIG-WAECHTER WAR TOT.
Mein CONFIG_DEPS-Eintrag fuer auto_m15 vom 19.08. trug das Feld "soll", die
anderen 15 Eintraege tragen "validated". config_drift() lief in einen KeyError
und warf - damit meldeten ALLE 16 Anker nichts mehr, seit gestern. Der Waechter,
der die auto_m15-Abweichung haette melden sollen, war durch genau diesen
Eintrag erledigt.
Behoben: Feldname angeglichen UND config_drift gehaertet - ein defekter Eintrag
wird jetzt uebersprungen und als eigener Befund GEMELDET statt den ganzen
Waechter zu toeten. Ein Waechter, der still stirbt, ist schlimmer als keiner
(dieselbe Klasse wie der ruff-Exit-2-Fall vom 07.08.).
Der Waechter meldet seitdem wieder: margin_buffer_pct 40 gegen 95,
auto_m15 true gegen false, auto_squeeze true gegen false - alle drei sind
dokumentierte User-Entscheidungen, aber sie waren unsichtbar geworden.

FUND 2 (Geld) - DER EINSATZ JE PFAD WAR FUER BRK WIRKUNGSLOS.
engine._open setzt den Einsatz je Pfad - aber _manage_squeeze_pending legt
ruhende Stop-Orders ueber trader.place_stop -> calc_lots, also NICHT ueber
_open. Gemessen fuellen 7 von 8 BRK-Trades per ruhender Order (seit dem
Pending-Umbau 05.08.). Das Feld haette also genau an der Stelle nicht gegriffen,
fuer die es gebaut wurde - und das faellt im Betrieb nur auf, wenn jemand die
Lots nachrechnet.

FUND 3 (Geld, Race) - GLOBALE MUTATION UEBER EINE LOCK-GRENZE.
Der erste Entwurf setzte config.MARGIN_BUFFER temporaer. Der Global wirkt
prozessweit, und zwischen dem Setzen in _open und dem mt5_lock in trader._send
liegt ein Fenster von bis zu 15 s (Lock-Timeout). Eine gleichzeitige MANUELLE
Order haette darin mit dem Prozentsatz des AUTONOMEN Pfads gesized.

FUND 2 und 3 gemeinsam behoben: calc_lots bekommt einen EXPLIZITEN Parameter
buffer_pct (Default None = global), durchgereicht ueber _send/_send_locked/
open_long/open_short/place_stop. Keine Mutation mehr, und beide Bestellwege
tragen denselben Wert.

TESTS - und eine Luecke in meinem eigenen Test, die erst die Mutationsprobe zeigte:
tests/test_buffer_pct.py, 6 Tests. Die erste Fassung bildete die Regel NACH
(_buf) statt die echte Funktion zu pruefen - die Mutation "calc_lots ignoriert
den Parameter wieder" lief damit GRUEN durch. Das ist die dokumentierte
Nachbau-Falle, diesmal in einem TEST. Ergaenzt um eine AST-Pruefung, dass
calc_lots den Parameter im Rumpf wirklich benutzt. Beide Mutationen werden jetzt
gefangen (Parameter aus place_stop entfernt -> rot; calc_lots ignoriert ihn ->
rot).

OHNE BEFUND (geprueft, sauber): check_nfalle, ruff F821, 91 Tests, node --check;
100 JS-Zugriffe gegen 124 HTML-IDs -> 0 fehlend (die 4 gemeldeten waren
Falsch-Positive meiner Regex: zwei stehen in Kommentaren, raum-* wird dynamisch
als $("raum-" + st) gebaut, tb-dur ueber getElementById); 2 Config-Schluessel
ohne Leser (beide [zones], dokumentiert schlafend); 14 Snapshot-Felder ohne
app.js-Leser (dokumentiert als Diagnose-Oberflaeche, deploy.py --feld braucht
sie); Snapshot-Median 15,7 ms bei p90 25,7 ms - unveraendert zum 11.08. und weit
unter dem 1-s-Budget, keine Massnahme.

TELEMETRIE-PULS: alle 7 Logger schreiben. rec_outcomes steht bei 72 Zeilen -
beim Review am 11.08. stand es auf "hat NIE geschrieben", der Fix vom 12.08. hat
also gewirkt.

DIVERGENZ-WAECHTER: A) WARTEN +16,6 Pp ueber der Erwartung (bekannt, wird von
den Live-only-Gates getragen); D) mom3 -0,55 Sigma - knapp ueber der bewusst
tiefen 0,5-Sigma-Schwelle, beobachten.

⚠ NICHT ANGEFASST (User-Entscheidungen, nur berichtet): auto_m15 laeuft live
ueber runtime_state.json gegen die ini; Circuit Breaker aus (cb_limit_pct 0
gegen ini 8); BRK an trotz gefallener B5-Regel.

Deploy ueber tools/deploy.py --feld margin_brk, alle 5 Schritte gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 19:38:56 +02:00
Axel HocksandClaude Opus 5 7915e171d0 M5-Kontextzeile in der M15-Karte statt einer eigenen M5-Setup-Karte
User fragte nach einer M1- oder M5-Setup-Karte und hat der hier gebauten
Variante zugestimmt: eine reine ZUSTANDS-Zeile, ohne Richtung und ohne Banner.

WARUM KEINE ZWEITE KARTE - und diesmal entscheidet eine frische Messung, nicht
eine Meinung. Die entkoppelte Selbstmessung der BESTEHENDEN Karte steht bei
n=342 (gruen + gerichtet, ab dem Hysterese-Stichtag 12.08.):
    30 min  53,5 %  KI [48,2 .. 58,8]   -> enthaelt 50 %
    60 min  49,3 %  KI [44,0 .. 54,5]   -> enthaelt 50 %, liegt DARUNTER
Am 12.08. war die Bedingung fuer ein Ja VORAB fixiert worden: ">=350 Faelle,
Trefferquote ueber 50 %, KI ohne die 50". Die Stichprobe ist jetzt da, die
Bedingung ist NICHT erfuellt. Das ist kein "noch zu wenig Daten" mehr.
Dazu die Messung vom 13.08.: als Handelsregel faellt die Karte durch
(backtest_m15_auto.py, OeR -0,162/-0,094, beide KI ohne Null, schlechter als
die HTF-Richtung UND schlechter als ihr eigenes Gegenteil).

M1 scheitert zusaetzlich an der Arithmetik: Spread/ATR Median 0,319 gegen 0,193
(M5) und 0,104 (M15). Feiner aufloesen macht die EINZIGE gemessene Staerke der
M15-Karte - die Kosten - monoton schlechter. Um 01:00 ist der Spread
1,051xATR_M1, also groesser als die mittlere Kerze; und die M1-Historie ist bei
80 Tagen gedeckelt, zwei Stichproben laegen im selben Regime.

GEBAUT ist deshalb Zustand ohne Urteil: Squeeze-Lage (armiert/Ausbruch/keine
Kompression + Box), Kosten in xATR_M5 mit den Schwellen aus
backtest_realcosts.py (Median 0,193, ab 0,32 Kostenfalle) und der ATR.
Der M5-RAUM wird bewusst NICHT wiederholt - Gate 3b rechnet ohnehin auf M5.

⚠ NUR ZUSAMMENGESETZT, nichts neu gerechnet: wave.squeeze und bid/ask/ATR_M5
stehen im Snapshot ohnehin. Ein zweiter Rechenweg war der Fehler des
Konsens-Pfeils (komplettes zweites _verdict im 5-s-Takt) und ist die Quelle
jeder Divergenz zwischen Karte und Chart.

⚠ Kein Verdict-Gewicht, kein Trade-Trigger, keine Farbampel - dieselbe
Zurueckhaltung wie bei der Kerzen-Anatomie und der Ueberdehnungs-Anzeige.

Live verifiziert: "M5 · keine Kompression (Box 3.52xATR) · Kosten 0.15xATR_M5
guenstig · ATR 0.165". Deploy ueber tools/deploy.py --feld m15_setup.m5
(Punktpfad), alle 5 Schritte gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 19:17:18 +02:00
Axel HocksandClaude Opus 5 0a465f9258 Einsatz-Prozentsatz je autonomem Pfad (BRK / M15) + Dashboard-Feld
User: "Baue ein Eingabefeld im Dashboard ein in welchem ich das Margin
Verhaeltnis von M15 / BRK manuell setzen kann".

⚠⚠ EHRLICHE EINORDNUNG, weil die Umsetzung NICHT ist, wonach es klingt: eine
GLEICHZEITIGE Aufteilung (z.B. 40 % manuell / 50 % reserviert fuer BRK) ist
heute nicht baubar. Der Bot haelt EINE Position - _check_auto_squeeze feuert
"nur FLAT", und Trailing, Notfall-Stop, S/R-Close, Time-Stop und Breaker
verwalten je EINE Position (42 Einzel-Positions-Annahmen in engine.py, 25 in
trader.py). Mit zwei Positionen auf demselben Symbol haengt der GESAMTE
Schutz-Stack an einer davon, die andere liefe ungeschuetzt. Das ist kein
Aufwands-, sondern ein Sicherheitsargument.

GEBAUT ist deshalb das, was heute wirkt und dieselbe Frage beantwortet: je Pfad
ein eigener Einsatz-Prozentsatz. 0 = globaler Wert (bisheriges Verhalten).
Quellen-abhaengig verdrahtet wie die SL-Zeitebene seit 05.08.: _open() setzt
config.MARGIN_BUFFER fuer die Dauer des einen Aufrufs und stellt ihn im
finally-Zweig zurueck. Manuelle Trades bleiben beim globalen Wert (der Mensch
ist die gemessen bessere Population, +1,56 gegen -4,71 EUR/Lot).

⚠ Direkt gesetzt statt ueber set_margin_buffer(): das loggt je Trade eine
Zeile UND wuerde den globalen Wert dauerhaft ueberschreiben.

⚠⚠ ZWEI ECHTE FEHLER VOM LINTER GEFANGEN, die py_compile durchgewinkt hat:
"config" war in engine.py gar nicht importiert (nur Einzelnamen via
"from core.config import ..."), und in server.py hiess die Engine "eng" statt
"app.state.engine". Beide sassen in Pfaden, die erst beim ERSTEN autonomen
Trade bzw. beim ersten Klick gefeuert haetten - also genau die Klasse, fuer
die ruff F821 am 07.08. eingebaut wurde.

⚠ Frontend: $streng statt $, weil LEER hier ausdruecklich 0 = "global" bedeutet
und nicht "unveraendert"; mit dem Auffang-Element waere .value undefined -> NaN
-> null. Der Render ueberschreibt das Feld nicht, solange es den Fokus hat
(sonst frisst der 1-s-Snapshot die laufende Eingabe).

⚠ Beim Committen selbst zweimal danebengegriffen, beides dokumentiert weil es
Fehlerklassen sind: (a) Backticks in einer Bash-Commit-Nachricht werden als
Kommando-Substitution ausgefuehrt und loeschen die eingeklammerten Namen aus
dem Text; (b) ein Bash-Pfad (/c/Users/...) an Python uebergeben schlaegt fehl,
und "git commit --amend -F <fehlende Datei>" nahm daraufhin eine STALE
COMMIT_EDITMSG - die Nachricht eines fremden Commits. Der Code war davon nie
betroffen (Arbeitsbaum sauber, Remote synchron), nur die Beschriftung.

Ende-zu-Ende geprueft: 50/25 gesetzt -> Snapshot -> persistiert; 150 abgelehnt;
0/0 zurueck. Deploy ueber tools/deploy.py --feld margin_brk, alle 5 Schritte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 19:06:25 +02:00
Axel HocksandClaude Opus 5 c5190e77fd M15-Auto-Entry: Richtung aus dem Veto + Abbruchregel verankert
(1) Der Auto-Entry nimmt die Richtung jetzt aus bias.verboten (= die ERLAUBTE
Richtung), also genau das, was die Karte anzeigt (app.js:504 nimmt erl). Kein
Veto -> kein Entry, weil die Karte dort ausdruecklich keine Richtung gibt.
Gegenprobe an der Live-Lage: verboten=SHORT, lesart=ab -> alt SHORT (die
verbotene!), neu LONG = identisch zur Anzeige. Damit entspricht der Pfad der
gemessenen Kontrolle C (-0,085/-0,030), der am wenigsten schlechten Variante --
aber weiterhin negativ. Die Korrektur behebt den Widerspruch, nicht den
fehlenden Edge.

(2) measurement_reminder.py: neue Messung m15_abbruch (>=20 AUTOM15_*-Trades,
Latte Verhaeltnis < 1,0 ODER PF < 1) und Config-Anker auto_m15 (validiert
false), dazu der Helfer _zaehle_setup(). Der Zaehler zaehlt nur geschlossene
Trades. Damit kann die vorab fixierte Regel nicht mehr unbemerkt verfallen --
genau das war bei B5 wochenlang der Fall.

Aktivierung steht aus: Backend-Aenderung, braucht einen Neustart. auto_m15 ist
aus, also keine Eile -- der Neustart wartet, bis das Konto flat ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 18:10:07 +02:00
Axel HocksandClaude Opus 5 bd65bdaad0 M15-Auto-Entry gebaut (Default AUS) -- gegen die Messung, auf User-Wunsch
User wollte den Auto-Trade testen, nach vollstaendiger Information ueber die
Beleglage. backtest_m15_auto.py (13.08.): die gehandelte Lesart ist in BEIDEN
Halbjahren negativ (OeR -0,162/-0,094, PF 0,72/0,84), beide KI schliessen die
Null aus, Nachbarn monoton schlechter, und sie ist schlechter als die
HTF-Richtung UND als ihr eigenes Gegenteil. Live entkoppelt 46,8 % Treffer.

_check_auto_m15 im _pos_loop: Ausloeser gruen + gerichtet, Richtung exakt wie im
Backtest (auf->LONG, ab->SHORT), Dedup 1x je Episode ueber (Richtung, Level),
nur FLAT, Setup-Tag AUTOM15_*. Erbt die VOLLE Guard-Kette ueber
_auto_guard('m15') -- der Parameter war laut Docstring genau dafuer vorgesehen,
nachgebaut wurde nichts.

Abweichung ausdruecklich benannt: gemessen wurde der Einstieg AM Level mit Fill
bei Beruehrung, gebaut ist der Markt-Einstieg. Der ist hier mehrfach als der
schlechtere gemessen -- die Live-Zahlen sind eher noch unter -0,16/-0,09 zu
erwarten.

Abbruchregel VORAB fixiert: nach >=20 AUTOM15_*-Trades Verhaeltnis < 1,0 ODER
PF < 1 -> auto_m15 = false. Dieselbe Latte wie B5, damit sie nicht nachtraeglich
wandert.

Verifiziert: Toggle, Snapshot-Felder, Deploy mit --feld auto_m15, ruff F821
(neuer Code sitzt in einem except -- der dokumentierte blinde Fleck), 85 Tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 18:01:52 +02:00
Axel HocksandClaude Opus 5 e48ad80c0a UI aufgeraeumt + Telegram auf Closes reduziert (v=177)
Vier User-Vorgaben:
1. Einsatz-Felder entfernt. Backend bleibt vollstaendig -- Folge: der
   Prozentsatz ist ohne UI nur ueber ini + Neustart aenderbar.
2. BRK-Schalter entfernt, dafuer STOPP (Circuit-Breaker). Bewusster Tausch mit
   Konsequenz: der An/Aus-Schalter des AUTONOMEN Pfads ist aus der App weg (nur
   noch POST bzw. ini), sein Zustand bleibt in der Breakout-Karte sichtbar.
   Dafuer ist die Notbremse bedienbar, die am 17.08. real ausgeloest hat.
   set_circuit_breaker + POST /api/circuit + runtime_state (cb_limit_pct,
   cb_remember -- ohne das Gedaechtnis waere die Prozentzahl nach einmal
   Ausschalten fuer immer weg).
3. Telegram nur noch bei geschlossenen Trades: EINE Filterstelle vor
   _send_telegram_roh statt 17 Einzeleingriffe, _TG_ERLAUBT = ('Trade
   geschlossen',). Umkehren = Liste erweitern. Tages-/Wochenreport wird nur auf
   dem Telegram-Weg still, die E-Mail laeuft weiter.
   EINE Ausnahme mit Bypass: '<ok_word> FEHLGESCHLAGEN' beim Notfall-Close --
   dort ist die Position NICHT zu und es braucht eine Handeingabe.

Verifiziert: /api/circuit vorher 405, nachher 200; Toggle aus->an->8 %/57,94 EUR
persistiert; 85 Tests, node --check, check_nfalle gruen; 0 verwaiste
JS-Referenzen; genau eine Instanz je Port.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 17:03:30 +02:00
Axel HocksandClaude Opus 5 30cb77b795 Breakout-Karte vorbereitet (inaktiv bis Neustart) + Bewertung der Margin-Idee
User-Idee: 40 % Margin manuell, 50 % fuer Breakout reservieren, neue Karte.

Bewertung: (1) 40 % ist der groesste gemessene Hebel (MaxDD 82,8 %) und ein
Schalter ohne Neustart. (2) Reserve ist technisch moeglich (Konto ist
RETAIL_HEDGING), aber _check_auto_squeeze feuert 'nur FLAT' und engine.py hat 17
Einzel-Positions-Annahmen -- Kern-Umbau, kein Parameter. Zudem steht die
Zuteilung gegen die Messung: autonom -4,71 EUR/Lot gegen Mensch +1,56 EUR/Lot.
Live-Befund macht (1) dringlich: freie Margin -6,21 EUR, Margin-Level 99,3 %.
Es gibt derzeit nichts zu reservieren.

Gebaut (inaktiv): history.fetch_squeeze_since, engine._squeeze_b5_cached
(120 s gecacht), Snapshot-Feld squeeze_b5, Karte #card-brk. Eigenes Fenster ab
01.08. -- squeeze_monitor.live rechnet ueber alle 42 Trades, B5 zaehlt 11. Die
Karte zeigt beide Zahlen, weil der Monitor 'ontrack' aus der MECHANIK meldet,
waehrend live Verhaeltnis 0,14 / PF 0,39 steht.

Live aendert sich nichts: Karte ist hidden, renderBrk blendet sie aus solange
squeeze_b5 fehlt. Aktiv nach dem naechsten Neustart (wartet auf den Trade).

BEINAHE-SCHADEN: ein UnicodeEncodeError liess web/app.js mit 0 Bytes zurueck.
node --check bestand trotzdem -- eine leere Datei ist gueltiges JS. Gefangen hat
es erst der Groessenvergleich. Neue Regel: erst .tmp schreiben, Groesse pruefen,
dann os.replace.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 13:32:48 +02:00
Axel HocksandClaude Opus 5 ca61cf1498 S/R als ZONE statt Linie (RZ/SZ, Indikator v1.37)
User-Wunsch nach einem TradingView-Bild: Resistance Zone und eine untere Zone
als farbige Baender. Neu RZ;lo;hi und SZ;lo;hi, im Indikator als OBJ_RECTANGLE
mit Beschriftung, nach rechts verlaengert.

DIE BREITE IST ECHT: sie ist die Spanne der M30-Pivots, die den Cluster gebildet
haben (sr_levels.zonen(), additiv -- cluster() bleibt unveraendert, weil es den
S/R-Auto-Close speist). Live verifiziert: R;82.786 liegt in RZ;82.776;82.797,
S;82.15 in SZ;82.14;82.16. Einzel-Pivot bekommt 0,10xATR Mindestbreite.

ZWEI ABWEICHUNGEN VOM VORBILD, beide begruendet:
(1) KEIN Fibonacci. Das Bild leitet seine Zone aus 0,618/0,658 ab. Fib ist hier
    gemessen und verworfen (04.08.): 54,3/54,5 % Haltequote gegen 55,7/53,8 %
    einer Zufallslinie gleicher Distanz, und schlechter als M30-Pivots.
(2) Die untere Zone heisst SUPPORT, nicht "Cumulative Long Liquidation". Echte
    Liquidationsdaten hat das Projekt nicht; die HL-Waende sind am 17.08. als
    reaktiv gemessen. Bricht die Support-Zone, liegen dort die Long-Stops --
    dieselbe Stelle, ehrlich benannt.

Abschaltbar InpShowZonen. Kompiliert ins richtige Terminal (0/0), deployt,
verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 18:27:26 +02:00
Axel HocksandClaude Opus 5 204e80bb68 Meldungen oben links im MT5-Chart (MS;<text>, Indikator v1.36)
User-Wunsch. Neue CSV-Zeile MS;<text>, im Indikator als gestapelte OBJ_LABEL an
CORNER_LEFT_UPPER (oben rechts sind Kurs, G/V und HL belegt). Inhalt = dieselben
Zeilen wie die Dashboard-Karte "Meldungen": Squeeze, Ueberdehnung, S/R-Ziel mit
P(break), Stop-Seite, News-Blackout.

NUR ZUSAMMENGESETZT, NICHT NEU GERECHNET -- alles aus bereits berechneten
Snapshot-Teilen bzw. _last_sr_close_hint/_last_stop_approach; calendar.blackout()
ist ein reiner Speicher-Zugriff. Der Konsens-Pfeil hat im 5-s-Export-Takt einmal
ein komplettes zweites _verdict() gezogen.

Zwei Felder vorher geprueft statt angenommen: _last_calendar und
_export_meldungen gab es NICHT -- ohne die Pruefung haette das umgebende
except Exception es still verschluckt und die Meldungen waeren dauerhaft leer
geblieben (dieselbe Klasse wie der wave_snap-Fallstrick vom 04.08.).

ASCII-SICHER, real noetig: der erste Lauf lieferte "MS; Kompression  Ausbruch
steht bevor" -- Emoji und Gedankenstrich waren zu Leerzeichen geworden. Der
Indikator liest die CSV nicht als UTF-8 (deshalb steht dort auch
"Unterstuetzung"). Jetzt Ersetzung + Filter auf 32-126.
Verifiziert: MS;Squeeze-Ausbruch LONG @ 82.413, 0 Nicht-ASCII-Zeichen.

Deckel 5 Zeilen a 70 Zeichen; eigener Praefix SRB_MSG_*, damit die Labels beim
Redraw verschwinden. Abschaltbar per [trading] export_meldungen=false oder
InpShowMeldungen. Kompiliert ins richtige Terminal (0 errors, 0 warnings),
deployt und am laufenden Server verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 11:00:34 +02:00
Axel HocksandClaude Opus 5 44191947ac Telegram bei gruener M15-Karte (m15_alert) + Tests verschmutzen nicht mehr das Log
User: "wenn es eine Empfehlung gibt (gruen), schicke eine Telegram-Nachricht."
engine._check_m15_alert, direkt hinter _log_m15_state -- dieselbe Quelle wie
Anzeige und Selbstmessung, damit die drei nicht auseinanderlaufen koennen.

DIE ENTPRELLUNG IST DER GANZE BAU. Roh springt die Karte 85x/Tag auf gruen
(m15_states, 3 Tage nach der Hysterese vom 12.08.) -- das waere Spam. Alle
Stufen an den echten Daten kalibriert, nicht geraten:

  nur Flanke                          85,0/Tag
  + Level & Richtung als Schluessel   23,7/Tag
  + 30 min Mindestabstand             13,3/Tag
  + Fenster 8-20 Uhr (Default)         7,7/Tag
  (Vergleich: Close-Meldung ab 50 EUR  2,4-6,1/Tag)

Nach 4 h darf dasselbe Level erneut melden, sonst verschweigt der Alert ein
Setup, das den ganzen Tag wiederkommt.

Der Text sagt ausdruecklich, dass es KEINE Prognose ist: die Karte automatisch
zu handeln faellt gemessen durch (backtest_m15_auto.py: OeR -0,162/-0,094). Die
Meldung ist ein Hinweis zum Hinsehen fuer den Menschen (+3,20 EUR/Lot ueber 146
Trades). Die P(break)-Formulierung ist wortgleich zu Karte und Chart (v1.35).

13 Tests, Schwerpunkt auf dem was NICHT gesendet werden darf. Mutationsprobe in
vier Zweige, alle gefangen.
DIE PROBE HAT EIN TESTLOCH AUFGEDECKT: das Entfernen der Flankenerkennung liess
zunaechst ALLE Tests gruen, weil Cooldown und 4-h-Schluessel dasselbe abfangen.
Zwei Schutzschichten, die sich maskieren -- dasselbe Muster wie beim Fill-Dedup.
Geschlossen durch test_flankenerkennung_ISOLIERT.

NEBENBEFUND, behoben: Tests schrieben ins Produktions-Log (ueber 150
M15-Alert-Zeilen + Close-Push #4711 aus test_close_buchung). Ich hielt die
Entprellung deshalb zuerst fuer live defekt. conftest.py entfernt den
FileHandler des oil-Loggers jetzt fuer die Sitzung -- vierte Grundregel der
Suite. Verifiziert: Log-Groesse vor und nach einem Komplettlauf identisch.

Live verifiziert: seit dem Serverstart genau 1 Alert trotz mehrfachem
gruen/gelb-Wechsel. 85 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 08:37:53 +02:00
Axel HocksandClaude Opus 5 19ee379f20 rec_outcomes: zweiter Bug gefunden und behoben (timeframe_name)
Der Log verriet die wahre Ursache: 'WaveRecommender' object has no
attribute 'timeframe_name'. rec["tf"] ist leer, also lief der Aufruf
immer in diesen Fallback - AttributeError, im except auf DEBUG
verschluckt.

Der pb_feats-Fix vom 11.08. war damit RICHTIG: er kam an der ersten
Sperre vorbei und legte diese zweite frei. Vorher wurde log_rec_outcome
nie aufgerufen (atr immer 0), deshalb konnte der zweite Bug gar nicht
auftreten.

Richtig ist self._wave_tf_label (die Engine haelt das Label).

Lehre: nach einem Fix nicht nur pruefen, ob die Tabelle jetzt schreibt,
sondern das LOG lesen. Die Zeilen standen seit Stunden da - ich hatte
nur auf INFO gefiltert und daraus geschlossen, es gaebe keine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 20:17:12 +02:00
Axel HocksandClaude Opus 5 bf7e382818 Auto-Signal-Entry (SIG) komplett entfernt inkl. Button (v=166)
User-Entscheidung. Der Pfad war seit 01.08. aus und auf BEIDEN
Ausfuehrungs-Achsen gemessen negativ: Markt-Einstieg in allen 8
Feldern, ruhende Order mit Touch-Fill -0,392/-0,338 in allen 6 und
damit sogar schlechter als Markt. Die +0,35/+0,32 aus
backtest_auto_signal_v3.py galten in Variante B (Fill beim
Close-Bruch) und waren Look-ahead - Aufschlag 0,77-0,85 R. Ursache
strukturell: das Bestaetigungs-Level _pend WANDERT.

Nebenbei entfaellt der offene Churn-Defekt (4x setzen/stornieren in
76 s bei identischem Level, gefunden 06.08., nie behoben).

Entfernt: _check_auto_signal, set_auto_signal, der Signal-Zweig in
_pending_ziel, /api/autosignal, Button + Handler, vier Snapshot-Felder,
die auto_signal*/signal_pending_entry-Leser.
Geblieben: AUTOSIG_*-Trades in der DB, die Backtests, wave_rec.breakout
(speist block_reason) und _confirm_breakout selbst.
Sicherung: .removed_backup/auto_signal_2026-08-12.py + Git.

Das Risiko war nicht SIG, sondern der GETEILTE Pending-Manager (zwei
getrennte Manager wuerden sich gegenseitig stornieren). Deshalb wurde
das Squeeze-Verhalten VOR dem Eingriff in tests/test_pending_ziel.py
festgenagelt - 7 Tests, vorher gruen, laufen unveraendert weiter.

Zwei Folgefehler fing die Pruefkette sofort: ruff F821 ein verwaistes
_t, py_compile ein dangling if. Zwei Tests wurden mitgezogen statt
geloescht - test_signal_fill_long ist jetzt umgedreht (unbekannte
Quelle darf NICHT als Squeeze durchgehen).

Live verifiziert: alle vier Snapshot-Felder weg, Endpunkt tot,
auto_squeeze/squeeze_pending unveraendert, 67 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 18:47:28 +02:00
Axel HocksandClaude Opus 5 5fb1d7e268 M15-Karte: Flacker-Ursache gemessen, Hysterese + EINE Quelle (v=165)
Die Karte wechselte den Zustand alle 12 Sekunden (~1.030/Tag) - der
Grund, warum ihre Selbstmessung so stark geclustert war.

Mein erster Verdacht (das Level im Wechsel-Schluessel) war falsch.
Ausgezaehlt ueber 3.525 Zeilen: status 32,9 %, lesart 32,7 %,
level allein nur 7,6 %. Das Level zu entfernen braechte 3.525 -> 3.248,
also nichts. Der Zustand selbst zappelt: gap <= 0,5 und das 45/55-Band
von P(break) sind stetige Groessen um ihre Schwelle.

Das Projekt hatte die Loesung schon (analyze_pbreak_flicker.py, 14.07.:
Hysterese +-5 Pp) - die Karte umging sie, weil sie P(break) selbst neu
rechnet. Jetzt dieselbe Hysterese auf beide Schwellen: Status gruen ab
0,50 / zurueck erst ueber 0,60; Lesart gerichtet ab 40/60 / zurueck
erst innerhalb 45/55. Simuliert: 64 % weniger Wechsel.

Zweiter, groesserer Befund: Status und Lesart wurden an DREI Stellen
unabhaengig gebildet und wichen bereits ab - der Logger kannte den
"kein Veto"-Fall des Frontends nicht, protokollierte also einen
anderen Zustand als angezeigt wurde. Jetzt eine Quelle: _m15_setup
liefert status/lesart/nah im Snapshot, Logger und Frontend lesen sie.

Die alten 3.525 Zeilen sind mit den neuen nicht vergleichbar; die
Selbstmessung beginnt faktisch neu (Stichtag 12.08.). Kein Verlust -
sie liess vorher ohnehin kein Urteil zu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 09:37:12 +02:00
Axel HocksandClaude Opus 5 b2a1e35f5e rec_outcomes: Fix hat nicht gewirkt - jetzt instrumentiert
Korrektur meiner Behauptung vom 11.08. Nach dem Neustart um 22:45 gab
es bis 09:00 mindestens 10 gerichtete Episoden, und rec_outcomes stand
weiter bei 0 Zeilen. Die Praemisse (falsches dict: s.get("pb_feats")
auf dem MT5Data- statt dem Wave-Snapshot) ist live belegt - die
WIRKUNG des Fixes war es nicht. Ich habe "behoben" geschrieben, ohne
sie zu pruefen.

Warum es von aussen nicht feststellbar war: der except-Zweig loggte
auf DEBUG, der Logger steht auf INFO. Genau die Blindheit, die den
Ausfall fuenf Tage getragen hat.

Jetzt melden sich BEIDE Zweige sichtbar:
- Erfolg: "rec_outcome #<id>: LONG @ <px> atr=<atr>" (INFO)
- Fehlschlag: "rec_outcome NICHT geschrieben: atr=.. px=.. pb_feats=.."
- Exception: WARNING statt DEBUG, mit repr

Es feuert nur bei einem echten Richtungswechsel, also selten - kein
Laerm. Ursache offen bis zur naechsten Episode.

Der Telemetrie-Puls ist der Grund, dass die ausbleibende Wirkung
ueberhaupt auffiel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 09:21:50 +02:00
Axel HocksandClaude Opus 5 b18b594639 Systemzustand in den Tagesreport - der fehlende letzte Meter
Selbstaendige Empfehlung nach der Gesamtpruefung, vom User beauftragt.

Befund: die Erkennung funktioniert, die Zustellung nicht. Sieben
Waechter, jeder nach einem eigenen Vorfall gebaut, jeder funktioniert -
und trotzdem blieben diese Woche sechs Zustaende tagelang unbemerkt,
vier davon waren bereits erkannt.

Belegt an den Marker-Dateien: cfg_auto_sr_close traegt 06.08. 18:10,
cfg_auto_squeeze sogar 02.08. Der Config-Waechter meldet je Schluessel
genau einmal und schweigt danach fuer immer. auto_sr_close war damit
fuenf Tage aus - gemessen +350,81 EUR ueber 43 Trades. Ursache ist ein
Kategorienfehler: die Marker-Logik behandelt einen Dauerzustand wie ein
Einmal-Ereignis.

Gebaut: engine._system_status() als Block im Tagesreport (07:30,
Telegram + E-Mail) - der einzige Kanal, der nachweislich jeden Tag
ankommt. Saubere Trennung: Popup = "etwas Neues", Report = "so steht
es gerade". Reine Anzeige.

- telemetrie_puls() liegt in core/history.py, beide Nutzer rufen
  dieselbe Funktion (Skripte importieren core, nie umgekehrt)
- measurement_reminder wird lazy und gekapselt importiert; ein
  Fehlschlag wird sichtbar gemeldet statt still verschluckt
- tests/test_system_status.py: 7 Tests, Schwerpunkt Ausfallpfade -
  der Report darf an dieser Zeile nie scheitern

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 22:43:24 +02:00
Axel HocksandClaude Opus 5 dca3c11bbd Gesamtpruefung 2026-08-11: drei Defekte behoben
Zweiter vollstaendiger Durchlauf nach docs/review-prompt.md.

BEFUND 1: rec_outcomes war seit dem Einbau (06.08.) still tot - 0
Zeilen in 5 Tagen. _run_analysis las s.get("pb_feats"), aber s ist der
MT5Data-Snapshot; pb_feats lebt im Wave-Snapshot. _atr also immer 0,0
und die Schreibbedingung nie erfuellt. Kein NameError (ruff sieht
nichts), und das umgebende except loggt auf DEBUG. Aufgefallen nur,
weil die Tabelle mit 0 Zeilen neben ihren Schwestern stand.
Generalisiert als measurement_reminder.telemetrie_puls(): jede
Telemetrie-Tabelle muss einen Puls haben. Erster Lauf meldet genau
diesen Fund, alle uebrigen gruen.

BEFUND 2: der Divergenz-Waechter war selbst driftend. Abschnitt A
verglich gegen 43 % WARTEN - seit 05.08. ausdruecklich ungueltig (das
misst _build allein); richtig sind 80,5 %. Und entry_room galt als
"live-only", obwohl es seit 04./05.08. modelliert wird.
A: +50,8 Pp Warnung -> +13,3 Pp OK. B: 63,9 % -> 5,0 %.

BEFUND 3: P(break) ist wieder kalibriert (Delta -1,7 Pp nach +14,3 Pp
am 07.08.) - stuetzt den Schluss, dass die gewanderte Basisrate ein
Zeitraum-Effekt war.

Sauber: alle Standardpruefungen, 0 fehlende Frontend-IDs, mt5_lock,
Broker-Zeit, Race-Klasse. Performance: Snapshot-Median 15,9 ms, alle
heissen Abfragen ueber Index - keine Optimierung noetig.

Kein toter Code geloescht: die vermeintlich verwaisten Snapshot-Felder
sind Diagnose-Oberflaeche (vier davon heute zur Deploy-Verifikation
benutzt).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 22:31:42 +02:00
Axel HocksandClaude Opus 5 4eb92bf192 Telegram: Close-Benachrichtigung ab Schwelle + Auto-Squeeze wieder an
Diagnose zu "ich bekomme keine Telegram-Nachrichten mehr": der Kanal
war intakt (getMe/getChat ok, Testnachricht zugestellt, keine einzige
Fehlermeldung im Log, Tagesreport kam taeglich). Ursache war, dass
ALLE NEUN sendenden Ausloeser aus waren - Auto-Squeeze (ueber
runtime_state.json, unbemerkt), Auto-Signal, S/R-Close, Flip-Close,
15-Minuten-Regel, Circuit-Breaker und die drei Notfall-Stop-Modi.
Jede Abschaltung war fuer sich begruendet; zusammen ergaben sie eine
Stille, die niemand beschlossen hatte.

Gebaut: engine._check_close_notify - Telegram bei JEDEM geschlossenen
Trade ab close_notify_min_eur (50, 0 = aus). Haengt an keiner
Automatik, feuert also auch bei manuellem Close und Broker-SL. Der
-87-EUR-SL vom 10.08. kam bisher wortlos.

Schwelle aus den Daten: bei ~17 Trades/Tag rund 2,4-6,1 Meldungen/Tag,
erfasst 54-80 % des bewegten Geldes. Absolute Euro-Schwelle altert mit
der Positionsgroesse - bewusst so, ein Mensch denkt in Euro.

Der Unterschied zum frueher entfernten Push ist die Schwelle, und sie
liegt in der Engine statt in der DB-Schicht. Vorgemerkt statt sofort
gesendet, weil der Flat-Zustand dem DB-Schreiber einen Tick voraus
sein kann (exit_time IS NULL heisst "noch nicht fertig").

- tests/test_close_notify.py: 7 Tests, Netz abgefangen
- Mutationsprobe in beide kritischen Zweige, beide gefangen
- Snapshot-Feld close_notify_min (belegt die Schwelle im Prozess)
- Auto-Squeeze wieder AN ueber /api/autosqueeze (ini + runtime_state)
- v=161

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 09:22:41 +02:00
Axel HocksandClaude Opus 5 47c596ed70 M15-Karte: Gate 3b zeigt Motor-Block + RAUM je Richtung
Anlass Trade #49671601 (-87,03 EUR). Die Praemisse "SL trotz LONG-
Empfehlung" stimmte nicht: 138 Zeilen zwischen Ein- und Ausstieg,
100 % WARTEN (entry_room 76 %, breakout_pending 19 %, min_conf 5 %).
Gesehen wurde "verboten: SHORT" - ein Veto. Dritter Fall derselben
Veto->Richtung-Umwandlung in dieser Karte (Code 08.08., Geometrie
10.08. frueh, jetzt die Lesart).

Der eigentliche Befund: entry_room und Gate 3 lesen DIESELBE Tatsache
("ein Level ist nah") mit umgekehrtem Vorzeichen. Beide gemessen,
beide richtig - ueber verschiedene Trades (Markt-Einstieg mit dem
Level als Hindernis vs. ruhende Order AM Level). Die Karte zeigte nur
die gruene Haelfte; die Block-Grund-Zeile war mit der Gesamtempfehlung
verschwunden.

Gebaut: Zeile 3b (#m15-motor) mit block_reason im Klartext + Raum je
Richtung. Reine Anzeige. Das Status-Banner bleibt bewusst unveraendert
- es auf gelb zu ziehen waere eine Strategie-Aenderung, und die einzige
Live-Zahl dafuer (-9,91 vs +3,24 EUR/Lot, n=76) hat ein KI, das die
Null enthaelt.

- wave_rec.room_info(): EINE Implementierung fuer Gate und Anzeige,
  _room_gate rechnet jetzt darueber (kein Nachbau)
- tests/test_room_info.py: Bitgleichheit ueber 2.000 Zufallslagen x 3
  Signale, Gate feuerte >300x; Grenzfall-Test fuer die Rundung
- v=160

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 09:09:27 +02:00
Axel HocksandClaude Opus 5 5474c2be61 Gate 4 der M15-Karte: Ziel nur noch in der ERLAUBTEN Richtung
User-Fund: Karte zeigte "verboten SHORT" (= LONG erlaubt) UND ein Ziel
0,15 $ UNTER dem Kurs. Die Arithmetik war korrekt - aber fuer die
verbotene Richtung.

Ursache: das Ziel war schlicht das entferntere der beiden Level
(max nach gap), ohne Richtungspruefung. Strukturell steckte dahinter
ein Fade-Trade (Gegenlevel als Ziel = Mean Reversion) in einer Kette,
deren Gate 2 ein Trendfilter ist - zwei unvereinbare Konzepte. Damit
derselbe Fehler, wegen dem die Gesamtempfehlung entfernt wurde: aus
einem VERBOT wird ueber die Hintertuer wieder eine RICHTUNG.

Fix nach der gemessenen Population (backtest_m15_gates.py): Einstieg
am naechstgelegenen Level, Richtung = die vom HTF erlaubte. Ein Ziel
nur, wenn es jenseits dieses Einstiegs in der erlaubten Richtung
liegt; sonst "kein Ziel" mit Grund statt einer erfundenen Zahl.
Richtung steht jetzt im Anzeigetext.

- tests/test_m15_ziel.py (6 Tests, Invariante ueber 32 Konstellationen)
- Mutationsprobe: alte Zeile zurueck -> 4 von 6 Tests fallen
- deploy.py --feld unterstuetzt jetzt Punktpfade (m15_setup.ziel_grund)
- v=159

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 06:36:02 +02:00
Axel HocksandClaude Opus 5 b8705e297f Kegel mit Adaptive Conformal Inference nachkalibriert (v=158)
Der Kegel war seit dem 31.07. dokumentiert 3-5 Pp ZU ENG - 80 % nominal gegen
real 76,7 / 76,6 / 75,3 % - und blieb es, weil Nachfitten das Problem nur
verschiebt. ACI justiert stattdessen ONLINE nach jedem aufgeloesten Fenster und
konvergiert nachweislich gegen die Zielabdeckung, auch unter Drift.

EHRLICH ZUR BAUART: die Lehrbuch-Form justiert alpha und schlaegt das Quantil
nach. Hier liegt nur eine feste Quantil-Tabelle vor, kein Verteilungsobjekt -
umgesetzt ist die multiplikative Variante:
    s <- s * exp(gamma * (1{verfehlt} - alpha_ziel)),  gamma 0,02, Deckel 0,7-2,0
Dieselbe Regelungsidee, aber die Konvergenz-GARANTIE der Originalform ist damit
nicht woertlich uebertragen.

Verifiziert: bei exakt 20 % Verfehlern bleibt die Skala bei 1,0000 - der
Fixpunkt stimmt. Simulation aus der dokumentierten Lage (76,6 %): nach ~50
Checks um 80 %. Die Skala pendelt um das Ziel statt exakt zu treffen - das ist
das bekannte ACI-Verhalten (garantiert ist die Langfrist-Abdeckung).

NICHT-UEBERLAPPEND geloggt (neue Tabelle cone_checks): ein 120-min-Fenster alle
5 min waere 24-fach ueberlappend - genau die Cluster-Verzerrung, an der
analyze_hl_funding.py aufgelaufen ist und die die Faelligkeitsbedingung
pbreak_accuracy_v2 um das Zehnfache danebenliegen liess. Je Horizont startet ein
neuer Check erst, wenn der vorige ablief -> 48/24/12 Checks je Tag.

Neustart-fest ueber runtime_state.json. build() ohne skalen liefert bitgenau die
alten Werte (additiv geprueft).

ZWEI EIGENE PLATZIERUNGSFEHLER, beide gefangen: der Lade-Block landete zuerst
HINTER den except-Klauseln von _load_runtime_state, wo st nicht mehr existiert;
und beim M15-Setup landete ein Block mitten in einem mehrzeiligen Aufruf. Der
erste waere stillschweigend nie gelaufen - gefunden nur, weil ich die Funktion
danach gelesen habe statt dem gruenen py_compile zu trauen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 23:45:26 +02:00
Axel HocksandClaude Opus 5 86c432f791 M15-Karte misst sich selbst + Ausfuehrungsqualitaet sichtbar (v=157)
Nach Web-Recherche umgesetzt, Punkte 2 und 3 der Wahl.

SELBSTMESSUNG (neue Tabelle m15_states): die Karte hatte KEINE Rueckkopplung -
geprueft, es gab kein Logging. Das war die auffaelligste Luecke: jeder Ausfall,
der in diesem Projekt je aufgedeckt wurde, kam aus einer Rueckkopplung
(pbreak_predictions entlarvte den Modellausfall LIVE, was kein Backtest konnte;
der B4-Monitor die Squeeze-Drift). Die Karte haette monatelang falsch stehen
koennen.
Neu: eine Zeile je ZUSTANDSWECHSEL, nach 30/60 min gegen candles_m1
ausgewertet, Ergebnis als Zeile 6 in der Karte. Gewertet wird die LESART, nicht
der Status, und nur die gerichtete (45-55 % zaehlt nicht mit). Gegen 50 % lesen.
Nur bei Wechsel, nie je Tick - sonst dieselbe Cluster-Verzerrung, die am 07.08.
elf widerlegte Hypothesen ausgeloest hat. Live verifiziert: 1 Zeile trotz
laufendem Sekundentakt.

AUSFUEHRUNGSQUALITAET (Zeile 7): analyze_squeeze_entry_gap.py existiert seit dem
05.08. und misst die TCA-Kennzahl (Arrival-Price-Slippage) - niemand hat je
hineingesehen. Dabei war das der einzige Erfolgsmassstab des Stop-Order-Umbaus
und zugleich der groesste je gemessene Hebel (+0,32 R). Jetzt steht der
Zaehlstand in der Karte: 3 von 12 Bot-Trades seit dem Umbau.

NICHT gebaut: der Kegel mit Adaptive Conformal Inference. Er ist mit
76,7/76,6/75,3 % gegen 80 % Nennwert dokumentiert zu eng, und ACI waere die
Standardmethode (adjustiert online, garantiert Konvergenz auch unter Drift).
Bleibt offen.

BEIM BAU EIN NAMEERROR IM 1-SEKUNDEN-PFAD, VOM LINTER GEFANGEN: der erste
Entwurf berechnete _m15 in _run_analysis und benutzte es in snapshot(); dort
gibt es weder market noch wave_snap. py_compile sieht das NICHT, ruff F821
meldete 4 Befunde. Genau die Fehlerklasse, fuer die der Linter am 07.08.
eingebaut wurde - und der erste echte Fang. Zweiter Fehler beim Verschieben:
der Block landete mitten in einem mehrzeiligen Aufruf. Beide behoben.

DB-Backup: oil_widget_history.db.bak-2026-08-08-m15states

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 23:38:56 +02:00
Axel HocksandClaude Opus 5 30830d76b1 M15-Karte: Bias war ein Richtungsgeber - korrigiert zum Veto (v=155)
Tagestest an 07.08. (test_m15_karte_tag.py) deckt einen strukturellen Fehler in
meiner eigenen Karte auf.

Rohzahlen: 92 M15-Bars, davon 46 (50 %) auf GRUEN. Entkoppelt auf
zusammenhaengende Bloecke bleiben 13 Setup-Episoden - und ALLE 13 waren LONG,
an einem Tag, der von 78,399 auf 77,383 FIEL (-1,016 $). Trefferquote 0 %,
OeR -0,753, SumR -9,79.

Ursache ist nicht Pech, sondern ein Denkfehler: gemessen ist "gegen den
M30-Trend zu handeln halbiert den Edge" - eine VERBOTS-Aussage. Ich hatte
daraus "M30+H1 einig -> Bias LONG" gemacht, also einen Richtungsgeber. Exakt
der Fehler, wegen dem die Gesamtempfehlung entfernt wurde (Richtung dort 48-51 %
Treffer). Die nachlaufende EMA zeigt im Trendtag stur in die alte Richtung -
dokumentiert seit analyze_signal_live.py.

Korrigiert: das Feld liefert nur noch, welche Richtung VERBOTEN ist
(bias.verboten); bias.richtung ist dauerhaft None. Das Banner nennt keine
Richtung mehr:
  "BEDINGUNGEN OK @ 77,098 - Order ANS LEVEL, nicht zum Markt - SHORT vermeiden"

Zwei weitere Befunde aus demselben Test, offen dokumentiert:
- Das Kosten-Gate blockte 0 von 92 Bars. Auf M15 liegt Spread/ATR bei ~0,10,
  die Schwelle bei 0,32 - das Gate ist dort faktisch dekorativ.
- Die strengere Bias-Variante (M30 UND H1) unterscheidet sich kaum von der
  laxen (46 gegen 47 gruene Bars) - die Zusatzstrenge kostet nichts, bringt
  aber auch nichts.

Auch ein Fehler in meinem TEST, dokumentiert: der erste Lauf zaehlte 46
fortlaufende Bars als 46 Trades und meldete 7 % Trefferquote - eine Bewegung
46-mal gezaehlt. Erst die Entkopplung auf Episoden macht die Zahl lesbar.

WARNUNG zur Beweiskraft: EIN Tag ist kein Edge-Nachweis. Belastbar ist hier
nicht die Trefferquote, sondern der MECHANISMUS - und der ist aus zwei
Halbjahren dokumentiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 23:14:47 +02:00
Axel HocksandClaude Opus 5 e5adfc9757 Slippage vs Vola-Regime gemessen + Ziel-Erreichbarkeit gebaut (v=154)
MESSUNG (analyze_slippage_vola.py, 337 SL-Closes): die Exit-Slippage steigt
MONOTON ueber alle vier Delta-ATR-Quartile:
  0,39-0,91   Schaetzer 0,0200 $
  0,91-1,08             0,0390 $
  1,08-1,26             0,0645 $
  1,26-2,39             0,0839 $   Faktor 4,19x
Mechanismus stimmig: die Slip-RATE bleibt flach (20-23 %), die GROESSE waechst
(0,094 -> 0,396 $). Es rutscht nicht oefter, sondern weiter.

ABER: der Bootstrap auf die DIFFERENZ oben-unten ergibt [-0,012 ... +0,183] -
enthaelt die Null. Bei n=85 je Quartil NICHT statistisch belegt.
Meine vorab fixierte Regel (Faktor >=2 UND monoton) war damit
unterspezifiziert - sie haette ein Konfidenzintervall verlangen muessen.
Konsequenz: gebaut als reiner HINWEIS im Kosten-Gate, kein Gate, und die
Beschriftung sagt "historisch ~4x hoeher", nicht "belegt".

ZIEL-ERREICHBARKEIT (Vorschlag 3, Decay-Clock): reine Geometrie auf dem
kalibrierten Kegel - passt das Gegenlevel noch in das 80-%-Band des jeweiligen
Horizonts? Live: Ziel 77,784 (0,401 $) liegt im 120'-Kegel, nicht im 30'/60'.
Die im Vorschlag mitgedachte Annahme "je laenger, desto eher bricht es" ist
BEWUSST NICHT eingebaut - sie ist nicht belegt (Touch-Zahl: umgekehrtes U auf
4 Live-Tagen, im Backtest +0,010 AUC, nach dem Nachtrainieren gar nichts mehr).

Umsetzung ohne zweiten MT5-Fetch: _vola_regime puffert den ATR_M15 aus dem
ohnehin laufenden Turn-Fetch (deque, ~5 h). Kaltstart liefert datr=null statt
zu raten - live verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:59:37 +02:00
Axel HocksandClaude Opus 5 44955bf70a M15-Karte "Setup-Bereitschaft" gebaut - Ersatz der Gesamtempfehlung (v=153)
Nach drei negativen M15-Messungen (Squeeze-Einstieg, VWAP-Baender, Exit-ATR)
steht fest: auf M15 traegt keine Richtungsquelle. Gebaut ist deshalb bewusst
KEINE Empfehlung, sondern eine sequenzielle Gate-Kette:

  [1 HTF-BIAS M30/H1] -> [2 KOSTEN Spread/ATR_M15] -> [3 LEVEL & KEGEL]
  -> Order AM LEVEL

Der Unterschied zur alten Karte ist grundsaetzlich: dort wurden Stimmen zu einem
Bias VERRECHNET (gemessen 48-51 % Treffer), hier muss jedes Gate EINZELN
passieren. Ein gefallenes Gate laesst sich nicht durch ein anderes ausgleichen.

Nur belegte Bausteine: HTF-Trend (einziger robuster Filter, Edge x2), Kosten
(M15 gemessen 0,104 gegen M5 0,193), naechstes stehendes Level + P(break),
Kegel (out-of-sample kalibriert, 80-%-Band trifft 77 %), Veto (-6,60 EUR/Lot).

Status-Banner: SETUP BEREIT / WARTEN AUF LEVEL / KEIN TRADE. Es bestaetigt
ausdruecklich auch das NICHT-Handeln - die gemessene Kern-Leckage sind
diskretionaere Abweichungen.

Die Order-Buttons werden BEWUSST NICHT gesperrt (gegen den Vorschlag
"ausgrauen"): hartes Blockieren wurde im Projekt verworfen, und
User-Uebersteuerungen liefen gemessen 68 % WR.

Umsetzung: engine._m15_setup() setzt nur zusammen, was der Snapshot ohnehin
erzeugt. Neu gerechnet wird allein das M15-Kosten-Verhaeltnis und P(break) fuer
das naechste Level. Dafuer veroeffentlicht wave_rec jetzt tf_atr (ADDITIV) - der
ATR je Zeitebene wurde im Turn-Fetch laengst berechnet, war aber nirgends
abrufbar.

P(break)-Merkmale bleiben auf M5 (Modell ist darauf trainiert, Fix 2026-07-13).

Mit 5 Szenarien getestet (alles passt, Bias uneinig, Kosten teuer, Level zu
weit, Kaltstart ohne ATR_M15 -> kein Absturz), live verifiziert ueber
deploy.py --feld m15_setup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 15:18:29 +02:00
Axel HocksandClaude Opus 5 30c8616280 Gesamtempfehlung entfernt (User-Entscheidung 2026-08-08)
"Funktioniert so leider nicht, entferne es komplett - wir bauen etwas Neues."

Entfernt: Headline, Konfidenz-Ring, Bias-Nadel, Modul-Chips, Konsens-Zeile,
Block-Gruende. Dazu renderVerdict(), die zugehoerigen 24 CSS-Regeln,
docs/gesamtempfehlung.md und die Snapshot-Felder `verdict` + `block_mix`.

Die Aggregation war reine ANZEIGE - vor dem Loeschen belegt: die Order-Logik
haengt an `wave_signal` bzw. `checklist`, nicht am Verdict (Blinken app.js:821,
Order-Dialog 1312/1366/1391). Orders, Alarme und das gemessene Veto
(-6,60 EUR/Lot) sind unberuehrt.

BEHALTEN (sassen nur in derselben Karte, je eigene Beleglage, User-Entscheidung):
  Zeitebenen-Ampel  #wave-turns  - war aus der Welle-Karte dorthin verschoben
  Erwartete Spanne  #kx-cone     - out-of-sample kalibriert, trifft real ~77 %
  Selbstkalibrierung #kx-selfcal - misst das Wellen-Signal, das bleibt
  HL-Kontext        #hl-note     - lief in renderVerdict mit, schreibt aber in
                                   die Meldungen-Karte
Sie stehen jetzt in der neuen, schlanken Karte "Marktkontext" (#card-kontext).
IDs von vd- auf kx- umbenannt, damit keine tote Nomenklatur zurueckbleibt.

verdict_votes wird WEITER geloggt (User-Entscheidung): `_verdict()` bleibt
bestehen und laeuft 1x/min fuer die Telemetrie sowie fuer den optionalen
MQL5-Konsens-Pfeil. Aus dem 1-s-Snapshot ist es raus - dort waere es Arbeit fuer
eine Anzeige, die es nicht mehr gibt.

Verifiziert: node --check gruen, 34 Tests gruen, 0 verwaiste $("id")-Zugriffe
(die zwei Treffer 'neu'/'x' stehen in Kommentaren), CSS-Klammern ausgeglichen
(287/287), @media und @keyframes intakt. Zeile 1572 (_SQM_VERDICT[d.verdict])
ist der SQUEEZE-MONITOR-Verdict und bleibt.

Asset-Version v=152.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 14:12:27 +02:00
Axel HocksandClaude Opus 5 aefac274d3 Level-Auswahl: Nachbau behoben (core/sr_levels.py) - Luecke bleibt offen
Auftrag zum benannten naechsten Schritt: die Backtests bauten die
Live-Level-Auswahl nach, statt sie zu benutzen. Drei echte Abweichungen:

  1. Der Nachbau clusterte den GEMISCHTEN Rohpool (sorted(ch+cl)); live werden
     ph und pl GETRENNT geclustert. Das ist exakt der Fehler, den der Live-Code
     als behoben dokumentiert ("nicht vorher zusammenlegen!" - Ketten-Mega-
     Cluster in dichten Zonen). Gemessen: 4,5 % aller Zeitpunkte hatten einen
     anderen Widerstand.
  2. Live rundet jede Linie auf 3 Stellen, der Nachbau nicht.
  3. Live fuehrt Widerstand und Unterstuetzung mit getrennter Hysterese.

Geloest ueber core/sr_levels.py (cluster/linien/naechste/halten).
engine._draw_levels ruft es auf, Verhalten bitgenau unveraendert
(tests/test_sr_levels.py, 6 Tests, je 300-400 Zufallsfaelle). Der Test enthaelt
die Gegenprobe, dass der Nachbau wirklich abwich - sonst waere nicht belegt,
dass es etwas zu beheben gab.

backtest_pbreak_retrain.build_levels bleibt unveraendert (Migrations-Regel: die
daraus gefitteten Live-Gewichte duerfen sich nicht rueckwirkend verschieben).
Daneben neu: build_levels_live fuer kuenftige Fits.

ABER die Korrektur schliesst die Basisraten-Luecke nicht: 38,0 -> 38,3 %,
live 52,7 %.

Damit fuenf Hypothesen geprueft und alle widerlegt:
  Niveau/Achsenabschnitt   Roll-Achse faellt live durch
  Vola-Regime              ueber 5 Quintile flach (37,0-39,2 %)
  Sammelart                -1,7 Pp, falsche Richtung
  ATR-Floor-Artefakt       +2,8 Pp; bei live-gleichem ATR erst 40,1 %
  Level-Auswahl            +0,4 Pp

Nebenbefund: 53,9 % aller Backtest-Bars sitzen auf dem ATR-Floor 0,12, live nur
5,4 % - der Backtest-Zeitraum ist deutlich ruhiger. Der ATR selbst stimmt aber
ueberein (Median live 0,2167 gegen letzte 7 Tage 0,2174).

Kein Notfall: auto_sr_close ist false, das Modell schliesst keine Trades.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 11:30:07 +02:00
Axel HocksandClaude Opus 5 fd3c7f57a5 Live-Code von Backtest-Skript entkoppelt: core/squeeze_scan.py
core/engine.py (squeeze_monitor) und weekly_review.py importierten
backtest_breakout_squeeze - die Abhaengigkeitsrichtung war verkehrt:
ein Fehler im Backtest konnte den laufenden Bot treffen.

Schwerer wog, WIE die Parameter hineinkamen:

    BQ._N = _SQ_N; BQ._K = _SQ_K

Das mutiert Modul-Globale eines Backtests, wirkt prozessweit und damit auf
jeden anderen Nutzer desselben Moduls im selben Prozess. Die Werte weichen
real ab (Backtest _N=12, live _SQ_N=10).

Geloest ueber core/squeeze_scan.py - Parameter stehen in der Signatur.
backtest_breakout_squeeze.py leitet nur noch weiter, damit es EINE
Implementierung gibt statt zweier (der sim_run/_ema_series-Fehler).

Der Exit ist bewusst NICHT mitrepariert: exit_legacy ist eine bitgenaue
Kopie inkl. seiner Abweichungen vom kanonischen Exit (Trail 1,5 statt 1,0,
kein Lock/Time-Stop/TP, max_hold 288 statt 200). Damit misst der B4-Monitor
gegen einen veralteten Exit - separater, offener Befund. Ihn hier still
mitzuaendern haette die Vergleichsgrundlage verschoben.

Bitgenauigkeit bewiesen (tests/test_squeeze_scan.py): die alte Fassung liegt
eingefroren im Test und laeuft gegen die neue ueber 500 synthetische Reihen
x 3 Multiplikatoren. Ein Vorher/Nachher-Lauf waere ungueltig gewesen - der
Backtest zieht Bars live aus MT5, das Fenster verschiebt sich staendig.

Test selbst per Mutationsprobe geprueft: 5 von 6 eingebauten Fehlern schlagen
an, der sechste (d>0 -> d>=0) ist beweisbar aequivalent, da d nur +-1 ist.

Live-Gegenprobe auf 9000 M5-Bars: n=112, Treffer 44%, OeR +0,178, PF 1,26.

Aktivierung beim naechsten Neustart - bei offener Position kein Neustart fuer
eine verhaltensneutrale Aenderung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 07:21:45 +02:00
Axel HocksandClaude Opus 5 caa937f87d Gesamtempfehlung: nur noch Module mit Stimmrecht · Tooltips ueberall (v=147)
· Modul-Chips: neues `used`-Flag in _verdict.add(). used=False = dauerhaft
  entmachtet (Elliott, Orderbuch — beide heute gemessen ohne Inhalt), das
  Frontend filtert sie aus. ⚠ Sie bleiben im Snapshot und in verdict_votes:
  log_verdict_votes speist daraus die Telemetrie und die 25.000-Verdict-Messung
  braucht die Reihe weiter. Ausgeblendet wird die Anzeige, nicht die Messung.
  Module mit weight=0 aus SITUATIVER Stille (Welle bei WARTEN, Squeeze ohne
  Ausbruch) bleiben sichtbar.
· #vd-note (Muenzwurf-Hinweistext) entfernt, samt CSS. Die Aussage steht
  weiter im Karten-Tooltip.
· Tooltips auf allen Dashboard-Anzeigen (59 title-Attribute): Karten,
  Header-Boxen, Trade-Leiste, Anzeige-Elemente. Wo eine Messung existiert,
  steht sie drin. Gesetzt ueber set_tooltips.py — idempotent, ergaenzt nur
  fehlende title=.

Verifiziert: keine Anzeige mehr ohne Tooltip, keine doppelten IDs, Tag-Balance
ok, v=147 ausgeliefert, Elliott/Orderbuch used=False, eine Instanz auf 8000.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 23:46:31 +02:00
Axel HocksandClaude Opus 5 2cdd1ba0e8 Hyperliquid geprueft: Orderbuch-Stimme raus, Funding gemessen (traegt nicht),
Kontext in die Meldungen (v=145)

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

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

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

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

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 23:38:01 +02:00
Axel HocksandClaude Opus 5 874ee16e00 Gesamtempfehlung: Selbst-Kalibrierung, voller Ausrichtungs-Split, Block-Gruende,
Elliott entmachtet (v=144)

Vier Verbesserungen, alle aus dem Gemessenen abgeleitet — kein neues Signal.
Ausgangspunkt: die Karte hat genau eine belegte Funktion, das Veto; als Prognose
ist sie ein Muenzwurf (48-51 % ueber 1.071 Episoden).

(1) SELBST-KALIBRIERUNG. Neue Tabelle rec_outcomes: eine Zeile je EPISODE
    (Richtungswechsel, nicht je Minute), Auswertung ~alle 5 min gegen candles_m1
    nach 30/60 min, Snapshot rec_track, Zeile #vd-selfcal. Gegen 50 % zu lesen.
    Warum der groesste Hebel: die Qualitaet war bis heute unsichtbar und musste
    auf Nachfrage rueckwirkend gemessen werden. Dasselbe Muster
    (pbreak_predictions) hat den Ausfall des P(break)-Modells LIVE aufgedeckt.
    Mit 4 Szenarien getestet (tests_rec_outcomes.py). Zwei Fehlschlaege dabei
    waren Testfehler, keine Code-Fehler — dokumentiert.

(2) alignment_stats auf die VOLLE Historie (1.216 statt 40 Trades) und
    zusaetzlich je Lot. Absolute Euro-Vergleiche sind bei wechselnder
    Positionsgroesse ungueltig (Lehre 04.08.). Damit steht die einzige
    beidhaelftig robuste Aussage der Karte auf ihrer vollen Stichprobe.

(3) Block-Gruende sichtbar (block_mix -> #vd-blocks): "heute X % ohne Block ·
    entry_room … · min_conf …". Bisher nur per DB-Abfrage zu beantworten.

(4) ELLIOTT: Verdict-Gewicht 1,0 -> 0. Gemessen ueber 15.544 Zeilen hatte es mit
    1.384 Episoden die groesste Stichprobe der Tabelle und ist darin flach
    (-0,075/+0,032, 50 % Treffer) — bei 25,9 % Einfluss auf die Nadel, weil es
    in nur 1 % der Zeilen schweigt. Chip bleibt, Stimme entfaellt.
    ⚠ Folge: die Nadel schlaegt staerker aus (real +0,33 -> +1,00).

⚠ Namenskollision beim Bau gefunden und behoben: die neue Klasse hiess zuerst
.vd-track — so heisst bereits die Schiene der Bias-Nadel; sie waere
ueberschrieben worden. Jetzt .vd-selfcal.

Live verifiziert: alignment je Lot, block_mix (93 von 1381 ohne Block),
rec_outcomes angelegt, Elliott weight=0 bei erhaltenem Chip, v=144 ausgeliefert,
eine Instanz auf Port 8000.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 23:21:52 +02:00
Axel HocksandClaude Opus 5 3c1442109d Pending-Fill: Bot-Trades wurden nicht als solche gebucht
Auftrag "überprüfe die heutigen autotrades": die DB meldete für den 06.08.
null Bot-Trades, das Log vier gefüllte SQZ-STOP-Orders. Beides stimmte.

Ein Pending-Fill läuft nicht über engine._open — die Position wird von
trader._refresh_locked per magic-match adoptiert, und dieser Pfad loggt nur
Ticket/Symbol/Richtung/Lots/Preis. Es fehlten setup, sl_at_entry und alle
16 ctx_*-Spalten. Damit war genau die Messpipeline, die den Pending-Umbau
vom 05.08. kontrollieren soll, blind für ihn (B4-Monitor, squeeze_b5,
squeeze_entry_gap zählten null) — Deployment-Drift Fall 8, erste Variante,
bei der nicht die Strategie driftet, sondern ihre Beobachtbarkeit.

- history.tag_bot_trade(): UPDATE nur wenn setup IS NULL, stiller Fail-open
- engine._pending_tickets: Ticket -> Quelle, beim Platzieren/Stornieren gepflegt
- engine._check_pending_fill() im _pos_loop vor dem Pending-Manager;
  Zuordnung über Positions-Nr == Order-Nr (an allen 4 Fills verifiziert),
  setzt zusätzlich _bot_open_ticket/_source und die Entry-Zähler

6 Szenarien getestet, darunter die zwei gefährlichen: fremde Position wird
nicht getaggt, derselbe Fill zählt bei Folge-Ticks nur einmal.
Die 4 Trades des 06.08. nachgetragen (Backup .bak-2026-08-06).

ctx_*/sl_at_entry bewusst NICHT nachgetragen: rekonstruiert wären sie später
von gemessenen Werten nicht unterscheidbar.

Dabei gefunden, dokumentiert, NICHT behoben: der Signal-Pfad setzt/storniert
dieselbe Order 4x in 76 s bei identischem Level, weil block_reason zwischen
entry_room und breakout_pending pendelt (Drift Fall 9).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 10:55:41 +02:00
Axel HocksandClaude Opus 5 a1a5d560b9 Charts-Tab komplett entfernt (User-Vorgabe)
Entfernt: Tab-Button, #view-charts, der gesamte app.js-Chart-Block
(Kartenaufbau, renderChart, loadCharts, 20-s-Refresh, Resize-Handler), die
Chart-CSS-Regeln, die vendorte Bibliothek
web/lightweight-charts.standalone.production.js (164 KB) samt script-Tag - und
die Backend-Kette dahinter: /api/bars und engine.get_bars (60 Zeilen). Beide
existierten ausschliesslich fuer dieses Tab; geprueft, dass es keinen anderen
Aufrufer gibt.

Nicht betroffen (sahen nur aehnlich aus): die Chartmuster-Karte (Verdict-Gewicht
0,25, im Tab "SIG Live"), der MQL5-Indikator samt sr_levels.csv-Export (eigener
Pfad ueber _write_levels_file) und die Analyse-Module structure/patterns/cone -
die speisen den Snapshot, nicht das Chart. Der MT5-Chart bleibt voll bedient.

Ein veralteter Kommentar in trader.py, der auf engine.get_bars verwies, wurde
auf core/gaps.py umgehaengt.

Verifiziert am laufenden Server: /api/bars -> 404, Bibliothek -> 404,
data-view="charts" und id="view-charts" nicht mehr im ausgelieferten HTML,
6 Tabs zu 6 Views paarig, keine verwaisten JS-Referenzen, Klammern-Balance ok,
keine Fehler im Log. v=142.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 23:27:24 +02:00
Axel HocksandClaude Opus 5 7009541c42 Squeeze-Trades bekommen den SL aus M5-ATR (User-Entscheidung), TP unveraendert
trader._calc_sl_tp bekommt die ATR-Zeitebene als Parameter (Default SL_TF =
M15); _send/_send_locked/open_long/open_short und place_stop reichen sie durch.
Gesetzt wird sie an genau zwei Stellen: engine._open bei source="auto_squeeze"
und _manage_squeeze_pending bei quelle="squeeze". Manuelle Trades und
Auto-Signal bleiben bei M15.

Grundlage backtest_sl_basis.py: auf Squeeze-Entries ist der Ertrag zwischen
beiden Basen ein Wash (alle Varianten innerhalb eines Standardfehlers), der
Worst-Case sinkt aber von -8,83 auf -2,44 xATR_M5 = Faktor 3. Auf der
Wellen-Population ist der weite M15-SL in BEIDEN Haelften besser - deshalb
bewusst keine globale Umstellung.

Die Multiplikatoren (1,8-2,2 xATR) sind nicht angefasst, nur die Zeitebene.

TP bewusst NICHT betroffen (User: "nur fuer SL, der TP soll mit dem Runner
mitwachsen"). Geprueft statt angenommen: der von _calc_sl_tp zurueckgegebene TP
wird von KEINEM Aufrufer gesendet, beide setzen nur req["sl"]. Das Ziel
verwaltet trailing.py dynamisch (3,5 x ATR der Wellen-Zeitebene). Warnkommentar
im Code, warum der TP dort nicht mit in die Order darf.

4 Szenarien getestet. Dabei eigene Fehlannahme korrigiert: ohne Pivot greift der
1,2-%-Fallback, der beim M15 vom MINDEST-Deckel aufgeweitet wird - die
2,2x-Obergrenze wird dort gar nicht erreicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 17:39:41 +02:00
Axel HocksandClaude Opus 5 90d77a2305 Pending-Pfad fuer SIG: ruhende Stop-Order am Bestaetigungs-Level
SIG laeuft damit auf der gemessen positiven Variante (OeR +0,35/+0,32, PF 2,2)
statt auf der Market-Order (-0,09/-0,11).

Der heikelste Punkt war nicht die Order, sondern die Kollision beider Pfade:
trader.pending_orders() liefert ALLE magic-gleichen Orders, zwei getrennte
Manager haetten sich gegenseitig storniert - sporadisch und im Log kaum
erkennbar. Deshalb EIN gemeinsamer Ziel-Zustand (engine._pending_ziel), der
Manager gleicht nur noch ab. Vorrang Squeeze > Signal (unabhaengig validiert,
selten; das Signal feuert dauernd, es gibt einen Positions-Slot).

Zwei additive Ergaenzungen in wave_rec._confirm_breakout: das
Bestaetigungs-Level wird auch NACH der Bestaetigung veroeffentlicht (die
Nachjagd-Bremse braucht es genau dann; pending bleibt False, Frontend
unberuehrt), und conf = die Konfidenz VOR dem Stummschalten - sonst muesste
die ruhende Order blind platziert werden.

Nachjagd-Bremse jetzt auch fuer SIG (0,20 xATR, Haertetest-gedeckt).
12 Szenarien getestet, live am Snapshot verifiziert. Snapshot-Felder
squeeze_pending_levels -> pending_levels + pending_quelle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 11:43:04 +02:00
Axel HocksandClaude Opus 5 5f70980e59 Erfolgskontrolle fuer den Stop-Order-Umbau: Skript + Reminder
analyze_squeeze_entry_gap.py fuehrt die zwei noetigen Quellen zusammen - das
Ausbruchs-Level steht NUR im Log, der tatsaechliche Fill NUR in trades - und
splittet am Umbau-Stichtag. Die Erfolgsmeldung ist paradox: eine per Pending
gefuellte Order erzeugt KEINE AUTO-SQUEEZE-ENTRY-Logzeile (die entsteht nur im
Market-Fallback), Squeeze-Trades ohne Log-Treffer sind also der Erfolg. Das
Skript weist sie deshalb getrennt aus.

Als Messung squeeze_entry_gap im measurement_reminder.py hinterlegt (>=12
Squeeze-Trades ab dem Umbau). Stichtag exakt 05.08. 08:55 statt Mitternacht -
der 08:33-Trade lief noch ueber die Market-Order und haette die Zaehlung
verfaelscht (0/12 statt faelschlich 1/12).

Zahlen-Korrektur: die zuerst dokumentierten +0,306 / +0,741 xATR stammten aus
einer Scratchpad-Auswertung mit FESTEM Stundenversatz. DST-korrekt ueber
zoneinfo sind es +0,275 / +0,686 (n=34 unveraendert). In CLAUDE.md, engine.py,
trader.py und der ini nachgezogen; die Schlussfolgerung aendert sich nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 09:06:50 +02:00
Axel HocksandClaude Opus 5 5e0e8b00ca Squeeze-Einstieg ueber ruhende Stop-Orders + Meta-Labeling gemessen (verworfen)
1) STOP-ORDER STATT MARKET (gebaut, live). engine._manage_squeeze_pending haelt
beide Box-Grenzen mit BUY_STOP/SELL_STOP bestueckt, solange der Squeeze armed
ist; trader.place_stop/cancel_pending/pending_orders neu. Groesse und SL kommen
aus denselben Funktionen wie die Market-Order, nur bezogen auf den Trigger.
OCO-Ersatz: faellt eine Seite, wird die andere im selben Tick storniert.

Der kritische Punkt bei einer ruhenden Order sind die Gates - sie waren bisher
Laufzeit-Checks im Market-Pfad. Neu: engine._squeeze_guard() als EINE Quelle
fuer beide Wege, jeden Tick neu bewertet; schlaegt ein Gate zu, werden die
Orders storniert. Market bleibt Fallback mit Nachjagd-Bremse
squeeze_max_chase_atr=0.20 (gemessen der noch positive Bereich).

Behandelt: Broker-Mindestabstand, falsche Marktseite, Toleranz 0,02 xATR gegen
Order-Churn, Log nur bei Fehleraenderung, Startup-Schonfrist. 10 Szenarien
getestet, live am Snapshot verifiziert.

2) META-LABELING (backtest_metalabel.py) - VERWORFEN. Zweitmodell auf 12
kausalen Merkmalen, Fit/Test in BEIDEN Richtungen: AUC 0,508 und 0,479 =
Muenzwurf, Kalibrierung im Top-Bucket 74 % vorhergesagt gegen 39 % real, und
8 von 12 Gewichten kippen das Vorzeichen. Die scheinbar besseren Schwellen
sind reine Handelsvermeidung und reproduzieren gegenlaeufig nicht.
23. verworfener Signal-Eingriff - deckt sich mit dem Caveat der Quelle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 09:03:14 +02:00
Axel HocksandClaude Opus 5 cc4f1a0863 Provider-Failover bei hartem Fehlschlag + Einsatz-Prozentfeld im Dashboard
1) LLM-Failover (core/agent.py): ein hart gescheiterter Provider wird zeitweise
uebersprungen, analyze() nimmt den naechsten aus der Kette. Hart = 401/402/403/
404 (Key/Guthaben/Modell) -> 30 min, nicht erreichbar -> 5 min. Timeout/429/5xx
loesen BEWUSST keinen Wechsel aus (voruebergehend; sonst kostet jede Lastspitze
die volle Timeout-Summe aller Anbieter). Neu im Snapshot: agent.provider_dead
mit Restminuten - der DeepSeek-Ausfall stand vorher nur im Log und blieb
deshalb 18 h unbemerkt. 9 Szenarien getestet.

2) Einsatz-Prozentfeld (web, v=137): margin_buffer_pct hatte bisher keine UI.
Neues Feld "Einsatz %" neben "Einsatz EUR", POST /api/marginpct ->
engine.set_margin_pct -> config.set_margin_buffer, Snapshot margin_pct,
neustart-fest. Der feste EUR-Betrag hat Vorrang; das Prozentfeld wird dann
ausgegraut, damit nicht unklar bleibt was gilt. Auf 1-99 % geklemmt.
Ende-zu-Ende getestet (50, 150->99, 0 und -5 abgelehnt, 95, persistiert).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 08:38:17 +02:00
Axel HocksandClaude Opus 5 1c9bb34095 Auto-Squeeze-Nachtsperre von 0-7 auf 3-6 Uhr verkuerzt (User-Vorgabe)
Gemessen (backtest_cost_gate.py, Teil 2): es gibt KEINE toten Stunden - alle
24 Stunden sind in beiden Halbjahren positiv, keine ist beidhaelftig negativ.
Std 0 ist sogar die staerkste des Tages (OeR +1,48/+1,51) und lag im alten
Gate. Jedes Fenster kostet also Ertrag; die Sperre kauft ausschliesslich
Beaufsichtigungs-Ruhe.

Gewaehlt wurde deshalb nach PREIS, nicht nach Edge: 3-6 ist das guenstigste
Fenster mit noch >=4 h Schutz (SigmaR -12,5/-62,9 gegen -42,4/-242,6 bei 0-7
= ~27 %). Freigegeben: 0, 1, 2, 7 Uhr. Die 4-h-Untergrenze ist gesetzt, nicht
gemessen.

Umsetzung: neues [trading] auto_squeeze_night_hours (Default 3,4,5,6, leer =
aus), genutzt von _check_auto_squeeze und _check_auto_signal. _SQUEEZE_NIGHT
bleibt als STATISTISCHE Nacht-Definition fuer Entry-Checkliste und B4-Monitor
- dort gilt die Kostenfalle weiter und der Altdaten-Vergleich bleibt stabil.

7 Parse-Faelle getestet (Default, fehlender Schluessel, leer, Muell,
Rueckwaerts-Kompatibilitaet). Live verifiziert am NEUEN Snapshot-Feld
squeeze_night_hours = 3,4,5,6 und am Startup-Log; genau eine Instanz auf 8000.

Offen und als Reminder hinterlegt: der Backtest modelliert keine Slippage,
und die freigegebenen Stunden liegen in der duennsten Liquiditaet. Nach 15
Squeeze-Trades aus 0/1/2/7 Uhr gegen die Erwartung pruefen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 08:25:48 +02:00