Files
ferro-ta/src/options/greeks.rs
T
Pratik BhadaneandGitHub 3e0f289d51 chore: update ferro-ta version to 1.1.3 (#8)
- Bumped version numbers across Cargo.toml, Cargo.lock, pyproject.toml, and conda/meta.yaml to 1.1.3.
- Added new features including American option pricing, digital options, extended Greeks, and historical volatility estimators.
- Enhanced documentation and tests for new functionalities.
- Updated CHANGELOG.md to reflect changes for version 1.1.3.
2026-04-02 16:38:32 +05:30

243 lines
7.6 KiB
Rust

use crate::validation;
use numpy::{IntoPyArray, PyArray1, PyReadonlyArray1};
use pyo3::prelude::*;
type ExtendedGreekArrays<'py> = (
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
);
type GreekArrays<'py> = (
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
Bound<'py, PyArray1<f64>>,
);
#[pyfunction]
#[pyo3(signature = (underlying, strike, rate, time_to_expiry, volatility, option_type = "call", model = "bsm", carry = 0.0))]
#[allow(clippy::too_many_arguments)]
pub fn option_greeks(
underlying: f64,
strike: f64,
rate: f64,
time_to_expiry: f64,
volatility: f64,
option_type: &str,
model: &str,
carry: f64,
) -> PyResult<(f64, f64, f64, f64, f64)> {
let kind = super::parse_option_kind(option_type)?;
let model = super::parse_pricing_model(model)?;
let greeks =
ferro_ta_core::options::greeks::model_greeks(ferro_ta_core::options::OptionEvaluation {
contract: ferro_ta_core::options::OptionContract {
model,
underlying,
strike,
rate,
carry,
time_to_expiry,
kind,
},
volatility,
});
Ok((
greeks.delta,
greeks.gamma,
greeks.vega,
greeks.theta,
greeks.rho,
))
}
#[pyfunction]
#[pyo3(signature = (underlying, strike, rate, time_to_expiry, volatility, option_type = "call", model = "bsm", carry = None))]
#[allow(clippy::too_many_arguments)]
pub fn option_greeks_batch<'py>(
py: Python<'py>,
underlying: PyReadonlyArray1<'py, f64>,
strike: PyReadonlyArray1<'py, f64>,
rate: PyReadonlyArray1<'py, f64>,
time_to_expiry: PyReadonlyArray1<'py, f64>,
volatility: PyReadonlyArray1<'py, f64>,
option_type: &str,
model: &str,
carry: Option<PyReadonlyArray1<'py, f64>>,
) -> PyResult<GreekArrays<'py>> {
let kind = super::parse_option_kind(option_type)?;
let model = super::parse_pricing_model(model)?;
let underlying = underlying.as_slice()?;
let strike = strike.as_slice()?;
let rate = rate.as_slice()?;
let time_to_expiry = time_to_expiry.as_slice()?;
let volatility = volatility.as_slice()?;
let carry_vec = match carry {
Some(array) => array.as_slice()?.to_vec(),
None => vec![0.0; underlying.len()],
};
validation::validate_equal_length(&[
(underlying.len(), "underlying"),
(strike.len(), "strike"),
(rate.len(), "rate"),
(time_to_expiry.len(), "time_to_expiry"),
(volatility.len(), "volatility"),
(carry_vec.len(), "carry"),
])?;
let mut delta = Vec::with_capacity(underlying.len());
let mut gamma = Vec::with_capacity(underlying.len());
let mut vega = Vec::with_capacity(underlying.len());
let mut theta = Vec::with_capacity(underlying.len());
let mut rho = Vec::with_capacity(underlying.len());
for (((((&u, &k), &r), &t), &vol), &c) in underlying
.iter()
.zip(strike.iter())
.zip(rate.iter())
.zip(time_to_expiry.iter())
.zip(volatility.iter())
.zip(carry_vec.iter())
{
let g = ferro_ta_core::options::greeks::model_greeks(
ferro_ta_core::options::OptionEvaluation {
contract: ferro_ta_core::options::OptionContract {
model,
underlying: u,
strike: k,
rate: r,
carry: c,
time_to_expiry: t,
kind,
},
volatility: vol,
},
);
delta.push(g.delta);
gamma.push(g.gamma);
vega.push(g.vega);
theta.push(g.theta);
rho.push(g.rho);
}
Ok((
delta.into_pyarray(py),
gamma.into_pyarray(py),
vega.into_pyarray(py),
theta.into_pyarray(py),
rho.into_pyarray(py),
))
}
#[pyfunction]
#[pyo3(signature = (underlying, strike, rate, time_to_expiry, volatility, option_type = "call", model = "bsm", carry = 0.0))]
#[allow(clippy::too_many_arguments)]
pub fn extended_greeks(
underlying: f64,
strike: f64,
rate: f64,
time_to_expiry: f64,
volatility: f64,
option_type: &str,
model: &str,
carry: f64,
) -> PyResult<(f64, f64, f64, f64, f64)> {
let kind = super::parse_option_kind(option_type)?;
let model = super::parse_pricing_model(model)?;
let eg = ferro_ta_core::options::greeks::model_extended_greeks(
ferro_ta_core::options::OptionEvaluation {
contract: ferro_ta_core::options::OptionContract {
model,
underlying,
strike,
rate,
carry,
time_to_expiry,
kind,
},
volatility,
},
);
Ok((eg.vanna, eg.volga, eg.charm, eg.speed, eg.color))
}
#[pyfunction]
#[pyo3(signature = (underlying, strike, rate, time_to_expiry, volatility, option_type = "call", model = "bsm", carry = None))]
#[allow(clippy::too_many_arguments)]
pub fn extended_greeks_batch<'py>(
py: Python<'py>,
underlying: PyReadonlyArray1<'py, f64>,
strike: PyReadonlyArray1<'py, f64>,
rate: PyReadonlyArray1<'py, f64>,
time_to_expiry: PyReadonlyArray1<'py, f64>,
volatility: PyReadonlyArray1<'py, f64>,
option_type: &str,
model: &str,
carry: Option<PyReadonlyArray1<'py, f64>>,
) -> PyResult<ExtendedGreekArrays<'py>> {
let kind = super::parse_option_kind(option_type)?;
let model = super::parse_pricing_model(model)?;
let underlying = underlying.as_slice()?;
let strike = strike.as_slice()?;
let rate = rate.as_slice()?;
let time_to_expiry = time_to_expiry.as_slice()?;
let volatility = volatility.as_slice()?;
let carry_vec = match carry {
Some(array) => array.as_slice()?.to_vec(),
None => vec![0.0; underlying.len()],
};
validation::validate_equal_length(&[
(underlying.len(), "underlying"),
(strike.len(), "strike"),
(rate.len(), "rate"),
(time_to_expiry.len(), "time_to_expiry"),
(volatility.len(), "volatility"),
(carry_vec.len(), "carry"),
])?;
let mut vanna = Vec::with_capacity(underlying.len());
let mut volga = Vec::with_capacity(underlying.len());
let mut charm = Vec::with_capacity(underlying.len());
let mut speed = Vec::with_capacity(underlying.len());
let mut color = Vec::with_capacity(underlying.len());
for (((((&u, &k), &r), &t), &vol), &c) in underlying
.iter()
.zip(strike.iter())
.zip(rate.iter())
.zip(time_to_expiry.iter())
.zip(volatility.iter())
.zip(carry_vec.iter())
{
let eg = ferro_ta_core::options::greeks::model_extended_greeks(
ferro_ta_core::options::OptionEvaluation {
contract: ferro_ta_core::options::OptionContract {
model,
underlying: u,
strike: k,
rate: r,
carry: c,
time_to_expiry: t,
kind,
},
volatility: vol,
},
);
vanna.push(eg.vanna);
volga.push(eg.volga);
charm.push(eg.charm);
speed.push(eg.speed);
color.push(eg.color);
}
Ok((
vanna.into_pyarray(py),
volga.into_pyarray(py),
charm.into_pyarray(py),
speed.into_pyarray(py),
color.into_pyarray(py),
))
}