"""
================================================================
  ⚙️  APEX PREDATOR V15 — CONFIG FUTURES (TopstepX / ProjectX)
================================================================

  V15 CHANGES vs V14:
    ❌ MT5 / FP Markets CFD                 → ✅ TopstepX / CME futures
    ❌ Symboli .r (EURUSD.r)                → ✅ Root symbols (MES/MNQ/MGC/MCL)
    ❌ Lot decimali (0.01)                  → ✅ Contratti interi
    ❌ pip / pip_mult / tick_value_override → ✅ tick_size + tick_value (dall'API)
    ❌ MAGIC_NUMBER MT5                     → ✅ Account ID Topstep

  FASE 1 SCOPE: MICRO contracts only (risk 1/10 vs full contracts)
    MES  = Micro E-mini S&P 500     (tick 0.25 = $1.25)
    MNQ  = Micro E-mini Nasdaq-100  (tick 0.25 = $0.50)
    MGC  = Micro Gold               (tick 0.10 = $1.00)
    MCL  = Micro Crude Oil          (tick 0.01 = $1.00)

  TARGET ACCOUNT: Express Funded Account $50k
    Starting balance: $0 (EFA starts at 0)
    Max Loss Limit:   starts at -$2,000, trails up to $0 then locks
    → Internal buffer: -$1,200 (60% of -$2,000) to stay safe

================================================================
"""

# ═══════════════════════════════════════════════════════════════
# 🔑 CREDENZIALI API (da env o da qui — preferire .env in prod)
# ═══════════════════════════════════════════════════════════════
import os

# ProjectX / TopstepX credentials
PROJECTX_USERNAME = os.getenv("PROJECT_X_USERNAME", "")  # ← riempi in .env
PROJECTX_API_KEY  = os.getenv("PROJECT_X_API_KEY",  "")  # ← riempi in .env

# Claude AI (invariato da V14)
ANTHROPIC_API_KEY = os.getenv(
    "ANTHROPIC_API_KEY",
    "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"
)
CLAUDE_MODEL = "claude-haiku-4-5-20251001"

# Gemini fallback (invariato da V14 — rimosso per compattezza; 
# può essere reintegrato aggiungendo PAID_KEY + API_KEYS come in V14)
GEMINI_PAID_KEY = "AIzaSyCAiSBZu3Y-EcHh8EMET8pgouDW4JcKh04"

# ═══════════════════════════════════════════════════════════════
# 🏦 TOPSTEP EFA $50k — HARD LIMITS (internal guards)
# ═══════════════════════════════════════════════════════════════
# Source: help.topstep.com (verified 2026-04)
#
# EFA $50k starts at balance 0. MLL trails upward from -$2,000.
# Once balance reaches $2,000 → MLL locks at $0 permanently.
#
# We use INTERNAL buffers more conservative than Topstep limits,
# so we auto-flatten well before Topstep does.

TOPSTEP_EFA_CONFIG = {
    "account_type":            "EFA_50k",
    "starting_balance":         0.0,      # EFA start balance
    "topstep_max_loss":        -2000.0,   # Topstep hard limit (initial)
    "internal_max_loss_buffer": 0.60,     # Trigger flatten at 60% of MLL used
    "internal_max_loss":       -1200.0,   # ← auto-flatten + halt here
    "daily_loss_soft_stop":     -400.0,   # No new entries after -$400 in day
    "daily_loss_hard_stop":     -2000.0,  # 🔧 V15 27/04 demo: pre-funded riportare a -1500   # Auto-flatten + halt for the day
    "daily_profit_target":       300.0,   # Stop opening new trades after +$300
}

