//! Performance analytics and metrics for backtesting
//!
//! Provides comprehensive performance analysis including returns, risk metrics,
//! drawdown analysis, and statistical measures for strategy evaluation.

use std::collections::HashMap;

use anyhow::Result;
use chrono::{DateTime, Datelike, Duration as ChronoDuration, TimeZone, Utc};
use serde::{Deserialize, Serialize};
use statrs::statistics::Statistics;
use tracing::info;

use common::Symbol;
use rust_decimal::Decimal;
use rust_decimal::MathematicalOps;

use crate::strategy_tester::{PerformanceSnapshot, TradeRecord};

/// Comprehensive performance analytics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceAnalytics {
    /// Basic return metrics
    pub returns: ReturnMetrics,
    /// Risk metrics
    pub risk: RiskMetrics,
    /// Drawdown analysis
    pub drawdown: DrawdownMetrics,
    /// Trade statistics
    pub trade_stats: TradeStatistics,
    /// Benchmark comparison
    pub benchmark: Option<BenchmarkComparison>,
    /// Portfolio metrics
    pub portfolio: PortfolioMetrics,
    /// Time-based analysis
    pub time_analysis: TimeAnalysis,
}

/// Return-based metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReturnMetrics {
    /// Total return
    pub total_return: Decimal,
    /// Annualized return
    pub annualized_return: Decimal,
    /// Compound annual growth rate (CAGR)
    pub cagr: Decimal,
    /// Daily returns
    pub daily_returns: Vec<Decimal>,
    /// Monthly returns
    pub monthly_returns: Vec<Decimal>,
    /// Best single day return
    pub best_day: Decimal,
    /// Worst single day return
    pub worst_day: Decimal,
    /// Average daily return
    pub avg_daily_return: Decimal,
    /// Median daily return
    pub median_daily_return: Decimal,
    /// Return standard deviation
    pub return_std: Decimal,
    /// Skewness of returns
    pub skewness: Decimal,
    /// Kurtosis of returns
    pub kurtosis: Decimal,
}

/// Risk-based metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiskMetrics {
    /// Sharpe ratio
    pub sharpe_ratio: Decimal,
    /// Sortino ratio
    pub sortino_ratio: Decimal,
    /// Calmar ratio
    pub calmar_ratio: Decimal,
    /// Value at Risk (VaR) 95%
    pub var_95: Decimal,
    /// Value at Risk (VaR) 99%
    pub var_99: Decimal,
    /// Conditional Value at Risk (CVaR) 95%
    pub cvar_95: Decimal,
    /// Maximum consecutive losses
    pub max_consecutive_losses: u32,
    /// Beta (if benchmark provided)
    pub beta: Option<Decimal>,
    /// Alpha (if benchmark provided)
    pub alpha: Option<Decimal>,
    /// Tracking error (if benchmark provided)
    pub tracking_error: Option<Decimal>,
    /// Information ratio (if benchmark provided)
    pub information_ratio: Option<Decimal>,
}

/// Drawdown analysis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DrawdownMetrics {
    /// Maximum drawdown
    pub max_drawdown: Decimal,
    /// Current drawdown
    pub current_drawdown: Decimal,
    /// Average drawdown
    pub avg_drawdown: Decimal,
    /// Maximum drawdown duration (days)
    pub max_drawdown_duration: i64,
    /// Current drawdown duration (days)
    pub current_drawdown_duration: i64,
    /// Recovery time from max drawdown (days)
    pub recovery_time: Option<i64>,
    /// Drawdown periods
    pub drawdown_periods: Vec<DrawdownPeriod>,
    /// Underwater curve
    pub underwater_curve: Vec<(DateTime<Utc>, Decimal)>,
}

/// Individual drawdown period
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DrawdownPeriod {
    /// Start date of drawdown
    pub start_date: DateTime<Utc>,
    /// End date of drawdown
    pub end_date: Option<DateTime<Utc>>,
    /// Peak value before drawdown
    pub peak_value: Decimal,
    /// Trough value during drawdown
    pub trough_value: Decimal,
    /// Maximum drawdown during period
    pub max_drawdown: Decimal,
    /// Duration in days
    pub duration: i64,
    /// Recovery date
    pub recovery_date: Option<DateTime<Utc>>,
}

/// Trade-based statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TradeStatistics {
    /// Total number of trades
    pub total_trades: u64,
    /// Winning trades
    pub winning_trades: u64,
    /// Losing trades
    pub losing_trades: u64,
    /// Win rate
    pub win_rate: Decimal,
    /// Average trade return
    pub avg_trade_return: Decimal,
    /// Average winning trade
    pub avg_winning_trade: Decimal,
    /// Average losing trade
    pub avg_losing_trade: Decimal,
    /// Best trade return
    pub best_trade: Decimal,
    /// Worst trade return
    pub worst_trade: Decimal,
    /// Profit factor
    pub profit_factor: Decimal,
    /// Average trade duration
    pub avg_trade_duration: ChronoDuration,
    /// Trades per symbol
    pub trades_per_symbol: HashMap<Symbol, u64>,
    /// Monthly trade count
    pub monthly_trade_count: Vec<(DateTime<Utc>, u64)>,
}

/// Portfolio-level metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PortfolioMetrics {
    /// Initial capital
    pub initial_capital: Decimal,
    /// Final portfolio value
    pub final_value: Decimal,
    /// Peak portfolio value
    pub peak_value: Decimal,
    /// Average portfolio value
    pub avg_portfolio_value: Decimal,
    /// Total fees paid
    pub total_fees: Decimal,
    /// Total slippage cost
    pub total_slippage: Decimal,
    /// Portfolio turnover
    pub turnover: Decimal,
    /// Average number of positions
    pub avg_positions: Decimal,
    /// Maximum positions held
    pub max_positions: u32,
    /// Cash utilization
    pub cash_utilization: Decimal,
}

/// Time-based analysis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeAnalysis {
    /// Strategy start date
    pub start_date: DateTime<Utc>,
    /// Strategy end date
    pub end_date: DateTime<Utc>,
    /// Total days
    pub total_days: i64,
    /// Trading days
    pub trading_days: i64,
    /// Monthly performance
    pub monthly_performance: Vec<MonthlyPerformance>,
    /// Yearly performance
    pub yearly_performance: Vec<YearlyPerformance>,
    /// Best month
    pub best_month: Decimal,
    /// Worst month
    pub worst_month: Decimal,
    /// Best year
    pub best_year: Decimal,
    /// Worst year
    pub worst_year: Decimal,
}

/// Monthly performance summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MonthlyPerformance {
    /// Month/year
    pub month: DateTime<Utc>,
    /// Return for the month
    pub return_pct: Decimal,
    /// Number of trades
    pub trade_count: u64,
    /// Win rate for the month
    pub win_rate: Decimal,
    /// Portfolio value at month end
    pub portfolio_value: Decimal,
}

