diff --git a/src/backtesting/results.rs b/src/backtesting/results.rs index 9630b775..6c887ccf 100644 --- a/src/backtesting/results.rs +++ b/src/backtesting/results.rs @@ -196,6 +196,7 @@ impl SimulationStatsResult { /// - P&L statistics (total, average, max, min) /// - Holding period information /// - Exit reason distribution + #[inline(never)] pub fn print_summary(&self) { use prettytable::{Cell, Row, Table, color, format}; use rust_decimal_macros::dec; @@ -351,6 +352,7 @@ impl SimulationStatsResult { /// - Final P&L /// - Holding period /// - Exit reason + #[inline(never)] pub fn print_individual_results(&self) { use prettytable::{Cell, Row, Table, color, format}; use rust_decimal_macros::dec; diff --git a/src/chains/chain.rs b/src/chains/chain.rs index a1a6340c..54d75513 100644 --- a/src/chains/chain.rs +++ b/src/chains/chain.rs @@ -370,6 +370,7 @@ impl OptionChain { /// - `expiration_date` is missing from price params /// - Failed to get days from expiration date /// - Failed to get date string from expiration date + #[inline(never)] pub fn build_chain(params: &OptionChainBuildParams) -> Result { let underlying_price = params .price_params @@ -1090,6 +1091,7 @@ impl OptionChain { /// Returns [`ChainError::FileError`] wrapping a `FileErrorKind::IOError` /// when the file cannot be created or written, or /// `FileErrorKind::ParseError` when `csv` serialization fails. + #[inline(never)] pub fn save_to_csv(&self, file_path: &str) -> Result<(), ChainError> { let full_path = format!("{}/{}.csv", file_path, self.get_title()); let mut wtr = WriterBuilder::new().from_path(full_path)?; @@ -1170,6 +1172,7 @@ impl OptionChain { /// Returns [`ChainError::FileError`] wrapping a `FileErrorKind::IOError` /// when the file cannot be created or written, or /// `FileErrorKind::ParseError` when `serde_json` serialization fails. + #[inline(never)] pub fn save_to_json(&self, file_path: &str) -> Result<(), ChainError> { let full_path = format!("{}/{}.json", file_path, self.get_title()); let file = File::create(full_path)?; @@ -1223,6 +1226,7 @@ impl OptionChain { /// `FileErrorKind::ParseError` when the CSV records cannot be parsed. /// Invalid option data (bad strike, volatility or price) surfaces as /// [`ChainError::OptionDataError`]. + #[inline(never)] pub fn load_from_csv(file_path: &str) -> Result { let mut rdr = csv::Reader::from_path(file_path)?; let mut options = BTreeSet::new(); @@ -1313,6 +1317,7 @@ impl OptionChain { /// Returns [`ChainError::FileError`] wrapping `FileErrorKind::IOError` /// when the file cannot be opened, or `FileErrorKind::ParseError` /// when `serde_json` deserialization fails. + #[inline(never)] pub fn load_from_json(file_path: &str) -> Result { let file = File::open(file_path)?; let mut option_chain: OptionChain = serde_json::from_reader(file)?; @@ -1586,6 +1591,7 @@ impl OptionChain { /// # Returns /// /// An iterator where each item is a reference to an `OptionData`. + #[inline] pub fn iter(&self) -> impl Iterator { self.get_single_iter() } @@ -1601,6 +1607,7 @@ impl OptionChain { /// Since the `options` field is stored as a `BTreeSet`, the elements are ordered /// in ascending order based on the sorting rules of `BTreeSet` (typically defined by `Ord` implementation). /// + #[inline] pub fn get_single_iter(&self) -> impl Iterator { self.options.iter().filter(|option| option.validate()) } @@ -2648,6 +2655,7 @@ impl OptionChain { /// # Returns /// /// A `String` representing the expiration date of the option chain. + #[inline] #[must_use] pub fn get_expiration_date(&self) -> String { self.expiration_date.clone() @@ -2657,6 +2665,7 @@ impl OptionChain { /// /// # Returns /// * `Option` - The expiration date if it can be parsed, or `None` if parsing fails. + #[inline] #[must_use] pub fn get_expiration(&self) -> Option { ExpirationDate::from_string(&self.expiration_date).ok() @@ -3181,6 +3190,7 @@ impl OptionChain { /// This method prints the option chain directly to stdout using prettytable's /// `printstd()` method, which properly displays colors in the terminal. /// Use this method instead of `info!("{}", chain)` to see colored headers. + #[inline(never)] pub fn show(&self) { // Print header information let mut header = Table::new(); diff --git a/src/chains/optiondata.rs b/src/chains/optiondata.rs index eaa502fa..9fb3180f 100644 --- a/src/chains/optiondata.rs +++ b/src/chains/optiondata.rs @@ -246,6 +246,7 @@ impl OptionData { /// /// # Note /// The `Positive` type is assumed to enforce non-negative values for correctness. + #[inline] #[must_use] pub fn get_call_spread(&self) -> Option { match (self.call_bid, self.call_ask) { @@ -281,6 +282,7 @@ impl OptionData { /// /// # Errors /// This function does not return an error. It simply returns `None` if the calculation is not feasible. + #[inline] #[must_use] pub fn get_call_spread_per(&self) -> Option { match (self.call_bid, self.call_ask) { @@ -310,6 +312,7 @@ impl OptionData { /// to convert to a numeric type for calculation purposes. /// The spread is always represented as a positive value. /// + #[inline] #[must_use] pub fn get_put_spread(&self) -> Option { match (self.put_bid, self.put_ask) { @@ -337,6 +340,7 @@ impl OptionData { /// /// # Note /// This function returns `None` if there are missing values for either `put_bid` or `put_ask`. + #[inline] #[must_use] pub fn get_put_spread_per(&self) -> Option { match (self.put_bid, self.put_ask) { @@ -364,6 +368,7 @@ impl OptionData { /// /// Ensure that the `Positive` type enforces constraints to prevent invalid values /// such as negative volatility. + #[inline] #[must_use] pub fn get_volatility(&self) -> Positive { self.implied_volatility @@ -373,6 +378,7 @@ impl OptionData { /// /// # Arguments /// * `volatility` - A positive decimal value representing the implied volatility. + #[inline] pub fn set_volatility(&mut self, volatility: &Positive) { self.implied_volatility = *volatility; } @@ -449,6 +455,7 @@ impl OptionData { /// a valid positive number. /// /// [`Positive`]: struct.Positive.html + #[inline] #[must_use] pub fn strike(&self) -> Positive { self.strike_price @@ -464,6 +471,7 @@ impl OptionData { /// # Returns /// /// `true` if all required call option data is present, `false` otherwise. + #[inline] pub(crate) fn valid_call(&self) -> bool { self.strike_price > Positive::ZERO && self.call_bid.is_some() && self.call_ask.is_some() } @@ -478,6 +486,7 @@ impl OptionData { /// # Returns /// /// `true` if all required put option data is present, `false` otherwise. + #[inline] pub(crate) fn valid_put(&self) -> bool { self.strike_price > Positive::ZERO && self.put_bid.is_some() && self.put_ask.is_some() } @@ -490,6 +499,7 @@ impl OptionData { /// # Returns /// /// The call option's ask price as a `Positive` value, or `None` if the price is unavailable. + #[inline] #[must_use] pub fn get_call_buy_price(&self) -> Option { self.call_ask @@ -503,6 +513,7 @@ impl OptionData { /// # Returns /// /// The call option's bid price as a `Positive` value, or `None` if the price is unavailable. + #[inline] #[must_use] pub fn get_call_sell_price(&self) -> Option { self.call_bid @@ -516,6 +527,7 @@ impl OptionData { /// # Returns /// /// The put option's ask price as a `Positive` value, or `None` if the price is unavailable. + #[inline] #[must_use] pub fn get_put_buy_price(&self) -> Option { self.put_ask @@ -529,6 +541,7 @@ impl OptionData { /// # Returns /// /// The put option's bid price as a `Positive` value, or `None` if the price is unavailable. + #[inline] #[must_use] pub fn get_put_sell_price(&self) -> Option { self.put_bid @@ -540,6 +553,7 @@ impl OptionData { /// fields of the `OptionData` struct are `None`, indicating missing price information. /// It returns `false` if all four fields have valid price data. /// + #[inline] #[must_use] pub fn some_price_is_none(&self) -> bool { self.call_bid.is_none() @@ -1070,6 +1084,7 @@ impl OptionData { /// A tuple containing: /// * First element: The call option mid-price (bid+ask)/2, or `None` if not available /// * Second element: The put option mid-price (bid+ask)/2, or `None` if not available + #[inline] #[must_use] pub fn get_mid_prices(&self) -> (Option, Option) { (self.call_middle, self.put_middle) @@ -1101,6 +1116,7 @@ impl OptionData { /// * Second element: `Option` - The delta value for the put option. May be `None` if /// the delta value is not available or could not be calculated. /// + #[inline] #[must_use] pub fn current_deltas(&self) -> (Option, Option) { (self.delta_call, self.delta_put) @@ -1117,6 +1133,7 @@ impl OptionData { /// * `Option` - The current gamma value wrapped in `Some` if it exists, /// or `None` if the gamma value is not set. /// + #[inline] #[must_use] pub fn current_gamma(&self) -> Option { self.gamma diff --git a/src/error/chains.rs b/src/error/chains.rs index 6b78d1db..8049c40e 100644 --- a/src/error/chains.rs +++ b/src/error/chains.rs @@ -517,6 +517,8 @@ impl ChainError { /// /// A `ChainError` containing the strike validation error details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_strike(strike: f64, reason: &str) -> Self { ChainError::OptionDataError(OptionDataErrorKind::InvalidStrike { strike, @@ -538,6 +540,8 @@ impl ChainError { /// /// A `ChainError` containing the volatility validation error details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_volatility(volatility: Option, reason: &str) -> Self { ChainError::OptionDataError(OptionDataErrorKind::InvalidVolatility { volatility, @@ -560,6 +564,8 @@ impl ChainError { /// /// A `ChainError` containing the price validation error details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_prices(bid: Option, ask: Option, reason: &str) -> Self { ChainError::OptionDataError(OptionDataErrorKind::InvalidPrices { bid, @@ -583,6 +589,8 @@ impl ChainError { /// /// A `ChainError` containing the strategy legs validation error details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_legs(expected: usize, found: usize, reason: &str) -> Self { ChainError::StrategyError(StrategyErrorKind::InvalidLegs { expected, @@ -605,6 +613,8 @@ impl ChainError { /// /// A `ChainError` containing the parameter validation error details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_parameters(parameter: &str, reason: &str) -> Self { ChainError::ChainBuildError(ChainBuildErrorKind::InvalidParameters { parameter: parameter.to_string(), @@ -625,6 +635,8 @@ impl ChainError { /// /// A `ChainError` containing the parameter validation error details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_price_calculation(reason: &str) -> Self { ChainError::OptionDataError(OptionDataErrorKind::PriceCalculationError( reason.to_string(), diff --git a/src/error/curves.rs b/src/error/curves.rs index 127ef401..50663afd 100644 --- a/src/error/curves.rs +++ b/src/error/curves.rs @@ -190,6 +190,8 @@ impl CurveError { /// - For example, attempting an unsupported computation method on a specific curve type. /// #[must_use] + #[cold] + #[inline(never)] pub fn operation_not_supported(operation: &str, reason: &str) -> Self { CurveError::OperationError(OperationErrorKind::NotSupported { operation: operation.to_string(), @@ -209,6 +211,8 @@ impl CurveError { /// - For example, providing malformed or missing parameters for interpolation or curve construction. /// #[must_use] + #[cold] + #[inline(never)] pub fn invalid_parameters(operation: &str, reason: &str) -> Self { CurveError::OperationError(OperationErrorKind::InvalidParameters { operation: operation.to_string(), diff --git a/src/error/decimal.rs b/src/error/decimal.rs index ecb2c18b..639e9c6c 100644 --- a/src/error/decimal.rs +++ b/src/error/decimal.rs @@ -229,6 +229,8 @@ impl DecimalError { /// /// A new `DecimalError::InvalidValue` instance #[must_use] + #[cold] + #[inline(never)] pub fn invalid_value(value: f64, reason: &str) -> Self { DecimalError::InvalidValue { value, @@ -249,6 +251,8 @@ impl DecimalError { /// # Returns /// /// A new `DecimalError::ArithmeticError` instance + #[cold] + #[inline(never)] #[must_use] pub fn arithmetic_error(operation: &str, reason: &str) -> Self { DecimalError::ArithmeticError { @@ -271,6 +275,8 @@ impl DecimalError { /// # Returns /// /// A new `DecimalError::ConversionError` instance + #[cold] + #[inline(never)] #[must_use] pub fn conversion_error(from_type: &str, to_type: &str, reason: &str) -> Self { DecimalError::ConversionError { @@ -293,6 +299,8 @@ impl DecimalError { /// # Returns /// /// A new `DecimalError::OutOfBounds` instance + #[cold] + #[inline(never)] #[must_use] pub fn out_of_bounds(value: f64, min: f64, max: f64) -> Self { DecimalError::OutOfBounds { value, min, max } @@ -311,6 +319,8 @@ impl DecimalError { /// # Returns /// /// A new `DecimalError::InvalidPrecision` instance + #[cold] + #[inline(never)] #[must_use] pub fn invalid_precision(precision: i32, reason: &str) -> Self { DecimalError::InvalidPrecision { diff --git a/src/error/greeks.rs b/src/error/greeks.rs index ee37ff12..27d614f2 100644 --- a/src/error/greeks.rs +++ b/src/error/greeks.rs @@ -495,6 +495,8 @@ impl GreeksError { /// # Returns /// A `GreeksError::InputError` with `InvalidVolatility` kind #[must_use] + #[cold] + #[inline(never)] pub fn invalid_volatility(value: f64, reason: &str) -> Self { GreeksError::InputError(InputErrorKind::InvalidVolatility { value, @@ -514,6 +516,8 @@ impl GreeksError { /// # Returns /// A `GreeksError::InputError` with `InvalidTime` kind #[must_use] + #[cold] + #[inline(never)] pub fn invalid_time(value: Positive, reason: &str) -> Self { GreeksError::InputError(InputErrorKind::InvalidTime { value, @@ -533,6 +537,8 @@ impl GreeksError { /// # Returns /// A `GreeksError::CalculationError` with `DeltaError` kind #[must_use] + #[cold] + #[inline(never)] pub fn delta_error(reason: &str) -> Self { GreeksError::CalculationError(CalculationErrorKind::DeltaError { reason: reason.to_string(), @@ -545,9 +551,9 @@ impl GreeksError { /// Intended to be used at `f64` → `Decimal` boundaries inside /// Greeks kernels, as a thin constructor paired with an /// `if !value.is_finite() { .. }` guard. - #[must_use] - #[inline] #[cold] + #[inline(never)] + #[must_use] pub fn non_finite(context: &'static str, value: f64) -> Self { GreeksError::NonFinite { context, value } } diff --git a/src/error/options.rs b/src/error/options.rs index 9361fe93..5fa58855 100644 --- a/src/error/options.rs +++ b/src/error/options.rs @@ -274,6 +274,8 @@ impl OptionsError { /// /// An `OptionsError::ValidationError` variant with formatted fields #[must_use] + #[cold] + #[inline(never)] pub fn validation_error(field: &str, reason: &str) -> Self { OptionsError::ValidationError { field: field.to_string(), @@ -294,6 +296,8 @@ impl OptionsError { /// /// An `OptionsError::PricingError` variant with formatted fields #[must_use] + #[cold] + #[inline(never)] pub fn pricing_error(method: &str, reason: &str) -> Self { OptionsError::PricingError { method: method.to_string(), @@ -315,6 +319,8 @@ impl OptionsError { /// /// An `OptionsError::GreeksCalculationError` variant with formatted fields #[must_use] + #[cold] + #[inline(never)] pub fn greeks_error(greek: &str, reason: &str) -> Self { OptionsError::GreeksCalculationError { greek: greek.to_string(), @@ -336,6 +342,8 @@ impl OptionsError { /// /// An `OptionsError::TimeError` variant with formatted fields #[must_use] + #[cold] + #[inline(never)] pub fn time_error(operation: &str, reason: &str) -> Self { OptionsError::TimeError { operation: operation.to_string(), @@ -355,6 +363,8 @@ impl OptionsError { /// /// An `OptionsError::PayoffError` variant with formatted reason #[must_use] + #[cold] + #[inline(never)] pub fn payoff_error(reason: &str) -> Self { OptionsError::PayoffError { reason: reason.to_string(), @@ -375,6 +385,8 @@ impl OptionsError { /// /// An `OptionsError::UpdateError` variant with formatted fields #[must_use] + #[cold] + #[inline(never)] pub fn update_error(field: &str, reason: &str) -> Self { OptionsError::UpdateError { field: field.to_string(), diff --git a/src/error/position.rs b/src/error/position.rs index 645180fd..b9f785e1 100644 --- a/src/error/position.rs +++ b/src/error/position.rs @@ -370,6 +370,8 @@ impl PositionError { /// /// A `PositionError::StrategyError` variant with UnsupportedOperation details #[must_use] + #[cold] + #[inline(never)] pub fn unsupported_operation(strategy_type: &str, operation: &str) -> Self { PositionError::StrategyError(StrategyErrorKind::UnsupportedOperation { strategy_type: strategy_type.to_string(), @@ -388,6 +390,8 @@ impl PositionError { /// /// A `PositionError::StrategyError` variant with StrategyFull details #[must_use] + #[cold] + #[inline(never)] pub fn strategy_full(strategy_type: &str, max_positions: usize) -> Self { PositionError::StrategyError(StrategyErrorKind::StrategyFull { strategy_type: strategy_type.to_string(), @@ -406,6 +410,8 @@ impl PositionError { /// /// A `PositionError::ValidationError` variant with InvalidSize details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_position_size(size: f64, reason: &str) -> Self { PositionError::ValidationError(PositionValidationErrorKind::InvalidSize { size, @@ -424,6 +430,8 @@ impl PositionError { /// /// A `PositionError::ValidationError` variant with IncompatibleSide details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_position_type(position_side: Side, reason: String) -> Self { PositionError::ValidationError(PositionValidationErrorKind::IncompatibleSide { position_side, @@ -442,6 +450,8 @@ impl PositionError { /// /// A `PositionError::ValidationError` variant with IncompatibleStyle details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_position_style(style: OptionStyle, reason: String) -> Self { PositionError::ValidationError(PositionValidationErrorKind::IncompatibleStyle { style, @@ -459,6 +469,8 @@ impl PositionError { /// /// A `PositionError::ValidationError` variant with InvalidPosition details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_position(reason: &str) -> Self { PositionError::ValidationError(PositionValidationErrorKind::InvalidPosition { reason: reason.to_string(), @@ -476,6 +488,8 @@ impl PositionError { /// /// A `PositionError::UpdateError` variant with PositionFieldUpdateFailure details #[must_use] + #[cold] + #[inline(never)] pub fn invalid_position_update(field: String, reason: String) -> Self { PositionError::UpdateError(PositionUpdateErrorKind::PositionFieldUpdateFailure { field, diff --git a/src/error/pricing.rs b/src/error/pricing.rs index 6f721b95..9f0b815f 100644 --- a/src/error/pricing.rs +++ b/src/error/pricing.rs @@ -122,6 +122,8 @@ impl PricingError { /// * `method` - Name of the pricing method that failed /// * `reason` - Detailed reason for the failure #[must_use] + #[cold] + #[inline(never)] pub fn method_error(method: &str, reason: &str) -> Self { PricingError::MethodError { method: method.to_string(), @@ -134,6 +136,8 @@ impl PricingError { /// # Arguments /// * `reason` - Detailed reason for the simulation failure #[must_use] + #[cold] + #[inline(never)] pub fn simulation_error(reason: &str) -> Self { PricingError::SimulationError { reason: reason.to_string(), @@ -145,6 +149,8 @@ impl PricingError { /// # Arguments /// * `reason` - Detailed reason for the invalid engine #[must_use] + #[cold] + #[inline(never)] pub fn invalid_engine(reason: &str) -> Self { PricingError::InvalidEngine { reason: reason.to_string(), @@ -155,7 +161,8 @@ impl PricingError { /// replacement for the former `OtherError` catch-all. Prefer /// [`PricingError::method_error`] with a specific method name when known. #[must_use] - #[inline] + #[cold] + #[inline(never)] pub fn other(reason: &str) -> Self { PricingError::MethodError { method: "pricing".to_string(), @@ -169,6 +176,8 @@ impl PricingError { /// * `option_type` - The option type that is not supported /// * `method` - The pricing method that does not support this option type #[must_use] + #[cold] + #[inline(never)] pub fn unsupported_option_type(option_type: &str, method: &str) -> Self { PricingError::UnsupportedOptionType { option_type: option_type.to_string(), @@ -182,9 +191,9 @@ impl PricingError { /// Intended to be used at `f64` → `Decimal` boundaries inside /// pricing kernels, as a thin constructor paired with an /// `if !value.is_finite() { .. }` guard. - #[must_use] - #[inline] #[cold] + #[inline(never)] + #[must_use] pub fn non_finite(context: &'static str, value: f64) -> Self { PricingError::NonFinite { context, value } } diff --git a/src/error/probability.rs b/src/error/probability.rs index 4f0991c8..d1d9953d 100644 --- a/src/error/probability.rs +++ b/src/error/probability.rs @@ -496,6 +496,8 @@ impl From for ProbabilityError { impl ProbabilityError { /// Creates a new invalid probability error #[must_use] + #[cold] + #[inline(never)] pub fn invalid_probability(value: f64, reason: &str) -> Self { ProbabilityError::CalculationError(ProbabilityCalculationErrorKind::InvalidProbability { value, @@ -505,6 +507,8 @@ impl ProbabilityError { /// Creates a new invalid profit range error #[must_use] + #[cold] + #[inline(never)] pub fn invalid_profit_range(range: &str, reason: &str) -> Self { ProbabilityError::RangeError(ProfitLossRangeErrorKind::InvalidProfitRange { range: range.to_string(), @@ -514,6 +518,8 @@ impl ProbabilityError { /// Creates a new invalid expiration error #[must_use] + #[cold] + #[inline(never)] pub fn invalid_expiration(reason: &str) -> Self { ProbabilityError::ExpirationError(ExpirationErrorKind::InvalidExpiration { reason: reason.to_string(), diff --git a/src/error/simulation.rs b/src/error/simulation.rs index 7b6148ae..243e0361 100644 --- a/src/error/simulation.rs +++ b/src/error/simulation.rs @@ -140,7 +140,8 @@ impl SimulationError { /// # Arguments /// * `reason` - Detailed reason for the walk generation failure #[must_use] - #[inline] + #[cold] + #[inline(never)] pub fn walk_error(reason: &str) -> Self { SimulationError::WalkError { reason: reason.to_string(), @@ -152,7 +153,8 @@ impl SimulationError { /// # Arguments /// * `reason` - Detailed reason for the invalid parameters #[must_use] - #[inline] + #[cold] + #[inline(never)] pub fn invalid_parameters(reason: &str) -> Self { SimulationError::InvalidParameters { reason: reason.to_string(), @@ -164,7 +166,8 @@ impl SimulationError { /// # Arguments /// * `reason` - Detailed reason for the step calculation failure #[must_use] - #[inline] + #[cold] + #[inline(never)] pub fn step_error(reason: &str) -> Self { SimulationError::StepError { reason: reason.to_string(), @@ -173,9 +176,9 @@ impl SimulationError { /// Creates a [`SimulationError::NonFinite`] from a static call-site /// tag and the offending `f64` value. - #[must_use] - #[inline] #[cold] + #[inline(never)] + #[must_use] pub fn non_finite(context: &'static str, value: f64) -> Self { SimulationError::NonFinite { context, value } } diff --git a/src/error/strategies.rs b/src/error/strategies.rs index 3a807ce1..97c6ad95 100644 --- a/src/error/strategies.rs +++ b/src/error/strategies.rs @@ -332,6 +332,8 @@ impl StrategyError { /// let error = StrategyError::operation_not_supported("butterfly_adjustment", "IronCondor"); /// ``` #[must_use] + #[cold] + #[inline(never)] pub fn operation_not_supported(operation: &str, strategy_type: &str) -> Self { StrategyError::OperationError(OperationErrorKind::NotSupported { operation: operation.to_string(), @@ -363,6 +365,8 @@ impl StrategyError { /// ); /// ``` #[must_use] + #[cold] + #[inline(never)] pub fn invalid_parameters(operation: &str, reason: &str) -> Self { StrategyError::OperationError(OperationErrorKind::InvalidParameters { operation: operation.to_string(), diff --git a/src/error/surfaces.rs b/src/error/surfaces.rs index 5a51106a..c564f1a0 100644 --- a/src/error/surfaces.rs +++ b/src/error/surfaces.rs @@ -112,6 +112,8 @@ impl SurfaceError { /// - For example, attempting an unsupported computation method on a specific curve type. /// #[must_use] + #[cold] + #[inline(never)] pub fn operation_not_supported(operation: &str, reason: &str) -> Self { SurfaceError::OperationError(OperationErrorKind::NotSupported { operation: operation.to_string(), @@ -131,6 +133,8 @@ impl SurfaceError { /// - For example, providing malformed or missing parameters for interpolation or curve construction. /// #[must_use] + #[cold] + #[inline(never)] pub fn invalid_parameters(operation: &str, reason: &str) -> Self { SurfaceError::OperationError(OperationErrorKind::InvalidParameters { operation: operation.to_string(), diff --git a/src/error/trade.rs b/src/error/trade.rs index 26de8360..10526021 100644 --- a/src/error/trade.rs +++ b/src/error/trade.rs @@ -57,6 +57,8 @@ impl TradeError { /// /// A `TradeError::InvalidTrade` variant #[must_use] + #[cold] + #[inline(never)] pub fn invalid_trade(reason: &str) -> Self { TradeError::InvalidTrade { reason: reason.to_string(), @@ -73,6 +75,8 @@ impl TradeError { /// /// A `TradeError::InvalidTradeStatus` variant #[must_use] + #[cold] + #[inline(never)] pub fn invalid_trade_status(reason: &str) -> Self { TradeError::InvalidTradeStatus { reason: reason.to_string(), diff --git a/src/error/volatility.rs b/src/error/volatility.rs index d64a27db..975a5e35 100644 --- a/src/error/volatility.rs +++ b/src/error/volatility.rs @@ -162,9 +162,9 @@ pub enum VolatilityError { impl VolatilityError { /// Creates a [`VolatilityError::NonFinite`] from a static call-site /// tag and the offending `f64` value. - #[must_use] - #[inline] #[cold] + #[inline(never)] + #[must_use] pub fn non_finite(context: &'static str, value: f64) -> Self { VolatilityError::NonFinite { context, value } } diff --git a/src/greeks/utils.rs b/src/greeks/utils.rs index c2d3ebbf..bc781a98 100644 --- a/src/greeks/utils.rs +++ b/src/greeks/utils.rs @@ -82,6 +82,7 @@ use statrs::distribution::{ContinuousCDF, Normal}; /// Err(e) => error!("Error: {:?}", e), /// } /// ``` +#[inline] pub fn d1( underlying_price: Positive, strike_price: Positive, @@ -200,6 +201,7 @@ pub fn d1( /// # Ok(()) /// # } /// ``` +#[inline] pub fn d2( underlying_price: Positive, strike_price: Positive, @@ -290,6 +292,7 @@ pub fn d2( /// # Notes /// /// The function uses the `Decimal` type for precision and error handling. The result is returned +#[inline] pub fn n(x: Decimal) -> Result { // 1 / sqrt(2π) — standard normal PDF normalisation constant. // Precomputed so we avoid the runtime fallible sqrt on Decimal. @@ -340,6 +343,7 @@ pub fn n(x: Decimal) -> Result { /// the provided input type `T`. Improper or undefined behavior of `n` may lead /// to unexpected results or runtime errors. #[allow(dead_code)] +#[inline] pub(crate) fn n_prime(x: Decimal) -> Result { Ok(-x * n(x)?) // -x * n(x) } @@ -386,6 +390,7 @@ pub(crate) fn n_prime(x: Decimal) -> Result { /// Err(e) => error!("Error: {:?}", e), /// } /// ``` +#[inline] pub fn big_n(x: Decimal) -> Result { let Some(x_f64) = x.to_f64() else { return Err(DecimalError::ConversionError { @@ -442,6 +447,7 @@ pub fn big_n(x: Decimal) -> Result { /// - `d1_value`: The calculated d1 value. /// - `d2_value`: The calculated d2 value. /// +#[inline] pub(crate) fn calculate_d_values(option: &Options) -> Result<(Decimal, Decimal), GreeksError> { let b = option.risk_free_rate - option.dividend_yield.to_dec(); let d1_value = d1( diff --git a/src/pnl/model.rs b/src/pnl/model.rs index 1c4b8014..21336817 100644 --- a/src/pnl/model.rs +++ b/src/pnl/model.rs @@ -49,6 +49,7 @@ impl PnLRange { /// let range = PnLRange::new(-100, 100); /// // Creates a PnL range from -100 (inclusive) to 100 (exclusive) /// ``` + #[inline] #[must_use] pub fn new(lower: i32, upper: i32) -> Self { Self { lower, upper } diff --git a/src/pnl/transaction.rs b/src/pnl/transaction.rs index f9b3f9a9..51e0cddc 100644 --- a/src/pnl/transaction.rs +++ b/src/pnl/transaction.rs @@ -95,60 +95,70 @@ impl Transaction { // Getters /// Gets the date and time of the transaction. + #[inline] #[must_use] pub fn date_time(&self) -> Option> { self.date_time } /// Gets the option type. + #[inline] #[must_use] pub fn option_type(&self) -> OptionType { self.option_type.clone() } /// Gets the side (Long or Short). + #[inline] #[must_use] pub fn side(&self) -> Side { self.side } /// Gets the option style (Call or Put). + #[inline] #[must_use] pub fn option_style(&self) -> OptionStyle { self.option_style } /// Gets the quantity of contracts. + #[inline] #[must_use] pub fn quantity(&self) -> Positive { self.quantity } /// Gets the premium. + #[inline] #[must_use] pub fn premium(&self) -> Positive { self.premium } /// Gets the fees. + #[inline] #[must_use] pub fn fees(&self) -> Positive { self.fees } /// Gets the underlying price, if available. + #[inline] #[must_use] pub fn underlying_price(&self) -> Option { self.underlying_price } /// Gets the days to expiration, if available. + #[inline] #[must_use] pub fn days_to_expiration(&self) -> Option { self.days_to_expiration } /// Gets the implied volatility, if available. + #[inline] #[must_use] pub fn implied_volatility(&self) -> Option { self.implied_volatility @@ -161,6 +171,7 @@ impl Transaction { /// # Parameters /// /// * `iv` - The new implied volatility value + #[inline] pub fn update_implied_volatility(&mut self, iv: Positive) { self.implied_volatility = Some(iv); } @@ -170,6 +181,7 @@ impl Transaction { /// # Parameters /// /// * `price` - The new underlying price value + #[inline] pub fn update_underlying_price(&mut self, price: Positive) { self.underlying_price = Some(price); } @@ -179,6 +191,7 @@ impl Transaction { /// # Parameters /// /// * `days` - The new days to expiration value + #[inline] pub fn update_days_to_expiration(&mut self, days: Positive) { self.days_to_expiration = Some(days); } diff --git a/src/pnl/utils.rs b/src/pnl/utils.rs index cf20679a..e0dc5909 100644 --- a/src/pnl/utils.rs +++ b/src/pnl/utils.rs @@ -93,6 +93,7 @@ impl PnL { /// Utc::now(), // Current timestamp /// ); /// ``` + #[inline] #[must_use] pub fn new( realized: Option, @@ -135,6 +136,7 @@ impl PnL { /// /// assert_eq!(pnl.total_pnl(), Some(dec!(750.0))); /// ``` + #[inline] #[must_use] pub fn total_pnl(&self) -> Option { match (self.realized, self.unrealized) { diff --git a/src/pricing/payoff.rs b/src/pricing/payoff.rs index 62c3a02c..bb74110f 100644 --- a/src/pricing/payoff.rs +++ b/src/pricing/payoff.rs @@ -140,6 +140,7 @@ impl PayoffInfo { /// # Ok(()) /// # } /// ``` + #[inline] #[must_use] pub fn spot_prices_len(&self) -> Option { self.spot_prices.as_ref().map(|vec| vec.len()) @@ -159,6 +160,7 @@ impl PayoffInfo { /// This function evaluates the payoff based on the option style: /// - For a call option: Max(spot price - strike price, 0) /// - For a put option: Max(strike price - spot price, 0) +#[inline] pub(crate) fn standard_payoff(info: &PayoffInfo) -> f64 { trace!("standard_payoff - spot: {}", info.spot); trace!("standard_payoff - info.strike: {}", info.strike); diff --git a/src/pricing/utils.rs b/src/pricing/utils.rs index 5926e043..0a7a4a4c 100644 --- a/src/pricing/utils.rs +++ b/src/pricing/utils.rs @@ -114,6 +114,7 @@ pub fn simulate_returns( /// /// * A floating point number representing the up factor calculated based on the given volatility and time increment. /// +#[inline] pub(crate) fn calculate_up_factor( volatility: Positive, dt: Decimal, @@ -136,6 +137,7 @@ pub(crate) fn calculate_up_factor( /// A floating-point number representing the down factor, calculated using the /// given volatility and time step. /// +#[inline] pub(crate) fn calculate_down_factor( volatility: Positive, dt: Decimal, @@ -159,6 +161,7 @@ pub(crate) fn calculate_down_factor( /// # Returns /// /// Returns the calculated probability which is clamped between `CLAMP_MIN` and `CLAMP_MAX`. +#[inline] pub(crate) fn calculate_probability( int_rate: Decimal, dt: Decimal, @@ -183,6 +186,7 @@ pub(crate) fn calculate_probability( /// # Returns /// A floating-point number representing the discount factor. /// +#[inline] pub(crate) fn calculate_discount_factor( int_rate: Decimal, dt: Decimal, @@ -207,6 +211,7 @@ pub(crate) fn calculate_discount_factor( /// # Returns /// /// * A `f64` representing the calculated value of the current option node. +#[inline] pub(crate) fn option_node_value_wrapper( probability: Decimal, next: &mut [Vec], @@ -231,6 +236,7 @@ pub(crate) fn option_node_value_wrapper( /// /// # Returns /// The discounted expected value of the option node. +#[inline] pub(crate) fn option_node_value( probability: Decimal, price_up: Decimal, diff --git a/src/risk/span.rs b/src/risk/span.rs index 29d8a42a..41581245 100644 --- a/src/risk/span.rs +++ b/src/risk/span.rs @@ -74,6 +74,7 @@ impl SPANMargin { /// dec!(0.15) // 15% volatility scan range /// ); /// ``` + #[inline] #[must_use] pub fn new( short_option_minimum: Decimal, @@ -188,6 +189,7 @@ impl SPANMargin { /// # Returns /// /// A vector of three `Positive` values representing the price scenarios + #[inline] fn generate_price_scenarios(&self, underlying_price: Positive) -> Vec { vec![ underlying_price * (Decimal::ONE - self.price_scan_range), @@ -213,6 +215,7 @@ impl SPANMargin { /// # Returns /// /// A vector of three `Positive` values representing the volatility scenarios + #[inline] fn generate_volatility_scenarios(&self, implied_volatility: Positive) -> Vec { vec![ implied_volatility * (Decimal::ONE - self.volatility_scan_range), @@ -279,6 +282,7 @@ impl SPANMargin { /// `short_option_minimum * underlying_price * quantity` /// /// For long options, the function returns zero as the short option minimum doesn't apply. + #[inline] fn calculate_short_option_minimum(&self, position: &Position) -> Decimal { let option = &position.option; if option.is_short() { diff --git a/src/series/model.rs b/src/series/model.rs index 7ca31897..ec20268f 100644 --- a/src/series/model.rs +++ b/src/series/model.rs @@ -47,6 +47,7 @@ impl OptionSeries { /// - An empty `chains` field of type `BTreeMap`. /// - `None` for both `risk_free_rate` and `dividend_yield`. /// + #[inline] #[must_use] pub fn new(symbol: String, underlying_price: Positive) -> Self { Self { @@ -157,6 +158,7 @@ impl OptionSeries { /// - Failed to build any option chain in the series /// - Failed to get date string from expiration date /// - Missing underlying price in price params + #[inline(never)] pub fn build_series(params: &OptionSeriesBuildParams) -> Result { let mut params = params.clone(); let mut chains: BTreeMap = BTreeMap::new(); diff --git a/src/series/params.rs b/src/series/params.rs index df7aad0c..26a12981 100644 --- a/src/series/params.rs +++ b/src/series/params.rs @@ -37,6 +37,7 @@ impl OptionSeriesBuildParams { /// # Returns /// - A new `Self` instance initialized with the provided `chain_params` and `series`. /// + #[inline] #[must_use] pub fn new(chain_params: OptionChainBuildParams, series: Vec) -> Self { Self { @@ -60,6 +61,7 @@ impl OptionSeriesBuildParams { /// the `set_underlying_price` method of `chain_params` that could panic needs to /// be considered by the caller. /// + #[inline] pub fn set_underlying_price(&mut self, price: &Positive) { let price = Some(Box::new(*price)); self.chain_params.set_underlying_price(price); @@ -82,6 +84,7 @@ impl OptionSeriesBuildParams { /// - Use `Some(value)` to set a new positive implied volatility. /// - Pass `None` to clear the existing implied volatility. /// + #[inline] pub fn set_implied_volatility(&mut self, volatility: Positive) { self.chain_params.set_implied_volatility(volatility); } diff --git a/src/strategies/base.rs b/src/strategies/base.rs index 16883847..6e57803d 100644 --- a/src/strategies/base.rs +++ b/src/strategies/base.rs @@ -227,6 +227,7 @@ impl StrategyType { /// assert!(StrategyType::is_valid("BullCallSpread")); /// assert!(!StrategyType::is_valid("InvalidStrategy")); /// ``` + #[inline] #[must_use] pub fn is_valid(strategy: &str) -> bool { StrategyType::from_str(strategy).is_ok() @@ -351,6 +352,7 @@ impl Strategy { /// assert_eq!(strategy.max_loss, None); /// assert!(strategy.break_even_points.is_empty()); /// ``` + #[inline] #[must_use] pub fn new(name: String, kind: StrategyType, description: String) -> Self { Strategy { diff --git a/src/strategies/bear_call_spread.rs b/src/strategies/bear_call_spread.rs index b2a1d589..8bfe2ee8 100644 --- a/src/strategies/bear_call_spread.rs +++ b/src/strategies/bear_call_spread.rs @@ -136,6 +136,7 @@ impl BearCallSpread { /// call spread and are surfaced only to keep the constructor /// panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/bear_put_spread.rs b/src/strategies/bear_put_spread.rs index e35614b4..efcc592a 100644 --- a/src/strategies/bear_put_spread.rs +++ b/src/strategies/bear_put_spread.rs @@ -140,6 +140,7 @@ impl BearPutSpread { /// put spread and are surfaced only to keep the constructor /// panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/build/model.rs b/src/strategies/build/model.rs index 59da07eb..f4e5870b 100644 --- a/src/strategies/build/model.rs +++ b/src/strategies/build/model.rs @@ -55,6 +55,7 @@ impl StrategyRequest { /// /// # Returns /// A new `StrategyRequest` instance containing the provided strategy type and positions. + #[inline] #[must_use] pub fn new(strategy_type: StrategyType, positions: Vec) -> Self { Self { @@ -78,6 +79,7 @@ impl StrategyRequest { /// # Errors /// This method can return errors from the underlying strategy constructors or /// `StrategyError::NotImplemented` for strategies that are defined but not yet implemented. + #[inline(never)] pub fn get_strategy(&self) -> Result, StrategyError> { match self.strategy_type { StrategyType::BullCallSpread => { diff --git a/src/strategies/bull_call_spread.rs b/src/strategies/bull_call_spread.rs index 210af93d..e02317b2 100644 --- a/src/strategies/bull_call_spread.rs +++ b/src/strategies/bull_call_spread.rs @@ -138,6 +138,7 @@ impl BullCallSpread { /// call spread and are surfaced only to keep the constructor /// panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/bull_put_spread.rs b/src/strategies/bull_put_spread.rs index 964e7ea6..c5607374 100644 --- a/src/strategies/bull_put_spread.rs +++ b/src/strategies/bull_put_spread.rs @@ -150,6 +150,7 @@ impl BullPutSpread { /// put spread and are surfaced only to keep the constructor /// panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/call_butterfly.rs b/src/strategies/call_butterfly.rs index e167aac7..bc4f49eb 100644 --- a/src/strategies/call_butterfly.rs +++ b/src/strategies/call_butterfly.rs @@ -137,6 +137,7 @@ impl CallButterfly { /// these branches are unreachable for a freshly-built call butterfly and /// are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/collar.rs b/src/strategies/collar.rs index d54697b4..f5c6fd5b 100644 --- a/src/strategies/collar.rs +++ b/src/strategies/collar.rs @@ -183,6 +183,7 @@ impl Collar { /// practice this branch is unreachable for a freshly-built collar and /// is surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/covered_call.rs b/src/strategies/covered_call.rs index a1c75ab1..251324d0 100644 --- a/src/strategies/covered_call.rs +++ b/src/strategies/covered_call.rs @@ -156,6 +156,7 @@ impl CoveredCall { /// practice this branch is unreachable for a freshly-built covered /// call and is surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/custom.rs b/src/strategies/custom.rs index cc60806f..98a6581e 100644 --- a/src/strategies/custom.rs +++ b/src/strategies/custom.rs @@ -125,6 +125,7 @@ impl CustomStrategy { /// Returns `StrategyError::OperationError` when `positions` is empty, and /// propagates any error from `update_break_even_points`. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( name: String, symbol: String, diff --git a/src/strategies/delta_neutral/adjustment.rs b/src/strategies/delta_neutral/adjustment.rs index c28efed0..73b2fd24 100644 --- a/src/strategies/delta_neutral/adjustment.rs +++ b/src/strategies/delta_neutral/adjustment.rs @@ -230,6 +230,7 @@ impl Default for AdjustmentConfig { impl AdjustmentConfig { /// Creates a configuration that only allows adjusting existing legs. + #[inline] #[must_use] pub fn existing_legs_only() -> Self { Self { @@ -240,6 +241,7 @@ impl AdjustmentConfig { } /// Creates a configuration that allows underlying hedging. + #[inline] #[must_use] pub fn with_underlying() -> Self { Self { @@ -249,6 +251,7 @@ impl AdjustmentConfig { } /// Creates a configuration for aggressive adjustment with new legs. + #[inline] #[must_use] pub fn aggressive() -> Self { Self { @@ -261,6 +264,7 @@ impl AdjustmentConfig { } /// Sets the maximum cost constraint. + #[inline] #[must_use] pub fn with_max_cost(mut self, max_cost: Positive) -> Self { self.max_cost = Some(max_cost); @@ -268,6 +272,7 @@ impl AdjustmentConfig { } /// Sets the delta tolerance. + #[inline] #[must_use] pub fn with_delta_tolerance(mut self, tolerance: Decimal) -> Self { self.delta_tolerance = tolerance; @@ -275,6 +280,7 @@ impl AdjustmentConfig { } /// Sets the strike range for new legs. + #[inline] #[must_use] pub fn with_strike_range(mut self, min: Positive, max: Positive) -> Self { self.strike_range = Some((min, max)); @@ -282,6 +288,7 @@ impl AdjustmentConfig { } /// Sets whether new legs are allowed. + #[inline] #[must_use] pub fn with_allow_new_legs(mut self, allow: bool) -> Self { self.allow_new_legs = allow; @@ -289,6 +296,7 @@ impl AdjustmentConfig { } /// Sets whether underlying hedging is allowed. + #[inline] #[must_use] pub fn with_allow_underlying(mut self, allow: bool) -> Self { self.allow_underlying = allow; @@ -296,6 +304,7 @@ impl AdjustmentConfig { } /// Sets the maximum number of new legs. + #[inline] #[must_use] pub fn with_max_new_legs(mut self, max: usize) -> Self { self.max_new_legs = Some(max); @@ -303,6 +312,7 @@ impl AdjustmentConfig { } /// Sets the minimum liquidity requirement. + #[inline] #[must_use] pub fn with_min_liquidity(mut self, min: u64) -> Self { self.min_liquidity = Some(min); @@ -310,6 +320,7 @@ impl AdjustmentConfig { } /// Sets whether to prefer existing legs over new ones. + #[inline] #[must_use] pub fn with_prefer_existing_legs(mut self, prefer: bool) -> Self { self.prefer_existing_legs = prefer; @@ -342,6 +353,7 @@ pub struct AdjustmentPlan { impl AdjustmentPlan { /// Creates a new adjustment plan. + #[inline] #[must_use] pub fn new( actions: Vec, @@ -360,18 +372,21 @@ impl AdjustmentPlan { } /// Returns true if this plan achieves delta neutrality within tolerance. + #[inline] #[must_use] pub fn is_delta_neutral(&self, tolerance: Decimal) -> bool { self.residual_delta.abs() <= tolerance } /// Returns true if this plan has no actions. + #[inline] #[must_use] pub fn is_empty(&self) -> bool { self.actions.is_empty() } /// Returns the number of actions in the plan. + #[inline] #[must_use] pub fn action_count(&self) -> usize { self.actions.len() diff --git a/src/strategies/delta_neutral/portfolio.rs b/src/strategies/delta_neutral/portfolio.rs index 13445954..e0476507 100644 --- a/src/strategies/delta_neutral/portfolio.rs +++ b/src/strategies/delta_neutral/portfolio.rs @@ -61,6 +61,7 @@ pub struct PortfolioGreeks { impl PortfolioGreeks { /// Creates a new PortfolioGreeks with specified values. + #[inline] #[must_use] pub fn new( delta: Decimal, @@ -160,6 +161,7 @@ impl PortfolioGreeks { /// # Returns /// /// `true` if absolute delta is within tolerance + #[inline] #[must_use] pub fn is_delta_neutral(&self, tolerance: Decimal) -> bool { self.delta.abs() <= tolerance @@ -174,6 +176,7 @@ impl PortfolioGreeks { /// # Returns /// /// `true` if absolute gamma is within tolerance + #[inline] #[must_use] pub fn is_gamma_neutral(&self, tolerance: Decimal) -> bool { self.gamma.abs() <= tolerance @@ -188,6 +191,7 @@ impl PortfolioGreeks { /// # Returns /// /// `true` if absolute vega is within tolerance + #[inline] #[must_use] pub fn is_vega_neutral(&self, tolerance: Decimal) -> bool { self.vega.abs() <= tolerance @@ -202,6 +206,7 @@ impl PortfolioGreeks { /// # Returns /// /// The difference between current delta and target + #[inline] #[must_use] pub fn delta_gap(&self, target: Decimal) -> Decimal { target - self.delta @@ -216,6 +221,7 @@ impl PortfolioGreeks { /// # Returns /// /// The difference between current gamma and target + #[inline] #[must_use] pub fn gamma_gap(&self, target: Decimal) -> Decimal { target - self.gamma @@ -224,6 +230,7 @@ impl PortfolioGreeks { /// Adds another PortfolioGreeks to this one. /// /// Useful for combining Greeks from multiple sources. + #[inline] pub fn add(&mut self, other: &PortfolioGreeks) { self.delta += other.delta; self.gamma += other.gamma; @@ -233,6 +240,7 @@ impl PortfolioGreeks { } /// Returns a new PortfolioGreeks that is the sum of this and another. + #[inline] #[must_use] pub fn combined(&self, other: &PortfolioGreeks) -> PortfolioGreeks { PortfolioGreeks { @@ -285,6 +293,7 @@ impl AdjustmentTarget { /// # Returns /// /// An AdjustmentTarget with delta = 0 and other Greeks unconstrained + #[inline] #[must_use] pub fn delta_neutral() -> Self { Self { @@ -298,6 +307,7 @@ impl AdjustmentTarget { /// # Returns /// /// An AdjustmentTarget with delta = 0 and gamma = 0 + #[inline] #[must_use] pub fn delta_gamma_neutral() -> Self { Self { @@ -312,6 +322,7 @@ impl AdjustmentTarget { /// # Returns /// /// An AdjustmentTarget with delta = 0, gamma = 0, and vega = 0 + #[inline] #[must_use] pub fn full_neutral() -> Self { Self { @@ -327,6 +338,7 @@ impl AdjustmentTarget { /// # Arguments /// /// * `delta` - Target delta value + #[inline] #[must_use] pub fn with_delta(mut self, delta: Decimal) -> Self { self.delta = Some(delta); @@ -338,6 +350,7 @@ impl AdjustmentTarget { /// # Arguments /// /// * `gamma` - Target gamma value + #[inline] #[must_use] pub fn with_gamma(mut self, gamma: Decimal) -> Self { self.gamma = Some(gamma); @@ -349,6 +362,7 @@ impl AdjustmentTarget { /// # Arguments /// /// * `vega` - Target vega value + #[inline] #[must_use] pub fn with_vega(mut self, vega: Decimal) -> Self { self.vega = Some(vega); @@ -360,6 +374,7 @@ impl AdjustmentTarget { /// # Arguments /// /// * `theta` - Target theta value + #[inline] #[must_use] pub fn with_theta(mut self, theta: Decimal) -> Self { self.theta = Some(theta); @@ -375,6 +390,7 @@ impl AdjustmentTarget { /// # Returns /// /// The delta gap if delta target is set, otherwise zero + #[inline] #[must_use] pub fn delta_gap(&self, current: &PortfolioGreeks) -> Decimal { self.delta @@ -391,6 +407,7 @@ impl AdjustmentTarget { /// # Returns /// /// The gamma gap if gamma target is set, otherwise None + #[inline] #[must_use] pub fn gamma_gap(&self, current: &PortfolioGreeks) -> Option { self.gamma.map(|t| t - current.gamma) @@ -405,6 +422,7 @@ impl AdjustmentTarget { /// # Returns /// /// The vega gap if vega target is set, otherwise None + #[inline] #[must_use] pub fn vega_gap(&self, current: &PortfolioGreeks) -> Option { self.vega.map(|t| t - current.vega) diff --git a/src/strategies/iron_butterfly.rs b/src/strategies/iron_butterfly.rs index eaadd62b..e5ce8ea3 100644 --- a/src/strategies/iron_butterfly.rs +++ b/src/strategies/iron_butterfly.rs @@ -176,6 +176,7 @@ impl IronButterfly { /// these branches are unreachable for a freshly-built iron butterfly and /// are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/iron_condor.rs b/src/strategies/iron_condor.rs index 7fbaf7f5..670f3482 100644 --- a/src/strategies/iron_condor.rs +++ b/src/strategies/iron_condor.rs @@ -181,6 +181,7 @@ impl IronCondor { /// these branches are unreachable for a freshly-built iron condor and /// are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/long_butterfly_spread.rs b/src/strategies/long_butterfly_spread.rs index c5a37e78..600f5d05 100644 --- a/src/strategies/long_butterfly_spread.rs +++ b/src/strategies/long_butterfly_spread.rs @@ -125,6 +125,7 @@ impl LongButterflySpread { /// butterfly spread and is surfaced only to keep the constructor /// panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/long_call.rs b/src/strategies/long_call.rs index 5f1e2cef..0ee58933 100644 --- a/src/strategies/long_call.rs +++ b/src/strategies/long_call.rs @@ -107,6 +107,7 @@ impl LongCall { /// - Uses the `Options` and `Position` structures to model and manage the long call position. /// - Assumes the current time (_via `Utc::now()`) when opening the long call position for tracking purposes. #[allow(clippy::too_many_arguments, dead_code)] + #[inline(never)] pub fn new( underlying_symbol: String, long_call_strike: Positive, diff --git a/src/strategies/long_straddle.rs b/src/strategies/long_straddle.rs index afd643c4..b83590e0 100644 --- a/src/strategies/long_straddle.rs +++ b/src/strategies/long_straddle.rs @@ -158,6 +158,7 @@ impl LongStraddle { /// practice these branches are unreachable for a freshly-built long /// straddle and are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/long_strangle.rs b/src/strategies/long_strangle.rs index 06c68990..1c50d226 100644 --- a/src/strategies/long_strangle.rs +++ b/src/strategies/long_strangle.rs @@ -168,6 +168,7 @@ impl LongStrangle { /// practice these branches are unreachable for a freshly-built /// strangle and are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/poor_mans_covered_call.rs b/src/strategies/poor_mans_covered_call.rs index c39e4aea..484a3280 100644 --- a/src/strategies/poor_mans_covered_call.rs +++ b/src/strategies/poor_mans_covered_call.rs @@ -182,6 +182,7 @@ impl PoorMansCoveredCall { /// practice these branches are unreachable for a freshly-built PMCC and /// are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/protective_put.rs b/src/strategies/protective_put.rs index b291fb15..ec7e7a93 100644 --- a/src/strategies/protective_put.rs +++ b/src/strategies/protective_put.rs @@ -68,6 +68,7 @@ impl ProtectivePut { /// practice this branch is unreachable for a freshly-built protective /// put and is surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/short_butterfly_spread.rs b/src/strategies/short_butterfly_spread.rs index 7466f53d..100e8ed7 100644 --- a/src/strategies/short_butterfly_spread.rs +++ b/src/strategies/short_butterfly_spread.rs @@ -118,6 +118,7 @@ impl ShortButterflySpread { /// butterfly spread and is surfaced only to keep the constructor /// panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/short_put.rs b/src/strategies/short_put.rs index 48af8d95..ef95cb70 100644 --- a/src/strategies/short_put.rs +++ b/src/strategies/short_put.rs @@ -109,6 +109,7 @@ impl ShortPut { /// only to keep the constructor panic-free. /// #[allow(clippy::too_many_arguments, dead_code)] + #[inline(never)] pub fn new( underlying_symbol: String, short_put_strike: Positive, diff --git a/src/strategies/short_straddle.rs b/src/strategies/short_straddle.rs index 016edab1..a75461e7 100644 --- a/src/strategies/short_straddle.rs +++ b/src/strategies/short_straddle.rs @@ -170,6 +170,7 @@ impl ShortStraddle { /// practice these branches are unreachable for a freshly-built short /// straddle and are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/strategies/short_strangle.rs b/src/strategies/short_strangle.rs index 0bc162c7..eb85ff13 100644 --- a/src/strategies/short_strangle.rs +++ b/src/strategies/short_strangle.rs @@ -155,6 +155,7 @@ impl ShortStrangle { /// practice these branches are unreachable for a freshly-built /// strangle and are surfaced only to keep the constructor panic-free. #[allow(clippy::too_many_arguments)] + #[inline(never)] pub fn new( underlying_symbol: String, underlying_price: Positive, diff --git a/src/volatility/utils.rs b/src/volatility/utils.rs index e4b87f39..527ea925 100644 --- a/src/volatility/utils.rs +++ b/src/volatility/utils.rs @@ -514,6 +514,7 @@ pub fn uncertain_volatility_bounds( /// Returns [`VolatilityError::PositiveError`] when the scaling factor /// multiplied by the base volatility cannot be represented as a /// `Positive` (e.g. overflow on an extreme timeframe annualisation). +#[inline] pub fn annualized_volatility( volatility: Positive, timeframe: TimeFrame, @@ -554,6 +555,7 @@ pub fn annualized_volatility( /// Returns [`VolatilityError::PositiveError`] when the rescaling /// produces a value that violates the `Positive` invariant, typically /// due to division rounding on an extremely small timeframe. +#[inline] pub fn de_annualized_volatility( annual_volatility: Positive, timeframe: TimeFrame, @@ -678,6 +680,7 @@ pub fn adjust_volatility( /// # Errors /// /// Returns an error if the de-annualization fails +#[inline] pub fn volatility_for_dt( annual_volatility: Positive, _dt: Positive,