#!/usr/bin/env python3
"""
OPTIMISEUR LLM MODE - Optimisation intelligente des paramètres martingale

Au lieu de tester toutes les combinaisons (force brute), on:
1. Part de la config gagnante
2. Teste des variations intelligentes
3. Apprend de chaque résultat
4. Converge vers l'optimum

Comme un LLM qui affine ses poids!
"""

from martingale_backtester import MartingaleBacktester
from true_martingale import TrueMartingaleStrategy
import numpy as np
import json
from datetime import datetime

print("=" * 80)
print("🧠 OPTIMISEUR LLM MODE - RECHERCHE INTELLIGENTE")
print("=" * 80)

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

# ============ ESPACE DE RECHERCHE ============

# Config gagnante comme point de départ
BEST_KNOWN = {
    'base_position_size': 5.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
}

# Plages de recherche autour du best
SEARCH_SPACE = {
    'base_position_size': [2, 3, 4, 5, 6, 7, 8, 10],  # $
    'max_martingale_level': [4, 5, 6, 7, 8],  # Niveaux
    'base_leverage': [10, 15, 20, 25, 30, 40, 50],  # x
    'max_leverage': [500, 750, 1000],  # x
    'stop_loss_pct': [0.002, 0.0025, 0.003, 0.0035, 0.004],  # %
    'take_profit_ratio': [2.0, 2.5, 3.0, 3.5, 4.0],  # ratio
}

def test_config(config, iteration):
    """Teste une config et retourne les métriques"""
    print(f"\n{'=' * 80}")
    print(f"🧪 ITERATION {iteration}")
    print(f"{'=' * 80}")
    print(f"Position: ${config['base_position_size']} | Max Level: {config['max_martingale_level']} | "
          f"Lev: {config['base_leverage']}x→{config['max_leverage']}x | "
          f"SL: {config['stop_loss_pct']*100:.2f}% | TP ratio: {config['take_profit_ratio']}")

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

    if result:
        metrics = {
            'config': config.copy(),
            '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
        }

        # Score composite pour l'optimisation
        # On veut: ROI élevé, DD faible, PF > 1
        score = (
            metrics['roi'] * 2.0 +  # ROI est le plus important
            (100 - abs(metrics['max_dd'])) * 0.5 +  # Pénalise DD
            metrics['profit_factor'] * 10.0 +  # Bonus si PF > 1
            (metrics['win_rate'] * 100) * 0.3  # Bonus WR
        )

        metrics['score'] = score

        status = "✅ PROFITABLE" if metrics['roi'] > 0 else "❌ Perte"
        print(f"📊 ROI: {metrics['roi']:+.2f}% | DD: {metrics['max_dd']:.2f}% | "
              f"PF: {metrics['profit_factor']:.2f} | Score: {score:.2f} {status}")

        return metrics

    return None

