#!/usr/bin/env python3
"""
Analyseur de corrélation Pattern-Performance pour optimiser les signaux IA
Analyse les trades historiques pour identifier les paramètres optimaux
"""

import json
import numpy as np
from datetime import datetime
from collections import defaultdict
from typing import Dict, List, Tuple

def load_trade_history(file_path: str = "trade_history.json") -> List[Dict]:
    """Charge l'historique des trades"""
    try:
        with open(file_path, 'r') as f:
            return json.load(f)
    except Exception as e:
        print(f"❌ Erreur lecture trade_history: {e}")
        return []

def analyze_pattern_performance(trades: List[Dict]) -> Dict:
    """Analyse détaillée des performances par pattern"""
    
    pattern_stats = defaultdict(lambda: {
        'total': 0,
        'wins': 0,
        'losses': 0,
        'pnl_list': [],
        'win_pnl': [],
        'loss_pnl': [],
        'durations': [],
        'by_exit_reason': defaultdict(int)
    })
    
    for trade in trades:
        pattern = trade.get('pattern', 'UNKNOWN')
        pnl_pct = trade.get('pnl_pct', 0)
        reason = trade.get('reason', 'unknown')
        
        # Calcul durée si disponible
        duration_min = 0
        if 'entry_time' in trade and 'exit_time' in trade:
            try:
                entry = datetime.fromisoformat(trade['entry_time'])
                exit = datetime.fromisoformat(trade['exit_time'])
                duration_min = (exit - entry).total_seconds() / 60
            except:
                pass
        
        stats = pattern_stats[pattern]
        stats['total'] += 1
        stats['pnl_list'].append(pnl_pct)
        stats['durations'].append(duration_min)
        stats['by_exit_reason'][reason] += 1
        
        if pnl_pct > 0:
            stats['wins'] += 1
            stats['win_pnl'].append(pnl_pct)
        else:
            stats['losses'] += 1
            stats['loss_pnl'].append(pnl_pct)
    
    # Calcul métriques finales
    results = {}
    for pattern, stats in pattern_stats.items():
        if stats['total'] == 0:
            continue
            
        win_rate = (stats['wins'] / stats['total']) * 100
        avg_pnl = np.mean(stats['pnl_list'])
        avg_win = np.mean(stats['win_pnl']) if stats['win_pnl'] else 0
        avg_loss = np.mean(stats['loss_pnl']) if stats['loss_pnl'] else 0
        avg_duration = np.mean(stats['durations']) if stats['durations'] else 0
        
        # Profit factor
        total_wins = sum(stats['win_pnl']) if stats['win_pnl'] else 0
        total_losses = abs(sum(stats['loss_pnl'])) if stats['loss_pnl'] else 0
        profit_factor = total_wins / total_losses if total_losses > 0 else float('inf')
        
        # Quick-exit rate (indicateur de mauvais timing)
        quick_exits = stats['by_exit_reason'].get('quick-exit', 0)
        quick_exit_rate = (quick_exits / stats['total']) * 100
        
        results[pattern] = {
            'total_trades': stats['total'],
            'wins': stats['wins'],
            'losses': stats['losses'],
            'win_rate': round(win_rate, 2),
            'avg_pnl': round(avg_pnl, 3),
            'avg_win': round(avg_win, 3),
            'avg_loss': round(avg_loss, 3),
            'profit_factor': round(profit_factor, 2),
            'avg_duration_min': round(avg_duration, 1),
            'quick_exit_rate': round(quick_exit_rate, 1),
            'exit_reasons': dict(stats['by_exit_reason']),
            'quality_score': calculate_quality_score(win_rate, avg_pnl, profit_factor, quick_exit_rate)
        }
    
    return dict(sorted(results.items(), key=lambda x: x[1]['quality_score'], reverse=True))

def calculate_quality_score(win_rate: float, avg_pnl: float, profit_factor: float, quick_exit_rate: float) -> float:
    """Score de qualité composite (0-100)"""
    # Win rate contribue 40%
    wr_score = min(win_rate / 50 * 40, 40)
    
    # Avg PnL contribue 30%
    pnl_score = min(max(avg_pnl, 0) / 1.5 * 30, 30)
    
    # Profit factor contribue 20%
    pf_score = min(profit_factor / 3 * 20, 20)
    
    # Quick-exit pénalise (moins c'est mieux)
    qe_penalty = (quick_exit_rate / 100) * 10
    
    return max(0, wr_score + pnl_score + pf_score - qe_penalty)