# Scaling plan EFA: max contracts per trade (conservativo)
# Topstep starts at 5 micros / 1 mini — noi partiamo ancora più stretti
MAX_CONTRACTS_PER_TRADE = {
    # ── Index micros ─────────────────────────────────────────────
    "MES": 6,    # V17 sizing-uniform: 6 ct × MAX_SL 40t × $1.25 = $300 worst-case
    "MNQ": 12,   # V17 sizing-uniform: 12 ct × 48t × $0.50 = $288 worst-case
    "MYM": 12,   # V17 sizing-uniform: 12 ct × 50t × $0.50 = $300 worst-case
    # ── Metal micros ─────────────────────────────────────────────
    "MGC": 4,    # V17 sizing-uniform: 4 ct × 80t × $1.00 = $320 worst-case (round-up)
    # ── Energy micros ────────────────────────────────────────────
    "MCL": 4,    # V17 sizing-uniform: 4 ct × 80t × $1.00 = $320 worst-case (round-up)
    # ── FX majors (full-size — tick value più alto) ──────────────
    # V18 12-mag: tutti gli FX a 2 ct per abilitare partial 50%.
    # Single-contract trades non possono fare partial → si perdeva il
    # ramo Brain TF/MR auto_partial_50 (PARTIAL_50 + SL→BE). Il MIN
    # floor sotto garantisce sizing=2 anche quando il calcolo per
    # risk_usd ne darebbe 1.
    "6E": 2,    # worst-case 2 × 40t × $6.25 = $500
    "6B": 2,    # worst-case 2 × 40t × $6.25 = $500
    "6A": 2,    # V18: era 1; worst-case 2 × 12t × $10 = $240 (MIN_SL=12)
    "6J": 2,    # V18: era 1; worst-case 2 × 20t × $6.25 = $250 (MIN_SL=20)
    "6C": 2,    # V18: era 1; worst-case 2 × 50t × $5 = $500
    # ── Full size indices (disattivati in Fase 1) ────────────────
    "ES":  1,
    "NQ":  1,
    "GC":  1,
    "CL":  1,
    "default": 1,
}

# V18 12-mag — MIN contracts floor per asset.
# Sui futures FX il sizing naturale può scendere a 1 contratto (tick
# value elevato → 1 ct esaurisce il budget di rischio). Single-contract
# disabilita però la partial exit (N/2 ≥ N → demote a EXIT). Il floor
# qui forza un minimo per asset così la posizione resta "partialabile".
# Letto da trading.sizing.compute_contracts DOPO il clamp a max_contracts.
MIN_CONTRACTS_PER_TRADE = {
    "6E": 2,
    "6B": 2,
    "6A": 2,
    "6J": 2,
    "6C": 2,
}

MAX_OPEN_TRADES_TOTAL = 2   # max 2 posizioni contemporaneamente (EFA prudente)

# ═══════════════════════════════════════════════════════════════
# 📐 RISK MANAGEMENT
# ═══════════════════════════════════════════════════════════════
# NOTE: su futures il sizing è discreto (contratti interi).
# Se il target_contracts calcolato è < MIN_CONTRACT_FRACTION → skip entry
# (meglio saltare che rischiare 2x il target).
RISK_PER_TRADE = 0.003        # 0.30% del balance (allineato a V14 — più conservativo)
                              # Su $50k → max -$150/trade, ~4.7 SL prima del DLL -$700
MIN_CONTRACT_FRACTION = 0.70  # se target_contracts < 0.7 → skip
# Un trade NON può mai rischiare più di questa % del daily_loss_hard_stop rimanente
MAX_RISK_VS_DAILY_BUDGET = 0.50  # 🔧 V15 27/04 demo: pre-funded riportare a 0.33

# ═══════════════════════════════════════════════════════════════
# 📊 ASSETS — CME FUTURES SPECS (Fase 1: solo MICROS)
# ═══════════════════════════════════════════════════════════════
# tick_size / tick_value saranno confermati dinamicamente dall'API
# al boot, ma li includiamo qui come fallback e per i cap di sicurezza.
#
# hours: ore UTC in cui operare (cash session + overlap)
# digits: decimali per arrotondamento prezzo
# category: usato per SL/TP profiles

