def test_BondOptionZEROVOLConvergence(): # Build discount curve settlement_date = Date(1, 9, 2019) rate = 0.05 discount_curve = DiscountCurveFlat(settlement_date, rate, FrequencyTypes.ANNUAL) # Bond details issue_date = Date(1, 9, 2014) maturity_date = Date(1, 9, 2025) coupon = 0.06 freq_type = FrequencyTypes.ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) # Option Details expiry_date = Date(1, 12, 2021) face = 100.0 dfExpiry = discount_curve.df(expiry_date) fwdCleanValue = bond.clean_price_from_discount_curve( expiry_date, discount_curve) # fwdFullValue = bond.full_price_from_discount_curve(expiry_date, discount_curve) # print("BOND FwdCleanBondPx", fwdCleanValue) # print("BOND FwdFullBondPx", fwdFullValue) # print("BOND Accrued:", bond._accruedInterest) spotCleanValue = bond.clean_price_from_discount_curve( settlement_date, discount_curve) testCases.header("STRIKE", "STEPS", "CALL_INT", "CALL_INT_PV", "CALL_EUR", "CALL_AMER", "PUT_INT", "PUT_INT_PV", "PUT_EUR", "PUT_AMER") numTimeSteps = range(100, 1000, 100) strikePrices = [90, 100, 110, 120] for strikePrice in strikePrices: callIntrinsic = max(spotCleanValue - strikePrice, 0) putIntrinsic = max(strikePrice - spotCleanValue, 0) callIntrinsicPV = max(fwdCleanValue - strikePrice, 0) * dfExpiry putIntrinsicPV = max(strikePrice - fwdCleanValue, 0) * dfExpiry for num_steps in numTimeSteps: sigma = 0.0000001 a = 0.1 model = FinModelRatesHW(sigma, a, num_steps) optionType = FinOptionTypes.EUROPEAN_CALL bondOption1 = BondOption(bond, expiry_date, strikePrice, face, optionType) v1 = bondOption1.value(settlement_date, discount_curve, model) optionType = FinOptionTypes.AMERICAN_CALL bondOption2 = BondOption(bond, expiry_date, strikePrice, face, optionType) v2 = bondOption2.value(settlement_date, discount_curve, model) optionType = FinOptionTypes.EUROPEAN_PUT bondOption3 = BondOption(bond, expiry_date, strikePrice, face, optionType) v3 = bondOption3.value(settlement_date, discount_curve, model) optionType = FinOptionTypes.AMERICAN_PUT bondOption4 = BondOption(bond, expiry_date, strikePrice, face, optionType) v4 = bondOption4.value(settlement_date, discount_curve, model) testCases.print(strikePrice, num_steps, callIntrinsic, callIntrinsicPV, v1, v2, putIntrinsic, putIntrinsicPV, v3, v4)
def test_HullWhiteCallableBond(): # Valuation of a European option on a coupon bearing bond settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) maturity_date = settlement_date.addTenor("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 for flowDate in bond._flow_dates[1:]: if flowDate > settlement_date: flow_time = (flowDate - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) ########################################################################### # Set up the call and put times and prices ########################################################################### call_dates = [] call_prices = [] callPx = 120.0 call_dates.append(settlement_date.addTenor("2Y")); call_prices.append(callPx) call_dates.append(settlement_date.addTenor("3Y")); call_prices.append(callPx) call_dates.append(settlement_date.addTenor("4Y")); call_prices.append(callPx) call_dates.append(settlement_date.addTenor("5Y")); call_prices.append(callPx) call_dates.append(settlement_date.addTenor("6Y")); call_prices.append(callPx) call_dates.append(settlement_date.addTenor("7Y")); call_prices.append(callPx) call_dates.append(settlement_date.addTenor("8Y")); call_prices.append(callPx) call_times = [] for dt in call_dates: t = (dt - settlement_date) / gDaysInYear call_times.append(t) put_dates = [] put_prices = [] putPx = 98.0 put_dates.append(settlement_date.addTenor("2Y")); put_prices.append(putPx) put_dates.append(settlement_date.addTenor("3Y")); put_prices.append(putPx) put_dates.append(settlement_date.addTenor("4Y")); put_prices.append(putPx) put_dates.append(settlement_date.addTenor("5Y")); put_prices.append(putPx) put_dates.append(settlement_date.addTenor("6Y")); put_prices.append(putPx) put_dates.append(settlement_date.addTenor("7Y")); put_prices.append(putPx) put_dates.append(settlement_date.addTenor("8Y")); put_prices.append(putPx) put_times = [] for dt in put_dates: t = (dt - settlement_date) / gDaysInYear put_times.append(t) ########################################################################### tmat = (maturity_date - settlement_date) / gDaysInYear curve = DiscountCurveFlat(settlement_date, 0.05, FrequencyTypes.CONTINUOUS) dfs = [] times = [] for dt in bond._flow_dates: if dt > settlement_date: t = (dt - settlement_date) / gDaysInYear df = curve.df(dt) times.append(t) dfs.append(df) dfs = np.array(dfs) times = np.array(times) ########################################################################### v1 = bond.clean_price_from_discount_curve(settlement_date, curve) sigma = 0.02 # basis point volatility a = 0.01 # Test convergence num_stepsList = [100, 200, 500, 1000] tmat = (maturity_date - settlement_date)/gDaysInYear testCases.header("NUMSTEPS", "TIME", "BOND_ONLY", "CALLABLE_BOND") for numTimeSteps in num_stepsList: start = time.time() model = FinModelRatesHW(sigma, a, numTimeSteps) model.buildTree(tmat, times, dfs) v2 = model.callablePuttableBond_Tree(coupon_times, coupon_flows, call_times, call_prices, put_times, put_prices, 100.0) end = time.time() period = end-start testCases.print(numTimeSteps, period, v1, v2)