"""
Strategy Analyzer Module
Main class for analyzing trading strategy performance
"""

import threading
from datetime import datetime
from typing import List, Optional, Dict, Callable
from collections import defaultdict
import math

from hyperliquid_monitor_plus.core_types import Trade
from hyperliquid_monitor_plus.pnl.types import PnLRecord, PortfolioPnL
from hyperliquid_monitor_plus.strategy.types import (
    StrategyMetrics,
    TradePattern,
    StrategyComparison,
    TimeAnalysis,
    StrategyRecommendation,
    PatternType,
    RecommendationType
)


class StrategyAnalyzer:
    """
    Analyzes trading strategy performance and provides insights
    
    Features:
    - Calculate comprehensive performance metrics
    - Identify trading patterns
    - Analyze time-based performance
    - Generate improvement recommendations
    - Compare multiple strategies
    
    Thread-safe implementation using RLock
    """
    
    def __init__(
        self,
        strategy_name: str = "Default Strategy",
        analysis_callback: Optional[Callable[[StrategyMetrics], None]] = None
    ):
        """
        Initialize Strategy Analyzer
        
        Args:
            strategy_name: Name identifier for this strategy
            analysis_callback: Optional callback when analysis is complete
        """
        self._strategy_name = strategy_name
        self._analysis_callback = analysis_callback
        self._lock = threading.RLock()
        
        # Storage
        self._pnl_records: List[PnLRecord] = []
        self._trades: List[Trade] = []
        self._latest_metrics: Optional[StrategyMetrics] = None
    
    @property
    def strategy_name(self) -> str:
        """Get strategy name"""
        return self._strategy_name
    
    @strategy_name.setter
    def strategy_name(self, value: str):
        """Set strategy name"""
        with self._lock:
            self._strategy_name = value
    
    def add_pnl_record(self, record: PnLRecord) -> None:
        """
        Add a PnL record for analysis
        
        Args:
            record: PnL record to add
        """
        with self._lock:
            self._pnl_records.append(record)
    
    def add_pnl_records(self, records: List[PnLRecord]) -> None:
        """
        Add multiple PnL records for analysis
        
        Args:
            records: List of PnL records to add
        """
        with self._lock:
            self._pnl_records.extend(records)
    
    def add_trade(self, trade: Trade) -> None:
        """
        Add a trade for analysis
        
        Args:
            trade: Trade to add
        """
        with self._lock:
            self._trades.append(trade)
    
    def add_trades(self, trades: List[Trade]) -> None:
        """
        Add multiple trades for analysis
        
        Args:
            trades: List of trades to add
        """
        with self._lock:
            self._trades.extend(trades)
    
    def load_from_portfolio(self, portfolio: PortfolioPnL) -> None:
        """
        Load PnL records from a PortfolioPnL object
        
        Args:
            portfolio: Portfolio PnL data
        """
        with self._lock:
            self._pnl_records.clear()
            for coin_pnl in portfolio.coin_pnls.values():
                self._pnl_records.extend(coin_pnl.pnl_history)
    
    def clear(self) -> None:
        """Clear all stored data"""
        with self._lock:
            self._pnl_records.clear()
            self._trades.clear()
            self._latest_metrics = None
    
    def analyze(self) -> StrategyMetrics:
        """
        Perform comprehensive strategy analysis
        
        Returns:
            StrategyMetrics with all calculated metrics
        """
        with self._lock:
            if not self._pnl_records:
                return StrategyMetrics(
                    strategy_name=self._strategy_name,
                    analysis_timestamp=datetime.now()
                )
            
            # Sort records by timestamp
            sorted_records = sorted(self._pnl_records, key=lambda r: r.timestamp)
            
            # Initialize metrics
            metrics = StrategyMetrics(
                strategy_name=self._strategy_name,
                analysis_timestamp=datetime.now()
            )
            
            # Basic counts and PnL
            self._calculate_basic_metrics(metrics, sorted_records)
            
            # Performance ratios
            self._calculate_performance_ratios(metrics)
            
            # Risk metrics (drawdown, etc.)
            self._calculate_risk_metrics(metrics, sorted_records)
            
            # Streak analysis
            self._calculate_streaks(metrics, sorted_records)
            
            # Coin analysis
            self._calculate_coin_metrics(metrics, sorted_records)
            
            # Time analysis
            metrics.time_analysis = self._analyze_time_patterns(sorted_records)
            
            # Pattern recognition
            metrics.identified_patterns = self._identify_patterns(metrics, sorted_records)
            if metrics.identified_patterns:
                metrics.primary_pattern = metrics.identified_patterns[0].pattern_type
            
            # Date range
            metrics.start_date = sorted_records[0].timestamp
            metrics.end_date = sorted_records[-1].timestamp
            
            # Store latest metrics
            self._latest_metrics = metrics
            
            # Callback if set
            if self._analysis_callback:
                self._analysis_callback(metrics)
            
            return metrics
    
    def _calculate_basic_metrics(
        self,
        metrics: StrategyMetrics,
        records: List[PnLRecord]
    ) -> None:
        """Calculate basic trade counts and PnL metrics"""
        gross_profit = 0.0
        gross_loss = 0.0
        total_fees = 0.0
        total_volume = 0.0
        trade_values = []
        
        for record in records:
            pnl = record.pnl
            trade_value = record.size * record.entry_price
            trade_values.append(trade_value)
            total_volume += trade_value
            total_fees += record.fee
            
            if pnl > 0:
                metrics.winning_trades += 1
                gross_profit += pnl
                if pnl > metrics.largest_win:
                    metrics.largest_win = pnl
            elif pnl < 0:
                metrics.losing_trades += 1
                gross_loss += abs(pnl)
                if abs(pnl) > metrics.largest_loss:
                    metrics.largest_loss = abs(pnl)
            else:
                metrics.break_even_trades += 1
        
        metrics.total_trades = len(records)
        metrics.gross_profit = gross_profit
        metrics.gross_loss = gross_loss
        metrics.net_profit = gross_profit - gross_loss
        metrics.total_fees = total_fees
        metrics.total_volume = total_volume
        
        if trade_values:
            metrics.avg_trade_value = sum(trade_values) / len(trade_values)
            metrics.avg_trade_size = sum(r.size for r in records) / len(records)
    
    def _calculate_performance_ratios(self, metrics: StrategyMetrics) -> None:
        """Calculate performance ratios"""
        # Win rate
        total_decided = metrics.winning_trades + metrics.losing_trades
        if total_decided > 0:
            metrics.win_rate = (metrics.winning_trades / total_decided) * 100
        
        # Profit factor
        if metrics.gross_loss > 0:
            metrics.profit_factor = metrics.gross_profit / metrics.gross_loss
        elif metrics.gross_profit > 0:
            metrics.profit_factor = float('inf')
        
        # Average win/loss
        if metrics.winning_trades > 0:
            metrics.avg_win = metrics.gross_profit / metrics.winning_trades
        if metrics.losing_trades > 0:
            metrics.avg_loss = metrics.gross_loss / metrics.losing_trades
        
        # Risk/Reward ratio
        if metrics.avg_loss > 0:
            metrics.risk_reward_ratio = metrics.avg_win / metrics.avg_loss
        elif metrics.avg_win > 0:
            metrics.risk_reward_ratio = float('inf')
        
        # Expectancy (expected value per trade)
        if total_decided > 0:
            win_prob = metrics.winning_trades / total_decided
            loss_prob = metrics.losing_trades / total_decided
            metrics.expectancy = (win_prob * metrics.avg_win) - (loss_prob * metrics.avg_loss)
    
    def _calculate_risk_metrics(
        self,
        metrics: StrategyMetrics,
        records: List[PnLRecord]
    ) -> None:
        """Calculate risk metrics including drawdown and ratios"""
        if not records:
            return
        
        # Build equity curve
        equity = 0.0
        equity_curve = []
        peak = 0.0
        max_drawdown = 0.0
        returns = []
        negative_returns = []
        
        for record in records:
            equity += record.pnl
            equity_curve.append(equity)
            
            # Track returns for Sharpe/Sortino
            returns.append(record.pnl)
            if record.pnl < 0:
                negative_returns.append(record.pnl)
            
            # Update peak and drawdown
            if equity > peak:
                peak = equity
            
            drawdown = peak - equity
            if drawdown > max_drawdown:
                max_drawdown = drawdown
        
        metrics.equity_curve = equity_curve
        metrics.max_drawdown = max_drawdown
        
        # Max drawdown percentage
        if peak > 0:
            metrics.max_drawdown_percentage = (max_drawdown / peak) * 100
        
        # Recovery factor
        if max_drawdown > 0:
            metrics.recovery_factor = metrics.net_profit / max_drawdown
        elif metrics.net_profit > 0:
            metrics.recovery_factor = float('inf')
        
        # Sharpe Ratio (simplified - assuming risk-free rate = 0)
        if len(returns) > 1:
            avg_return = sum(returns) / len(returns)
            variance = sum((r - avg_return) ** 2 for r in returns) / (len(returns) - 1)
            std_dev = math.sqrt(variance) if variance > 0 else 0
            if std_dev > 0:
                metrics.sharpe_ratio = avg_return / std_dev
        
        # Sortino Ratio (uses downside deviation)
        if len(negative_returns) > 1:
            avg_return = sum(returns) / len(returns)
            downside_variance = sum(r ** 2 for r in negative_returns) / len(negative_returns)
            downside_dev = math.sqrt(downside_variance) if downside_variance > 0 else 0
            if downside_dev > 0:
                metrics.sortino_ratio = avg_return / downside_dev
        
        # Calmar Ratio
        if max_drawdown > 0 and metrics.trade_duration_days > 0:
            annualized_return = (metrics.net_profit / metrics.trade_duration_days) * 365
            metrics.calmar_ratio = annualized_return / max_drawdown
    
    def _calculate_streaks(
        self,
        metrics: StrategyMetrics,
        records: List[PnLRecord]
    ) -> None:
        """Calculate win/loss streaks"""
        if not records:
            return
        
        current_streak = 0
        current_type = None
        max_wins = 0
        max_losses = 0
        
        for record in records:
            if record.pnl > 0:
                if current_type == "WIN":
                    current_streak += 1
                else:
                    current_streak = 1
                    current_type = "WIN"
                max_wins = max(max_wins, current_streak)
            elif record.pnl < 0:
                if current_type == "LOSS":
                    current_streak += 1
                else:
                    current_streak = 1
                    current_type = "LOSS"
                max_losses = max(max_losses, current_streak)
        
        metrics.max_consecutive_wins = max_wins
        metrics.max_consecutive_losses = max_losses
        metrics.current_streak = current_streak
        metrics.current_streak_type = current_type
    
    def _calculate_coin_metrics(
        self,
        metrics: StrategyMetrics,
        records: List[PnLRecord]
    ) -> None:
        """Calculate per-coin performance metrics"""
        coin_pnl: Dict[str, float] = defaultdict(float)
        coin_trades: Dict[str, int] = defaultdict(int)
        
        for record in records:
            coin_pnl[record.coin] += record.pnl
            coin_trades[record.coin] += 1
        
        metrics.coins_traded = list(coin_pnl.keys())
        metrics.coin_performance = dict(coin_pnl)
        
        if coin_trades:
            metrics.most_traded_coin = max(coin_trades.keys(), key=lambda c: coin_trades[c])
        
        if coin_pnl:
            metrics.most_profitable_coin = max(coin_pnl.keys(), key=lambda c: coin_pnl[c])
            metrics.least_profitable_coin = min(coin_pnl.keys(), key=lambda c: coin_pnl[c])
    
    def _analyze_time_patterns(self, records: List[PnLRecord]) -> TimeAnalysis:
        """Analyze performance by time of day and day of week"""
        analysis = TimeAnalysis()
        
        hour_pnl: Dict[int, float] = defaultdict(float)
        day_pnl: Dict[int, float] = defaultdict(float)
        hours_active = set()
        
        for record in records:
            hour = record.timestamp.hour
            day = record.timestamp.weekday()
            
            hour_pnl[hour] += record.pnl
            day_pnl[day] += record.pnl
            hours_active.add(hour)
        
        analysis.hour_of_day = dict(hour_pnl)
        analysis.day_of_week = dict(day_pnl)
        analysis.total_active_hours = len(hours_active)
        
        if hour_pnl:
            analysis.best_hour = max(hour_pnl.keys(), key=lambda h: hour_pnl[h])
            analysis.worst_hour = min(hour_pnl.keys(), key=lambda h: hour_pnl[h])
        
        if day_pnl:
            analysis.best_day = max(day_pnl.keys(), key=lambda d: day_pnl[d])
            analysis.worst_day = min(day_pnl.keys(), key=lambda d: day_pnl[d])
        
        return analysis
    
    def _identify_patterns(
        self,
        metrics: StrategyMetrics,
        records: List[PnLRecord]
    ) -> List[TradePattern]:
        """Identify trading patterns from metrics and records"""
        patterns = []
        
        # Analyze trade sizes
        sizes = [r.size for r in records]
        avg_size = sum(sizes) / len(sizes) if sizes else 0
        size_variance = sum((s - avg_size) ** 2 for s in sizes) / len(sizes) if sizes else 0
        
        # Scalping pattern (many small, quick trades)
        if metrics.total_trades > 20 and metrics.trades_per_day > 5:
            if avg_size < 1.0:  # Small position sizes
                patterns.append(TradePattern(
                    pattern_type=PatternType.SCALPING,
                    confidence=min(90, 50 + metrics.trades_per_day * 5),
                    description="High frequency, small position trades typical of scalping",
                    supporting_metrics={
                        "trades_per_day": metrics.trades_per_day,
                        "avg_size": avg_size
                    },
                    sample_trades_count=metrics.total_trades
                ))
        
        # Swing trading pattern
        elif 0.5 <= metrics.trades_per_day <= 3:
            patterns.append(TradePattern(
                pattern_type=PatternType.SWING,
                confidence=70,
                description="Moderate frequency trades typical of swing trading",
                supporting_metrics={
                    "trades_per_day": metrics.trades_per_day
                },
                sample_trades_count=metrics.total_trades
            ))
        
        # Position trading (low frequency, larger positions)
        elif metrics.trades_per_day < 0.5:
            patterns.append(TradePattern(
                pattern_type=PatternType.POSITION,
                confidence=75,
                description="Low frequency, longer-term position trading",
                supporting_metrics={
                    "trades_per_day": metrics.trades_per_day
                },
                sample_trades_count=metrics.total_trades
            ))
        
        # Momentum pattern (high win rate, but need to check trend alignment)
        if metrics.win_rate > 55 and metrics.profit_factor > 1.5:
            patterns.append(TradePattern(
                pattern_type=PatternType.MOMENTUM,
                confidence=60 + min(20, metrics.win_rate - 55),
                description="High win rate suggests momentum-following approach",
                supporting_metrics={
                    "win_rate": metrics.win_rate,
                    "profit_factor": metrics.profit_factor
                },
                sample_trades_count=metrics.total_trades
            ))
        
        # Mean reversion pattern (lower win rate but good R:R)
        if metrics.win_rate < 45 and metrics.risk_reward_ratio > 2.0:
            patterns.append(TradePattern(
                pattern_type=PatternType.MEAN_REVERSION,
                confidence=65,
                description="Lower win rate with high risk/reward typical of mean reversion",
                supporting_metrics={
                    "win_rate": metrics.win_rate,
                    "risk_reward_ratio": metrics.risk_reward_ratio
                },
                sample_trades_count=metrics.total_trades
            ))
        
        # Sort by confidence
        patterns.sort(key=lambda p: p.confidence, reverse=True)
        
        return patterns
    
    def get_recommendations(self) -> List[StrategyRecommendation]:
        """
        Generate recommendations for improving the strategy
        
        Returns:
            List of prioritized recommendations
        """
        with self._lock:
            if not self._latest_metrics:
                self.analyze()
            
            if not self._latest_metrics:
                return []
            
            metrics = self._latest_metrics
            recommendations = []
            
            # Risk management recommendations
            if metrics.max_drawdown_percentage > 20:
                recommendations.append(StrategyRecommendation(
                    recommendation_type=RecommendationType.RISK_MANAGEMENT,
                    priority=1,
                    title="Reduce Maximum Drawdown",
                    description=f"Current max drawdown is {metrics.max_drawdown_percentage:.1f}%. "
                               f"Consider implementing stricter stop-losses or reducing position sizes "
                               f"to keep drawdown below 20%.",
                    expected_impact="Improved capital preservation and psychological comfort",
                    metrics_affected=["max_drawdown", "recovery_factor"]
                ))
            
            # Win rate recommendations
            if metrics.win_rate < 40:
                recommendations.append(StrategyRecommendation(
                    recommendation_type=RecommendationType.ENTRY_STRATEGY,
                    priority=2,
                    title="Improve Entry Timing",
                    description=f"Win rate of {metrics.win_rate:.1f}% is below optimal. "
                               f"Review entry criteria and consider adding confirmation signals.",
                    expected_impact="Higher percentage of winning trades",
                    metrics_affected=["win_rate", "profit_factor"]
                ))
            
            # Risk/Reward recommendations
            if metrics.risk_reward_ratio < 1.5:
                recommendations.append(StrategyRecommendation(
                    recommendation_type=RecommendationType.EXIT_STRATEGY,
                    priority=2,
                    title="Improve Risk/Reward Ratio",
                    description=f"Current R:R is {metrics.risk_reward_ratio:.2f}. "
                               f"Consider wider profit targets or tighter stop-losses "
                               f"to achieve at least 1.5:1 ratio.",
                    expected_impact="Better profitability per trade",
                    metrics_affected=["risk_reward_ratio", "expectancy"]
                ))
            
            # Largest loss recommendations
            if metrics.largest_loss > metrics.avg_win * 3:
                recommendations.append(StrategyRecommendation(
                    recommendation_type=RecommendationType.RISK_MANAGEMENT,
                    priority=1,
                    title="Limit Maximum Loss Per Trade",
                    description=f"Largest loss (${metrics.largest_loss:.2f}) is significantly "
                               f"larger than average win (${metrics.avg_win:.2f}). "
                               f"Implement strict stop-losses to prevent outsized losses.",
                    expected_impact="More consistent returns and better drawdown control",
                    metrics_affected=["max_drawdown", "avg_loss"]
                ))
            
            # Consecutive losses
            if metrics.max_consecutive_losses >= 5:
                recommendations.append(StrategyRecommendation(
                    recommendation_type=RecommendationType.RISK_MANAGEMENT,
                    priority=2,
                    title="Implement Loss Limit Rules",
                    description=f"Max consecutive losses is {metrics.max_consecutive_losses}. "
                               f"Consider implementing a daily or weekly loss limit to prevent "
                               f"overtrading during drawdowns.",
                    expected_impact="Better capital preservation during losing streaks",
                    metrics_affected=["max_consecutive_losses", "max_drawdown"]
                ))
            
            # Diversification
            if len(metrics.coins_traded) == 1:
                recommendations.append(StrategyRecommendation(
                    recommendation_type=RecommendationType.DIVERSIFICATION,
                    priority=3,
                    title="Consider Diversification",
                    description="Currently trading only one coin. "
                               "Diversifying across multiple assets can reduce overall risk.",
                    expected_impact="Reduced portfolio volatility",
                    metrics_affected=["max_drawdown", "sharpe_ratio"]
                ))
            
            # Time analysis recommendations
            if metrics.time_analysis:
                ta = metrics.time_analysis
                if ta.worst_hour is not None and ta.hour_of_day.get(ta.worst_hour, 0) < -100:
                    recommendations.append(StrategyRecommendation(
                        recommendation_type=RecommendationType.TIMING,
                        priority=3,
                        title="Avoid Worst Performing Hours",
                        description=f"Hour {ta.worst_hour}:00 has significant losses. "
                                   f"Consider avoiding trading during this time.",
                        expected_impact="Improved overall performance",
                        metrics_affected=["net_profit", "win_rate"]
                    ))
            
            # Profit factor recommendation
            if 0 < metrics.profit_factor < 1.0:
                recommendations.append(StrategyRecommendation(
                    recommendation_type=RecommendationType.EXIT_STRATEGY,
                    priority=1,
                    title="Strategy Needs Fundamental Review",
                    description=f"Profit factor of {metrics.profit_factor:.2f} indicates "
                               f"losses exceed profits. Fundamental strategy review needed.",
                    expected_impact="Move from losing to profitable",
                    metrics_affected=["profit_factor", "net_profit"]
                ))
            
            # Sort by priority
            recommendations.sort(key=lambda r: r.priority)
            
            return recommendations
    
    def get_summary_report(self) -> str:
        """
        Generate a text summary report of the strategy analysis
        
        Returns:
            Formatted string report
        """
        with self._lock:
            if not self._latest_metrics:
                self.analyze()
            
            if not self._latest_metrics:
                return "No data available for analysis."
            
            m = self._latest_metrics
            
            report = []
            report.append("=" * 60)
            report.append(f"STRATEGY ANALYSIS REPORT: {m.strategy_name}")
            report.append("=" * 60)
            report.append("")
            
            # Overall Performance
            report.append("📊 OVERALL PERFORMANCE")
            report.append("-" * 40)
            report.append(f"Grade: {m.get_grade()}")
            report.append(f"Total Trades: {m.total_trades}")
            report.append(f"Net Profit: ${m.net_profit:,.2f}")
            report.append(f"Total Fees: ${m.total_fees:,.2f}")
            report.append(f"Net After Fees: ${m.net_profit_after_fees:,.2f}")
            report.append("")
            
            # Win/Loss Stats
            report.append("🎯 WIN/LOSS STATISTICS")
            report.append("-" * 40)
            report.append(f"Winning Trades: {m.winning_trades}")
            report.append(f"Losing Trades: {m.losing_trades}")
            report.append(f"Win Rate: {m.win_rate:.1f}%")
            report.append(f"Profit Factor: {m.profit_factor:.2f}")
            report.append(f"Risk/Reward: {m.risk_reward_ratio:.2f}")
            report.append(f"Expectancy: ${m.expectancy:.2f}")
            report.append("")
            
            # Trade Statistics
            report.append("💰 TRADE STATISTICS")
            report.append("-" * 40)
            report.append(f"Average Win: ${m.avg_win:.2f}")
            report.append(f"Average Loss: ${m.avg_loss:.2f}")
            report.append(f"Largest Win: ${m.largest_win:.2f}")
            report.append(f"Largest Loss: ${m.largest_loss:.2f}")
            report.append(f"Avg Trade Value: ${m.avg_trade_value:.2f}")
            report.append("")
            
            # Risk Metrics
            report.append("⚠️ RISK METRICS")
            report.append("-" * 40)
            report.append(f"Max Drawdown: ${m.max_drawdown:.2f} ({m.max_drawdown_percentage:.1f}%)")
            report.append(f"Recovery Factor: {m.recovery_factor:.2f}")
            report.append(f"Sharpe Ratio: {m.sharpe_ratio:.2f}")
            report.append(f"Sortino Ratio: {m.sortino_ratio:.2f}")
            report.append(f"Max Consecutive Wins: {m.max_consecutive_wins}")
            report.append(f"Max Consecutive Losses: {m.max_consecutive_losses}")
            report.append("")
            
            # Coin Performance
            if m.coin_performance:
                report.append("🪙 COIN PERFORMANCE")
                report.append("-" * 40)
                report.append(f"Coins Traded: {', '.join(m.coins_traded)}")
                report.append(f"Most Traded: {m.most_traded_coin}")
                report.append(f"Most Profitable: {m.most_profitable_coin}")
                report.append(f"Least Profitable: {m.least_profitable_coin}")
                report.append("")
            
            # Time Analysis
            if m.time_analysis and m.time_analysis.best_hour is not None:
                report.append("⏰ TIME ANALYSIS")
                report.append("-" * 40)
                report.append(f"Best Hour: {m.time_analysis.best_hour}:00")
                report.append(f"Worst Hour: {m.time_analysis.worst_hour}:00")
                if m.time_analysis.best_day_name:
                    report.append(f"Best Day: {m.time_analysis.best_day_name}")
                    report.append(f"Worst Day: {m.time_analysis.worst_day_name}")
                report.append("")
            
            # Patterns
            if m.identified_patterns:
                report.append("🔍 IDENTIFIED PATTERNS")
                report.append("-" * 40)
                for pattern in m.identified_patterns[:3]:
                    report.append(f"• {pattern.pattern_type.value.title()} "
                                f"(Confidence: {pattern.confidence:.0f}%)")
                    report.append(f"  {pattern.description}")
                report.append("")
            
            # Date Range
            if m.start_date and m.end_date:
                report.append("📅 ANALYSIS PERIOD")
                report.append("-" * 40)
                report.append(f"Start: {m.start_date.strftime('%Y-%m-%d %H:%M')}")
                report.append(f"End: {m.end_date.strftime('%Y-%m-%d %H:%M')}")
                report.append(f"Duration: {m.trade_duration_days} days")
                report.append(f"Trades/Day: {m.trades_per_day:.1f}")
                report.append("")
            
            report.append("=" * 60)
            
            return "\n".join(report)
    
    @staticmethod
    def compare_strategies(
        strategies: List["StrategyAnalyzer"]
    ) -> StrategyComparison:
        """
        Compare multiple strategies
        
        Args:
            strategies: List of StrategyAnalyzer instances
            
        Returns:
            StrategyComparison with comparison results
        """
        comparison = StrategyComparison(
            comparison_timestamp=datetime.now()
        )
        
        # Analyze each strategy
        for analyzer in strategies:
            metrics = analyzer.analyze()
            comparison.strategies.append(metrics)
        
        if not comparison.strategies:
            return comparison
        
        # Find best by each key metric
        metrics_list = comparison.strategies
        
        # Best by net profit
        best_profit = max(metrics_list, key=lambda m: m.net_profit)
        comparison.best_by_metric["net_profit"] = best_profit.strategy_name
        
        # Best by win rate
        best_win_rate = max(metrics_list, key=lambda m: m.win_rate)
        comparison.best_by_metric["win_rate"] = best_win_rate.strategy_name
        
        # Best by profit factor
        best_pf = max(metrics_list, key=lambda m: m.profit_factor if m.profit_factor != float('inf') else 0)
        comparison.best_by_metric["profit_factor"] = best_pf.strategy_name
        
        # Best by risk/reward
        best_rr = max(metrics_list, key=lambda m: m.risk_reward_ratio if m.risk_reward_ratio != float('inf') else 0)
        comparison.best_by_metric["risk_reward"] = best_rr.strategy_name
        
        # Best by Sharpe ratio
        best_sharpe = max(metrics_list, key=lambda m: m.sharpe_ratio)
        comparison.best_by_metric["sharpe_ratio"] = best_sharpe.strategy_name
        
        # Best by drawdown (lowest is best)
        best_dd = min(metrics_list, key=lambda m: m.max_drawdown_percentage)
        comparison.best_by_metric["lowest_drawdown"] = best_dd.strategy_name
        
        # Overall best (by net profit)
        comparison.best_overall = best_profit.strategy_name
        
        # Generate summary
        summary_lines = [
            f"Compared {len(strategies)} strategies.",
            f"Best Overall (Net Profit): {comparison.best_overall}",
            "",
            "Best by Metric:",
        ]
        
        for metric, name in comparison.best_by_metric.items():
            summary_lines.append(f"  • {metric}: {name}")
        
        comparison.summary = "\n".join(summary_lines)
        
        return comparison
    
    def get_latest_metrics(self) -> Optional[StrategyMetrics]:
        """Get the latest calculated metrics"""
        with self._lock:
            return self._latest_metrics
    
    def get_pnl_records_count(self) -> int:
        """Get the number of PnL records"""
        with self._lock:
            return len(self._pnl_records)
    
    def get_trades_count(self) -> int:
        """Get the number of trades"""
        with self._lock:
            return len(self._trades)