ASSETS_MAP = {
    # ══════════════════════════════════════════════════════════════
    # EQUITY INDEX MICROS
    # ══════════════════════════════════════════════════════════════
    # CME Globex: Sun 5PM CT → Fri 4PM CT, maintenance 4-5PM CT daily
    # Summer (DST): CT = UTC-5 → pausa 21-22 UTC. Inverno: 22-23 UTC.
    # Per semplicità: tutte le ore tranne pausa maintenance.
    
    # ── MICRO E-MINI S&P 500 (≈ V14 US500) ───────────────────────
    "MES": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    2,
        "tick_size": 0.25,
        "tick_value": 1.25,
        "category":  "INDEX_MICRO",
        "exchange":  "CME",
        "root":      "MES",
    },
    # ── MICRO E-MINI NASDAQ-100 (≈ V14 US100) ────────────────────
    "MNQ": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    2,
        "tick_size": 0.25,
        "tick_value": 0.50,
        "category":  "INDEX_MICRO",
        "exchange":  "CME",
        "root":      "MNQ",
    },
    # ── MICRO E-MINI DOW JONES (≈ V14 US30) ──────────────────────
    # 🆕 V15: aggiunto per coprire US30 del V14
    "MYM": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    0,   # Dow in punti interi
        "tick_size": 1.0,
        "tick_value": 0.50,   # $0.50 per punto (1 tick)
        "category":  "INDEX_MICRO",
        "exchange":  "CBOT",
        "root":      "MYM",
    },
    
    # ══════════════════════════════════════════════════════════════
    # METAL MICROS
    # ══════════════════════════════════════════════════════════════
    # ── MICRO GOLD (≈ V14 XAUUSD) ────────────────────────────────
    "MGC": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    1,
        "tick_size": 0.10,
        "tick_value": 1.00,
        "category":  "METAL_MICRO",
        "exchange":  "COMEX",
        "root":      "MGC",
    },
    
    # ══════════════════════════════════════════════════════════════
    # ENERGY MICROS
    # ══════════════════════════════════════════════════════════════
    # ── MICRO CRUDE OIL WTI (nuovo vs V14) ───────────────────────
    "MCL": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    2,
        "tick_size": 0.01,
        "tick_value": 1.00,
        "category":  "ENERGY_MICRO",
        "exchange":  "NYMEX",
        "root":      "MCL",
    },
    
    # ══════════════════════════════════════════════════════════════
    # FX FUTURES (FULL SIZE — no micro su TopstepX per liquidità)
    # ══════════════════════════════════════════════════════════════
    # 🆕 V15: aggiunti per coprire le 4 coppie forex del V14
    # ⚠️ IMPORTANTE: tick_value è per contratto FULL, non micro.
    #    6E: €125,000 notional; 6B: £62,500; 6A: AUD 100,000; 6J: ¥12,500,000
    # ⚠️ 6J ha CONVENZIONE INVERSA: prezzo quota USD/JPY invertito
    #    → 6J↑ = yen si rafforza = USDJPY↓ (OPPOSTO del V14 USDJPY.r!)
    #    La logica V14 SELL USDJPY corrisponde a BUY 6J nel V15.
    #    Gestione in bias_computer V15 — flag inverted_quote.
    
    # ── EURO FX (≈ V14 EURUSD.r) ─────────────────────────────────
    "6E": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    5,    # es: 1.08345
        "tick_size": 0.00005,
        "tick_value": 6.25,
        "category":  "FX_MAJOR",
        "exchange":  "CME",
        "root":      "6E",
        "inverted_quote": False,
    },
    # ── BRITISH POUND (≈ V14 GBPUSD.r) ───────────────────────────
    "6B": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    4,    # es: 1.2650
        "tick_size": 0.0001,
        "tick_value": 6.25,
        "category":  "FX_MAJOR",
        "exchange":  "CME",
        "root":      "6B",
        "inverted_quote": False,
    },
    # ── AUSTRALIAN DOLLAR (≈ V14 AUDUSD.r) ───────────────────────
    "6A": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    4,
        "tick_size": 0.0001,
        "tick_value": 10.00,
        "category":  "FX_MAJOR",
        "exchange":  "CME",
        "root":      "6A",
        "inverted_quote": False,
    },
    # ── JAPANESE YEN (≈ V14 USDJPY.r MA INVERSO!) ────────────────
    # 6J quota JPY/USD → movimento 6J UP = yen up = USDJPY DOWN
    # Il Brain V14 "BUY USDJPY" deve diventare "SELL 6J" nel V15.
    # Gestito in wrapper direction (flag inverted_quote=True).
    "6J": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    7,    # es: 0.0065450
        "tick_size": 0.0000005,
        "tick_value": 6.25,
        "category":  "FX_MAJOR",
        "exchange":  "CME",
        "root":      "6J",
        "inverted_quote": True,  # ⚠️ direzione inversa rispetto a USDJPY
    },
    # ── CANADIAN DOLLAR (≈ V14 USDCAD.r MA INVERSO!) ─────────────
    # 6C quota CAD/USD → 6C UP = CAD up = USDCAD DOWN
    "6C": {
        "hours":     [h for h in range(24) if h not in (21, 22)],
        "digits":    5,
        "tick_size": 0.00005,
        "tick_value": 5.00,
        "category":  "FX_MAJOR",
        "exchange":  "CME",
        "root":      "6C",
        "inverted_quote": True,  # ⚠️ direzione inversa rispetto a USDCAD
    },
}

