#!/usr/bin/env python3
"""Auto-Signal-Entry: trägt er OHNE das Reversal-Setup? (2026-08-04)

Anlass: Am 2026-08-04 wurde das antizyklische Reversal-Setup abgeschaltet
(`reversal_enabled=false`, gemessen beidhälftig negativ). Frage des Users:
liefert der Auto-Signal-Entry mit dieser Änderung positive Ergebnisse?

Die letzte Messung (`backtest_auto_signal.py`, 2026-07-30) fand ALLE 8 Varianten
durchgefallen — H1 durchgehend negativ (ØR −0,076…−0,182), H2 positiv
(+0,112…+0,167) = Regime-Kippen. Damals war der Reversal-Zweig aktiv, denn
`_build` enthielt ihn bedingungslos.

Dieses Skript importiert `scan`/`_rep` aus `backtest_auto_signal` — also exakt
dieselbe Maschinerie (echte `_build`-Logik, HTF aus M5 aggregiert, sequentielle
1-Positions-Sim, Live-Exit, Echtkosten) — und variiert NUR
`WaveRecommender._reversal_enabled`. Das isoliert den Effekt der Abschaltung.

⚠ Das bestehende Skript bleibt unverändert: sein Default (Reversal AN) reproduziert
weiterhin die Messung vom 30.07.

Geprüft werden die LIVE-Parameter (`auto_signal_min_conf=75`,
`auto_signal_skip_night=true`, `adverse_15min_atr=0` → keine 15-Min-Regel) plus
die Konfidenz-Nachbarn 55/65, damit ein Treffer nicht an einer Schwelle klebt.

Aufruf:  python backtest_auto_signal_norev.py [bars]
"""
import sys

import MetaTrader5 as mt5

from datetime import datetime, timezone

from backtest_auto_signal import (_ATRMIN, _MAXH, _NIGHT, _TIMESTOP, _NeutralTU,
                                  _atr_series, _ema_series, _htf_signs, _HTF_N,
                                  _sim, scan)
from core.analysis import calc_trend_angle
from core.wave_rec import _ANGLE_LR, _EMA_FAST, _EMA_SLOW, WaveRecommender


def scan_angle(bars, H, L, C, SP, A, HTF, H1, EF, ES, AD, w,
               lo_i, hi_i, min_conf, skip_night):
    """Wie `scan`, aber MIT dem Regressions-Winkel.

    ⚠⚠ Der Grund für diese Kopie: `backtest_auto_signal.scan` ruft `_build` OHNE
    `angle=` auf → der Default 90,0 macht `ad = 0`. Damit kann dort weder der
    Reversal-Zweig feuern (braucht |ad| > _ANGLE_DEAD) noch der Winkel-Konfidenz-
    term (±5/−10) greifen. Das Skript behauptet in seiner Docstring, die „echte
    `_build`-Logik inkl. Reversal-Zweig" zu testen — strukturell tut es das nicht.
    Vierter Fall derselben Klasse: gemessen unter „kein Winkel", betrieben unter
    „Winkel steuert einen Signalzweig UND ±15 Konfidenzpunkte".
    Die Original-Datei bleibt unangetastet (ihre Zahlen sind dokumentiert); hier
    steht die live-treue Variante daneben.
    """
    Rs = []
    i = max(lo_i, _EMA_SLOW + 20)
    hi_i = min(hi_i, len(C) - _MAXH - 2)
    while i < hi_i:
        atr = A[i]
        if not atr or atr < _ATRMIN:
            i += 1; continue
        if skip_night:
            hb = (datetime.fromtimestamp(int(bars[i]["time"]),
                                         timezone.utc).hour - 1) % 24
            if hb in _NIGHT:
                i += 1; continue
        rec, _snap = w._build(EF[i], ES[i], C[i], atr, "M5", 5,
                              htf_trend=HTF[i], h1_trend=H1[i], angle=AD[i])
        sig = rec.get("signal")
        if sig not in ("LONG", "SHORT") or (rec.get("conf_pct") or 0) < min_conf:
            i += 1; continue
        d = 1 if sig == "LONG" else -1
        cost = (SP[i] if SP[i] > 0 else 0.0225) / atr
        Rs.append(_sim(C[i], d, atr, H, L, C, i + 1, None) - cost)
        i += _TIMESTOP          # identischer Vorlauf wie im Original (kein Overlap)
    return Rs


