# -*- coding: utf-8 -*-
# putcall
# -------
# Collection of classical option pricing formulas.
#
# Author: sonntagsgesicht, based on a fork of Deutsche Postbank [pbrisk]
# Version: 0.2, copyright Wednesday, 18 September 2019
# Website: https://github.com/sonntagsgesicht/putcall
# License: Apache License 2.0 (see LICENSE file)
from math import sqrt, log
from mathtoolspy import cdf_abramowitz_stegun as normal_cdf
from mathtoolspy import density_normal_dist as normal_density
from ..option_payoffs import option_payoff, digital_option_payoff, straddle_payoff
#from putcall.formulas.option_payoffs import option_payoff, digital_option_payoff, straddle_payoff
def _black_param(forward_value, strike_value, implied_vol_value, time_value):
sigma = implied_vol_value * sqrt(time_value)
fms = forward_value - strike_value
d0 = (log(forward_value / strike_value) - 0.5 * sigma ** 2) / sigma if sigma > 0.0 else 0.0
d1 = d0 + sigma
return sigma, fms, d0, d1
[docs]def black(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Standard Black-76 formula for log-normal underlying distribution.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return option_payoff(forward_value, strike_value, is_call_bool)
if is_call_bool:
# call
return forward_value * normal_cdf(d1) - strike_value * normal_cdf(d0)
else:
# put
return strike_value * normal_cdf(-d0) - forward_value * normal_cdf(-d1)
[docs]def black_delta(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 delta sensitivity.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
if is_call_bool:
return 1.0 if fms > 0.0 else 0.0
else:
return -1.0 if fms < 0.0 else 0.0
# call
call_value = normal_cdf(d1)
return call_value if is_call_bool else call_value - 1.0 # put
[docs]def black_gamma(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 gamma sensitivity.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 0.0
return None # TODO Black76 gamma
[docs]def black_vega(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 vega sensitivity.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 0.0
return forward_value * sqrt(time_value) * normal_density(d1)
[docs]def black_digital(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Standard Black-76 formula for digital option on log-normal underlying distribution.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return digital_option_payoff(forward_value, strike_value, is_call_bool)
return normal_cdf(d0) if is_call_bool else normal_cdf(-d0)
[docs]def black_digital_delta(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 delta sensitivity for digital payoff.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 0.0
if is_call_bool:
# call
return normal_density(d1) / (sigma * forward_value)
else:
# put
return -normal_density(-d1) / (sigma * forward_value)
[docs]def black_digital_gamma(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 gamma sensitivity for digital payoff.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 0.0
return None # TODO Black76 gamma for digital payoff
[docs]def black_digital_vega(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 vega sensitivity for digital payoff.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 0.0
# call
call_value = d1 * normal_density(d0) / implied_vol_value
return call_value if is_call_bool else -call_value # put
[docs]def black_straddle(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Standard Black-76 formula for straddle option on log-normal underlying distribution.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return straddle_payoff(forward_value, strike_value, is_call_bool)
nd1 = normal_cdf(d1)
nd2 = normal_cdf(d0)
mnd1 = normal_cdf(-d1)
mnd2 = normal_cdf(-d0)
return forward_value * nd1 - strike_value * nd2 + strike_value * mnd2 - forward_value * mnd1
[docs]def black_straddle_delta(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 delta sensitivity for straddle payoff.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 1.0 if fms >= 0.0 else -1.0
return 2.0 * normal_density(d1) - 1
[docs]def black_straddle_gamma(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 gamma sensitivity for straddle payoff.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 0.0
return None # TODO Black76 gamma for straddle payoff
[docs]def black_straddle_vega(forward_value, strike_value, implied_vol_value, time_value, is_call_bool):
"""
Black-76 vega sensitivity for straddle payoff.
:param float forward_value: forward price of underlying at exercise date
:param float strike_value: strike price
:param float implied_vol_value: volatility of underlying price
:param float time_value: year fraction until exercise date
:param boolean is_call_bool: call -> True, put -> False
:return: float
"""
sigma, fms, d0, d1 = _black_param(forward_value, strike_value, implied_vol_value, time_value)
if sigma == 0.0:
return 0.0
return 2.0 * forward_value * sqrt(time_value) * normal_density(d1)