/// Yearly performance summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct YearlyPerformance {
    /// Year
    pub year: i32,
    /// Return for the year
    pub return_pct: Decimal,
    /// Number of trades
    pub trade_count: u64,
    /// Win rate for the year
    pub win_rate: Decimal,
    /// Portfolio value at year end
    pub portfolio_value: Decimal,
    /// Maximum drawdown during year
    pub max_drawdown: Decimal,
}

/// Benchmark comparison metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchmarkComparison {
    /// Benchmark name
    pub benchmark_name: String,
    /// Benchmark total return
    pub benchmark_return: Decimal,
    /// Strategy excess return
    pub excess_return: Decimal,
    /// Beta coefficient
    pub beta: Decimal,
    /// Alpha (risk-adjusted excess return)
    pub alpha: Decimal,
    /// Tracking error
    pub tracking_error: Decimal,
    /// Information ratio
    pub information_ratio: Decimal,
    /// Up capture ratio
    pub up_capture: Decimal,
    /// Down capture ratio
    pub down_capture: Decimal,
}

/// Performance metrics calculator
pub struct MetricsCalculator {
    /// Performance snapshots
    snapshots: Vec<PerformanceSnapshot>,
    /// Trade records
    trades: Vec<TradeRecord>,
    /// Benchmark data (if available)
    benchmark_data: Option<Vec<(DateTime<Utc>, Decimal)>>,
    /// Risk-free rate (annualized)
    risk_free_rate: Decimal,
}

impl MetricsCalculator {
    /// Create new metrics calculator
    ///
    /// # Arguments
    /// * `risk_free_rate` - Annual risk-free rate for Sharpe ratio calculations
    pub fn new(risk_free_rate: Decimal) -> Self {
        Self {
            snapshots: Vec::new(),
            trades: Vec::new(),
            benchmark_data: None,
            risk_free_rate,
        }
    }

    /// Add performance snapshot
    ///
    /// # Arguments
    /// * `snapshot` - Performance snapshot to add to the collection
    pub fn add_snapshot(&mut self, snapshot: PerformanceSnapshot) {
        self.snapshots.push(snapshot);
    }

    /// Add trade record
    ///
    /// # Arguments
    /// * `trade` - Trade record to add to the collection
    pub fn add_trade(&mut self, trade: TradeRecord) {
        self.trades.push(trade);
    }

    /// Set benchmark data
    ///
    /// # Arguments
    /// * `benchmark_name` - Name of the benchmark for identification
    ///
    /// * `data` - Time series data of benchmark values as (timestamp, value) pairs
    pub fn set_benchmark(&mut self, _benchmark_name: String, data: Vec<(DateTime<Utc>, Decimal)>) {
        self.benchmark_data = Some(data);
    }

    /// Calculate comprehensive performance analytics
    ///
    /// # Errors
    ///
    /// Returns error if:
    /// - No performance snapshots available
    /// - Return calculation fails
    /// - Risk metrics calculation fails
    /// - Sharpe ratio calculation fails
    /// - Trade analysis fails
    /// - Drawdown analysis fails
    ///
    pub fn calculate_analytics(&self) -> Result<PerformanceAnalytics> {
        if self.snapshots.is_empty() {
            return Err(anyhow::anyhow!("No performance snapshots available"));
        }

        info!(
            "Calculating performance analytics for {} snapshots and {} trades",
            self.snapshots.len(),
            self.trades.len()
        );

        let returns = self.calculate_return_metrics()?;
        let risk = self.calculate_risk_metrics(&returns)?;
        let drawdown = self.calculate_drawdown_metrics()?;
        let trade_stats = self.calculate_trade_statistics()?;
        let benchmark = self.calculate_benchmark_comparison(&returns)?;
        let portfolio = self.calculate_portfolio_metrics()?;
        let time_analysis = self.calculate_time_analysis()?;

        Ok(PerformanceAnalytics {
            returns,
            risk,
            drawdown,
            trade_stats,
            benchmark,
            portfolio,
            time_analysis,
        })
    }

    /// Calculate return-based metrics
    ///
    /// # Returns
    /// * `Result<ReturnMetrics>` - Comprehensive return metrics including total return, volatility, and skewness
    fn calculate_return_metrics(&self) -> Result<ReturnMetrics> {
        let daily_returns = self.calculate_daily_returns()?;

        if daily_returns.is_empty() {
            return Err(anyhow::anyhow!("No daily returns calculated"));
        }

        let total_return = self.calculate_total_return()?;
        let annualized_return = self.calculate_annualized_return(&daily_returns)?;
        let cagr = self.calculate_cagr()?;

        let returns_f64: Vec<f64> = daily_returns
            .iter()
            .map(|d| d.to_string().parse().unwrap_or(0.0))
            .collect();

        let avg_daily_return = if !returns_f64.is_empty() {
            Decimal::from_f64_retain(returns_f64.clone().mean()).unwrap_or_default()
        } else {
            Decimal::ZERO
        };

        let return_std = if returns_f64.len() > 1 {
            Decimal::from_f64_retain(returns_f64.clone().std_dev()).unwrap_or_default()
        } else {
            Decimal::ZERO
        };

        let best_day = daily_returns.iter().max().cloned().unwrap_or_default();
        let worst_day = daily_returns.iter().min().cloned().unwrap_or_default();

        // Calculate median
        let mut sorted_returns = daily_returns.clone();
        sorted_returns.sort();
        let median_daily_return = if !sorted_returns.is_empty() {
            if sorted_returns.len() % 2 == 0 {
                let mid = sorted_returns.len() / 2;
                (sorted_returns[mid - 1] + sorted_returns[mid]) / Decimal::from(2)
            } else {
                sorted_returns[sorted_returns.len() / 2]
            }
        } else {
            Decimal::ZERO
        };

        // Calculate skewness and kurtosis (simplified)
        let skewness = self.calculate_skewness(&returns_f64);
        let kurtosis = self.calculate_kurtosis(&returns_f64);

        let monthly_returns = self.calculate_monthly_returns()?;

        Ok(ReturnMetrics {
            total_return,
            annualized_return,
            cagr,
            daily_returns,
            monthly_returns,
            best_day,
            worst_day,
            avg_daily_return,
            median_daily_return,
            return_std,
            skewness,
            kurtosis,
        })
    }

