#!/usr/bin/env python3
"""
Analisi Correlazione Perdite <-> Cambi di Regime
=================================================
Questo script analizza se le perdite (stop loss) si concentrano
nei momenti di cambio regime di mercato.

Obiettivi:
1. Identificare tutti i cambi di regime (bullish/bearish/sideways)
2. Simulare la strategia dip-buyer
3. Correlare ogni perdita con:
   - Regime al momento dell'entry
   - Cambio regime durante il trade
   - Distanza temporale dal cambio regime
"""

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from pathlib import Path
import json
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Tuple
import warnings
warnings.filterwarnings('ignore')

# ============================================
# CONFIGURAZIONE
# ============================================
DATA_DIR = Path('/var/www/html/pippo.cuttalo.com/data')
OUTPUT_DIR = Path('/var/www/html/pippo.cuttalo.com/optimization_results')

# Fee Kraken
KRAKEN_MAKER_FEE = 0.0016
SPREAD_PCT = 0.0003

# Strategia migliore (Alpha_24h)
STRATEGY_CONFIG = {
    'dip_threshold': 0.08,    # 8% dip
    'profit_target': 0.15,    # 15% TP
    'stop_loss': 0.12,        # 12% SL
    'position_size': 1.0,
    'lookback_minutes': 1440,
}

# Timeframe per regime (4h = 240 minuti)
REGIME_TIMEFRAME_MINUTES = 240


@dataclass
class RegimeChange:
    """Singolo cambio di regime."""
    timestamp: datetime
    from_regime: str
    to_regime: str
    price_at_change: float
    ema12: float
    ema26: float
    spread_pct: float


@dataclass
class Trade:
    """Trade con info sul regime."""
    entry_time: datetime
    exit_time: Optional[datetime]
    entry_price: float
    exit_price: Optional[float]
    exit_reason: str
    net_pnl: float
    pnl_pct: float
    duration_minutes: int
    dip_at_entry: float
    # Info regime
    regime_at_entry: str
    regime_at_exit: str
    regime_changed_during_trade: bool
    regime_changes_during_trade: List[RegimeChange]
    minutes_since_last_regime_change: int
    regime_strength_at_entry: float


def load_data() -> pd.DataFrame:
    """Carica dati BTC EUR."""
    dfs = []
    for f in sorted(DATA_DIR.glob('prices_BTC_EUR_*.csv')):
        print(f"Loading {f.name}...")
        df = pd.read_csv(f)
        if df['timestamp'].dtype != 'object':
            if df['timestamp'].iloc[0] < 1e12:
                df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s')
            else:
                df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
        else:
            df['timestamp'] = pd.to_datetime(df['timestamp'])
        dfs.append(df)

    prices = pd.concat(dfs, ignore_index=True)
    prices = prices.sort_values('timestamp').drop_duplicates(subset='timestamp').reset_index(drop=True)
    return prices


def resample_to_4h(prices: pd.DataFrame) -> pd.DataFrame:
    """Resample a candele 4h per calcolo regime."""
    prices_indexed = prices.set_index('timestamp')

    resampled = prices_indexed.resample('4h').agg({
        'open': 'first',
        'high': 'max',
        'low': 'min',
        'close': 'last',
        'volume': 'sum'
    }).dropna()

    return resampled.reset_index()


def calculate_ema(prices: np.ndarray, period: int) -> np.ndarray:
    """Calcola EMA."""
    ema = np.zeros(len(prices))
    multiplier = 2 / (period + 1)

    # SMA iniziale
    ema[period-1] = np.mean(prices[:period])

    # EMA
    for i in range(period, len(prices)):
        ema[i] = (prices[i] - ema[i-1]) * multiplier + ema[i-1]

    return ema