# NOTE V14 → V15:
# ❌ GBPJPY: no futures CME diretto (cross, richiede 6B/6J sintetico)
# ❌ EURGBP: no futures CME diretto (cross, richiede 6E/6B sintetico)
# ❌ GER40:  è Eurex, non CME → non disponibile su Topstep
# Queste 3 coppie V14 non possono essere portate su V15 TopstepX.

# ═══════════════════════════════════════════════════════════════
# 🎯 SL/TP PROFILES — calibrati per categoria futures
# ═══════════════════════════════════════════════════════════════
# ATR M5 × base_atr_mult = sl_distance in POINTS (not ticks).
# Una volta calcolato, divideremo per tick_size per ottenere sl_ticks.
# Session multipliers applicati sopra (trend hours vs quiet hours).

ASSET_VOLATILITY_PROFILE = {
    # ── EQUITY INDEX MICROS ──────────────────────────────────────
    "MES": {
        "base_atr_mult": 1.20,
        "reversal_speed": "NORMAL",
        "session_mult": {"ASIA": 1.30, "EUROPA": 1.10, "USA": 0.95},
    },
    "MNQ": {
        "base_atr_mult": 1.20,
        "reversal_speed": "FAST",
        "session_mult": {"ASIA": 1.30, "EUROPA": 1.10, "USA": 0.95},
    },
    # Dow futures: meno volatile di S&P/Nasdaq ma con mean reversion normale
    "MYM": {
        "base_atr_mult": 1.25,
        "reversal_speed": "NORMAL",
        "session_mult": {"ASIA": 1.35, "EUROPA": 1.10, "USA": 0.95},
    },
    # ── METAL MICROS ─────────────────────────────────────────────
    "MGC": {
        "base_atr_mult": 1.15,
        "reversal_speed": "SLOW",
        "session_mult": {"ASIA": 1.20, "EUROPA": 1.05, "USA": 1.00},
    },
    # ── ENERGY MICROS ────────────────────────────────────────────
    "MCL": {
        "base_atr_mult": 1.35,
        "reversal_speed": "VERY_FAST",
        "session_mult": {"ASIA": 1.40, "EUROPA": 1.15, "USA": 0.95},
    },
    # ── FX MAJORS ────────────────────────────────────────────────
    # Forex futures: volatilità moderata, mean reversion tipica
    # session_mult: FX è più attivo in EUROPA + US session overlap
    "6E": {
        "base_atr_mult": 1.10,
        "reversal_speed": "NORMAL",
        "session_mult": {"ASIA": 1.25, "EUROPA": 0.95, "USA": 1.00},
    },
    "6B": {
        "base_atr_mult": 1.15,   # GBP più volatile
        "reversal_speed": "NORMAL",
        "session_mult": {"ASIA": 1.25, "EUROPA": 0.95, "USA": 1.00},
    },
    "6A": {
        "base_atr_mult": 1.10,
        "reversal_speed": "NORMAL",
        "session_mult": {"ASIA": 0.95, "EUROPA": 1.15, "USA": 1.10},
    },
    "6J": {
        "base_atr_mult": 1.20,   # JPY movements spesso più ampi
        "reversal_speed": "NORMAL",
        "session_mult": {"ASIA": 0.90, "EUROPA": 1.10, "USA": 1.15},
    },
    "6C": {
        "base_atr_mult": 1.10,
        "reversal_speed": "NORMAL",
        "session_mult": {"ASIA": 1.30, "EUROPA": 1.10, "USA": 0.95},   # CAD attivo su US session
    },
}

