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>
This commit is contained in:
Axel Hocks
2026-08-05 11:43:04 +02:00
co-authored by Claude Opus 5
parent 12fb11fa44
commit 90d77a2305
3 changed files with 168 additions and 42 deletions
+15 -1
View File
@@ -571,20 +571,34 @@ class WaveRecommender:
p = {"dir": d, "level": cur + d * k * atr, "invalid": cur - d * k * atr,
"confirmed": False, "start": time.time()}
self._pend = p
# ⚠ Das Bestätigungs-Level wird AUCH nach der Bestätigung veröffentlicht
# (2026-08-05). Zwei Konsumenten brauchen es: die ruhende Stop-Order (sie
# liegt dort) und die Nachjagd-Bremse im Market-Fallback (sie misst den
# Abstand dorthin). `pending` bleibt False — das Frontend rendert nur bei
# `pending`, ist also unberührt.
if p["confirmed"]:
snap["breakout"] = {"pending": False, "dir": sig, "need": None,
"level": round(p["level"], 3), "confirmed": True}
return rec # schon bestätigt → durchlassen
broke = (cur >= p["level"]) if d > 0 else (cur <= p["level"])
against = (cur <= p["invalid"]) if d > 0 else (cur >= p["invalid"])
if broke:
p["confirmed"] = True
snap["breakout"] = {"pending": False, "dir": sig, "need": None,
"level": round(p["level"], 3), "confirmed": True}
return rec
if against or (time.time() - p["start"]) > self._breakout_timeout_s:
p = {"dir": d, "level": cur + d * k * atr, "invalid": cur - d * k * atr,
"confirmed": False, "start": time.time()} # neu verankern
self._pend = p
need = abs(p["level"] - cur)
# ⚠ `conf` = die Konfidenz VOR dem Stummschalten. Der Rückgabewert unten
# setzt `conf_pct` auf 0 (das Signal gilt ja noch nicht) — wer die ruhende
# Stop-Order gegen die Mindest-Konfidenz prüfen will, hätte sonst KEINE
# Zahl und müsste die Order blind platzieren.
snap["breakout"] = {"pending": True, "dir": sig,
"level": round(p["level"], 3), "need": round(need, 3)}
"level": round(p["level"], 3), "need": round(need, 3),
"conf": rec.get("conf_pct") or 0, "confirmed": False}
return {"signal": "WARTEN", "conf_pct": 0, "score": 0.0, "setup": "WAVE",
"regime": None, "rsi": None, "block": "breakout_pending",
"reasons": [f"warte auf Breakout (+{k:.1f}×ATR {sig}, noch {need:.2f})"]}