Verworfene Setups auf der Ausfuehrungs-Achse — und der Squeeze steht mit auf null

User: "backteste alle verworfenen Signale". Bewusst kein Komplettlauf (der lief
am 04.08., 14 Klassen, alle blieben verworfen) — neu ist genau eine Achse, der
Einstiegspreis, angewandt mit der heutigen Korrektur (Fill bei BERUEHRUNG statt
bei Schluss-Bruch) und nur dort, wo sie greifen kann: stehendes Level +
Ausbruchsrichtung.

Ergebnis (Variante C, 80k M5, 2 Halbjahre):
  KONTROLLE Squeeze  +0,133/+0,293   (reproduziert touchfill — Pipeline ok)
  ORB (4 Varianten)  faellt durch    (bestaetigt 2026-07-17)
  PDH/PDL            +0,246/+0,464
  Asian Range        +0,142/+0,134
  Equal H/L          +0,218/+0,170
Alle drei nachbar-robust (11 Zellen, keine kippt).

⚠ Das sind keine drei neuen Signale: PDH/PDL, Asian-Range-Extrem, Equal H/L und
die Squeeze-Box sind dasselbe — waagerechtes Level aus frueheren Extremen,
gebrochen, ruhende Order, kanonisches Trailing. Deckt sich mit der Kontrolle
"beliebige Box" aus dem Multi-Instrument-Lauf.

⚠⚠ Mit der gemessenen Exit-Slippage bleibt fast nichts uebrig. Beim guenstigsten
Wert (0,0124 $, Tagfenster): PDH/PDL +0,099/+0,386 haelt, Equal H/L duenn, Asian
Range faellt — und der LIVE laufende Auto-Squeeze steht in H1 bei -0,002.
Die Edges dieser Familie liegen in derselben Groessenordnung wie die
Ausstiegskosten, und die Slippage-Zahl ist eine Untergrenze.

Konsequenz: kein neues Setup bauen. Der naechste Hebel ist die
Ausfuehrungsqualitaet am EXIT, nicht ein weiteres Einstiegs-Signal.

