optionstratlib 0.18.1

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

use criterion::Criterion;
use optionstratlib::greeks::Greeks;
use optionstratlib::nz;
use optionstratlib::pnl::utils::PnLCalculator;
use optionstratlib::{ExpirationDate, OptionStyle, OptionType, Options, Side};
use positive::{Positive, pos_or_panic};
use rust_decimal_macros::dec;
use std::hint::black_box;

fn create_test_option() -> Options {
    Options::new(
        OptionType::European,
        Side::Long,
        "AAPL".to_string(),
        Positive::HUNDRED,
        ExpirationDate::Days(pos_or_panic!(30.0)),
        pos_or_panic!(0.2),
        Positive::ONE,
        Positive::HUNDRED,
        dec!(0.05),
        OptionStyle::Call,
        pos_or_panic!(0.01),
        None,
    )
}

pub(crate) fn benchmark_pricing(c: &mut Criterion) {
    let mut group = c.benchmark_group("Pricing Methods");
    let option = create_test_option();

    group.bench_function("black_scholes", |bencher| {
        bencher.iter(|| black_box(option.calculate_price_black_scholes()))
    });

    group.bench_function("binomial_50_steps", |bencher| {
        bencher.iter(|| black_box(option.calculate_price_binomial(nz!(50))))
    });

    group.bench_function("telegraph_50_steps", |bencher| {
        bencher.iter(|| black_box(option.calculate_price_telegraph(nz!(50))))
    });

    group.finish();
}

pub(crate) fn benchmark_greeks(c: &mut Criterion) {
    let mut group = c.benchmark_group("Greeks Calculations");
    let option = create_test_option();

    group.bench_function("delta", |bencher| {
        bencher.iter(|| black_box(option.delta().unwrap()))
    });

    group.bench_function("gamma", |bencher| {
        bencher.iter(|| black_box(option.gamma().unwrap()))
    });

    group.bench_function("theta", |bencher| {
        bencher.iter(|| black_box(option.theta().unwrap()))
    });

    group.bench_function("vega", |bencher| {
        bencher.iter(|| black_box(option.vega().unwrap()))
    });

    group.bench_function("rho", |bencher| {
        bencher.iter(|| black_box(option.rho().unwrap()))
    });

    group.bench_function("vanna", |bencher| {
        bencher.iter(|| black_box(option.vanna().unwrap()))
    });

    group.bench_function("vomma", |bencher| {
        bencher.iter(|| black_box(option.vomma().unwrap()))
    });

    group.bench_function("veta", |bencher| {
        bencher.iter(|| black_box(option.veta().unwrap()))
    });

    group.bench_function("charm", |bencher| {
        bencher.iter(|| black_box(option.charm().unwrap()))
    });

    group.bench_function("color", |bencher| {
        bencher.iter(|| black_box(option.color().unwrap()))
    });

    group.bench_function("all_greeks", |bencher| {
        bencher.iter(|| black_box(option.greeks().unwrap()))
    });

    group.finish();
}

pub(crate) fn benchmark_valuations(c: &mut Criterion) {
    let mut group = c.benchmark_group("Valuations");
    let option = create_test_option();

    group.bench_function("payoff", |bencher| {
        bencher.iter(|| black_box(option.payoff()))
    });

    group.bench_function("intrinsic_value", |bencher| {
        bencher.iter(|| black_box(option.intrinsic_value(pos_or_panic!(110.0))))
    });

    group.bench_function("time_value", |bencher| {
        bencher.iter(|| black_box(option.time_value()))
    });

    group.bench_function("pnl_calculation", |bencher| {
        bencher.iter(|| {
            black_box(option.calculate_pnl(
                &pos_or_panic!(110.0),
                ExpirationDate::Days(pos_or_panic!(15.0)),
                &pos_or_panic!(0.25),
            ))
        })
    });

    group.finish();
}

pub(crate) fn benchmark_binary_tree(c: &mut Criterion) {
    let mut group = c.benchmark_group("Binary Tree Operations");
    // Configure more time for samples
    group
        .sample_size(50)
        .warm_up_time(std::time::Duration::from_secs(5))
        .measurement_time(std::time::Duration::from_secs(10));

    let option = create_test_option();

    for steps in [10usize, 50, 100, 200].iter() {
        let nz_steps = nz!(*steps);
        group.bench_function(format!("binomial_tree_{steps}_steps"), |bencher| {
            bencher.iter(|| black_box(option.calculate_price_binomial_tree(nz_steps)))
        });
    }

    group.finish();
}

pub(crate) fn benchmark_maturities(c: &mut Criterion) {
    let mut group = c.benchmark_group("Maturity Impact on Pricing");
    let mut option = create_test_option();

    for days in [1, 7, 30, 90, 365].iter() {
        option.expiration_date = ExpirationDate::Days(pos_or_panic!(*days as f64));
        group.bench_function(format!("black_scholes_{days}_days"), |bencher| {
            bencher.iter(|| black_box(option.calculate_price_black_scholes()))
        });
    }

    group.finish();
}