#!/usr/bin/env python3
"""
SYSTÈME OPTIMISÉ V2 - Basé sur analyse des trades

Optimisations appliquées:
1. ✅ LONG bias détecté (78.6% vs 47.1%) → Filtrer SHORT strictement
2. ✅ 2.5 confirmations optimal (63% WR) → Seuil à 2.5
3. ✅ SL trop large (-43% avg) → Resserrer SL
4. ✅ Leverage 30-40x performant → Privilégier ce range
"""

import pandas as pd
import numpy as np
from martingale_backtester import MartingaleBacktester
import json

class OptimizedSystemV2:
    """Système optimisé basé sur data-driven insights"""

    def __init__(self, initial_capital=1000):
        self.capital = initial_capital
        self.initial_capital = initial_capital
        self.position = None
        self.trades = []
        self.consecutive_losses = 0

    def detect_market_regime(self, df, i):
        """Market regime avec filtres renforcés"""

        if i < 100:
            return None

        recent = df.iloc[i-100:i]

        # 1. TREND
        ma50 = recent['close'].tail(50).mean()
        ma20 = recent['close'].tail(20).mean()
        current_price = df.iloc[i]['close']

        trend_strength = (ma20 - ma50) / ma50 if ma50 > 0 else 0

        # FILTRE: Skip strong downtrends
        if trend_strength < -0.05:
            return None

        # Classify
        if ma20 > ma50 * 1.02:
            trend = 'UPTREND'
        elif ma20 < ma50 * 0.98:
            trend = 'DOWNTREND'
        else:
            trend = 'RANGING'

        # 2. VOLATILITY
        returns = recent['close'].pct_change()
        volatility = returns.std()

        # 3. ATR
        high_low = recent['high'] - recent['low']
        atr = high_low.mean()
        atr_pct = (atr / recent['close'].mean()) * 100

        # 4. VOLUME
        vol_ma = recent['volume'].mean()
        current_vol = df.iloc[i]['volume']
        volume_ratio = current_vol / vol_ma if vol_ma > 0 else 1

        return {
            'trend': trend,
            'trend_strength': trend_strength,
            'volatility': volatility,
            'atr': atr,
            'atr_pct': atr_pct,
            'volume_ratio': volume_ratio,
            'tradeable': True
        }

    def calculate_adaptive_params(self, regime):
        """Paramètres adaptatifs OPTIMISÉS"""

        # LEVERAGE: Privilégier 30-40x (meilleur WR)
        if regime['atr_pct'] > 2.0:
            base_leverage = 15  # Très volatile
        elif regime['atr_pct'] > 1.0:
            base_leverage = 25
        elif regime['atr_pct'] > 0.5:
            base_leverage = 35  # Sweet spot 30-40x
        else:
            base_leverage = 40

        # Adjust for volume
        if regime['volume_ratio'] > 2.0:
            leverage = int(base_leverage * 1.2)
        elif regime['volume_ratio'] < 0.5:
            leverage = int(base_leverage * 0.8)
        else:
            leverage = base_leverage

        leverage = min(max(leverage, 25), 45)  # Range 25-45x

        # TP/SL: RESSERRÉ (SL était trop large à -43%)
        tp_pct = regime['atr_pct'] * 2.0
        sl_pct = regime['atr_pct'] * 0.75  # RÉDUIT de 1.0 à 0.75

        # Limites
        tp_pct = max(0.8, min(tp_pct, 4.0))
        sl_pct = max(0.4, min(sl_pct, 2.0))  # Max SL 2% (vs 3% avant)

        # POSITION SIZE
        if self.consecutive_losses >= 2:
            risk_pct = 0.01
        else:
            risk_pct = 0.02

        risk_amount = self.capital * risk_pct
        position_size = risk_amount / (sl_pct/100 * leverage)
        position_size = min(position_size, self.capital * 0.3)

        return {
            'leverage': leverage,
            'tp_pct': tp_pct,
            'sl_pct': sl_pct,
            'position_size': position_size
        }

    def detect_entry_signal(self, df, i, regime):
        """Signaux avec SEUIL 2.5+ confirmations ET LONG BIAS"""

        current = df.iloc[i]
        recent = df.iloc[max(0, i-50):i]

        confirmations = 0
        side = None

        # SIGNAL 1: Volatility Expansion (OBLIGATOIRE)
        current_range = current['high'] - current['low']
        avg_range = (recent['high'] - recent['low']).mean()

        if current_range <= avg_range * 1.5:
            return None

        # Direction
        is_bullish = current['close'] > current['open']

        # SIGNAL 2: Trend alignment
        if regime['trend'] == 'UPTREND' and is_bullish:
            side = 'LONG'
            confirmations += 1
        elif regime['trend'] == 'DOWNTREND' and not is_bullish:
            side = 'SHORT'
            confirmations += 1
        elif regime['trend'] == 'RANGING':
            side = 'LONG' if is_bullish else 'SHORT'
            confirmations += 0.5

        # SIGNAL 3: Volume
        if regime['volume_ratio'] > 1.5:
            confirmations += 1

        # SIGNAL 4: Momentum
        ma20 = recent['close'].tail(20).mean()
        if is_bullish and current['close'] > ma20 * 1.01:
            confirmations += 1
        elif not is_bullish and current['close'] < ma20 * 0.99:
            confirmations += 1

        # OPTIMISATION: Seuil à 2.5 confirmations (vs 2.0)
        if confirmations < 2.5:
            return None

        # OPTIMISATION: LONG BIAS - Filtrer SHORT faible
        if side == 'SHORT':
            # SHORT nécessite UPTREND inverse OU plus de confirmations
            if regime['trend'] != 'DOWNTREND' and confirmations < 3.0:
                return None  # Skip SHORT faible

        return {
            'side': side,
            'confirmations': confirmations,
            'confidence': min(confirmations / 4.0, 1.0)
        }

    def should_exit(self, df, i, position, params):
        """Exit avec SL RESSERRÉ"""

        current = df.iloc[i]

        # TP/SL
        if position['side'] == 'LONG':
            tp = position['entry'] * (1 + params['tp_pct']/100)
            sl = position['entry'] * (1 - params['sl_pct']/100)

            if current['close'] >= tp:
                return True, 'TP'
            if current['close'] <= sl:
                return True, 'SL'

            # Trailing stop
            profit = (current['close'] - position['entry']) / position['entry']
            if profit > (params['tp_pct']/100) * 0.5:
                trailing = position['entry'] + (current['close'] - position['entry']) * 0.75  # Plus serré
                if current['close'] < trailing:
                    return True, 'TRAILING'

        else:  # SHORT
            tp = position['entry'] * (1 - params['tp_pct']/100)
            sl = position['entry'] * (1 + params['sl_pct']/100)

            if current['close'] <= tp:
                return True, 'TP'
            if current['close'] >= sl:
                return True, 'SL'

            profit = (position['entry'] - current['close']) / position['entry']
            if profit > (params['tp_pct']/100) * 0.5:
                trailing = position['entry'] - (position['entry'] - current['close']) * 0.75
                if current['close'] > trailing:
                    return True, 'TRAILING'

        return False, None

    def close_trade(self, exit_price, exit_type):
        """Close trade"""

        if not self.position:
            return

        params = self.position['params']

        # PnL
        if self.position['side'] == 'LONG':
            pnl_pct = (exit_price - self.position['entry']) / self.position['entry']
        else:
            pnl_pct = (self.position['entry'] - exit_price) / self.position['entry']

        pnl_pct *= params['leverage']
        pnl_pct -= 0.001

        pnl_usd = params['position_size'] * pnl_pct
        self.capital += pnl_usd

        won = pnl_usd > 0

        if won:
            self.consecutive_losses = 0
        else:
            self.consecutive_losses += 1

        self.trades.append({
            'entry': self.position['entry'],
            'exit': exit_price,
            'side': self.position['side'],
            'pnl_usd': pnl_usd,
            'pnl_pct': pnl_pct * 100,
            'won': won,
            'exit_type': exit_type,
            'confirmations': self.position['confirmations']
        })

        self.position = None

    def backtest(self, df):
        """Backtest système optimisé"""

        for i in range(100, len(df)):
            # Market regime
            regime = self.detect_market_regime(df, i)
            if not regime or not regime.get('tradeable', False):
                continue

            # Params adaptatifs
            params = self.calculate_adaptive_params(regime)

            # Gérer position
            if self.position:
                should_exit, exit_type = self.should_exit(df, i, self.position, self.position['params'])
                if should_exit:
                    self.close_trade(df.iloc[i]['close'], exit_type)
                continue

            # Stop après 4 pertes
            if self.consecutive_losses >= 4:
                continue

            # Signal avec seuil 2.5+ et LONG bias
            signal = self.detect_entry_signal(df, i, regime)
            if signal:
                self.position = {
                    'entry': df.iloc[i]['close'],
                    'side': signal['side'],
                    'params': params,
                    'confirmations': signal['confirmations']
                }

        # Stats
        if not self.trades:
            return None

        wins = [t for t in self.trades if t['won']]
        losses = [t for t in self.trades if not t['won']]

        total_return = ((self.capital - self.initial_capital) / self.initial_capital) * 100
        win_rate = len(wins) / len(self.trades)
        avg_win = np.mean([t['pnl_pct'] for t in wins]) if wins else 0
        avg_loss = np.mean([t['pnl_pct'] for t in losses]) if losses else 0
        profit_factor = abs(sum([t['pnl_usd'] for t in wins]) / sum([t['pnl_usd'] for t in losses])) if losses else 999

        # Max DD
        peak = self.initial_capital
        max_dd = 0
        cap = self.initial_capital
        for t in self.trades:
            cap += t['pnl_usd']
            if cap > peak:
                peak = cap
            dd = ((peak - cap) / peak) * 100
            if dd > max_dd:
                max_dd = dd

        return {
            'roi': total_return,
            'capital': self.capital,
            'trades': len(self.trades),
            'win_rate': win_rate,
            'avg_win': avg_win,
            'avg_loss': avg_loss,
            'profit_factor': profit_factor,
            'max_dd': max_dd
        }

