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>
This commit is contained in:
Axel Hocks
2026-08-08 22:59:37 +02:00
co-authored by Claude Opus 5
parent 44955bf70a
commit e5adfc9757
4 changed files with 237 additions and 7 deletions
+63
View File
@@ -3974,6 +3974,43 @@ class TradingEngine:
log.debug(f"sr_close_hint: {e}")
return None
def _vola_regime(self, atr15) -> dict | None:
"""ΔATR = aktueller ATR_M15 / Median der letzten ~5 h.
⚠ KEIN zweiter MT5-Fetch: der ATR wird aus dem ohnehin laufenden
Turn-Fetch gesammelt (`wave.tf_atr`), hier nur gepuffert. Ein extra
Abruf fuer Zahlen, die schon da sind, war beim Konsens-Pfeil der Fehler.
⚠⚠ BELEGLAGE, ehrlich: gemessen (`analyze_slippage_vola.py`, 337
SL-Closes) steigt die Exit-Slippage MONOTON ueber alle vier
ΔATR-Quartile — 0,0200 → 0,0390 → 0,0645 → 0,0839 $, Faktor 4,19×.
Die Slip-RATE bleibt dabei flach (2023 %), die GROESSE waechst
(0,094 → 0,396 $): es rutscht nicht oefter, sondern weiter.
ABER: der Bootstrap auf die DIFFERENZ obenunten ergibt
[0,012 … +0,183] — **enthaelt die Null**. Bei n≈85 je Quartil ist der
Unterschied NICHT statistisch belegt. Deshalb reine ANZEIGE, kein Gate,
und die Beschriftung sagt das auch.
"""
try:
if not atr15 or atr15 <= 0:
return None
buf = getattr(self, "_atr15_buf", None)
if buf is None:
from collections import deque
buf = self._atr15_buf = deque(maxlen=1200) # ~5 h bei 15-s-Takt
buf.append(float(atr15))
if len(buf) < 200:
return {"datr": None, "stufe": None}
import statistics as _st
med = _st.median(buf)
if med <= 0:
return {"datr": None, "stufe": None}
d = atr15 / med
return {"datr": round(d, 2),
"stufe": "hoch" if d >= 1.26 else "normal" if d >= 0.91 else "ruhig"}
except Exception:
return None
def _m15_setup(self, market, wave_snap, cone, alignment) -> dict | None:
"""SETUP-BEREITSCHAFT auf M15 — der Ersatz für die entfernte Gesamtempfehlung.
@@ -4044,6 +4081,32 @@ class TradingEngine:
"lo": x.get("lo"), "hi": x.get("hi")}
for x in b80] or None
# ── 4b) ZIEL-ERREICHBARKEIT — reine GEOMETRIE auf dem Kegel.
# Ziel eines Trades am nahen Level ist das GEGENÜBERLIEGENDE.
# Gefragt wird nur: passt dieser Abstand noch in das 80-%-Band
# des jeweiligen Horizonts? ⚠ KEINE Bruch-Annahme — die im
# Vorschlag mitgedachte „je länger, desto eher bricht es"-Regel
# ist gemessen NICHT robust (Touch-Zahl: umgekehrtes U auf 4
# Live-Tagen, im Backtest +0,010 AUC und nach dem Nachtrainieren
# gar nichts mehr). Hier steckt deshalb nur Arithmetik.
if len(zonen) == 2 and bid and b80:
nah = min(zonen, key=lambda x: x["gap_atr15"])
fern = max(zonen, key=lambda x: x["gap_atr15"])
strecke = abs(fern["level"] - bid)
out["ziel"] = {
"level": fern["level"], "strecke": round(strecke, 3),
"horizonte": [{"minutes": x.get("minutes"),
"drin": bool(x.get("lo") is not None
and x.get("hi") is not None
and x["lo"] <= fern["level"] <= x["hi"])}
for x in b80],
"von": nah["level"]}
else:
out["ziel"] = None
# ── 4c) VOLA-REGIME als Slippage-HINWEIS (kein Gate, s. Docstring)
out["vola"] = self._vola_regime(atr15)
# ── 5) VETO — die eigene Bilanz, je Lot (absolute Euro sind bei
# wechselnder Positionsgröße ungültig, Lehre vom 04.08.)
out["veto"] = alignment or None