def identify_optimal_parameters(trades: List[Dict], pattern_stats: Dict) -> Dict:
    """Identifie les paramètres optimaux basés sur les données"""
    
    # Patterns performants vs sous-performants
    good_patterns = [p for p, s in pattern_stats.items() if s['win_rate'] >= 60]
    bad_patterns = [p for p, s in pattern_stats.items() if s['win_rate'] < 40 and s['total_trades'] >= 3]
    
    # Analyse des quick-exits pour identifier timing problématique
    quick_exit_patterns = [p for p, s in pattern_stats.items() if s['quick_exit_rate'] > 60]
    
    recommendations = {
        'excellent_patterns': good_patterns,
        'problematic_patterns': bad_patterns,
        'high_quick_exit_patterns': quick_exit_patterns,
        'parameter_adjustments': []
    }
    
    # Recommandations spécifiques par pattern
    for pattern, stats in pattern_stats.items():
        if stats['total_trades'] < 3:
            continue  # Pas assez de données
        
        adjustments = []
        
        # EARLY_BREAKOUT sous-performe massivement
        if pattern == 'EARLY_BREAKOUT' and stats['win_rate'] < 20:
            adjustments.append({
                'pattern': pattern,
                'issue': f"Win rate catastrophique: {stats['win_rate']}%",
                'current_problem': 'Achète APRÈS la remontée (trop tard)',
                'solution': 'DÉSACTIVER ou remplacer par CREUX_REBOUND_EARLY',
                'impact': 'HIGH',
                'code_change': 'Bloquer pattern ou augmenter score minimum à 80+'
            })
        
        # POSSIBLE avec faible win rate
        if pattern == 'POSSIBLE' and stats['win_rate'] < 40:
            adjustments.append({
                'pattern': pattern,
                'issue': f"Win rate faible: {stats['win_rate']}% (trop permissif)",
                'current_problem': 'Critères trop larges, accepte signaux médiocres',
                'solution': 'Augmenter score minimum de 65 à 75',
                'impact': 'MEDIUM',
                'code_change': 'ai_predictor.py: score_threshold POSSIBLE 65→75'
            })
        
        # Patterns avec trop de quick-exits
        if stats['quick_exit_rate'] > 70:
            adjustments.append({
                'pattern': pattern,
                'issue': f"Quick-exit: {stats['quick_exit_rate']}% (mauvais timing)",
                'current_problem': 'Entre trop tôt ou dans mauvaises conditions',
                'solution': 'Renforcer critères momentum ou attendre confirmation',
                'impact': 'HIGH',
                'code_change': f'Augmenter momentum_min pour {pattern}'
            })
        
        # Patterns excellents à favoriser
        if stats['win_rate'] >= 70 and stats['total_trades'] >= 2:
            adjustments.append({
                'pattern': pattern,
                'issue': f"EXCELLENT pattern: {stats['win_rate']}% win rate!",
                'current_problem': 'Pas assez utilisé (seulement {stats["total_trades"]} trades)',
                'solution': 'AUGMENTER priorité et assouplir légèrement critères',
                'impact': 'HIGH',
                'code_change': f'Bonus score +5 pour {pattern}, assouplir seuils 5-10%'
            })
        
        if adjustments:
            recommendations['parameter_adjustments'].extend(adjustments)
    
    return recommendations

def generate_config_changes(recommendations: Dict) -> List[str]:
    """Génère les changements de config à appliquer"""
    
    changes = []
    
    # Changements dans config.py
    changes.append("# ============================================")
    changes.append("# CHANGEMENTS RECOMMANDÉS - config.py")
    changes.append("# ============================================\n")
    
    # Si EARLY_BREAKOUT est catastrophique
    if 'EARLY_BREAKOUT' in recommendations['problematic_patterns']:
        changes.append("# 🔴 EARLY_BREAKOUT: Win rate 0% - DÉSACTIVER")
        changes.append("PATTERN_MIN_SCORE_EARLY_BREAKOUT = 85  # Augmenté de 65 à 85 (quasi-bloqué)")
        changes.append("")
    
    # Si POSSIBLE trop permissif
    if any('POSSIBLE' in adj['pattern'] for adj in recommendations['parameter_adjustments']):
        changes.append("# ⚠️ POSSIBLE: Win rate faible - RENFORCER")
        changes.append("PATTERN_MIN_SCORE_POSSIBLE = 75  # Augmenté de 65 à 75")
        changes.append("")
    
    # Favoriser patterns excellents
    for pattern in recommendations['excellent_patterns']:
        changes.append(f"# ✅ {pattern}: Excellent win rate - FAVORISER")
        changes.append(f"# Bonus score +5, critères assouplis")
        changes.append("")
    
    # Changements dans ai_predictor.py
    changes.append("\n# ============================================")
    changes.append("# CHANGEMENTS RECOMMANDÉS - ai_predictor.py")
    changes.append("# ============================================\n")
    
    for adj in recommendations['parameter_adjustments']:
        if adj['impact'] == 'HIGH':
            changes.append(f"# {adj['pattern']}: {adj['issue']}")
            changes.append(f"# Solution: {adj['solution']}")
            changes.append(f"# Code: {adj['code_change']}")
            changes.append("")
    
    return changes

