def test_BKExampleOne(): testCases.banner("=== HULL INITIAL EXAMPLE SECTION 28.7 ED 6 PG 668 ====") times = [0.0, 0.5000, 1.00000, 1.50000, 2.00000, 2.500000, 3.00000] zeros = [0.03, 0.0343, 0.03824, 0.04183, 0.04512, 0.048512, 0.05086] times = np.array(times) zeros = np.array(zeros) dfs = np.exp(-zeros * times) startDate = FinDate(1, 12, 2019) endDate = FinDate(1, 6, 2021) sigma = 0.25 a = 0.22 numTimeSteps = 3 tmat = (endDate - startDate) / gDaysInYear model = FinModelRatesBK(sigma, a, numTimeSteps) model.buildTree(tmat, times, dfs) # Agrees with Figure 28.10 - Not exact as we have dt not exactly 0.50 if numTimeSteps < 5: testCases.header("LABEL", "VALUE") testCases.print("QTREE", model._Q) testCases.print("RTREE", model._rt) printTree(model._rt) testCases.print("PU AT LAST TIME", model._pu) testCases.print("PDM AT LAST TIME", model._pm) testCases.print("PD AT LAST TIME", model._pd)
def test_HullWhiteExampleOne(): # HULL BOOK INITIAL EXAMPLE SECTION 28.7 HW EDITION 6 times = [0.0, 0.5000, 1.00000, 1.50000, 2.00000, 2.500000, 3.00000] zeros = [0.03, 0.0343, 0.03824, 0.04183, 0.04512, 0.048512, 0.05086] times = np.array(times) zeros = np.array(zeros) dfs = np.exp(-zeros * times) startDate = FinDate(1, 12, 2019) endDate = FinDate(1, 12, 2022) sigma = 0.01 a = 0.1 numTimeSteps = 3 model = FinModelRatesHullWhite(a, sigma) treeMat = (endDate - startDate) / gDaysInYear model.buildTree(treeMat, numTimeSteps, times, dfs) printTree(model._Q) print("") printTree(model._rt) print("")
def test_BlackKarasinskiExampleOne(): # HULL BOOK INITIAL EXAMPLE SECTION 28.7 HW EDITION 6 times = [0.0, 0.5000, 1.00000, 1.50000, 2.00000, 2.500000, 3.00000] zeros = [0.03, 0.0343, 0.03824, 0.04183, 0.04512, 0.048512, 0.05086] times = np.array(times) zeros = np.array(zeros) dfs = np.exp(-zeros * times) startDate = FinDate(1, 12, 2019) curve = FinDiscountCurve(startDate, times, dfs) endDate = FinDate(1, 12, 2022) sigma = 0.25 a = 0.22 numTimeSteps = 6 tmat = (endDate - startDate) / gDaysInYear model = FinModelRatesBlackKarasinski(a, sigma) model.buildTree(tmat, numTimeSteps, times, dfs) printTree(model._Q) print("") printTree(model._rt) print("")
def test_BDTExampleTwo(): # Valuation of a European option on a coupon bearing bond # This follows example in Fig 28.11 of John Hull's book (6th Edition) # but does not have the exact same dt so there are some differences testCases.banner("===================== FIG 28.11 HULL BOOK =============") settlementDate = FinDate(1, 12, 2019) issueDate = FinDate(1, 12, 2015) expiryDate = settlementDate.addTenor("18m") maturityDate = settlementDate.addTenor("10Y") coupon = 0.05 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) couponTimes = [] couponFlows = [] cpn = bond._coupon / bond._frequency numFlows = len(bond._flowDates) for i in range(1, numFlows): pcd = bond._flowDates[i - 1] ncd = bond._flowDates[i] if pcd < settlementDate and ncd > settlementDate: flowTime = (pcd - settlementDate) / gDaysInYear couponTimes.append(flowTime) couponFlows.append(cpn) for flowDate in bond._flowDates: if flowDate > settlementDate: flowTime = (flowDate - settlementDate) / gDaysInYear couponTimes.append(flowTime) couponFlows.append(cpn) couponTimes = np.array(couponTimes) couponFlows = np.array(couponFlows) strikePrice = 105.0 face = 100.0 tmat = (maturityDate - settlementDate) / gDaysInYear texp = (expiryDate - settlementDate) / gDaysInYear times = np.linspace(0, tmat, 11) dates = settlementDate.addYears(times) dfs = np.exp(-0.05 * times) testCases.header("LABEL", "VALUES") testCases.print("TIMES:", times) curve = FinDiscountCurve(settlementDate, dates, dfs) price = bond.cleanPriceFromDiscountCurve(settlementDate, curve) testCases.print("Fixed Income Price:", price) sigma = 0.20 # Test convergence numStepsList = [5] #[100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] exerciseType = FinExerciseTypes.AMERICAN testCases.header("Values") treeVector = [] for numTimeSteps in numStepsList: model = FinModelRatesBDT(sigma, numTimeSteps) model.buildTree(tmat, times, dfs) v = model.bondOption(texp, strikePrice, face, couponTimes, couponFlows, exerciseType) testCases.print(v) treeVector.append(v['call']) if PLOT_GRAPHS: plt.plot(numStepsList, treeVector) # The value in Hull converges to 0.699 with 100 time steps while I get 0.70 if 1 == 0: print("RT") printTree(model._rt, 5) print("Q") printTree(model._Q, 5)
treeVector = [] for numTimeSteps in numStepsList: start = time.time() model = FinModelRatesBlackKarasinski(a, sigma) model.buildTree(tmat, int(numTimeSteps), times, dfs) v = model.bondOption(texp, strikePrice, face, couponTimes, couponFlows, isAmerican) end = time.time() period = end - start treeVector.append(v[0]) print(numTimeSteps, v, period) # plt.plot(numStepsList, treeVector) # The value in Hill converges to 0.699 with 100 time steps while I get 0.700 if 1 == 0: print("RT") printTree(model._rt, 5) print("BOND") printTree(model._bondValues, 5) print("OPTION") printTree(model._optionValues, 5) ############################################################################### # This has broken and needs to be repaired!!!! #test_BlackKarasinskiExampleOne() test_BlackKarasinskiExampleTwo()
def test_HullWhiteBondOption(): # Valuation of a European option on a coupon bearing bond settlementDate = FinDate(1, 12, 2019) issueDate = FinDate(1, 12, 2018) expiryDate = settlementDate.addTenor("18m") maturityDate = settlementDate.addTenor("10Y") coupon = 0.05 frequencyType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType) couponTimes = [] couponFlows = [] cpn = bond._coupon / bond._frequency numFlows = len(bond._flowDates) for i in range(1, numFlows): pcd = bond._flowDates[i - 1] ncd = bond._flowDates[i] if ncd > settlementDate: if len(couponTimes) == 0: flowTime = (pcd - settlementDate) / gDaysInYear couponTimes.append(flowTime) couponFlows.append(cpn) flowTime = (ncd - settlementDate) / gDaysInYear couponTimes.append(flowTime) couponFlows.append(cpn) couponTimes = np.array(couponTimes) couponFlows = np.array(couponFlows) strikePrice = 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 = FinModelRatesHW(sigma, a, None) # Test convergence numStepsList = range(20, 500, 10) texp = (expiryDate - settlementDate) / gDaysInYear vJam = model.europeanBondOptionJamshidian(texp, strikePrice, face, couponTimes, couponFlows, 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", "EXPIRY_ONLY", "EXPIRY_TREE", "JAMSHIDIAN", "TIME") for numTimeSteps in numStepsList: start = time.time() model = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_ONLY) model.buildTree(texp, times, dfs) exerciseType = FinOptionExerciseTypes.EUROPEAN v1 = model.bondOption(texp, strikePrice, face, couponTimes, couponFlows, exerciseType) model = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_TREE) model.buildTree(texp, times, dfs) v2 = model.bondOption(texp, strikePrice, face, couponTimes, couponFlows, exerciseType) end = time.time() period = end - start testCases.print(numTimeSteps, v1, v2, vJam, period) # plt.plot(numStepsList, treeVector) if 1 == 0: print("RT") printTree(model._rt, 5) print("BOND") printTree(model._bondValues, 5) print("OPTION") printTree(model._optionValues, 5)
def test_HullWhiteBondOption(): # Valuation of a European option on a coupon bearing bond settlementDate = FinDate(1, 12, 2019) expiryDate = settlementDate.addTenor("18m") maturityDate = settlementDate.addTenor("10Y") coupon = 0.05 frequencyType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(maturityDate, coupon, frequencyType, accrualType) bond.calculateFlowDates(settlementDate) couponTimes = [] couponFlows = [] cpn = bond._coupon / bond._frequency for flowDate in bond._flowDates[1:]: flowTime = (flowDate - settlementDate) / gDaysInYear couponTimes.append(flowTime) couponFlows.append(cpn) couponTimes = np.array(couponTimes) couponFlows = np.array(couponFlows) strikePrice = 105.0 face = 100.0 tmat = (maturityDate - settlementDate) / gDaysInYear times = np.linspace(0, tmat, 20) dfs = np.exp(-0.05 * times) curve = FinDiscountCurve(settlementDate, times, dfs) price = bond.fullPriceFromDiscountCurve(settlementDate, curve) print("Spot Bond Price:", price) price = bond.fullPriceFromDiscountCurve(expiryDate, curve) print("Fwd Bond Price:", price) sigma = 0.01 a = 0.1 # Test convergence numStepsList = [100, 200, 300, 400, 500] texp = (expiryDate - settlementDate) / gDaysInYear print("NUMSTEPS", "FAST TREE", "FULLTREE", "TIME") for numTimeSteps in numStepsList: start = time.time() model = FinModelRatesHullWhite(a, sigma) model.buildTree(texp, numTimeSteps, times, dfs) americanExercise = False v1 = model.americanBondOption_Tree(texp, strikePrice, face, couponTimes, couponFlows, americanExercise) v2 = model.europeanBondOption_Tree(texp, strikePrice, face, couponTimes, couponFlows) end = time.time() period = end - start print(numTimeSteps, v1, v2, period) # plt.plot(numStepsList, treeVector) if 1 == 0: print("RT") printTree(model._rt, 5) print("BOND") printTree(model._bondValues, 5) print("OPTION") printTree(model._optionValues, 5) v = model.europeanBondOption_Jamshidian(texp, strikePrice, face, couponTimes, couponFlows, times, dfs) print("EUROPEAN BOND JAMSHIDIAN DECOMP", v)
def test_HullWhiteCallableBond(): # Valuation of a European option on a coupon bearing bond settlementDate = FinDate(1, 12, 2019) maturityDate = settlementDate.addTenor("10Y") coupon = 0.05 frequencyType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(maturityDate, coupon, frequencyType, accrualType) bond.calculateFlowDates(settlementDate) couponTimes = [] couponFlows = [] cpn = bond._coupon / bond._frequency for flowDate in bond._flowDates[1:]: flowTime = (flowDate - settlementDate) / gDaysInYear couponTimes.append(flowTime) couponFlows.append(cpn) couponTimes = np.array(couponTimes) couponFlows = np.array(couponFlows) ########################################################################### # Set up the call and put times and prices ########################################################################### callDates = [] callPrices = [] callPx = 120.0 callDates.append(settlementDate.addTenor("5Y")) callPrices.append(callPx) callDates.append(settlementDate.addTenor("6Y")) callPrices.append(callPx) callDates.append(settlementDate.addTenor("7Y")) callPrices.append(callPx) callDates.append(settlementDate.addTenor("8Y")) callPrices.append(callPx) callTimes = [] for dt in callDates: t = (dt - settlementDate) / gDaysInYear callTimes.append(t) putDates = [] putPrices = [] putPx = 98.0 putDates.append(settlementDate.addTenor("5Y")) putPrices.append(putPx) putDates.append(settlementDate.addTenor("6Y")) putPrices.append(putPx) putDates.append(settlementDate.addTenor("7Y")) putPrices.append(putPx) putDates.append(settlementDate.addTenor("8Y")) putPrices.append(putPx) putTimes = [] for dt in putDates: t = (dt - settlementDate) / gDaysInYear putTimes.append(t) ########################################################################### tmat = (maturityDate - settlementDate) / gDaysInYear times = np.linspace(0, tmat, 20) dfs = np.exp(-0.05 * times) curve = FinDiscountCurve(settlementDate, times, dfs) ########################################################################### v1 = bond.fullPriceFromDiscountCurve(settlementDate, curve) sigma = 0.02 # basis point volatility a = 0.1 # Test convergence numStepsList = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] tmat = (maturityDate - settlementDate) / gDaysInYear print("NUMSTEPS", "BOND_ONLY", "CALLABLE_BOND", "TIME") for numTimeSteps in numStepsList: start = time.time() model = FinModelRatesHullWhite(a, sigma) model.buildTree(tmat, numTimeSteps, times, dfs) v2 = model.callablePuttableBond_Tree(couponTimes, couponFlows, callTimes, callPrices, putTimes, putPrices) end = time.time() period = end - start print(numTimeSteps, v1, v2, period) if 1 == 0: print("RT") printTree(model._rt, 5) print("BOND") printTree(model._bondValues, 5) print("OPTION") printTree(model._optionValues, 5)