    /// Calculate risk metrics
    ///
    /// # Arguments
    /// * `returns` - Return metrics used for risk calculations
    ///
    /// # Returns
    /// * `Result<RiskMetrics>` - Risk-adjusted metrics including Sharpe ratio, VaR, and drawdown analysis
    fn calculate_risk_metrics(&self, returns: &ReturnMetrics) -> Result<RiskMetrics> {
        let sharpe_ratio = self.calculate_sharpe_ratio(&returns.daily_returns)?;
        let sortino_ratio = self.calculate_sortino_ratio(&returns.daily_returns)?;
        let calmar_ratio = self.calculate_calmar_ratio(returns.annualized_return)?;

        let (var_95, var_99) = self.calculate_var(&returns.daily_returns)?;
        let cvar_95 = self.calculate_cvar(&returns.daily_returns, Decimal::new(5, 2))?;

        let max_consecutive_losses = self.calculate_max_consecutive_losses()?;

        // Benchmark-related metrics
        let (beta, alpha, tracking_error, information_ratio) = if self.benchmark_data.is_some() {
            self.calculate_benchmark_risk_metrics(&returns.daily_returns)?
        } else {
            (None, None, None, None)
        };

        Ok(RiskMetrics {
            sharpe_ratio,
            sortino_ratio,
            calmar_ratio,
            var_95,
            var_99,
            cvar_95,
            max_consecutive_losses,
            beta,
            alpha,
            tracking_error,
            information_ratio,
        })
    }

    /// Calculate drawdown metrics
    ///
    /// # Returns
    /// * `Result<DrawdownMetrics>` - Comprehensive drawdown analysis including maximum drawdown and recovery times
    fn calculate_drawdown_metrics(&self) -> Result<DrawdownMetrics> {
        let (max_drawdown, current_drawdown, drawdown_periods, underwater_curve) =
            self.calculate_drawdowns()?;

        let avg_drawdown = if !drawdown_periods.is_empty() {
            let sum: Decimal = drawdown_periods.iter().map(|p| p.max_drawdown).sum();
            sum / Decimal::from(drawdown_periods.len())
        } else {
            Decimal::ZERO
        };

        let max_drawdown_duration = drawdown_periods
            .iter()
            .map(|p| p.duration)
            .max()
            .unwrap_or(0);

        let current_drawdown_duration = if let Some(period) = drawdown_periods.last() {
            if period.end_date.is_none() {
                period.duration
            } else {
                0
            }
        } else {
            0
        };

        let recovery_time = drawdown_periods
            .iter()
            .find(|p| p.max_drawdown == max_drawdown)
            .and_then(|p| p.recovery_date)
            .map(|recovery| {
                if let Some(peak_period) = drawdown_periods
                    .iter()
                    .find(|pp| pp.max_drawdown == max_drawdown)
                {
                    (recovery - peak_period.start_date).num_days()
                } else {
                    0
                }
            });

        Ok(DrawdownMetrics {
            max_drawdown,
            current_drawdown,
            avg_drawdown,
            max_drawdown_duration,
            current_drawdown_duration,
            recovery_time,
            drawdown_periods,
            underwater_curve,
        })
    }

    /// Calculate trade statistics
    ///
    /// # Returns
    /// * `Result<TradeStatistics>` - Detailed trade-level statistics including win rate and profit factor
    fn calculate_trade_statistics(&self) -> Result<TradeStatistics> {
        if self.trades.is_empty() {
            return Ok(TradeStatistics {
                total_trades: 0,
                winning_trades: 0,
                losing_trades: 0,
                win_rate: Decimal::ZERO,
                avg_trade_return: Decimal::ZERO,
                avg_winning_trade: Decimal::ZERO,
                avg_losing_trade: Decimal::ZERO,
                best_trade: Decimal::ZERO,
                worst_trade: Decimal::ZERO,
                profit_factor: Decimal::ZERO,
                avg_trade_duration: ChronoDuration::zero(),
                trades_per_symbol: HashMap::new(),
                monthly_trade_count: Vec::new(),
            });
        }

        let total_trades = self.trades.len() as u64;
        let winning_trades = self
            .trades
            .iter()
            .filter(|t| t.return_pct > Decimal::ZERO)
            .count() as u64;
        let losing_trades = total_trades - winning_trades;

        let win_rate = if total_trades > 0 {
            Decimal::from(winning_trades) / Decimal::from(total_trades)
        } else {
            Decimal::ZERO
        };

        let avg_trade_return = if !self.trades.is_empty() {
            let sum: Decimal = self.trades.iter().map(|t| t.return_pct).sum();
            sum / Decimal::from(self.trades.len())
        } else {
            Decimal::ZERO
        };

        let winning_trades_vec: Vec<_> = self
            .trades
            .iter()
            .filter(|t| t.return_pct > Decimal::ZERO)
            .collect();

        let losing_trades_vec: Vec<_> = self
            .trades
            .iter()
            .filter(|t| t.return_pct <= Decimal::ZERO)
            .collect();

        let avg_winning_trade = if !winning_trades_vec.is_empty() {
            let sum: Decimal = winning_trades_vec.iter().map(|t| t.return_pct).sum();
            sum / Decimal::from(winning_trades_vec.len())
        } else {
            Decimal::ZERO
        };

        let avg_losing_trade = if !losing_trades_vec.is_empty() {
            let sum: Decimal = losing_trades_vec.iter().map(|t| t.return_pct).sum();
            sum / Decimal::from(losing_trades_vec.len())
        } else {
            Decimal::ZERO
        };

        let best_trade = self
            .trades
            .iter()
            .map(|t| t.return_pct)
            .max()
            .unwrap_or_default();

        let worst_trade = self
            .trades
            .iter()
            .map(|t| t.return_pct)
            .min()
            .unwrap_or_default();

        let gross_profit: Decimal = winning_trades_vec.iter().map(|t| t.pnl).sum();
        let gross_loss: Decimal = losing_trades_vec.iter().map(|t| t.pnl.abs()).sum();

        let profit_factor = if gross_loss > Decimal::ZERO {
            gross_profit / gross_loss
        } else {
            Decimal::ZERO
        };

        let avg_trade_duration = if !self.trades.is_empty() {
            let total_duration: i64 = self
                .trades
                .iter()
                .map(|t| (t.exit_time - t.entry_time).num_seconds())
                .sum();
            ChronoDuration::seconds(total_duration / self.trades.len() as i64)
        } else {
            ChronoDuration::zero()
        };

        // Calculate trades per symbol
        let mut trades_per_symbol = HashMap::new();
        for trade in &self.trades {
            *trades_per_symbol.entry(trade.symbol.clone()).or_insert(0) += 1;
        }

        // Calculate monthly trade count
        let monthly_trade_count = self.calculate_monthly_trade_count();

        Ok(TradeStatistics {
            total_trades,
            winning_trades,
            losing_trades,
            win_rate,
            avg_trade_return,
            avg_winning_trade,
            avg_losing_trade,
            best_trade,
            worst_trade,
            profit_factor,
            avg_trade_duration,
            trades_per_symbol,
            monthly_trade_count,
        })
    }

