#!/usr/bin/env python3
"""
OPTIMIZATION ULTRA SCALPING
Teste toutes les variations pour trouver les paramètres optimaux
"""

import pandas as pd
import numpy as np
import requests
from typing import Optional
from dataclasses import dataclass
from itertools import product


@dataclass
class ScalpSignal:
    side: str
    entry_price: float
    stop_loss: float
    take_profit: float
    leverage: int


class OptimizedUltraScalping:
    """Version paramétrable de l'Ultra Scalping"""

    def __init__(
        self,
        leverage: int = 20,
        sl_pct: float = 0.02,
        tp_pct: float = 0.03,
        ema_fast: int = 3,
        ema_slow: int = 7,
        min_change_pct: float = 0.02,
        vol_multiplier: float = 1.0
    ):
        self.leverage = leverage
        self.sl_pct = sl_pct
        self.tp_pct = tp_pct
        self.ema_fast = ema_fast
        self.ema_slow = ema_slow
        self.min_change_pct = min_change_pct
        self.vol_multiplier = vol_multiplier

    def analyze(self, df: pd.DataFrame) -> Optional[ScalpSignal]:
        if len(df) < 50:
            return None

        current_price = df['close'].iloc[-1]

        # EMAs
        ema_fast = df['close'].ewm(span=self.ema_fast, adjust=False).mean().iloc[-1]
        ema_slow = df['close'].ewm(span=self.ema_slow, adjust=False).mean().iloc[-1]

        # Price change dernières bougies
        lookback = self.ema_fast + 1
        last_change = ((current_price - df['close'].iloc[-lookback]) / df['close'].iloc[-lookback]) * 100

        # Volume
        vol_ma = df['volume'].rolling(window=10).mean().iloc[-1]
        current_vol = df['volume'].iloc[-1]

        # LONG
        if (ema_fast > ema_slow and
            last_change > self.min_change_pct and
            current_vol > vol_ma * self.vol_multiplier):

            return ScalpSignal(
                side='LONG',
                entry_price=current_price,
                stop_loss=current_price * (1 - self.sl_pct/100),
                take_profit=current_price * (1 + self.tp_pct/100),
                leverage=self.leverage
            )

        # SHORT
        elif (ema_fast < ema_slow and
              last_change < -self.min_change_pct and
              current_vol > vol_ma * self.vol_multiplier):

            return ScalpSignal(
                side='SHORT',
                entry_price=current_price,
                stop_loss=current_price * (1 + self.sl_pct/100),
                take_profit=current_price * (1 - self.tp_pct/100),
                leverage=self.leverage
            )

        return None


def backtest(df, strategy):
    """Backtest rapide"""
    capital = 100.0
    trades = []
    open_position = None

    for i in range(50, len(df)):
        window = df.iloc[:i+1]
        current_price = window['close'].iloc[-1]

        if open_position:
            entry = open_position['entry_price']
            leverage = open_position['leverage']

            if open_position['side'] == 'LONG':
                pnl_pct = ((current_price - entry) / entry) * 100 * leverage
            else:
                pnl_pct = ((entry - current_price) / entry) * 100 * leverage

            pnl_pct = max(pnl_pct, -100)

            if pnl_pct <= -100:
                pnl_usd = capital * -1.0
                capital = 0
                trades.append(pnl_pct)
                break

            hit_sl = (
                (open_position['side'] == 'LONG' and current_price <= open_position['stop_loss']) or
                (open_position['side'] == 'SHORT' and current_price >= open_position['stop_loss'])
            )

            hit_tp = (
                (open_position['side'] == 'LONG' and current_price >= open_position['take_profit']) or
                (open_position['side'] == 'SHORT' and current_price <= open_position['take_profit'])
            )

            if hit_sl or hit_tp:
                pnl_usd = capital * (pnl_pct / 100)
                capital += pnl_usd
                trades.append(pnl_pct)
                open_position = None

        if not open_position and capital > 0:
            signal = strategy.analyze(window)
            if signal:
                open_position = {
                    'side': signal.side,
                    'entry_price': signal.entry_price,
                    'stop_loss': signal.stop_loss,
                    'take_profit': signal.take_profit,
                    'leverage': signal.leverage
                }

    if not trades:
        return None

    winners = len([t for t in trades if t > 0])
    pnl_pct = ((capital - 100) / 100) * 100
    win_rate = (winners / len(trades)) * 100

    return {
        'trades': len(trades),
        'win_rate': win_rate,
        'pnl_pct': pnl_pct,
        'final_capital': capital
    }


def get_bnb_data():
    url = "https://api.binance.com/api/v3/klines"
    params = {'symbol': 'BNBUSDT', 'interval': '1m', 'limit': 1000}
    response = requests.get(url, params=params, timeout=10)
    data = response.json()

    df = pd.DataFrame(data, columns=[
        'timestamp', 'open', 'high', 'low', 'close', 'volume',
        'close_time', 'quote_volume', 'trades', 'taker_buy_base',
        'taker_buy_quote', 'ignore'
    ])

    for col in ['open', 'high', 'low', 'close', 'volume']:
        df[col] = df[col].astype(float)

    return df