# Min SL (in ticks) per asset — safety floor
MIN_SL_TICKS = {
    # Equity indices
    "MES": 8,    # 2 points = $10/ct
    "MNQ": 8,    # 2 points = $4/ct
    "MYM": 10,   # 10 points = $5/ct (Dow si muove più ampio in points)
    # Metals
    "MGC": 15,   # 1.5 points = $15/ct
    # Energy
    "MCL": 20,   # 0.20 points = $20/ct
    # FX
    "6E": 10,    # 10 ticks = 5 pips = $62.50/ct (full size!)
    "6B": 10,    # $62.50/ct
    "6A": 12,    # $120/ct
    "6J": 20,    # 20 ticks = $125/ct (JPY volatile)
    "6C": 10,    # $50/ct
}

# Max SL (in ticks) per asset — cap per evitare outlier
MAX_SL_TICKS = {
    # Equity indices
    "MES": 40,   # 10 points = $50/ct
    "MNQ": 48,   # 12 points = $24/ct
    "MYM": 50,   # 50 points = $25/ct
    # Metals
    "MGC": 80,   # 8 points = $80/ct (V16-30-apr: 60→80, clamp_active 100% in
                 #                     produzione con ATR M5 tipico 3-4 + sl_atr mid 1.95)
    # Energy
    "MCL": 80,   # 0.80 points = $80/ct
    # FX (SL ridotti perché full-size = tick value elevato)
    "6E": 40,    # 40 ticks = $250/ct max
    "6B": 40,    # $250/ct max
    "6A": 40,    # $400/ct max (tick value $10!)
    "6J": 60,    # 60 ticks = $375/ct max
    "6C": 50,    # $250/ct max
}

# Structural SL cap: se swing pivot SL > cap × atr_sl → fallback ATR puro
STRUCTURAL_SL_CAP = {
    # 🔧 2026-04-26 (sera): NUOVA FILOSOFIA — struttura sempre prioritaria.
    # Cap = soglia oltre cui struct è "immenso" e usiamo ATR fallback.
    # Soglie alzate: meno fallback ATR, più SL strutturali.
    # FX: ATR molto basso, struct legittimi possono arrivare a 3.5×ATR
    # Indici: ATR alto, swing strutturali tipicamente 4×ATR
    # Metalli/Energy: 3×ATR
    # Equity (indici)
    "MES": 4.0,
    "MNQ": 4.0,
    "MYM": 4.0,
    # Metals
    "MGC": 3.0,
    # Energy
    "MCL": 3.0,
    # FX
    "6E": 3.5,
    "6B": 3.5,
    "6A": 3.5,
    "6J": 3.5,
    "6C": 3.5,
    "default": 3.0,
}

# 🔧 2026-04-24: tetto assoluto in tick per evitare SL giganti in asset volatili.
# Se struct > ATR*CAP E struct > MAX_STRUCT_SL_TICKS → ATR fallback
MAX_STRUCT_SL_TICKS = {
    # 🔧 2026-04-26 (sera): tetto ASSOLUTO ampliato.
    # Solo per evitare SL "kamikaze" tipo 200 tick. Struct legittimi devono passare.
    # FX swing 25-35t sono normali → tetto 40t.
    # Indici/Metals → swing tipici 50-100t.
    # Equity
    "MES": 60,
    "MNQ": 60,
    "MYM": 60,
    # Metals
    "MGC": 120,
    # Energy
    "MCL": 80,
    # FX
    "6E": 40,
    "6B": 40,
    "6A": 40,
    "6J": 40,
    "6C": 40,
    "default": 50,
}

# ═══════════════════════════════════════════════════════════════
# 🎯 TP RESOLUTION — variante γ (rr_multiplier × real $ risk)
# ═══════════════════════════════════════════════════════════════
# Filosofia APEX: SL=risk meccanico ATR-based; TP=frazione del rischio
# reale in dollari, scelta dall'AI come `rr_multiplier` ∈ [0.17, 0.67]
# (advisory prompt-range, hard clamp tp_resolver [0.10, 0.80]).
#
# Math (in trading/tp_resolver.py):
#   sl_usd_actual = contracts × sl_ticks × tick_value
#   tp_usd_target = rr_multiplier × sl_usd_actual
#   tp_distance   = rr_multiplier × sl_ticks × tick_size  [contracts cancel]
#   tp_ticks_raw  = round(rr_multiplier × sl_ticks)
#   tp_ticks_final = max(MIN_TP_TICKS[symbol], tp_ticks_raw)
#
# MIN_TP_TICKS: soglia minima in ticks per asset, a copertura dei
# costi round-trip Topstep + tick scale. Filosofia V14 "TP < costi =
# trade perdente by design" → tp_ticks viene alzato al floor in ticks.
# CALIBRAZIONE 5-9 mag: rivalidare valori da brain_log.jsonl
# (eventi tp_resolved con min_tp_ticks_applied=true).
# ═══════════════════════════════════════════════════════════════

