"""
V12 — Momentum Taker con Confirmación.

Evolución de V11. Misma lógica base pero con dos mejoras clave:

  1. CONFIRMACIÓN DE MOMENTUM: V11 entraba en el primer tick que cruzaba
     el threshold → vulnerable a "chop" (spike + reversión inmediata).
     V12 requiere que el movimiento persista N ticks consecutivos (CONFIRM_TICKS)
     en la misma dirección antes de generar señal.

  2. AGGRESSIVE BUMP REDUCIDO: V11 pagaba ask+$0.02 para asegurar fill.
     V12 reduce a ask+$0.01 (configurable via AGGRESSIVE_BUMP).
     Cada centavo de overpay destruye edge en shares de ~$0.50.
"""
import json, math, os
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path


# -- Infraestructura ----------------------------------------------------------

GAMMA_API  = "https://gamma-api.polymarket.com/events/slug"
PRICE_API  = "https://polymarket.com/api/crypto/crypto-price"
CLOB_WS    = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
HOST       = "https://clob.polymarket.com"
CHAIN_ID   = 137
UA         = {"User-Agent": "Mozilla/5.0"}

# -- Momentum Strategy -------------------------------------------------------

# Señal: |price/strike - 1| > MOMENTUM_THRESHOLD → entrar
MOMENTUM_THRESHOLD = 0.0005    # 0.05% — sweet spot del backtest

# Entry
ENTRY_SIZE_USD     = 5.0       # USD por trade
MIN_SHARES         = 5.0
TICK_SIZE          = 0.01

# Filtros de precio
# En momentum taker, compramos cuando tenemos señal direccional.
# A precio 0.50 el payoff es 1:1 → necesitamos WR>52% para ser rentables
# A precio 0.60 el payoff es 0.67:1 → necesitamos WR>60%
# A precio 0.65 el payoff es 0.54:1 → necesitamos WR>65%
# Con WR~80%, hasta precio 0.65 es rentable (EV positivo)
MAX_ENTRY_PRICE    = 0.65      # Cap para mantener EV positivo con 80% WR
MIN_ENTRY_PRICE    = 0.20      # No comprar demasiado barato (mercado raro)

# Taker fee
TAKER_FEE_RATE     = 0.02      # 2% taker fee en Polymarket

# V12: Confirmación de momentum
# Requiere N ticks consecutivos (1 tick = 1 segundo) con |move| > threshold
# en la MISMA dirección antes de entrar. Filtra spikes transitorios ("chop").
CONFIRM_TICKS      = 3         # 3 segundos — filtra spikes de 1 tick sin perder edge vs CLOB

# V12: Bump agresivo reducido
# V11 usaba +$0.02 sobre ask para asegurar fill. Eso es 4% de overpay en
# un share de $0.50, destruyendo edge. Reducido a $0.01.
AGGRESSIVE_BUMP    = 0.01      # centavos sobre ask (V11 era 0.02)

# Paper simulation
PAPER_SLIPPAGE     = 0.01      # Slippage simulado: pagamos 1c más del mid

# Defense mechanisms
LOSS_STREAK_MAX    = 3         # consecutive losses → trigger cooldown
LOSS_STREAK_COOL   = 3         # windows to skip during cooldown
DAILY_LOSS_LIMIT   = 999.0     # desactivado — las otras defensas (global cooldown, filtro horario, thresholds) son suficientes

# Filtro horario (UTC). Horas donde WR histórico < 40% → no operar.
# Datos: ~300 trades, las horas desactivadas promedian WR 30% vs 55% en las activas.
# Para replicar en POLYBOT2: copiar esta línea a POLYBOT2/v11/config.py
# y añadir el import + check en bot.py (buscar "BLOCKED_HOURS").
BLOCKED_HOURS_UTC  = set()  # DESACTIVADO — test limpio desde 2026-06-01 18:00 UTC
# Original: {0, 2, 6, 7, 9, 11, 12, 15, 21, 22, 23}

# Settle — esperar outcome oficial de Polymarket (NUNCA inferir)
OUTCOME_MAX_WAIT   = 900       # 15min max — siempre tenemos posición

# -- Configuración por duración de ventana ------------------------------------

WINDOW_CONFIGS = {
    5: {
        "win_secs": 300,
        "slug_tag": "5m",
        "price_variant": "fiveminute",
        "signal_start_tleft": 270,    # Empezar con 4.5min restantes (30s warmup)
        "signal_stop_tleft": 60,      # Parar con 1min restante
    },
    15: {
        "win_secs": 900,
        "slug_tag": "15m",
        "price_variant": "fifteenminute",
        "signal_start_tleft": 840,    # Empezar con 14min restantes
        "signal_stop_tleft": 120,     # Parar con 2min restantes
    },
}

# -- Per-asset ----------------------------------------------------------------