def detect_regimes(prices_4h: pd.DataFrame) -> Tuple[pd.DataFrame, List[RegimeChange]]:
    """
    Rileva i regimi e i cambi di regime.
    Ritorna: (dataframe con regime per ogni candela, lista cambi regime)
    """
    closes = prices_4h['close'].values

    ema12 = calculate_ema(closes, 12)
    ema26 = calculate_ema(closes, 26)

    regimes = []
    regime_changes: List[RegimeChange] = []
    prev_regime = None

    for i in range(len(closes)):
        if i < 26:
            regimes.append({'regime': 'unknown', 'strength': 0, 'ema12': 0, 'ema26': 0, 'spread': 0})
            continue

        spread_pct = ((ema12[i] - ema26[i]) / ema26[i]) * 100

        # Momentum (6 candele = 24h su 4h tf)
        lookback = min(6, i)
        momentum = ((closes[i] - closes[i-lookback]) / closes[i-lookback]) * 100 if closes[i-lookback] > 0 else 0

        # Determina regime
        if spread_pct > 0.5 and closes[i] > ema12[i] and momentum > 1:
            regime = 'bullish'
            strength = min(100, (spread_pct * 20) + (momentum * 10))
        elif spread_pct < -0.5 and closes[i] < ema12[i] and momentum < -1:
            regime = 'bearish'
            strength = min(100, (abs(spread_pct) * 20) + (abs(momentum) * 10))
        elif spread_pct > 0.2 or (closes[i] > ema26[i] * 1.01 and momentum > 0.5):
            regime = 'bullish'
            strength = min(60, (spread_pct * 15) + (momentum * 8))
        elif spread_pct < -0.2 or (closes[i] < ema26[i] * 0.99 and momentum < -0.5):
            regime = 'bearish'
            strength = min(60, (abs(spread_pct) * 15) + (abs(momentum) * 8))
        else:
            regime = 'sideways'
            strength = max(0, 50 - abs(spread_pct) * 50 - abs(momentum) * 20)

        regimes.append({
            'regime': regime,
            'strength': strength,
            'ema12': ema12[i],
            'ema26': ema26[i],
            'spread': spread_pct
        })

        # Traccia cambio regime
        if prev_regime is not None and regime != prev_regime:
            regime_changes.append(RegimeChange(
                timestamp=prices_4h.iloc[i]['timestamp'],
                from_regime=prev_regime,
                to_regime=regime,
                price_at_change=closes[i],
                ema12=ema12[i],
                ema26=ema26[i],
                spread_pct=spread_pct
            ))

        prev_regime = regime

    regime_df = pd.DataFrame(regimes)
    prices_4h = prices_4h.copy()
    prices_4h['regime'] = regime_df['regime']
    prices_4h['regime_strength'] = regime_df['strength']
    prices_4h['ema12'] = regime_df['ema12']
    prices_4h['ema26'] = regime_df['ema26']
    prices_4h['spread_pct'] = regime_df['spread']

    return prices_4h, regime_changes


def get_regime_at_time(prices_4h: pd.DataFrame, timestamp: datetime) -> Tuple[str, float]:
    """Ottieni il regime a un determinato timestamp."""
    # Trova la candela 4h corrispondente
    mask = prices_4h['timestamp'] <= timestamp
    if not mask.any():
        return 'unknown', 0

    idx = mask.sum() - 1
    return prices_4h.iloc[idx]['regime'], prices_4h.iloc[idx]['regime_strength']


def get_regime_changes_in_period(
    regime_changes: List[RegimeChange],
    start: datetime,
    end: datetime
) -> List[RegimeChange]:
    """Trova i cambi di regime in un periodo."""
    return [rc for rc in regime_changes if start <= rc.timestamp <= end]


def get_minutes_since_last_regime_change(
    regime_changes: List[RegimeChange],
    timestamp: datetime
) -> int:
    """Minuti dall'ultimo cambio di regime."""
    past_changes = [rc for rc in regime_changes if rc.timestamp < timestamp]
    if not past_changes:
        return 999999  # Nessun cambio precedente

    last_change = max(past_changes, key=lambda x: x.timestamp)
    return int((timestamp - last_change.timestamp).total_seconds() / 60)


