Skip to main content

optionstratlib_pricing/pricing/
payoff.rs

1//! Profit contracts: [`Profit`], the profit of a contract or position at a
2//! given underlying price. The payoff contracts at expiry (`Payoff`,
3//! `PayoffInfo`) are core's: `optionstratlib_core::model::payoff`.
4
5use crate::error::PricingError;
6use optionstratlib_core::model::Positive;
7use optionstratlib_core::model::{Options, Position};
8use rust_decimal::Decimal;
9use tracing::trace;
10
11/// Defines the profit calculation behavior for financial instruments.
12///
13/// This trait is used to calculate and visualize profit values at different price points
14/// for various financial instruments and strategies. It provides:
15/// 1. A required method to calculate the actual profit value at a given price
16/// 2. A default implementation to convert the profit calculation into a visualization point
17///
18/// # Usage
19///
20/// Implement this trait for any type that can calculate profit at a specific price point,
21/// such as options contracts, spreads, or complex trading strategies.
22///
23pub trait Profit {
24    /// Calculates the profit at a specified price.
25    ///
26    /// # Parameters
27    ///
28    /// * `price` - A positive value representing the price at which to calculate profit
29    ///
30    /// # Returns
31    ///
32    /// * `Result<Decimal, PricingError>` - The calculated profit as a Decimal value,
33    ///   or an error if the calculation fails
34    ///
35    /// # Errors
36    ///
37    /// Returns `PricingError::MethodError` when the strategy cannot
38    /// evaluate its payoff at `price` (typically propagated from the
39    /// underlying `Position::pnl_at_expiration` or Black–Scholes
40    /// evaluation).
41    fn calculate_profit_at(&self, price: &Positive) -> Result<Decimal, PricingError>;
42
43    /// Creates a chart point representation of the profit at the given price.
44    ///
45    /// This method automatically determines the appropriate visualization properties based
46    /// on the profit value, such as color (green for positive profit, red for negative).
47    ///
48    /// # Parameters
49    ///
50    /// * `price` - A positive value representing the price for which to create a chart point
51    ///
52    /// # Returns
53    ///
54    /// * `ChartPoint<(f64, f64)>` - A formatted chart point with coordinates (price, profit),
55    ///   styling, and a formatted profit label
56    ///
57    /// # Errors
58    ///
59    /// Propagates any `PricingError` returned by
60    /// [`Profit::calculate_profit_at`].
61    fn get_point_at_price(&self, _price: &Positive) -> Result<(Decimal, Decimal), PricingError> {
62        let profit = self.calculate_profit_at(_price)?;
63        let price: Decimal = _price.into();
64        let point = (price, profit);
65        trace!("get_point_at_price - point: {:?}", point);
66        Ok(point)
67    }
68}
69
70impl Profit for Options {
71    fn calculate_profit_at(&self, price: &Positive) -> Result<Decimal, PricingError> {
72        Ok(self.payoff_at_price(price)?)
73    }
74}
75
76/// Implementation of the Profit trait for the Position struct.
77///
78/// This allows calculating the profit of a position at a given price by using the
79/// position's profit and loss (PnL) calculation at expiration.
80///
81impl Profit for Position {
82    /// Calculates the profit of the position at a specific price.
83    ///
84    /// This method computes the profit or loss that would be realized if the position
85    /// were to expire with the underlying asset at the specified price.
86    ///
87    /// # Parameters
88    ///
89    /// * `price` - The price at which to calculate the profit, represented as a Positive value.
90    ///
91    /// # Returns
92    ///
93    /// * `Result<Decimal, PricingError>` - The calculated profit as a Decimal if successful,
94    ///   or an error if the calculation fails.
95    fn calculate_profit_at(&self, price: &Positive) -> Result<Decimal, PricingError> {
96        Ok(self.pnl_at_expiration(&Some(price))?)
97    }
98}