"""Trennt `conf_pct` ueberhaupt? Und ist 55 die richtige Schwelle? (2026-08-19) FRAGE (User, Punkt (2) der Verbesserungsliste). `min_conf` blockt live **11,4 %** aller Empfehlungen. Die Schwelle 55 stammt aus `backtest_conf.py`: Band 40-54 % gemessen negativ (-0,025), >= 55 % positiv (+0,058). WARUM DAS NEU ZU MESSEN IST -- drei Gruende, jeder fuer sich hinreichend: 1. `backtest_conf.py` misst `_build` ALLEIN, ohne Breakout-Bestaetigung und ohne Entry-Raum-Gate. Genau die beiden sind live die groessten Blocker (dokumentiert 2026-08-05: 77,9 % gerichtet allein vs. 19,5 % im vollen Stack). Es ist also eine andere Population. 2. Es nutzt ein aelteres Exit-Modell, nicht `exit_model.LIVE`. 3. `analyze_verdict_calibration.py` hat `conf_pct` als **nicht kalibriert** ausgewiesen und in H2 sogar INVERTIERT (85-100 % -> 40 % Trefferquote). Ob es wenigstens im ERTRAG trennt, ist damit offen. AUFBAU. Voller Live-Gate-Stack, aber `_MIN_CONF` auf 0 gesetzt, damit auch die heute geblockten Signale sichtbar werden; danach nach Konfidenz-Baendern aufgeteilt. Kanonischer Exit, Echtkosten, 2 Halbjahre, 95-%-KI je Zelle. Zusaetzlich beide Ausfuehrungs-Achsen (Markt / ruhende Order am Level), weil `backtest_entryroom_level.py` am selben Tag gezeigt hat, dass die Achse beidhaelftig +0,09 bis +0,11 R traegt. REGEL VORAB FIXIERT: - Die Schwelle wird nur verschoben, wenn ein anderer Schnitt in BEIDEN Haelften mehr OeR UND mehr Summe liefert und die Nachbarbaender mithalten. - Zusaetzliche Aussage: trennt conf ueberhaupt? Das verlangt einen in beiden Haelften GLEICHGERICHTETEN Verlauf ueber die Baender -- ein Band, das in H1 steigt und in H2 faellt, ist Rauschen. GRENZE: kein sequentieller Ein-Slot-Lauf (verglichen werden Populationen). Exit-Slippage ist nicht modelliert. Aufruf: python backtest_conf_gated.py [bars] """ import sys import MetaTrader5 as mt5 import core.wave_rec as WR from backtest_breakout_gated import _PIV_K, _TU, _atr_series, _htf_sign from backtest_cost_gate import kennzahlen from backtest_entryroom_level import _GATE, _K, handeln, sammle from core.analysis import calc_trend_angle from core.exit_model import LIVE from core.wave_rec import (WaveRecommender, _ANGLE_LR, _EMA_FAST, _EMA_SLOW, _ema_series) BAENDER = [(0, 45), (45, 55), (55, 65), (65, 75), (75, 101)] def zeig(lbl, k1, k2): def f(k): if not k: return " --" ci = k.get("ci") m = "" if ci: m = (" [{:+.3f} .. {:+.3f}]".format(ci[0], ci[1]) + ("" if ci[0] * ci[1] > 0 else " ~0")) return ("n={:>4} WR={:>3.0f}% OeR={:+.3f} SR={:+8.1f} PF={:.2f}{}" .format(k["n"], k["wr"], k["oer"], k["sr"], k["pf"], m)) print(" {:<16} H1 {}".format(lbl, f(k1))) print(" {:<16} H2 {}".format("", f(k2))) def main(): n = int(sys.argv[1]) if len(sys.argv) > 1 else 80000 mt5.initialize() sym = next((c for c in ("SpotCrude", "USOIL", "WTI", "XTIUSD") if mt5.symbol_info(c)), None) bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M5, 0, n) point = mt5.symbol_info(sym).point mt5.shutdown() H = [float(b["high"]) for b in bars]; L = [float(b["low"]) for b in bars] C = [float(b["close"]) for b in bars] SP = [float(b["spread"]) * point for b in bars] A = _atr_series(H, L, C) EF = _ema_series(C, _EMA_FAST); ES = _ema_series(C, _EMA_SLOW) N = len(C); mid = N // 2; ende = N - LIVE.max_hold - 1 print("Vorberechnung ...", flush=True) AD = [90.0] * N for i in range(_ANGLE_LR + 2, N): AD[i] = calc_trend_angle(C[i - (_ANGLE_LR + 1):i + 1], _ANGLE_LR) HTF = [0] * N; H1 = [0] * N for i in range(N): if A[i]: HTF[i] = _htf_sign(C, i, 6, A[i]) H1[i] = _htf_sign(C, i, 12, A[i]) PH = [j for j in range(_PIV_K, N - _PIV_K) if H[j] == max(H[j - _PIV_K:j + _PIV_K + 1])] PL = [j for j in range(_PIV_K, N - _PIV_K) if L[j] == min(L[j - _PIV_K:j + _PIV_K + 1])] w = WaveRecommender(_TU(), mt5.TIMEFRAME_M5) w.set_reversal_enabled(False) w.set_entry_room(_GATE) w.set_dead_hours([]) w.set_breakout_k(_K) # Gate oeffnen, damit die heute geblockten Baender ueberhaupt entstehen. # ⚠ Modul-Konstante, wirkt prozessweit -- deshalb hier und nirgends sonst. alt = WR._MIN_CONF WR._MIN_CONF = 0 print("=" * 100) print(" KONFIDENZ-SCHWELLE im vollen Gate-Stack -- {} M5 ({} Bars)".format(sym, N)) print(" _MIN_CONF {} -> 0 fuer die Messung ({} Bars pro Haelfte)".format(alt, mid)) print("=" * 100) try: s1 = sammle(w, H, L, C, A, EF, ES, AD, HTF, H1, PH, PL, 0, mid) s2 = sammle(w, H, L, C, A, EF, ES, AD, HTF, H1, PH, PL, mid, ende) finally: WR._MIN_CONF = alt print(" Signale ohne Konfidenz-Gate: H1 {} H2 {}".format(len(s1), len(s2))) for modus, titel in (("markt", "A) MARKT am Bar-Close (= wie die Sim von 2026-07-16)"), ("level", "B) ruhende Order AM Level, Fill bei BERUEHRUNG")): print("") print(" " + titel) print(" " + "-" * 96) for lo, hi in BAENDER: def rs(sigs): out = [] for s in sigs: c = s.get("conf") if c is None or not (lo <= c < hi): continue r = handeln(s, H, L, C, SP, ende, modus, 0.0, 12) if r is not None: out.append(r) return out zeig("conf {}-{}".format(lo, hi - 1), kennzahlen(rs(s1)), kennzahlen(rs(s2))) print("") # Kumulativ: was liefert die Schwelle X, wenn man alles >= X handelt? print(" Schwellen-Vergleich (alles >= X gehandelt)") for x in (0, 45, 55, 65, 75): def rs2(sigs): out = [] for s in sigs: c = s.get("conf") if c is None or c < x: continue r = handeln(s, H, L, C, SP, ende, modus, 0.0, 12) if r is not None: out.append(r) return out tag = " <- LIVE" if x == alt else "" zeig(">= {}{}".format(x, tag), kennzahlen(rs2(s1)), kennzahlen(rs2(s2))) print("") print("=" * 100) if __name__ == "__main__": main()