#!/usr/bin/env python3
"""
RECHERCHE EDGE V2 - Edges plus créatifs

Tests:
- Attendre après pertes (mean reversion)
- Filtrer par volatilité
- Only LONG ou Only SHORT
- Combos avancés
"""

from martingale_backtester import MartingaleBacktester
from martingale_strategy import MartingaleStrategy
import numpy as np

print("="*80)
print("🔬 RECHERCHE EDGE V2 - STRATÉGIES CRÉATIVES")
print("="*80)

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

print("\n📥 Téléchargement données...")
df = backtester.fetch_binance_data('BTCUSDT', '1m', 1000)

if df is None:
    exit(1)

print(f"✅ {len(df)} bougies\n")

# ============ EDGES CRÉATIFS ============

class CreativeEdgeStrategy(MartingaleStrategy):
    def __init__(self, edge_type, **kwargs):
        super().__init__(**kwargs)
        self.edge_type = edge_type
        self.wait_count = 0
        self.force_side = None

    def get_martingale_multiplier(self):
        return 0.5 ** self.current_level  # Anti-martingale

    def generate_signal(self, df):
        # EDGE: Wait après 3 pertes (attendre mean reversion)
        if self.edge_type == 'wait_after_3_losses':
            if self.consecutive_losses >= 3:
                if self.wait_count < 5:  # Wait 5 bougies
                    self.wait_count += 1
                    return None
                else:
                    self.wait_count = 0

        # EDGE: Only trade dans direction du trend
        if self.edge_type == 'trend_only':
            # EMA 50 comme trend
            if len(df) >= 50:
                ema50 = df['close'].ewm(span=50).mean().iloc[-1]
                current_price = df.iloc[-1]['close']

                signal = super().generate_signal(df)
                if signal:
                    if current_price > ema50 and signal.side == 'SHORT':
                        return None  # Skip SHORT en uptrend
                    if current_price < ema50 and signal.side == 'LONG':
                        return None  # Skip LONG en downtrend
                return signal

        # EDGE: Only LONG (jamais SHORT)
        if self.edge_type == 'only_long':
            signal = super().generate_signal(df)
            if signal and signal.side == 'SHORT':
                return None
            return signal

        # EDGE: Only SHORT (jamais LONG)
        if self.edge_type == 'only_short':
            signal = super().generate_signal(df)
            if signal and signal.side == 'LONG':
                return None
            return signal

        # EDGE: Reverse après 3 pertes + Wait 3 bougies
        if self.edge_type == 'reverse_and_wait':
            if self.consecutive_losses >= 3:
                if self.wait_count < 3:
                    self.wait_count += 1
                    return None
                else:
                    self.wait_count = 0
                    signal = super().generate_signal(df)
                    if signal:
                        # Reverse
                        signal.side = 'SHORT' if signal.side == 'LONG' else 'LONG'
                        signal.stop_loss, signal.take_profit = signal.take_profit, signal.stop_loss
                    return signal

        # EDGE: TP adaptatif selon volatilité
        if self.edge_type == 'adaptive_tp':
            signal = super().generate_signal(df)
            if signal and len(df) >= 20:
                # Calculer ATR
                high_low = df['high'] - df['low']
                atr = high_low.rolling(14).mean().iloc[-1]
                volatility_ratio = atr / df['close'].iloc[-1]

                # TP plus large si volatilité haute
                if volatility_ratio > 0.005:  # Volatile
                    if signal.side == 'LONG':
                        signal.take_profit = signal.entry_price * (1 + 0.015)  # 1.5% TP
                    else:
                        signal.take_profit = signal.entry_price * (1 - 0.015)

            return signal

        # EDGE: Trade seulement si volume élevé
        if self.edge_type == 'high_volume_only':
            signal = super().generate_signal(df)
            if signal and len(df) >= 20:
                vol_ma = df['volume'].rolling(20).mean().iloc[-1]
                current_vol = df['volume'].iloc[-1]

                if current_vol < vol_ma * 1.5:  # Skip si volume faible
                    return None

            return signal

        # EDGE: Reverse après 2 pertes + TP x2
        if self.edge_type == 'reverse2_tp2x':
            signal = super().generate_signal(df)
            if signal and self.consecutive_losses >= 2:
                # Reverse
                signal.side = 'SHORT' if signal.side == 'LONG' else 'LONG'
                signal.stop_loss, signal.take_profit = signal.take_profit, signal.stop_loss

                # Double TP
                if signal.side == 'LONG':
                    tp_dist = signal.take_profit - signal.entry_price
                    signal.take_profit = signal.entry_price + tp_dist * 2
                else:
                    tp_dist = signal.entry_price - signal.take_profit
                    signal.take_profit = signal.entry_price - tp_dist * 2

            return signal

        # EDGE: Martingale normale (x2) au lieu d'anti
        if self.edge_type == 'normal_martingale_x2':
            # Override multiplier
            self.get_martingale_multiplier = lambda: 2 ** self.current_level
            return super().generate_signal(df)

        # EDGE: Fibonacci multiplier
        if self.edge_type == 'fibo_multi':
            # Fibonacci: 1, 1, 2, 3, 5, 8
            fibs = [1, 1, 2, 3, 5, 8]
            level = min(self.current_level, len(fibs)-1)
            self.get_martingale_multiplier = lambda: fibs[level]
            return super().generate_signal(df)

        return super().generate_signal(df)

    def update_after_trade(self, won):
        super().update_after_trade(won)
        if won:
            self.wait_count = 0

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

