Vol Slices

class KVMVolSlice(spot, rf_rate, dividend_yield, strikes, vols, *, _id=<factory>)

Bases: VolSlice

Parameters:
  • spot (float)

  • rf_rate (float)

  • dividend_yield (float)

  • strikes (List[float] | Tuple[float, ...] | PVector[float])

  • vols (List[float] | Tuple[float, ...] | PVector[float])

  • _id (ObjectIdField)

atmf_ivol()
Return type:

float

atmf_skew(space='strike')

output is: - dIVol/dStrike[strike=forward] (if space = ‘strike’) - dIVol/dMoneyness[moneyness=0] (if space = ‘moneyness’)

Parameters:

space (str)

Return type:

float

get_call_iprices(strikes=None, discounted=True)

This function is usefull to check the smile curve does not have butterfly arbitrage. See function “has_vol_arbitrages” for more details.

When we transform data using the isotonic regression we only get the overall trend/shape of the function. To fully specify the function we need to chose a value for a given point or an overall/mean value. Picking an arbitrary price level may lead to option prices below the intrinsic price. An alternative is to chose a level of the time-value curce i.e.

TimeValue = Price - IntrinsicValue

Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

  • discounted (bool)

Return type:

List[float | None]

get_call_iprices_()
Return type:

List[float | None]

get_call_prices(strikes=None, discounted=True)

This function is usefull to check the smile curve does not have butterfly arbitrage. See function “has_vol_arbitrages” for more details.

Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

  • discounted (bool)

Return type:

List[float | None]

get_call_prices_()
Return type:

List[float | None]

get_call_prices_with_derivatives(strikes, discounted)
Returns both following lists:
  • [CallPrice(strike) for strike in strikes]

  • [dCallPrice(strike)/dStrike for strike in strikes]

This utility is usefull when interpolating vol slices between 2 different expiration dates. We will be using the formula suggested by Gatheral and Jacquier in: - Arbitrage-free SVI volatility surfaces, Jim Gatheral and Antoine Jacquier, March 2013 - https://arxiv.org/pdf/1204.0646 The relevant formula from section 5.3 is:

C_t / K_t = α_t * (C_1 / K_1) + (1 - α_t) * (C_2 / K_2)

where:
  • C_t: Value of C at time t

  • K_t: Value of K at time t

  • α_t: Weighting factor at time t

  • C_1, C_2: Constants

  • K_1, K_2: Constants

A key part of the interpolation is to also fit the skew dVol/dK. This requires dC/dK which can also be obtained as a weighted average of dC_1/dK and dC_2/dK.

Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float])

  • discounted (bool)

Return type:

Tuple[List[float], List[float]]

get_discount_factor()
Return type:

float

get_forward()
Return type:

float

get_pvalue(strike)
Parameters:

strike (float)

Return type:

float

get_pvalues(strikes=None)
Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

Return type:

List[float]

get_vol(strike)
Parameters:

strike (float)

Return type:

Tuple[float, float]

get_vols(strikes=None)

This function returns the ivol and the derivative d_ivol/d_strike for each strike in the list.

Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

Return type:

Tuple[List[float], List[float]]

get_zscore(strike)
Parameters:

strike (float)

Return type:

float

get_zscores(strikes=None)
Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

Return type:

List[float]

has_vol_arbitrages()

Check the if smile curve has butterfly arbitrages. The conditions are:

with function :

C : k -> bs_call(k, sigma(k))

  1. that function “C” should be convex

  2. that function C should be non-increasing

Return type:

bool

lk_interp()

Returns a function “log(strike) -> ivol”

Return type:

Callable[[float], float]

min_ivol()
Return type:

float

min_ivol_moneyness()
Return type:

float

min_ivol_strike()
Return type:

float

moneyness_bounds()
Return type:

Tuple[float, float]

p_interp(solver='Brent')

Returns a function “p_value -> (strike, ivol)”

Note that the interpolation is linear in the log(strike) space.

Parameters:

solver (str)

Return type:

Callable[[float], Tuple[float, float]]

strike_bounds()
Return type:

Tuple[float, float]

total_variance()
Return type:

float

property as_of_date: date
property dividend_yield: float

Dividend Yield between as_of_date and expiration_date

property exercise_style: str
property expiration_date: date
property last_updated
property rf_rate: float

Risk Free Rate between as_of_date and expiration_date

property spot: float

Spot price of the option underlying

property strikes: PVector[float]

A list of strike prices for which the volatility is mapped

property ticker: str
property vols: PVector[float]

A list of volatility aligned with the strike prices list

class CHSVolSlice(spot, rf_rate, dividend_yield, strikes, vols, dvols, *, _id=<factory>)

Bases: KVMVolSlice

A volatility slice representation based on the mapping:

strike -> (ivol, divol/dstrike)

Specifying the vol skew (i.e. the derivative) allows us to build a spline from a smaller set of strikes.

Parameters:
  • spot (float)

  • rf_rate (float)

  • dividend_yield (float)

  • strikes (List[float] | Tuple[float, ...] | PVector[float])

  • vols (List[float] | Tuple[float, ...] | PVector[float])

  • dvols (List[float] | Tuple[float, ...] | PVector[float])

  • _id (ObjectIdField)

