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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b8705e297f
commit
5474c2be61
+55
-17
@@ -4368,27 +4368,65 @@ class TradingEngine:
|
||||
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
|
||||
# Gefragt wird nur: passt der 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:
|
||||
#
|
||||
# ⚠⚠ FEHLER BEHOBEN 2026-08-10 (User-Fund „Kurs 79, Ziel 78,7 — bei
|
||||
# LONG?"). Der erste Entwurf nahm als Ziel schlicht das ENTFERNTERE
|
||||
# der beiden Level (`max` nach gap) — also **rein geometrisch, ohne
|
||||
# die erlaubte Richtung zu prüfen**. Real zeigte die Karte damit
|
||||
# `verboten=SHORT` UND ein Ziel 0,15 $ UNTER dem Kurs: die Arithmetik
|
||||
# war korrekt, aber für die VERBOTENE Richtung.
|
||||
# Strukturell steckte dahinter die stillschweigende Annahme eines
|
||||
# **Fade-Trades** (am Level einsteigen, Gegenlevel als Ziel = Mean
|
||||
# Reversion), während Gate ② ein **Trendfilter** ist. Zwei
|
||||
# unvereinbare Handelskonzepte in einer Kette — und damit derselbe
|
||||
# Fehler, wegen dem die Gesamtempfehlung entfernt wurde: aus einem
|
||||
# VERBOT wird über die Hintertür wieder eine RICHTUNG.
|
||||
#
|
||||
# Jetzt gilt die gemessene Population aus `backtest_m15_gates.py`:
|
||||
# Einstieg am **nächstgelegenen** Level, Richtung = die vom HTF
|
||||
# erlaubte. Ein Ziel wird nur ausgewiesen, wenn es JENSEITS dieses
|
||||
# Einstiegs in der erlaubten Richtung liegt.
|
||||
# ⚠ Ohne Veto (M30 flach) gibt es KEIN Ziel — ein einzelnes Ziel
|
||||
# zu zeigen wäre wieder eine Richtungsaussage.
|
||||
# ⚠ `_draw_levels` liefert bewusst nur die NÄCHSTE Linie je Seite.
|
||||
# Beim Ausbruchs-Einstieg (nächstes Level == Ziel-Seite) ist das
|
||||
# nächste Ziel damit schlicht NICHT berechenbar — dann sagt die
|
||||
# Karte das, statt eine Zahl zu erfinden.
|
||||
out["ziel"] = None
|
||||
d_ok = (1 if verboten == "SHORT" else
|
||||
-1 if verboten == "LONG" else 0)
|
||||
if len(zonen) == 2 and bid and b80 and d_ok:
|
||||
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"]}
|
||||
kand = next((z for z in zonen
|
||||
if z["seite"] == ("res" if d_ok > 0 else "sup")), None)
|
||||
if kand is None:
|
||||
grund = "kein Level in der erlaubten Richtung"
|
||||
elif (kand["level"] - nah["level"]) * d_ok > 0:
|
||||
strecke = abs(kand["level"] - bid)
|
||||
out["ziel"] = {
|
||||
"level": kand["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"] <= kand["level"] <= x["hi"])}
|
||||
for x in b80],
|
||||
"von": nah["level"],
|
||||
"richtung": "LONG" if d_ok > 0 else "SHORT"}
|
||||
grund = None
|
||||
else:
|
||||
grund = ("Ausbruch — Einstieg am "
|
||||
+ ("Widerstand" if nah["seite"] == "res" else "Support")
|
||||
+ f" {nah['level']:.3f}, nächstes Ziel dahinter nicht berechenbar")
|
||||
out["ziel_grund"] = grund
|
||||
else:
|
||||
out["ziel"] = None
|
||||
out["ziel_grund"] = (None if d_ok else
|
||||
"kein Veto — Richtung offen, kein Ziel bestimmbar")
|
||||
|
||||
# ── 4c) VOLA-REGIME als Slippage-HINWEIS (kein Gate, s. Docstring)
|
||||
out["vola"] = self._vola_regime(atr15)
|
||||
|
||||
Reference in New Issue
Block a user