def run_backtest_with_regime(
    prices_1m: pd.DataFrame,
    prices_4h: pd.DataFrame,
    regime_changes: List[RegimeChange],
    config: Dict
) -> List[Trade]:
    """Esegue backtest tracciando info sul regime per ogni trade."""

    # Calcola 24h high
    prices_1m = prices_1m.copy()
    prices_1m['high_24h'] = prices_1m['high'].rolling(window=1440, min_periods=1).max()

    trades: List[Trade] = []
    in_position = False
    entry_price = 0
    entry_time = None
    entry_amount = 0
    entry_fee = 0
    capital = 5000.0  # Capitale iniziale

    start_idx = 1440  # Warmup 24h

    print(f"\nBacktest con tracking regime...")
    print(f"Periodo: {prices_1m.iloc[start_idx]['timestamp']} -> {prices_1m.iloc[-1]['timestamp']}")

    for i in range(start_idx, len(prices_1m)):
        row = prices_1m.iloc[i]
        timestamp = row['timestamp']
        current_price = row['close']
        candle_high = row['high']
        candle_low = row['low']
        high_24h = row['high_24h']

        dip_from_high = (current_price - high_24h) / high_24h if high_24h > 0 else 0

        # CHECK EXIT
        if in_position:
            stop_price = entry_price * (1 - config['stop_loss'])
            target_price = entry_price * (1 + config['profit_target'])

            # STOP LOSS
            if candle_low <= stop_price:
                exec_price = stop_price * (1 - SPREAD_PCT)
                fee = entry_amount * exec_price * KRAKEN_MAKER_FEE
                gross_pnl = entry_amount * (exec_price - entry_price)
                net_pnl = gross_pnl - fee - entry_fee
                pnl_pct = net_pnl / (entry_amount * entry_price)
                duration = int((timestamp - entry_time).total_seconds() / 60)

                # Info regime
                regime_at_entry, strength_at_entry = get_regime_at_time(prices_4h, entry_time)
                regime_at_exit, _ = get_regime_at_time(prices_4h, timestamp)
                changes_during = get_regime_changes_in_period(regime_changes, entry_time, timestamp)
                mins_since_change = get_minutes_since_last_regime_change(regime_changes, entry_time)

                trades.append(Trade(
                    entry_time=entry_time,
                    exit_time=timestamp,
                    entry_price=entry_price,
                    exit_price=exec_price,
                    exit_reason='stop_loss',
                    net_pnl=net_pnl,
                    pnl_pct=pnl_pct,
                    duration_minutes=duration,
                    dip_at_entry=dip_from_high,
                    regime_at_entry=regime_at_entry,
                    regime_at_exit=regime_at_exit,
                    regime_changed_during_trade=len(changes_during) > 0,
                    regime_changes_during_trade=changes_during,
                    minutes_since_last_regime_change=mins_since_change,
                    regime_strength_at_entry=strength_at_entry
                ))

                capital += (entry_amount * entry_price) + net_pnl
                in_position = False
                continue

            # TAKE PROFIT
            if candle_high >= target_price:
                exec_price = target_price * (1 - SPREAD_PCT)
                fee = entry_amount * exec_price * KRAKEN_MAKER_FEE
                gross_pnl = entry_amount * (exec_price - entry_price)
                net_pnl = gross_pnl - fee - entry_fee
                pnl_pct = net_pnl / (entry_amount * entry_price)
                duration = int((timestamp - entry_time).total_seconds() / 60)

                regime_at_entry, strength_at_entry = get_regime_at_time(prices_4h, entry_time)
                regime_at_exit, _ = get_regime_at_time(prices_4h, timestamp)
                changes_during = get_regime_changes_in_period(regime_changes, entry_time, timestamp)
                mins_since_change = get_minutes_since_last_regime_change(regime_changes, entry_time)

                trades.append(Trade(
                    entry_time=entry_time,
                    exit_time=timestamp,
                    entry_price=entry_price,
                    exit_price=exec_price,
                    exit_reason='take_profit',
                    net_pnl=net_pnl,
                    pnl_pct=pnl_pct,
                    duration_minutes=duration,
                    dip_at_entry=dip_from_high,
                    regime_at_entry=regime_at_entry,
                    regime_at_exit=regime_at_exit,
                    regime_changed_during_trade=len(changes_during) > 0,
                    regime_changes_during_trade=changes_during,
                    minutes_since_last_regime_change=mins_since_change,
                    regime_strength_at_entry=strength_at_entry
                ))

                capital += (entry_amount * entry_price) + net_pnl
                in_position = False
                continue

        # CHECK ENTRY
        else:
            if dip_from_high <= -config['dip_threshold']:
                trade_value = capital * config['position_size']
                if trade_value > 10:
                    exec_price = current_price * (1 + SPREAD_PCT)
                    fee = trade_value * KRAKEN_MAKER_FEE
                    amount = (trade_value - fee) / exec_price

                    in_position = True
                    entry_price = exec_price
                    entry_time = timestamp
                    entry_amount = amount
                    entry_fee = fee
                    capital -= trade_value

    return trades


