#!/usr/bin/env python3
"""
EDGE MATHÉMATIQUE PUR - Sans indicateurs techniques

Hypothèse: Si la martingale fonctionne mathématiquement, on n'a pas besoin de TA.
On cherche un edge purement probabiliste/mathématique.

Stratégies testées:
1. RANDOM - 50/50 LONG/SHORT aléatoire
2. ALWAYS LONG - Crypto monte sur le long terme
3. ALWAYS SHORT - Pour tester l'inverse
4. MEAN REVERSION - Trade contre le mouvement précédent
5. MOMENTUM - Trade dans la direction du mouvement
6. VOLATILITY BREAKOUT - Trade les cassures de volatilité
7. PRICE EXTREMES - Trade aux extrêmes de prix (percentiles)
8. TIME OF DAY - Trade seulement à certaines heures
9. ALTERNATING - Alterne LONG/SHORT systématiquement
10. AFTER RED/GREEN - LONG après rouge, SHORT après vert
"""

from martingale_backtester import MartingaleBacktester
from true_martingale import TrueMartingaleStrategy
import pandas as pd
import numpy as np
from typing import Optional, Tuple
from dataclasses import dataclass

@dataclass
class MartingaleSignal:
    timestamp: pd.Timestamp
    side: str
    entry_price: float
    stop_loss: float
    take_profit: float
    leverage: int
    position_size_usd: float
    martingale_level: int
    signal_score: float
    strategy: str

class PureMathStrategy(TrueMartingaleStrategy):
    """Stratégie basée sur des règles mathématiques pures, sans TA"""

    def __init__(self, math_rule='random', **kwargs):
        super().__init__(**kwargs)
        self.math_rule = math_rule
        self.trade_count = 0
        self.last_side = None
        np.random.seed(42)  # Reproductibilité

    def generate_base_signal(self, df: pd.DataFrame) -> Optional[Tuple[str, float]]:
        """
        Génère un signal basé UNIQUEMENT sur des règles mathématiques
        Pas d'indicateurs techniques!
        """
        current = df.iloc[-1]

        # ============ 1. RANDOM (50/50) ============
        if self.math_rule == 'random':
            side = 'LONG' if np.random.random() > 0.5 else 'SHORT'
            return (side, 1.0)

        # ============ 2. ALWAYS LONG ============
        if self.math_rule == 'always_long':
            return ('LONG', 1.0)

        # ============ 3. ALWAYS SHORT ============
        if self.math_rule == 'always_short':
            return ('SHORT', 1.0)

        # ============ 4. MEAN REVERSION ============
        if self.math_rule == 'mean_reversion':
            # Trade CONTRE le dernier mouvement
            if len(df) < 2:
                return ('LONG', 1.0)

            prev = df.iloc[-2]
            last_move = (current['close'] - prev['close']) / prev['close']

            # Si prix monte → SHORT (reversion attendue)
            # Si prix baisse → LONG (reversion attendue)
            if last_move > 0:
                return ('SHORT', 1.0)
            else:
                return ('LONG', 1.0)

        # ============ 5. MOMENTUM ============
        if self.math_rule == 'momentum':
            # Trade DANS la direction du mouvement
            if len(df) < 2:
                return ('LONG', 1.0)

            prev = df.iloc[-2]
            last_move = (current['close'] - prev['close']) / prev['close']

            if last_move > 0:
                return ('LONG', 1.0)
            else:
                return ('SHORT', 1.0)

        # ============ 6. VOLATILITY BREAKOUT ============
        if self.math_rule == 'volatility_breakout':
            if len(df) < 20:
                return ('LONG', 1.0)

            # Calculer volatilité des 20 dernières bougies
            returns = df['close'].pct_change().tail(20)
            volatility = returns.std()
            last_move = (current['close'] - df.iloc[-2]['close']) / df.iloc[-2]['close']

            # Trade si mouvement > 1.5x la volatilité normale
            if abs(last_move) > volatility * 1.5:
                # Trade dans la direction du breakout
                if last_move > 0:
                    return ('LONG', 1.0)
                else:
                    return ('SHORT', 1.0)

            return None  # Pas de breakout

        # ============ 7. PRICE EXTREMES (Percentiles) ============
        if self.math_rule == 'price_extremes':
            if len(df) < 100:
                return ('LONG', 1.0)

            # Prix actuel vs percentiles des 100 dernières bougies
            recent_prices = df['close'].tail(100)
            p10 = recent_prices.quantile(0.1)
            p90 = recent_prices.quantile(0.9)

            # Acheter aux extrêmes bas, vendre aux extrêmes hauts
            if current['close'] <= p10:
                return ('LONG', 1.0)  # Prix très bas → acheter
            elif current['close'] >= p90:
                return ('SHORT', 1.0)  # Prix très haut → vendre

            return None  # Prix neutre

        # ============ 8. TIME OF DAY ============
        if self.math_rule == 'time_of_day':
            hour = current['timestamp'].hour

            # Trade seulement pendant les heures "volatiles"
            # 14h-16h UTC (ouverture US) et 22h-00h UTC (pics crypto)
            if 14 <= hour < 16:
                return ('LONG', 1.0)
            elif 22 <= hour < 24:
                return ('SHORT', 1.0)

            return None  # Pas l'heure

        # ============ 9. ALTERNATING ============
        if self.math_rule == 'alternating':
            # Alterne systématiquement LONG/SHORT
            side = 'SHORT' if self.last_side == 'LONG' else 'LONG'
            self.last_side = side
            return (side, 1.0)

        # ============ 10. AFTER RED/GREEN CANDLE ============
        if self.math_rule == 'candle_color':
            if len(df) < 2:
                return ('LONG', 1.0)

            # Bougie précédente
            prev = df.iloc[-2]
            is_green = prev['close'] > prev['open']

            # LONG après bougie rouge, SHORT après bougie verte
            # (pari sur continuation/reversion)
            if is_green:
                return ('SHORT', 1.0)
            else:
                return ('LONG', 1.0)

        # ============ 11. FIXED INTERVALS ============
        if self.math_rule == 'fixed_interval':
            # Trade tous les N bougies
            if self.trade_count % 50 == 0:  # Tous les 50 trades
                return ('LONG', 1.0)
            return None

        # ============ 12. RANGE BOUND ============
        if self.math_rule == 'range_bound':
            if len(df) < 50:
                return ('LONG', 1.0)

            # Support/Résistance simples
            recent = df.tail(50)
            support = recent['low'].min()
            resistance = recent['high'].max()
            mid = (support + resistance) / 2

            # Acheter au support, vendre à la résistance
            if current['close'] <= support * 1.001:
                return ('LONG', 1.0)
            elif current['close'] >= resistance * 0.999:
                return ('SHORT', 1.0)

            return None

        # Par défaut: random
        return ('LONG' if np.random.random() > 0.5 else 'SHORT', 1.0)

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

