#!/usr/bin/env python3
"""AUTÓPSIA #1 — EFR2/IFR2 (Stormer) vs dados reais B3.
Regras como ensinadas: RSI(2)<25 no fechamento -> compra no fechamento;
alvo = máxima dos 2 candles anteriores (intradia); stop no tempo = 7 candles.
Custo 0.05%/lado (emolumentos+slippage). Variante com filtro MM200."""
import yfinance as yf
import pandas as pd
import numpy as np

TICKERS = ["ITUB4.SA", "CPLE6.SA", "PETR4.SA", "VALE3.SA", "BOVA11.SA"]
COST = 0.0005  # por lado
RSI_N, RSI_LIM, TIME_STOP = 2, 25, 7

def rsi(close, n):
    d = close.diff()
    up = d.clip(lower=0).ewm(alpha=1/n, adjust=False).mean()
    dn = (-d.clip(upper=0)).ewm(alpha=1/n, adjust=False).mean()
    rs = up / dn.replace(0, np.nan)
    return 100 - 100/(1+rs)

def backtest(df, use_ma_filter):
    c, h = df["Close"], df["High"]
    r = rsi(c, RSI_N)
    ma200 = c.rolling(200).mean()
    trades = []
    i = 200
    idx = df.index
    while i < len(df) - 1:
        sig = r.iloc[i] < RSI_LIM and (not use_ma_filter or c.iloc[i] > ma200.iloc[i])
        if sig:
            entry = c.iloc[i]
            target = max(h.iloc[i-1], h.iloc[i-2])
            exit_px, exit_j = None, None
            for j in range(i+1, min(i+1+TIME_STOP, len(df))):
                if h.iloc[j] >= target:
                    exit_px = max(target, df["Open"].iloc[j])  # gap acima = melhor preço
                    exit_j = j
                    break
            if exit_px is None:
                exit_j = min(i+TIME_STOP, len(df)-1)
                exit_px = c.iloc[exit_j]
            ret = exit_px/entry - 1 - 2*COST
            trades.append(ret)
            i = exit_j + 1
        else:
            i += 1
    return np.array(trades)

def stats(t):
    if len(t) == 0: return None
    wins = t[t > 0]; losses = t[t <= 0]
    wr = len(wins)/len(t)
    aw = wins.mean() if len(wins) else 0
    al = abs(losses.mean()) if len(losses) else np.nan
    payoff = aw/al if al and al > 0 else np.inf
    exp = t.mean()
    eq = np.cumprod(1+t); dd = (eq/np.maximum.accumulate(eq)-1).min()
    # pior sequência de perdas
    seq = mx = 0
    for x in t:
        seq = seq+1 if x <= 0 else 0
        mx = max(mx, seq)
    total = eq[-1]-1
    return dict(n=len(t), wr=wr, payoff=payoff, exp=exp, total=total, dd=dd, maxseq=mx)

print(f"{'ATIVO':10} {'FILTRO':7} {'N':>4} {'WINRATE':>8} {'PAYOFF':>7} {'EXP/TRADE':>10} {'TOTAL':>8} {'MAXDD':>7} {'PIORSEQ':>7}")
agg = {True: [], False: []}
for tk in TICKERS:
    df = yf.download(tk, period="4y", interval="1d", auto_adjust=True, progress=False)
    if df.empty:
        print(f"{tk:10} SEM DADOS"); continue
    if isinstance(df.columns, pd.MultiIndex):
        df.columns = df.columns.get_level_values(0)
    for f in [False, True]:
        t = backtest(df, f)
        agg[f].append(t)
        s = stats(t)
        if s:
            print(f"{tk:10} {'MM200' if f else 'puro':7} {s['n']:>4} {s['wr']:>7.1%} {s['payoff']:>7.2f} {s['exp']:>9.3%} {s['total']:>7.1%} {s['dd']:>6.1%} {s['maxseq']:>7}")
for f in [False, True]:
    allt = np.concatenate(agg[f]) if agg[f] else np.array([])
    s = stats(allt)
    if s:
        print(f"{'CARTEIRA':10} {'MM200' if f else 'puro':7} {s['n']:>4} {s['wr']:>7.1%} {s['payoff']:>7.2f} {s['exp']:>9.3%} {'—':>8} {'—':>7} {s['maxseq']:>7}")