def analyze_results(trades: List[Trade], regime_changes: List[RegimeChange]) -> Dict:
    """Analizza i risultati e genera statistiche."""

    if not trades:
        return {'error': 'Nessun trade'}

    # Separazione vincenti/perdenti
    wins = [t for t in trades if t.net_pnl > 0]
    losses = [t for t in trades if t.net_pnl <= 0]

    # ===== ANALISI 1: Perdite vs Cambi Regime =====

    # Perdite con cambio regime durante il trade
    losses_with_regime_change = [t for t in losses if t.regime_changed_during_trade]
    losses_without_regime_change = [t for t in losses if not t.regime_changed_during_trade]

    # Vincite con cambio regime durante il trade
    wins_with_regime_change = [t for t in wins if t.regime_changed_during_trade]
    wins_without_regime_change = [t for t in wins if not t.regime_changed_during_trade]

    # ===== ANALISI 2: Performance per Regime di Entry =====

    trades_by_entry_regime = {
        'bullish': [t for t in trades if t.regime_at_entry == 'bullish'],
        'bearish': [t for t in trades if t.regime_at_entry == 'bearish'],
        'sideways': [t for t in trades if t.regime_at_entry == 'sideways'],
    }

    # ===== ANALISI 3: Transizioni di Regime =====

    transition_stats = {}
    for t in losses:
        if t.regime_changes_during_trade:
            for rc in t.regime_changes_during_trade:
                key = f"{rc.from_regime}->{rc.to_regime}"
                if key not in transition_stats:
                    transition_stats[key] = {'losses': 0, 'total_loss': 0, 'wins': 0, 'total_win': 0}
                transition_stats[key]['losses'] += 1
                transition_stats[key]['total_loss'] += abs(t.net_pnl)

    for t in wins:
        if t.regime_changes_during_trade:
            for rc in t.regime_changes_during_trade:
                key = f"{rc.from_regime}->{rc.to_regime}"
                if key not in transition_stats:
                    transition_stats[key] = {'losses': 0, 'total_loss': 0, 'wins': 0, 'total_win': 0}
                transition_stats[key]['wins'] += 1
                transition_stats[key]['total_win'] += t.net_pnl

    # ===== ANALISI 4: Tempo dall'ultimo cambio regime =====

    # Bucket: 0-1h, 1-4h, 4-12h, 12-24h, 24h+
    time_buckets = {
        '0-1h': {'wins': [], 'losses': []},
        '1-4h': {'wins': [], 'losses': []},
        '4-12h': {'wins': [], 'losses': []},
        '12-24h': {'wins': [], 'losses': []},
        '24h+': {'wins': [], 'losses': []},
    }

    for t in trades:
        mins = t.minutes_since_last_regime_change
        if mins < 60:
            bucket = '0-1h'
        elif mins < 240:
            bucket = '1-4h'
        elif mins < 720:
            bucket = '4-12h'
        elif mins < 1440:
            bucket = '12-24h'
        else:
            bucket = '24h+'

        if t.net_pnl > 0:
            time_buckets[bucket]['wins'].append(t)
        else:
            time_buckets[bucket]['losses'].append(t)

    # ===== ANALISI 5: Strength del regime all'entry =====

    # Bucket strength: 0-30 (weak), 30-60 (moderate), 60+ (strong)
    strength_buckets = {
        'weak (0-30)': {'wins': [], 'losses': []},
        'moderate (30-60)': {'wins': [], 'losses': []},
        'strong (60+)': {'wins': [], 'losses': []},
    }

    for t in trades:
        strength = t.regime_strength_at_entry
        if strength < 30:
            bucket = 'weak (0-30)'
        elif strength < 60:
            bucket = 'moderate (30-60)'
        else:
            bucket = 'strong (60+)'

        if t.net_pnl > 0:
            strength_buckets[bucket]['wins'].append(t)
        else:
            strength_buckets[bucket]['losses'].append(t)

    # ===== COMPILAZIONE RISULTATI =====

    results = {
        'summary': {
            'total_trades': len(trades),
            'wins': len(wins),
            'losses': len(losses),
            'win_rate': len(wins) / len(trades) * 100 if trades else 0,
            'total_pnl': sum(t.net_pnl for t in trades),
            'avg_win': np.mean([t.net_pnl for t in wins]) if wins else 0,
            'avg_loss': np.mean([t.net_pnl for t in losses]) if losses else 0,
        },

        'regime_changes': {
            'total_regime_changes': len(regime_changes),
            'losses_WITH_regime_change': len(losses_with_regime_change),
            'losses_WITHOUT_regime_change': len(losses_without_regime_change),
            'wins_WITH_regime_change': len(wins_with_regime_change),
            'wins_WITHOUT_regime_change': len(wins_without_regime_change),
            'pct_losses_with_change': len(losses_with_regime_change) / len(losses) * 100 if losses else 0,
            'pct_wins_with_change': len(wins_with_regime_change) / len(wins) * 100 if wins else 0,
            'avg_loss_with_change': np.mean([abs(t.net_pnl) for t in losses_with_regime_change]) if losses_with_regime_change else 0,
            'avg_loss_without_change': np.mean([abs(t.net_pnl) for t in losses_without_regime_change]) if losses_without_regime_change else 0,
        },

        'by_entry_regime': {},

        'transitions': transition_stats,

        'time_since_change': {},

        'regime_strength': {},

        'detailed_losses': [],
    }

    # By entry regime
    for regime, t_list in trades_by_entry_regime.items():
        if t_list:
            w = [t for t in t_list if t.net_pnl > 0]
            l = [t for t in t_list if t.net_pnl <= 0]
            results['by_entry_regime'][regime] = {
                'total': len(t_list),
                'wins': len(w),
                'losses': len(l),
                'win_rate': len(w) / len(t_list) * 100,
                'total_pnl': sum(t.net_pnl for t in t_list),
                'avg_pnl': np.mean([t.net_pnl for t in t_list]),
            }

    # Time since change
    for bucket, data in time_buckets.items():
        total = len(data['wins']) + len(data['losses'])
        if total > 0:
            results['time_since_change'][bucket] = {
                'total': total,
                'wins': len(data['wins']),
                'losses': len(data['losses']),
                'win_rate': len(data['wins']) / total * 100,
                'total_pnl': sum(t.net_pnl for t in data['wins']) + sum(t.net_pnl for t in data['losses']),
            }

    # Strength
    for bucket, data in strength_buckets.items():
        total = len(data['wins']) + len(data['losses'])
        if total > 0:
            results['regime_strength'][bucket] = {
                'total': total,
                'wins': len(data['wins']),
                'losses': len(data['losses']),
                'win_rate': len(data['wins']) / total * 100,
            }

    # Detailed losses (top 10 by magnitude)
    sorted_losses = sorted(losses, key=lambda x: x.net_pnl)[:10]
    for t in sorted_losses:
        results['detailed_losses'].append({
            'entry_time': t.entry_time.isoformat(),
            'exit_time': t.exit_time.isoformat() if t.exit_time else None,
            'entry_price': round(t.entry_price, 2),
            'exit_price': round(t.exit_price, 2) if t.exit_price else None,
            'net_pnl': round(t.net_pnl, 2),
            'pnl_pct': round(t.pnl_pct * 100, 2),
            'duration_hours': round(t.duration_minutes / 60, 1),
            'regime_at_entry': t.regime_at_entry,
            'regime_at_exit': t.regime_at_exit,
            'regime_changed': t.regime_changed_during_trade,
            'num_regime_changes': len(t.regime_changes_during_trade),
            'changes': [f"{rc.from_regime}->{rc.to_regime}" for rc in t.regime_changes_during_trade],
            'mins_since_last_change': t.minutes_since_last_regime_change,
            'regime_strength': round(t.regime_strength_at_entry, 1),
        })

    return results