def main():
    print("=" * 80)
    print("🔍 ANALYSE CORRÉLATION PATTERN-PERFORMANCE")
    print("=" * 80)
    
    # Charger données
    trades = load_trade_history()
    if not trades:
        print("❌ Aucun trade trouvé")
        return
    
    print(f"\n📊 {len(trades)} trades analysés\n")
    
    # Analyser performances
    pattern_stats = analyze_pattern_performance(trades)
    
    print("\n" + "=" * 80)
    print("📈 PERFORMANCES PAR PATTERN (triés par qualité)")
    print("=" * 80)
    
    for pattern, stats in pattern_stats.items():
        color = '\033[92m' if stats['win_rate'] >= 60 else '\033[91m' if stats['win_rate'] < 40 else '\033[93m'
        reset = '\033[0m'
        
        print(f"\n{color}▶ {pattern}{reset} (Quality Score: {stats['quality_score']:.1f}/100)")
        print(f"  Trades: {stats['total_trades']} | Wins: {stats['wins']} | Losses: {stats['losses']}")
        print(f"  Win Rate: {stats['win_rate']}%")
        print(f"  P&L Moyen: {stats['avg_pnl']:+.2f}% | Gains: {stats['avg_win']:+.2f}% | Pertes: {stats['avg_loss']:+.2f}%")
        print(f"  Profit Factor: {stats['profit_factor']:.2f}")
        print(f"  Durée Moy: {stats['avg_duration_min']:.0f} min")
        print(f"  Quick-Exit: {stats['quick_exit_rate']}%")
        print(f"  Sorties: {stats['exit_reasons']}")
    
    # Recommandations
    recommendations = identify_optimal_parameters(trades, pattern_stats)
    
    print("\n" + "=" * 80)
    print("🎯 RECOMMANDATIONS")
    print("=" * 80)
    
    if recommendations['excellent_patterns']:
        print(f"\n✅ PATTERNS EXCELLENTS (≥60% win rate):")
        for p in recommendations['excellent_patterns']:
            s = pattern_stats[p]
            print(f"  • {p}: {s['win_rate']}% win rate, {s['avg_pnl']:+.2f}% avg")
            print(f"    → FAVORISER: Augmenter priorité, assouplir critères")
    
    if recommendations['problematic_patterns']:
        print(f"\n🔴 PATTERNS PROBLÉMATIQUES (<40% win rate):")
        for p in recommendations['problematic_patterns']:
            s = pattern_stats[p]
            print(f"  • {p}: {s['win_rate']}% win rate, {s['avg_pnl']:+.2f}% avg")
            print(f"    → DÉSACTIVER ou RENFORCER critères drastiquement")
    
    if recommendations['high_quick_exit_patterns']:
        print(f"\n⚠️ PATTERNS AVEC TROP DE QUICK-EXITS (>60%):")
        for p in recommendations['high_quick_exit_patterns']:
            s = pattern_stats[p]
            print(f"  • {p}: {s['quick_exit_rate']}% quick-exit rate")
            print(f"    → Mauvais timing d'entrée, renforcer momentum/confirmation")
    
    print("\n" + "=" * 80)
    print("🔧 AJUSTEMENTS DÉTAILLÉS")
    print("=" * 80)
    
    for adj in recommendations['parameter_adjustments']:
        icon = '🔴' if adj['impact'] == 'HIGH' else '⚠️'
        print(f"\n{icon} {adj['pattern']}")
        print(f"  Problème: {adj['issue']}")
        print(f"  Cause: {adj['current_problem']}")
        print(f"  Solution: {adj['solution']}")
        print(f"  Code: {adj['code_change']}")
    
    # Sauvegarder résultats
    output = {
        'timestamp': datetime.now().isoformat(),
        'total_trades': len(trades),
        'pattern_stats': pattern_stats,
        'recommendations': recommendations
    }
    
    with open('pattern_performance_analysis.json', 'w') as f:
        json.dump(output, f, indent=2)
    
    # Générer changements config
    config_changes = generate_config_changes(recommendations)
    
    with open('PATTERN_OPTIMIZATION_RECOMMENDATIONS.txt', 'w', encoding='utf-8') as f:
        f.write('\n'.join(config_changes))
    
    print("\n" + "=" * 80)
    print("✅ ANALYSE TERMINÉE")
    print("=" * 80)
    print(f"📄 Résultats détaillés: pattern_performance_analysis.json")
    print(f"📄 Recommandations config: PATTERN_OPTIMIZATION_RECOMMENDATIONS.txt")
    print("=" * 80)

if __name__ == "__main__":
    main()
