Skip to main content

optionstratlib_backtest/backtesting/
types.rs

1use chrono::{DateTime, NaiveDateTime, Utc};
2use optionstratlib_core::model::Position;
3use optionstratlib_core::model::Positive;
4use optionstratlib_pricing::greeks::GreeksSnapshot;
5use rust_decimal::Decimal;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use uuid::Uuid;
9
10/// Represents detailed statistical information aggregated from a collection of individual trades.
11///
12/// This struct provides insights into trading performance by summarizing various aspects
13/// such as the number of trades, win/loss ratios, average returns, trade durations,
14/// and breakdowns by trade type (e.g., long, short, call, put).
15#[derive(Debug, Clone, Default, Serialize, Deserialize)]
16pub struct TradeStatistics {
17    /// The total number of trades included in the statistics.
18    pub number_of_trades: usize,
19    /// The number of trades that resulted in a profit.
20    pub winners: usize,
21    /// The number of trades that resulted in a loss.
22    pub losers: usize,
23    /// The number of trades that resulted in neither profit nor loss (return is zero).
24    pub break_even: usize,
25    /// The average return per trade, expressed as a decimal value.
26    pub average_trade_return: Decimal,
27    /// The median return across all trades. Half the trades had a return less than or equal to this value,
28    /// and half had a return greater than or equal to this value.
29    pub median_trade_return: Decimal,
30    /// The largest profit recorded among all winning trades. `None` if there were no winning trades.
31    pub largest_win: Option<Decimal>,
32    /// The largest loss recorded among all losing trades (represented as a negative value). `None` if there were no losing trades.
33    pub largest_loss: Option<Decimal>,
34    /// The average duration for which trades were held open. Represented as a non-negative `Decimal`.
35    pub average_holding_period: Positive,
36    /// The median duration for which trades were held open. Represented as a non-negative `Decimal`.
37    pub median_holding_period: Positive,
38    /// The minimum duration any trade was held open. Represented as a non-negative `Decimal`.
39    pub min_holding_period: Positive,
40    /// The maximum duration any trade was held open. Represented as a non-negative `Decimal`.
41    pub max_holding_period: Positive,
42    /// The number of trades that were long positions.
43    pub long_trades: usize,
44    /// The number of trades that were short positions.
45    pub short_trades: usize,
46    /// The number of trades involving call options.
47    pub call_trades: usize,
48    /// The number of trades involving put options.
49    pub put_trades: usize,
50    /// The number of trades involving spreads (multi-leg option strategies).
51    pub spread_trades: usize,
52}
53
54/// Represents a comprehensive analysis of drawdown periods within a financial time series.
55///
56/// Drawdown refers to the decline from a historical peak in some variable, typically the
57/// cumulative profit or total value of a financial portfolio or instrument. This struct
58/// aggregates various metrics related to drawdowns observed over the analyzed period.
59#[derive(Debug, Clone, Default, Serialize, Deserialize)]
60pub struct DrawdownAnalysis {
61    /// The magnitude of the largest single drawdown observed during the analysis period.
62    /// This is typically expressed as a positive decimal representing the percentage loss
63    /// from the peak to the subsequent trough (e.g., 0.1 for a 10% loss).
64    pub max_drawdown: Decimal,
65    /// The duration from the peak to the trough of the maximum drawdown event.
66    /// Represented as a positive value (e.g., number of days).
67    pub max_drawdown_duration: Positive,
68    /// The time it took for the value to recover from the trough of the maximum drawdown
69    /// back to the level of its preceding peak.
70    /// This is `None` if recovery did not occur by the end of the analysis period.
71    pub recovery_duration: Option<Positive>,
72    /// The duration from the beginning of the analysis period until the peak
73    /// that preceded the maximum drawdown event.
74    pub time_to_max_drawdown: Positive,
75    /// A vector containing details of every individual drawdown event identified
76    /// during the analysis period. See [`DrawdownEvent`] for details.
77    pub drawdowns: Vec<DrawdownEvent>,
78    /// The average magnitude of all drawdown events recorded in `drawdowns`.
79    pub avg_drawdown: Decimal,
80    /// The average time it took to recover from the trough back to the preceding peak
81    /// across all drawdown events that achieved recovery within the analysis period.
82    /// This is `None` if no drawdowns recovered.
83    pub avg_recovery_time: Option<Positive>,
84    /// The total duration (e.g., number of days) the analyzed value spent below
85    /// a previously established peak ("underwater").
86    pub total_underwater_days: Positive,
87    /// The percentage of the total analysis duration that the value spent underwater.
88    /// Calculated as `total_underwater_days` divided by the total duration of the analysis period.
89    pub underwater_percentage: Decimal,
90}
91
92/// Represents a single drawdown event in a time series, typically of asset prices or portfolio values.
93///
94/// A drawdown is a peak-to-trough decline during a specific period for an investment,
95/// trading account, or fund. It is usually quoted as the percentage between the peak and
96/// the subsequent trough.
97///
98/// This struct captures the key dates, the magnitude (severity) of the drawdown,
99/// and its duration, including the time it takes to recover back to the initial peak value.
100#[derive(Debug, Clone, Serialize, Deserialize, Default)]
101pub struct DrawdownEvent {
102    /// The date and time when the drawdown period started (the peak before the decline).
103    pub start_date: NaiveDateTime,
104    /// The date and time when the value reached its lowest point (the trough) during the drawdown.
105    pub bottom_date: NaiveDateTime,
106    /// The date and time when the value recovered back to the level of `start_date`.
107    /// This is `None` if the value has not yet recovered by the end of the analyzed period.
108    pub recovery_date: Option<NaiveDateTime>,
109    /// The magnitude of the drawdown, typically expressed as a positive decimal representing
110    /// the percentage loss from the peak (`start_date`) to the trough (`bottom_date`).
111    /// For example, a value of `0.1` represents a 10% drawdown.
112    pub magnitude: Decimal,
113    /// The duration of the drawdown from the `start_date` to the `bottom_date`,
114    /// represented as a positive value (e.g., number of days or other time units).
115    pub duration: Positive,
116    /// The duration it took for the value to recover from the `bottom_date` back to
117    /// the `start_date` level. This is `None` if the recovery has not occurred
118    /// (i.e., `recovery_date` is `None`). Represented as a positive value.
119    pub recovery_duration: Option<Positive>,
120}
121
122/// Represents the allocation and utilization of capital within a trading strategy.
123///
124/// This struct tracks various metrics related to how capital is deployed and managed,
125/// including overall capital usage, specific metrics for options trading (margin and premium),
126/// and risk allocation measures like position sizing.
127#[derive(Debug, Clone, Default, Serialize, Deserialize)]
128pub struct CapitalUtilization {
129    /// The maximum amount of capital utilized at any point during the trading period.
130    pub max_capital_used: Decimal,
131    /// The average amount of capital utilized throughout the trading period.
132    pub avg_capital_used: Decimal,
133    /// A measure of return generated relative to the average capital used (Return / Average Capital Used).
134    pub capital_efficiency: Decimal, // return / average capital used
135    /// The total margin required and used for options positions throughout the period.
136    pub total_margin_used: Decimal,
137    /// The peak margin utilized at any single point in time.
138    pub max_margin_used: Decimal,
139    /// The average margin utilized throughout the trading period.
140    pub avg_margin_used: Decimal,
141    /// The total amount of premium paid for purchasing options.
142    pub total_premium_paid: Decimal,
143    /// The total amount of premium received for selling options.
144    pub total_premium_received: Decimal,
145    /// The net difference between premium received and premium paid (Received - Paid).
146    pub net_premium: Decimal,
147    /// The largest single position size taken, expressed as a percentage of total available capital.
148    pub max_position_size: Decimal, // as % of total capital
149    /// The average size of positions taken, expressed as a percentage of total available capital.
150    pub avg_position_size: Decimal,
151}
152
153/// Represents time-series data for tracking various portfolio metrics over time.
154///
155/// This struct holds vectors of data points, each corresponding to a specific timestamp.
156/// It's used to store the evolution of the equity curve, drawdown, margin usage,
157/// position count, and potentially option greeks exposures and custom metrics.
158#[derive(Debug, Clone, Default, Serialize, Deserialize)]
159pub struct TimeSeriesData {
160    /// Timestamps corresponding to each data point in the series.
161    pub timestamps: Vec<DateTime<Utc>>,
162    /// The value of the portfolio equity at each timestamp.
163    pub equity_curve: Vec<Decimal>,
164    /// The drawdown percentage or value from the peak equity at each timestamp.
165    pub drawdown_curve: Vec<Decimal>,
166    /// The amount or percentage of margin used at each timestamp.
167    pub margin_usage: Vec<Decimal>,
168    /// The number of open positions at each timestamp.
169    pub position_count: Vec<usize>,
170    /// Optional time series of the portfolio's delta exposure.
171    pub delta_exposure: Option<Vec<Decimal>>,
172    /// Optional time series of the portfolio's gamma exposure.
173    pub gamma_exposure: Option<Vec<Decimal>>,
174    /// Optional time series of the portfolio's theta exposure.
175    pub theta_exposure: Option<Vec<Decimal>>,
176    /// Optional time series of the portfolio's vega exposure.
177    pub vega_exposure: Option<Vec<Decimal>>,
178    /// Optional time series of the portfolio's vanna exposure.
179    pub vanna_exposure: Option<Vec<Decimal>>,
180    /// Optional time series of the portfolio's vomma exposure.
181    pub vomma_exposure: Option<Vec<Decimal>>,
182    /// Optional time series of the portfolio's veta exposure.
183    pub veta_exposure: Option<Vec<Decimal>>,
184    /// Optional time series of the portfolio's charm exposure.
185    pub charm_exposure: Option<Vec<Decimal>>,
186    /// Optional time series of the portfolio's color exposure.
187    pub color_exposure: Option<Vec<Decimal>>,
188    /// A map holding custom time series metrics, identified by a string key.
189    /// Each key maps to a vector of decimal values corresponding to the timestamps.
190    pub custom_series: HashMap<String, Vec<Decimal>>,
191}
192
193/// Represents a detailed record of an individual trade, capturing all relevant information
194/// from entry to exit.
195///
196/// This struct is used to log and analyze the performance and characteristics of specific trades,
197/// particularly in the context of options trading. It includes timestamps, financial details,
198/// associated strategy information, and reasons for exit.
199#[derive(Debug, Clone, Serialize, Deserialize, Default)]
200pub struct TradeRecord {
201    /// A unique identifier (`Uuid`) for this specific trade record.
202    pub id: Uuid,
203    /// The exact date and time (UTC) when the trade position was initiated or entered.
204    pub entry_date: DateTime<Utc>,
205    /// The exact date and time (UTC) when the trade position was closed or exited, if it has been closed.
206    /// `None` if the position is still open.
207    pub exit_date: Option<DateTime<Utc>>,
208    /// The duration for which the trade was held, typically measured in days or fractions thereof.
209    /// This value is guaranteed to be positive if present. `None` if the position is still open.
210    pub duration: Option<Positive>,
211    /// An optional identifier (`Uuid`) linking this trade to a specific trading strategy.
212    pub strategy: Option<Uuid>,
213    /// Contains detailed information about the option position itself, including the underlying option,
214    /// premium, fees, and entry date. See [`Position`] for more details.
215    pub position: Position,
216    /// The price per unit/contract at which the position was closed. `None` if the position is still open.
217    pub exit_price: Option<Decimal>,
218    /// Any additional cost incurred during the trade execution beyond the explicit fees,
219    /// such as price slippage. Usually represented as a cost per unit/contract or total cost.
220    pub slippage: Option<Decimal>,
221    /// The realized profit or loss from this trade after accounting for entry/exit prices and fees.
222    /// `None` if the position is still open or P/L hasn't been calculated yet.
223    pub profit_loss: Option<Decimal>,
224    /// The percentage return generated by the trade, typically calculated based on the initial investment or margin.
225    /// `None` if the position is still open or the return hasn't been calculated.
226    pub return_percentage: Option<Decimal>,
227    /// The amount of capital or margin required to open and maintain this position.
228    pub margin_required: Option<Decimal>,
229    /// The specific reason why the position was closed (e.g., target reached, stop loss hit, expiration).
230    /// See [`ExitReason`] for possible values. `None` if the position is still open.
231    pub exit_reason: Option<ExitReason>,
232    /// Optional field for any textual notes, observations, or comments related to this specific trade.
233    pub notes: Option<String>,
234    /// A snapshot of the calculated option Greeks (Delta, Gamma, Theta, Vega, Rho, Vanna, Vomma, Veta, etc.) at the moment of trade entry.
235    /// See [`GreeksSnapshot`] for details. `None` if Greeks were not calculated or recorded at entry.
236    pub entry_greeks: Option<GreeksSnapshot>,
237    /// A snapshot of the calculated option Greeks at the moment of trade exit.
238    /// See [`GreeksSnapshot`] for details. `None` if the position is still open or Greeks were not calculated/recorded at exit.
239    pub exit_greeks: Option<GreeksSnapshot>,
240}
241
242/// Represents the reason why a trading position was closed or exited.
243#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
244pub enum ExitReason {
245    /// The position was closed because the profit target price was reached.
246    TargetReached,
247    /// The position was closed because the stop-loss price was triggered.
248    StopLoss,
249    /// The position was closed due to the expiration of the underlying contract or option.
250    Expiration,
251    /// The position was rolled over to a new contract period.
252    RollOver,
253    /// The position was closed manually by the trader or user.
254    ManualClose,
255    /// The position was liquidated due to a margin call (insufficient funds).
256    MarginCall,
257    /// Represents any other reason for closing the position, with a descriptive string.
258    Other(String),
259}
260
261/// Represents volatility surface information captured during a backtest.
262///
263/// This struct stores data related to the implied volatility metrics
264/// observed at the time trades occurred within the simulation.
265#[derive(Debug, Clone, Default, Serialize, Deserialize)]
266pub struct VolatilityData {
267    /// Flag indicating whether implied volatility data was used in the backtest calculations for this trade.
268    pub implied_volatility_used: bool,
269    /// The average implied volatility observed around the time the trade was executed, if available.
270    pub avg_iv_traded: Option<Decimal>,
271    /// The percentile rank of the implied volatility at the time of the trade compared to its historical distribution, if available.
272    pub iv_percentile_traded: Option<Decimal>,
273    /// The rank of the implied volatility at the time of the trade compared to its historical range (e.g., IV Rank), if available.
274    pub iv_rank_traded: Option<Decimal>,
275}