def print_report(results: Dict):
    """Stampa report dettagliato."""

    print("\n" + "="*80)
    print("ANALISI CORRELAZIONE PERDITE <-> CAMBI DI REGIME")
    print("="*80)

    s = results['summary']
    print(f"\n--- SOMMARIO ---")
    print(f"Trade totali:     {s['total_trades']:>6}")
    print(f"Vincenti:         {s['wins']:>6} ({s['win_rate']:.1f}%)")
    print(f"Perdenti:         {s['losses']:>6}")
    print(f"P&L Totale:       {s['total_pnl']:>+10.2f}")
    print(f"Media vincita:    {s['avg_win']:>+10.2f}")
    print(f"Media perdita:    {s['avg_loss']:>+10.2f}")

    rc = results['regime_changes']
    print(f"\n--- CORRELAZIONE CAMBI REGIME ---")
    print(f"Cambi regime nel periodo:  {rc['total_regime_changes']}")
    print(f"\nPERDITE:")
    print(f"  Con cambio regime:       {rc['losses_WITH_regime_change']:>4} ({rc['pct_losses_with_change']:.1f}%)")
    print(f"  Senza cambio regime:     {rc['losses_WITHOUT_regime_change']:>4} ({100-rc['pct_losses_with_change']:.1f}%)")
    print(f"  Media perdita CON cambio:    {rc['avg_loss_with_change']:>+10.2f}")
    print(f"  Media perdita SENZA cambio:  {rc['avg_loss_without_change']:>+10.2f}")
    print(f"\nVINCITE:")
    print(f"  Con cambio regime:       {rc['wins_WITH_regime_change']:>4} ({rc['pct_wins_with_change']:.1f}%)")
    print(f"  Senza cambio regime:     {rc['wins_WITHOUT_regime_change']:>4}")

    print(f"\n--- PERFORMANCE PER REGIME DI ENTRY ---")
    for regime, data in results['by_entry_regime'].items():
        emoji = "" if regime == "bullish" else "" if regime == "bearish" else ""
        print(f"  {emoji} {regime.upper():>10}:  {data['total']:>3} trade | Win: {data['win_rate']:>5.1f}% | P&L: {data['total_pnl']:>+10.2f}")

    print(f"\n--- TRANSIZIONI REGIME (durante trade) ---")
    for transition, data in sorted(results['transitions'].items(), key=lambda x: x[1]['losses'], reverse=True):
        total = data['losses'] + data['wins']
        if total > 0:
            loss_pct = data['losses'] / total * 100
            print(f"  {transition:>20}:  Losses: {data['losses']:>2} | Wins: {data['wins']:>2} | Loss rate: {loss_pct:>5.1f}%")

    print(f"\n--- TEMPO DALL'ULTIMO CAMBIO REGIME ---")
    print(f"  {'Periodo':<12} {'Trade':>6} {'Win':>6} {'Loss':>6} {'WinRate':>8} {'P&L':>12}")
    print(f"  {'-'*52}")
    for bucket, data in results['time_since_change'].items():
        print(f"  {bucket:<12} {data['total']:>6} {data['wins']:>6} {data['losses']:>6} {data['win_rate']:>7.1f}% {data['total_pnl']:>+11.2f}")

    print(f"\n--- FORZA DEL REGIME ALL'ENTRY ---")
    for bucket, data in results['regime_strength'].items():
        print(f"  {bucket:<20}:  {data['total']:>3} trade | Win: {data['win_rate']:>5.1f}%")

    print(f"\n--- TOP 10 PERDITE PEGGIORI (dettaglio) ---")
    for i, loss in enumerate(results['detailed_losses'], 1):
        print(f"\n  #{i} | {loss['entry_time'][:16]}")
        print(f"      Prezzo: {loss['entry_price']:,.0f} -> {loss['exit_price']:,.0f}")
        print(f"      P&L: {loss['net_pnl']:+.2f} ({loss['pnl_pct']:+.1f}%)")
        print(f"      Durata: {loss['duration_hours']:.1f}h")
        print(f"      Regime: {loss['regime_at_entry']} -> {loss['regime_at_exit']}")
        print(f"      Cambio durante trade: {'SI' if loss['regime_changed'] else 'NO'} ({loss['num_regime_changes']} cambi)")
        if loss['changes']:
            print(f"      Transizioni: {', '.join(loss['changes'])}")
        print(f"      Min dall'ultimo cambio: {loss['mins_since_last_change']} ({loss['mins_since_last_change']/60:.1f}h)")
        print(f"      Forza regime entry: {loss['regime_strength']}")