ASSET_CONFIGS = {
    "btc": {
        "binance_stream":   "btcusdt@trade",
        "slug_base":        "btc-updown",
        "price_symbol":     "BTC",
        "min_ask_confirm":  0.38,    # sweet spot: 0.40-0.50, pero BTC asks son más bajos
        "entry_size_usd":   5.0,
        "max_entry_price":  0.55,    # datos: >0.65 WR=33%, cap conservador
        "momentum_threshold": 0.0008,  # 0.08% — subido desde 0.05%. Datos: <0.10% pierde, >0.10% gana
    },
    "eth": {
        "binance_stream":   "ethusdt@trade",
        "slug_base":        "eth-updown",
        "price_symbol":     "ETH",
        "min_ask_confirm":  0.40,    # datos: sweet spot 0.40-0.50 (WR=56%)
        "entry_size_usd":   5.0,
        "max_entry_price":  0.53,    # datos: >0.55 WR cae
        "momentum_threshold": 0.0010,  # 0.10% — subido desde 0.07%. Solo movimientos fuertes
    },
    "sol": {
        "binance_stream":   "solusdt@trade",
        "slug_base":        "sol-updown",
        "price_symbol":     "SOL",
        "min_ask_confirm":  0.48,    # +7% vs anterior (0.45) — más selectivo
        "entry_size_usd":   5.0,
        "max_entry_price":  0.53,
        "momentum_threshold": 0.0010,  # 0.10% — +43% vs anterior (0.07%), solo movimientos fuertes
    },
    "xrp": {
        "binance_stream":   "xrpusdt@trade",
        "slug_base":        "xrp-updown",
        "price_symbol":     "XRP",
        "min_ask_confirm":  0.45,
        "max_entry_price":  0.53,
        "momentum_threshold": 0.0007,
    },
    "doge": {
        "binance_stream":   "dogeusdt@trade",
        "slug_base":        "doge-updown",
        "price_symbol":     "DOGE",
        "min_ask_confirm":  0.45,
        "max_entry_price":  0.53,
        "momentum_threshold": 0.0007,
    },
    "bnb": {
        "binance_stream":   "bnbusdt@trade",
        "slug_base":        "bnb-updown",
        "price_symbol":     "BNB",
        "min_ask_confirm":  0.45,
        "max_entry_price":  0.53,
        "momentum_threshold": 0.0007,
    },
}


# -- Config resuelta ----------------------------------------------------------

@dataclass
class Config:
    asset: str
    live: bool
    window: int = 15            # 5 o 15 minutos

    binance_ws: str = ""
    slug_prefix: str = ""
    price_symbol: str = ""
    price_variant: str = ""
    win_secs: int = 900
    signal_start_tleft: int = 840
    signal_stop_tleft: int = 120
    min_ask_confirm: float = 0.20
    entry_size_usd: float = 5.0
    max_entry_price: float = 0.65   # per-asset override
    momentum_threshold: float = 0.0005  # per-asset override
    confirm_ticks: int = 10        # V12: ticks de confirmación (per-asset override)
    aggressive_bump: float = 0.01  # V12: centavos sobre ask (per-asset override)

    log_dir: Path = field(default_factory=lambda: Path("."))
    trades_csv: Path = field(default_factory=lambda: Path("."))
    windows_csv: Path = field(default_factory=lambda: Path("."))
    state_json: Path = field(default_factory=lambda: Path("."))

    def __post_init__(self):
        acfg = ASSET_CONFIGS[self.asset]
        wcfg = WINDOW_CONFIGS[self.window]

        self.binance_ws   = f"wss://stream.binance.com:9443/ws/{acfg['binance_stream']}"
        self.slug_prefix  = f"{acfg['slug_base']}-{wcfg['slug_tag']}-"
        self.price_symbol = acfg["price_symbol"]
        self.price_variant = wcfg["price_variant"]
        self.win_secs     = wcfg["win_secs"]
        self.signal_start_tleft = wcfg["signal_start_tleft"]
        self.signal_stop_tleft  = wcfg["signal_stop_tleft"]
        self.min_ask_confirm    = acfg.get("min_ask_confirm", 0.20)
        self.max_entry_price    = acfg.get("max_entry_price", MAX_ENTRY_PRICE)
        self.momentum_threshold = acfg.get("momentum_threshold", MOMENTUM_THRESHOLD)
        self.entry_size_usd     = acfg.get("entry_size_usd", ENTRY_SIZE_USD)
        self.confirm_ticks      = acfg.get("confirm_ticks", CONFIRM_TICKS)
        self.aggressive_bump    = acfg.get("aggressive_bump", AGGRESSIVE_BUMP)

        if self.live:
            sub = f"{self.asset}_live"
        else:
            sub = self.asset
        base = Path(__file__).parent.parent / "logs" / sub
        self.log_dir      = base
        self.trades_csv   = base / "trades.csv"
        self.windows_csv  = base / "windows.csv"
        self.state_json   = base / "state.json"


# -- Utilidades ---------------------------------------------------------------

def iso(ts: int) -> str:
    return datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

def snap_price(price: float) -> float:
    return round(max(0.01, min(0.99, round(price / TICK_SIZE) * TICK_SIZE)), 2)

def write_json(path: Path, data: dict):
    tmp = path.with_suffix(".tmp")
    try:
        tmp.write_text(json.dumps(data, ensure_ascii=False, indent=2))
        tmp.replace(path)
    except Exception as e:
        print(f"[json-write] {path.name}: {e}")
