#!/usr/bin/env python3
"""
COMPARAISON: TP/SL Fixe vs Trailing Stop Dynamique

Test quelle approche capture le plus de profit:
- Système A: TP/SL fixe (actuel)
- Système B: Trailing stop en % du PnL max
"""

import pandas as pd
import numpy as np
from datetime import datetime
import logging

logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)


class BacktestComparison:
    """Compare TP fixe vs Trailing stop"""

    def __init__(self, initial_capital: float = 500.0):
        self.initial_capital = initial_capital

    def run_fixed_tp(self, df: pd.DataFrame, signal_dict: dict, leverage: int = 150) -> dict:
        """Backtest avec TP/SL FIXE (système actuel)"""

        entry_price = signal_dict['entry_price']
        side = signal_dict['side']
        tp = signal_dict['take_profit']
        sl = signal_dict['stop_loss']

        # Trouver où signal se déclenche
        entry_idx = df[df['close'] >= entry_price].index[0] if side == 'LONG' else df[df['close'] <= entry_price].index[0]

        # Chercher exit (TP ou SL)
        for i in range(entry_idx + 1, len(df)):
            price = df.iloc[i]['close']

            if side == 'LONG':
                if price >= tp:
                    # TP touché
                    pnl_pct = (tp - entry_price) / entry_price * leverage * 100
                    return {
                        'exit_price': tp,
                        'exit_reason': 'TP',
                        'pnl_pct': pnl_pct,
                        'bars_held': i - entry_idx
                    }
                elif price <= sl:
                    # SL touché
                    pnl_pct = (sl - entry_price) / entry_price * leverage * 100
                    return {
                        'exit_price': sl,
                        'exit_reason': 'SL',
                        'pnl_pct': pnl_pct,
                        'bars_held': i - entry_idx
                    }
            else:  # SHORT
                if price <= tp:
                    pnl_pct = (entry_price - tp) / entry_price * leverage * 100
                    return {
                        'exit_price': tp,
                        'exit_reason': 'TP',
                        'pnl_pct': pnl_pct,
                        'bars_held': i - entry_idx
                    }
                elif price >= sl:
                    pnl_pct = (entry_price - sl) / entry_price * leverage * 100
                    return {
                        'exit_price': sl,
                        'exit_reason': 'SL',
                        'pnl_pct': pnl_pct,
                        'bars_held': i - entry_idx
                    }

        # Pas d'exit trouvé
        return None

    def run_trailing_stop(self, df: pd.DataFrame, signal_dict: dict, leverage: int = 150,
                         trailing_pct: float = 0.15) -> dict:
        """Backtest avec TRAILING STOP (% du PnL max)

        Args:
            trailing_pct: % de retrait du PnL max avant exit (ex: 0.15 = 15%)
        """

        entry_price = signal_dict['entry_price']
        side = signal_dict['side']
        sl = signal_dict['stop_loss']  # Garde SL initial pour limiter pertes

        # Trouver entry
        entry_idx = df[df['close'] >= entry_price].index[0] if side == 'LONG' else df[df['close'] <= entry_price].index[0]

        # Tracking
        max_pnl_pct = 0.0
        trailing_stop_price = None

        for i in range(entry_idx + 1, len(df)):
            price = df.iloc[i]['close']

            # Calculer PnL actuel
            if side == 'LONG':
                pnl_pct = (price - entry_price) / entry_price
            else:
                pnl_pct = (entry_price - price) / entry_price

            # Check SL initial (protection pertes)
            if side == 'LONG' and price <= sl:
                pnl_leveraged = (sl - entry_price) / entry_price * leverage * 100
                return {
                    'exit_price': sl,
                    'exit_reason': 'INITIAL_SL',
                    'pnl_pct': pnl_leveraged,
                    'max_pnl_pct': max_pnl_pct * leverage * 100,
                    'bars_held': i - entry_idx
                }
            elif side == 'SHORT' and price >= sl:
                pnl_leveraged = (entry_price - sl) / entry_price * leverage * 100
                return {
                    'exit_price': sl,
                    'exit_reason': 'INITIAL_SL',
                    'pnl_pct': pnl_leveraged,
                    'max_pnl_pct': max_pnl_pct * leverage * 100,
                    'bars_held': i - entry_idx
                }

            # Update max PnL
            if pnl_pct > max_pnl_pct:
                max_pnl_pct = pnl_pct

                # Activer trailing stop seulement si en profit
                if max_pnl_pct > 0:
                    # Trailing stop = prix qui donne (max_pnl * (1 - trailing_pct))
                    target_pnl = max_pnl_pct * (1 - trailing_pct)

                    if side == 'LONG':
                        trailing_stop_price = entry_price * (1 + target_pnl)
                    else:
                        trailing_stop_price = entry_price * (1 - target_pnl)

            # Check trailing stop
            if trailing_stop_price is not None:
                if side == 'LONG' and price <= trailing_stop_price:
                    # Trailing stop touché
                    pnl_leveraged = (trailing_stop_price - entry_price) / entry_price * leverage * 100
                    return {
                        'exit_price': trailing_stop_price,
                        'exit_reason': 'TRAILING_STOP',
                        'pnl_pct': pnl_leveraged,
                        'max_pnl_pct': max_pnl_pct * leverage * 100,
                        'bars_held': i - entry_idx
                    }
                elif side == 'SHORT' and price >= trailing_stop_price:
                    pnl_leveraged = (entry_price - trailing_stop_price) / entry_price * leverage * 100
                    return {
                        'exit_price': trailing_stop_price,
                        'exit_reason': 'TRAILING_STOP',
                        'pnl_pct': pnl_leveraged,
                        'max_pnl_pct': max_pnl_pct * leverage * 100,
                        'bars_held': i - entry_idx
                    }

        return None

    def compare_systems(self, df: pd.DataFrame, signals: list):
        """Compare les 2 systèmes sur une série de signaux"""

        print("="*80)
        print("🧪 COMPARAISON: TP FIXE vs TRAILING STOP")
        print("="*80)
        print(f"Signaux à tester: {len(signals)}")
        print(f"Données: {len(df)} bougies")
        print(f"{'='*80}\n")

        # Tester différents trailing %
        trailing_pcts = [0.10, 0.15, 0.20, 0.25, 0.30]

        results = {
            'fixed_tp': {'trades': [], 'total_pnl': 0, 'wins': 0, 'losses': 0},
        }

        for pct in trailing_pcts:
            results[f'trailing_{int(pct*100)}pct'] = {
                'trades': [], 'total_pnl': 0, 'wins': 0, 'losses': 0
            }

        # Tester chaque signal
        for signal in signals:
            # Système A: TP fixe
            result_fixed = self.run_fixed_tp(df, signal)
            if result_fixed:
                results['fixed_tp']['trades'].append(result_fixed)
                results['fixed_tp']['total_pnl'] += result_fixed['pnl_pct']
                if result_fixed['pnl_pct'] > 0:
                    results['fixed_tp']['wins'] += 1
                else:
                    results['fixed_tp']['losses'] += 1

            # Système B: Trailing stops (différents %)
            for pct in trailing_pcts:
                result_trailing = self.run_trailing_stop(df, signal, trailing_pct=pct)
                if result_trailing:
                    key = f'trailing_{int(pct*100)}pct'
                    results[key]['trades'].append(result_trailing)
                    results[key]['total_pnl'] += result_trailing['pnl_pct']
                    if result_trailing['pnl_pct'] > 0:
                        results[key]['wins'] += 1
                    else:
                        results[key]['losses'] += 1

        # Afficher résultats
        self._print_comparison(results)

        return results

    def _print_comparison(self, results: dict):
        """Affiche la comparaison"""

        print("\n" + "="*80)
        print("📊 RÉSULTATS COMPARATIFS")
        print("="*80)

        # Trier par PnL total
        sorted_systems = sorted(results.items(), key=lambda x: x[1]['total_pnl'], reverse=True)

        print(f"\n{'Système':<25} {'Trades':<8} {'Win%':<8} {'PnL Total':<12} {'PnL Moy':<12}")
        print("-" * 80)

        for system_name, data in sorted_systems:
            if not data['trades']:
                continue

            total_trades = len(data['trades'])
            win_rate = (data['wins'] / total_trades * 100) if total_trades > 0 else 0
            avg_pnl = data['total_pnl'] / total_trades if total_trades > 0 else 0

            # Format nom
            if system_name == 'fixed_tp':
                display_name = "TP/SL Fixe (actuel)"
            else:
                pct = system_name.split('_')[1]
                display_name = f"Trailing Stop {pct}"

            # Marqueur gagnant
            marker = "🏆 " if system_name == sorted_systems[0][0] else "   "

            print(f"{marker}{display_name:<22} {total_trades:<8} {win_rate:<7.1f}% "
                  f"{data['total_pnl']:<+11.2f}% {avg_pnl:<+11.2f}%")

        # Détails best vs worst
        best = sorted_systems[0]
        worst = sorted_systems[-1]

        improvement = best[1]['total_pnl'] - worst[1]['total_pnl']

        print("\n" + "="*80)
        print(f"🎯 MEILLEUR SYSTÈME: {best[0]}")
        print(f"   PnL total: {best[1]['total_pnl']:+.2f}%")
        print(f"   Amélioration vs pire: {improvement:+.2f}%")
        print("="*80)


if __name__ == '__main__':
    # Charger données
    df = pd.read_csv('historical_data/BTCUSDT_5m_9000candles.csv')
    df['timestamp'] = pd.to_datetime(df['timestamp'])

    print("📊 Chargement données...")
    print(f"   Période: {df['timestamp'].iloc[0]} → {df['timestamp'].iloc[-1]}")
    print(f"   Bougies: {len(df):,}\n")

    # Signaux de test (exemple - à remplacer par vrais signaux V10)
    # Pour ce test, on va générer quelques signaux fictifs
    test_signals = [
        {
            'entry_price': 110000,
            'side': 'SHORT',
            'take_profit': 108000,  # TP à -1.8%
            'stop_loss': 111200,    # SL à +1.1%
        },
        {
            'entry_price': 120000,
            'side': 'LONG',
            'take_profit': 122400,  # TP à +2%
            'stop_loss': 118800,    # SL à -1%
        },
    ]

    comparator = BacktestComparison(initial_capital=500)
    results = comparator.compare_systems(df, test_signals)
