#!/usr/bin/env python3
"""
SYSTÈME HYBRIDE - Meilleur des deux mondes

Combine:
1. Paramètres adaptatifs (adaptive_system.py - meilleure performance)
2. Confirmation modérée (2 signaux min au lieu de 3)
3. FILTRE MARKET REGIME (skip downtrends forts)
4. Risk management intelligent

Résout le problème ETH: évite de trader les downtrends forts
"""

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

class HybridSystem:
    """Système hybride adaptatif + filtres intelligents"""

    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):
        """Détecte le régime de marché et filtre les conditions défavorables"""

        if i < 100:
            return None

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

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

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

        # FILTRE: Skip strong downtrends (ETH problem)
        if trend_strength < -0.05:  # -5% = strong downtrend
            return None  # ❌ Ne pas trader

        # Classify trend
        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  # Passed filters
        }

    def calculate_adaptive_params(self, regime):
        """Paramètres adaptatifs basés sur volatilité"""

        # LEVERAGE: Inverse de la volatilité
        if regime['atr_pct'] > 2.0:
            base_leverage = 10
        elif regime['atr_pct'] > 1.0:
            base_leverage = 20
        elif regime['atr_pct'] > 0.5:
            base_leverage = 30
        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.7)
        else:
            leverage = base_leverage

        leverage = min(leverage, 50)

        # TP/SL: Basés sur ATR
        tp_pct = regime['atr_pct'] * 2.0
        sl_pct = regime['atr_pct'] * 1.0

        # Limites
        tp_pct = max(0.5, min(tp_pct, 5.0))
        sl_pct = max(0.3, min(sl_pct, 3.0))

        # POSITION SIZE: 2% risk (1% après pertes)
        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 CONFIRMATION MODÉRÉE (2+ au lieu de 3+)"""

        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 de la bougie
        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  # Less confidence in ranging

        # 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

        # Besoin de 2+ confirmations (plus souple que 3)
        if confirmations < 2:
            return None

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

    def should_exit(self, df, i, position, params):
        """Gestion de sortie avec trailing"""

        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.7
                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.7
                if current['close'] > trailing:
                    return True, 'TRAILING'

        return False, None

    def close_trade(self, exit_price, exit_type):
        """Ferme et enregistre le 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  # Frais

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

        won = pnl_usd > 0

        # Update streaks
        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 le système hybride"""

        for i in range(100, len(df)):
            # Analyser market regime
            regime = self.detect_market_regime(df, i)

            # Skip if market not tradeable
            if not regime or not regime.get('tradeable', False):
                continue

            # Calculer params adaptatifs
            params = self.calculate_adaptive_params(regime)

            # Gérer position existante
            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 consécutives
            if self.consecutive_losses >= 4:
                continue

            # Chercher signal
            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']
                }

        # Statistiques
        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 HYBRIDE - Adaptatif + Filtres Intelligents")
print("=" * 80)

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

# Test sur 4h uniquement (prouvé supérieur à 1h)
symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'ADAUSDT', 'AVAXUSDT']
results = []

print("\n📊 Tests 4h avec filtrage de market regime:\n")

for symbol in symbols:
    print(f"🧪 {symbol}...", end=" ")

    df = backtester.fetch_binance_data(symbol, '4h', 500)

    if df is None:
        print("❌")
        continue

    system = HybridSystem(initial_capital=1000)
    result = system.backtest(df)

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

# ============ RÉSULTATS ============

print("\n\n" + "=" * 80)
print("🏆 RÉSULTATS SYSTÈME HYBRIDE")
print("=" * 80)

if not results:
    print("\n⚠️  Tous les marchés filtrés (conditions défavorables)")
    exit(0)

results.sort(key=lambda x: x['roi'], reverse=True)

print(f"\n{'Symbol':<12} {'ROI%':>8} {'WR%':>6} {'PF':>6} {'Trades':>7} {'DD%':>7} {'Avg+':>7} {'Avg-':>7} {'Status'}")
print("-" * 90)

for res in results:
    status = "✅" if res['roi'] > 10 else "⚠️" if res['roi'] > 0 else "❌"
    print(f"{res['symbol']:<12} {res['roi']:>7.2f}% {res['win_rate']*100:>5.1f}% "
          f"{res['profit_factor']:>6.2f} {res['trades']:>7} {res['max_dd']:>6.2f}% "
          f"{res['avg_win']:>6.2f}% {res['avg_loss']:>6.2f}% {status}")

# Stats
profitable = [r for r in results if r['roi'] > 0]
avg_roi = np.mean([r['roi'] for r in results])
median_roi = np.median([r['roi'] for r in results])

print(f"\n📈 STATISTIQUES:")
print(f"   Tests:               {len(results)}")
print(f"   Profitables:         {len(profitable)} ({len(profitable)/len(results)*100:.1f}%)")
print(f"   ROI moyen:           {avg_roi:+.2f}%")
print(f"   ROI médian:          {median_roi:+.2f}%")

if profitable:
    avg_profit = np.mean([r['roi'] for r in profitable])
    avg_wr = np.mean([r['win_rate'] for r in profitable])
    print(f"   ROI moyen (profit):  +{avg_profit:.2f}%")
    print(f"   WR moyen (profit):   {avg_wr*100:.1f}%")

# Meilleur
if results:
    best = results[0]
    print(f"\n🥇 MEILLEUR:")
    print(f"   Symbol:  {best['symbol']}")
    print(f"   ROI:     {best['roi']:+.2f}%")
    print(f"   WR:      {best['win_rate']*100:.1f}%")
    print(f"   PF:      {best['profit_factor']:.2f}")
    print(f"   Trades:  {best['trades']}")

# Robustesse
std_roi = np.std([r['roi'] for r in results])
print(f"\n🎯 ROBUSTESSE:")
print(f"   Écart-type: {std_roi:.2f}%")

if std_roi < 10 and len(profitable)/len(results) > 0.7:
    print(f"   ✅ SYSTÈME TRÈS ROBUSTE!")
elif std_roi < 15 and len(profitable)/len(results) > 0.6:
    print(f"   ✅ SYSTÈME ROBUSTE")
elif len(profitable)/len(results) > 0.5:
    print(f"   ⚠️  Système modérément robuste")
else:
    print(f"   ❌ Système instable")

# Comparaison
print(f"\n📊 COMPARAISON vs AUTRES SYSTÈMES:")
print(f"   Adaptive System:  +16.37% ROI moyen (sur profitable)")
print(f"   Final System:     +11.01% ROI moyen (sur profitable)")
print(f"   Hybrid System:    {avg_profit if profitable else 0:+.2f}% ROI moyen (sur profitable)")

# Sauvegarder
with open('hybrid_system_results.json', 'w') as f:
    json.dump(results, f, indent=2, default=str)

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

# Verdict
print(f"\n{'=' * 80}")
if avg_roi > 10 and len(profitable)/len(results) > 0.7:
    print("🎉 SYSTÈME HYBRIDE EXCELLENT - ESPÉRANCE POSITIVE ROBUSTE!")
    print(f"   ✅ {len(profitable)/len(results)*100:.0f}% de taux de réussite")
    print(f"   ✅ +{avg_roi:.2f}% ROI moyen")
elif avg_roi > 5 and len(profitable)/len(results) > 0.6:
    print("✅ SYSTÈME HYBRIDE BON - Espérance positive confirmée")
    print(f"   ROI moyen: +{avg_roi:.2f}%")
elif avg_roi > 0:
    print("⚠️  Système légèrement profitable")
else:
    print("❌ Système non profitable")

print(f"{'=' * 80}")
