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");
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();
}