diff --git a/CLAUDE.md b/CLAUDE.md index d58af7d..7f4d528 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1478,6 +1478,36 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche: **Nichts abgeschaltet** — Autonomie-Schalter sind User-Entscheidungen. ⚠ Grenzen: die Live-Stichprobe ist n=34 mit genäherter ATR-Zuordnung; A und B sind zwei Modell-Enden, der Live-Betrieb liegt dazwischen (näher an B). + ✅✅ **LÖSUNG GEFUNDEN — RUHENDE STOP-ORDER STATT MARKET (Variante E, gemessen + 2026-08-05; Anstoß aus der Web-Recherche: „don't chase breakouts with market orders; + place orders just beyond the breakout level").** Eine PENDING `BUY_STOP`/`SELL_STOP` + liegt bereits am Ausbruchs-Level, WÄHREND der Squeeze `armed` ist (das Level ist da + schon bekannt = Box-Grenze), und wird vom Ausbruch selbst ausgelöst — anders als die + Limit-Order (D) wartet sie NICHT auf einen Rücklauf, verpasst also nichts. + | Fill-Annahme | H1 ØR / PF / ΣR | H2 ØR / PF / ΣR | + |---|---|---| + | Level exakt (= A) | +0,456 / 2,65 / +370 | +0,611 / 3,56 / +778 | + | **Level +0,05×ATR** | **+0,397 / 2,28 / +322** | **+0,553 / 3,06 / +697** | + | Level +0,10×ATR | +0,355 / 2,07 / +288 | +0,509 / 2,76 / +639 | + | **Level +0,20×ATR (pessimistisch)** | **+0,244 / 1,62 / +196** | **+0,426 / 2,25 / +531** | + | Market/Live (= B) | −0,158 / 0,74 / −126 | −0,006 / 0,99 / −8 | + **Selbst mit 0,20×ATR unterstellter Fill-Slippage — dem ~9-fachen des Median-Spreads + — bleibt es in BEIDEN Hälften klar positiv.** + ⚠⚠ **Der Schlüssel ist nicht der Median, sondern der SCHWANZ.** Live ist der + Median-Abstand +0,306×ATR, der **Mittelwert aber +0,741** (Max +4,339). Eine + Stop-Order **deckelt den Einstiegspreis konstruktiv**; die Market-Order auf dem + 5-s-Poll tut das nicht. Die Extremfälle (+3,5 / +4,3×ATR) stammen erkennbar aus + **blockiert-dann-freigegebenen** Ausbrüchen: feuert der Squeeze, während eine + Position offen ist (oder Nacht-/News-Fenster), wird KEIN Dedup-Marker gesetzt — der + Entry kommt später zum dann gültigen Marktpreis, u. U. weit hinter dem Level. + ⚠ **Noch NICHT gebaut** — Umsetzung hat echte Fallstricke: die Guards (Nacht, + News-Blackout, Cooldowns, flat-Prüfung) wirken heute als Laufzeit-Checks; mit einer + ruhenden Order müssten sie über **Platzieren/Stornieren** durchgesetzt werden, sonst + feuert eine vergessene Pending-Order in einem gesperrten Fenster. Dazu: MT5-Mindest- + abstand (`SYMBOL_TRADE_STOPS_LEVEL`) kann die Platzierung ablehnen, wenn der Kurs + schon zu nah am Level steht, und die Order muss storniert werden, sobald der Squeeze + sich klärt. **Das ist der stärkste offene Hebel im Projekt** — größer als jeder der + 22 verworfenen Signal-Eingriffe. - **Auto-Squeeze-Entry = LIVE AUTONOM (User-Vorgabe 2026-07-16, `[trading] auto_squeeze=true`, Default FALSE):** der Bot eröffnet **selbständig eine echte Order**, sobald der **gemessen-validierte** Squeeze-Ausbruch feuert (`wave.squeeze. diff --git a/backtest_squeeze_entry.py b/backtest_squeeze_entry.py index b795d31..5913b1f 100644 --- a/backtest_squeeze_entry.py +++ b/backtest_squeeze_entry.py @@ -97,6 +97,28 @@ def lauf_limit(K, H, L, C, lo, hi, warte: int, puffer: float = 0.0): return rs, verpasst +def lauf_stop(K, H, L, C, lo, hi, slip: float): + """Variante E — ruhende STOP-Order am Ausbruchs-Level. + + Sie liegt bereits, während der Squeeze `armed` ist, und wird vom Ausbruch selbst + ausgelöst → Fill am Level + `slip`×ATR (Auslösung erfolgt zum Markt, etwas + Slippage bleibt). Kein Warten auf einen Rücklauf wie bei der Limit-Order, also + auch KEINE verpassten Ausbrüche.""" + rs = [] + frei_ab = lo + for k in K: + i = k["i"] + if not (lo <= i < hi) or i < frei_ab: + continue + d, atr = k["d"], k["atr"] + entry = k["lvl"] + d * slip * atr + r, xb = simulate(entry, d, atr, H, L, C, i + 1, LIVE, + timestop=True, use_tp=True, ret_bar=True) + rs.append(r - k["kosten"]) + frei_ab = xb + 1 + return rs, 0 + + def zeile(lbl, k1, k2, extra=""): def f(k): if not k: @@ -162,6 +184,22 @@ def main(): erg[lbl] = (kennzahlen(r1), kennzahlen(r2)) zeile(lbl, *erg[lbl], extra=f"verpasst {v1}/{v2}") + # ── Variante E: RUHENDE STOP-ORDER am Level ────────────────────────── + # Aus der Web-Recherche (2026-08-05): „don't chase breakouts with market orders; + # place orders just beyond the breakout level." Genau das ist hier der Hebel — + # eine PENDING BUY_STOP/SELL_STOP, die schon liegt, WÄHREND der Squeeze `armed` + # ist, füllt am Level statt 0,31×ATR später. Anders als die Limit-Order (D) + # wartet sie NICHT auf einen Rücklauf: sie wird vom Ausbruch selbst ausgelöst. + # ⚠ Eine ausgelöste Stop-Order füllt zum Markt → etwas Slippage bleibt. Deshalb + # mit mehreren realistischen Aufschlägen gerechnet, nicht mit dem Idealpreis. + print(" " + "-" * 100) + for slip in (0.00, 0.05, 0.10, 0.20): + lbl = f"E Stop-Order Level +{slip:.2f}" + r1, _ = lauf_stop(K, H, L, C, 0, mid, slip) + r2, _ = lauf_stop(K, H, L, C, mid, N, slip) + erg[lbl] = (kennzahlen(r1), kennzahlen(r2)) + zeile(lbl, *erg[lbl], extra="(= Variante A)" if slip == 0 else "") + a1, a2 = erg["A Einstieg AM LEVEL"] b1, b2 = erg["B Einstieg am Bar-Close"] print()