|
| 1 | +/****************************************************************************** |
| 2 | + Author: Joaquín Béjar García |
| 3 | + Email: jb@taunais.com |
| 4 | + Date: 26/4/25 |
| 5 | +******************************************************************************/ |
| 6 | +use crate::Positive; |
| 7 | +use chrono::NaiveDateTime; |
| 8 | +use rust_decimal::Decimal; |
| 9 | +use serde::{Deserialize, Serialize}; |
| 10 | + |
| 11 | +/// Represents core performance metrics applicable to various trading strategies. |
| 12 | +/// |
| 13 | +/// This struct aggregates common financial metrics used to evaluate the |
| 14 | +/// effectiveness and risk profile of a trading strategy based on its historical |
| 15 | +/// or simulated performance. |
| 16 | +#[derive(Debug, Clone, Default, Serialize, Deserialize)] |
| 17 | +pub struct GeneralPerformanceMetrics { |
| 18 | + // === Return Metrics === |
| 19 | + /// The total percentage return generated by the strategy over the entire period. |
| 20 | + pub total_return: Decimal, |
| 21 | + /// The geometric average amount of money earned by an investment each year over a given time period. |
| 22 | + pub annualized_return: Decimal, |
| 23 | + |
| 24 | + // === Risk Metrics === |
| 25 | + /// A statistical measure of the dispersion of returns for a given security or market index. |
| 26 | + /// It represents the degree of variation of a trading price series over time. |
| 27 | + /// Expressed as a positive decimal value. `None` if calculation is not possible (e.g., insufficient data). |
| 28 | + pub volatility: Option<Positive>, |
| 29 | + /// A measure of downside risk, focusing only on returns that fall below a minimum acceptable return (MAR), |
| 30 | + /// typically the risk-free rate or zero. It quantifies the volatility of negative returns. |
| 31 | + /// Expressed as a positive decimal value. `None` if calculation is not possible. |
| 32 | + pub downside_deviation: Option<Positive>, |
| 33 | + |
| 34 | + // === Risk-Adjusted Return Metrics === |
| 35 | + /// Measures the performance of an investment compared to a risk-free asset, after adjusting for its risk. |
| 36 | + /// It is defined as the difference between the returns of the investment and the risk-free return, |
| 37 | + /// divided by the standard deviation of the investment (volatility). |
| 38 | + /// `None` if calculation is not possible (e.g., zero volatility or insufficient data). |
| 39 | + pub sharpe_ratio: Option<Decimal>, |
| 40 | + /// Similar to the Sharpe ratio, but it only penalizes returns falling below a user-specified target |
| 41 | + /// or required rate of return (using downside deviation instead of total volatility). |
| 42 | + /// `None` if calculation is not possible (e.g., zero downside deviation or insufficient data). |
| 43 | + pub sortino_ratio: Option<Decimal>, |
| 44 | + /// A risk-adjusted return metric based on maximum drawdown. It is calculated as the annualized return |
| 45 | + /// divided by the absolute value of the maximum drawdown. |
| 46 | + /// `None` if calculation is not possible (e.g., zero or positive maximum drawdown, insufficient data). |
| 47 | + pub calmar_ratio: Option<Decimal>, |
| 48 | + |
| 49 | + // === Win/Loss Metrics === |
| 50 | + /// The percentage of trades that resulted in a profit. Calculated as (Number of Winning Trades / Total Number of Trades). |
| 51 | + /// `None` if there are no trades. |
| 52 | + pub win_rate: Option<Decimal>, |
| 53 | + /// The ratio of the total profit from winning trades to the total loss from losing trades. |
| 54 | + /// Calculated as (Gross Profits / Gross Losses). |
| 55 | + /// `None` if there are no losses. |
| 56 | + pub profit_factor: Option<Decimal>, |
| 57 | + /// The average profit amount for all winning trades. |
| 58 | + /// `None` if there are no winning trades. |
| 59 | + pub avg_gain: Option<Decimal>, |
| 60 | + /// The average loss amount for all losing trades. |
| 61 | + /// `None` if there are no losing trades. |
| 62 | + pub avg_loss: Option<Decimal>, |
| 63 | + /// The ratio of the average gain per trade to the average loss per trade. |
| 64 | + /// Calculated as (Average Gain / Average Loss). |
| 65 | + /// `None` if there are no losses or no gains. |
| 66 | + pub gain_loss_ratio: Option<Decimal>, |
| 67 | +} |
| 68 | + |
| 69 | +/// Represents metrics specifically tailored for evaluating options trading strategies. |
| 70 | +/// |
| 71 | +/// This struct encapsulates various performance and risk exposure metrics |
| 72 | +/// that are particularly relevant when analyzing strategies involving options contracts. |
| 73 | +#[derive(Debug, Clone, Default, Serialize, Deserialize)] |
| 74 | +pub struct OptionsSpecificMetrics { |
| 75 | + /// The return generated based on the margin required to maintain the positions. |
| 76 | + /// Calculated as `Total PnL / Maximum Margin Used`. |
| 77 | + pub return_on_margin: Option<Decimal>, |
| 78 | + /// The return generated based on the net premium received or paid for the options. |
| 79 | + /// Calculated as `Total PnL / Net Premium`. |
| 80 | + pub return_on_premium: Option<Decimal>, |
| 81 | + /// The percentage of the initial potential profit (net premium for short strategies) |
| 82 | + /// that was actually realized. |
| 83 | + /// Calculated as `Actual PnL / Initial Potential Profit`. Relevant primarily for premium selling strategies. |
| 84 | + pub premium_capture: Option<Decimal>, |
| 85 | + /// The average sensitivity of the portfolio's value to changes in the underlying asset's price (Delta). |
| 86 | + pub avg_delta_exposure: Option<Decimal>, |
| 87 | + /// The average rate of change of the portfolio's Delta with respect to the underlying asset's price (Gamma). |
| 88 | + pub avg_gamma_exposure: Option<Decimal>, |
| 89 | + /// The average sensitivity of the portfolio's value to the passage of time (Theta). |
| 90 | + /// Represents the daily time decay. |
| 91 | + pub avg_theta_exposure: Option<Decimal>, |
| 92 | + /// The average sensitivity of the portfolio's value to changes in the implied volatility of the underlying asset (Vega). |
| 93 | + pub avg_vega_exposure: Option<Decimal>, |
| 94 | + /// The percentage of trades or positions involving call options. |
| 95 | + pub calls_percentage: Option<Decimal>, |
| 96 | + /// The percentage of trades or positions involving put options. |
| 97 | + pub puts_percentage: Option<Decimal>, |
| 98 | + /// The percentage of trades or positions that are long options (bought). |
| 99 | + pub long_percentage: Option<Decimal>, |
| 100 | + /// The percentage of trades or positions that are short options (sold/written). |
| 101 | + pub short_percentage: Option<Decimal>, |
| 102 | +} |
| 103 | + |
| 104 | +/// Represents metrics related to market conditions observed during a specific period, typically a backtest. |
| 105 | +/// |
| 106 | +/// This struct captures counts of days categorized by different market trends (bull, bear, sideways) |
| 107 | +/// and volatility levels (high, low). It also stores the average market volatility over the period. |
| 108 | +/// The counts are represented using the `Positive` type, ensuring they are non-negative decimal values. |
| 109 | +#[derive(Debug, Clone, Default, Serialize, Deserialize)] |
| 110 | +pub struct MarketConditionMetrics { |
| 111 | + /// The number of days identified as being in a bull market trend. |
| 112 | + pub bull_market_days: Positive, |
| 113 | + /// The number of days identified as being in a bear market trend. |
| 114 | + pub bear_market_days: Positive, |
| 115 | + /// The number of days identified as being in a sideways or range-bound market trend. |
| 116 | + pub sideways_market_days: Positive, |
| 117 | + /// The number of days identified as having high market volatility. |
| 118 | + pub high_volatility_days: Positive, |
| 119 | + /// The number of days identified as having low market volatility. |
| 120 | + pub low_volatility_days: Positive, |
| 121 | + /// The calculated average market volatility over the period. This might be `None` if volatility couldn't be calculated. |
| 122 | + pub avg_market_volatility: Option<Decimal>, |
| 123 | +} |
| 124 | + |
| 125 | +/// Represents rolling window metrics calculated over a specific period. |
| 126 | +/// |
| 127 | +/// This struct holds various performance metrics calculated using a sliding window approach, |
| 128 | +/// allowing for the analysis of how a strategy's performance characteristics change over time. |
| 129 | +#[derive(Debug, Clone, Serialize, Deserialize)] |
| 130 | +pub struct RollingMetrics { |
| 131 | + /// The size of the rolling window used for calculations. |
| 132 | + /// This indicates the number of data points included in each rolling calculation. |
| 133 | + /// It must be a positive value. |
| 134 | + pub window_size: Positive, |
| 135 | + /// A vector of timestamps corresponding to the end of each rolling window period. |
| 136 | + pub timestamps: Vec<NaiveDateTime>, |
| 137 | + /// A vector of rolling returns calculated for each window. |
| 138 | + pub rolling_returns: Vec<Decimal>, |
| 139 | + /// A vector of rolling volatility (standard deviation of returns) calculated for each window. |
| 140 | + pub rolling_volatility: Vec<Decimal>, |
| 141 | + /// A vector of rolling Sharpe ratios calculated for each window. |
| 142 | + /// The Sharpe ratio measures risk-adjusted return, typically using volatility as the risk measure. |
| 143 | + pub rolling_sharpe: Vec<Decimal>, |
| 144 | + /// A vector of rolling Sortino ratios calculated for each window. |
| 145 | + /// The Sortino ratio is similar to the Sharpe ratio but only considers downside volatility. |
| 146 | + pub rolling_sortino: Vec<Decimal>, |
| 147 | + /// A vector of rolling win rates calculated for each window. |
| 148 | + /// The win rate represents the percentage of winning trades or periods within the window. |
| 149 | + pub rolling_win_rate: Vec<Decimal>, |
| 150 | +} |
| 151 | + |
| 152 | +/// Represents the results of comparing a portfolio's performance against a specified benchmark. |
| 153 | +/// |
| 154 | +/// This struct holds various statistical metrics commonly used in finance to evaluate |
| 155 | +/// how well a portfolio has performed relative to a market benchmark index. |
| 156 | +#[derive(Debug, Clone, Default, Serialize, Deserialize)] |
| 157 | +pub struct BenchmarkComparison { |
| 158 | + /// The name or identifier of the benchmark used for comparison (e.g., "S&P 500"). |
| 159 | + pub benchmark_name: String, |
| 160 | + /// The total return of the benchmark over the evaluated period. |
| 161 | + pub benchmark_return: Decimal, |
| 162 | + /// Alpha represents the excess return of the portfolio relative to the return of the benchmark, |
| 163 | + /// after adjusting for risk (as measured by beta). A positive alpha suggests the portfolio |
| 164 | + /// outperformed the benchmark on a risk-adjusted basis. |
| 165 | + pub alpha: Decimal, |
| 166 | + /// Beta measures the volatility or systematic risk of the portfolio in comparison to the benchmark. |
| 167 | + /// A beta greater than 1 indicates the portfolio is more volatile than the benchmark, while a beta |
| 168 | + /// less than 1 indicates less volatility. |
| 169 | + pub beta: Decimal, |
| 170 | + /// Correlation measures the degree to which the portfolio's returns move in relation to the benchmark's returns. |
| 171 | + /// A value close to 1 indicates a strong positive relationship, -1 a strong negative relationship, |
| 172 | + /// and 0 indicates no linear relationship. |
| 173 | + pub correlation: Decimal, |
| 174 | + /// Tracking Error measures the standard deviation of the difference between the portfolio's returns |
| 175 | + /// and the benchmark's returns. It quantifies how closely the portfolio's performance follows the benchmark. |
| 176 | + /// A lower tracking error indicates the portfolio is closely tracking the benchmark. |
| 177 | + pub tracking_error: Decimal, |
| 178 | + /// The Information Ratio measures the portfolio's risk-adjusted returns relative to the benchmark. |
| 179 | + /// It is typically calculated as the portfolio's alpha divided by its tracking error. |
| 180 | + /// A higher information ratio suggests better risk-adjusted performance relative to the benchmark. |
| 181 | + /// This is optional as it cannot be calculated if the tracking error is zero. |
| 182 | + pub information_ratio: Option<Decimal>, |
| 183 | + /// Up Capture Ratio measures the portfolio's performance relative to the benchmark during periods |
| 184 | + /// when the benchmark had positive returns. A value greater than 100 suggests the portfolio |
| 185 | + /// outperformed the benchmark during up-market periods. |
| 186 | + pub up_capture: Option<Decimal>, |
| 187 | + /// Down Capture Ratio measures the portfolio's performance relative to the benchmark during periods |
| 188 | + /// when the benchmark had negative returns. A value less than 100 suggests the portfolio |
| 189 | + /// lost less than the benchmark during down-market periods. |
| 190 | + pub down_capture: Option<Decimal>, |
| 191 | +} |
| 192 | + |
| 193 | +/// Represents a collection of advanced risk metrics for assessing investment performance, |
| 194 | +/// focusing on downside risk and tail events beyond simple standard deviation. |
| 195 | +#[derive(Debug, Clone, Default, Serialize, Deserialize)] |
| 196 | +pub struct AdvancedRiskMetrics { |
| 197 | + /// Value at Risk (VaR) at the 95% confidence level. |
| 198 | + /// Represents the maximum potential loss over a specific time period |
| 199 | + /// with 95% confidence. `None` if not calculated. |
| 200 | + pub value_at_risk_95: Option<Decimal>, |
| 201 | + /// Value at Risk (VaR) at the 99% confidence level. |
| 202 | + /// Represents the maximum potential loss over a specific time period |
| 203 | + /// with 99% confidence. `None` if not calculated. |
| 204 | + pub value_at_risk_99: Option<Decimal>, |
| 205 | + /// Expected Shortfall (ES), also known as Conditional Value at Risk (CVaR). |
| 206 | + /// Represents the expected loss given that the loss exceeds the VaR threshold |
| 207 | + /// (typically calculated at the 95% or 99% level). `None` if not calculated. |
| 208 | + pub expected_shortfall: Option<Decimal>, |
| 209 | + /// The ratio of the 95th percentile gain to the absolute value of the 5th percentile loss. |
| 210 | + /// Provides insight into the symmetry of the return distribution's tails. `None` if not calculated. |
| 211 | + pub tail_ratio: Option<Decimal>, |
| 212 | + /// The maximum number of consecutive periods (e.g., days, weeks) with negative returns. |
| 213 | + pub max_consecutive_losses: usize, |
| 214 | + /// The Ulcer Index, measuring the depth and duration of drawdowns from peak values. |
| 215 | + /// Higher values indicate more significant and prolonged drawdowns. `None` if not calculated. |
| 216 | + pub ulcer_index: Option<Decimal>, |
| 217 | + /// The Pain Index, similar to the Ulcer Index, measuring the average depth and duration |
| 218 | + /// of drawdowns. `None` if not calculated. |
| 219 | + pub pain_index: Option<Decimal>, |
| 220 | +} |
0 commit comments