def main():
    print("="*80)
    print("ANALISI CORRELAZIONE PERDITE <-> CAMBI DI REGIME")
    print("="*80)

    # 1. Carica dati
    print("\n1. Caricamento dati...")
    prices_1m = load_data()
    print(f"   Candele 1m: {len(prices_1m):,}")
    print(f"   Periodo: {prices_1m['timestamp'].min()} -> {prices_1m['timestamp'].max()}")

    # 2. Resample a 4h per regime
    print("\n2. Resample a 4h per calcolo regime...")
    prices_4h = resample_to_4h(prices_1m)
    print(f"   Candele 4h: {len(prices_4h):,}")

    # 3. Rileva regimi
    print("\n3. Rilevamento regimi e transizioni...")
    prices_4h, regime_changes = detect_regimes(prices_4h)
    print(f"   Cambi regime trovati: {len(regime_changes)}")

    # Breakdown cambi
    change_types = {}
    for rc in regime_changes:
        key = f"{rc.from_regime}->{rc.to_regime}"
        change_types[key] = change_types.get(key, 0) + 1

    print(f"   Breakdown:")
    for k, v in sorted(change_types.items(), key=lambda x: x[1], reverse=True):
        print(f"     {k}: {v}")

    # 4. Backtest con tracking regime
    print("\n4. Backtest con tracking regime...")
    trades = run_backtest_with_regime(prices_1m, prices_4h, regime_changes, STRATEGY_CONFIG)
    print(f"   Trade eseguiti: {len(trades)}")

    # 5. Analisi risultati
    print("\n5. Analisi correlazione...")
    results = analyze_results(trades, regime_changes)

    # 6. Stampa report
    print_report(results)

    # 7. Salva risultati
    output_path = OUTPUT_DIR / 'regime_loss_analysis.json'

    # Converti per JSON
    output = {
        'timestamp': datetime.now().isoformat(),
        'strategy_config': STRATEGY_CONFIG,
        'data_period': f"{prices_1m['timestamp'].min()} to {prices_1m['timestamp'].max()}",
        'total_1m_candles': len(prices_1m),
        'total_4h_candles': len(prices_4h),
        'regime_changes_count': len(regime_changes),
        'results': {
            k: v for k, v in results.items() if k != 'detailed_losses'
        },
        'detailed_losses': results['detailed_losses'],
    }

    with open(output_path, 'w') as f:
        json.dump(output, f, indent=2, default=str)

    print(f"\n\nRisultati salvati in: {output_path}")

    # 8. Conclusioni
    rc = results['regime_changes']
    print("\n" + "="*80)
    print("CONCLUSIONI")
    print("="*80)

    if rc['pct_losses_with_change'] > 50:
        print(f"\n LA MAGGIORANZA delle perdite ({rc['pct_losses_with_change']:.0f}%) avviene")
        print(f"   durante un CAMBIO DI REGIME.")
        print(f"   Questo conferma l'ipotesi che i cambi di regime sono pericolosi.")
    else:
        print(f"\n Solo {rc['pct_losses_with_change']:.0f}% delle perdite avviene durante cambi di regime.")
        print(f"   Le perdite sembrano piu legate ad altri fattori.")

    if rc['avg_loss_with_change'] > rc['avg_loss_without_change']:
        pct_bigger = (rc['avg_loss_with_change'] / rc['avg_loss_without_change'] - 1) * 100
        print(f"\n Le perdite DURANTE i cambi regime sono {pct_bigger:.0f}% PIU GRANDI")
        print(f"   rispetto alle perdite in regime stabile.")

    # Best entry regime
    best_regime = max(results['by_entry_regime'].items(), key=lambda x: x[1]['win_rate'])
    worst_regime = min(results['by_entry_regime'].items(), key=lambda x: x[1]['win_rate'])
    print(f"\n MIGLIOR regime per entrare: {best_regime[0].upper()} ({best_regime[1]['win_rate']:.0f}% win rate)")
    print(f"   PEGGIOR regime per entrare: {worst_regime[0].upper()} ({worst_regime[1]['win_rate']:.0f}% win rate)")

    # Best timing
    if results['time_since_change']:
        best_timing = max(results['time_since_change'].items(), key=lambda x: x[1]['win_rate'])
        worst_timing = min(results['time_since_change'].items(), key=lambda x: x[1]['win_rate'])
        print(f"\n MIGLIOR timing post-cambio: {best_timing[0]} ({best_timing[1]['win_rate']:.0f}% win rate)")
        print(f"   PEGGIOR timing post-cambio: {worst_timing[0]} ({worst_timing[1]['win_rate']:.0f}% win rate)")


if __name__ == '__main__':
    main()
