"""Traegt ein LONG, wenn der Kurs SEHR weit ueber der EMA steht? (2026-08-20) ANLASS (User): "der Tagestrend ist aktuell aufwaerts, auch die News deuten auf bullish hin - warum wird das in der Empfehlung nicht beruecksichtigt." Die Praemisse stimmt (Tageskerze +2,47 $ / +2,89 %, H1 monoton steigend). Der Blocker ist `_STRETCH_MAX = 3,5`: der Kurs steht +4,36xATR ueber der EMA50 der Basis-TF, das Signal wird als "Spaet-Long" unterdrueckt. Die 3,5 stammen aus `backtest_stretch.py` ("ab 3,5xATR kippt der Edge negativ"). Dort wurde die SCHWELLE gesucht; hier wird die Frage des Users direkt gestellt: was passiert, wenn man GENAU IN DIESER LAGE trotzdem long geht? AUFBAU. Reine Stretch-Bedingung auf M30 (die aktuelle Basis-TF) und auf M5, kein weiteres Gate - es geht um die eine Achse. Einstieg am Bar-Close in Trend-Richtung, kanonischer Exit (`exit_model.LIVE`), Echtkosten aus dem Bar-Spread, zwei Halbjahre, 95-%-Bootstrap, Episoden-entkoppelt (sonst zaehlt dieselbe Ueberdehnung dutzendfach). Baender: 2,0-2,5 / 2,5-3,0 / 3,0-3,5 (= erlaubt) gegen 3,5-4,5 / 4,5+ (= gesperrt). REGEL VORAB FIXIERT: die Sperre gehoert gelockert, wenn die gesperrten Baender in BEIDEN Halbjahren einen positiven OeR liefern UND ihr 95-%-Intervall die Null ausschliesst. Sonst bleibt sie. """ import sys import MetaTrader5 as mt5 from backtest_cost_gate import kennzahlen from core.exit_model import LIVE, simulate from core.squeeze_scan import atr_series BAENDER = [(2.0, 2.5), (2.5, 3.0), (3.0, 3.5), (3.5, 4.5), (4.5, 99.0)] GATE = 3.5 def ema_serie(C, p): k = 2.0 / (p + 1.0); out = [C[0]] for x in C[1:]: out.append(x * k + out[-1] * (1 - k)) return out def lauf(H, L, C, SP, A, e50, von, bis, ende, lo, hi): """Alle Bars im Band -> LONG bei Ueberdehnung nach OBEN, SHORT nach unten. Entkoppelt: je zusammenhaengender Episode im Band nur der ERSTE Bar. """ rs = []; im_band = False for i in range(von, min(bis, ende)): atr = A[i] if not atr or atr < 0.06: im_band = False; continue st = (C[i] - e50[i]) / atr drin = lo <= abs(st) < hi if drin and not im_band: d = 1 if st > 0 else -1 # Richtung = Trendrichtung r = simulate(C[i], d, atr, H, L, C, i + 1, LIVE, timestop=True, use_tp=True) rs.append(r - ((SP[i] if SP[i] > 0 else 0.0225) / atr)) im_band = drin return rs def zeig(lbl, k, gesperrt): mark = " <== heute GESPERRT" if gesperrt else "" if not k: print(" {:<12} --{}".format(lbl, mark)); return ci = k.get("ci"); m = "" if ci: m = (" [{:+.3f} .. {:+.3f}]".format(ci[0], ci[1]) + ("" if ci[0] * ci[1] > 0 else " ~0")) print(" {:<12} n={:>4} WR={:>3.0f}% OeR={:+.3f} PF={:.2f}{}{}" .format(lbl, k["n"], k["wr"], k["oer"], k["pf"], m, mark)) def main(): n = int(sys.argv[1]) if len(sys.argv) > 1 else 60000 mt5.initialize() sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD") if mt5.symbol_info(c)), None) point = mt5.symbol_info(sym).point daten = {} for tf, lbl in ((mt5.TIMEFRAME_M30, "M30"), (mt5.TIMEFRAME_M5, "M5")): b = mt5.copy_rates_from_pos(sym, tf, 0, n) daten[lbl] = ([float(x["high"]) for x in b], [float(x["low"]) for x in b], [float(x["close"]) for x in b], [float(x["spread"]) * point for x in b]) mt5.shutdown() print("=" * 96) print(" UEBERDEHNUNG: traegt ein Einstieg JENSEITS des Gates? — {}".format(sym)) print(" Gate live: |stretch| > {} x ATR -> WARTEN · kanonischer Exit, Echtkosten" .format(GATE)) print("=" * 96) for lbl in ("M30", "M5"): H, L, C, SP = daten[lbl] A = atr_series(H, L, C); e50 = ema_serie(C, 50) N = len(C); mid = N // 2; ende = N - LIVE.max_hold - 1 print("\n {} ({} Bars)".format(lbl, N)) print(" " + "-" * 92) for lo, hi in BAENDER: band = "{:.1f}-{:.1f}".format(lo, hi) if hi < 90 else "{:.1f}+".format(lo) g = lo >= GATE zeig("H1 " + band, kennzahlen(lauf(H, L, C, SP, A, e50, 0, mid, ende, lo, hi)), g) zeig("H2 " + band, kennzahlen(lauf(H, L, C, SP, A, e50, mid, ende, ende, lo, hi)), g) print() print(" " + "=" * 92) print(" REGEL: lockern nur, wenn die GESPERRTEN Baender beidhaelftig") print(" positiv sind UND ihr Intervall die Null ausschliesst.") if __name__ == "__main__": main()