Source code for rpylib.numerical.closedform.cfblackscholes

"""
Closed-Form pricing formulas for the Black-Scholes model
"""

import numpy as np
from scipy.stats import norm


[docs]class CFBlackScholes: """Some Closed-form formulas for the Black-Scholes model""" eps = 1e-8 # used as a threshold for very low variance or maturity
[docs] def __init__(self, bs_model: "BlackScholesModel"): """ :param bs_model: the Black-Scholes model object """ import rpylib.model.levymodel.mixed.blackscholes if not isinstance( bs_model, rpylib.model.levymodel.mixed.blackscholes.BlackScholesModel ): raise ValueError("expected a Black-Scholes model") self.bs_model = bs_model
[docs] def forward(self, strike, maturity): """Price a forward in the Black-Scholes model :param strike: strike of the forward contract :param maturity: maturity of the forward contract Returns: The value of the forward contract """ r, d, spot = self.bs_model.r, self.bs_model.d, self.bs_model.spot return spot * np.exp(-d * maturity) - strike * np.exp(-r * maturity)
def _call_put(self, flag: int, strike: float, maturity: float): r, d, = ( self.bs_model.r, self.bs_model.d, ) spot, sigma = self.bs_model.spot, self.bs_model.parameters.sigma df = np.exp(-r * maturity) fwd = spot * np.exp((r - d) * maturity) if ( sigma < CFBlackScholes.eps or spot < CFBlackScholes.eps or maturity < CFBlackScholes.eps ): intrinsic = max(0.0, flag * (fwd - strike)) return df * intrinsic stddev = sigma * np.sqrt(maturity) d1 = np.log(fwd / strike) / stddev + 0.5 * stddev d2 = d1 - stddev return df * flag * (fwd * norm.cdf(d1 * flag) - strike * norm.cdf(d2 * flag))
[docs] def call(self, strike: float, maturity: float): """Price a Call option in the Black-Scholes model :param strike: call strike :param maturity: call maturity """ return self._call_put(1, strike, maturity)
[docs] def put(self, strike: float, maturity: float): """Price a Put option in the Black-Scholes model :param strike: put strike :param maturity: put maturity """ return self._call_put(-1, strike, maturity)
[docs] def butterfly( self, strike1: float, strike2: float, strike3: float, maturity: float ): """Price a Butterfly option in the Black-Scholes model strike1: first strike strike2: second strike strike3: third strike maturity: butterfly maturity .. note:: we expect strike1 < strike2 < strike3 """ return ( self.call(strike1, maturity) - 2 * self.call(strike2, maturity) + self.call(strike3, maturity) )
[docs] def digital(self, strike, maturity): """Price a digital option in the Black-Scholes model :param strike: digital strike :param maturity: digital maturity """ r, d, = ( self.bs_model.r, self.bs_model.d, ) spot, sigma = self.bs_model.spot, self.bs_model.parameters.sigma fwd = spot * np.exp((r - d) * maturity) df = np.exp(-r * maturity) if ( sigma < CFBlackScholes.eps or spot < CFBlackScholes.eps or maturity < CFBlackScholes.eps ): intrinsic = np.array([1 if fwd > k else 0 for k in strike]) return df * intrinsic stddev = sigma * np.sqrt(maturity) d2 = np.log(fwd / strike) / stddev - 0.5 * stddev return df * norm.cdf(d2)