def compare_values(M0=50, I=5000): results = [] for T in t_list: # # Simulation # M = int(M0 * T) cho_matrix = generate_cholesky(rho) rand = random_number_generator(M, I, anti_paths, moment_matching) r = SRD_generate_paths(r0, kappa_r, theta_r, sigma_r, T, M, I, rand, 0, cho_matrix) v = SRD_generate_paths(v0, kappa_v, theta_v, sigma_v, T, M, I, rand, 2, cho_matrix) S = B96_generate_paths(S0, r, v, lamb, mu, delta, rand, 1, 3, cho_matrix, T, M, I, moment_matching) for K in k_list: # # Valuation # h = np.maximum(S[-1] - K, 0) B0T = B([r0, kappa_r, theta_r, sigma_r, 0.0, T]) V0_mcs = B0T * np.sum(h) / I # MCS estimator # # European Call Option via Fourier # ra = -math.log(B0T) / T # average short rate/yield C0 = BCC_call_value(S0, K, T, ra, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta) results.append((T, K, C0, V0_mcs, V0_mcs - C0)) print(" %6s | %6s | %7s | %7s | %7s" % ('T', 'K', 'C0', 'MCS', 'DIFF')) for res in results: print(" %6.3f | %6d | %7.3f | %7.3f | %7.3f" % res)
def lsm_compare_values(M0=50, I=5000): results = [] for T in t_list: # # Simulation # M = int(M0 * T) cho_matrix = generate_cholesky(rho) rand = random_number_generator(M, I, anti_paths, moment_matching) r = SRD_generate_paths(r0, kappa_r, theta_r, sigma_r, T, M, I, rand, 0, cho_matrix) v = SRD_generate_paths(v0, kappa_v, theta_v, sigma_v, T, M, I, rand, 2, cho_matrix) S = B96_generate_paths(S0, r, v, lamb, mu, delta, rand, 1, 3, cho_matrix, T, M, I, moment_matching) for K in k_list: # # Valuation # B0T = B([r0, kappa_r, theta_r, sigma_r, 0.0, T]) V0_lsm = BCC97_lsm_valuation(S, r, v, K, T, M, I) # LSM estimator # # European Call Option via Fourier # ra = -math.log(B0T) / T # average short rate/yield C0 = BCC_call_value(S0, K, T, ra, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta) P0 = C0 + K * B0T - S0 results.append((T, K, P0, V0_lsm, V0_lsm - P0)) print(" %6s | %6s | %7s | %7s | %7s" % ('T', 'K', 'P0', 'LSM', 'DIFF')) for res in results: print(" %6.3f | %6d | %7.3f | %7.3f | %7.3f" % res)
def BCC_jump_calculate_model_values(p0): ''' Calculates all model values given parameter vector p0. ''' lamb, mu, delta = p0 values = [] for row, option in options.iterrows(): T = (option['Maturity'] - option['Date']).days / 365. B0T = B([r0, kappa_r, theta_r, sigma_r, 0, T]) r = -math.log(B0T) / T model_value = BCC_call_value(S0, option['Strike'], T, r, kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta) values.append(model_value) return np.array(values)
print(tmpl_1 % ('T', 'K', 'V0', 'V0_LSM', 'V0_CV', 'P0', 'P0_MCS', 'err', 'rerr', 'acc1', 'acc2')) # correlation matrix, cholesky decomposition v0, kappa_v, sigma_v, rho = para[panel] correlation_matrix = np.zeros((3, 3), dtype=np.float) correlation_matrix[0] = [1.0, rho, 0.0] correlation_matrix[1] = [rho, 1.0, 0.0] correlation_matrix[2] = [0.0, 0.0, 1.0] CM = np.linalg.cholesky(correlation_matrix) z = 0 # option counter S, r, v, h, V, matrix = 0, 0, 0, 0, 0, 0 gc.collect() for T in t_list: # times-to-maturity # discount factor B0T = B([r0, kappa_r, theta_r, sigma_r, 0.0, T]) # average constant short rate/yield ra = -math.log(B0T) / T # time interval in years dt = T / M # pseudo-random numbers rand = random_number_generator(M, I) # short rate process paths r = SRD_generate_paths(x_disc, r0, kappa_r, theta_r, sigma_r, T, M, I, rand, 0, CM) # volatility process paths v = SRD_generate_paths(x_disc, v0, kappa_v, theta_v, sigma_v, T, M, I, rand, 2, CM) # index level process paths S = H93_index_paths(S0, r, v, 1, CM) for K in k_list: # strikes
def BCC97_hedge_simulation(M=50, I=1000): ''' Monte Carlo simualtion of dynamic hedging paths for American put option in BSM model. ''' # # Initializations # po = np.zeros(M + 1, dtype=np.float) # vector for portfolio values delt = np.zeros(M + 1, dtype=np.float) # vector for deltas ds = dis * S0 V_1, S, r, v, ex, rg, h, dt = BCC97_lsm_put_value(S0 + (2 - a) * ds, K, T, M, I) # 'data basis' for delta hedging V_2 = BCC97_lsm_put_value(S0 - a * ds, K, T, M, I)[0] delt[0] = (V_1 - V_2) / (2 * ds) # initial option value for S0 V0LSM = BCC97_lsm_put_value(S0, K, T, M, I)[0] po[0] = V0LSM # initial portfolio values # # Hedge Runs # pl_list = [] runs = min(I, 10000) for run in range(runs): bo = V0LSM - delt[0] * S0 # initial bond position value p = run run += 1 for t in range(1, M + 1, 1): if ex[t, p] == 0: df = math.exp((r[t, p] + r[t - 1, p]) / 2 * dt) if t != M: po[t] = delt[t - 1] * S[t, p] + bo * df # portfolio payoff ds = dis * S[t, p] sd = S[t, p] + (2 - a) * ds # disturbed index level stateV_A = [ sd * v[t, p] * r[t, p], sd * v[t, p], sd * r[t, p], v[t, p] * r[t, p], sd**2, v[t, p]**2, r[t, p]**2, sd, v[t, p], r[t, p], 1 ] # state vector for S[t, p] + (2.0 - a) * ds stateV_A.reverse() V0A = max(0, np.dot(rg[t], stateV_A)) # revaluation via regression sd = S[t, p] - a * ds # disturbed index level stateV_B = [ sd * v[t, p] * r[t, p], sd * v[t, p], sd * r[t, p], v[t, p] * r[t, p], sd**2, v[t, p]**2, r[t, p]**2, sd, v[t, p], r[t, p], 1 ] # state vector for S[t, p] - a * ds stateV_B.reverse() V0B = max(0, np.dot(rg[t], stateV_B)) # revaluation via regression delt[t] = (V0A - V0B) / (2 * ds) else: po[t] = delt[t - 1] * S[t, p] + bo * df delt[t] = 0.0 bo = po[t] - delt[t] * S[t, p] else: po[t] = delt[t - 1] * S[t, p] + bo * df break alpha_t = [kappa_r, theta_r, sigma_r, r0, 0.0, t * dt] pl = (po[t] - h[t, p]) * B(alpha_t) if run % 1000 == 0: print("run %5d p/l %8.3f" % (run, pl)) pl_list.append(pl) pl_list = np.array(pl_list) # # Results Output # print("\nSUMMARY STATISTICS FOR P&L") print("---------------------------------") print("Dynamic Replications %12d" % runs) print("Time Steps %12d" % M) print("Paths for Valuation %12d" % I) print("Maximum %12.3f" % max(pl_list)) print("Average %12.3f" % np.mean(pl_list)) print("Median %12.3f" % np.median(pl_list)) print("Minimum %12.3f" % min(pl_list)) print("---------------------------------") return pl_list