def main():
    print("=" * 100)
    print("🔥 OPTIMIZATION ULTRA SCALPING")
    print("=" * 100)

    df = get_bnb_data()
    print(f"\n📊 Données: {len(df)} bougies BNB 1m")

    # Paramètres à tester
    leverages = [15, 20, 25, 30]
    sl_pcts = [0.015, 0.02, 0.025, 0.03]
    tp_pcts = [0.025, 0.03, 0.035, 0.04, 0.045]
    ema_pairs = [(2, 5), (3, 7), (5, 10)]
    min_changes = [0.015, 0.02, 0.025]
    vol_mults = [0.8, 1.0, 1.2]

    print(f"\n🎯 Testing {len(leverages) * len(sl_pcts) * len(tp_pcts) * len(ema_pairs) * len(min_changes) * len(vol_mults)} combinaisons...")
    print("   (ça va prendre 1-2 minutes)\n")

    results = []
    tested = 0

    for lev, sl, tp, (ema_f, ema_s), min_ch, vol_m in product(
        leverages, sl_pcts, tp_pcts, ema_pairs, min_changes, vol_mults
    ):
        # Ratio TP/SL raisonnable
        if tp / sl < 1.2 or tp / sl > 3.0:
            continue

        strategy = OptimizedUltraScalping(
            leverage=lev,
            sl_pct=sl,
            tp_pct=tp,
            ema_fast=ema_f,
            ema_slow=ema_s,
            min_change_pct=min_ch,
            vol_multiplier=vol_m
        )

        result = backtest(df, strategy)

        if result and result['trades'] >= 20:  # Minimum 20 trades
            results.append({
                'leverage': lev,
                'sl_pct': sl,
                'tp_pct': tp,
                'ema_fast': ema_f,
                'ema_slow': ema_s,
                'min_change': min_ch,
                'vol_mult': vol_m,
                **result
            })

        tested += 1
        if tested % 100 == 0:
            print(f"   Progress: {tested} tested, {len(results)} valides...")

    print(f"\n   ✅ {tested} combinaisons testées, {len(results)} valides")

    if results:
        # Trier par PnL
        results.sort(key=lambda x: x['pnl_pct'], reverse=True)

        print("\n" + "=" * 120)
        print("🏆 TOP 20 CONFIGURATIONS")
        print("=" * 120)

        print(f"\n{'Rank':<5} | {'Lev':<4} | {'SL%':<6} | {'TP%':<6} | {'EMA':<7} | {'MinCh%':<7} | {'Vol':<5} | {'Trades':<7} | {'WR%':<6} | {'PnL%':<10}")
        print("-" * 120)

        for i, r in enumerate(results[:20], 1):
            ema_str = f"{r['ema_fast']}/{r['ema_slow']}"
            print(f"{i:<5} | {r['leverage']:<4} | {r['sl_pct']:<6.3f} | {r['tp_pct']:<6.3f} | "
                  f"{ema_str:<7} | {r['min_change']:<7.3f} | {r['vol_mult']:<5.1f} | "
                  f"{r['trades']:<7} | {r['win_rate']:<6.1f} | {r['pnl_pct']:<10.2f}")

        print("-" * 120)

        # Meilleur
        best = results[0]
        print(f"\n🥇 MEILLEURE CONFIGURATION:")
        print(f"   Leverage: {best['leverage']}x")
        print(f"   SL: {best['sl_pct']:.3f}% | TP: {best['tp_pct']:.3f}% (ratio {best['tp_pct']/best['sl_pct']:.1f}:1)")
        print(f"   EMAs: {best['ema_fast']}/{best['ema_slow']}")
        print(f"   Min change: {best['min_change']:.3f}%")
        print(f"   Volume mult: {best['vol_mult']:.1f}x")
        print(f"\n   📈 PERFORMANCE:")
        print(f"   PnL: {best['pnl_pct']:+.2f}%")
        print(f"   Trades: {best['trades']}")
        print(f"   Win rate: {best['win_rate']:.1f}%")
        print(f"   Capital final: ${best['final_capital']:.2f}")

        # Gain vs baseline
        baseline_pnl = 2.1  # Résultat original
        improvement = ((best['pnl_pct'] - baseline_pnl) / abs(baseline_pnl)) * 100
        print(f"\n   🚀 Amélioration vs baseline: {improvement:+.0f}%")

        # Stats générales
        profitable = [r for r in results if r['pnl_pct'] > 0]
        print(f"\n📊 STATISTIQUES:")
        print(f"   Configurations profitables: {len(profitable)}/{len(results)} ({len(profitable)/len(results)*100:.0f}%)")

        if len(profitable) > 1:
            avg_pnl = np.mean([r['pnl_pct'] for r in profitable])
            print(f"   PnL moyen (profitables): {avg_pnl:.2f}%")

    else:
        print("\n⚠️  AUCUNE CONFIGURATION VALIDE TROUVÉE!")

    print("\n" + "=" * 100)
    print("✅ OPTIMIZATION TERMINÉE")
    print("=" * 100 + "\n")


if __name__ == '__main__':
    main()
