#!/usr/bin/env python3
"""
Degen Scalping Strategy - Ultra High Leverage (225x)
Stratégie de scalping rapide pour mode DEGEN avec leverage extrême

Caractéristiques:
- Entrées/sorties rapides (1-5 minutes)
- TP très petit: 0.15% = +33% profit avec 225x
- Signaux très forts uniquement (>90% confiance)
- Breakouts clairs seulement
- Filtre de volatilité
"""

import pandas as pd
import numpy as np
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
import logging
from datetime import datetime, timedelta

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


@dataclass
class ScalpSignal:
    """Signal de scalping"""
    symbol: str
    side: str  # 'LONG' ou 'SHORT'
    confidence: float  # 0-100
    entry_price: float
    stop_loss: float
    take_profit: float
    leverage: int
    reason: str
    indicators: Dict[str, float]


class DegenScalpingStrategy:
    """
    Stratégie de scalping pour leverage extrême (225x)

    Règles strictes:
    1. Volatilité < 0.4% sur 5min (éviter les mouvements brusques)
    2. Breakout clair avec volume > 1.5x moyenne
    3. 3+ indicateurs alignés
    4. Confiance > 90%
    5. TP rapide: 0.15% (+33% profit)
    6. SL ultra-serré: 0.025% (-5.6% perte)
    """

    def __init__(self, leverage: int = 225):
        self.leverage = leverage

        # TP/SL OPTIMISÉS (Config #1 - meilleure performance)
        self.stop_loss_pct = 0.00037  # 0.037% = -8.3% avec 225x
        self.take_profit_pct = 0.00291  # 0.291% = +65.5% avec 225x

        # Seuils de confiance OPTIMISÉS
        self.min_confidence = 75.0  # Optimisé (plus de signaux)

        # Filtre de volatilité OPTIMISÉ
        self.max_volatility_5m = 0.0043  # 0.43% optimisé

        # Volume minimum OPTIMISÉ
        self.min_volume_multiplier = 2.87  # 2.87x optimisé

        logger.info("🎯 DegenScalpingStrategy initialisée")
        logger.info(f"   Leverage: {self.leverage}x")
        logger.info(f"   TP: {self.take_profit_pct*100:.3f}% = +{self.take_profit_pct*self.leverage*100:.1f}% profit")
        logger.info(f"   SL: {self.stop_loss_pct*100:.3f}% = -{self.stop_loss_pct*self.leverage*100:.1f}% perte")
        logger.info(f"   Min confiance: {self.min_confidence}%")

    def analyze(self, symbol: str, df: pd.DataFrame) -> Optional[ScalpSignal]:
        """
        Analyse et génère un signal de scalping

        Args:
            symbol: Symbole du token
            df: DataFrame avec colonnes: timestamp, open, high, low, close, volume
                Timeframe: 1min ou 5min

        Returns:
            ScalpSignal ou None
        """
        if df is None or len(df) < 50:
            return None

        try:
            # 1. Vérifier volatilité
            volatility_ok, volatility = self._check_volatility(df)
            if not volatility_ok:
                logger.debug(f"   ❌ Volatilité trop élevée: {volatility*100:.2f}%")
                return None

            # 2. Calculer indicateurs
            indicators = self._calculate_indicators(df)

            # 3. Détecter breakout
            breakout = self._detect_breakout(df, indicators)
            if not breakout['detected']:
                return None

            # 4. Calculer confiance
            confidence = self._calculate_confidence(indicators, breakout)

            if confidence < self.min_confidence:
                logger.debug(f"   ⚠️  Confiance trop faible: {confidence:.1f}% (min {self.min_confidence}%)")
                return None

            # 5. Déterminer direction
            side = breakout['direction']
            current_price = float(df['close'].iloc[-1])

            # 6. Calculer SL/TP
            if side == 'LONG':
                stop_loss = current_price * (1 - self.stop_loss_pct)
                take_profit = current_price * (1 + self.take_profit_pct)
            else:  # SHORT
                stop_loss = current_price * (1 + self.stop_loss_pct)
                take_profit = current_price * (1 - self.take_profit_pct)

            # 7. Créer signal
            signal = ScalpSignal(
                symbol=symbol,
                side=side,
                confidence=confidence,
                entry_price=current_price,
                stop_loss=stop_loss,
                take_profit=take_profit,
                leverage=self.leverage,
                reason=breakout['reason'],
                indicators=indicators
            )

            logger.info(f"🎯 SIGNAL DEGEN SCALP: {side} {symbol}")
            logger.info(f"   Confiance: {confidence:.1f}%")
            logger.info(f"   Entry: ${current_price:,.2f}")
            logger.info(f"   TP: ${take_profit:,.2f} ({self.take_profit_pct*100:.2f}%)")
            logger.info(f"   SL: ${stop_loss:,.2f} ({self.stop_loss_pct*100:.3f}%)")
            logger.info(f"   Raison: {breakout['reason']}")

            return signal

        except Exception as e:
            logger.error(f"❌ Erreur analyse: {e}")
            return None

    def _check_volatility(self, df: pd.DataFrame) -> Tuple[bool, float]:
        """Vérifie que la volatilité n'est pas trop élevée"""
        # Calculer volatilité sur les 5 dernières bougies
        last_5 = df.tail(5)
        high_low_range = (last_5['high'].max() - last_5['low'].min()) / last_5['close'].iloc[-1]

        return high_low_range < self.max_volatility_5m, high_low_range

    def _calculate_indicators(self, df: pd.DataFrame) -> Dict[str, float]:
        """Calcule les indicateurs de scalping"""
        close = df['close']
        high = df['high']
        low = df['low']
        volume = df['volume']

        # RSI court terme (7 périodes pour scalping)
        rsi_7 = self._calculate_rsi(close, 7)

        # MACD rapide (5, 13, 5)
        macd, signal, hist = self._calculate_macd(close, 5, 13, 5)

        # Bollinger Bands (20, 2)
        bb_upper, bb_middle, bb_lower = self._calculate_bollinger(close, 20, 2)

        # Volume ratio
        volume_ma = volume.rolling(20).mean()
        volume_ratio = volume.iloc[-1] / volume_ma.iloc[-1] if volume_ma.iloc[-1] > 0 else 1

        # Prix relatif aux BB
        current_price = close.iloc[-1]
        bb_position = (current_price - bb_lower.iloc[-1]) / (bb_upper.iloc[-1] - bb_lower.iloc[-1])

        return {
            'rsi': rsi_7.iloc[-1],
            'macd': macd.iloc[-1],
            'macd_signal': signal.iloc[-1],
            'macd_hist': hist.iloc[-1],
            'bb_position': bb_position,
            'volume_ratio': volume_ratio,
            'price': current_price,
            'bb_upper': bb_upper.iloc[-1],
            'bb_lower': bb_lower.iloc[-1]
        }

    def _detect_breakout(self, df: pd.DataFrame, indicators: Dict) -> Dict:
        """Détecte un breakout clair"""

        # Breakout conditions
        reasons = []
        score = 0
        direction = None

        # 1. Breakout Bollinger Bands + Volume
        if indicators['bb_position'] > 0.95 and indicators['volume_ratio'] > self.min_volume_multiplier:
            reasons.append("BB breakout UP + volume spike")
            score += 30
            direction = 'LONG'
        elif indicators['bb_position'] < 0.05 and indicators['volume_ratio'] > self.min_volume_multiplier:
            reasons.append("BB breakout DOWN + volume spike")
            score += 30
            direction = 'SHORT'

        # 2. RSI extrême avec reversal
        if indicators['rsi'] < 25:  # Oversold
            reasons.append("RSI oversold (<25)")
            score += 25
            if direction is None:
                direction = 'LONG'
        elif indicators['rsi'] > 75:  # Overbought
            reasons.append("RSI overbought (>75)")
            score += 25
            if direction is None:
                direction = 'SHORT'

        # 3. MACD signal cross
        if indicators['macd_hist'] > 0 and indicators['macd'] > indicators['macd_signal']:
            reasons.append("MACD bullish cross")
            score += 20
            if direction == 'LONG':
                score += 10  # Bonus si aligné
        elif indicators['macd_hist'] < 0 and indicators['macd'] < indicators['macd_signal']:
            reasons.append("MACD bearish cross")
            score += 20
            if direction == 'SHORT':
                score += 10

        # 4. Volume spike seul
        if indicators['volume_ratio'] > 2.0:
            reasons.append(f"Volume spike {indicators['volume_ratio']:.1f}x")
            score += 15

        detected = score >= 50 and direction is not None

        return {
            'detected': detected,
            'direction': direction,
            'score': score,
            'reason': ' | '.join(reasons) if reasons else 'No clear signal'
        }

    def _calculate_confidence(self, indicators: Dict, breakout: Dict) -> float:
        """Calcule le niveau de confiance (0-100)"""

        confidence = breakout['score']  # Base: score du breakout

        # Bonus: alignement multi-indicateurs
        alignment_count = 0

        if breakout['direction'] == 'LONG':
            if indicators['rsi'] < 35:
                alignment_count += 1
            if indicators['macd_hist'] > 0:
                alignment_count += 1
            if indicators['bb_position'] < 0.3:
                alignment_count += 1
        else:  # SHORT
            if indicators['rsi'] > 65:
                alignment_count += 1
            if indicators['macd_hist'] < 0:
                alignment_count += 1
            if indicators['bb_position'] > 0.7:
                alignment_count += 1

        # Bonus pour alignement
        confidence += alignment_count * 10

        # Bonus pour volume fort
        if indicators['volume_ratio'] > 2.5:
            confidence += 10

        return min(confidence, 100.0)

    @staticmethod
    def _calculate_rsi(series: pd.Series, period: int = 14) -> pd.Series:
        """Calcule le RSI"""
        delta = series.diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
        rs = gain / loss
        return 100 - (100 / (1 + rs))

    @staticmethod
    def _calculate_macd(series: pd.Series, fast=12, slow=26, signal_period=9):
        """Calcule le MACD"""
        ema_fast = series.ewm(span=fast, adjust=False).mean()
        ema_slow = series.ewm(span=slow, adjust=False).mean()
        macd = ema_fast - ema_slow
        signal = macd.ewm(span=signal_period, adjust=False).mean()
        hist = macd - signal
        return macd, signal, hist

    @staticmethod
    def _calculate_bollinger(series: pd.Series, period=20, std_dev=2):
        """Calcule les Bollinger Bands"""
        middle = series.rolling(window=period).mean()
        std = series.rolling(window=period).std()
        upper = middle + (std * std_dev)
        lower = middle - (std * std_dev)
        return upper, middle, lower


if __name__ == '__main__':
    logger.info("="*80)
    logger.info("🧪 TEST DEGEN SCALPING STRATEGY")
    logger.info("="*80)

    strategy = DegenScalpingStrategy()

    # Test avec données simulées
    import random

    # Générer fausses données
    base_price = 107000
    data = []

    for i in range(100):
        price = base_price + random.uniform(-500, 500)
        data.append({
            'timestamp': datetime.now() - timedelta(minutes=100-i),
            'open': price,
            'high': price + random.uniform(0, 200),
            'low': price - random.uniform(0, 200),
            'close': price,
            'volume': random.uniform(1000, 5000)
        })

    df = pd.DataFrame(data)

    logger.info(f"\n📊 Test avec {len(df)} bougies")
    logger.info(f"   Prix: ${df['close'].iloc[-1]:,.2f}")

    signal = strategy.analyze('BTCUSD_DEGEN', df)

    if signal:
        logger.info(f"\n✅ Signal généré!")
    else:
        logger.info(f"\n⚠️  Aucun signal (conditions non remplies)")

    logger.info("\n" + "="*80)
    logger.info("✅ Test terminé")
    logger.info("="*80)
