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}