print("=" * 80)
print("🎲 RECHERCHE D'EDGE MATHÉMATIQUE PUR - SANS TA")
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")

# Config optimale trouvée précédemment
OPTIMAL_CONFIG = {
    'base_position_size': 11.0,
    'max_martingale_level': 6,
    'base_leverage': 20,
    'max_leverage': 1000,
    'stop_loss_pct': 0.003,
    'take_profit_ratio': 3.0,
    'min_signal_score': 0.6
}

# Stratégies mathématiques à tester
math_strategies = [
    'random',
    'always_long',
    'always_short',
    'mean_reversion',
    'momentum',
    'volatility_breakout',
    'price_extremes',
    'time_of_day',
    'alternating',
    'candle_color',
    'fixed_interval',
    'range_bound'
]

results = []

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

    config = OPTIMAL_CONFIG.copy()

    strategy = PureMathStrategy(
        math_rule=rule,
        **config
    )

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

    if result:
        results.append({
            'rule': rule,
            'roi': result.total_return_pct,
            'win_rate': result.win_rate,
            'profit_factor': result.profit_factor,
            'trades': result.total_trades,
            'max_dd': result.max_drawdown_pct,
            'capital': result.final_capital,
            'avg_win': result.avg_win_pct,
            'avg_loss': result.avg_loss_pct
        })
    else:
        results.append({
            'rule': rule,
            'roi': 0,
            'win_rate': 0,
            'profit_factor': 0,
            'trades': 0,
            'max_dd': 0,
            'capital': 1000
        })

# ============ CLASSEMENT ============

print("\n\n" + "=" * 80)
print("🏆 CLASSEMENT EDGES MATHÉMATIQUES PURS")
print("=" * 80)

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

print(f"\n{'RANG':<5} {'RÈGLE MATHÉMATIQUE':<25} {'ROI %':>10} {'WR %':>8} {'PF':>6} "
      f"{'Trades':>7} {'DD %':>8} {'Cap $':>10}")
print("-" * 90)

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'] > -2 else "❌"

    print(f"{emoji:<5} {res['rule']:<25} {res['roi']:>9.2f}% {res['win_rate']*100:>7.1f}% "
          f"{res['profit_factor']:>5.2f} {res['trades']:>7} "
          f"{res['max_dd']:>7.2f}% {res['capital']:>9.2f} {status}")

# Meilleure stratégie
best = results[0]

print(f"\n\n{'=' * 80}")
print(f"🏆 MEILLEURE RÈGLE MATHÉMATIQUE: {best['rule'].upper().replace('_', ' ')}")
print(f"{'=' * 80}")
print(f"\n📊 PERFORMANCE:")
print(f"   ROI:           {best['roi']:+.2f}% {'✅ PROFITABLE!' if best['roi'] > 0 else '❌'}")
print(f"   Capital final: ${best['capital']:.2f}")
print(f"   Gain:          ${best['capital'] - 1000:.2f}")
print(f"   Win Rate:      {best['win_rate']*100:.1f}%")
print(f"   Profit Factor: {best['profit_factor']:.2f}")
print(f"   Max DD:        {best['max_dd']:.2f}%")
print(f"   Trades:        {best['trades']}")

if best['trades'] > 0:
    print(f"\n💰 TRADES:")
    print(f"   Gain moyen:    {best['avg_win']:+.2f}%")
    print(f"   Perte moyenne: {best['avg_loss']:+.2f}%")

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

# Comparaison avec TA
print(f"\n📊 COMPARAISON AVEC TA:")
print(f"   TA (RSI/EMA/MACD): ROI +3.49%, WR 41.7%")
print(f"   Math Pure ({best['rule']}): ROI {best['roi']:+.2f}%, WR {best['win_rate']*100:.1f}%")

if best['roi'] > 3.49:
    improvement = best['roi'] - 3.49
    print(f"\n🎉 MATH PURE EST MEILLEURE! +{improvement:.2f}%")
elif best['win_rate'] > 0.417:
    print(f"\n✨ MEILLEUR WIN RATE! {best['win_rate']*100:.1f}% vs 41.7%")

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

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

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