#!/usr/bin/env python3
"""
OPTIMISEUR PRICE EXTREMES - La stratégie la plus prometteuse!

PF: 19.99 (gain moyen 20x la perte!)
ROI: +3.45%
WR: 54%
DD: -0.06%

Principe:
- Acheter quand prix <= percentile bas (ex: 10%)
- Vendre quand prix >= percentile haut (ex: 90%)
- Mean reversion basique mais TRÈS efficace

On optimise:
1. Percentiles (5/95, 10/90, 15/85, etc.)
2. Lookback period (50, 100, 200 bougies)
3. Paramètres martingale
"""

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

# Créer une version customizable de PriceExtremes
class OptimizedPriceExtremes(TrueMartingaleStrategy):
    """Version optimisée de Price Extremes avec paramètres ajustables"""

    def __init__(self, percentile_low=10, percentile_high=90, lookback=100, **kwargs):
        super().__init__(**kwargs)
        self.percentile_low = percentile_low
        self.percentile_high = percentile_high
        self.lookback = lookback

    def generate_base_signal(self, df: pd.DataFrame) -> Optional[Tuple[str, float]]:
        """Generate signal based on price percentiles"""
        current = df.iloc[-1]

        if len(df) < self.lookback:
            return None

        # Prix actuel vs percentiles
        recent_prices = df['close'].tail(self.lookback)
        p_low = recent_prices.quantile(self.percentile_low / 100.0)
        p_high = recent_prices.quantile(self.percentile_high / 100.0)

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

        return None  # Prix neutre

print("=" * 80)
print("🎯 OPTIMISEUR PRICE EXTREMES - Stratégie PF 19.99")
print("=" * 80)

# Fetch data
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")

# ============ GRILLE D'OPTIMISATION ============

print("🔬 PHASE 1: OPTIMISATION PERCENTILES & LOOKBACK")
print("=" * 80)

# Test percentiles
percentile_configs = [
    (5, 95),    # Très extrêmes
    (10, 90),   # Baseline (celui qui marche)
    (15, 85),   # Moins extrêmes
    (20, 80),   # Modérés
    (25, 75),   # Larges
]

lookback_periods = [50, 100, 150, 200]

# Paramètres martingale de base (on optimisera après)
base_martingale_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.0
}

phase1_results = []

test_num = 0
total_tests = len(percentile_configs) * len(lookback_periods)

for p_low, p_high in percentile_configs:
    for lookback in lookback_periods:
        test_num += 1

        print(f"\r🧪 Test {test_num}/{total_tests} | P{p_low}/{p_high} LB{lookback}",
              end="", flush=True)

        try:
            strategy = OptimizedPriceExtremes(
                percentile_low=p_low,
                percentile_high=p_high,
                lookback=lookback,
                **base_martingale_config
            )

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

            if result and result.total_trades > 0:
                phase1_results.append({
                    'percentile_low': p_low,
                    'percentile_high': p_high,
                    'lookback': lookback,
                    '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
                })
        except:
            pass

print("\n\n" + "=" * 80)
print("🏆 TOP 10 COMBINAISONS PERCENTILES/LOOKBACK")
print("=" * 80)

if not phase1_results:
    print("\n❌ Aucun résultat en Phase 1! Arrêt.")
    exit(1)

phase1_results.sort(key=lambda x: x['profit_factor'], reverse=True)
top_10_phase1 = phase1_results[:10]

print(f"\n{'#':<3} {'P-Low':>6} {'P-High':>7} {'LB':>5} {'ROI %':>8} {'WR%':>5} "
      f"{'PF':>7} {'Tr':>4} {'DD%':>7} {'Cap $':>10}")
print("-" * 80)

for rank, res in enumerate(top_10_phase1, 1):
    emoji = "🥇" if rank == 1 else "🥈" if rank == 2 else "🥉" if rank == 3 else f"{rank:2}"
    status = "✅" if res['roi'] > 0 else "❌"

    print(f"{emoji:<3} {res['percentile_low']:>6} {res['percentile_high']:>7} "
          f"{res['lookback']:>5} {res['roi']:>7.2f}% {res['win_rate']*100:>4.1f}% "
          f"{res['profit_factor']:>7.2f} {res['trades']:>4} "
          f"{res['max_dd']:>6.2f}% {res['capital']:>9.2f} {status}")

# Meilleure config phase 1
best_p1 = top_10_phase1[0]