def stats(Rs):
    if not Rs:
        return None
    n = len(Rs); w = sum(1 for x in Rs if x > 0); s = sum(Rs)
    up = sum(x for x in Rs if x > 0); dn = -sum(x for x in Rs if x < 0)
    return dict(n=n, wr=100 * w / n, oR=s / n,
                pf=(up / dn if dn > 0 else 9.99), sum=s)


def fmt(s):
    if not s:
        return "— (keine Trades)"
    return (f"n={s['n']:>4} WR={s['wr']:>3.0f}% ØR={s['oR']:+.3f} "
            f"PF={s['pf']:>4.2f} ΣR={s['sum']:>+6.0f}")


def main():
    n = int(sys.argv[1]) if len(sys.argv) > 1 else 80000
    if not mt5.initialize():
        print(f"MT5-Init fehlgeschlagen: {mt5.last_error()}"); sys.exit(1)
    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 + _MAXH + 60)
    point = mt5.symbol_info(sym).point
    mt5.shutdown()
    if bars is None or len(bars) < 5000:
        print("Zu wenige Bars."); sys.exit(1)

    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)
    HTF = _htf_signs(H, L, C, _HTF_N)
    H1 = _htf_signs(H, L, C, _HTF_N * 2)
    EF = _ema_series(C, _EMA_FAST)
    ES = _ema_series(C, _EMA_SLOW)
    N = len(C); mid = N // 2

    w_on = WaveRecommender(_NeutralTU(), mt5.TIMEFRAME_M5)
    w_on.set_reversal_enabled(True)          # Stand bis 03.08. (= Messung 30.07.)
    w_off = WaveRecommender(_NeutralTU(), mt5.TIMEFRAME_M5)
    w_off.set_reversal_enabled(False)        # Live-Stand seit 04.08.

    print("=" * 96)
    print(f"  AUTO-SIGNAL-ENTRY mit/ohne Reversal — {sym} M5 ({N} Bars)")
    print("  Identische Maschinerie aus backtest_auto_signal.py; variiert wird NUR")
    print("  `_reversal_enabled`. Nacht-Sperre AN, keine 15-Min-Regel (live = 0).")
    print("  Referenz (validierter Auto-Entry Squeeze): ØR +0,14…+0,23 · PF>1")
    print("=" * 96)

    # Winkel je Bar — genau wie im Live-Pfad aufgerufen
    AD = [90.0] * len(C)
    for i in range(_ANGLE_LR + 2, len(C)):
        AD[i] = calc_trend_angle(C[i - (_ANGLE_LR + 1):i + 1], _ANGLE_LR)

    for mc in (55, 65, 75):
        live = "   ← LIVE-Schwelle" if mc == 75 else ""
        print(f"\n  Konfidenz ≥ {mc}{live}")
        for lbl, lo, hi in (("H1 (alt)", 0, mid), ("H2 (neu)", mid, N)):
            r_alt = stats(scan(bars, H, L, C, SP, A, HTF, H1, EF, ES,
                               w_on, lo, hi, mc, True, None))
            r_rev = stats(scan_angle(bars, H, L, C, SP, A, HTF, H1, EF, ES, AD,
                                     w_on, lo, hi, mc, True))
            r_live = stats(scan_angle(bars, H, L, C, SP, A, HTF, H1, EF, ES, AD,
                                      w_off, lo, hi, mc, True))
            print(f"    {lbl}")
            print(f"       ALT-Messung (ohne Winkel, Rev. wirkungslos) : {fmt(r_alt)}")
            print(f"       mit Winkel + Reversal AN  (Stand bis 03.08.): {fmt(r_rev)}")
            print(f"       mit Winkel + Reversal AUS (LIVE seit 04.08.): {fmt(r_live)}")
            if r_rev and r_live:
                print(f"       Δ durch das Abschalten: ØR "
                      f"{r_live['oR'] - r_rev['oR']:+.3f}   ΣR "
                      f"{r_live['sum'] - r_rev['sum']:+.0f}")
        print()
    print("  Urteil: Einbau nur, wenn ØR>0 UND PF>1 in BEIDEN Hälften — und die")
    print("  Konfidenz-Nachbarn mithalten (sonst klebt der Treffer an einer Schwelle).")
    print()


if __name__ == "__main__":
    main()
