def test_BKExampleTwo(): # Valuation of a European option on a coupon bearing bond # This follows example in Fig 28.11 of John Hull's book but does not # have the exact same dt so there are some differences settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) expiry_date = settlement_date.add_tenor("18m") maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency num_flows = len(bond._flow_dates) for i in range(1, num_flows): pcd = bond._flow_dates[i - 1] ncd = bond._flow_dates[i] if pcd < settlement_date and ncd > settlement_date: flow_time = (pcd - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) for flow_date in bond._flow_dates: if flow_date > settlement_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) strike_price = 105.0 face = 100.0 tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear times = np.linspace(0, tmat, 11) dates = settlement_date.add_years(times) dfs = np.exp(-0.05 * times) curve = DiscountCurve(settlement_date, dates, dfs) price = bond.clean_price_from_discount_curve(settlement_date, curve) testCases.header("LABEL", "VALUE") testCases.print("Fixed Income Price:", price) sigma = 0.20 a = 0.05 num_time_steps = 26 model = BKTree(sigma, a, num_time_steps) model.build_tree(tmat, times, dfs) exercise_type = FinExerciseTypes.AMERICAN v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) # Test convergence num_steps_list = [100, 200, 300, 500, 1000] exercise_type = FinExerciseTypes.AMERICAN testCases.header("TIMESTEPS", "TIME", "VALUE") treeVector = [] for num_time_steps in num_steps_list: start = time.time() model = BKTree(sigma, a, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) end = time.time() period = end - start treeVector.append(v) testCases.print(num_time_steps, period, v) # plt.plot(num_steps_list, treeVector) # Value in Hill converges to 0.699 with 100 time steps while I get 0.700 if 1 == 0: print("RT") print_tree(model._rt, 5) print("Q") print_tree(model._Q, 5)
def test_HullWhiteBondOption(): # Valuation of a European option on a coupon bearing bond settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) expiry_date = settlement_date.add_tenor("18m") maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency num_flows = len(bond._coupon_dates) for i in range(1, num_flows): pcd = bond._coupon_dates[i - 1] ncd = bond._coupon_dates[i] if ncd > settlement_date: if len(coupon_times) == 0: flow_time = (pcd - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) flow_time = (ncd - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) strike_price = 100.0 face = 100.0 y = 0.05 times = np.linspace(0, 10, 21) dfs = np.power(1 + y / 2, -times * 2) sigma = 0.0000001 a = 0.1 model = HWTree(sigma, a, None) # Test convergence num_steps_list = range(50, 500, 50) texp = (expiry_date - settlement_date) / gDaysInYear vJam = model.european_bond_option_jamshidian(texp, strike_price, face, coupon_times, coupon_flows, times, dfs) testCases.banner( "Pricing bond option on tree that goes to bond maturity and one using european bond option tree that goes to expiry." ) testCases.header("NUMSTEPS", "TIME", "EXPIRY_ONLY", "EXPIRY_TREE", "JAMSHIDIAN") for num_time_steps in num_steps_list: start = time.time() model = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_ONLY) model.build_tree(texp, times, dfs) exercise_type = FinExerciseTypes.EUROPEAN v1 = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) model = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_TREE) model.build_tree(texp, times, dfs) v2 = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) end = time.time() period = end - start testCases.print(num_time_steps, period, v1, v2, vJam) # plt.plot(num_steps_list, treeVector) if 1 == 0: print("RT") print_tree(model._rt, 5) print("BOND") print_tree(model._bond_values, 5) print("OPTION") print_tree(model._option_values, 5)