print(f"\n✨ MEILLEURE COMBINAISON:")
print(f"   Percentiles: {best_p1['percentile_low']}% / {best_p1['percentile_high']}%")
print(f"   Lookback:    {best_p1['lookback']} bougies")
print(f"   ROI:         {best_p1['roi']:+.2f}%")
print(f"   PF:          {best_p1['profit_factor']:.2f}")
print(f"   Trades:      {best_p1['trades']}")

# ============ PHASE 2: OPTIMISATION MARTINGALE ============

print("\n\n🔬 PHASE 2: OPTIMISATION PARAMÈTRES MARTINGALE")
print("=" * 80)

# Utiliser les meilleurs percentiles trouvés
best_percentiles = {
    'percentile_low': best_p1['percentile_low'],
    'percentile_high': best_p1['percentile_high'],
    'lookback': best_p1['lookback']
}

# Grille martingale
position_sizes = [3, 5, 7, 9, 11, 13, 15]
max_levels = [5, 6, 7, 8]
leverages = [
    (10, 500),
    (15, 750),
    (20, 1000),
    (25, 1000),
]
sl_pcts = [0.002, 0.0025, 0.003, 0.0035, 0.004]
tp_ratios = [2.0, 2.5, 3.0, 3.5, 4.0]

phase2_results = []
test_num = 0

# Smart sampling au lieu de tout tester
num_samples = 100
print(f"🎯 Test de {num_samples} combinaisons intelligentes...\n")

for i in range(num_samples):
    test_num += 1

    # Sample random mais intelligent
    pos_size = np.random.choice(position_sizes)
    max_lv = np.random.choice(max_levels)
    base_lev, max_lev = leverages[np.random.randint(0, len(leverages))]
    sl = np.random.choice(sl_pcts)
    tp = np.random.choice(tp_ratios)

    print(f"\r🧪 Test {test_num}/{num_samples} | Meilleur ROI: "
          f"{max([r['roi'] for r in phase2_results], default=0):+.2f}%",
          end="", flush=True)

    try:
        strategy = OptimizedPriceExtremes(
            **best_percentiles,
            base_position_size=pos_size,
            max_martingale_level=max_lv,
            base_leverage=base_lev,
            max_leverage=max_lev,
            stop_loss_pct=sl,
            take_profit_ratio=tp,
            min_signal_score=0.0
        )

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

        if result and result.total_trades > 0:
            phase2_results.append({
                'config': {
                    **best_percentiles,
                    'base_position_size': pos_size,
                    'max_martingale_level': max_lv,
                    'base_leverage': base_lev,
                    'max_leverage': max_lev,
                    'stop_loss_pct': sl,
                    'take_profit_ratio': tp
                },
                '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,
                'max_consec_losses': result.max_consecutive_losses
            })
    except:
        pass

print("\n\n" + "=" * 80)
print("🏆 TOP 20 CONFIGURATIONS COMPLÈTES")
print("=" * 80)

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

print(f"\n{'#':<3} {'Pos$':>5} {'Lv':>3} {'Leg':>8} {'SL%':>5} {'TP':>4} "
      f"{'ROI%':>7} {'WR%':>5} {'PF':>7} {'DD%':>7} {'Tr':>3}")
print("-" * 85)

for rank, res in enumerate(top_20, 1):
    cfg = res['config']
    emoji = "🥇" if rank == 1 else "🥈" if rank == 2 else "🥉" if rank == 3 else f"{rank:2}"
    status = "✅" if res['roi'] > 0 else "❌"

    lev_str = f"{cfg['base_leverage']}→{cfg['max_leverage']}"

    print(f"{emoji:<3} {cfg['base_position_size']:>5.0f} {cfg['max_martingale_level']:>3} "
          f"{lev_str:>8} {cfg['stop_loss_pct']*100:>4.2f} {cfg['take_profit_ratio']:>4.1f} "
          f"{res['roi']:>6.2f}% {res['win_rate']*100:>4.1f}% "
          f"{res['profit_factor']:>7.2f} {res['max_dd']:>6.2f}% {res['trades']:>3} {status}")

# Meilleur résultat final
best = top_20[0]

print(f"\n\n{'=' * 80}")
print(f"🏆 CONFIGURATION OPTIMALE PRICE EXTREMES")
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 Drawdown:       {best['max_dd']:.2f}%")
print(f"   Trades:             {best['trades']}")
print(f"   Max pertes consec:  {best['max_consec_losses']}")

