Skip to main content

nautilus_model/python/data/
greeks.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use nautilus_core::UnixNanos;
17use pyo3::{prelude::*, types::PyType};
18
19use crate::data::greeks::{
20    BlackScholesGreeksResult, GreeksData, OptionGreekValues, PortfolioGreeks, black_scholes_greeks,
21    imply_vol, imply_vol_and_greeks, refine_vol_and_greeks,
22};
23
24#[cfg(feature = "python")]
25#[pymethods]
26#[pyo3_stub_gen::derive::gen_stub_pymethods]
27impl OptionGreekValues {
28    #[getter]
29    fn delta(&self) -> f64 {
30        self.delta
31    }
32
33    #[getter]
34    fn gamma(&self) -> f64 {
35        self.gamma
36    }
37
38    #[getter]
39    fn vega(&self) -> f64 {
40        self.vega
41    }
42
43    #[getter]
44    fn theta(&self) -> f64 {
45        self.theta
46    }
47
48    #[getter]
49    fn rho(&self) -> f64 {
50        self.rho
51    }
52}
53
54#[cfg(feature = "python")]
55#[pymethods]
56#[pyo3_stub_gen::derive::gen_stub_pymethods]
57impl GreeksData {
58    #[classmethod]
59    #[pyo3(name = "from_delta", signature = (instrument_id, delta, multiplier, ts_event=0))]
60    fn py_from_delta(
61        _cls: &Bound<'_, PyType>,
62        instrument_id: crate::identifiers::InstrumentId,
63        delta: f64,
64        multiplier: f64,
65        ts_event: u64,
66    ) -> Self {
67        Self::from_delta(instrument_id, delta, multiplier, UnixNanos::from(ts_event))
68    }
69
70    #[getter]
71    fn ts_init(&self) -> u64 {
72        self.ts_init.as_u64()
73    }
74
75    #[getter]
76    fn ts_event(&self) -> u64 {
77        self.ts_event.as_u64()
78    }
79
80    #[getter]
81    fn instrument_id(&self) -> crate::identifiers::InstrumentId {
82        self.instrument_id
83    }
84
85    #[getter]
86    fn is_call(&self) -> bool {
87        self.is_call
88    }
89
90    #[getter]
91    fn strike(&self) -> f64 {
92        self.strike
93    }
94
95    #[getter]
96    fn expiry(&self) -> i32 {
97        self.expiry
98    }
99
100    #[getter]
101    fn expiry_in_days(&self) -> i32 {
102        self.expiry_in_days
103    }
104
105    #[getter]
106    fn expiry_in_years(&self) -> f64 {
107        self.expiry_in_years
108    }
109
110    #[getter]
111    fn multiplier(&self) -> f64 {
112        self.multiplier
113    }
114
115    #[getter]
116    fn quantity(&self) -> f64 {
117        self.quantity
118    }
119
120    #[getter]
121    fn underlying_price(&self) -> f64 {
122        self.underlying_price
123    }
124
125    #[getter]
126    fn interest_rate(&self) -> f64 {
127        self.interest_rate
128    }
129
130    #[getter]
131    fn cost_of_carry(&self) -> f64 {
132        self.cost_of_carry
133    }
134
135    #[getter]
136    fn vol(&self) -> f64 {
137        self.vol
138    }
139
140    #[getter]
141    fn pnl(&self) -> f64 {
142        self.pnl
143    }
144
145    #[getter]
146    fn price(&self) -> f64 {
147        self.price
148    }
149
150    #[getter]
151    fn delta(&self) -> f64 {
152        self.greeks.delta
153    }
154
155    #[getter]
156    fn gamma(&self) -> f64 {
157        self.greeks.gamma
158    }
159
160    #[getter]
161    fn vega(&self) -> f64 {
162        self.greeks.vega
163    }
164
165    #[getter]
166    fn theta(&self) -> f64 {
167        self.greeks.theta
168    }
169
170    #[getter]
171    fn rho(&self) -> f64 {
172        self.greeks.rho
173    }
174
175    #[getter]
176    fn itm_prob(&self) -> f64 {
177        self.itm_prob
178    }
179}
180
181#[cfg(feature = "python")]
182#[pymethods]
183#[pyo3_stub_gen::derive::gen_stub_pymethods]
184impl PortfolioGreeks {
185    #[getter]
186    fn ts_init(&self) -> u64 {
187        self.ts_init.as_u64()
188    }
189
190    #[getter]
191    fn ts_event(&self) -> u64 {
192        self.ts_event.as_u64()
193    }
194
195    #[getter]
196    fn pnl(&self) -> f64 {
197        self.pnl
198    }
199
200    #[getter]
201    fn price(&self) -> f64 {
202        self.price
203    }
204
205    #[getter]
206    fn delta(&self) -> f64 {
207        self.greeks.delta
208    }
209
210    #[getter]
211    fn gamma(&self) -> f64 {
212        self.greeks.gamma
213    }
214
215    #[getter]
216    fn vega(&self) -> f64 {
217        self.greeks.vega
218    }
219
220    #[getter]
221    fn theta(&self) -> f64 {
222        self.greeks.theta
223    }
224
225    #[getter]
226    fn rho(&self) -> f64 {
227        self.greeks.rho
228    }
229}
230
231#[cfg(feature = "python")]
232#[pymethods]
233#[pyo3_stub_gen::derive::gen_stub_pymethods]
234impl BlackScholesGreeksResult {
235    #[getter]
236    fn price(&self) -> f64 {
237        self.price
238    }
239
240    #[getter]
241    fn vol(&self) -> f64 {
242        self.vol
243    }
244
245    #[getter]
246    fn delta(&self) -> f64 {
247        self.delta
248    }
249
250    #[getter]
251    fn gamma(&self) -> f64 {
252        self.gamma
253    }
254
255    #[getter]
256    fn vega(&self) -> f64 {
257        self.vega
258    }
259
260    #[getter]
261    fn theta(&self) -> f64 {
262        self.theta
263    }
264
265    #[getter]
266    fn itm_prob(&self) -> f64 {
267        self.itm_prob
268    }
269}
270
271/// Computes Black-Scholes greeks using the fast `compute_greeks` implementation.
272/// This function uses `compute_greeks` from `black_scholes.rs` which is optimized for performance.
273#[pyfunction]
274#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.model")]
275#[pyo3(name = "black_scholes_greeks")]
276pub fn py_black_scholes_greeks(
277    s: f64,
278    r: f64,
279    b: f64,
280    vol: f64,
281    is_call: bool,
282    k: f64,
283    t: f64,
284) -> PyResult<BlackScholesGreeksResult> {
285    Ok(black_scholes_greeks(s, r, b, vol, is_call, k, t))
286}
287
288/// Computes the implied volatility for an option given its parameters and market price.
289///
290/// # Errors
291///
292/// Returns a `PyErr` if implied volatility calculation fails.
293#[pyfunction]
294#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.model")]
295#[pyo3(name = "imply_vol")]
296pub fn py_imply_vol(
297    s: f64,
298    r: f64,
299    b: f64,
300    is_call: bool,
301    k: f64,
302    t: f64,
303    price: f64,
304) -> PyResult<f64> {
305    let vol = imply_vol(s, r, b, is_call, k, t, price);
306    Ok(vol)
307}
308
309/// Computes implied volatility and greeks using the fast implementations.
310/// This function uses `compute_greeks` after implying volatility.
311#[pyfunction]
312#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.model")]
313#[pyo3(name = "imply_vol_and_greeks")]
314pub fn py_imply_vol_and_greeks(
315    s: f64,
316    r: f64,
317    b: f64,
318    is_call: bool,
319    k: f64,
320    t: f64,
321    price: f64,
322) -> PyResult<BlackScholesGreeksResult> {
323    Ok(imply_vol_and_greeks(s, r, b, is_call, k, t, price))
324}
325
326/// Refines implied volatility using an initial guess and computes greeks.
327/// This function uses `compute_iv_and_greeks` which performs a Halley iteration
328/// to refine the volatility estimate from an initial guess.
329#[pyfunction]
330#[pyo3_stub_gen::derive::gen_stub_pyfunction(module = "nautilus_trader.model")]
331#[pyo3(name = "refine_vol_and_greeks")]
332#[expect(clippy::too_many_arguments)]
333pub fn py_refine_vol_and_greeks(
334    s: f64,
335    r: f64,
336    b: f64,
337    is_call: bool,
338    k: f64,
339    t: f64,
340    target_price: f64,
341    initial_vol: f64,
342) -> PyResult<BlackScholesGreeksResult> {
343    Ok(refine_vol_and_greeks(
344        s,
345        r,
346        b,
347        is_call,
348        k,
349        t,
350        target_price,
351        initial_vol,
352    ))
353}