# Costi reali round-trip per contratto Topstep (apr 2026):
#   FX (6E/6B/6A/6C): $4.24    |    6J: $4.24
#   MGC: $1.74, MES: $1.24, MCL: $1.54, MNQ/MYM: $1.24 stima
# Floor in ticks dimensionato ~3-5× costo round-trip per asset.
MIN_TP_TICKS: dict[str, int] = {
    # FX (10 ticks ≈ 10 pip per asset standard, 4 ticks per 6J inverted)
    "6E": 10,    # 10 pip = $12.50/ct (~3× costo)
    "6B": 10,    # 10 pip = $12.50/ct
    "6A": 10,    # 10 pip = $10/ct
    "6J": 4,     # 4 pip USDJPY-equiv = $25/ct (~5× costo round-trip)
    "6C": 10,    # 10 pip = $10/ct
    # Equity index micros
    "MES": 4,    # 4 ticks = $5/ct (~4× costo)
    "MNQ": 8,    # 8 ticks = $4/ct
    "MYM": 10,   # 10 ticks = $5/ct
    # Metals/Energy
    "MGC": 10,   # 10 ticks = $10/ct (~5× costo)
    "MCL": 10,   # 10 ticks = $10/ct (~6× costo)
}

# SL safety multiplier (applicato dopo structural/ATR, prima del sizing)
SL_SAFETY_MULT = 1.10

# ═══════════════════════════════════════════════════════════════
# 💰 TP MIN PROFITABILITY (V17 — AI-suggested TP path only)
# ═══════════════════════════════════════════════════════════════
# Quando il brain V17 emette `tp_price_suggested` valido e direction-
# coherent, _post_validate calcola:
#     tp_distance_post_margin = 0.85 × |tp_suggested − entry|
#     tp_ticks                = round(tp_distance_post_margin / tick_size)
#     tp_gross_per_contract   = tp_ticks × tick_value
#     tp_net_per_contract     = tp_gross_per_contract − COMMISSION_PER_CONTRACT_USD
# Se tp_net_per_contract < TP_MIN_NET_PROFIT_USD → entry REJECTED con
# rule "TP_BELOW_MIN_PROFIT" (NIENTE floor — la tightness è segnale che
# il setup è marginale, meglio attendere). Il path rr-fallback NON è
# soggetto a questa regola: lì interviene MIN_TP_TICKS come floor.
#
# COMMISSION_PER_CONTRACT_USD ≈ $6.70 = round-trip Topstep + exchange
# fees + NFA + slippage cushion (stima conservativa V17, calibrare 5-9
# mag su dati reali).
# ═══════════════════════════════════════════════════════════════
TP_MIN_NET_PROFIT_USD: float = 20.0
COMMISSION_PER_CONTRACT_USD: float = 6.70

# ═══════════════════════════════════════════════════════════════
# 📰 NEWS FILTER (V14 port — ForexFactory High-impact)
# ═══════════════════════════════════════════════════════════════
# Solo eventi HIGH-impact gateano l'entry. MEDIUM events cached per
# calibrazione/forensics ma non bloccano.
# Window V14-fedele: 45 min prima → 15 min dopo l'evento.
# Network fail-open: fetch fallito → no block (V14 fidelity).
# ═══════════════════════════════════════════════════════════════
ENABLE_NEWS_FILTER = True
NEWS_BLOCK_BEFORE_MIN = 45   # blocca entry 45 min prima di High Impact
NEWS_BLOCK_AFTER_MIN  = 15   # blocca entry 15 min dopo
NEWS_SOURCE_URL = "https://nfs.faireconomy.media/ff_calendar_thisweek.json"
NEWS_SYNC_INTERVAL_MIN = 60
NEWS_HTTP_TIMEOUT_SEC = 10