atmf_ivol()
Return type:

float

atmf_skew(space='strike')

output is: - dIVol/dStrike[strike=forward] (if space = ‘strike’) - dIVol/dMoneyness[moneyness=0] (if space = ‘moneyness’)

Parameters:

space (str)

Return type:

float

get_call_iprices(strikes=None, discounted=True)

This function is usefull to check the smile curve does not have butterfly arbitrage. See function “has_vol_arbitrages” for more details.

When we transform data using the isotonic regression we only get the overall trend/shape of the function. To fully specify the function we need to chose a value for a given point or an overall/mean value. Picking an arbitrary price level may lead to option prices below the intrinsic price. An alternative is to chose a level of the time-value curce i.e.

TimeValue = Price - IntrinsicValue

Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

  • discounted (bool)

Return type:

List[float | None]

get_call_iprices_()
Return type:

List[float | None]

get_call_prices(strikes=None, discounted=True)

This function is usefull to check the smile curve does not have butterfly arbitrage. See function “has_vol_arbitrages” for more details.

Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

  • discounted (bool)

Return type:

List[float | None]

get_call_prices_()
Return type:

List[float | None]

get_call_prices_with_derivatives(strikes, discounted)
Returns both following lists:
  • [CallPrice(strike) for strike in strikes]

  • [dCallPrice(strike)/dStrike for strike in strikes]

This utility is usefull when interpolating vol slices between 2 different expiration dates. We will be using the formula suggested by Gatheral and Jacquier in: - Arbitrage-free SVI volatility surfaces, Jim Gatheral and Antoine Jacquier, March 2013 - https://arxiv.org/pdf/1204.0646 The relevant formula from section 5.3 is:

C_t / K_t = α_t * (C_1 / K_1) + (1 - α_t) * (C_2 / K_2)

where:
  • C_t: Value of C at time t

  • K_t: Value of K at time t

  • α_t: Weighting factor at time t

  • C_1, C_2: Constants

  • K_1, K_2: Constants

A key part of the interpolation is to also fit the skew dVol/dK. This requires dC/dK which can also be obtained as a weighted average of dC_1/dK and dC_2/dK.

Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float])

  • discounted (bool)

Return type:

Tuple[List[float], List[float]]

get_discount_factor()
Return type:

float

get_forward()
Return type:

float

get_pvalue(strike)
Parameters:

strike (float)

Return type:

float

get_pvalues(strikes=None)
Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

Return type:

List[float]

get_vol(strike)
Parameters:

strike (float)

Return type:

Tuple[float, float]

get_vols(strikes=None)

This function returns the ivol and the derivative d_ivol/d_strike for each strike in the list.

Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

Return type:

Tuple[List[float], List[float]]

get_zscore(strike)
Parameters:

strike (float)

Return type:

float

get_zscores(strikes=None)
Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float] | None)

Return type:

List[float]

has_vol_arbitrages()

Check the if smile curve has butterfly arbitrages. The conditions are:

with function :

C : k -> bs_call(k, sigma(k))

  1. that function “C” should be convex

  2. that function C should be non-increasing

Return type:

bool

lk_interp()

Returns a function that interpolates log(strike) -> ivol using cubic Hermite splines. This function uses both the values of the volatilities and their skews (dvol/dstrike).

Since the interpolation is based on log(strike), the dvols must be transformed to dvol/dlog(strike) using the chain rule: dvol/dlog(strike) = dvol/dstrike * strike.

Return type:

Callable[[float], float]

min_ivol()
Return type:

float

min_ivol_moneyness()
Return type:

float

min_ivol_strike()
Return type:

float

moneyness_bounds()
Return type:

Tuple[float, float]

p_interp(solver='Brent')

Returns a function “p_value -> (strike, ivol)”

Note that the interpolation is linear in the log(strike) space.

Parameters:

solver (str)

Return type:

Callable[[float], Tuple[float, float]]

strike_bounds()
Return type:

Tuple[float, float]

total_variance()
Return type:

float

property as_of_date: date
property dividend_yield: float

Dividend Yield between as_of_date and expiration_date

property dvols: PVector[float]
property exercise_style: str
property expiration_date: date
property last_updated
property rf_rate: float

Risk Free Rate between as_of_date and expiration_date

property spot: float

Spot price of the option underlying

property strikes: PVector[float]

A list of strike prices for which the volatility is mapped

property ticker: str
property vols: PVector[float]

A list of volatility aligned with the strike prices list

class SVIVolSlice(forward, svi, *, _id=<factory>)

Bases: VolSlice

Parameters:
  • forward (float)

  • svi (SVIParameters | Dict[str, float])

  • _id (ObjectIdField)

atmf_ivol()
Return type:

float

atmf_skew(space='strike')

output is: - dIVol/dStrike[strike=forward] (if space = ‘strike’) - dIVol/dMoneyness[moneyness=0] (if space = ‘moneyness’)

Parameters:

space (str)

Return type:

float

get_call_prices(strikes, discounted)
Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float])

  • discounted (bool)

