/******************************************************************************
   Author: Joaquín Béjar García
   Email: jb@taunais.com
   Date: 26/4/25
******************************************************************************/
use crate::Positive;
use chrono::NaiveDateTime;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};

/// Represents core performance metrics applicable to various trading strategies.
///
/// This struct aggregates common financial metrics used to evaluate the
/// effectiveness and risk profile of a trading strategy based on its historical
/// or simulated performance.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GeneralPerformanceMetrics {
    // === Return Metrics ===
    /// The total percentage return generated by the strategy over the entire period.
    pub total_return: Decimal,
    /// The geometric average amount of money earned by an investment each year over a given time period.
    pub annualized_return: Decimal,

    // === Risk Metrics ===
    /// A statistical measure of the dispersion of returns for a given security or market index.
    /// It represents the degree of variation of a trading price series over time.
    /// Expressed as a positive decimal value. `None` if calculation is not possible (e.g., insufficient data).
    pub volatility: Option<Positive>,
    /// A measure of downside risk, focusing only on returns that fall below a minimum acceptable return (MAR),
    /// typically the risk-free rate or zero. It quantifies the volatility of negative returns.
    /// Expressed as a positive decimal value. `None` if calculation is not possible.
    pub downside_deviation: Option<Positive>,

    // === Risk-Adjusted Return Metrics ===
    /// Measures the performance of an investment compared to a risk-free asset, after adjusting for its risk.
    /// It is defined as the difference between the returns of the investment and the risk-free return,
    /// divided by the standard deviation of the investment (volatility).
    /// `None` if calculation is not possible (e.g., zero volatility or insufficient data).
    pub sharpe_ratio: Option<Decimal>,
    /// Similar to the Sharpe ratio, but it only penalizes returns falling below a user-specified target
    /// or required rate of return (using downside deviation instead of total volatility).
    /// `None` if calculation is not possible (e.g., zero downside deviation or insufficient data).
    pub sortino_ratio: Option<Decimal>,
    /// A risk-adjusted return metric based on maximum drawdown. It is calculated as the annualized return
    /// divided by the absolute value of the maximum drawdown.
    /// `None` if calculation is not possible (e.g., zero or positive maximum drawdown, insufficient data).
    pub calmar_ratio: Option<Decimal>,

    // === Win/Loss Metrics ===
    /// The percentage of trades that resulted in a profit. Calculated as (Number of Winning Trades / Total Number of Trades).
    /// `None` if there are no trades.
    pub win_rate: Option<Decimal>,
    /// The ratio of the total profit from winning trades to the total loss from losing trades.
    /// Calculated as (Gross Profits / Gross Losses).
    /// `None` if there are no losses.
    pub profit_factor: Option<Decimal>,
    /// The average profit amount for all winning trades.
    /// `None` if there are no winning trades.
    pub avg_gain: Option<Decimal>,
    /// The average loss amount for all losing trades.
    /// `None` if there are no losing trades.
    pub avg_loss: Option<Decimal>,
    /// The ratio of the average gain per trade to the average loss per trade.
    /// Calculated as (Average Gain / Average Loss).
    /// `None` if there are no losses or no gains.
    pub gain_loss_ratio: Option<Decimal>,
}

