Skip to content

Commit 176807e

Browse files
committed
Type hints for market folder
1 parent f240be7 commit 176807e

18 files changed

+381
-259
lines changed

financepy/market/volatility/equity_vol_curve.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66

77
from ...utils.error import FinError
88
from ...utils.math import test_monotonicity
9+
from ...utils.date import Date
910

1011
########################################################################################
1112
# TODO: This should be deleted and replaced with equity_vol_surface
1213

1314

15+
from typing import Any, Sequence, Optional
16+
1417
class EquityVolCurve:
1518
"""Class to manage a smile or skew in volatility at a single maturity
1619
horizon. It fits the volatility using a polynomial. Includes analytics to
@@ -19,7 +22,14 @@ class EquityVolCurve:
1922

2023
####################################################################################
2124

22-
def __init__(self, curve_dt, expiry_dt, strikes, volatilities, polynomial=3):
25+
def __init__(
26+
self,
27+
curve_dt: Date,
28+
expiry_dt: Date,
29+
strikes: np.ndarray,
30+
volatilities: np.ndarray,
31+
polynomial: int = 3
32+
) -> None:
2333

2434
if expiry_dt <= curve_dt:
2535
raise FinError("Expiry date before curve date.")
@@ -49,7 +59,7 @@ def __init__(self, curve_dt, expiry_dt, strikes, volatilities, polynomial=3):
4959

5060
####################################################################################
5161

52-
def volatility(self, strike):
62+
def volatility(self, strike: float) -> float:
5363
"""Return the volatility for a strike using a given polynomial
5464
interpolation."""
5565

@@ -62,7 +72,7 @@ def volatility(self, strike):
6272

6373
####################################################################################
6474

65-
def calculate_pdf(self):
75+
def calculate_pdf(self) -> Optional[Any]:
6676
"""calculate the probability density function of the underlying using
6777
the volatility smile or skew curve following the approach set out in
6878
Breedon and Litzenberger."""

financepy/market/volatility/equity_vol_surface.py

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Copyright (C) 2018, 2019, 2020 Dominic O'Kane
33
##############################################################################
44

5-
from typing import Union
5+
from typing import Union, Any, Sequence, Optional, Tuple, List
66
import matplotlib.pyplot as plt
77

88
import numpy as np
@@ -53,7 +53,7 @@
5353

5454

5555
@njit(fastmath=True, cache=True)
56-
def _obj(params, *args):
56+
def _obj(params: np.ndarray, *args: Any) -> float:
5757
"""Return a value that is minimised when the ATM, MS and RR vols have
5858
been best fitted using the parametric volatility curve represented by
5959
params and specified by the vol_type_value. We fit at one time slice only.
@@ -89,17 +89,17 @@ def _obj(params, *args):
8989

9090

9191
def _solve_to_horizon(
92-
s,
93-
t,
94-
r,
95-
q,
96-
strikes,
97-
time_index,
98-
volatility_grid,
99-
vol_type_value,
100-
x_inits,
101-
fin_solver_type,
102-
):
92+
s: float,
93+
t: float,
94+
r: float,
95+
q: float,
96+
strikes: Sequence[float],
97+
time_index: int,
98+
volatility_grid: Union[List[Sequence[float]], np.ndarray],
99+
vol_type_value: int,
100+
x_inits: Sequence[float],
101+
fin_solver_type: Any,
102+
) -> np.ndarray:
103103

104104
###########################################################################
105105
# Determine parameters of vol surface using minimisation
@@ -151,7 +151,13 @@ def _solve_to_horizon(
151151
cache=True,
152152
fastmath=True,
153153
)
154-
def vol_function(vol_function_type_value, params, f, k, t):
154+
def vol_function(
155+
vol_function_type_value: int,
156+
params: np.ndarray,
157+
f: float,
158+
k: float,
159+
t: float
160+
) -> float:
155161
"""Return the volatility for a strike using a given polynomial
156162
interpolation following Section 3.9 of Iain Clark book."""
157163

@@ -187,7 +193,7 @@ def vol_function(vol_function_type_value, params, f, k, t):
187193

188194