# ============ TESTS ============

print("=" * 80)
print("🚀 SYSTÈME OPTIMISÉ V2 - Data-Driven")
print("=" * 80)
print("\nOptimisations:")
print("  ✅ Seuil 2.5+ confirmations (vs 2.0)")
print("  ✅ LONG bias - Filtrage SHORT strict")
print("  ✅ SL resserré (0.75x ATR vs 1.0x)")
print("  ✅ Leverage range 25-45x optimal")

backtester = MartingaleBacktester(
    initial_capital=1000.0,
    trading_fee_pct=0.0005,
    timeout_minutes=60
)

print("\n📊 Test BTC 4h - Walk-Forward Validation:\n")
print("📥 Téléchargement...")
df_full = backtester.fetch_binance_data('BTCUSDT', '4h', 1000)

if df_full is None:
    exit(1)

# Split en 3
n = len(df_full)
periods = [
    ("P1 (Mai-Juil)", df_full.iloc[:n//3]),
    ("P2 (Juil-Sep)", df_full.iloc[n//3:2*n//3]),
    ("P3 (Sep-Nov)", df_full.iloc[2*n//3:])
]

results = []

for name, period_df in periods:
    print(f"🧪 {name}...", end=" ")

    system = OptimizedSystemV2(initial_capital=1000)
    result = system.backtest(period_df)

    if result:
        results.append(result)
        status = "✅" if result['roi'] > 15 else "⚠️" if result['roi'] > 10 else "🔵"
        print(f"{status} ROI: {result['roi']:+.2f}% | WR: {result['win_rate']*100:.1f}% | Trades: {result['trades']}")
    else:
        print(f"❌ Aucun trade")

# Stats
print("\n" + "=" * 80)
print("📊 RÉSULTATS VS BASELINE")
print("=" * 80)

if results:
    rois = [r['roi'] for r in results]
    wrs = [r['win_rate'] for r in results]

    avg_roi_v2 = np.mean(rois)
    std_roi_v2 = np.std(rois)
    avg_wr_v2 = np.mean(wrs)

    # Baseline (hybrid)
    baseline_roi = 17.14
    baseline_std = 4.08
    baseline_wr = 0.571

    print(f"\n{'Métrique':<20} {'Baseline':>12} {'V2 Optimisé':>12} {'Delta':>10}")
    print("-" * 60)
    print(f"{'ROI moyen':<20} {baseline_roi:>11.2f}% {avg_roi_v2:>11.2f}% {avg_roi_v2-baseline_roi:>9.2f}%")
    print(f"{'Écart-type ROI':<20} {baseline_std:>11.2f}% {std_roi_v2:>11.2f}% {std_roi_v2-baseline_std:>9.2f}%")
    print(f"{'Win Rate moyen':<20} {baseline_wr*100:>11.1f}% {avg_wr_v2*100:>11.1f}% {(avg_wr_v2-baseline_wr)*100:>9.1f}%")

    # Verdict
    print(f"\n🎯 VERDICT:")
    if avg_roi_v2 > baseline_roi * 1.1:
        print(f"   ✅ AMÉLIORATION SIGNIFICATIVE (+{((avg_roi_v2/baseline_roi - 1)*100):.1f}%)")
    elif avg_roi_v2 > baseline_roi:
        print(f"   ✅ Légère amélioration (+{avg_roi_v2-baseline_roi:.2f}%)")
    elif avg_roi_v2 > baseline_roi * 0.95:
        print(f"   ⚠️  Performance similaire")
    else:
        print(f"   ❌ Performance inférieure")

    if avg_wr_v2 > baseline_wr + 0.05:
        print(f"   ✅ Win rate amélioré (+{(avg_wr_v2-baseline_wr)*100:.1f}%)")

    # Sauvegarder
    with open('optimized_v2_results.json', 'w') as f:
        json.dump({
            'periods': results,
            'avg_roi': avg_roi_v2,
            'std_roi': std_roi_v2,
            'avg_win_rate': avg_wr_v2,
            'baseline_comparison': {
                'roi_improvement': avg_roi_v2 - baseline_roi,
                'wr_improvement': avg_wr_v2 - baseline_wr
            }
        }, f, indent=2, default=str)

    print(f"\n💾 Résultats: optimized_v2_results.json")

print("=" * 80)