if best['trades'] > 0:
    print(f"\n💰 STATISTIQUES TRADES:")
    print(f"   Gain moyen:         +{best['avg_win']:.2f}%")
    print(f"   Perte moyenne:      {best['avg_loss']:.2f}%")
    ratio = abs(best['avg_win'] / best['avg_loss']) if best['avg_loss'] != 0 else 0
    print(f"   Ratio Gain/Perte:   {ratio:.2f}x")

cfg = best['config']
print(f"\n⚙️  PARAMÈTRES OPTIMAUX:")
print(f"\n   📐 PERCENTILES:")
print(f"      Percentile BAS:     {cfg['percentile_low']}% (LONG si prix <= P{cfg['percentile_low']})")
print(f"      Percentile HAUT:    {cfg['percentile_high']}% (SHORT si prix >= P{cfg['percentile_high']})")
print(f"      Lookback period:    {cfg['lookback']} bougies")

print(f"\n   💰 MARTINGALE:")
print(f"      Position de base:   ${cfg['base_position_size']:.2f}")
print(f"      Max level:          {cfg['max_martingale_level']} (x{2**cfg['max_martingale_level']})")
print(f"      Leverage:           {cfg['base_leverage']}x → {cfg['max_leverage']}x")
print(f"      Stop Loss:          {cfg['stop_loss_pct']*100:.3f}%")
print(f"      Take Profit:        {cfg['take_profit_ratio']:.1f}x SL")

# Analyse mathématique
max_position = cfg['base_position_size'] * (2 ** cfg['max_martingale_level'])
print(f"\n🧮 ANALYSE MATHÉMATIQUE:")
print(f"   Position max:       ${max_position:.2f}")
print(f"   Marge sécurité:     {(1000 / max_position):.2f}x")
print(f"   Proba ruine:        {(0.5 ** (cfg['max_martingale_level'] + 1)) * 100:.4f}%")

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

# Code Python
print(f"\n📝 CODE POUR UTILISER:")
print("=" * 80)
print(f"""
from optimize_price_extremes import OptimizedPriceExtremes

strategy = OptimizedPriceExtremes(
    # Percentiles
    percentile_low={cfg['percentile_low']},
    percentile_high={cfg['percentile_high']},
    lookback={cfg['lookback']},

    # Martingale
    base_position_size={cfg['base_position_size']},
    max_martingale_level={cfg['max_martingale_level']},
    base_leverage={cfg['base_leverage']},
    max_leverage={cfg['max_leverage']},
    stop_loss_pct={cfg['stop_loss_pct']},
    take_profit_ratio={cfg['take_profit_ratio']},
    min_signal_score=0.0
)

# STATISTIQUES:
# ROI: {best['roi']:+.2f}%
# Win Rate: {best['win_rate']*100:.1f}%
# Profit Factor: {best['profit_factor']:.2f}
# Max DD: {best['max_dd']:.2f}%

# LOGIQUE:
# LONG  si prix <= percentile {cfg['percentile_low']}% des {cfg['lookback']} dernières bougies
# SHORT si prix >= percentile {cfg['percentile_high']}% des {cfg['lookback']} dernières bougies
# Sinon: rien (on attend les extrêmes)
""")
print("=" * 80)

# Sauvegarder
with open('price_extremes_optimized.json', 'w') as f:
    json.dump({
        'best_config': best['config'],
        'best_metrics': best,
        'top_20': top_20,
        'phase1_results': phase1_results,
        'phase2_results': phase2_results
    }, f, indent=2, default=str)

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

# Stats globales
profitable = [r for r in phase2_results if r['roi'] > 0]
print(f"\n📈 STATISTIQUES GLOBALES:")
print(f"   Configs testées:     {len(phase2_results)}")
print(f"   Configs profitables: {len(profitable)} ({len(profitable)/len(phase2_results)*100:.1f}%)")
if profitable:
    avg_roi = np.mean([r['roi'] for r in profitable])
    avg_pf = np.mean([r['profit_factor'] for r in profitable])
    print(f"   ROI moyen:           +{avg_roi:.2f}%")
    print(f"   PF moyen:            {avg_pf:.2f}")

print(f"\n{'=' * 80}")
print("🎉 OPTIMISATION TERMINÉE!")
print(f"{'=' * 80}")