189195
@njit(cache=True, fastmath=True)
190-
def _delta_fit(k, *args):
196+
def _delta_fit(k: float, *args: Any) -> float:
191197
"""This is the objective function used in the determination of the
192198
option implied strike which is computed in the class below. I map it into
193199
inverse normcdf space to avoid the flat slope of this function at low vol
@@ -220,16 +226,16 @@ def _delta_fit(k, *args):
220226
# @njit(float64(float64, float64, float64, float64, int64, int64, float64,
221227
# float64, float64[:]), fastmath=True)
222228
def _solver_for_smile_strike(
223-
s,
224-
t,
225-
r,
226-
q,
227-
opt_type_value,
228-
vol_type_value,
229-
delta_target,
230-
initial_guess,
231-
parameters,
232-
):
229+
s: float,
230+
t: float,
231+
r: float,
232+
q: float,
233+
opt_type_value: int,
234+
vol_type_value: int,
235+
delta_target: float,
236+
initial_guess: float,
237+
parameters: np.ndarray,
238+
) -> float:
233239
"""Solve for the strike that sets the delta of the option equal to the
234240
target value of delta allowing the volatility to be a function of the
235241
strike."""
@@ -269,12 +275,12 @@ def __init__(
269275
stock_price: float,
270276
discount_curve: DiscountCurve,
271277
dividend_curve: DiscountCurve,
272-
expiry_dts: list,
273-
strikes: Union[list, np.ndarray],
274-
volatility_grid: Union[list, np.ndarray],
275-
vol_func_type=VolFuncTypes.CLARK,
276-
fin_solver_type=FinSolverTypes.NELDER_MEAD,
277-
):
278+
expiry_dts: List[Date],
279+
strikes: np.ndarray,
280+
volatility_grid: np.ndarray,
281+
vol_func_type: VolFuncTypes = VolFuncTypes.CLARK,
282+
fin_solver_type: FinSolverTypes = FinSolverTypes.NELDER_MEAD,
283+
) -> None:
278284
"""Create the EquitySurface object by passing in market vol data
279285
for a list of strikes and expiry dates."""
280286

@@ -310,7 +316,7 @@ def __init__(
310316

311317
###########################################################################
312318

313-
def vol_from_strike_dt(self, k, expiry_dt):
319+
def vol_from_strike_dt(self, k: float, expiry_dt: Date) -> float:
314320
"""Interpolates the Black-Scholes volatility from the volatility
315321
surface given call option strike and expiry date. Linear interpolation
316322
is done in variance space. The smile strikes at bracketed dates are
@@ -487,7 +493,12 @@ def vol_from_strike_dt(self, k, expiry_dt):
487493

488494
####################################################################################
489495

490-
def vol_from_delta_date(self, call_delta, expiry_dt, delta_method=None):
496+
def vol_from_delta_date(
497+
self,
498+
call_delta: float,
499+
expiry_dt: Date,
500+
delta_method = None,
501+
) -> Tuple[float, float]:
491502
"""Interpolates the Black-Scholes volatility from the volatility
492503
surface given a call option delta and expiry date. Linear interpolation
493504
is done in variance space. The smile strikes at bracketed dates are
@@ -600,7 +611,7 @@ def vol_from_delta_date(self, call_delta, expiry_dt, delta_method=None):
600611

601612
####################################################################################
602613

603-
def _build_vol_surface(self, fin_solver_type=FinSolverTypes.NELDER_MEAD):
614+
def _build_vol_surface(self, fin_solver_type: Any = FinSolverTypes.NELDER_MEAD) -> None:
604615
"""Main function to construct the vol surface."""
605616

606617
s = self._stock_price
@@ -702,7 +713,7 @@ def _build_vol_surface(self, fin_solver_type=FinSolverTypes.NELDER_MEAD):
702713

703714
####################################################################################
704715

705-
def check_calibration(self, verbose: bool):
716+
def check_calibration(self, verbose: bool) -> None:
706717
"""Compare calibrated vol surface with market and output a report
707718
which sets out the quality of fit to the ATM and 10 and 25 delta market
708719
strangles and risk reversals."""
@@ -744,7 +755,12 @@ def check_calibration(self, verbose: bool):
744755

745756
####################################################################################
746757

747-
def implied_dbns(self, low_s, high_s, num_intervals):
758+
def implied_dbns(
759+
self,
760+
low_s: float,
761+
high_s: float,
762+
num_intervals: int
763+
) -> List[FinDistribution]:
748764
"""Calculate the pdf for each tenor horizon. Returns a list of
749765
FinDistribution objects, one for each tenor horizon."""
750766

@@ -793,7 +809,7 @@ def implied_dbns(self, low_s, high_s, num_intervals):
793809

794810
####################################################################################
795811

796-
def plot_vol_curves(self):
812+
def plot_vol_curves(self) -> None:
797813
"""Generates a plot of each of the vol discount implied by the market
798814
and fitted."""
799815

@@ -835,7 +851,7 @@ def plot_vol_curves(self):
835851

836852
####################################################################################
837853

838-
def __repr__(self):
854+
def __repr__(self) -> str:
839855
s = label_to_string("OBJECT TYPE", type(self).__name__)
840856
s += label_to_string("VALUE DATE", self.value_dt)
841857
s += label_to_string("STOCK PRICE", self._stock_price)
@@ -853,7 +869,7 @@ def __repr__(self):
853869

854870
####################################################################################
855871

856-
def _print(self):
872+
def _print(self) -> None:
857873
"""Print a list of the unadjusted coupon payment dates used in
858874
analytic calculations for the bond."""
859875
print(self)

0 commit comments

Comments
 (0)