Offen und benannt: Volume-Profile-LVN und die Chartmuster-Nackenlinie
qualifizieren sich, wurden aber nicht gemessen (Laufzeit bzw. Detektor).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-06 22:21:06 +02:00
co-authored by Claude Opus 5
parent 45bfc87153
commit 7e03e481ca
4 changed files with 474 additions and 0 deletions
+55
View File
@@ -319,6 +319,61 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
~15 s→5 s schneller erkannt, dann ~1 s Handeln (`_pos_loop`). Gleiche validierte M5-Regel,
reine Infra (kein Backtest nötig). **Variante B (Squeeze auf M1) = OFFEN/UNBELEGT** — erst
backtesten, wenn der M1-Logger (`candles_m1`, seit 2026-07-21) ab ~2027-01 genug History hat.
- **⚠⚠⚠ VERWORFENE SETUPS AUF DER AUSFÜHRUNGS-ACHSE NEU GEMESSEN — und das
Ergebnis stellt den LIVE-Squeeze mit in Frage (`backtest_verworfene_v2.py`,
2026-08-06, User: „backteste alle verworfenen Signale").**
⚠ Bewusst **kein** erneuter Komplettlauf — der lief am 04.08. (14 Klassen, alle
blieben verworfen). Neu ist genau **eine** Achse, der Einstiegspreis, und sie
wurde mit der heutigen Korrektur angewandt: **Fill bei BERÜHRUNG**, nicht bei
Schluss-Bruch. Geprüft wurde nur, wo die Achse überhaupt greifen kann —
**stehendes Level + Ausbruchsrichtung** (Momentum scheitert, weil sein Level
wandert; Reversions-Einstiege werden von einer ruhenden Order sogar schlechter,
`backtest_candle_fade2.py`).
| Setup | A) Markt | B) Close-Bruch | **C) Berührung (real)** | n |
|---|---|---|---|---|
| *KONTROLLE Squeeze* | 0,180/0,017 | +0,560/+0,755 | **+0,133/+0,293** | 1094 |
| ORB EU 15/30 · US 15/30 | negativ | +0,45…+0,73 | **alle 4 ❌** | ~200 |
| PDH / PDL Bruch | 0,280/+0,044 | +0,906/+1,368 | **+0,246/+0,464** | 147 |
| Asian Range Bruch | +0,021/0,116 | +0,928/+0,718 | **+0,142/+0,134** | 218 |
| Equal H/L Bruch | 0,279/+0,228 | +0,574/+0,905 | **+0,218/+0,170** | 168 |
✅ Die Kontrolle reproduziert `backtest_squeeze_touchfill.py` (+0,133/+0,293
gegen +0,124/+0,292) — Pipeline in Ordnung. ✅ **ORB bleibt verworfen** in allen
vier Varianten (bestätigt 2026-07-17). ✅ Die drei Überlebenden sind
**nachbar-robust** (PDH/PDL über die Gültigkeitsdauer, Asian Range über das
Fenster, Equal H/L über Toleranz und Gültigkeit — 11 Zellen, keine kippt).
⚠⚠ **Das sind KEINE drei neuen Signale.** PDH/PDL, Asian-Range-Extrem, Equal
Highs/Lows und die Squeeze-Box sind **dasselbe**: ein waagerechtes Level aus
früheren Kursextremen, gebrochen, mit ruhender Stop-Order betreten und mit dem
kanonischen Trailing verlassen. Deckt sich mit der Multi-Instrument-Kontrolle
(„beliebige Box" ist überall positiv, die Kompression trägt +0,009…+0,155).
**Der Edge liegt in der Kombination Ausführung + Exit, nicht in der Regel, die
das Level auswählt.**
⚠⚠⚠ **UND JETZT DER TEIL, DER AUCH DAS LAUFENDE SYSTEM BETRIFFT — mit der
gemessenen Exit-Slippage (`analyze_slippage_holdtime.py`) bleibt fast nichts
übrig:**
| Setup | 0 $ | **0,0124 $** (Tagfenster) | 0,0370 $ (alle Std) |
|---|---|---|---|
| **Squeeze (LIVE!)** | +0,133/+0,293 | **0,002/+0,221** | 0,270/+0,080 |
| PDH / PDL | +0,246/+0,464 | **+0,099/+0,386** | 0,192/+0,231 |
| Equal H/L | +0,218/+0,170 | +0,077/+0,092 | 0,202/0,062 |
| Asian Range | +0,142/+0,134 | 0,011/+0,065 | 0,316/0,071 |
**Die Edges dieser ganzen Familie liegen in derselben Größenordnung wie die
Exit-Slippage.** Beim günstigsten gemessenen Wert hält nur **PDH/PDL** beide
Hälften klar; Equal H/L ist dünn, Asian Range fällt — und der **live laufende
Auto-Squeeze steht in H1 bei 0,002, also auf null**.
⚠ Die Slippage ist dabei eine **Untergrenze** (s. Herleitung dort) — der wahre
Abzug ist größer, nicht kleiner.
**Konsequenz: KEIN neues Setup bauen.** Drei weitere Module derselben Klasse
addieren Frequenz zu einem Edge, der von den Ausstiegskosten aufgezehrt wird.
Der nächste Hebel ist **die Ausführungsqualität am EXIT** (dort ist der Posten,
der alles frisst), nicht ein weiteres Einstiegs-Signal.
**Nicht mitgemessen, ehrlich benannt:** (a) **Volume-Profile-LVN** — stehendes
Level, aber das Profil müsste je Bar neu gebinnt werden (Laufzeit); (b)
**Chartmuster-/Doppeltop-Nackenlinie** — stehendes Level und Ausbruchsrichtung,
qualifiziert sich also, braucht aber den Muster-Detektor kausal getrieben.
**Beide bleiben offen.** Alle übrigen Ablehnungen (Inter-Market, Chop-Gate,
Meta-Labeling, RSI/MACD/ADX, HTF-Winkel, H1-Stärke, Konfluenz-Strafe) haben gar
kein Level — die Achse kann dort nichts ändern.
- **⚠⚠ DER SQUEEZE TRÄGT AUCH AUF ANDEREN INSTRUMENTEN — 7 von 9 (gemessen
`backtest_squeeze_multi.py`, 2026-08-06).** Anlass: `analyze_signal_live.py` hat
gezeigt, dass die Richtung ein Münzwurf ist; das Grundproblem ist also nicht die
+80
View File
@@ -0,0 +1,80 @@
"""Nachbar-Pruefung der drei Setups, die den vollen Lauf bestanden haben.
Kippt ein Nachbar-Parameter das Vorzeichen, ist der Treffer Rauschen — genau das
Kriterium, an dem ORB (2026-07-17) und die SMC-Sweeps gescheitert sind.
"""
import sys
sys.path.insert(0, r"c:\Users\ah\Downloads\tradingrobot")
from datetime import timedelta
import MetaTrader5 as mt5
from backtest_cost_gate import _atr_series, kennzahlen
import backtest_verworfene_v2 as V
mt5.initialize()
sym = "SpotCrude"
b = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, 80000)
point = mt5.symbol_info(sym).point
mt5.shutdown()
H = [float(x["high"]) for x in b]; L = [float(x["low"]) for x in b]
C = [float(x["close"]) for x in b]; T = [int(x["time"]) for x in b]
SP = [float(x["spread"]) * point for x in b]
A = _atr_series(H, L, C); m = len(C) // 2
def zeig(lbl, lv):
k1 = kennzahlen(V.lauf(lv, H, L, C, SP, A, 0, m, "touch"))
k2 = kennzahlen(V.lauf(lv, H, L, C, SP, A, m, len(C), "touch"))
if not k1 or not k2:
print(f" {lbl:<28} — zu wenige"); return False
gut = k1["oer"] > 0 and k2["oer"] > 0 and k1["pf"] > 1 and k2["pf"] > 1
print(f" {lbl:<28} H1 {k1['oer']:>+7.3f} PF {k1['pf']:.2f} n{k1['n']:<5} | "
f"H2 {k2['oer']:>+7.3f} PF {k2['pf']:.2f} n{k2['n']:<5} {'OK' if gut else 'KIPPT'}")
return gut
print("=" * 96)
print(" NACHBAR-PRUEFUNG (Variante C = Beruehrungs-Fill, 80k M5-Bars)")
print("=" * 96)
print("\n PDH/PDL — Gueltigkeitsdauer variiert:")
alle_pdh = True
basis = V.tagesextrem(H, L, T)
alle_pdh &= zeig("voller Folgetag (Basis)", basis)
for kuerz in (0.5, 0.25):
lv = [(a, a + int((bb - a) * kuerz), l, d) for a, bb, l, d in basis]
alle_pdh &= zeig(f"nur erste {int(kuerz*100)} % des Tages", lv)
print("\n Asian Range — Fenster variiert:")
alle_asia = True
alle_asia &= zeig("0008 Uhr (Basis)", V.asia(H, L, T))
for h_ende in (7, 9):
orig = V.asia.__code__
lv = []
tag, sam = None, []
for i in range(len(H)):
bz = V._berlin(T[i])
if bz.date() != tag:
tag, sam = bz.date(), []
if bz.hour < h_ende:
sam.append(i)
elif sam and bz.hour == h_ende and bz.minute < 5:
hi = max(H[j] for j in sam); lo = min(L[j] for j in sam)
bis = i
while bis < len(H) - 2 and V._berlin(T[bis]).date() == tag:
bis += 1
lv.append((i, bis, hi, +1)); lv.append((i, bis, lo, -1)); sam = []
alle_asia &= zeig(f"00{h_ende:02d} Uhr", lv)
print("\n Equal H/L — Toleranz und Gueltigkeit variiert:")
alle_eq = True
alle_eq &= zeig("tol 0.15 · 120 Bars (Basis)", V.equal_hl(H, L, A))
for tol in (0.10, 0.25):
alle_eq &= zeig(f"tol {tol} · 120 Bars", V.equal_hl(H, L, A, tol=tol))
for g in (60, 240):
alle_eq &= zeig(f"tol 0.15 · {g} Bars", V.equal_hl(H, L, A, gueltig=g))
print()
print("=" * 96)
for n, ok in (("PDH/PDL", alle_pdh), ("Asian Range", alle_asia), ("Equal H/L", alle_eq)):
print(f" {n:<14}{'ROBUST' if ok else 'KIPPT bei den Nachbarn — verworfen'}")
print("=" * 96)
+57
View File
@@ -0,0 +1,57 @@
"""Halten die drei Ueberlebenden auch mit gemessener Exit-Slippage?
`backtest_verworfene_v2.lauf` rechnet nur den Spread. Aus
`analyze_slippage_holdtime.py`: E[Slippage] >= 0,0370 $ ueber alle Stunden,
0,0124 $ im Fenster 10-17. Bei ATR_M5 ~0,15 sind das 0,08-0,25 R je Trade —
gegen Edges von +0,13..+0,25 ist das nicht vernachlaessigbar.
"""
import sys
sys.path.insert(0, r"c:\Users\ah\Downloads\tradingrobot")
import MetaTrader5 as mt5
from backtest_cost_gate import _atr_series, kennzahlen
from core.exit_model import LIVE, simulate
import backtest_verworfene_v2 as V
mt5.initialize(); sym = "SpotCrude"
b = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, 80000)
point = mt5.symbol_info(sym).point
mt5.shutdown()
H=[float(x["high"]) for x in b]; L=[float(x["low"]) for x in b]
C=[float(x["close"]) for x in b]; T=[int(x["time"]) for x in b]
SP=[float(x["spread"])*point for x in b]
A=_atr_series(H,L,C); m=len(C)//2
def lauf_slip(levels, lo, hi, slip_usd):
ev=[]
for ab,bis,lvl,d in levels:
for i in range(max(ab,1), min(bis+1, len(C)-2)):
atr=A[i-1]
if not atr or atr < V._ATRMIN: continue
if not ((H[i]>=lvl) if d>0 else (L[i]<=lvl)): continue
ev.append((i,d,lvl,atr,SP[i])); break
ev.sort(); rs=[]; frei=lo
for i,d,entry,atr,sp in ev:
if not (lo<=i<hi) or i<frei: continue
r,xb=simulate(entry,d,atr,H,L,C,i+1,LIVE,timestop=True,use_tp=True,ret_bar=True)
rs.append(r-(sp if sp>0 else 0.0225)/atr - slip_usd/atr)
frei=xb+1
return rs
setups=[("KONTROLLE Squeeze", V.squeeze_kontrolle(H,L,C,A)),
("PDH / PDL Bruch", V.tagesextrem(H,L,T)),
("Asian Range Bruch", V.asia(H,L,T)),
("Equal H/L Bruch", V.equal_hl(H,L,A))]
print("="*92)
print(" EXIT-SLIPPAGE angesetzt (gemessen: >=0,0124 $ im Tagfenster, >=0,0370 $ gesamt)")
print("="*92)
print(f" {'Setup':<22} {'0,000 $':>18} {'0,0124 $':>18} {'0,0370 $':>18}")
for name,lv in setups:
z=f" {name:<22}"
for s in (0.0, 0.0124, 0.0370):
k1=kennzahlen(lauf_slip(lv,0,m,s)); k2=kennzahlen(lauf_slip(lv,m,len(C),s))
z += (f" {k1['oer']:>+7.3f}/{k2['oer']:>+7.3f}" if k1 and k2 else f" {'':^16}")
print(z)
print()
print(" ⚠ Die Edges liegen bei +0,13..+0,25 R — eine Slippage von 0,08..0,25 R")
print(" je Trade ist dagegen keine Randgroesse, sondern der entscheidende Posten.")
+282
View File
@@ -0,0 +1,282 @@
#!/usr/bin/env python3
"""Die verworfenen Signale — neu gemessen auf der EINEN Achse, die heute neu ist.
ANLASS (2026-08-06, User: „backteste alle verworfenen Signale").
⚠ WAS DAS HIER NICHT IST: ein erneuter Durchlauf aller Ablehnungen. Der lief am
2026-08-04 (`run_all_backtests.py`, 14 Klassen, alle blieben verworfen) und waere
nur eine Wiederholung — mit dem Mehrfachvergleichs-Problem obendrauf.
NEU ist genau eine Achse: der **Einstiegspreis**. Sie hat am 05.08. Squeeze und
Auto-Signal von negativ auf positiv gedreht. ALLE alten Ablehnungen wurden mit
Markt-/Bar-Close-Einstieg gemessen — sie koennten also unter einer Annahme
gefallen sein, die nicht mehr gilt.
⚠⚠ ABER MIT DER HEUTIGEN KORREKTUR. `backtest_momentum_v2.py` hat gezeigt, dass
„Einstieg am Level" zweideutig ist:
(B) Fill, WO der Bar-CLOSE das Level bricht → Look-ahead, ~+0,3…0,45 R zu gut
(C) Fill bei der ERSTEN BERUEHRUNG → das, was live passiert
Gemessen wird deshalb C. B laeuft nur als Diagnose mit, um den Aufschlag sichtbar
zu machen.
⚠⚠ UND NUR DORT, WO DIE ACHSE UEBERHAUPT GREIFEN KANN. Der Vorteil entsteht an
Levels, die **STILLSTEHEN** (Squeeze-Box: +0,124/+0,292) — nicht an mitwandernden
(Momentum: 0,04…−0,09). Geprueft werden deshalb die verworfenen Setups mit einem
stehenden Level und einer AUSBRUCHS-Richtung:
ORB (EU/US) · PDH/PDL · Asian Range · Equal Highs/Lows
⚠ Bewusst NICHT dabei, weil die Achse dort nichts aendern kann:
· Momentum, Inter-Market, Chop-Gate, Meta-Labeling, RSI/MACD/ADX — kein Level.
· Reversal/Bounce, Kerzen-Fade, POC-Reversion, Fibonacci, Kanalrand — REVERSIONS-
Einstiege. Dort fuellt eine ruhende Order gerade dann, wenn man falsch liegt
(gemessen `backtest_candle_fade2.py`: Limit am Extrem macht es SCHLECHTER).
· Volume Profile — Level steht zwar, aber das Profil muesste je Bar neu gebinnt
werden; Laufzeit unverhaeltnismaessig. Offen.
VORAB FIXIERTE ENTSCHEIDUNGSREGEL (vor dem ersten Lauf):
(1) in Variante C: ØR > 0 UND PF > 1 in BEIDEN Haelften
(2) mind. 40 Trades je Haelfte
(3) muss die KONTROLLE (Squeeze, +0,124/+0,292) nicht schlagen, aber selbst
beidhaelftig tragen
(4) Mehrfachvergleich wird ausgewiesen: bei ~10 Tests sind ~0,5 Zufallstreffer
zu erwarten — ein einzelnes ✅ ist damit schwach.
Aufruf: python backtest_verworfene_v2.py [bars]
"""
import sys
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
import MetaTrader5 as mt5
import core.wave_rec as wr
from backtest_cost_gate import _atr_series, kennzahlen
from core.exit_model import LIVE, simulate
_BERLIN = ZoneInfo("Europe/Berlin")
_BROKER = timezone(timedelta(hours=3))
_UTC = timezone.utc
_ATRMIN = 0.06
_MIN_N = 40
def _berlin(ts):
return (datetime.fromtimestamp(int(ts), _UTC)
.replace(tzinfo=_BROKER).astimezone(_BERLIN))
# ─────────────────────────────────────────────────────────────────────────
# Setups: jedes liefert STEHENDE Level als (ab_bar, bis_bar, level, richtung)
# richtung: +1 = Ausbruch nach oben ist LONG, 1 = nach unten ist SHORT
# ─────────────────────────────────────────────────────────────────────────
def orb(H, L, T, A, start_h, start_m, minuten):
"""Opening Range Breakout: Box = erste `minuten` nach dem Open, gilt bis 22:00."""
out, tag, box = [], None, None
for i in range(len(H)):
b = _berlin(T[i])
d = b.date()
if d != tag:
tag, box = d, None
beginn = b.replace(hour=start_h, minute=start_m, second=0, microsecond=0)
ende = beginn + timedelta(minutes=minuten)
if box is None and b >= ende:
js = [j for j in range(max(0, i - 40), i)
if beginn <= _berlin(T[j]) < ende]
if js:
hi, lo = max(H[j] for j in js), min(L[j] for j in js)
bis = i
while bis < len(H) - 2 and _berlin(T[bis]).date() == d \
and _berlin(T[bis]).hour < 22:
bis += 1
out.append((i, bis, hi, +1))
out.append((i, bis, lo, -1))
box = True
return out
def tagesextrem(H, L, T):
"""PDH/PDL — Hoch/Tief des Vortages, gilt den ganzen Folgetag."""
tage = {}
for i in range(len(H)):
d = _berlin(T[i]).date()
r = tage.setdefault(d, [i, i, H[i], L[i]])
r[1] = i; r[2] = max(r[2], H[i]); r[3] = min(r[3], L[i])
folge = sorted(tage)
out = []
for k in range(1, len(folge)):
_, _, hi, lo = tage[folge[k - 1]]
a, b, _, _ = tage[folge[k]]
out.append((a, b, hi, +1))
out.append((a, b, lo, -1))
return out
def asia(H, L, T):
"""Asian Range 00:0008:00 Berlin, gilt 08:00 bis Tagesende."""
out, tag, gesammelt = [], None, []
for i in range(len(H)):
b = _berlin(T[i])
if b.date() != tag:
tag, gesammelt, gesetzt = b.date(), [], False
if b.hour < 8:
gesammelt.append(i)
elif gesammelt and not globals().get("_dummy"):
if b.hour == 8 and b.minute < 5:
hi = max(H[j] for j in gesammelt); lo = min(L[j] for j in gesammelt)
bis = i
while bis < len(H) - 2 and _berlin(T[bis]).date() == tag:
bis += 1
out.append((i, bis, hi, +1))
out.append((i, bis, lo, -1))
gesammelt = []
return out
def equal_hl(H, L, A, tol=0.15, gueltig=120):
"""Equal Highs/Lows aus M5-Pivots (k=3) — zwei Extrema innerhalb tol×ATR."""
ph = [i for i in range(3, len(H) - 3)
if H[i] == max(H[i - 3:i + 4])]
pl = [i for i in range(3, len(L) - 3)
if L[i] == min(L[i - 3:i + 4])]
out = []
for piv, arr, d in ((ph, H, +1), (pl, L, -1)):
for a in range(1, len(piv)):
i0, i1 = piv[a - 1], piv[a]
if not (6 <= i1 - i0 <= 240):
continue
atr = A[i1]
if not atr or atr < _ATRMIN:
continue
if abs(arr[i1] - arr[i0]) > tol * atr:
continue
lvl = (arr[i1] + arr[i0]) / 2.0
out.append((i1 + 4, min(i1 + 4 + gueltig, len(H) - 2), lvl, d))
return out
def squeeze_kontrolle(H, L, C, A):
"""Kontrolle: die Squeeze-Box als stehendes Level (muss +0,124/+0,292 treffen)."""
out = []
for i in range(wr._SQ_N + 2, len(C) - 2):
atr = A[i - 1]
if not atr or atr < _ATRMIN:
continue
hb = H[i - wr._SQ_N - 1:i - 1]; lb = L[i - wr._SQ_N - 1:i - 1]
if not hb or not lb:
continue
hi, lo = max(hb), min(lb)
if (hi - lo) / atr > wr._SQ_MULT:
continue
out.append((i, i, hi + wr._SQ_K * atr, +1))
out.append((i, i, lo - wr._SQ_K * atr, -1))
return out
# ─────────────────────────────────────────────────────────────────────────
def lauf(levels, H, L, C, SP, A, lo, hi, modus):
"""modus: 'markt' = Bar-Close · 'close' = Level, aber nur bei Close-Bruch
· 'touch' = Level, Fill bei erster Beruehrung (REALITAET)."""
ereignisse = []
for ab, bis, lvl, d in levels:
for i in range(max(ab, 1), min(bis + 1, len(C) - 2)):
atr = A[i - 1]
if not atr or atr < _ATRMIN:
continue
beruehrt = (H[i] >= lvl) if d > 0 else (L[i] <= lvl)
if not beruehrt:
continue
gebrochen = (C[i] > lvl) if d > 0 else (C[i] < lvl)
if modus != "touch" and not gebrochen:
break # Level verbraucht (Docht) — kein Signal
entry = C[i] if modus == "markt" else lvl
ereignisse.append((i, d, entry, atr, SP[i]))
break # ein Fill je Level
ereignisse.sort()
rs, frei_ab = [], lo
for i, d, entry, atr, sp in ereignisse:
if not (lo <= i < hi) or i < frei_ab:
continue
r, xb = simulate(entry, d, atr, H, L, C, i + 1, LIVE,
timestop=True, use_tp=True, ret_bar=True)
rs.append(r - (sp if sp > 0 else 0.0225) / atr)
frei_ab = xb + 1
return rs
def main():
n = int(sys.argv[1]) if len(sys.argv) > 1 else 80000
if not mt5.initialize():
print("MT5 nicht erreichbar"); return 1
sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD")
if mt5.symbol_info(c)), None)
b = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, n)
point = mt5.symbol_info(sym).point
mt5.shutdown()
H = [float(x["high"]) for x in b]; L = [float(x["low"]) for x in b]
C = [float(x["close"]) for x in b]; T = [int(x["time"]) for x in b]
SP = [float(x["spread"]) * point for x in b]
A = _atr_series(H, L, C)
m = len(C) // 2
setups = [
("KONTROLLE Squeeze", squeeze_kontrolle(H, L, C, A)),
("ORB EU 15 min", orb(H, L, T, A, 10, 0, 15)),
("ORB EU 30 min", orb(H, L, T, A, 10, 0, 30)),
("ORB US 15 min", orb(H, L, T, A, 16, 30, 15)),
("ORB US 30 min", orb(H, L, T, A, 16, 30, 30)),
("PDH / PDL Bruch", tagesextrem(H, L, T)),
("Asian Range Bruch", asia(H, L, T)),
("Equal H/L Bruch", equal_hl(H, L, A)),
]
print("=" * 104)
print(f" VERWORFENE SETUPS — neu auf der Ausfuehrungs-Achse ({sym}, {len(C)} M5-Bars)")
print("=" * 104)
print(" Geprueft wird NUR, was ein STEHENDES Level + Ausbruchsrichtung hat —")
print(" dort kann die Achse ueberhaupt wirken (Squeeze ja, Momentum nein).")
print(" Massgeblich ist Spalte C. B steht nur da, um den Look-ahead zu zeigen.")
print()
print(f" {'Setup':<22} {'A) Markt H1/H2':^22} {'B) Close-Bruch H1/H2':^24} "
f"{'C) BERUEHRUNG H1/H2':^24} n Urteil")
print(" " + "-" * 100)
treffer = []
for name, lv in setups:
z = f" {name:<22}"
erg = {}
for modus in ("markt", "close", "touch"):
k1 = kennzahlen(lauf(lv, H, L, C, SP, A, 0, m, modus))
k2 = kennzahlen(lauf(lv, H, L, C, SP, A, m, len(C), modus))
erg[modus] = (k1, k2)
z += (f" {k1['oer']:>+7.3f}/{k2['oer']:>+7.3f} " if k1 and k2
else f" {'':^16} ")
c1, c2 = erg["touch"]
if not c1 or not c2:
print(z + ""); continue
ok = (c1["oer"] > 0 and c2["oer"] > 0 and c1["pf"] > 1 and c2["pf"] > 1
and c1["n"] >= _MIN_N and c2["n"] >= _MIN_N)
z += f" {c1['n']:>4} {'' if ok else ''}"
if c1["n"] < _MIN_N or c2["n"] < _MIN_N:
z += " (duenn)"
print(z)
if ok and not name.startswith("KONTROLLE"):
treffer.append(name)
print()
print("=" * 104)
print(f" ERGEBNIS: {len(treffer)} von {len(setups)-1} verworfenen Setups tragen "
f"auch mit realistischem Fill")
if treffer:
print(f"{', '.join(treffer)}")
print(" ⚠ Vor jeder Konsequenz: Nachbar-Parameter pruefen und gegen die")
print(" Kontrolle halten. Ein einzelnes ✅ bei ~7 Tests ist erwartbar.")
else:
print(" → Die Ablehnungen bleiben bestehen. Die Ausfuehrungs-Achse rettet")
print(" keines dieser Setups.")
print()
print(" ⚠ Spalte B gegen C gelesen = der Look-ahead-Aufschlag. Ist er gross,")
print(" war das Setup nie so gut, wie ein Level-Backtest suggeriert.")
return 0
if __name__ == "__main__":
sys.exit(main())