    /// Calculate benchmark comparison if available
    ///
    /// # Arguments
    /// * `returns` - Return metrics to compare against benchmark
    ///
    /// # Returns
    /// * `Result<Option<BenchmarkComparison>>` - Benchmark comparison metrics if benchmark data is available
    fn calculate_benchmark_comparison(
        &self,
        returns: &ReturnMetrics,
    ) -> Result<Option<BenchmarkComparison>> {
        let benchmark_data = match &self.benchmark_data {
            Some(data) if !data.is_empty() => data,
            _ => return Ok(None),
        };

        // Extract benchmark name
        let benchmark_name = "benchmark".to_string(); // Default name

        // Calculate benchmark returns
        let mut benchmark_returns = Vec::new();
        for i in 1..benchmark_data.len() {
            let prev_value = benchmark_data[i - 1].1;
            let curr_value = benchmark_data[i].1;
            if prev_value > Decimal::ZERO {
                let return_pct = (curr_value - prev_value) / prev_value;
                benchmark_returns.push(return_pct);
            }
        }

        if benchmark_returns.is_empty() {
            return Ok(None);
        }

        // Calculate strategy daily returns
        let strategy_returns = self.calculate_daily_returns()?;
        if strategy_returns.is_empty() {
            return Ok(None);
        }

        // Align returns (use minimum length)
        let min_len = strategy_returns.len().min(benchmark_returns.len());
        let strategy_returns = &strategy_returns[..min_len];
        let benchmark_returns = &benchmark_returns[..min_len];

        // Calculate benchmark total return
        let benchmark_return = benchmark_returns.iter().sum::<Decimal>();

        // Calculate excess return
        let excess_return = returns.total_return - benchmark_return;

        // Calculate beta (covariance / variance)
        let strategy_mean =
            strategy_returns.iter().sum::<Decimal>() / Decimal::from(strategy_returns.len());
        let benchmark_mean =
            benchmark_returns.iter().sum::<Decimal>() / Decimal::from(benchmark_returns.len());

        let mut covariance = Decimal::ZERO;
        let mut benchmark_variance = Decimal::ZERO;

        for i in 0..min_len {
            let strategy_dev = strategy_returns[i] - strategy_mean;
            let benchmark_dev = benchmark_returns[i] - benchmark_mean;
            covariance += strategy_dev * benchmark_dev;
            benchmark_variance += benchmark_dev * benchmark_dev;
        }

        covariance /= Decimal::from(min_len);
        benchmark_variance /= Decimal::from(min_len);

        let beta = if benchmark_variance > Decimal::ZERO {
            covariance / benchmark_variance
        } else {
            Decimal::ZERO
        };

        // Calculate alpha (CAPM formula)
        // Alpha = Strategy Return - (Risk-free Rate + Beta * (Benchmark Return - Risk-free Rate))
        let alpha = returns.annualized_return
            - (self.risk_free_rate + beta * (benchmark_return - self.risk_free_rate));

        // Calculate tracking error (std dev of excess returns)
        let mut excess_returns = Vec::new();
        for i in 0..min_len {
            excess_returns.push(strategy_returns[i] - benchmark_returns[i]);
        }

        let excess_mean =
            excess_returns.iter().sum::<Decimal>() / Decimal::from(excess_returns.len());
        let mut tracking_variance = Decimal::ZERO;
        for excess_return in &excess_returns {
            let dev = excess_return - excess_mean;
            tracking_variance += dev * dev;
        }
        tracking_variance /= Decimal::from(excess_returns.len());
        let tracking_error = tracking_variance.sqrt().unwrap_or(Decimal::ZERO);

        // Calculate information ratio
        let information_ratio = if tracking_error > Decimal::ZERO {
            alpha / tracking_error
        } else {
            Decimal::ZERO
        };

        // Calculate up/down capture ratios
        let mut up_strategy = Vec::new();
        let mut up_benchmark = Vec::new();
        let mut down_strategy = Vec::new();
        let mut down_benchmark = Vec::new();

        for i in 0..min_len {
            if benchmark_returns[i] > Decimal::ZERO {
                up_strategy.push(strategy_returns[i]);
                up_benchmark.push(benchmark_returns[i]);
            } else if benchmark_returns[i] < Decimal::ZERO {
                down_strategy.push(strategy_returns[i]);
                down_benchmark.push(benchmark_returns[i]);
            }
        }

        let up_capture = if !up_benchmark.is_empty() {
            let up_strategy_avg =
                up_strategy.iter().sum::<Decimal>() / Decimal::from(up_strategy.len());
            let up_benchmark_avg =
                up_benchmark.iter().sum::<Decimal>() / Decimal::from(up_benchmark.len());
            if up_benchmark_avg > Decimal::ZERO {
                up_strategy_avg / up_benchmark_avg
            } else {
                Decimal::ZERO
            }
        } else {
            Decimal::ZERO
        };

        let down_capture = if !down_benchmark.is_empty() {
            let down_strategy_avg =
                down_strategy.iter().sum::<Decimal>() / Decimal::from(down_strategy.len());
            let down_benchmark_avg =
                down_benchmark.iter().sum::<Decimal>() / Decimal::from(down_benchmark.len());
            if down_benchmark_avg < Decimal::ZERO {
                down_strategy_avg / down_benchmark_avg
            } else {
                Decimal::ZERO
            }
        } else {
            Decimal::ZERO
        };

        Ok(Some(BenchmarkComparison {
            benchmark_name,
            benchmark_return,
            excess_return,
            beta,
            alpha,
            tracking_error,
            information_ratio,
            up_capture,
            down_capture,
        }))
    }

    /// Calculate portfolio metrics
    ///
    /// # Returns
    /// * `Result<PortfolioMetrics>` - Portfolio-level metrics including turnover and utilization
    fn calculate_portfolio_metrics(&self) -> Result<PortfolioMetrics> {
        if self.snapshots.is_empty() {
            return Err(anyhow::anyhow!(
                "No snapshots available for portfolio metrics"
            ));
        }

        let initial_capital = self.snapshots[0].portfolio_value;
        let final_value = self
            .snapshots
            .last()
            .ok_or_else(|| anyhow::anyhow!("No snapshots available for final value calculation"))?
            .portfolio_value;
        let peak_value = self
            .snapshots
            .iter()
            .map(|s| s.portfolio_value)
            .max()
            .unwrap_or(initial_capital);

        let avg_portfolio_value = if !self.snapshots.is_empty() {
            let sum: Decimal = self.snapshots.iter().map(|s| s.portfolio_value).sum();
            sum / Decimal::from(self.snapshots.len())
        } else {
            initial_capital
        };

        let total_fees = self.trades.iter().map(|t| t.commission).sum();
        let total_slippage = Decimal::ZERO; // Would be calculated from execution data

        // Portfolio turnover calculation (simplified)
        let turnover = if !self.trades.is_empty() && avg_portfolio_value > Decimal::ZERO {
            let total_traded: Decimal = self
                .trades
                .iter()
                .map(|t| {
                    t.quantity.to_decimal().unwrap_or_default()
                        * t.entry_price.to_decimal().unwrap_or_default()
                })
                .sum();
            total_traded / avg_portfolio_value
        } else {
            Decimal::ZERO
        };

        let avg_positions = if !self.snapshots.is_empty() {
            let sum = self.snapshots.iter().map(|s| s.open_positions).sum::<u32>();
            Decimal::from(sum) / Decimal::from(self.snapshots.len())
        } else {
            Decimal::ZERO
        };

        let max_positions = self
            .snapshots
            .iter()
            .map(|s| s.open_positions)
            .max()
            .unwrap_or(0);

        let cash_utilization = if initial_capital > Decimal::ZERO {
            let final_cash = self
                .snapshots
                .last()
                .ok_or_else(|| {
                    anyhow::anyhow!("No snapshots available for cash utilization calculation")
                })?
                .cash_balance;
            (initial_capital - final_cash) / initial_capital
        } else {
            Decimal::ZERO
        };

        Ok(PortfolioMetrics {
            initial_capital,
            final_value,
            peak_value,
            avg_portfolio_value,
            total_fees,
            total_slippage,
            turnover,
            avg_positions,
            max_positions,
            cash_utilization,
        })
    }

    /// Calculate time-based analysis
    ///
    /// # Returns
    /// * `Result<TimeAnalysis>` - Time-based performance analysis including monthly and yearly breakdowns
    fn calculate_time_analysis(&self) -> Result<TimeAnalysis> {
        if self.snapshots.is_empty() {
            return Err(anyhow::anyhow!("No snapshots available for time analysis"));
        }

        let start_date = self.snapshots[0].timestamp;
        let end_date = self
            .snapshots
            .last()
            .ok_or_else(|| anyhow::anyhow!("No snapshots available for time analysis end date"))?
            .timestamp;
        let total_days = (end_date.timestamp() - start_date.timestamp()) / 86400;
        let trading_days = self.snapshots.len() as i64; // Simplified

        let monthly_performance = self.calculate_monthly_performance()?;
        let yearly_performance = self.calculate_yearly_performance()?;

        let best_month = monthly_performance
            .iter()
            .map(|m| m.return_pct)
            .max()
            .unwrap_or_default();

        let worst_month = monthly_performance
            .iter()
            .map(|m| m.return_pct)
            .min()
            .unwrap_or_default();

        let best_year = yearly_performance
            .iter()
            .map(|y| y.return_pct)
            .max()
            .unwrap_or_default();

        let worst_year = yearly_performance
            .iter()
            .map(|y| y.return_pct)
            .min()
            .unwrap_or_default();

        Ok(TimeAnalysis {
            start_date,
            end_date,
            total_days,
            trading_days,
            monthly_performance,
            yearly_performance,
            best_month,
            worst_month,
            best_year,
            worst_year,
        })
    }

    // Helper methods for calculations

    /// Calculate daily returns from portfolio snapshots
    ///
    /// # Returns
    /// * `Result<Vec<Decimal>>` - Vector of daily return percentages
    fn calculate_daily_returns(&self) -> Result<Vec<Decimal>> {
        if self.snapshots.len() < 2 {
            return Ok(Vec::new());
        }

        let mut returns = Vec::new();
        for i in 1..self.snapshots.len() {
            let prev_value = self.snapshots[i - 1].portfolio_value;
            let curr_value = self.snapshots[i].portfolio_value;

            if prev_value > Decimal::ZERO {
                let return_pct = (curr_value - prev_value) / prev_value;
                returns.push(return_pct);
            }
        }

        Ok(returns)
    }

    /// Calculate total return over the entire period
    ///
    /// # Returns
    /// * `Result<Decimal>` - Total return as a percentage
    fn calculate_total_return(&self) -> Result<Decimal> {
        if self.snapshots.is_empty() {
            return Ok(Decimal::ZERO);
        }

        let initial_value = self.snapshots[0].portfolio_value;
        let final_value = self
            .snapshots
            .last()
            .ok_or_else(|| anyhow::anyhow!("No snapshots available for total return calculation"))?
            .portfolio_value;

        if initial_value > Decimal::ZERO {
            Ok((final_value - initial_value) / initial_value)
        } else {
            Ok(Decimal::ZERO)
        }
    }

    /// Calculate annualized return from daily returns
    ///
    /// # Arguments
    /// * `daily_returns` - Vector of daily return percentages
    ///
    /// # Returns
    /// * `Result<Decimal>` - Annualized return percentage
    fn calculate_annualized_return(&self, daily_returns: &[Decimal]) -> Result<Decimal> {
        if daily_returns.is_empty() {
            return Ok(Decimal::ZERO);
        }

        // Compound daily returns to get annualized return
        let compound_return = daily_returns
            .iter()
            .fold(Decimal::from(1), |acc, &ret| acc * (Decimal::from(1) + ret));

        let days = daily_returns.len() as f64;
        let years = days / 365.25;

        if years > 0.0 && compound_return > Decimal::ZERO {
            let annualized = compound_return.powf(1.0 / years) - Decimal::from(1);
            Ok(annualized)
        } else {
            Ok(Decimal::ZERO)
        }
    }

    /// Calculate Compound Annual Growth Rate (CAGR)
    ///
    /// # Returns
    /// * `Result<Decimal>` - CAGR as a percentage
    fn calculate_cagr(&self) -> Result<Decimal> {
        if self.snapshots.len() < 2 {
            return Ok(Decimal::ZERO);
        }

        let initial_value = self.snapshots[0].portfolio_value;
        let final_value = self
            .snapshots
            .last()
            .ok_or_else(|| anyhow::anyhow!("No snapshots available for CAGR calculation"))?
            .portfolio_value;
        let start_date = self.snapshots[0].timestamp;
        let end_date = self
            .snapshots
            .last()
            .ok_or_else(|| anyhow::anyhow!("No snapshots available for CAGR end date"))?
            .timestamp;

        let years = (end_date.timestamp() - start_date.timestamp()) as f64 / (365.25 * 86400.0);

        if years > 0.0 && initial_value > Decimal::ZERO && final_value > Decimal::ZERO {
            let cagr = (final_value / initial_value).powf(1.0 / years) - Decimal::from(1);
            Ok(cagr)
        } else {
            Ok(Decimal::ZERO)
        }
    }

    /// Calculate Sharpe ratio from daily returns
    ///
    /// # Arguments
    /// * `daily_returns` - Vector of daily return percentages
    ///
    /// # Returns
    /// * `Result<Decimal>` - Annualized Sharpe ratio
    fn calculate_sharpe_ratio(&self, daily_returns: &[Decimal]) -> Result<Decimal> {
        if daily_returns.is_empty() {
            return Ok(Decimal::ZERO);
        }

        let returns_f64: Vec<f64> = daily_returns
            .iter()
            .map(|d| d.to_string().parse().unwrap_or(0.0))
            .collect();

        let mean_return = returns_f64.clone().mean();
        let std_dev = if returns_f64.len() > 1 {
            returns_f64.clone().std_dev()
        } else {
            return Ok(Decimal::ZERO);
        };

        let daily_risk_free = (self.risk_free_rate / Decimal::from(365))
            .to_string()
            .parse::<f64>()
            .unwrap_or(0.0);
        let excess_return = mean_return - daily_risk_free;

        if std_dev > 0.0 {
            let sharpe = excess_return / std_dev;
            let annualized_sharpe = sharpe * (365.25_f64).sqrt();
            Ok(Decimal::from_f64_retain(annualized_sharpe).unwrap_or_default())
        } else {
            Ok(Decimal::ZERO)
        }
    }

    /// Calculate Sortino ratio focusing on downside risk
    ///
    /// # Arguments
    /// * `daily_returns` - Vector of daily return percentages
    ///
    /// # Returns
    /// * `Result<Decimal>` - Annualized Sortino ratio
    fn calculate_sortino_ratio(&self, daily_returns: &[Decimal]) -> Result<Decimal> {
        if daily_returns.is_empty() {
            return Ok(Decimal::ZERO);
        }

        let returns_f64: Vec<f64> = daily_returns
            .iter()
            .map(|d| d.to_string().parse().unwrap_or(0.0))
            .collect();

        let mean_return = returns_f64.clone().mean();
        let daily_risk_free = (self.risk_free_rate / Decimal::from(365))
            .to_string()
            .parse::<f64>()
            .unwrap_or(0.0);

        // Calculate downside deviation
        let negative_returns: Vec<f64> = returns_f64
            .iter()
            .filter(|&&r| r < daily_risk_free)
            .map(|&r| (r - daily_risk_free).powi(2))
            .collect();

        if negative_returns.is_empty() {
            return Ok(Decimal::ZERO);
        }

        let downside_deviation =
            (negative_returns.iter().sum::<f64>() / negative_returns.len() as f64).sqrt();

        if downside_deviation > 0.0 {
            let sortino = (mean_return - daily_risk_free) / downside_deviation;
            let annualized_sortino = sortino * (365.25_f64).sqrt();
            Ok(Decimal::from_f64_retain(annualized_sortino).unwrap_or_default())
        } else {
            Ok(Decimal::ZERO)
        }
    }

    /// Calculate Calmar ratio (return to maximum drawdown)
    ///
    /// # Arguments
    /// * `annualized_return` - Annualized return percentage
    ///
    /// # Returns
    /// * `Result<Decimal>` - Calmar ratio
    fn calculate_calmar_ratio(&self, annualized_return: Decimal) -> Result<Decimal> {
        let max_drawdown = self.calculate_max_drawdown()?;

        if max_drawdown.abs() > Decimal::ZERO {
            Ok(annualized_return / max_drawdown.abs())
        } else {
            Ok(Decimal::ZERO)
        }
    }

    /// Calculate maximum drawdown from portfolio snapshots
    ///
    /// # Returns
    /// * `Result<Decimal>` - Maximum drawdown as a positive percentage (absolute value)
    fn calculate_max_drawdown(&self) -> Result<Decimal> {
        if self.snapshots.is_empty() {
            return Ok(Decimal::ZERO);
        }

        let mut max_dd = Decimal::ZERO;
        let mut peak = self.snapshots[0].portfolio_value;

        for snapshot in &self.snapshots {
            if snapshot.portfolio_value > peak {
                peak = snapshot.portfolio_value;
            }

            let drawdown = (snapshot.portfolio_value - peak) / peak;
            if drawdown < max_dd {
                max_dd = drawdown;
            }
        }

        Ok(max_dd.abs())
    }

    /// Calculate Value at Risk (VaR) at 95% and 99% confidence levels
    ///
    /// # Arguments
    /// * `daily_returns` - Vector of daily return percentages
    ///
    /// # Returns
    /// * `Result<(Decimal, Decimal)>` - Tuple of (VaR 95%, VaR 99%)
    fn calculate_var(&self, daily_returns: &[Decimal]) -> Result<(Decimal, Decimal)> {
        if daily_returns.is_empty() {
            return Ok((Decimal::ZERO, Decimal::ZERO));
        }

        let mut sorted_returns = daily_returns.to_vec();
        sorted_returns.sort();

        let var_95_idx = (sorted_returns.len() as f64 * 0.05) as usize;
        let var_99_idx = (sorted_returns.len() as f64 * 0.01) as usize;

        let var_95 = if var_95_idx < sorted_returns.len() {
            sorted_returns[var_95_idx]
        } else {
            Decimal::ZERO
        };

        let var_99 = if var_99_idx < sorted_returns.len() {
            sorted_returns[var_99_idx]
        } else {
            Decimal::ZERO
        };

        Ok((var_95, var_99))
    }

    /// Calculate Conditional Value at Risk (CVaR)
    ///
    /// # Arguments
    /// * `daily_returns` - Vector of daily return percentages
    ///
    /// * `confidence_level` - Confidence level (e.g., 0.05 for 95% confidence)
    ///
    /// # Returns
    /// * `Result<Decimal>` - CVaR value
    fn calculate_cvar(
        &self,
        daily_returns: &[Decimal],
        confidence_level: Decimal,
    ) -> Result<Decimal> {
        if daily_returns.is_empty() {
            return Ok(Decimal::ZERO);
        }

        let mut sorted_returns = daily_returns.to_vec();
        sorted_returns.sort();

        let cutoff_idx = (sorted_returns.len() as f64
            * {
                use num_traits::ToPrimitive;
                confidence_level.to_f64().unwrap_or(0.05)
            })
            as usize;

        if cutoff_idx == 0 {
            return Ok(Decimal::ZERO);
        }

        let tail_returns = &sorted_returns[..cutoff_idx];
        if tail_returns.is_empty() {
            return Ok(Decimal::ZERO);
        }

        let cvar = tail_returns.iter().sum::<Decimal>() / Decimal::from(tail_returns.len());
        Ok(cvar)
    }

    /// Calculate maximum consecutive losing trades
    ///
    /// # Returns
    /// * `Result<u32>` - Maximum number of consecutive losses
    fn calculate_max_consecutive_losses(&self) -> Result<u32> {
        let mut max_consecutive = 0;
        let mut current_consecutive = 0;

        for trade in &self.trades {
            if trade.return_pct < Decimal::ZERO {
                current_consecutive += 1;
                max_consecutive = max_consecutive.max(current_consecutive);
            } else {
                current_consecutive = 0;
            }
        }

        Ok(max_consecutive)
    }

    /// Calculate risk metrics relative to benchmark
    ///
    /// # Arguments
    /// * `_daily_returns` - Vector of daily return percentages (currently unused)
    ///
    /// # Returns
    /// * `Result<(Option<Decimal>, Option<Decimal>, Option<Decimal>, Option<Decimal>)>` -
    ///
    ///   Tuple of (beta, alpha, tracking_error, information_ratio)
    fn calculate_benchmark_risk_metrics(
        &self,
        _daily_returns: &[Decimal],
    ) -> Result<(
        Option<Decimal>,
        Option<Decimal>,
        Option<Decimal>,
        Option<Decimal>,
    )> {
        // Implementation for benchmark risk metrics calculation
        Ok((None, None, None, None))
    }

    /// Calculate comprehensive drawdown analysis
    ///
    /// # Returns
    /// * `Result<(Decimal, Decimal, Vec<DrawdownPeriod>, Vec<(DateTime<Utc>, Decimal)>)>` -
    ///
    ///   Tuple of (max_drawdown, current_drawdown, drawdown_periods, underwater_curve)
    fn calculate_drawdowns(
        &self,
    ) -> Result<(
        Decimal,
        Decimal,
        Vec<DrawdownPeriod>,
        Vec<(DateTime<Utc>, Decimal)>,
    )> {
        if self.snapshots.is_empty() {
            return Ok((Decimal::ZERO, Decimal::ZERO, Vec::new(), Vec::new()));
        }

        let mut max_drawdown = Decimal::ZERO;
        let mut peak = self.snapshots[0].portfolio_value;
        let mut drawdown_periods = Vec::new();
        let mut underwater_curve = Vec::new();
        let mut in_drawdown = false;
        let mut drawdown_start: Option<DateTime<Utc>> = None;
        let mut drawdown_peak = Decimal::ZERO;

        for snapshot in &self.snapshots {
            if snapshot.portfolio_value > peak {
                // New peak - end any current drawdown
                if in_drawdown {
                    if let Some(start) = drawdown_start {
                        drawdown_periods.push(DrawdownPeriod {
                            start_date: start,
                            end_date: Some(snapshot.timestamp),
                            peak_value: drawdown_peak,
                            trough_value: peak, // This would be the actual trough
                            max_drawdown: (peak - drawdown_peak) / drawdown_peak,
                            duration: (snapshot.timestamp - start).num_days(),
                            recovery_date: Some(snapshot.timestamp),
                        });
                    }
                    in_drawdown = false;
                }
                peak = snapshot.portfolio_value;
            }

            let current_drawdown = (snapshot.portfolio_value - peak) / peak;
            underwater_curve.push((snapshot.timestamp, current_drawdown));

            if current_drawdown < Decimal::ZERO && !in_drawdown {
                // Start of new drawdown
                in_drawdown = true;
                drawdown_start = Some(snapshot.timestamp);
                drawdown_peak = peak;
            }

            if current_drawdown < max_drawdown {
                max_drawdown = current_drawdown;
            }
        }

        // Handle ongoing drawdown
        if in_drawdown {
            if let Some(start) = drawdown_start {
                drawdown_periods.push(DrawdownPeriod {
                    start_date: start,
                    end_date: None,
                    peak_value: drawdown_peak,
                    trough_value: self
                        .snapshots
                        .last()
                        .map(|s| s.portfolio_value)
                        .unwrap_or(drawdown_peak),
                    max_drawdown: self
                        .snapshots
                        .last()
                        .map(|s| (s.portfolio_value - drawdown_peak) / drawdown_peak)
                        .unwrap_or(Decimal::ZERO),
                    duration: self
                        .snapshots
                        .last()
                        .map(|s| (s.timestamp - start).num_days())
                        .unwrap_or(0),
                    recovery_date: None,
                });
            }
        }

        let current_drawdown = if let Some(last_snapshot) = self.snapshots.last() {
            (last_snapshot.portfolio_value - peak) / peak
        } else {
            Decimal::ZERO
        };

        Ok((
            max_drawdown.abs(),
            current_drawdown,
            drawdown_periods,
            underwater_curve,
        ))
    }

    /// Calculate monthly return percentages
    ///
    /// # Returns
    /// * `Result<Vec<Decimal>>` - Vector of monthly returns
    fn calculate_monthly_returns(&self) -> Result<Vec<Decimal>> {
        // Implementation for monthly returns calculation
        Ok(Vec::new())
    }

    /// Calculate number of trades per month
    ///
    /// # Returns
    /// * `Vec<(DateTime<Utc>, u64)>` - Vector of (month, trade_count) pairs
    fn calculate_monthly_trade_count(&self) -> Vec<(DateTime<Utc>, u64)> {
        // Implementation for monthly trade count calculation
        Vec::new()
    }

    /// Calculate detailed monthly performance metrics
    ///
    /// # Returns
    /// * `Result<Vec<MonthlyPerformance>>` - Vector of monthly performance summaries
    fn calculate_monthly_performance(&self) -> Result<Vec<MonthlyPerformance>> {
        use std::collections::BTreeMap;

        if self.snapshots.is_empty() {
            return Ok(Vec::new());
        }

        // Group snapshots by month
        let mut monthly_groups: BTreeMap<(i32, u32), Vec<&PerformanceSnapshot>> = BTreeMap::new();

        for snapshot in &self.snapshots {
            let key = (snapshot.timestamp.year(), snapshot.timestamp.month());
            monthly_groups.entry(key).or_default().push(snapshot);
        }

        // Calculate metrics for each month
        let mut monthly_performance = Vec::new();

        for ((year, month), snapshots) in monthly_groups {
            if snapshots.is_empty() {
                continue;
            }

            let (start_value, end_value) = match (snapshots.first(), snapshots.last()) {
                (Some(first), Some(last)) => (first.portfolio_value, last.portfolio_value),
                _ => continue,
            };

            let return_pct = if start_value > Decimal::ZERO {
                ((end_value - start_value) / start_value) * Decimal::from(100)
            } else {
                Decimal::ZERO
            };

            // Count trades in this month
            let trade_count = self
                .trades
                .iter()
                .filter(|t| {
                    let trade_month = (t.exit_time.year(), t.exit_time.month());
                    trade_month == (year, month)
                })
                .count() as u64;

            // Calculate win rate for month
            let month_trades: Vec<_> = self
                .trades
                .iter()
                .filter(|t| {
                    let trade_month = (t.exit_time.year(), t.exit_time.month());
                    trade_month == (year, month)
                })
                .collect();

            let winning_trades = month_trades
                .iter()
                .filter(|t| t.pnl > Decimal::ZERO)
                .count();

            let win_rate = if !month_trades.is_empty() {
                Decimal::from(winning_trades) / Decimal::from(month_trades.len())
            } else {
                Decimal::ZERO
            };

            // Use first day of month for timestamp
            let month_timestamp = chrono::Utc
                .with_ymd_and_hms(year, month, 1, 0, 0, 0)
                .single()
                .or_else(|| snapshots.first().map(|s| s.timestamp))
                .unwrap_or_default();

            monthly_performance.push(MonthlyPerformance {
                month: month_timestamp,
                return_pct,
                trade_count,
                win_rate,
                portfolio_value: end_value,
            });
        }

        Ok(monthly_performance)
    }