/// Represents metrics specifically tailored for evaluating options trading strategies.
///
/// This struct encapsulates various performance and risk exposure metrics
/// that are particularly relevant when analyzing strategies involving options contracts.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OptionsSpecificMetrics {
    /// The return generated based on the margin required to maintain the positions.
    /// Calculated as `Total PnL / Maximum Margin Used`.
    pub return_on_margin: Option<Decimal>,
    /// The return generated based on the net premium received or paid for the options.
    /// Calculated as `Total PnL / Net Premium`.
    pub return_on_premium: Option<Decimal>,
    /// The percentage of the initial potential profit (net premium for short strategies)
    /// that was actually realized.
    /// Calculated as `Actual PnL / Initial Potential Profit`. Relevant primarily for premium selling strategies.
    pub premium_capture: Option<Decimal>,
    /// The average sensitivity of the portfolio's value to changes in the underlying asset's price (Delta).
    pub avg_delta_exposure: Option<Decimal>,
    /// The average rate of change of the portfolio's Delta with respect to the underlying asset's price (Gamma).
    pub avg_gamma_exposure: Option<Decimal>,
    /// The average sensitivity of the portfolio's value to the passage of time (Theta).
    /// Represents the daily time decay.
    pub avg_theta_exposure: Option<Decimal>,
    /// The average sensitivity of the portfolio's value to changes in the implied volatility of the underlying asset (Vega).
    pub avg_vega_exposure: Option<Decimal>,
    /// The average sensitivity of the portfolio's Delta to changes in the implied volatility of the underlying asset (Vanna).
    pub avg_vanna_exposure: Option<Decimal>,
    /// The average sensitivity of the portfolio's Vega to changes in the implied volatility of the underlying asset (Vomma).
    pub avg_vomma_exposure: Option<Decimal>,
    /// The average sensitivity of the portfolio's Vega to the passage of time (Veta).
    pub avg_veta_exposure: Option<Decimal>,
    /// The average sensitivity of the portfolio's Delta to the passage of time (Charm).
    pub avg_charm_exposure: Option<Decimal>,
    /// The average sensitivity of the portfolio's Gamma to the passage of time (Color).
    pub avg_color_exposure: Option<Decimal>,
    /// The percentage of trades or positions involving call options.
    pub calls_percentage: Option<Decimal>,
    /// The percentage of trades or positions involving put options.
    pub puts_percentage: Option<Decimal>,
    /// The percentage of trades or positions that are long options (bought).
    pub long_percentage: Option<Decimal>,
    /// The percentage of trades or positions that are short options (sold/written).
    pub short_percentage: Option<Decimal>,
}

/// Represents metrics related to market conditions observed during a specific period, typically a backtest.
///
/// This struct captures counts of days categorized by different market trends (bull, bear, sideways)
/// and volatility levels (high, low). It also stores the average market volatility over the period.
/// The counts are represented using the `Positive` type, ensuring they are non-negative decimal values.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct MarketConditionMetrics {
    /// The number of days identified as being in a bull market trend.
    pub bull_market_days: Positive,
    /// The number of days identified as being in a bear market trend.
    pub bear_market_days: Positive,
    /// The number of days identified as being in a sideways or range-bound market trend.
    pub sideways_market_days: Positive,
    /// The number of days identified as having high market volatility.
    pub high_volatility_days: Positive,
    /// The number of days identified as having low market volatility.
    pub low_volatility_days: Positive,
    /// The calculated average market volatility over the period. This might be `None` if volatility couldn't be calculated.
    pub avg_market_volatility: Option<Decimal>,
}

/// Represents rolling window metrics calculated over a specific period.
///
/// This struct holds various performance metrics calculated using a sliding window approach,
/// allowing for the analysis of how a strategy's performance characteristics change over time.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RollingMetrics {
    /// The size of the rolling window used for calculations.
    /// This indicates the number of data points included in each rolling calculation.
    /// It must be a positive value.
    pub window_size: Positive,
    /// A vector of timestamps corresponding to the end of each rolling window period.
    pub timestamps: Vec<NaiveDateTime>,
    /// A vector of rolling returns calculated for each window.
    pub rolling_returns: Vec<Decimal>,
    /// A vector of rolling volatility (standard deviation of returns) calculated for each window.
    pub rolling_volatility: Vec<Decimal>,
    /// A vector of rolling Sharpe ratios calculated for each window.
    /// The Sharpe ratio measures risk-adjusted return, typically using volatility as the risk measure.
    pub rolling_sharpe: Vec<Decimal>,
    /// A vector of rolling Sortino ratios calculated for each window.
    /// The Sortino ratio is similar to the Sharpe ratio but only considers downside volatility.
    pub rolling_sortino: Vec<Decimal>,
    /// A vector of rolling win rates calculated for each window.
    /// The win rate represents the percentage of winning trades or periods within the window.
    pub rolling_win_rate: Vec<Decimal>,
}

