def test_FinBondPortfolio(): import pandas as pd path = os.path.join(os.path.dirname(__file__), './data/giltBondPrices.txt') bondDataFrame = pd.read_csv(path, sep='\t') bondDataFrame['mid'] = 0.5*(bondDataFrame['bid'] + bondDataFrame['ask']) freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA settlement = FinDate(2012, 9, 19) testCases.header("DCTYPE", "MATDATE", "CPN", "PRICE", "ACCD", "YTM") for accrualType in FinDayCountTypes: for _, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = fromDatetime(matDatetime) issueDt = FinDate(maturityDt._d, maturityDt._m, 2000) coupon = bond['coupon']/100.0 cleanPrice = bond['mid'] bond = FinBond(issueDt, maturityDt, coupon, freqType, accrualType) ytm = bond.yieldToMaturity(settlement, cleanPrice) accd = bond._accruedInterest testCases.print(accrualType, maturityDt, coupon*100.0, cleanPrice, accd, ytm*100.0)
def test_FinBondOptionAmericanConvergenceONE(): # Build discount curve settlementDate = FinDate(1, 12, 2019) discountCurve = FinDiscountCurveFlat(settlementDate, 0.05) # Bond details maturityDate = FinDate(1, 9, 2025) issueDate = FinDate(1, 9, 2016) coupon = 0.05 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) # Option Details expiryDate = FinDate(1, 12, 2020) strikePrice = 100.0 face = 100.0 testCases.header("TIME", "N", "PUT_AMER", "PUT_EUR", "CALL_AME", "CALL_EUR") timeSteps = range(30, 100, 10) for numTimeSteps in timeSteps: sigma = 0.20 a = 0.1 start = time.time() optionType = FinOptionTypes.AMERICAN_PUT bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model1 = FinModelRatesBK(sigma, a, numTimeSteps) v1put = bondOption1.value(settlementDate, discountCurve, model1) optionType = FinOptionTypes.EUROPEAN_PUT bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model2 = FinModelRatesBK(sigma, a, numTimeSteps) v2put = bondOption2.value(settlementDate, discountCurve, model2) optionType = FinOptionTypes.AMERICAN_CALL bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model1 = FinModelRatesBK(sigma, a, numTimeSteps) v1call = bondOption1.value(settlementDate, discountCurve, model1) optionType = FinOptionTypes.EUROPEAN_CALL bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model2 = FinModelRatesBK(sigma, a, numTimeSteps) v2call = bondOption2.value(settlementDate, discountCurve, model2) end = time.time() period = end - start testCases.print(period, numTimeSteps, v1put, v2put, v1call, v2call)
def test_BlackKarasinskiExampleTwo(): # 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 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: 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, 20) dfs = np.exp(-0.05 * times) curve = FinDiscountCurve(settlementDate, times, dfs) price = bond.fullPriceFromDiscountCurve(settlementDate, curve) print("Fixed Income Price:", price) sigma = 0.20 a = 0.05 # Test convergence numStepsList = [100] #,101,200,300,400,500,600,700,800,900,1000] isAmerican = True 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)
def test_FinBondExDividend(): issueDate = FinDate(7, 9, 2000) maturityDate = FinDate(7, 9, 2020) coupon = 0.05 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA face = 100.0 exDivDays = 7 testCases.header("LABEL", "VALUE") calendarType = FinCalendarTypes.UNITED_KINGDOM bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType, face) settlementDate = FinDate(7, 9, 2003) accrued = bond.calcAccruedInterest(settlementDate, exDivDays, calendarType) testCases.print("SettlementDate:", settlementDate) testCases.print("Accrued:", accrued) ########################################################################### testCases.banner("=======================================================") testCases.header("SETTLEMENT", "ACCRUED") issueDate = FinDate(7, 9, 2000) maturityDate = FinDate(7, 9, 2020) coupon = 0.05 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA face = 100.0 exDivDays = 7 calendarType = FinCalendarTypes.UNITED_KINGDOM bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType, face) settlementDate = FinDate(25, 8, 2010) for _ in range(0, 13): settlementDate = settlementDate.addDays(1) accrued = bond.calcAccruedInterest(settlementDate, exDivDays, calendarType) testCases.print(settlementDate, accrued)
def test_FinBondOption(): 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) tmat = (maturityDate - settlementDate) / gDaysInYear times = np.linspace(0, tmat, 20) dfs = np.exp(-0.05 * times) discountCurve = FinDiscountCurve(settlementDate, times, dfs) expiryDate = settlementDate.addTenor("18m") strikePrice = 105.0 face = 100.0 optionType = FinBondOptionTypes.AMERICAN_CALL price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve) print("Fixed Income Price:", price) for strikePrice in [90, 95, 100, 105, 110]: sigma = 0.01 a = 0.1 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesHullWhite(a, sigma) v = bondOption.value(settlementDate, discountCurve, model) print("HW", strikePrice, v) for strikePrice in [90, 95, 100, 105, 110]: sigma = 0.20 a = 0.05 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBlackKarasinski(a, sigma) v = bondOption.value(settlementDate, discountCurve, model) print("BK", strikePrice, v)
def test_FinBondZeroCurve(): import pandas as pd path = os.path.join(os.path.dirname(__file__), './data/giltBondPrices.txt') bondDataFrame = pd.read_csv(path, sep='\t') bondDataFrame['mid'] = 0.5 * (bondDataFrame['bid'] + bondDataFrame['ask']) freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA settlement = FinDate(19, 9, 2012) bonds = [] cleanPrices = [] for _, bondRow in bondDataFrame.iterrows(): dateString = bondRow['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = fromDatetime(matDatetime) issueDt = FinDate(maturityDt._d, maturityDt._m, 2000) coupon = bondRow['coupon'] / 100.0 cleanPrice = bondRow['mid'] bond = FinBond(issueDt, maturityDt, coupon, freqType, accrualType) bonds.append(bond) cleanPrices.append(cleanPrice) ############################################################################### bondCurve = FinBondZeroCurve(settlement, bonds, cleanPrices) testCases.header("DATE", "ZERO RATE") for _, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = fromDatetime(matDatetime) zeroRate = bondCurve.zeroRate(maturityDt) testCases.print(maturityDt, zeroRate) if plotGraphs: bondCurve.plot("BOND CURVE")
def test_FinBondZeroCurve(): import pandas as pd bondDataFrame = pd.read_csv('./data/giltbondprices.txt', sep='\t') bondDataFrame['mid'] = 0.5*(bondDataFrame['bid'] + bondDataFrame['ask']) frequencyType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA settlement = FinDate(2012, 9, 19) bonds = [] cleanPrices = [] for index, bondRow in bondDataFrame.iterrows(): dateString = bondRow['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = FinDate.fromDatetime(matDatetime) coupon = bondRow['coupon']/100.0 cleanPrice = bondRow['mid'] bond = FinBond(maturityDt, coupon, frequencyType, accrualType) bonds.append(bond) cleanPrices.append(cleanPrice) ############################################################################### bondCurve = FinBondZeroCurve(settlement, bonds, cleanPrices) testCases.header("DATE", "ZERO RATE") for index, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = FinDate.fromDatetime(matDatetime) zeroRate = bondCurve.zeroRate(maturityDt) testCases.print(maturityDt, zeroRate) bondCurve.plot("BOND CURVE")
def test_FinBondFuture(): # Example taken from Martellini and Priaulet page 360 freq = FinFrequencyTypes.SEMI_ANNUAL basis = FinDayCountTypes.ACT_ACT_ICMA issueDate = FinDate(15, 2, 2004) bond1 = FinBond(issueDate, FinDate(2011, 8, 15), 0.0500, freq, basis) bond2 = FinBond(issueDate, FinDate(2011, 2, 15), 0.0500, freq, basis) bond3 = FinBond(issueDate, FinDate(2010, 8, 15), 0.0575, freq, basis) bond4 = FinBond(issueDate, FinDate(2010, 2, 15), 0.0650, freq, basis) bond5 = FinBond(issueDate, FinDate(2009, 8, 15), 0.0600, freq, basis) bond6 = FinBond(issueDate, FinDate(2009, 5, 15), 0.0550, freq, basis) bond7 = FinBond(issueDate, FinDate(2008, 11, 15), 0.0475, freq, basis) bonds = [] bonds.append(bond1) bonds.append(bond2) bonds.append(bond3) bonds.append(bond4) bonds.append(bond5) bonds.append(bond6) bonds.append(bond7) firstDeliveryDate = FinDate(2002, 3, 1) lastDeliveryDate = FinDate(2002, 3, 28) contractSize = 100000 contractCoupon = 0.06 bondFutureContract = FinBondFuture("TYH2", firstDeliveryDate, lastDeliveryDate, contractSize, contractCoupon) settlementDate = FinDate(2001, 12, 10) # Get the Conversion Factors testCases.header("Bond Maturity", "Coupon", "Conversion Factor") for bond in bonds: cf = bondFutureContract.conversionFactor(bond) testCases.print(bond._maturityDate, bond._coupon * 100, cf) # Example from # https://www.cmegroup.com/education/files/understanding-treasury-futures.pdf testCases.banner("EXAMPLE FROM CME") testCases.banner("================") settlementDate = FinDate(2017, 10, 10) bonds = [] prices = [] bond = FinBond(issueDate, FinDate(2027, 8, 15), 0.0225, freq, basis) bonds.append(bond) prices.append(99 + 1 / 32) bond = FinBond(issueDate, FinDate(2027, 5, 15), 0.02375, freq, basis) bonds.append(bond) prices.append(100 + 5 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2027, 2, 15), 0.0225, freq, basis) bonds.append(bond) prices.append(99 + 5 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2026, 11, 15), 0.02, freq, basis) bonds.append(bond) prices.append(97 + 7 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2026, 8, 15), 0.015, freq, basis) bonds.append(bond) prices.append(93 + 14 / 32) bond = FinBond(issueDate, FinDate(2026, 5, 15), 0.01625, freq, basis) bonds.append(bond) prices.append(94 + 21 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2026, 2, 15), 0.01625, freq, basis) bonds.append(bond) prices.append(94 + 29 / 32) bond = FinBond(issueDate, FinDate(2025, 11, 15), 0.0225, freq, basis) bonds.append(bond) prices.append(99 + 25 / 32) bond = FinBond(issueDate, FinDate(2025, 8, 15), 0.02, freq, basis) bonds.append(bond) prices.append(98 + 3 / 32) bond = FinBond(issueDate, FinDate(2025, 5, 15), 0.02125, freq, basis) bonds.append(bond) prices.append(99 + 5 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2025, 2, 15), 0.02, freq, basis) bonds.append(bond) prices.append(98 + 14 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2024, 11, 15), 0.0225, freq, basis) bonds.append(bond) prices.append(100 + 9 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2024, 8, 15), 0.02375, freq, basis) bonds.append(bond) prices.append(101 + 7 / 32 + 1 / 64) bond = FinBond(issueDate, FinDate(2024, 8, 15), 0.01875, freq, basis) bonds.append(bond) # There may be an error in the document says 98-01+ prices.append(98 + 1 / 32) testCases.header("BOND MATURITY", "YIELD") for bond, cleanPrice in zip(bonds, prices): yld = bond.yieldToMaturity(settlementDate, cleanPrice) testCases.print(str(bond._maturityDate), yld) firstDeliveryDate = FinDate(2017, 12, 1) lastDeliveryDate = FinDate(2017, 12, 28) contractSize = 100000 contractCoupon = 0.06 bondFutureContract = FinBondFuture("TYZ7", firstDeliveryDate, lastDeliveryDate, contractSize, contractCoupon) testCases.header("BOND MATURITY", "CF") for bond in bonds: cf = bondFutureContract.conversionFactor(bond) testCases.print(str(bond._maturityDate), cf) # Get the Invoice Prices futuresPrice = 125.265625 testCases.header("BOND MATURITY", "PRINCIPAL INVOICE PRICE") for bond in bonds: pip = bondFutureContract.principalInvoicePrice(bond, futuresPrice) testCases.print(str(bond._maturityDate), pip) testCases.header("BOND MATURITY", "TOTAL INVOICE AMOUNT") for bond in bonds: tia = bondFutureContract.totalInvoiceAmount(settlementDate, bond, futuresPrice) testCases.print(str(bond._maturityDate), tia) ctd = bondFutureContract.cheapestToDeliver(bonds, prices, futuresPrice) testCases.header("CTD MATURITY", "CTD COUPON") testCases.print(str(ctd._maturityDate), ctd._coupon)
def test_FinBondOptionZEROVOLConvergence(): # Build discount curve settlementDate = FinDate(1, 12, 2019) # CHANGED rate = 0.05 discountCurve = FinDiscountCurveFlat(settlementDate, rate, FinFrequencyTypes.ANNUAL) # Bond details issueDate = FinDate(1, 9, 2015) maturityDate = FinDate(1, 9, 2025) coupon = 0.06 freqType = FinFrequencyTypes.ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) # Option Details expiryDate = settlementDate.addTenor("18m") # FinDate(1, 12, 2021) # print("EXPIRY:", expiryDate) face = 100.0 dfExpiry = discountCurve.df(expiryDate) spotCleanValue = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) fwdCleanValue = bond.cleanPriceFromDiscountCurve(expiryDate, discountCurve) # print("BOND SpotCleanBondPx", spotCleanValue) # print("BOND FwdCleanBondPx", fwdCleanValue) # print("BOND Accrued:", bond._accruedInterest) spotCleanValue = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) 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, 200) 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 numSteps in numTimeSteps: sigma = 0.0000001 model = FinModelRatesBDT(sigma, numSteps) optionType = FinOptionTypes.EUROPEAN_CALL bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) v1 = bondOption1.value(settlementDate, discountCurve, model) optionType = FinOptionTypes.AMERICAN_CALL bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) v2 = bondOption2.value(settlementDate, discountCurve, model) optionType = FinOptionTypes.EUROPEAN_PUT bondOption3 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) v3 = bondOption3.value(settlementDate, discountCurve, model) optionType = FinOptionTypes.AMERICAN_PUT bondOption4 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) v4 = bondOption4.value(settlementDate, discountCurve, model) testCases.print(strikePrice, numSteps, callIntrinsic, callIntrinsicPV, v1, v2, putIntrinsic, putIntrinsicPV, v3, v4)
def test_FinBondYieldCurve(): ########################################################################### import pandas as pd path = os.path.join(os.path.dirname(__file__), './data/giltBondPrices.txt') bondDataFrame = pd.read_csv(path, sep='\t') bondDataFrame['mid'] = 0.5 * (bondDataFrame['bid'] + bondDataFrame['ask']) freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA settlement = FinDate(19, 9, 2012) bonds = [] ylds = [] for _, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = fromDatetime(matDatetime) issueDt = FinDate(maturityDt._d, maturityDt._m, 2000) coupon = bond['coupon'] / 100.0 cleanPrice = bond['mid'] bond = FinBond(issueDt, maturityDt, coupon, freqType, accrualType) yld = bond.yieldToMaturity(settlement, cleanPrice) bonds.append(bond) ylds.append(yld) ############################################################################### curveFitMethod = FinCurveFitPolynomial() fittedCurve1 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod) # fittedCurve1.display("GBP Yield Curve") curveFitMethod = FinCurveFitPolynomial(5) fittedCurve2 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod) # fittedCurve2.display("GBP Yield Curve") curveFitMethod = FinCurveFitNelsonSiegel() fittedCurve3 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod) # fittedCurve3.display("GBP Yield Curve") curveFitMethod = FinCurveFitNelsonSiegelSvensson() fittedCurve4 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod) # fittedCurve4.display("GBP Yield Curve") curveFitMethod = FinCurveFitBSpline() fittedCurve5 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod) # fittedCurve5.display("GBP Yield Curve") ############################################################################### testCases.header("PARAMETER", "VALUE") testCases.print("beta1", fittedCurve3._curveFit._beta1) testCases.print("beta2", fittedCurve3._curveFit._beta2) testCases.print("beta3", fittedCurve3._curveFit._beta3) testCases.print("tau", fittedCurve3._curveFit._tau) testCases.header("PARAMETER", "VALUE") testCases.print("beta1", fittedCurve4._curveFit._beta1) testCases.print("beta2", fittedCurve4._curveFit._beta2) testCases.print("beta3", fittedCurve4._curveFit._beta3) testCases.print("beta4", fittedCurve4._curveFit._beta4) testCases.print("tau1", fittedCurve4._curveFit._tau1) testCases.print("tau2", fittedCurve4._curveFit._tau2) ############################################################################### maturityDate = FinDate(19, 9, 2030) interpolatedYield = fittedCurve5.interpolatedYield(maturityDate) testCases.print(maturityDate, interpolatedYield)
def test_FinBondOptionAmericanConvergenceTWO(): # Build discount curve settlementDate = FinDate(1, 12, 2019) discountCurve = FinDiscountCurveFlat(settlementDate, 0.05, FinFrequencyTypes.CONTINUOUS) # Bond details issueDate = FinDate(1, 9, 2014) maturityDate = FinDate(1, 9, 2025) coupon = 0.05 freqType = FinFrequencyTypes.ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) expiryDate = settlementDate.addTenor("18m") face = 100.0 spotValue = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve) testCases.header("LABEL", "VALUE") testCases.print("BOND PRICE", spotValue) testCases.header("TIME", "N", "EUR_CALL", "AMER_CALL", "EUR_PUT", "AMER_PUT") sigma = 0.2 model = FinModelRatesBDT(sigma) K = 101.0 vec_ec = [] vec_ac = [] vec_ep = [] vec_ap = [] if 1 == 1: K = 100.0 bkModel = FinModelRatesBDT(sigma, 100) europeanCallBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.EUROPEAN_CALL) v_ec = europeanCallBondOption.value(settlementDate, discountCurve, model) testCases.header("LABEL", "VALUE") testCases.print("OPTION", v_ec) numStepsVector = range(100, 100, 1) # should be 100-400 for numSteps in numStepsVector: bkModel = FinModelRatesBDT(sigma, numSteps) start = time.time() europeanCallBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.EUROPEAN_CALL) v_ec = europeanCallBondOption.value(settlementDate, discountCurve, bkModel) americanCallBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.AMERICAN_CALL) v_ac = americanCallBondOption.value(settlementDate, discountCurve, bkModel) europeanPutBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.EUROPEAN_PUT) v_ep = europeanPutBondOption.value(settlementDate, discountCurve, bkModel) americanPutBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.AMERICAN_PUT) v_ap = americanPutBondOption.value(settlementDate, discountCurve, bkModel) end = time.time() period = end - start testCases.print(period, numSteps, v_ec, v_ac, v_ep, v_ap) vec_ec.append(v_ec) vec_ac.append(v_ac) vec_ep.append(v_ep) vec_ap.append(v_ap) if plotGraphs: plt.figure() plt.plot(numStepsVector, vec_ec, label="European Call") plt.legend() plt.figure() plt.plot(numStepsVector, vec_ac, label="American Call") plt.legend() plt.figure() plt.plot(numStepsVector, vec_ep, label="European Put") plt.legend() plt.figure() plt.plot(numStepsVector, vec_ap, label="American Put") plt.legend()
def test_FinBondOption(): settlementDate = FinDate(1, 12, 2019) issueDate = FinDate(1, 12, 2018) maturityDate = settlementDate.addTenor("10Y") coupon = 0.05 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) tmat = (maturityDate - settlementDate) / gDaysInYear times = np.linspace(0, tmat, 20) dates = settlementDate.addYears(times) dfs = np.exp(-0.05 * times) discountCurve = FinDiscountCurve(settlementDate, dates, dfs) expiryDate = settlementDate.addTenor("18m") strikePrice = 105.0 face = 100.0 ########################################################################### strikes = [80, 90, 100, 110, 120] optionType = FinOptionTypes.EUROPEAN_CALL testCases.header("LABEL", "VALUE") price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve) testCases.print("Fixed Income Price:", price) numTimeSteps = 100 testCases.header("OPTION TYPE AND MODEL", "STRIKE", "VALUE") for strikePrice in strikes: sigma = 0.20 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("EUROPEAN CALL - BK", strikePrice, v) for strikePrice in strikes: sigma = 0.20 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("EUROPEAN CALL - BK", strikePrice, v) ########################################################################### optionType = FinOptionTypes.AMERICAN_CALL price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve) testCases.header("LABEL", "VALUE") testCases.print("Fixed Income Price:", price) testCases.header("OPTION TYPE AND MODEL", "STRIKE", "VALUE") for strikePrice in strikes: sigma = 0.20 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("AMERICAN CALL - BK", strikePrice, v) for strikePrice in strikes: sigma = 0.20 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("AMERICAN CALL - BK", strikePrice, v) ########################################################################### optionType = FinOptionTypes.EUROPEAN_PUT price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve) for strikePrice in strikes: sigma = 0.01 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("EUROPEAN PUT - BK", strikePrice, v) for strikePrice in strikes: sigma = 0.20 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("EUROPEAN PUT - BK", strikePrice, v) ########################################################################### optionType = FinOptionTypes.AMERICAN_PUT price = bond.fullPriceFromDiscountCurve(settlementDate, discountCurve) for strikePrice in strikes: sigma = 0.02 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("AMERICAN PUT - BK", strikePrice, v) for strikePrice in strikes: sigma = 0.20 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesBDT(sigma, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print("AMERICAN PUT - BK", strikePrice, v)
def test_HullWhiteCallableBond(): # Valuation of a European option on a coupon bearing bond settlementDate = FinDate(1, 12, 2019) issueDate = FinDate(1, 12, 2018) 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 for flowDate in bond._flowDates[1:]: if flowDate > settlementDate: 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("2Y")) callPrices.append(callPx) callDates.append(settlementDate.addTenor("3Y")) callPrices.append(callPx) callDates.append(settlementDate.addTenor("4Y")) callPrices.append(callPx) 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("2Y")) putPrices.append(putPx) putDates.append(settlementDate.addTenor("3Y")) putPrices.append(putPx) putDates.append(settlementDate.addTenor("4Y")) putPrices.append(putPx) 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 curve = FinDiscountCurveFlat(settlementDate, 0.05, FinFrequencyTypes.CONTINUOUS) dfs = [] times = [] for dt in bond._flowDates: if dt > settlementDate: t = (dt - settlementDate) / gDaysInYear df = curve.df(dt) times.append(t) dfs.append(df) dfs = np.array(dfs) times = np.array(times) ########################################################################### v1 = bond.cleanPriceFromDiscountCurve(settlementDate, curve) sigma = 0.02 # basis point volatility a = 0.01 # Test convergence numStepsList = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] tmat = (maturityDate - settlementDate) / gDaysInYear testCases.header("NUMSTEPS", "BOND_ONLY", "CALLABLE_BOND", "TIME") for numTimeSteps in numStepsList: start = time.time() model = FinModelRatesHW(sigma, a, numTimeSteps) model.buildTree(tmat, times, dfs) v2 = model.callablePuttableBond_Tree(couponTimes, couponFlows, callTimes, callPrices, putTimes, putPrices, 100.0) end = time.time() period = end - start testCases.print(numTimeSteps, v1, v2, period)
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)
def test_FinBondOptionEuropeanConvergence(): # CONVERGENCE TESTS # COMPARE AMERICAN TREE VERSUS JAMSHIDIAN IN EUROPEAN LIMIT TO CHECK THAT # TREE HAS BEEN CORRECTLY CONSTRUCTED. FIND VERY GOOD AGREEMENT. # Build discount curve settlementDate = FinDate(1, 12, 2019) discountCurve = FinDiscountCurveFlat(settlementDate, 0.05, FinFrequencyTypes.CONTINUOUS) # Bond details issueDate = FinDate(1, 12, 2015) maturityDate = FinDate(1, 12, 2020) coupon = 0.05 freqType = FinFrequencyTypes.ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) # Option Details - put expiry in the middle of a coupon period expiryDate = FinDate(1, 3, 2020) strikePrice = 100.0 face = 100.0 timeSteps = range(100, 400, 100) strikePrice = 100.0 testCases.header("TIME", "N", "PUT_JAM", "PUT_TREE", "CALL_JAM", "CALL_TREE") for numTimeSteps in timeSteps: sigma = 0.05 a = 0.1 start = time.time() optionType = FinOptionTypes.EUROPEAN_PUT bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model1 = FinModelRatesHW(sigma, a, numTimeSteps) v1put = bondOption1.value(settlementDate, discountCurve, model1) bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model2 = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_ONLY) v2put = bondOption2.value(settlementDate, discountCurve, model2) optionType = FinOptionTypes.EUROPEAN_CALL bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model1 = FinModelRatesHW(sigma, a, numTimeSteps) v1call = bondOption1.value(settlementDate, discountCurve, model1) bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model2 = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_TREE) v2call = bondOption2.value(settlementDate, discountCurve, model2) end = time.time() period = end - start testCases.print(period, numTimeSteps, v1put, v2put, v1call, v2call)
def test_FinBondOption(): settlementDate = FinDate(1, 12, 2019) issueDate = FinDate(1, 12, 2018) maturityDate = settlementDate.addTenor("10Y") coupon = 0.05 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) times = np.linspace(0, 10.0, 21) dfs = np.exp(-0.05 * times) dates = settlementDate.addYears(times) discountCurve = FinDiscountCurve(settlementDate, dates, dfs) expiryDate = settlementDate.addTenor("18m") strikePrice = 105.0 face = 100.0 ########################################################################### strikes = [80, 85, 90, 95, 100, 105, 110, 115, 120] optionType = FinOptionTypes.EUROPEAN_CALL testCases.header("LABEL", "VALUE") price = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) testCases.print("Fixed Income Price:", price) numTimeSteps = 100 testCases.banner("HW EUROPEAN CALL") testCases.header("STRIKE", "VALUE") for strikePrice in strikes: sigma = 0.01 a = 0.1 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesHW(sigma, a, numTimeSteps) v = bondOption.value(settlementDate, discountCurve, model) testCases.print(strikePrice, v) ########################################################################### optionType = FinOptionTypes.AMERICAN_CALL price = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) testCases.header("LABEL", "VALUE") testCases.print("Fixed Income Price:", price) testCases.banner("HW AMERICAN CALL") testCases.header("STRIKE", "VALUE") for strikePrice in strikes: sigma = 0.01 a = 0.1 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesHW(sigma, a) v = bondOption.value(settlementDate, discountCurve, model) testCases.print(strikePrice, v) ########################################################################### optionType = FinOptionTypes.EUROPEAN_PUT testCases.banner("HW EUROPEAN PUT") testCases.header("STRIKE", "VALUE") price = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) for strikePrice in strikes: sigma = 0.01 a = 0.1 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesHW(sigma, a) v = bondOption.value(settlementDate, discountCurve, model) testCases.print(strikePrice, v) ########################################################################### optionType = FinOptionTypes.AMERICAN_PUT testCases.banner("HW AMERICAN PUT") testCases.header("STRIKE", "VALUE") price = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) for strikePrice in strikes: sigma = 0.02 a = 0.1 bondOption = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model = FinModelRatesHW(sigma, a) v = bondOption.value(settlementDate, discountCurve, model) testCases.print(strikePrice, v)
def test_FinBondEmbeddedOptionQUANTLIB(): # Based on example at the nice blog on Quantlib at # http://gouthamanbalaraman.com/blog/callable-bond-quantlib-python.html # I get a price of 68.97 for 1000 time steps which is higher than the # 68.38 found in blog article. But this is for 40 grid points. # Note also that a basis point vol of 0.120 is 12% which is VERY HIGH! valuationDate = FinDate(16, 8, 2016) settlementDate = valuationDate.addWeekDays(3) ########################################################################### discountCurve = FinDiscountCurveFlat(valuationDate, 0.035, FinFrequencyTypes.SEMI_ANNUAL) ########################################################################### issueDate = FinDate(15, 9, 2010) maturityDate = FinDate(15, 9, 2022) coupon = 0.025 freqType = FinFrequencyTypes.QUARTERLY accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) ########################################################################### # Set up the call and put times and prices ########################################################################### nextCallDate = FinDate(15, 9, 2016) callDates = [nextCallDate] callPrices = [100.0] for i in range(1, 24): nextCallDate = nextCallDate.addMonths(3) callDates.append(nextCallDate) callPrices.append(100.0) putDates = [] putPrices = [] # the value used in blog of 12% bp vol is unrealistic sigma = 0.12 # basis point volatility a = 0.03 puttableBond = FinBondEmbeddedOption(issueDate, maturityDate, coupon, freqType, accrualType, callDates, callPrices, putDates, putPrices) testCases.header("BOND PRICE", "PRICE") v = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) testCases.print("Bond Pure Price:", v) testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure") timeSteps = range(100, 1000, 100) values = [] for numTimeSteps in timeSteps: model = FinModelRatesHW(sigma, a, numTimeSteps) start = time.time() v = puttableBond.value(settlementDate, discountCurve, model) end = time.time() period = end - start testCases.print(period, numTimeSteps, v['bondwithoption'], v['bondpure']) values.append(v['bondwithoption']) if plotGraphs: plt.figure() plt.title("Puttable Bond Price Convergence") plt.plot(timeSteps, values)
accrualType = FinDayCountTypes.ACT_ACT_ICMA settlement = FinDate(2012, 9, 19) bonds = [] ylds = [] # LOAD BONDS AND CREATE A VECTOR OF FINBOND AND THEIR CORRESPONDING YIELDS for index, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = FinDate.fromDatetime(matDatetime) coupon = bond['coupon'] / 100.0 cleanPrice = bond['mid'] bond = FinBond(maturityDt, coupon, frequencyType, accrualType) yld = bond.yieldToMaturity(settlement, cleanPrice) bonds.append(bond) ylds.append(yld) # FIT THE BOND YIELDS TO A CUBIC POLYNOMIAL curveFitMethod = FinCurveFitMethodPolynomial() fittedCurve1 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod) fittedCurve1.display("GBP Yield Curve") # FIT THE BOND YIELDS TO A QUINTIC POLYNOMIAL curveFitMethod = FinCurveFitMethodPolynomial(5) fittedCurve2 = FinBondYieldCurve(settlement, bonds, ylds, curveFitMethod) fittedCurve2.display("GBP Yield Curve") # FIT THE BONDS TO A NELSON-SIEGEL CURVE
def test_FinBond(): import pandas as pd path = os.path.join(os.path.dirname(__file__), './data/giltBondPrices.txt') bondDataFrame = pd.read_csv(path, sep='\t') bondDataFrame['mid'] = 0.5 * (bondDataFrame['bid'] + bondDataFrame['ask']) freqType = FinFrequencyTypes.SEMI_ANNUAL settlementDate = FinDate(19, 9, 2012) face = ONE_MILLION for accrualType in FinDayCountTypes: testCases.header("MATURITY", "COUPON", "CLEAN_PRICE", "ACCD_DAYS", "ACCRUED", "YTM") for _, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = fromDatetime(matDatetime) issueDt = FinDate(maturityDt._d, maturityDt._m, 2000) coupon = bond['coupon'] / 100.0 cleanPrice = bond['mid'] bond = FinBond(issueDt, maturityDt, coupon, freqType, accrualType, 100) ytm = bond.yieldToMaturity(settlementDate, cleanPrice) accd = bond._accruedInterest accd_days = bond._accruedDays testCases.print("%18s" % maturityDt, "%8.4f" % coupon, "%10.4f" % cleanPrice, "%6.0f" % accd_days, "%10.4f" % accd, "%8.4f" % ytm) ########################################################################### # EXAMPLE FROM http://bondtutor.com/btchp4/topic6/topic6.htm accrualConvention = FinDayCountTypes.ACT_ACT_ICMA y = 0.062267 settlementDate = FinDate(19, 4, 1994) issueDate = FinDate(15, 7, 1990) maturityDate = FinDate(15, 7, 1997) coupon = 0.085 face = ONE_MILLION freqType = FinFrequencyTypes.SEMI_ANNUAL bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualConvention, face) testCases.header("FIELD", "VALUE") fullPrice = bond.fullPriceFromYTM(settlementDate, y) testCases.print("Full Price = ", fullPrice) cleanPrice = bond.cleanPriceFromYTM(settlementDate, y) testCases.print("Clean Price = ", cleanPrice) accd = bond._accruedInterest testCases.print("Accrued = ", accd) ytm = bond.yieldToMaturity(settlementDate, cleanPrice) testCases.print("Yield to Maturity = ", ytm) bump = 1e-4 priceBumpedUp = bond.fullPriceFromYTM(settlementDate, y + bump) testCases.print("Price Bumped Up:", priceBumpedUp) priceBumpedDn = bond.fullPriceFromYTM(settlementDate, y - bump) testCases.print("Price Bumped Dn:", priceBumpedDn) durationByBump = -(priceBumpedUp - fullPrice) / bump testCases.print("Duration by Bump = ", durationByBump) duration = bond.dollarDuration(settlementDate, y) testCases.print("Dollar Duration = ", duration) testCases.print("Duration Difference:", duration - durationByBump) modifiedDuration = bond.modifiedDuration(settlementDate, y) testCases.print("Modified Duration = ", modifiedDuration) macauleyDuration = bond.macauleyDuration(settlementDate, y) testCases.print("Macauley Duration = ", macauleyDuration) conv = bond.convexityFromYTM(settlementDate, y) testCases.print("Convexity = ", conv) # ASSET SWAP SPREAD # When the libor curve is the flat bond curve then the ASW is zero by # definition flatCurve = FinDiscountCurveFlat(settlementDate, ytm, FinFrequencyTypes.SEMI_ANNUAL) testCases.header("FIELD", "VALUE") cleanPrice = bond.cleanPriceFromYTM(settlementDate, ytm) asw = bond.assetSwapSpread(settlementDate, cleanPrice, flatCurve) testCases.print("Discounted on Bond Curve ASW:", asw * 10000) # When the libor curve is the Libor curve then the ASW is positive liborCurve = buildIborCurve(settlementDate) asw = bond.assetSwapSpread(settlementDate, cleanPrice, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, cleanPrice, liborCurve) testCases.print("Discounted on LIBOR Curve ASW:", asw * 10000) testCases.print("Discounted on LIBOR Curve OAS:", oas * 10000) p = 90.0 asw = bond.assetSwapSpread(settlementDate, p, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve) testCases.print("Deep discount bond at 90 ASW:", asw * 10000) testCases.print("Deep discount bond at 90 OAS:", oas * 10000) p = 100.0 asw = bond.assetSwapSpread(settlementDate, p, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve) testCases.print("Par bond at 100 ASW:", asw * 10000) testCases.print("Par bond at 100 OAS:", oas * 10000) p = 120.0 asw = bond.assetSwapSpread(settlementDate, p, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve) testCases.print("Above par bond at 120 ASW:", asw * 10000) testCases.print("Above par bond at 120 OAS:", oas * 10000) ########################################################################## # https://data.bloomberglp.com/bat/sites/3/2017/07/SF-2017_Paul-Fjeldsted.pdf # Page 10 TREASURY NOTE SCREENSHOT ########################################################################## testCases.banner("BLOOMBERG US TREASURY EXAMPLE") settlementDate = FinDate(21, 7, 2017) issueDate = FinDate(15, 5, 2010) maturityDate = FinDate(15, 5, 2027) coupon = 0.02375 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA face = 100.0 bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType, face) testCases.header("FIELD", "VALUE") cleanPrice = 99.7808417 yld = bond.currentYield(cleanPrice) testCases.print("Current Yield = ", yld) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYTMCalcType.UK_DMO) testCases.print("UK DMO Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYTMCalcType.US_STREET) testCases.print("US STREET Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYTMCalcType.US_TREASURY) testCases.print("US TREASURY Yield To Maturity = ", ytm) fullPrice = bond.fullPriceFromYTM(settlementDate, ytm) testCases.print("Full Price = ", fullPrice) cleanPrice = bond.cleanPriceFromYTM(settlementDate, ytm) testCases.print("Clean Price = ", cleanPrice) accd = bond._accruedInterest testCases.print("Accrued = ", accd) accddays = bond._accruedDays testCases.print("Accrued Days = ", accddays) duration = bond.dollarDuration(settlementDate, ytm) testCases.print("Dollar Duration = ", duration) modifiedDuration = bond.modifiedDuration(settlementDate, ytm) testCases.print("Modified Duration = ", modifiedDuration) macauleyDuration = bond.macauleyDuration(settlementDate, ytm) testCases.print("Macauley Duration = ", macauleyDuration) conv = bond.convexityFromYTM(settlementDate, ytm) testCases.print("Convexity = ", conv) ########################################################################## # Page 11 APPLE NOTE SCREENSHOT ########################################################################## testCases.banner("BLOOMBERG APPLE CORP BOND EXAMPLE") settlementDate = FinDate(21, 7, 2017) issueDate = FinDate(13, 5, 2012) maturityDate = FinDate(13, 5, 2022) coupon = 0.027 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.THIRTY_E_360_ISDA face = 100.0 bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType, face) testCases.header("FIELD", "VALUE") cleanPrice = 101.581564 yld = bond.currentYield(cleanPrice) testCases.print("Current Yield", yld) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYTMCalcType.UK_DMO) testCases.print("UK DMO Yield To Maturity", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYTMCalcType.US_STREET) testCases.print("US STREET Yield To Maturity", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYTMCalcType.US_TREASURY) testCases.print("US TREASURY Yield To Maturity", ytm) fullPrice = bond.fullPriceFromYTM(settlementDate, ytm) testCases.print("Full Price", fullPrice) cleanPrice = bond.cleanPriceFromYTM(settlementDate, ytm) testCases.print("Clean Price", cleanPrice) accddays = bond._accruedDays testCases.print("Accrued Days", accddays) accd = bond._accruedInterest testCases.print("Accrued", accd) duration = bond.dollarDuration(settlementDate, ytm) testCases.print("Dollar Duration", duration) modifiedDuration = bond.modifiedDuration(settlementDate, ytm) testCases.print("Modified Duration", modifiedDuration) macauleyDuration = bond.macauleyDuration(settlementDate, ytm) testCases.print("Macauley Duration", macauleyDuration) conv = bond.convexityFromYTM(settlementDate, ytm) testCases.print("Convexity", conv)
from financepy.market.curves.FinFlatCurve import FinFlatCurve from financepy.market.curves.FinFlatCurve import FinCompoundingMethods ############################################################################### print("BLOOMBERG US TREASURY EXAMPLE") settlementDate = FinDate(2017, 7, 21) maturityDate = FinDate(2027, 5, 15) coupon = 0.02375 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA # By setting the face to 100 we expect a price of par to be 100.0 face = 100.0 bond = FinBond(maturityDate, coupon, freqType, accrualType, face) cleanPrice = 99.780842 # if face is 1 then this must be 0.99780842 yld = bond.currentYield(cleanPrice) print("Current Yield = ", yld) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.UK_DMO) print("UK DMO Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.US_STREET) print("US STREET Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice,
def test_FinBondOptionAmericanConvergenceTWO(): # Build discount curve settlementDate = FinDate(1, 12, 2019) discountCurve = FinDiscountCurveFlat(settlementDate, 0.05) # Bond details issueDate = FinDate(1, 12, 2015) maturityDate = settlementDate.addTenor("10Y") coupon = 0.05 frequencyType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, frequencyType, accrualType) expiryDate = settlementDate.addTenor("18m") face = 100.0 spotValue = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) testCases.header("LABEL", "VALUE") testCases.print("BOND PRICE", spotValue) testCases.header("PERIOD", "N", "EUR_CALL", "AMER_CALL", "EUR_PUT", "AMER_PUT") sigma = 0.01 a = 0.1 hwModel = FinModelRatesHW(sigma, a) K = 102.0 vec_ec = [] vec_ac = [] vec_ep = [] vec_ap = [] numStepsVector = range(10, 500, 10) for numSteps in numStepsVector: hwModel = FinModelRatesHW(sigma, a, numSteps) start = time.time() europeanCallBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.EUROPEAN_CALL) v_ec = europeanCallBondOption.value(settlementDate, discountCurve, hwModel) americanCallBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.AMERICAN_CALL) v_ac = americanCallBondOption.value(settlementDate, discountCurve, hwModel) europeanPutBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.EUROPEAN_PUT) v_ep = europeanPutBondOption.value(settlementDate, discountCurve, hwModel) americanPutBondOption = FinBondOption(bond, expiryDate, K, face, FinOptionTypes.AMERICAN_PUT) v_ap = americanPutBondOption.value(settlementDate, discountCurve, hwModel) end = time.time() period = end - start testCases.print(period, numSteps, v_ec, v_ac, v_ep, v_ap) vec_ec.append(v_ec) vec_ac.append(v_ac) vec_ep.append(v_ep) vec_ap.append(v_ap) if plotGraphs: plt.figure() plt.plot(numStepsVector, vec_ac, label="American Call") plt.legend() plt.figure() plt.plot(numStepsVector, vec_ap, label="American Put") plt.legend()
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)
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_BDTExampleThree(): # Valuation of a swaption as in Leif Andersen's paper - see Table 1 on # SSRN-id155208.pdf testCases.banner("===================== ANDERSEN PAPER ==============") # This is a sanity check testBlackModelCheck() settlementDate = FinDate(1, 1, 2020) times = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]) dates = settlementDate.addYears(times) rate = 0.06 dfs = 1.0 / (1.0 + rate / 2.0)**(2.0 * times) curve = FinDiscountCurve(settlementDate, dates, dfs) coupon = 0.06 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA strikePrice = 100.0 face = 100.0 # Andersen paper numTimeSteps = 200 testCases.header("ExerciseType", "Sigma", "NumSteps", "Texp", "Tmat", "V_Fixed", "V_pay", "V_rec") for exerciseType in [FinExerciseTypes.EUROPEAN, FinExerciseTypes.BERMUDAN]: for maturityYears in [4.0, 5.0, 10.0, 20.0]: maturityDate = settlementDate.addYears(maturityYears) issueDate = FinDate(maturityDate._d, maturityDate._m, 2000) if maturityYears == 4.0 or maturityYears == 5.0: sigma = 0.2012 elif maturityYears == 10.0: sigma = 0.1522 elif maturityYears == 20.0: sigma = 0.1035 for expiryYears in range( int(maturityYears / 2) - 1, int(maturityYears)): expiryDate = settlementDate.addYears(expiryYears) tmat = (maturityDate - settlementDate) / gDaysInYear texp = (expiryDate - settlementDate) / gDaysInYear bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) couponTimes = [] couponFlows = [] cpn = bond._coupon / bond._frequency for flowDate in bond._flowDates: if flowDate > expiryDate: flowTime = (flowDate - settlementDate) / gDaysInYear couponTimes.append(flowTime) couponFlows.append(cpn) couponTimes = np.array(couponTimes) couponFlows = np.array(couponFlows) price = bond.cleanPriceFromDiscountCurve(settlementDate, curve) model = FinModelRatesBDT(sigma, numTimeSteps) model.buildTree(tmat, times, dfs) v = model.bermudanSwaption(texp, tmat, strikePrice, face, couponTimes, couponFlows, exerciseType) testCases.print("%s" % exerciseType, "%9.5f" % sigma, "%9.5f" % numTimeSteps, "%9.5f" % expiryYears, "%9.5f" % maturityYears, "%9.5f" % price, "%9.2f" % (v['pay'] * 100.0), "%9.2f" % (v['rec'] * 100.0))
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_FinBondEmbeddedOptionMATLAB(): # https://fr.mathworks.com/help/fininst/optembndbyhw.html # I FIND THAT THE PRICE CONVERGES TO 102.88 WHICH IS CLOSE TO 102.9127 # FOUND BY MATLAB ALTHOUGH THEY DO NOT EXAMINE THE ASYMPTOTIC PRICE # WHICH MIGHT BE A BETTER MATCH settlementDate = FinDate(1, 1, 2007) valuationDate = settlementDate ########################################################################### dcType = FinDayCountTypes.THIRTY_E_360 fixedFreq = FinFrequencyTypes.ANNUAL fixedLegType = FinSwapTypes.PAY swap1 = FinIborSwap(settlementDate, "1Y", fixedLegType, 0.0350, fixedFreq, dcType) swap2 = FinIborSwap(settlementDate, "2Y", fixedLegType, 0.0400, fixedFreq, dcType) swap3 = FinIborSwap(settlementDate, "3Y", fixedLegType, 0.0450, fixedFreq, dcType) swaps = [swap1, swap2, swap3] discountCurve = FinIborSingleCurve(valuationDate, [], [], swaps) ########################################################################### issueDate = FinDate(1, 1, 2004) maturityDate = FinDate(1, 1, 2010) coupon = 0.0525 freqType = FinFrequencyTypes.ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) callDates = [] callPrices = [] putDates = [] putPrices = [] putDate = FinDate(1, 1, 2008) for i in range(0, 24): putDates.append(putDate) putPrices.append(100) putDate = putDate.addMonths(1) testCases.header("BOND PRICE", "PRICE") v = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) testCases.print("Bond Pure Price:", v) sigma = 0.01 # basis point volatility a = 0.1 puttableBond = FinBondEmbeddedOption(issueDate, maturityDate, coupon, freqType, accrualType, callDates, callPrices, putDates, putPrices) testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure") timeSteps = range(50, 1000, 10) values = [] for numTimeSteps in timeSteps: model = FinModelRatesHW(sigma, a, numTimeSteps) start = time.time() v = puttableBond.value(settlementDate, discountCurve, model) end = time.time() period = end - start testCases.print(period, numTimeSteps, v['bondwithoption'], v['bondpure']) values.append(v['bondwithoption']) if plotGraphs: plt.figure() plt.plot(timeSteps, values)
def test_FinBond(): import pandas as pd bondDataFrame = pd.read_csv('./data/giltbondprices.txt', sep='\t') bondDataFrame['mid'] = 0.5*(bondDataFrame['bid'] + bondDataFrame['ask']) frequencyType = FinFrequencyTypes.SEMI_ANNUAL settlement = FinDate(2012, 9, 19) for accrualType in FinDayCountTypes: testCases.header("MATURITY", "COUPON", "CLEAN_PRICE", "ACCD_DAYS", "ACCRUED", "YTM") for index, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = FinDate.fromDatetime(matDatetime) coupon = bond['coupon']/100.0 cleanPrice = bond['mid'] bond = FinBond(maturityDt, coupon, frequencyType, accrualType) ytm = bond.yieldToMaturity(settlement, cleanPrice) accd = bond._accrued accd_days = bond._accruedDays testCases.print("%18s" % maturityDt, "%8.4f" % coupon, "%10.4f" % cleanPrice, "%6.0f" % accd_days, "%10.4f" % accd, "%8.4f" % ytm) # EXAMPLE FROM http://bondtutor.com/btchp4/topic6/topic6.htm accrualConvention = FinDayCountTypes.ACT_ACT_ICMA y = 0.062267 settlementDate = FinDate(1994, 4, 19) maturityDate = FinDate(1997, 7, 15) coupon = 0.085 face = 1.0 freqType = FinFrequencyTypes.SEMI_ANNUAL bond = FinBond(maturityDate, coupon, freqType, accrualConvention, face) testCases.header("FIELD", "VALUE") fullPrice = bond.fullPriceFromYield(settlementDate, y) testCases.print("Full Price = ", fullPrice) cleanPrice = bond.cleanPriceFromYield(settlementDate, y) testCases.print("Clean Price = ", cleanPrice) accd = bond._accrued testCases.print("Accrued = ", accd) ytm = bond.yieldToMaturity(settlementDate, cleanPrice) testCases.print("Yield to Maturity = ", ytm) bump = 1e-4 priceBumpedUp = bond.fullPriceFromYield(settlementDate, y + bump) testCases.print("Price Bumped Up:", priceBumpedUp) priceBumpedDn = bond.fullPriceFromYield(settlementDate, y - bump) testCases.print("Price Bumped Dn:", priceBumpedDn) durationByBump = -(priceBumpedUp - fullPrice) / bump testCases.print("Duration by Bump = ", durationByBump) duration = bond.dollarDuration(settlementDate, y) testCases.print("Dollar Duration = ", duration) testCases.print("Duration Difference:", duration - durationByBump) modifiedDuration = bond.modifiedDuration(settlementDate, y) testCases.print("Modified Duration = ", modifiedDuration) macauleyDuration = bond.macauleyDuration(settlementDate, y) testCases.print("Macauley Duration = ", macauleyDuration) conv = bond.convexityFromYield(settlementDate, y) testCases.print("Convexity = ", conv) # ASSET SWAP SPREAD # When the libor curve is the flat bond curve then the ASW is zero by # definition flatCurve = FinFlatCurve(settlementDate, ytm, 2) testCases.header("FIELD", "VALUE") cleanPrice = bond.cleanPriceFromYield(settlementDate, ytm) asw = bond.assetSwapSpread(settlementDate, cleanPrice, flatCurve) testCases.print("Discounted on Bond Curve ASW:", asw * 10000) # When the libor curve is the Libor curve then the ASW is positive liborCurve = buildLiborCurve(settlementDate) asw = bond.assetSwapSpread(settlementDate, cleanPrice, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, cleanPrice, liborCurve) testCases.print("Discounted on LIBOR Curve ASW:", asw * 10000) testCases.print("Discounted on LIBOR Curve OAS:", oas * 10000) p = 0.90 asw = bond.assetSwapSpread(settlementDate, p, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve) testCases.print("Deep discount bond at 90 ASW:", asw * 10000) testCases.print("Deep discount bond at 90 OAS:", oas * 10000) p = 1.00 asw = bond.assetSwapSpread(settlementDate, p, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve) testCases.print("Par bond at 100 ASW:", asw * 10000) testCases.print("Par bond at 100 OAS:", oas * 10000) p = 1.20 asw = bond.assetSwapSpread(settlementDate, p, liborCurve) oas = bond.optionAdjustedSpread(settlementDate, p, liborCurve) testCases.print("Above par bond at 120 ASW:", asw * 10000) testCases.print("Above par bond at 120 OAS:", oas * 10000) ########################################################################## # https://data.bloomberglp.com/bat/sites/3/2017/07/SF-2017_Paul-Fjeldsted.pdf # Page 10 TREASURY NOTE SCREENSHOT ########################################################################## testCases.banner("BLOOMBERG US TREASURY EXAMPLE") settlementDate = FinDate(2017, 7, 21) maturityDate = FinDate(2027, 5, 15) coupon = 0.02375 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA face = 100.0 bond = FinBond(maturityDate, coupon, freqType, accrualType, face) testCases.header("FIELD", "VALUE") cleanPrice = 99.780842 yld = bond.currentYield(cleanPrice) testCases.print("Current Yield = ", yld) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.UK_DMO) testCases.print("UK DMO Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.US_STREET) testCases.print("US STREET Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.US_TREASURY) testCases.print("US TREASURY Yield To Maturity = ", ytm) fullPrice = bond.fullPriceFromYield(settlementDate, ytm) testCases.print("Full Price = ", fullPrice) cleanPrice = bond.cleanPriceFromYield(settlementDate, ytm) testCases.print("Clean Price = ", cleanPrice) accd = bond._accrued testCases.print("Accrued = ", accd) accddays = bond._accruedDays testCases.print("Accrued Days = ", accddays) duration = bond.dollarDuration(settlementDate, ytm) testCases.print("Dollar Duration = ", duration) modifiedDuration = bond.modifiedDuration(settlementDate, ytm) testCases.print("Modified Duration = ", modifiedDuration) macauleyDuration = bond.macauleyDuration(settlementDate, ytm) testCases.print("Macauley Duration = ", macauleyDuration) conv = bond.convexityFromYield(settlementDate, ytm) testCases.print("Convexity = ", conv) ########################################################################## # Page 11 APPLE NOTE SCREENSHOT ########################################################################## testCases.banner("BLOOMBERG APPLE CORP BOND EXAMPLE") settlementDate = FinDate(2017, 7, 21) maturityDate = FinDate(2022, 5, 13) coupon = 0.027 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA face = 100.0 bond = FinBond(maturityDate, coupon, freqType, accrualType, face) testCases.header("FIELD", "VALUE") cleanPrice = 101.581564 yld = bond.currentYield(cleanPrice) testCases.print("Current Yield = ", yld) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.UK_DMO) testCases.print("UK DMO Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.US_STREET) testCases.print("US STREET Yield To Maturity = ", ytm) ytm = bond.yieldToMaturity(settlementDate, cleanPrice, FinYieldConventions.US_TREASURY) testCases.print("US TREASURY Yield To Maturity = ", ytm) fullPrice = bond.fullPriceFromYield(settlementDate, ytm) testCases.print("Full Price = ", fullPrice) cleanPrice = bond.cleanPriceFromYield(settlementDate, ytm) testCases.print("Clean Price = ", cleanPrice) # I GET 69 DAYS BUT BBG GETS 68 - CANNOT EXPLAIN!! accddays = bond._accruedDays testCases.print("Accrued Days = ", accddays) accd = bond._accrued testCases.print("Accrued = ", accd) duration = bond.dollarDuration(settlementDate, ytm) testCases.print("Dollar Duration = ", duration) modifiedDuration = bond.modifiedDuration(settlementDate, ytm) testCases.print("Modified Duration = ", modifiedDuration) macauleyDuration = bond.macauleyDuration(settlementDate, ytm) testCases.print("Macauley Duration = ", macauleyDuration) conv = bond.convexityFromYield(settlementDate, ytm) testCases.print("Convexity = ", conv)