    /// Calculate detailed yearly performance metrics
    ///
    /// # Returns
    /// * `Result<Vec<YearlyPerformance>>` - Vector of yearly performance summaries
    fn calculate_yearly_performance(&self) -> Result<Vec<YearlyPerformance>> {
        use std::collections::BTreeMap;

        if self.snapshots.is_empty() {
            return Ok(Vec::new());
        }

        // Group snapshots by year
        let mut yearly_groups: BTreeMap<i32, Vec<&PerformanceSnapshot>> = BTreeMap::new();

        for snapshot in &self.snapshots {
            yearly_groups
                .entry(snapshot.timestamp.year())
                .or_default()
                .push(snapshot);
        }

        // Calculate metrics for each year
        let mut yearly_performance = Vec::new();

        for (year, snapshots) in yearly_groups {
            if snapshots.is_empty() {
                continue;
            }

            let (start_value, end_value) = match (snapshots.first(), snapshots.last()) {
                (Some(first), Some(last)) => (first.portfolio_value, last.portfolio_value),
                _ => continue,
            };

            let return_pct = if start_value > Decimal::ZERO {
                ((end_value - start_value) / start_value) * Decimal::from(100)
            } else {
                Decimal::ZERO
            };

            // Count trades in this year
            let trade_count = self
                .trades
                .iter()
                .filter(|t| t.exit_time.year() == year)
                .count() as u64;

            // Calculate win rate for year
            let year_trades: Vec<_> = self
                .trades
                .iter()
                .filter(|t| t.exit_time.year() == year)
                .collect();

            let winning_trades = year_trades.iter().filter(|t| t.pnl > Decimal::ZERO).count();

            let win_rate = if !year_trades.is_empty() {
                Decimal::from(winning_trades) / Decimal::from(year_trades.len())
            } else {
                Decimal::ZERO
            };

            // Calculate max drawdown for this year
            let year_snapshots: Vec<_> = snapshots.clone();
            let mut peak = year_snapshots[0].portfolio_value;
            let mut max_drawdown = Decimal::ZERO;

            for snapshot in &year_snapshots {
                if snapshot.portfolio_value > peak {
                    peak = snapshot.portfolio_value;
                }

                let drawdown = if peak > Decimal::ZERO {
                    ((snapshot.portfolio_value - peak) / peak) * Decimal::from(100)
                } else {
                    Decimal::ZERO
                };

                if drawdown < max_drawdown {
                    max_drawdown = drawdown;
                }
            }

            yearly_performance.push(YearlyPerformance {
                year,
                return_pct,
                trade_count,
                win_rate,
                portfolio_value: end_value,
                max_drawdown,
            });
        }

        Ok(yearly_performance)
    }

    /// Calculate skewness of returns distribution
    ///
    /// # Arguments
    /// * `returns` - Vector of return values as f64
    ///
    /// # Returns
    /// * `Decimal` - Skewness measure (0 = symmetric, positive = right tail, negative = left tail)
    fn calculate_skewness(&self, returns: &[f64]) -> Decimal {
        if returns.len() < 3 {
            return Decimal::ZERO;
        }

        let mean = returns.mean();
        let std_dev = returns.std_dev();

        if std_dev == 0.0 {
            return Decimal::ZERO;
        }

        let n = returns.len() as f64;
        let skewness = returns
            .iter()
            .map(|&x| ((x - mean) / std_dev).powi(3))
            .sum::<f64>()
            * n
            / ((n - 1.0) * (n - 2.0));

        Decimal::from_f64_retain(skewness).unwrap_or_default()
    }

    /// Calculate kurtosis of returns distribution
    ///
    /// # Arguments
    /// * `returns` - Vector of return values as f64
    ///
    /// # Returns
    /// * `Decimal` - Excess kurtosis measure (0 = normal, positive = fat tails, negative = thin tails)
    fn calculate_kurtosis(&self, returns: &[f64]) -> Decimal {
        if returns.len() < 4 {
            return Decimal::ZERO;
        }

        let mean = returns.mean();
        let std_dev = returns.std_dev();

        if std_dev == 0.0 {
            return Decimal::ZERO;
        }

        let n = returns.len() as f64;
        let kurtosis = returns
            .iter()
            .map(|&x| ((x - mean) / std_dev).powi(4))
            .sum::<f64>()
            * n
            * (n + 1.0)
            / ((n - 1.0) * (n - 2.0) * (n - 3.0))
            - 3.0 * (n - 1.0) * (n - 1.0) / ((n - 2.0) * (n - 3.0));

        Decimal::from_f64_retain(kurtosis).unwrap_or_default()
    }
}

// Extension trait for Decimal power operations
/// Extension trait providing power operations for Decimal type
trait DecimalPower {
    /// Raise Decimal to a floating-point power
    ///
    /// # Arguments
    /// * `exp` - Exponent as f64
    ///
    /// # Returns
    /// * `Decimal` - Result of self^exp
    fn powf(self, exp: f64) -> Decimal;
}

impl DecimalPower for Decimal {
    fn powf(self, exp: f64) -> Decimal {
        use num_traits::ToPrimitive;
        let base_f64 = self.to_f64().unwrap_or(0.0);
        let result = base_f64.powf(exp);
        Decimal::from_f64_retain(result).unwrap_or_default()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_metrics_calculator_creation() {
        let calculator = MetricsCalculator::new(Decimal::new(2, 2)); // 2% risk-free rate
        assert_eq!(calculator.risk_free_rate, Decimal::new(2, 2));
    }

    #[test]
    fn test_empty_calculations() {
        let calculator = MetricsCalculator::new(Decimal::new(2, 2));

        // Should handle empty data gracefully
        let returns = calculator.calculate_daily_returns().unwrap();
        assert!(returns.is_empty());

        let total_return = calculator.calculate_total_return().unwrap();
        assert_eq!(total_return, Decimal::ZERO);
    }
}
