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>
This commit is contained in:
Axel Hocks
2026-08-20 08:32:21 +02:00
co-authored by Claude Opus 5
parent e01ecde3a3
commit c081bdc734
3 changed files with 218 additions and 5 deletions
+34 -2
View File
@@ -69,6 +69,11 @@ _BROKER_OFF_DEFAULT_S = 3 * 3600
_BROKER_TICK_FRESH_S = 900
# ⚠ Pivot-Anker des Initial-SL — seit 2026-08-20 AUS (s. Begruendung in
# `_calc_sl_tp`). True stellt das alte Verhalten wieder her.
_SL_PIVOT_ANKER = False
class TradeManager:
def __init__(self, nur_ticket: bool = False):
"""`nur_ticket=True` => STRIKT an das eigene Ticket gebunden.
@@ -139,9 +144,33 @@ class TradeManager:
max_dist = (INIT_SL_MAX_ATR * atr) if atr else None
min_dist = (INIT_SL_MIN_ATR * atr) if atr else None
capped = floored = False
if otype == mt5.ORDER_TYPE_BUY:
# ⚠⚠ KEIN PIVOT-ANKER MEHR (2026-08-20, User-Fund "immer am S/R
# geschlossen"). Der SL wurde bis heute an den naechsten M15-Pivot
# gelegt — also fuer einen LONG direkt unter die UNTERSTUETZUNG, fuer
# einen SHORT ueber den WIDERSTAND — und erst danach auf 1,82,2×ATR
# geklemmt. Ueber 69 geloggte Orders war der Pivot in 4 % massgeblich
# (in 59 % kappte der Deckel, in 36 % weitete der Boden auf); in diesen
# Faellen lag der Stop exakt auf dem Level, an dem der Markt ohnehin am
# haeufigsten durchwickt.
# GEMESSEN mit dem HEUTIGEN Exit (`backtest_sl_pivot.py`, 60k M5,
# 2 Halbjahre, gleiche Einstiege, nur die SL-Methode variiert):
# 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. ⚠ Beide KI enthalten die Null — es
# ist KEIN belegter Ertragsgewinn. Der Punkt ist ein anderer: die
# Verankerung nuetzt nichts und legt den Stop auf das Level.
# ⚠ Das bestaetigt `backtest_sl_method.py` (gedeckelt sind alle
# Methoden gleichwertig, der Band-Cap dominiert) auf dem heutigen
# Exit — dort war es nur nie als NACHTEIL sichtbar.
# ZURUECK: `_SL_PIVOT_ANKER = True`.
if _SL_PIVOT_ANKER and otype == mt5.ORDER_TYPE_BUY:
piv = pivot_low(sym, entry_price)
sl = (piv - buf) if piv else round(entry_price * (1 - INIT_SL_FALLBACK), si.digits)
elif otype == mt5.ORDER_TYPE_BUY:
piv = None
sl = entry_price - (INIT_SL_MIN_ATR + INIT_SL_MAX_ATR) / 2.0 * atr \
if atr else round(entry_price * (1 - INIT_SL_FALLBACK), si.digits)
if max_dist and entry_price - sl > max_dist:
sl = entry_price - max_dist; capped = True
if min_dist and entry_price - sl < min_dist:
@@ -149,9 +178,12 @@ class TradeManager:
sl = round(sl, si.digits)
sl_dist = entry_price - sl
tp = round(entry_price + INIT_TP_RR * sl_dist, si.digits) if sl_dist > 0 else 0.0
else:
elif _SL_PIVOT_ANKER:
piv = pivot_high(sym, entry_price)
sl = (piv + buf) if piv else round(entry_price * (1 + INIT_SL_FALLBACK), si.digits)
else:
piv = None
sl = entry_price + (INIT_SL_MIN_ATR + INIT_SL_MAX_ATR) / 2.0 * atr if atr else round(entry_price * (1 + INIT_SL_FALLBACK), si.digits)
if max_dist and sl - entry_price > max_dist:
sl = entry_price + max_dist; capped = True
if min_dist and sl - entry_price < min_dist: