#!/usr/bin/env python3
"""
ULTRA PROBABILISTIC STRATEGIES - Acharnement total
Toutes les approches possibles testées en parallèle
"""

import pandas as pd
import numpy as np
from typing import Optional, Dict, List
from dataclasses import dataclass
from scipy import stats as scipy_stats


@dataclass
class UltraSignal:
    """Signal ultra-optimisé"""
    symbol: str
    side: str
    entry_price: float
    stop_loss: float
    take_profit: float
    leverage: int
    confidence: float
    probability: float
    strategy_name: str
    reason: str


# ============================================================================
# STRATÉGIE 1: PROBABILISTE + TA CLASSIQUE
# ============================================================================

class ProbabilisticTA:
    """Combine probabilités + RSI/MACD/Bollinger"""

    def __init__(self, leverage: int = 50):
        self.leverage = leverage
        self.name = "Probabilistic+TA"

    def analyze(self, symbol: str, df: pd.DataFrame) -> Optional[UltraSignal]:
        if len(df) < 200:
            return None

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

        # === INDICATEURS TECHNIQUES ===

        # RSI 14
        delta = df['close'].diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
        rs = gain / loss
        rsi = 100 - (100 / (1 + rs))
        current_rsi = rsi.iloc[-1]

        # MACD
        ema_12 = df['close'].ewm(span=12, adjust=False).mean()
        ema_26 = df['close'].ewm(span=26, adjust=False).mean()
        macd = ema_12 - ema_26
        signal_line = macd.ewm(span=9, adjust=False).mean()
        macd_hist = macd - signal_line
        current_macd_hist = macd_hist.iloc[-1]

        # Bollinger Bands
        sma_20 = df['close'].rolling(window=20).mean()
        std_20 = df['close'].rolling(window=20).std()
        bb_upper = sma_20 + (std_20 * 2)
        bb_lower = sma_20 - (std_20 * 2)
        bb_position = (current_price - bb_lower.iloc[-1]) / (bb_upper.iloc[-1] - bb_lower.iloc[-1])

        # Volume spike
        vol_ma = df['volume'].rolling(window=20).mean()
        vol_spike = df['volume'].iloc[-1] / vol_ma.iloc[-1]

        # === PROBABILITÉS ===

        # Probabilité basée sur RSI (empirique)
        if current_rsi < 30:
            prob_rsi = 0.65  # Oversold → probable remontée
        elif current_rsi > 70:
            prob_rsi = 0.65  # Overbought → probable baisse
        else:
            prob_rsi = 0.50

        # Probabilité basée sur Bollinger
        if bb_position < 0.2:
            prob_bb = 0.70  # Très proche lower band
        elif bb_position > 0.8:
            prob_bb = 0.70  # Très proche upper band
        else:
            prob_bb = 0.50

        # Probabilité basée sur MACD
        prob_macd = 0.60 if abs(current_macd_hist) > 0.5 else 0.50

        # Probabilité combinée (moyenne pondérée)
        combined_prob = (prob_rsi * 0.4 + prob_bb * 0.4 + prob_macd * 0.2)

        # === SIGNAUX ===

        # LONG: RSI oversold + near BB lower + positive MACD divergence + volume
        if (current_rsi < 35 and bb_position < 0.3 and current_macd_hist > 0 and vol_spike > 1.2):

            sl_pct = 0.04  # 0.04% SL
            tp_pct = 0.08  # 0.08% TP

            confidence = min(100, (100 - current_rsi) * 1.5 + (1 - bb_position) * 50)

            return UltraSignal(
                symbol=symbol,
                side='LONG',
                entry_price=current_price,
                stop_loss=current_price * (1 - sl_pct/100),
                take_profit=current_price * (1 + tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=combined_prob,
                strategy_name=self.name,
                reason=f"RSI:{current_rsi:.0f} BB:{bb_position:.2f} MACD+:{current_macd_hist:.2f} Vol:{vol_spike:.1f}x"
            )

        # SHORT: RSI overbought + near BB upper + negative MACD + volume
        elif (current_rsi > 65 and bb_position > 0.7 and current_macd_hist < 0 and vol_spike > 1.2):

            sl_pct = 0.04
            tp_pct = 0.08

            confidence = min(100, current_rsi * 0.8 + bb_position * 50)

            return UltraSignal(
                symbol=symbol,
                side='SHORT',
                entry_price=current_price,
                stop_loss=current_price * (1 + sl_pct/100),
                take_profit=current_price * (1 - tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=combined_prob,
                strategy_name=self.name,
                reason=f"RSI:{current_rsi:.0f} BB:{bb_position:.2f} MACD-:{current_macd_hist:.2f} Vol:{vol_spike:.1f}x"
            )

        return None


# ============================================================================
# STRATÉGIE 2: MOMENTUM PROBABILISTE
# ============================================================================

class MomentumProbabilistic:
    """Probabilités de CONTINUATION au lieu de REVERSION"""

    def __init__(self, leverage: int = 75):
        self.leverage = leverage
        self.name = "Momentum Prob"

    def analyze(self, symbol: str, df: pd.DataFrame) -> Optional[UltraSignal]:
        if len(df) < 100:
            return None

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

        # === MOMENTUM DETECTION ===

        # EMAs rapides
        ema_5 = df['close'].ewm(span=5, adjust=False).mean().iloc[-1]
        ema_10 = df['close'].ewm(span=10, adjust=False).mean().iloc[-1]
        ema_20 = df['close'].ewm(span=20, adjust=False).mean().iloc[-1]

        # Momentum score
        momentum = ((ema_5 - ema_20) / ema_20) * 100

        # Recent price action (dernières 10 bougies)
        recent_change = ((current_price - df['close'].iloc[-10]) / df['close'].iloc[-10]) * 100

        # Volume confirmation
        vol_ma = df['volume'].rolling(window=20).mean().iloc[-1]
        current_vol = df['volume'].iloc[-1]
        vol_ratio = current_vol / vol_ma

        # === PROBABILITÉ DE CONTINUATION (empirique) ===

        # Si momentum fort + volume → probable continuation
        if abs(momentum) > 0.3 and vol_ratio > 1.3:
            prob_continuation = 0.68
        elif abs(momentum) > 0.2 and vol_ratio > 1.1:
            prob_continuation = 0.60
        else:
            return None  # Pas assez de momentum

        # === SIGNAUX ===

        # LONG: Momentum haussier fort
        if momentum > 0.2 and ema_5 > ema_10 > ema_20 and recent_change > 0.1:

            sl_pct = 0.06  # Plus large pour momentum
            tp_pct = 0.15  # TP plus ambitieux

            confidence = min(100, abs(momentum) * 100 + vol_ratio * 20)

            return UltraSignal(
                symbol=symbol,
                side='LONG',
                entry_price=current_price,
                stop_loss=current_price * (1 - sl_pct/100),
                take_profit=current_price * (1 + tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=prob_continuation,
                strategy_name=self.name,
                reason=f"MOM↑:{momentum:.2f}% EMA5>10>20 Vol:{vol_ratio:.1f}x"
            )

        # SHORT: Momentum baissier fort
        elif momentum < -0.2 and ema_5 < ema_10 < ema_20 and recent_change < -0.1:

            sl_pct = 0.06
            tp_pct = 0.15

            confidence = min(100, abs(momentum) * 100 + vol_ratio * 20)

            return UltraSignal(
                symbol=symbol,
                side='SHORT',
                entry_price=current_price,
                stop_loss=current_price * (1 + sl_pct/100),
                take_profit=current_price * (1 - tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=prob_continuation,
                strategy_name=self.name,
                reason=f"MOM↓:{momentum:.2f}% EMA5<10<20 Vol:{vol_ratio:.1f}x"
            )

        return None


# ============================================================================
# STRATÉGIE 3: PROBABILITÉS EMPIRIQUES PURES
# ============================================================================

class EmpiricalProbabilities:
    """Probabilités calculées sur historique réel (pas de scipy.stats)"""

    def __init__(self, leverage: int = 60):
        self.leverage = leverage
        self.name = "Empirical Prob"
        self.lookback = 200

    def analyze(self, symbol: str, df: pd.DataFrame) -> Optional[UltraSignal]:
        if len(df) < self.lookback + 50:
            return None

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

        # === CALCUL EMPIRIQUE ===

        # Historique des mouvements après déviation
        window = df.iloc[-self.lookback:]

        # Stats simples
        mean = window['close'].mean()
        std = window['close'].std()

        # Position actuelle
        deviation = (current_price - mean) / std

        # === PROBABILITÉ EMPIRIQUE (comptage réel) ===

        # Compter combien de fois après une déviation similaire, ça revient
        reversals = 0
        total_samples = 0

        for i in range(50, len(window) - 10):
            past_mean = window['close'].iloc[:i].mean()
            past_std = window['close'].iloc[:i].std()
            past_price = window['close'].iloc[i]
            past_dev = (past_price - past_mean) / past_std

            # Si déviation similaire
            if abs(past_dev - deviation) < 0.3:
                total_samples += 1

                # Check si retour dans les 10 bougies suivantes
                future_prices = window['close'].iloc[i+1:i+11]
                if deviation < 0:  # Prix bas → check si remonte
                    if any(future_prices > past_mean):
                        reversals += 1
                else:  # Prix haut → check si baisse
                    if any(future_prices < past_mean):
                        reversals += 1

        # Probabilité empirique
        if total_samples > 5:
            empirical_prob = reversals / total_samples
        else:
            return None  # Pas assez de samples

        # Filtrer si probabilité trop faible
        if empirical_prob < 0.55:
            return None

        # === SIGNAUX ===

        # LONG: Prix bas + haute probabilité de reversal empirique
        if deviation < -1.5 and empirical_prob > 0.55:

            sl_pct = 0.05
            tp_pct = 0.10

            confidence = min(100, empirical_prob * 100)

            return UltraSignal(
                symbol=symbol,
                side='LONG',
                entry_price=current_price,
                stop_loss=current_price * (1 - sl_pct/100),
                take_profit=current_price * (1 + tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=empirical_prob,
                strategy_name=self.name,
                reason=f"Empirical P(reversal):{empirical_prob*100:.0f}% (samples:{total_samples})"
            )

        # SHORT: Prix haut + haute probabilité de reversal empirique
        elif deviation > 1.5 and empirical_prob > 0.55:

            sl_pct = 0.05
            tp_pct = 0.10

            confidence = min(100, empirical_prob * 100)

            return UltraSignal(
                symbol=symbol,
                side='SHORT',
                entry_price=current_price,
                stop_loss=current_price * (1 + sl_pct/100),
                take_profit=current_price * (1 - tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=empirical_prob,
                strategy_name=self.name,
                reason=f"Empirical P(reversal):{empirical_prob*100:.0f}% (samples:{total_samples})"
            )

        return None


# ============================================================================
# STRATÉGIE 4: ULTRA SCALPING (Leverage faible, TP/SL serrés)
# ============================================================================

class UltraScalping:
    """Leverage 20x, TP 0.03%, SL 0.02%, high frequency"""

    def __init__(self, leverage: int = 20):
        self.leverage = leverage
        self.name = "Ultra Scalping"

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

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

        # === MICRO MOMENTUM ===

        # EMA ultra-rapide
        ema_3 = df['close'].ewm(span=3, adjust=False).mean().iloc[-1]
        ema_7 = df['close'].ewm(span=7, adjust=False).mean().iloc[-1]

        # Price action dernières 3 bougies
        last_3_change = ((current_price - df['close'].iloc[-4]) / df['close'].iloc[-4]) * 100

        # Volume immédiat
        vol_now = df['volume'].iloc[-1]
        vol_avg = df['volume'].rolling(window=10).mean().iloc[-1]

        # === PROBABILITÉ (simple, basée sur micro-pattern) ===

        # Si ema_3 > ema_7 + volume → probable continuation micro
        prob = 0.52  # Juste au-dessus de 50%

        # === SIGNAUX (très fréquents, petits gains) ===

        # LONG: Micro-trend up
        if ema_3 > ema_7 and last_3_change > 0.02 and vol_now > vol_avg:

            sl_pct = 0.02  # TRÈS serré
            tp_pct = 0.03  # TRÈS petit

            confidence = 55  # Basse confiance mais haute fréquence

            return UltraSignal(
                symbol=symbol,
                side='LONG',
                entry_price=current_price,
                stop_loss=current_price * (1 - sl_pct/100),
                take_profit=current_price * (1 + tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=prob,
                strategy_name=self.name,
                reason=f"Micro↑ EMA3>7 Last3:{last_3_change:.3f}%"
            )

        # SHORT: Micro-trend down
        elif ema_3 < ema_7 and last_3_change < -0.02 and vol_now > vol_avg:

            sl_pct = 0.02
            tp_pct = 0.03

            confidence = 55

            return UltraSignal(
                symbol=symbol,
                side='SHORT',
                entry_price=current_price,
                stop_loss=current_price * (1 + sl_pct/100),
                take_profit=current_price * (1 - tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=prob,
                strategy_name=self.name,
                reason=f"Micro↓ EMA3<7 Last3:{last_3_change:.3f}%"
            )

        return None


# ============================================================================
# STRATÉGIE 5: BREAKOUT PROBABILISTE
# ============================================================================

class BreakoutProbabilistic:
    """Breakout de range avec probabilité de continuation"""

    def __init__(self, leverage: int = 80):
        self.leverage = leverage
        self.name = "Breakout Prob"

    def analyze(self, symbol: str, df: pd.DataFrame) -> Optional[UltraSignal]:
        if len(df) < 100:
            return None

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

        # === RANGE DETECTION ===

        # High/Low dernières 50 bougies
        high_50 = df['high'].iloc[-50:].max()
        low_50 = df['low'].iloc[-50:].min()
        range_size = ((high_50 - low_50) / low_50) * 100

        # Prix proche du range?
        distance_to_high = ((high_50 - current_price) / current_price) * 100
        distance_to_low = ((current_price - low_50) / current_price) * 100

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

        # === PROBABILITÉ DE BREAKOUT ===

        # Si prix near resistance + volume spike → probable breakout
        if distance_to_high < 0.05 and vol_spike > 1.5:
            prob_breakout = 0.65
        elif distance_to_low < 0.05 and vol_spike > 1.5:
            prob_breakout = 0.65
        else:
            return None

        # === SIGNAUX ===

        # LONG: Breakout resistance
        if distance_to_high < 0.05 and vol_spike > 1.5 and current_price > df['close'].iloc[-2]:

            sl_pct = 0.04
            tp_pct = 0.12  # Plus ambitieux sur breakout

            confidence = min(100, vol_spike * 30 + 50)

            return UltraSignal(
                symbol=symbol,
                side='LONG',
                entry_price=current_price,
                stop_loss=current_price * (1 - sl_pct/100),
                take_profit=current_price * (1 + tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=prob_breakout,
                strategy_name=self.name,
                reason=f"Breakout↑ High:{high_50:.2f} Vol:{vol_spike:.1f}x"
            )

        # SHORT: Breakout support (to downside)
        elif distance_to_low < 0.05 and vol_spike > 1.5 and current_price < df['close'].iloc[-2]:

            sl_pct = 0.04
            tp_pct = 0.12

            confidence = min(100, vol_spike * 30 + 50)

            return UltraSignal(
                symbol=symbol,
                side='SHORT',
                entry_price=current_price,
                stop_loss=current_price * (1 + sl_pct/100),
                take_profit=current_price * (1 - tp_pct/100),
                leverage=self.leverage,
                confidence=confidence,
                probability=prob_breakout,
                strategy_name=self.name,
                reason=f"Breakdown↓ Low:{low_50:.2f} Vol:{vol_spike:.1f}x"
            )

        return None


if __name__ == '__main__':
    print("🔥 ULTRA PROBABILISTIC STRATEGIES")
    print("=" * 80)
    print("\n5 STRATÉGIES DÉVELOPPÉES:")
    print("  1. Probabilistic+TA: RSI + MACD + Bollinger + probabilités")
    print("  2. Momentum Prob: Continuation au lieu de reversion")
    print("  3. Empirical Prob: Probabilités sur historique réel")
    print("  4. Ultra Scalping: Lev 20x, TP 0.03%, haute fréquence")
    print("  5. Breakout Prob: Breakout de range + volume")
    print("\nChacune avec approche probabiliste unique!")