edges = [
    'base',
    'wait_after_3_losses',
    'trend_only',
    'only_long',
    'only_short',
    'reverse_and_wait',
    'adaptive_tp',
    'high_volume_only',
    'reverse2_tp2x'
]

results = []

for i, edge in enumerate(edges, 1):
    print(f"\n{'='*80}")
    print(f"🧪 TEST {i}/{len(edges)}: {edge.upper()}")
    print(f"{'='*80}")

    if edge == 'base':
        # Base anti-martingale
        class AntiMartingale(MartingaleStrategy):
            def get_martingale_multiplier(self):
                return 0.5 ** self.current_level

        strategy = AntiMartingale(
            base_position_size=10.0,
            max_martingale_level=5,
            base_leverage=100,
            max_leverage=1000,
            stop_loss_pct=0.003,
            take_profit_ratio=3.0,
            min_signal_score=0.6
        )
    else:
        strategy = CreativeEdgeStrategy(
            edge_type=edge,
            base_position_size=10.0,
            max_martingale_level=5,
            base_leverage=100,
            max_leverage=1000,
            stop_loss_pct=0.003,
            take_profit_ratio=3.0,
            min_signal_score=0.6
        )

    result = backtester.run_backtest(df, 'BTCUSDT', strategy)

    if result:
        results.append({
            'edge': edge,
            'roi': result.total_return_pct,
            'win_rate': result.win_rate,
            'pf': result.profit_factor,
            'trades': result.total_trades,
            'dd': result.max_drawdown_pct,
            'capital': result.final_capital
        })
    else:
        results.append({
            'edge': edge,
            'roi': 0,
            'win_rate': 0,
            'pf': 0,
            'trades': 0,
            'dd': 0,
            'capital': 1000
        })

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

print("\n" + "="*80)
print("🏆 CLASSEMENT EDGES CRÉATIFS")
print("="*80)

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

print(f"\n{'RANG':<5} {'EDGE':<30} {'ROI %':>10} {'WR %':>8} {'PF':>6} {'Trades':>7} {'DD %':>8}")
print("-"*80)

for rank, res in enumerate(results, 1):
    emoji = "🥇" if rank == 1 else "🥈" if rank == 2 else "🥉" if rank == 3 else f"{rank:2}"
    status = "✅" if res['roi'] > 0 else "⚠️" if res['roi'] > -1 else "❌"
    print(f"{emoji:<5} {res['edge']:<30} {res['roi']:>9.2f}% {res['win_rate']*100:>7.1f}% "
          f"{res['pf']:>5.2f} {res['trades']:>7} {res['dd']:>7.2f}% {status}")

best = results[0]
print(f"\n{'='*80}")
print(f"🏆 MEILLEUR: {best['edge'].upper()}")
print(f"{'='*80}")
print(f"   ROI:     {best['roi']:+.2f}% {'✅ PROFITABLE!' if best['roi'] > 0 else '❌'}")
print(f"   Capital: ${best['capital']:.2f} ({'gain' if best['capital'] > 1000 else 'perte'} de ${abs(best['capital']-1000):.2f})")
print(f"   WR:      {best['win_rate']*100:.1f}%")
print(f"   Trades:  {best['trades']}")
print(f"   DD:      {best['dd']:.2f}%")
print(f"{'='*80}")

# Sauvegarder
import json
with open('edge_v2_results.json', 'w') as f:
    json.dump(results, f, indent=2)

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

if best['roi'] > 0:
    print(f"\n🎉 EDGE TROUVÉ! La stratégie {best['edge'].upper()} est PROFITABLE!")
    # Sauvegarder comme config
    with open('winning_edge_config.txt', 'w') as f:
        f.write(f"WINNING EDGE: {best['edge']}\n")
        f.write(f"ROI: {best['roi']:.2f}%\n")
        f.write(f"Capital: ${best['capital']:.2f}\n")
    print("✅ Config sauvegardée: winning_edge_config.txt")