Return type:

List[float | None]

get_call_prices_with_derivatives(strikes, discounted)
Returns both following lists:
  • [CallPrice(strike) for strike in strikes]

  • [dCallPrice(strike)/dStrike for strike in strikes]

This utility is usefull when interpolating vol slices between 2 different expiration dates. We will be using the formula suggested by Gatheral and Jacquier in: - Arbitrage-free SVI volatility surfaces, Jim Gatheral and Antoine Jacquier, March 2013 - https://arxiv.org/pdf/1204.0646 The relevant formula from section 5.3 is:

C_t / K_t = α_t * (C_1 / K_1) + (1 - α_t) * (C_2 / K_2)

where:
  • C_t: Value of C at time t

  • K_t: Value of K at time t

  • α_t: Weighting factor at time t

  • C_1, C_2: Constants

  • K_1, K_2: Constants

A key part of the interpolation is to also fit the skew dVol/dK. This requires dC/dK which can also be obtained as a weighted average of dC_1/dK and dC_2/dK.

Parameters:
  • strikes (List[float] | Tuple[float, ...] | PVector[float])

  • discounted (bool)

Return type:

Tuple[List[float], List[float]]

get_discount_factor()
Return type:

float

get_forward()
Return type:

float

get_pvalue(strike)
Parameters:

strike (float)

Return type:

float

get_pvalues(strikes)
Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float])

Return type:

List[float]

get_vars(strikes)

This function returns the ivar and the derivative d_ivar/d_moneyness for each strike in the list.

Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float])

Return type:

Tuple[List[float], List[float]]

get_vol(strike)
Parameters:

strike (float)

Return type:

Tuple[float, float]

get_vols(strikes)

This function returns the ivol and the derivative d_ivol/d_strike for each strike in the list.

Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float])

Return type:

Tuple[List[float], List[float]]

get_zscore(strike)
Parameters:

strike (float)

Return type:

float

get_zscores(strikes)
Parameters:

strikes (List[float] | Tuple[float, ...] | PVector[float])

Return type:

List[float]

has_vol_arbitrages()

As the strikes are sorted in ascending order the z-scores should also be sorted. Unless there is a vol arbitrage where a spike in vol causes a z-score value to be out of order.

Return type:

bool

min_ivol()
Return type:

float

min_ivol_moneyness()
Return type:

float

min_ivol_strike()
Return type:

float

moneyness_bounds()
Return type:

Tuple[float, float]

p_interp(solver='Brent')

Returns a function “p_value -> (strike, ivol)”

Note that the interpolation is linear in the log(strike) space.

Parameters:

solver (str)

Return type:

Callable[[float], Tuple[float, float]]

strike_bounds()
Return type:

Tuple[float, float]

total_variance()
Return type:

float

property as_of_date: date
property exercise_style: str
property expiration_date: date
property forward: float
property last_updated
property svi: SVIParameters
property ticker: str
class SVIParameters(a, b, rho, m, sigma)

Bases: object

So called “Raw” SVI parameters. The SVI model admits several parameterization.

Reference paper: - Arbitrage-free SVI volatility surfaces, Jim Gatheral and Antoine Jacquier, March 2013 - https://arxiv.org/pdf/1204.0646

Parameters:
  • a (float)

  • b (float)

  • rho (float)

  • m (float)

  • sigma (float)

atm_variance()

When strike=forward (the ATM Foward) we have mn=0

Return type:

float

convert_to_jump_svi(t)

Convert Raw SVI parameters to “Jump Wings” SVI parameters.

Equations can be found in this reference paper: - Arbitrage-free SVI volatility surfaces, Jim Gatheral and Antoine Jacquier, March 2013 - https://arxiv.org/pdf/1204.0646

Parameters:

t (float)

Return type:

JumpSVIParameters

convert_to_natural_svi()

Convert Raw SVI parameters to Natural SVI parameters.

Equations can be found in this reference paper: - Arbitrage-free SVI volatility surfaces, Jim Gatheral and Antoine Jacquier, March 2013 - https://arxiv.org/pdf/1204.0646

Return type:

NaturalSVIParameters

is_valid()
Return type:

bool

is_valid_domain()
Return type:

bool

is_variance_positive()
Return type:

bool

min_variance()
See reference slides here:

https://mfe.baruch.cuny.edu/wp-content/uploads/2013/01/OsakaSVI2012.pdf

Return type:

float

min_variance_moneyness()

The value for moneyness that minimize : mn -> svi_func(mn)

With change of variable y = (mn-m)/sigma it is easy to show that the minimum is reached for:

y = -rho / sqrt(1 - rho^2)

Return type:

float

svi_d2func()
Return type:

Callable[[float | ndarray], float | ndarray]

svi_dfunc()
Return type:

Callable[[float | ndarray], float | ndarray]

svi_func()
Return type:

Callable[[float | ndarray], float | ndarray]

vertex_variance()

In the SVI model the parameter “m” is called the vertex. When “k = m” some terms cancel out and we are left with:

variance = self.a + self.b * self.sigma

Return type:

float

a: float
b: float
m: float
rho: float
sigma: float