def test_prices(self): while self.tdi.has_next(): row = self.tdi.next_row() S, K, t, r, sigma = row['S'], row['K'], row['t'], row['R'], row[ 'v'] self.assertAlmostEqual(black_scholes_merton( 'c', S, K, t, r, sigma, q), row['bs_call'], delta=0.000001) self.assertAlmostEqual(black_scholes_merton( 'p', S, K, t, r, sigma, q), row['bs_put'], delta=0.000001)
def price_black_scholes_merton(self, option_type: str, spot: float, strike: float, years_to_maturity: float, risk_free_rate: float, dividend: float = 0) -> float: """ Finds the no-arbitrage price of a European Vanilla option. The price is computed using the Black-Scholes-Merton framework, but the variance of the underlying is extracted from this model. :param option_type: the type of the option (c for call, p for put) :param spot: the spot price of the underlying :param strike: the option strike price :param years_to_maturity: the years remaining before maturity - as a decimal number :param risk_free_rate: the risk-free interest rate :param dividend: the dividend paid by the underlying - as a decimal number :return: the no-arbitrage price of the option """ volatility = self.volatility(years_to_maturity) check_option_type(option_type) price = black_scholes_merton(option_type, spot, strike, years_to_maturity, risk_free_rate, volatility, dividend) return price
def test_implied_volatility(self): while self.tdi.has_next(): row = self.tdi.next_row() S, K, t, r, sigma = row['S'], row['K'], row['t'], row['R'], row[ 'v'] C, P = black_scholes_merton('c', S, K, t, r, sigma, q), black_scholes_merton( 'p', S, K, t, r, sigma, q) try: iv = implied_volatility(C, S, K, t, r, q, 'c') self.assertAlmostEqual(sigma, iv, delta=0.0001) except: print('could not calculate iv for ', C, S, K, t, r, 'c') iv = implied_volatility(P, S, K, t, r, q, 'p') self.assertTrue( iv == 0.0) if iv == 0.0 else self.assertAlmostEqual( sigma, iv, delta=0.001)
def theo(self, S, vol, t0=None): if t0 is None: if self.exp not in option.time_exp: option.time_exp[self.exp] = self.timetoexp() te = option.time_exp[self.exp] else: te = self.timetoexp(t0) if te <= 0: te = 0 option.time_exp[self.exp] = te if te < 0: self.tv = np.nan else: self.tv = bs.black_scholes_merton(self.flag, S, self.K, te, self.rate, vol, 0.) return self.tv
def get_malliavin_greeks_bs_flat(s0: float, t: float, no_steps: int, no_paths: int, r: float, q: float, sigma: float, payoff: Callable[[ndarray], ndarray], euler_scheme: EULER_SCHEME_TYPE): shift_delta = 0.01 shift_vega = 0.01 z = np.random.standard_normal(size=(no_paths, no_steps - 1)) drift_t = partial(bs_drift_flat, rate_t=r, dividend_t=q) sigma_t = partial(bs_sigma_flat, sigma_t=sigma) sigma_t_shift = partial(bs_sigma_flat, sigma_t=sigma + shift_vega) s_t = sde_euler_simulation(0.0, t, s0, no_steps, no_paths, z, drift_t, sigma_t, euler_scheme) s_t_shift_delta = sde_euler_simulation(0.0, t, s0 + shift_delta, no_steps, no_paths, z, drift_t, sigma_t, euler_scheme) s_t_shift_vega = sde_euler_simulation(0.0, t, s0, no_steps, no_paths, z, drift_t, sigma_t_shift, euler_scheme) phi_t = payoff(s_t[:, -1]) mc_price = np.average(phi_t) * np.exp(-r * t) mc_price_delta = np.average(payoff(s_t_shift_delta[:, -1])) * np.exp( -r * t) mc_price_vega = np.average(payoff(s_t_shift_vega[:, -1])) * np.exp(-r * t) delta = analytical.delta('c', s0, 90, t, r, sigma, q) price = black_scholes_merton('c', s0, 90, t, r, sigma, q) vega = analytical.vega('c', s0, 90, t, r, sigma, q) * 100 mc_delta = (mc_price_delta - mc_price) / shift_delta malliavin_delta = get_malliavin_delta_bs_flat(phi_t, s_t[:, -1], s0, sigma, r, q, t) mc_vega = (mc_price_vega - mc_price) / shift_vega malliavin_vega = get_malliavin_vega_bs_flat(phi_t, s_t[:, -1], s0, sigma, r, q, t) return mc_delta, malliavin_delta
def btnClicked2(self): price = float(self.ui.StPrice.toPlainText()) strike = float(self.ui.Strike.toPlainText()) dayst = float(self.ui.Days.toPlainText()) days = dayst / 365.0 rate = float(self.ui.intrate.toPlainText()) divd = float(self.ui.dividend.toPlainText()) cp = self.ui.corp.toPlainText() vol = float(self.ui.volatility.toPlainText()) price1 = BSprice.black_scholes_merton(cp, price, strike, days, rate, vol, divd) #price2 = binAm(price,strike,days,rate,vol,1000) delt = BSgreeksN.delta(cp, price, strike, days, rate, vol, divd) vega = BSgreeksN.vega(cp, price, strike, days, rate, vol, divd) gamma = BSgreeksN.gamma(cp, price, strike, days, rate, vol, divd) theta = BSgreeksN.theta(cp, price, strike, days, rate, vol, divd) self.ui.optprice.setText(str(price1)) self.ui.Delta1.setText(str(delt)) self.ui.Theta1.setText(str(theta)) self.ui.Gamma1.setText(str(gamma)) self.ui.Vega1.setText(str(vega))
T = 4.0 mesh_t = Mesh(uniform_mesh, 50, 0.0, T) r = 0.03 q = 0.01 sigma = 0.3 S0 = 100.0 K = np.exp((r - q) * T) * S0 + 10 log_K = np.log(K) f = np.exp((r - q) * T) * S0 df = np.exp(-r * T) start_time = time.time() analytic_price = df * black_scholes_merton('c', f, K, T, 0.0, sigma, 0.0) end_time = time.time() print(end_time - start_time) print(analytic_price) mesh_x = LnUnderlyingMesh(r, q, sigma, S0, T, 0.999, uniform_mesh, 100) bs_pde = PDE.from_ipde_terms(LN_BS_PDE(r, q, sigma)) bc = Zero_Laplacian_BC() operator_exp = PDEOperators.LinearPDEOperator(mesh_x, bs_pde, bc) operator_impl = PDEOperators.LinearPDEOperator(mesh_x, bs_pde, bc) operators = [operator_exp, operator_impl] def f_ln_payoff(mesh: Mesh) -> np_ndarray:
from py_vollib.black_scholes_merton import black_scholes_merton from py_vollib.helpers.numerical_greeks import delta as numerical_delta from py_vollib.helpers.numerical_greeks import vega as numerical_vega from py_vollib.helpers.numerical_greeks import theta as numerical_theta from py_vollib.helpers.numerical_greeks import rho as numerical_rho from py_vollib.helpers.numerical_greeks import gamma as numerical_gamma from py_vollib.black_scholes_merton.greeks.analytical import gamma as agamma from py_vollib.black_scholes_merton.greeks.analytical import delta as adelta from py_vollib.black_scholes_merton.greeks.analytical import vega as avega from py_vollib.black_scholes_merton.greeks.analytical import rho as arho from py_vollib.black_scholes_merton.greeks.analytical import theta as atheta # ----------------------------------------------------------------------------- # FUNCTIONS - NUMERICAL GREEK CALCULATION f = lambda flag, S, K, t, r, sigma, b: black_scholes_merton( flag, S, K, t, r, sigma, r - b) def delta(flag, S, K, t, r, sigma, q): """Returns the Black-Scholes-Merton delta of an option. :param flag: 'c' or 'p' for call or put. :type flag: str :param S: underlying asset price :type S: float :param K: strike price :type K: float :param t: time to expiration in years :type t: float :param r: annual risk-free interest rate :type r: float
no_dt = len(dt) for i in range(0, no_dt): no_time_steps = int(dt[i] / delta_time) rnd_generator.set_seed(seed) # european_option = EuropeanOption(f0, 1, TypeSellBuy.BUY, TypeEuropeanOption.CALL, f0, dt[i]) # map_output = SABR_Engine.get_path_multi_step(0.0, dt[i], parameters, f0, no_paths, no_time_steps, # Types.TYPE_STANDARD_NORMAL_SAMPLING.ANTITHETIC, # rnd_generator) # # results = european_option.get_price(map_output[Types.SABR_OUTPUT.PATHS]) # mc_option_price.append(results[0]) # price the option with var swap approximation analytic_price = EuropeanOptionExpansion.get_var_swap_apprx_price(f0, 1.0, TypeSellBuy.BUY, TypeEuropeanOption.CALL, f0, dt[i], parameters, Types.TypeModel.SABR) var_swap_approximation_price.append(analytic_price) # hagan's price iv_hagan = SABRTools.sabr_vol_jit(parameters[0], parameters[1], parameters[2], 0.0, dt[i]) hagan_price = black_scholes_merton('c', f0, f0, dt[i], 0.0, iv_hagan, 0.0) hagan_approximation_price.append(hagan_price) plt.plot(dt, mc_option_price, label='mc price') plt.plot(dt, var_swap_approximation_price, label='variance swap approximation') plt.plot(dt, hagan_approximation_price, label='Hagan approximation') plt.legend() plt.title('ATM option price') plt.show()
# We will do the dynamic hedge of option call under BS model. k = 100.0 spot = 120.0 r = 0.02 q = 0.00 sigma = 0.7 delta_time = T notional = 1000.0 portfolio_t_i = np.zeros(no_time_steps) option_t_i = np.zeros(no_time_steps) alpha_t_i_1 = analytical.delta('c', spot, k, delta_time, r, sigma, q) * notional option_t_i[0] = black_scholes_merton('c', spot, k, delta_time, r, sigma, q) * notional beta_t = option_t_i[0] - alpha_t_i_1 * spot portfolio_t_i[0] = (alpha_t_i_1 * spot + beta_t) s_t_i_1 = spot s_t_i = 0.0 alpha_t_i = 0.0 rebalanced_index = list( map(lambda x: int(x), list(np.arange(0.0, no_time_steps, 30)))) # rebalanced_index = np.arange(1, no_time_steps) rng = RNG.RndGenerator(123) z_s = rng.normal(0.0, 1.0, no_time_steps - 1)
0.0, T, parameters, f0, no_paths, no_time_steps, Types.TYPE_STANDARD_NORMAL_SAMPLING.REGULAR_WAY, rnd_generator) option_prices_mc = [] option_prices_hagan = [] density_mc = [] density_hagan = [] no_options = len(european_options) for i in range(0, no_options): result = european_options[i].get_price( map_output[Types.SABR_OUTPUT.PATHS][:, -1]) option_prices_mc.append(result[0]) z = np.log(f0 / k_s[i]) iv_hagan = SABRTools.sabr_vol_jit(alpha, rho, nu, z, T) option_prices_hagan.append( black_scholes_merton('c', f0, k_s[i], T, 0.0, iv_hagan, 0.0)) pdf_hagan = [] pdf_mc = [] plt.figure(figsize=(8, 5)) for i in range(1, no_options - 1): pdf_hagan.append( (option_prices_hagan[i + 1] - 2.0 * option_prices_hagan[i] + option_prices_hagan[i - 1]) / (delta_strike * delta_strike)) pdf_mc.append((option_prices_mc[i + 1] - 2.0 * option_prices_mc[i] + option_prices_mc[i - 1]) / (delta_strike * delta_strike)) plt.plot(k_s[1:no_options - 1], pdf_hagan, label="Hagan's density", linestyle='--',
def get_var_swap_apprx_price(strike: float, notional: float, buy_sell: TypeSellBuy, option_type: TypeEuropeanOption, spot: float, delta_time: float, parameters: List[float], model: Types.TypeModel): if model == Types.TypeModel.SABR: alpha = parameters[0] rho = parameters[1] nu = parameters[2] var_swap = SABRTools.get_variance_swap(alpha, nu, delta_time) if option_type == TypeEuropeanOption.CALL: bs0 = black_scholes_merton('c', spot, strike, delta_time, 0.0, var_swap, 0.0) h_0 = delta_vega(strike, spot, var_swap, delta_time) rho_term = SABRTools.get_rho_term_var_swap(alpha, nu, delta_time) * h_0 if buy_sell == TypeSellBuy.BUY: return notional * (bs0 + 0.5 * rho * rho_term) else: return - notional * (bs0 + 0.5 * rho * rho_term) else: bs0 = black_scholes_merton('p', spot, strike, delta_time, 0.0, var_swap, 0.0) h_0 = delta_vega(strike, spot, var_swap, delta_time) rho_term = SABRTools.get_rho_term_var_swap(alpha, nu, delta_time) * h_0 forward = (spot - strike) call_price = notional * (bs0 + 0.5 * rho * rho_term) if buy_sell == TypeSellBuy.BUY: return call_price - forward else: return forward - call_price elif model == Types.TypeModel.HESTON: k = parameters[0] theta = parameters[1] epsilon = parameters[2] rho = parameters[3] v0 = parameters[4] var_swap = HestonTool.get_variance_swap(v0, k, theta, delta_time) if option_type == TypeEuropeanOption.CALL: bs0 = black_scholes_merton('c', spot, strike, delta_time, 0.0, var_swap, 0.0) h_0 = delta_vega(strike, spot, var_swap, delta_time) rho_term = HestonTool.get_rho_term_var_swap(v0, k, theta, epsilon, delta_time) * h_0 if buy_sell == TypeSellBuy.BUY: return notional * (bs0 + 0.5 * rho * rho_term) else: return - notional * (bs0 + 0.5 * rho * rho_term) else: bs0 = black_scholes_merton('p', spot, strike, delta_time, 0.0, var_swap, 0.0) h_0 = delta_vega(strike, spot, var_swap, delta_time) rho_term = HestonTool.get_rho_term_var_swap(v0, k, theta, delta_time) * h_0 forward = (spot - strike) call_price = notional * (bs0 + 0.5 * rho * rho_term) if buy_sell == TypeSellBuy.BUY: return call_price - forward else: return forward - call_price elif model == Types.TypeModel.ROUGH_BERGOMI: return 0.0 else: print(f'At the moment we have not implmented the approximation price for {str(model)} ')