optionstratlib 0.17.0

OptionStratLib is a comprehensive Rust library for options trading and strategy development across multiple asset classes.
Documentation
/******************************************************************************
use positive::pos_or_panic;
   Author: Joaquín Béjar García
   Email: jb@taunais.com
   Date: 1/8/24
******************************************************************************/

//! # SPAN (Standard Portfolio Analysis of Risk) Module
//!
//! This module implements the SPAN® (Standard Portfolio Analysis of Risk) methodology,
//! a system developed by the Chicago Mercantile Exchange (CME) for calculating margin
//! requirements for derivatives portfolios.
//!
//! ## Overview
//!
//! SPAN calculates margin requirements by analyzing the potential losses a portfolio might
//! experience under various market scenarios. It considers:
//! - Price changes in the underlying asset
//! - Changes in volatility
//! - Extreme market moves
//! - Time decay effects
//! - Short option exposure
//!
//! ## Core Components
//!
//! ### SPANMargin Structure
//!
//! ```rust
//! pub struct SPANMargin {
//!     scanning_range: f64,   // Overall market move range
//!     short_option_minimum: f64,   // Minimum charge for short options
//!     price_scan_range: f64,   // Range for price scenarios
//!     volatility_scan_range: f64,   // Range for volatility scenarios
//! }
//! ```
//!
//! ### Risk Scenarios
//!
//! The module evaluates positions under multiple scenarios combining:
//! - Price movements (up/down/unchanged)
//! - Volatility changes (up/down/unchanged)
//! - Time decay effects
//!
//! ## Usage Examples
//!
//! ### Basic Margin Calculation
//!
//! ```rust
//! use optionstratlib::{ExpirationDate, Options};
//! use optionstratlib::model::types::{ OptionStyle, OptionType, Side};
//! use positive::Positive;
//! use optionstratlib::model::position::Position;
//! use positive::pos_or_panic;
//! use chrono::Utc;
//! use rust_decimal_macros::dec;
//! use optionstratlib::risk::SPANMargin;
//!
//! fn main() -> Result<(), optionstratlib::error::Error> {
//!     // Create an option position
//!     let option = Options::new(
//!         OptionType::European,
//!         Side::Short,
//!         "STOCK".to_string(),
//!         pos_or_panic!(150.0),   // Strike price
//!         ExpirationDate::Days(pos_or_panic!(30.0)),
//!         pos_or_panic!(0.2),   // Volatility
//!         Positive::ONE,   // Quantity
//!         pos_or_panic!(155.0),   // Current price
//!         dec!(0.05),   // Risk-free rate
//!         OptionStyle::Call,
//!         Positive::ZERO,   // Dividend yield
//!         None,   // Exotic parameters
//!     );
//!
//!     let position = Position {
//!         option,
//!         premium: pos_or_panic!(5.0),
//!         date: Utc::now(),
//!         open_fee: pos_or_panic!(0.5),
//!         close_fee: pos_or_panic!(0.5),
//!         epic: None,
//!         extra_fields: None,
//!     };
//!
//!     // Create SPAN calculator
//!     let span = SPANMargin::new(
//!         dec!(0.10),   // 10% short option minimum
//!         dec!(0.05),   // 5% price scan range
//!         dec!(0.10),   // 10% volatility scan range
//!     );
//!
//!     // Calculate margin requirement
//!     let margin = span.calculate_margin(&position)?;
//!     Ok(())
//! }
//! ```
//!
//! ### Portfolio Analysis
//!
//! ```rust
//! use chrono::Utc;
//! use rust_decimal::Decimal;
//! use rust_decimal_macros::dec;
//! use optionstratlib::{ExpirationDate, Options};
//! use optionstratlib::model::types::{ OptionStyle, OptionType, Side};
//! use optionstratlib::model::position::Position;
//! use positive::Positive;
//! use positive::pos_or_panic;
//! use optionstratlib::risk::SPANMargin;
//!
//! fn main() -> Result<(), optionstratlib::error::Error> {
//!     let option = Options {
//!         option_type: OptionType::European,
//!         side: Side::Long,
//!         underlying_symbol: "AAPL".to_string(),
//!         strike_price: Positive::HUNDRED,
//!         expiration_date: ExpirationDate::Days(pos_or_panic!(30.0)),
//!         implied_volatility: pos_or_panic!(0.2),
//!         quantity: Positive::ONE,
//!         underlying_price: pos_or_panic!(105.0),
//!         risk_free_rate: dec!(0.05),
//!         option_style: OptionStyle::Call,
//!         dividend_yield: pos_or_panic!(0.01),
//!         exotic_params: None,
//!     };
//!     // Create multiple positions
//!     let positions = vec![
//!         Position {
//!             option: option.clone(),
//!             premium: pos_or_panic!(5.0),
//!             date: Utc::now(),
//!             open_fee: pos_or_panic!(0.5),
//!             close_fee: pos_or_panic!(0.5),
//!             epic: None,
//!             extra_fields: None,
//!         },
//!         Position {
//!             option,
//!             premium: pos_or_panic!(3.0),
//!             date: Utc::now(),
//!             open_fee: pos_or_panic!(0.5),
//!             close_fee: pos_or_panic!(0.5),
//!             epic: None,
//!             extra_fields: None,
//!         },
//!     ];
//!
//!     let span = SPANMargin::new(dec!(0.10), dec!(0.05), dec!(0.10));
//!
//!     // Calculate margin for each position; propagate any pricing error.
//!     let margins: Vec<Decimal> = positions
//!         .iter()
//!         .map(|pos| span.calculate_margin(pos))
//!         .collect::<Result<Vec<_>, _>>()?;
//!     Ok(())
//! }
//! ```
//!
//! ## Implementation Details
//!
//! ### Risk Array Calculation
//!
//! The risk array is calculated by:
//! 1. Generating price scenarios
//! 2. Generating volatility scenarios
//! 3. Calculating potential loss in each scenario
//! 4. Taking the maximum loss as the base margin requirement
//!
//! ### Short Option Minimum
//!
//! Additional protection against short option positions:
//! - Applied when the position is short
//! - Based on the underlying price and quantity
//! - Acts as a floor for the margin requirement
//!
//!
//! ## Performance Considerations
//!
//! - Time complexity: O(n * m) where n is the number of price scenarios and m is the number of volatility scenarios
//! - Memory complexity: O(n * m) for storing the risk array
//! - Calculation intensive due to multiple option pricing calculations per position
//!
//! ## Notes
//!
//! - All parameters should be provided as decimals (e.g., 0.15 for 15%)
//! - The module uses Black-Scholes pricing for scenario calculations
//! - Short option minimum is always enforced for short positions
//! - Results are conservative estimates of potential losses

mod model;
mod span;

pub use model::{RiskCategory, RiskMetricsSimulation};
pub use span::SPANMargin;