def smart_search():
    """Recherche intelligente des meilleurs paramètres"""

    all_results = []

    # ============ PHASE 1: Test config de base ============
    print("\n" + "🔍 PHASE 1: TEST CONFIG GAGNANTE")
    print("=" * 80)

    baseline = test_config(BEST_KNOWN, 1)
    all_results.append(baseline)
    best_score = baseline['score']
    best_config = BEST_KNOWN.copy()

    print(f"\n🎯 Baseline: ROI {baseline['roi']:+.2f}% | Score {best_score:.2f}")

    # ============ PHASE 2: Optimisation par dimension ============
    print("\n\n🔍 PHASE 2: OPTIMISATION PAR DIMENSION")
    print("=" * 80)

    iteration = 2
    improved = True
    current_config = best_config.copy()

    # On va faire plusieurs passes, tant qu'on améliore
    for pass_num in range(3):  # Max 3 passes
        if not improved:
            break

        improved = False
        print(f"\n🔄 PASSE {pass_num + 1}")

        # Tester chaque dimension
        for param_name, param_values in SEARCH_SPACE.items():
            print(f"\n📐 Optimisation: {param_name}")

            best_for_param = None
            best_score_for_param = best_score

            # Tester chaque valeur de ce paramètre
            for value in param_values:
                # Skip si c'est la valeur actuelle
                if value == current_config[param_name]:
                    continue

                # Test config avec cette variation
                test_cfg = current_config.copy()
                test_cfg[param_name] = value

                result = test_config(test_cfg, iteration)
                iteration += 1

                if result and result['score'] > best_score_for_param:
                    best_score_for_param = result['score']
                    best_for_param = value
                    all_results.append(result)

            # Si on a trouvé mieux, mettre à jour
            if best_for_param is not None:
                old_value = current_config[param_name]
                current_config[param_name] = best_for_param
                best_score = best_score_for_param
                improved = True
                print(f"   ✨ Amélioration! {param_name}: {old_value} → {best_for_param} "
                      f"(Score: {best_score:.2f})")
            else:
                print(f"   ⏭️  Pas mieux, on garde {param_name}={current_config[param_name]}")

    # ============ PHASE 3: Recherche locale fine ============
    print("\n\n🔍 PHASE 3: RECHERCHE LOCALE FINE")
    print("=" * 80)

    # Affiner position_size autour de la meilleure
    best_pos = current_config['base_position_size']
    fine_positions = [
        best_pos * 0.9,
        best_pos * 0.95,
        best_pos * 1.05,
        best_pos * 1.1
    ]

    for pos in fine_positions:
        if pos < 1 or pos > 15:  # Limites raisonnables
            continue

        test_cfg = current_config.copy()
        test_cfg['base_position_size'] = round(pos, 2)

        result = test_config(test_cfg, iteration)
        iteration += 1

        if result and result['score'] > best_score:
            best_score = result['score']
            current_config['base_position_size'] = test_cfg['base_position_size']
            all_results.append(result)
            print(f"   ✨ Amélioration fine! Position: ${test_cfg['base_position_size']:.2f}")

    # ============ RÉSULTATS ============

    print("\n\n" + "=" * 80)
    print("🏆 CLASSEMENT TOP 10")
    print("=" * 80)

    all_results.sort(key=lambda x: x['score'], reverse=True)
    top_results = all_results[:10]

    print(f"\n{'#':<3} {'ROI %':>8} {'DD %':>7} {'PF':>5} {'WR %':>6} {'Score':>8} {'Config':<50}")
    print("-" * 100)

    for rank, res in enumerate(top_results, 1):
        cfg = res['config']
        status = "✅" if res['roi'] > 0 else "❌"
        config_str = f"Pos:${cfg['base_position_size']:.1f} Lv:{cfg['max_martingale_level']} " \
                     f"Leg:{cfg['base_leverage']}→{cfg['max_leverage']}"

        print(f"{rank:<3} {res['roi']:>7.2f}% {res['max_dd']:>6.2f}% "
              f"{res['profit_factor']:>5.2f} {res['win_rate']*100:>5.1f}% "
              f"{res['score']:>8.2f} {config_str:<50} {status}")

    # Meilleure config
    best = top_results[0]

    print(f"\n\n{'=' * 80}")
    print(f"🏆 MEILLEURE CONFIG OPTIMISÉE")
    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"   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']}")
    print(f"   Score:         {best['score']:.2f}")

    print(f"\n⚙️  PARAMÈTRES:")
    cfg = best['config']
    print(f"   Position de base:    ${cfg['base_position_size']:.2f}")
    print(f"   Max martingale:      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"   TP Ratio:            {cfg['take_profit_ratio']:.1f}x")
    print(f"   Min Signal Score:    {cfg['min_signal_score']}")

    # Gain vs baseline
    gain = best['roi'] - baseline['roi']
    if gain > 0:
        print(f"\n🎉 AMÉLIORATION: +{gain:.2f}% vs baseline!")
        print(f"   Baseline: {baseline['roi']:+.2f}%")
        print(f"   Optimisé: {best['roi']:+.2f}%")

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

    # Sauvegarder
    with open('llm_optimization_results.json', 'w') as f:
        json.dump({
            'best_config': best['config'],
            'best_metrics': {
                'roi': best['roi'],
                'capital': best['capital'],
                'win_rate': best['win_rate'],
                'profit_factor': best['profit_factor'],
                'max_dd': best['max_dd'],
                'trades': best['trades'],
                'score': best['score']
            },
            'top_10': top_results,
            'all_results': all_results,
            'baseline': baseline,
            'improvement_pct': gain,
            'timestamp': datetime.now().isoformat()
        }, f, indent=2, default=str)

    print(f"\n💾 Résultats sauvegardés: llm_optimization_results.json")

    # Générer code Python pour la meilleure config
    print(f"\n📝 CODE POUR UTILISER LA MEILLEURE CONFIG:")
    print("=" * 80)
    print(f"""
from true_martingale import TrueMartingaleStrategy

strategy = TrueMartingaleStrategy(
    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={cfg['min_signal_score']}
)

# ROI attendu: {best['roi']:+.2f}%
# Win Rate: {best['win_rate']*100:.1f}%
# Profit Factor: {best['profit_factor']:.2f}
""")
    print("=" * 80)

    return best

if __name__ == "__main__":
    best_config = smart_search()