# Currency exposure per asset (per news filter routing).
# USD news (NFP/FOMC/CPI) impattano TUTTI gli asset USD-quoted, inclusi
# metalli/energia (Gold/Crude rispondono violentemente al dollar index).
# FX includono entrambe le valute del cross (BoE su 6B, BOJ su 6J, ecc.).
ASSET_CURRENCIES: dict[str, list[str]] = {
    # Equity index micros — USD-denominated
    "MES":  ["USD"],
    "MNQ":  ["USD"],
    "MYM":  ["USD"],
    # Metal/Energy — USD-denominated
    "MGC":  ["USD"],
    "MCL":  ["USD"],
    # FX — both legs
    "6E":   ["USD", "EUR"],
    "6B":   ["USD", "GBP"],
    "6A":   ["USD", "AUD"],
    "6J":   ["USD", "JPY"],
    "6C":   ["USD", "CAD"],
}

# ═══════════════════════════════════════════════════════════════
# 🕐 TRADING HOURS — filtro orari per asset (V14 port)
# ═══════════════════════════════════════════════════════════════
# Ore UTC ammesse per scan_entries per asset. Fuori da questi orari
# l'orchestrator emette scan_skip con reason=OUTSIDE_TRADING_HOURS
# (no Brain, no AI call) — riduce costi AI e setup di bassa qualità
# in sessioni illiquide.
#
# Orari derivati dai range V14 originali (ora italiana CEST = UTC+2),
# convertiti -2h e cappati a 18 UTC (Topstep no-overnight).
# Aggiunte rispetto a V14:
#   - 6A/6J: sessione Asia (V14 era CFD su broker europeo, no Asia;
#     futures TopstepX sono attivi 23h con liquidità Asia reale).
#   - MGC/6J: buchi V14 (artefatti probabili) riempiti.
#   - MCL: ristretto a NYMEX-only (crude è mercato USA).
#
# Note:
#   - Ore in formato hour-of-day UTC (0-23). Il filtro guarda solo
#     l'ora corrente (now.hour), non i minuti — coerente con V14.
#   - Il filtro NON tocca manage_exit: trade aperti continuano a
#     essere gestiti anche fuori dagli orari (exit/SL/TP rimangono
#     attivi).
#   - Asset non listati: fail-open (nessun blocco) per non
#     bloccare nuovi asset durante onboarding.
# ═══════════════════════════════════════════════════════════════
ENABLE_TRADING_HOURS_FILTER = True
TRADING_HOURS: dict[str, list[int]] = {
    # Equity index micros — pre-cash ramp + cash open + EU/US overlap.
    # Drop 18 UTC (= 14 ET): "lunch lull" classica, range-bound chop.
    "MES":  [13, 14, 15, 16, 17],
    "MNQ":  [13, 14, 15, 16, 17],
    "MYM":  [13, 14, 15, 16, 17],
    # Gold — London AM/PM fix + US data window. Drop 6,7 UTC
    # (pre-London thin, spread larghi su micro).
    "MGC":  [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
    # Crude — NYMEX pit core (closes 18:30 UTC). Drop 18 UTC: spread
    # widening + gap risk nei minuti pre-pit-close.
    "MCL":  [13, 14, 15, 16, 17],
    # EUR — Frankfurt → London close. Drop 6 (pre-Frankfurt thin) + 17,18
    # (post-London, USD-driven only senza partecipazione europea).
    "6E":   [7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
    # GBP — London-bound (BoE-relevant). Cap 16 = London close fix.
    "6B":   [7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
    # AUD — Tokyo/Sydney prime + US session. Drop 6-8 UTC (EU mattina,
    # AUD secondo-tier) e 17,18 UTC (US PM zombie pre-Sydney reopen).
    "6A":   [0, 1, 2, 3, 4, 5, 11, 12, 13, 14, 15, 16],
    # JPY — Tokyo + London + US-prime. Drop 6 UTC (Tokyo lunch gap)
    # e 17,18 UTC (US PM lull pre-Tokyo).
    "6J":   [0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
    # CAD — USA-only futures (oil-correlated, BoC). Restrict to [12-17]:
    # CAD è thin fuori dalla finestra US prime.
    "6C":   [12, 13, 14, 15, 16, 17],
}

# ═══════════════════════════════════════════════════════════════
# 🔗 CORRELAZIONE FUTURES
# ═══════════════════════════════════════════════════════════════
# ES/NQ/YM molto correlati intraday (0.85+)
# MES↔MNQ: stessa famiglia → blocca secondo trade se primo aperto
ENABLE_CORRELATION = True
CORRELATION_GROUPS = {
    # Equity indices: MES/MNQ/MYM si muovono correlati (>0.80 intraday)
    "EQUITY_INDICES": ["MES", "MNQ", "MYM", "ES", "NQ", "YM"],
    # Metals
    "METALS":         ["MGC", "GC"],
    # Energy
    "ENERGY":         ["MCL", "CL"],
    # FX majors vs USD — tutti correlati al dollar index
    # 6E/6B/6A up = USD down (inverse correlation con 6J/6C che sono già inverted)
    # Per semplicità: blocca 2+ FX aperti contemporaneamente
    "FX_MAJORS":      ["6E", "6B", "6A", "6J", "6C"],
}

# ═══════════════════════════════════════════════════════════════
# 🧠 BRAIN ROUTING — whitelist TF e blacklist MR (V14-equivalent)
# ═══════════════════════════════════════════════════════════════
# Portate da V14 _route_to_brain (righe 2185, 2207) adattate ai futures.
# Usate da _choose_brain di APEX_PREDATOR_V15.py per decidere MR/TF/SKIP.

# Asset esclusi da Brain MR (storico negativo in mean reversion).
# V14: US30 aveva MR -$1,314 WR50% → solo TF. MYM è l'equivalente futures.
# MCL aggiunto per test 24/04: 2 stop consecutivi su trade MR anomali —
# escludere fino a ulteriore validazione. Rimuovere quando TF validerà.
MR_EXCLUDED = {
    "MYM",   # ≡ US30: V14 storico MR -$1,314 WR50% — solo TF
    # "MCL", # DECOMMENTARE dopo test MR validation. Rimuoviamo exclusion
           # per ora e lasciamo che la pre-validation hardcoded del BrainMR
           # blocchi i trade anomali (RSI non estremo).
}

# Asset ammessi per Brain TF (trend following).
# Asset non in lista → solo MR (se non in MR_EXCLUDED).
TF_ALLOWED_SYMBOLS = {
    # Indici (ottimi TF storici V14)
    "MES",    # ≡ US500: TF positivo storico V14
    "MNQ",    # ≡ US100: TF +$465 WR81% V14
    "MYM",    # ≡ US30:  TF +$708 WR67% V14
    # Forex major (TF storico positivo V14)
    "6E",     # ≡ EURUSD.r
    "6B",     # ≡ GBPUSD.r: TF +$664 WR50% V14
    "6C",     # ≡ USDCAD.r: TF +$711 WR63% V14
    # Forex minori (TF da validare)
    "6A",     # ≡ AUDUSD.r: non testato V14
    "6J",     # ≡ USDJPY.r: 1 solo trade V14
    # Commodities
    "MGC",    # ≡ XAUUSD.r: WR33% senza struct V14 — rivalutare
    "MCL",    # Petrolio, nuovo in V15
}

# Indici futures (trattamento speciale in _choose_brain: TF solo a favore trend H1)
INDICI_FUTURES = {"MES", "MNQ", "MYM", "YM"}

# ═══════════════════════════════════════════════════════════════
# 🚦 OPERATIONAL CYCLE
# ═══════════════════════════════════════════════════════════════
LOOP_SLEEP_SEC    = 15        # ciclo main (stesso di V14)
BIAS_SLEEP_AFTER  = 8         # pausa tra chiamate bias AI
BAR_HISTORY_DAYS  = 5         # quanti giorni di barre tenere in buffer
TIMEFRAMES        = ["5min", "1hour", "4hour"]  # TF che il Brain necessita

# ═══════════════════════════════════════════════════════════════
# 📝 LOGGING
# ═══════════════════════════════════════════════════════════════
LOG_DIR = os.path.dirname(os.path.abspath(__file__))

def log_path(filename):
    return os.path.join(LOG_DIR, filename)