/// Represents the results of comparing a portfolio's performance against a specified benchmark.
///
/// This struct holds various statistical metrics commonly used in finance to evaluate
/// how well a portfolio has performed relative to a market benchmark index.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct BenchmarkComparison {
    /// The name or identifier of the benchmark used for comparison (e.g., "S&P 500").
    pub benchmark_name: String,
    /// The total return of the benchmark over the evaluated period.
    pub benchmark_return: Decimal,
    /// Alpha represents the excess return of the portfolio relative to the return of the benchmark,
    /// after adjusting for risk (as measured by beta). A positive alpha suggests the portfolio
    /// outperformed the benchmark on a risk-adjusted basis.
    pub alpha: Decimal,
    /// Beta measures the volatility or systematic risk of the portfolio in comparison to the benchmark.
    /// A beta greater than 1 indicates the portfolio is more volatile than the benchmark, while a beta
    /// less than 1 indicates less volatility.
    pub beta: Decimal,
    /// Correlation measures the degree to which the portfolio's returns move in relation to the benchmark's returns.
    /// A value close to 1 indicates a strong positive relationship, -1 a strong negative relationship,
    /// and 0 indicates no linear relationship.
    pub correlation: Decimal,
    /// Tracking Error measures the standard deviation of the difference between the portfolio's returns
    /// and the benchmark's returns. It quantifies how closely the portfolio's performance follows the benchmark.
    /// A lower tracking error indicates the portfolio is closely tracking the benchmark.
    pub tracking_error: Decimal,
    /// The Information Ratio measures the portfolio's risk-adjusted returns relative to the benchmark.
    /// It is typically calculated as the portfolio's alpha divided by its tracking error.
    /// A higher information ratio suggests better risk-adjusted performance relative to the benchmark.
    /// This is optional as it cannot be calculated if the tracking error is zero.
    pub information_ratio: Option<Decimal>,
    /// Up Capture Ratio measures the portfolio's performance relative to the benchmark during periods
    /// when the benchmark had positive returns. A value greater than 100 suggests the portfolio
    /// outperformed the benchmark during up-market periods.
    pub up_capture: Option<Decimal>,
    /// Down Capture Ratio measures the portfolio's performance relative to the benchmark during periods
    /// when the benchmark had negative returns. A value less than 100 suggests the portfolio
    /// lost less than the benchmark during down-market periods.
    pub down_capture: Option<Decimal>,
}

/// Represents a collection of advanced risk metrics for assessing investment performance,
/// focusing on downside risk and tail events beyond simple standard deviation.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AdvancedRiskMetrics {
    /// Value at Risk (VaR) at the 95% confidence level.
    /// Represents the maximum potential loss over a specific time period
    /// with 95% confidence. `None` if not calculated.
    pub value_at_risk_95: Option<Decimal>,
    /// Value at Risk (VaR) at the 99% confidence level.
    /// Represents the maximum potential loss over a specific time period
    /// with 99% confidence. `None` if not calculated.
    pub value_at_risk_99: Option<Decimal>,
    /// Expected Shortfall (ES), also known as Conditional Value at Risk (CVaR).
    /// Represents the expected loss given that the loss exceeds the VaR threshold
    /// (typically calculated at the 95% or 99% level). `None` if not calculated.
    pub expected_shortfall: Option<Decimal>,
    /// The ratio of the 95th percentile gain to the absolute value of the 5th percentile loss.
    /// Provides insight into the symmetry of the return distribution's tails. `None` if not calculated.
    pub tail_ratio: Option<Decimal>,
    /// The maximum number of consecutive periods (e.g., days, weeks) with negative returns.
    pub max_consecutive_losses: usize,
    /// The Ulcer Index, measuring the depth and duration of drawdowns from peak values.
    /// Higher values indicate more significant and prolonged drawdowns. `None` if not calculated.
    pub ulcer_index: Option<Decimal>,
    /// The Pain Index, similar to the Ulcer Index, measuring the average depth and duration
    /// of drawdowns. `None` if not calculated.
    pub pain_index: Option<Decimal>,
}
