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(50, 500, 50) 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", "TIME", "EXPIRY_ONLY", "EXPIRY_TREE", "JAMSHIDIAN") for numTimeSteps in numStepsList: start = time.time() model = FinModelRatesHW(sigma, a, numTimeSteps, FinHWEuropeanCalcType.EXPIRY_ONLY) model.buildTree(texp, times, dfs) exerciseType = FinExerciseTypes.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, period, v1, v2, vJam) # 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_FinDiscountCurves(): # Create a curve from times and discount factors valuationDate = FinDate(1, 1, 2018) years = [1.0, 2.0, 3.0, 4.0, 5.0] dates = valuationDate.addYears(years) years2 = [] for dt in dates: y = (dt - valuationDate) / gDaysInYear years2.append(y) rates = np.array([0.05, 0.06, 0.065, 0.07, 0.075]) discountFactors = np.exp(-np.array(rates) * np.array(years2)) curvesList = [] finDiscountCurve = FinDiscountCurve(valuationDate, dates, discountFactors, FinInterpTypes.FLAT_FWD_RATES) curvesList.append(finDiscountCurve) finDiscountCurveFlat = FinDiscountCurveFlat(valuationDate, 0.05) curvesList.append(finDiscountCurveFlat) finDiscountCurveNS = FinDiscountCurveNS(valuationDate, 0.0305, -0.01, 0.08, 10.0) curvesList.append(finDiscountCurveNS) finDiscountCurveNSS = FinDiscountCurveNSS(valuationDate, 0.035, -0.02, 0.09, 0.1, 1.0, 2.0) curvesList.append(finDiscountCurveNSS) finDiscountCurvePoly = FinDiscountCurvePoly(valuationDate, [0.05, 0.002, -0.00005]) curvesList.append(finDiscountCurvePoly) finDiscountCurvePWF = FinDiscountCurvePWF(valuationDate, dates, rates) curvesList.append(finDiscountCurvePWF) finDiscountCurvePWL = FinDiscountCurvePWL(valuationDate, dates, rates) curvesList.append(finDiscountCurvePWL) finDiscountCurveZeros = FinDiscountCurveZeros(valuationDate, dates, rates) curvesList.append(finDiscountCurveZeros) curveNames = [] for curve in curvesList: curveNames.append(type(curve).__name__) testCases.banner("SINGLE CALLS NO VECTORS") testCases.header("CURVE", "DATE", "ZERO", "DF", "CCFWD", "MMFWD", "SWAP") years = np.linspace(1, 10, 10) fwdMaturityDates = valuationDate.addYears(years) testCases.banner("######################################################") testCases.banner("SINGLE CALLS") testCases.banner("######################################################") for name, curve in zip(curveNames, curvesList): for fwdMaturityDate in fwdMaturityDates: tenor = "3M" zeroRate = curve.zeroRate(fwdMaturityDate) fwd = curve.fwd(fwdMaturityDate) fwdRate = curve.fwdRate(fwdMaturityDate, tenor) swapRate = curve.swapRate(valuationDate, fwdMaturityDate) df = curve.df(fwdMaturityDate) testCases.print("%-20s" % name, "%-12s" % fwdMaturityDate, "%7.6f" % (zeroRate), "%8.7f" % (df), "%7.6f" % (fwd), "%7.6f" % (fwdRate), "%7.6f" % (swapRate)) # Examine vectorisation testCases.banner("######################################################") testCases.banner("VECTORISATIONS") testCases.banner("######################################################") for name, curve in zip(curveNames, curvesList): tenor = "3M" zeroRate = curve.zeroRate(fwdMaturityDates) fwd = curve.fwd(fwdMaturityDates) fwdRate = curve.fwdRate(fwdMaturityDates, tenor) swapRate = curve.swapRate(valuationDate, fwdMaturityDates) df = curve.df(fwdMaturityDates) for i in range(0, len(fwdMaturityDates)): testCases.print("%-20s" % name, "%-12s" % fwdMaturityDate, "%7.6f" % (zeroRate[i]), "%8.7f" % (df[i]), "%7.6f" % (fwd[i]), "%7.6f" % (fwdRate[i]), "%7.6f" % (swapRate[i])) if PLOT_GRAPHS: years = np.linspace(0, 10, 121) years2 = years + 1.0 fwdDates = valuationDate.addYears(years) fwdDates2 = valuationDate.addYears(years2) plt.figure() for name, curve in zip(curveNames, curvesList): zeroRates = curve.zeroRate(fwdDates) plt.plot(years, zeroRates, label=name) plt.legend() plt.title("Zero Rates") plt.figure() for name, curve in zip(curveNames, curvesList): fwdRates = curve.fwd(fwdDates) plt.plot(years, fwdRates, label=name) plt.legend() plt.title("CC Fwd Rates") plt.figure() for name, curve in zip(curveNames, curvesList): fwdRates = curve.fwdRate(fwdDates, fwdDates2) plt.plot(years, fwdRates, label=name) plt.legend() plt.title("CC Fwd Rates") plt.figure() for name, curve in zip(curveNames, curvesList): dfs = curve.df(fwdDates) plt.plot(years, dfs, label=name) plt.legend() plt.title("Discount Factors")
# -*- coding: utf-8 -*- """ Created on Sun Jan 13 21:52:16 2019 @author: Dominic O'Kane """ from financepy.finutils.FinDate import FinDate # We can creat a FinDate as follows dt1 = FinDate(2019, 10, 10) # To see what this is, print it print("PRINT DATES") print(dt1) # To add two days we can do print("ADD CALENDAR DAYS") dt2 = dt1.addDays(2) print(dt2) # dt has not changed, we just created a new date # To add business days we do the following - note this does not know # about regional or religious holidays - just weekends print("ADD WORKDAYS") print(dt1, dt1.addWorkDays(2))
def test_FinLiborDepositsFuturesSwaps(): spotDate = FinDate(6, 6, 2018) spotDays = 0 settlementDate = spotDate.addWorkDays(spotDays) depoDCCType = FinDayCountTypes.ACT_360 depos = [] depositRate = 0.0231381 depo = FinLiborDeposit(settlementDate, "3M", depositRate, depoDCCType) depos.append(depo) depositRate = 0.027 depo = FinLiborDeposit(settlementDate, "3M", depositRate, depoDCCType) depos.append(depo) depos = [] depo = FinLiborDeposit(settlementDate, "1M", 0.0230, depoDCCType) depos.append(depo) depo = FinLiborDeposit(settlementDate, "2M", 0.0235, depoDCCType) depos.append(depo) depo = FinLiborDeposit(settlementDate, "3M", 0.0240, depoDCCType) depos.append(depo) fras = [] fraRate = futureToFRARate(97.6675, -0.00005) fraSettlementDate = spotDate.nextIMMDate() fraMaturityDate = fraSettlementDate.nextIMMDate() fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, depoDCCType) fras.append(fra) fraRate = futureToFRARate(97.5200, -0.00060) fraSettlementDate = fraMaturityDate fraMaturityDate = fraSettlementDate.nextIMMDate() fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, depoDCCType) fras.append(fra) fraRate = futureToFRARate(97.3550, -0.00146) fraSettlementDate = fraMaturityDate fraMaturityDate = fraSettlementDate.nextIMMDate() fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, depoDCCType) fras.append(fra) fraRate = futureToFRARate(97.2450, -0.00263) fraSettlementDate = fraMaturityDate fraMaturityDate = fraSettlementDate.nextIMMDate() fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, depoDCCType) fras.append(fra) fraRate = futureToFRARate(97.1450, -0.00411) fraSettlementDate = fraMaturityDate fraMaturityDate = fraSettlementDate.nextIMMDate() fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, depoDCCType) fras.append(fra) fraRate = futureToFRARate(97.0750, -0.00589) fraSettlementDate = fraSettlementDate.nextIMMDate() fraMaturityDate = fraSettlementDate.nextIMMDate() fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, depoDCCType) fras.append(fra) ########################################################################### spotDays = 2 startDate = spotDate.addWorkDays(spotDays) swaps = [] swapType = FinLiborSwapTypes.PAYER fixedDCCType = FinDayCountTypes.THIRTY_E_360 fixedFreqType = FinFrequencyTypes.SEMI_ANNUAL floatFreqType = FinFrequencyTypes.QUARTERLY notional = 1000000 floatSpread = 0.0 floatDCCType = FinDayCountTypes.ACT_360 calendarType = FinCalendarTypes.US busDayAdjustRule = FinBusDayAdjustTypes.PRECEDING swapRate = 0.02776305 swap = FinLiborSwap(startDate, "2Y", swapType, swapRate, fixedFreqType, fixedDCCType, notional, floatSpread, floatFreqType, floatDCCType, calendarType, busDayAdjustRule) swaps.append(swap) liborCurve = FinLiborCurve(spotDate, depos, fras, swaps) times = np.linspace(0.0, 2.0, 25) dates = spotDate.addYears(times) zeroRates = liborCurve.zeroRate(dates) fwdRates = liborCurve.fwd(dates) if PLOT_GRAPHS: plt.figure(figsize=(8, 6)) plt.plot(times, zeroRates * 100, label="zero rates") plt.plot(times, fwdRates * 100, label="fwd rates") plt.xlabel("Times") plt.ylabel("CC forward rates") plt.legend() print("==============================================================") for fra in fras: print(fra) print("==============================================================") endDate = spotDate df = liborCurve.df(endDate) print(endDate, df) endDate = settlementDate df = liborCurve.df(endDate) print(endDate, df) endDate = FinDate(20, 6, 2018) df = liborCurve.df(endDate) print(endDate, df) for depo in depos: endDate = depo._maturityDate df = liborCurve.df(endDate) print(endDate, df) for fra in fras: endDate = fra._maturityDate df = liborCurve.df(endDate) print(endDate, df) for swap in swaps: endDate = swap._maturityDate df = liborCurve.df(endDate) print(endDate, df) swap.printFixedLegPV(spotDate) swap.printFloatLegPV(spotDate)
def test_bloombergPricingExample(): ''' This is an example of a replication of a BBG example from https://github.com/vilen22/curve-building/blob/master/Bloomberg%20Curve%20Building%20Replication.xlsx ''' valuationDate = FinDate(6, 6, 2018) # We do the O/N rate which settles on trade date spotDays = 0 settlementDate = valuationDate.addWorkDays(spotDays) depoDCCType = FinDayCountTypes.ACT_360 depos = [] depositRate = 0.0231381 maturityDate = settlementDate.addMonths(3) depo = FinLiborDeposit(settlementDate, maturityDate, depositRate, depoDCCType) depos.append(depo) futs = [] fut = FinLiborFuture(valuationDate, 1) futs.append(fut) fut = FinLiborFuture(valuationDate, 2) futs.append(fut) fut = FinLiborFuture(valuationDate, 3) futs.append(fut) fut = FinLiborFuture(valuationDate, 4) futs.append(fut) fut = FinLiborFuture(valuationDate, 5) futs.append(fut) fut = FinLiborFuture(valuationDate, 6) futs.append(fut) fras = [None] * 6 fras[0] = futs[0].toFRA(97.6675, -0.00005) fras[1] = futs[1].toFRA(97.5200, -0.00060) fras[2] = futs[2].toFRA(97.3550, -0.00146) fras[3] = futs[3].toFRA(97.2450, -0.00263) fras[4] = futs[4].toFRA(97.1450, -0.00411) fras[5] = futs[5].toFRA(97.0750, -0.00589) accrual = FinDayCountTypes.THIRTY_E_360 freq = FinFrequencyTypes.SEMI_ANNUAL spotDays = 2 settlementDate = valuationDate.addWorkDays(spotDays) notional = ONE_MILLION swapType = FinLiborSwapTypes.PAYER swaps = [] swap = FinLiborSwap(settlementDate, "2Y", swapType, (2.77417 + 2.77844) / 200, freq, accrual, notional) swaps.append(swap) swap = FinLiborSwap(settlementDate, "3Y", swapType, (2.86098 + 2.86582) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "4Y", swapType, (2.90240 + 2.90620) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "5Y", swapType, (2.92944 + 2.92906) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "6Y", swapType, (2.94001 + 2.94499) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "7Y", swapType, (2.95352 + 2.95998) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "8Y", swapType, (2.96830 + 2.97400) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "9Y", swapType, (2.98403 + 2.98817) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "10Y", swapType, (2.99716 + 3.00394) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "11Y", swapType, (3.01344 + 3.01596) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "12Y", swapType, (3.02276 + 3.02684) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "15Y", swapType, (3.04092 + 3.04508) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "20Y", swapType, (3.04417 + 3.05183) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "25Y", swapType, (3.03219 + 3.03621) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "30Y", swapType, (3.01030 + 3.01370) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "40Y", swapType, (2.96946 + 2.97354) / 200, freq, accrual) swaps.append(swap) swap = FinLiborSwap(settlementDate, "50Y", swapType, (2.91552 + 2.93748) / 200, freq, accrual) swaps.append(swap) liborCurve = FinLiborCurve(valuationDate, depos, fras, swaps) # The valuation of 53714.55 is very close to the spreadsheet value 53713.96 principal = 0.0 testCases.header("VALUATION TO TODAY DATE", " PV") testCases.print( "VALUE:", swaps[0].value(valuationDate, liborCurve, liborCurve, None, principal)) testCases.print( "FIXED:", swaps[0].fixedLegValue(valuationDate, liborCurve, principal)) testCases.print( "FLOAT:", swaps[0].floatLegValue(valuationDate, liborCurve, liborCurve, None, principal)) testCases.header("VALUATION TO SWAP SETTLEMENT DATE", " PV") testCases.print( "VALUE:", swaps[0].value(settlementDate, liborCurve, liborCurve, None, principal)) testCases.print( "FIXED:", swaps[0].fixedLegValue(settlementDate, liborCurve, principal)) testCases.print( "FLOAT:", swaps[0].floatLegValue(settlementDate, liborCurve, liborCurve, None, principal))
def test_FinBinomialTree(): stockPrice = 50.0 riskFreeRate = 0.06 dividendYield = 0.04 volatility = 0.40 valueDate = FinDate(2016, 1, 1) expiryDate = FinDate(2017, 1, 1) model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, riskFreeRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) numStepsList = [100, 500, 1000, 2000, 5000] strikePrice = 50.0 testCases.banner("================== EUROPEAN PUT =======================") putOption = FinEquityVanillaOption(expiryDate, strikePrice, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) delta = putOption.delta(valueDate, stockPrice, discountCurve, dividendCurve, model) gamma = putOption.gamma(valueDate, stockPrice, discountCurve, dividendCurve, model) theta = putOption.theta(valueDate, stockPrice, discountCurve, dividendCurve, model) testCases.header("BS Value", "BS Delta", "BS Gamma", "BS Theta") testCases.print(value, delta, gamma, theta) payoff = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.EUROPEAN params = np.array([-1, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for numSteps in numStepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stockPrice, discountCurve, dividendCurve, volatility, numSteps, valueDate, payoff, expiryDate, payoff, exercise, params) end = time.time() duration = end - start testCases.print(numSteps, results, duration) testCases.banner("================== AMERICAN PUT =======================") payoff = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.AMERICAN params = np.array([-1, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for numSteps in numStepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stockPrice, discountCurve, dividendCurve, volatility, numSteps, valueDate, payoff, expiryDate, payoff, exercise, params) end = time.time() duration = end - start testCases.print(numSteps, results, duration) testCases.banner( "================== EUROPEAN CALL =======================") callOption = FinEquityVanillaOption(expiryDate, strikePrice, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) delta = callOption.delta(valueDate, stockPrice, discountCurve, dividendCurve, model) gamma = callOption.gamma(valueDate, stockPrice, discountCurve, dividendCurve, model) theta = callOption.theta(valueDate, stockPrice, discountCurve, dividendCurve, model) testCases.header("BS Value", "BS Delta", "BS Gamma", "BS Theta") testCases.print(value, delta, gamma, theta) payoff = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.EUROPEAN params = np.array([1.0, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for numSteps in numStepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stockPrice, discountCurve, dividendCurve, volatility, numSteps, valueDate, payoff, expiryDate, payoff, exercise, params) end = time.time() duration = end - start testCases.print(numSteps, results, duration) testCases.banner( "================== AMERICAN CALL =======================") payoff = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.AMERICAN params = np.array([1.0, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for numSteps in numStepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stockPrice, discountCurve, dividendCurve, volatility, numSteps, valueDate, payoff, expiryDate, payoff, exercise, params) end = time.time() duration = end - start testCases.print(numSteps, results, duration)
########################################################################### from financepy.finutils.FinFrequency import FinFrequencyTypes from financepy.finutils.FinDayCount import FinDayCountTypes from financepy.finutils.FinDate import FinDate from financepy.products.bonds.FinBond import FinBond, FinYieldConventions 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)
def test_FinBondFRN(): # https://data.bloomberglp.com/bat/sites/3/2017/07/SF-2017_Paul-Fjeldsted.pdf # I have a day out problem on the accrued interest - should be 71 and not 72 days # Other than that agreement on the DM is very good. ########################################################################## # CITIGROUP FRN SCREENSHOT ########################################################################## testCases.banner("BLOOMBERG CITIGROUP FRN EXAMPLE") issueDate = FinDate(10, 11, 2010) maturityDate = FinDate(10, 11, 2021) quotedMargin = 0.0025 freqType = FinFrequencyTypes.QUARTERLY accrualType = FinDayCountTypes.THIRTY_E_360 face = 1000000 bond = FinBondFRN(issueDate, maturityDate, quotedMargin, freqType, accrualType, face) testCases.header("FIELD", "VALUE") cleanPrice = 96.793 resetIbor = 0.0143456 - quotedMargin currentIbor = 0.0120534 futureIbors = 0.0130522 settlementDate = FinDate(21, 7, 2017) dm = bond.discountMargin(settlementDate, resetIbor, currentIbor, futureIbors, cleanPrice) testCases.print("Discount Margin (bp) = ", dm * 10000) fullPrice = bond.fullPriceFromDM(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Full Price = ", fullPrice) lastCouponDt = bond._pcd testCases.print("Last Coupon Date = ", str(lastCouponDt)) accddays = bond._accruedDays testCases.print("Accrued Days = ", accddays) accdAmount = bond._accruedInterest testCases.print("Accrued Amount = ", accdAmount) principal = bond.principal(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Dollar Principal = ", principal) duration = bond.dollarDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Dollar Rate Duration = ", duration) modifiedDuration = bond.modifiedRateDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Modified Rate Duration = ", modifiedDuration) macauleyDuration = bond.macauleyRateDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Macauley Duration = ", macauleyDuration) convexity = bond.convexityFromDM(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Convexity = ", convexity) duration = bond.dollarCreditDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Dollar Credit Duration = ", duration) modifiedDuration = bond.modifiedCreditDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Modified Credit Duration = ", modifiedDuration) ########################################################################## # EXAMPLE # https://ebrary.net/14293/economics/actual_floater ########################################################################## testCases.banner("BLOOMBERG CITIGROUP FRN EXAMPLE II") issueDate = FinDate(28, 3, 2000) settlementDate = FinDate(28, 3, 2014) maturityDate = FinDate(3, 2, 2021) quotedMargin = 0.0020 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.THIRTY_E_360_ISDA face = 1000000.0 bond = FinBondFRN(issueDate, maturityDate, quotedMargin, freqType, accrualType, face) testCases.header("FIELD", "VALUE") cleanPrice = 93.08 resetIbor = 0.00537 - quotedMargin currentIbor = 0.027558 futureIbors = 0.03295 dm = bond.discountMargin(settlementDate, resetIbor, currentIbor, futureIbors, cleanPrice) testCases.print("Discount Margin (bp) = ", dm * 10000) fullPrice = bond.fullPriceFromDM(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Full Price = ", fullPrice) lastCouponDt = bond._pcd testCases.print("Last Coupon Date = ", str(lastCouponDt)) accddays = bond._accruedDays testCases.print("Accrued Days = ", accddays) accdAmount = bond._accruedInterest testCases.print("Accrued Amount = ", accdAmount) principal = bond.principal(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Dollar Principal = ", principal) duration = bond.dollarDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Dollar Rate Duration = ", duration) modifiedDuration = bond.modifiedRateDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Modified Rate Duration = ", modifiedDuration) macauleyDuration = bond.macauleyRateDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Macauley Duration = ", macauleyDuration) convexity = bond.convexityFromDM(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Convexity = ", convexity) principal = bond.principal(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Principal = ", principal) duration = bond.dollarCreditDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Dollar Credit Duration = ", duration) modifiedDuration = bond.modifiedCreditDuration(settlementDate, resetIbor, currentIbor, futureIbors, dm) testCases.print("Modified Credit Duration = ", modifiedDuration)
def test_FinLiborSwaption(): import time valuationDate = FinDate(2011, 1, 1) exerciseDate = FinDate(2012, 1, 1) swapMaturityDate = FinDate(2017, 1, 1) swapFixedCoupon = 0.030 swapFixedFrequencyType = FinFrequencyTypes.SEMI_ANNUAL swapFixedDayCountType = FinDayCountTypes.ACT_365_ISDA liborCurve = test_FinLiborDepositsAndSwaps(valuationDate) start = time.time() swaptionType = FinLiborSwaptionType.PAYER swaption = FinLiborSwaption(exerciseDate, swapMaturityDate, swaptionType, swapFixedCoupon, swapFixedFrequencyType, swapFixedDayCountType) model = FinLiborModelBlack(0.25) settlementDate = valuationDate.addWorkDays(2) value = swaption.value(settlementDate, liborCurve, model) # swaption.print() testCases.header("LABEL", "VALUE") testCases.print("PAYER Swaption Value", value) swaptionType = FinLiborSwaptionType.RECEIVER swaption = FinLiborSwaption(exerciseDate, swapMaturityDate, swaptionType, swapFixedCoupon, swapFixedFrequencyType, swapFixedDayCountType) model = FinLiborModelBlack(0.25) settlementDate = valuationDate.addWorkDays(2) value = swaption.value(settlementDate, liborCurve, model) # swaption.print() testCases.print("RECEIVER Swaption Value", value) end = time.time() testCases.header("TIME") testCases.print(end - start) ########################################################################## ########################################################################## start = time.time() swaptionType = FinLiborSwaptionType.PAYER testCases.banner( "===================================================================") swaption = FinLiborSwaption(exerciseDate, swapMaturityDate, swaptionType, swapFixedCoupon, swapFixedFrequencyType, swapFixedDayCountType) model = FinLiborModelSABR(0.28, 1.0, -0.09, 0.21) value = swaption.value(settlementDate, liborCurve, model) # swaption.print() testCases.header("LABEL", "VALUE") testCases.print("PAYER Swaption Value", value) swaptionType = FinLiborSwaptionType.RECEIVER swaption = FinLiborSwaption(exerciseDate, swapMaturityDate, swaptionType, swapFixedCoupon, swapFixedFrequencyType, swapFixedDayCountType) model = FinLiborModelSABR(0.28, 1.0, -0.09, 0.21) value = swaption.value(settlementDate, liborCurve, model) # swaption.print() testCases.print("RECEIVER Swaption Value", value) end = time.time() testCases.header("TIME") testCases.print(end - start)
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_FinCDSCurve(): curveDate = FinDate(2018, 12, 20) swaps = [] depos = [] fras = [] fixedDCC = FinDayCountTypes.ACT_365F fixedFreq = FinFrequencyTypes.SEMI_ANNUAL fixedCoupon = 0.05 for i in range(1, 11): maturityDate = curveDate.addMonths(12 * i) swap = FinIborSwap(curveDate, maturityDate, FinSwapTypes.PAYER, fixedCoupon, fixedFreq, fixedDCC) swaps.append(swap) libor_curve = FinIborSingleCurve(curveDate, depos, fras, swaps) cdsContracts = [] for i in range(1, 11): maturityDate = curveDate.addMonths(12 * i) cds = FinCDS(curveDate, maturityDate, 0.005 + 0.001 * (i - 1)) cdsContracts.append(cds) issuerCurve = FinCDSCurve(curveDate, cdsContracts, libor_curve, recoveryRate=0.40, useCache=False) testCases.header("T", "Q") n = len(issuerCurve._times) for i in range(0, n): testCases.print(issuerCurve._times[i], issuerCurve._values[i]) testCases.header("CONTRACT", "VALUE") for i in range(1, 11): maturityDate = curveDate.addMonths(12 * i) cds = FinCDS(curveDate, maturityDate, 0.005 + 0.001 * (i - 1)) v = cds.value(curveDate, issuerCurve) testCases.print(i, v) if 1 == 0: x = [0.0, 1.2, 1.6, 1.7, 10.0] qs = issuerCurve.survProb(x) print("===>", qs) x = [0.3, 1.2, 1.6, 1.7, 10.0] xx = np.array(x) qs = issuerCurve.survProb(xx) print("===>", qs) x = [0.3, 1.2, 1.6, 1.7, 10.0] dfs = issuerCurve.df(x) print("===>", dfs) x = [0.3, 1.2, 1.6, 1.7, 10.0] xx = np.array(x) dfs = issuerCurve.df(xx) print("===>", dfs)
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_HullWhiteExampleTwo(): # HULL BOOK ZERO COUPON BOND EXAMPLE 28.1 SEE TABLE 28.3 # Replication may not be exact as I am using dates rather than times zeroDays = [0, 3, 31, 62, 94, 185, 367, 731, 1096, 1461, 1826, 2194, 2558, 2922, 3287, 3653] zeroRates = [5.0, 5.01772, 4.98282, 4.97234, 4.96157, 4.99058, 5.09389, 5.79733, 6.30595, 6.73464, 6.94816, 7.08807, 7.27527, 7.30852, 7.39790, 7.49015] times = np.array(zeroDays) / 365.0 zeros = np.array(zeroRates) / 100.0 dfs = np.exp(-zeros*times) startDate = FinDate(1, 12, 2019) sigma = 0.01 a = 0.1 strike = 63.0 face = 100.0 expiryDate = startDate.addTenor("3Y") maturityDate = startDate.addTenor("9Y") texp = (expiryDate - startDate)/gDaysInYear tmat = (maturityDate - startDate)/gDaysInYear numTimeSteps = None model = FinModelRatesHW(sigma, a, numTimeSteps) vAnal = model.optionOnZCB(texp, tmat, strike, face, times, dfs) # Test convergence numStepsList = range(100, 500, 100) analVector = [] treeVector = [] testCases.banner("Comparing option on zero coupon bond analytical vs Tree") testCases.header("NUMTIMESTEP", "TIME", "VTREE_CALL", "VTREE_PUT", "VANAL CALL", "VANAL_PUT", "CALLDIFF", "PUTDIFF") for numTimeSteps in numStepsList: start = time.time() model = FinModelRatesHW(sigma, a, numTimeSteps) model.buildTree(texp, times, dfs) vTree1 = model.optionOnZeroCouponBond_Tree(texp, tmat, strike, face) model = FinModelRatesHW(sigma, a, numTimeSteps+1) model.buildTree(texp, times, dfs) vTree2 = model.optionOnZeroCouponBond_Tree(texp, tmat, strike, face) end = time.time() period = end-start treeVector.append(vTree1['put']) analVector.append(vAnal['put']) vTreeCall = (vTree1['call'] + vTree2['call'] ) / 2.0 vTreePut = (vTree1['put'] + vTree2['put'] ) / 2.0 diffC = vTreeCall - vAnal['call'] diffP = vTreePut - vAnal['put'] testCases.print(numTimeSteps, period, vTreeCall, vAnal['call'], vTreePut, vAnal['put'], diffC, diffP)
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, 500, 1000] tmat = (maturityDate - settlementDate)/gDaysInYear testCases.header("NUMSTEPS", "TIME", "BOND_ONLY", "CALLABLE_BOND") 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, period, v1, v2)
def test_FinNelsonSiegelSvenssonCurve(): tau1 = 2.0 tau2 = 0.5 times = np.linspace(0.0, 10.0, 5) startDate = FinDate(1, 1, 2020) dates = startDate.addYears(times) curve1 = FinDiscountCurveNSS(startDate, 1., 0., 0., 0., tau1, tau2) factor1loading = curve1.zeroRate(dates) curve2 = FinDiscountCurveNSS(startDate, 0., 1., 0., 0., tau1, tau2) factor2loading = curve2.zeroRate(dates) curve3 = FinDiscountCurveNSS(startDate, 0., 0., 1., 0., tau1, tau2) factor3loading = curve3.zeroRate(dates) curve4 = FinDiscountCurveNSS(startDate, 0., 0., 0., 1., tau1, tau2) factor4loading = curve4.zeroRate(dates) testCases.header("FACTOR LOADING ON ZERO RATES") testCases.print(factor1loading) testCases.print(factor2loading) testCases.print(factor3loading) testCases.print(factor4loading) # plt.figure(figsize = (6,4)) # plt.plot(times,scaleVector(factor1loading,1),label='beta1'); # plt.plot(times,scaleVector(factor2loading,1),label='beta2'); # plt.plot(times,scaleVector(factor3loading,1),label='beta3'); # plt.ylim((0,1.05)) # # plt.title('Factor Loadings in Nelson-Siegel Model'); # plt.xlabel('Time (years)'); # plt.ylabel('Loading'); # plt.legend(loc='best') ########################################################################## testCases.header("BETA1", "BETA2", "BETA3", "BETA4", "ZEROS") beta1 = 0.03 beta2 = -0.02 beta3 = -0.02 beta4 = 0.08 curve1 = FinDiscountCurveNSS(startDate, beta1, beta2, beta3, beta4, tau1, tau2) zeroRates1 = curve1.zeroRate(dates) testCases.print(beta1, beta2, beta3, beta4, zeroRates1) beta1 = 0.04 beta2 = -0.02 beta3 = -0.02 beta4 = 0.08 curve2 = FinDiscountCurveNSS(startDate, beta1, beta2, beta3, beta4, tau1, tau2) zeroRates2 = curve2.zeroRate(dates) testCases.print(beta1, beta2, beta3, beta4, zeroRates2) beta1 = 0.05 beta2 = -0.02 beta3 = -0.02 beta4 = 0.08 curve3 = FinDiscountCurveNSS(startDate, beta1, beta2, beta3, beta4, tau1, tau2) zeroRates3 = curve3.zeroRate(dates) testCases.print(beta1, beta2, beta3, beta4, zeroRates3) beta1 = 0.06 beta2 = -0.02 beta3 = -0.02 beta4 = 0.08 curve4 = FinDiscountCurveNSS(startDate, beta1, beta2, beta3, beta4, tau1, tau2) zeroRates4 = curve4.zeroRate(dates) testCases.print(beta1, beta2, beta3, beta4, zeroRates4) beta1 = 0.07 beta2 = -0.02 beta3 = -0.02 beta4 = 0.08 curve5 = FinDiscountCurveNSS(startDate, beta1, beta2, beta3, beta4, tau1, tau2) zeroRates5 = curve5.zeroRate(dates) testCases.print(beta1, beta2, beta3, beta4, zeroRates5) if PLOT_GRAPHS: plt.figure(figsize=(6, 4)) plt.plot(times, scale(zeroRates1, 100), label='beta1=3%') plt.plot(times, scale(zeroRates2, 100), label='beta1=4%') plt.plot(times, scale(zeroRates3, 100), label='beta1=5%') plt.plot(times, scale(zeroRates4, 100), label='beta1=6%') plt.plot(times, scale(zeroRates5, 100), label='beta1=7%') plt.ylim((0, 7.5)) plt.title('Nelson-Siegel Zero Rate Curves') plt.xlabel('Time (years)') plt.ylabel('Zero Rate (%)') plt.legend(loc='lower right', frameon=False)
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(2012, 9, 19) 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(2030, 9, 19) interpolatedYield = fittedCurve5.interpolatedYield(maturityDate) testCases.print(maturityDate, interpolatedYield)
def test_FinFXMktVolSurface1(verboseCalibration): ########################################################################### if 1 == 1: # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARKE") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.00, 21.00, 20.750, 19.400, 18.250, 17.677] marketStrangle25DeltaVols = [0.65, 0.75, 0.85, 0.90, 0.95, 0.85] riskReversal25DeltaVols = [-0.20, -0.25, -0.30, -0.50, -0.60, -0.562] marketStrangle10DeltaVols = [2.433, 2.83, 3.228, 3.485, 3.806, 3.208] riskReversal10DeltaVols = [-1.258, -1.297, -1.332, -1.408, -1.359, -1.208] if 1==1: tenors = ['1Y'] atmVols = [18.250] marketStrangle25DeltaVols = [0.950] riskReversal25DeltaVols = [-0.600] marketStrangle10DeltaVols = [3.806] riskReversal10DeltaVols = [-1.359] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA volFunctionType = FinVolFunctionTypes.CLARKE # volFunctionType = FinVolFunctionTypes.SABR fxMarket = FinFXVolSurfacePlus(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, marketStrangle10DeltaVols, riskReversal10DeltaVols, atmMethod, deltaMethod, volFunctionType) fxMarket.checkCalibration(False) if PLOT_GRAPHS: fxMarket.plotVolCurves() dbns = fxMarket.impliedDbns(0.00001, 5.0, 10000) for i in range(0, len(dbns)): plt.plot(dbns[i]._x, dbns[i]._densitydx) print("SUM:", dbns[i].sum()) fxMarket = FinFXVolSurface(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod, volFunctionType) fxMarket.checkCalibration(False) if PLOT_GRAPHS: fxMarket.plotVolCurves() dbns = fxMarket.impliedDbns(0.00001, 5.0, 10000) for i in range(0, len(dbns)): plt.plot(dbns[i]._x, dbns[i]._densitydx) print("SUM:", dbns[i].sum())
from financepy.products.bonds.FinBond import FinBond from financepy.market.curves.FinBondYieldCurve import FinBondYieldCurve from financepy.market.curves.FinBondYieldCurveModel import * ############################################################################### # FIRST LOAD UP SOME UK BOND DATA USING PANDAS bondDataFrame = pd.read_csv('../tests/data/giltbondprices.txt', sep='\t') # CALCULATE MID MARKET PRICES bondDataFrame['mid'] = 0.5 * (bondDataFrame['bid'] + bondDataFrame['ask']) # SPECIFY UK BOND CONVENTIONS frequencyType = FinFrequencyTypes.SEMI_ANNUAL 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)
def test_fullPriceCDSIndexOption(): tradeDate = FinDate(2007, 8, 1) stepInDate = tradeDate.addDays(1) valuationDate = stepInDate liborCurve = buildIborCurve(tradeDate) maturity3Y = tradeDate.nextCDSDate(36) maturity5Y = tradeDate.nextCDSDate(60) maturity7Y = tradeDate.nextCDSDate(84) maturity10Y = tradeDate.nextCDSDate(120) path = os.path.join(os.path.dirname(__file__), './/data//CDX_NA_IG_S7_SPREADS.csv') f = open(path, 'r') data = f.readlines() f.close() issuerCurves = [] for row in data[1:]: splitRow = row.split(",") creditName = splitRow[0] spd3Y = float(splitRow[1]) / 10000.0 spd5Y = float(splitRow[2]) / 10000.0 spd7Y = float(splitRow[3]) / 10000.0 spd10Y = float(splitRow[4]) / 10000.0 recoveryRate = float(splitRow[5]) cds3Y = FinCDS(stepInDate, maturity3Y, spd3Y) cds5Y = FinCDS(stepInDate, maturity5Y, spd5Y) cds7Y = FinCDS(stepInDate, maturity7Y, spd7Y) cds10Y = FinCDS(stepInDate, maturity10Y, spd10Y) cdsContracts = [cds3Y, cds5Y, cds7Y, cds10Y] issuerCurve = FinCDSCurve(valuationDate, cdsContracts, liborCurve, recoveryRate) issuerCurves.append(issuerCurve) ########################################################################## ########################################################################## indexUpfronts = [0.0, 0.0, 0.0, 0.0] indexMaturityDates = [ FinDate(2009, 12, 20), FinDate(2011, 12, 20), FinDate(2013, 12, 20), FinDate(2016, 12, 20) ] indexRecovery = 0.40 testCases.banner( "======================= CDS INDEX OPTION ==========================") indexCoupon = 0.004 volatility = 0.50 expiryDate = FinDate(2008, 2, 1) maturityDate = FinDate(2011, 12, 20) notional = 10000.0 tolerance = 1e-6 testCases.header("TIME", "STRIKE", "INDEX", "PAYER", "RECEIVER", "G(K)", "X", "EXPH", "ABPAY", "ABREC") for index in np.linspace(20, 60, 10): ####################################################################### cdsContracts = [] for dt in indexMaturityDates: cds = FinCDS(valuationDate, dt, index / 10000.0) cdsContracts.append(cds) indexCurve = FinCDSCurve(valuationDate, cdsContracts, liborCurve, indexRecovery) if 1 == 1: indexSpreads = [index / 10000.0] * 4 indexPortfolio = FinCDSIndexPortfolio() adjustedIssuerCurves = indexPortfolio.hazardRateAdjustIntrinsic( valuationDate, issuerCurves, indexSpreads, indexUpfronts, indexMaturityDates, indexRecovery, tolerance) else: indexSpread = index / 10000.0 issuerCurve = buildFlatIssuerCurve(tradeDate, liborCurve, indexSpread, indexRecovery) adjustedIssuerCurves = [] for iCredit in range(0, 125): adjustedIssuerCurves.append(issuerCurve) ####################################################################### for strike in np.linspace(20, 60, 20): start = time.time() option = FinCDSIndexOption(expiryDate, maturityDate, indexCoupon, strike / 10000.0, notional) v_pay_1, v_rec_1, strikeValue, mu, expH = option.valueAnderson( valuationDate, adjustedIssuerCurves, indexRecovery, volatility) end = time.time() elapsed = end - start end = time.time() v_pay_2, v_rec_2 = option.valueAdjustedBlack( valuationDate, indexCurve, indexRecovery, liborCurve, volatility) elapsed = end - start testCases.print(elapsed, strike, index, v_pay_1, v_rec_1, strikeValue, mu, expH, v_pay_2, v_rec_2)
def test_FinFXVanillaOptionHullExample(): # Example from Hull 4th edition page 284 valueDate = FinDate(2015, 1, 1) expiryDate = valueDate.addMonths(4) spotFXRate = 1.60 volatility = 0.1411 domInterestRate = 0.08 forInterestRate = 0.11 model = FinFXModelBlackScholes(volatility) domDiscountCurve = FinDiscountCurveFlat(valueDate, domInterestRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forInterestRate) numPathsList = [10000, 20000, 40000, 80000, 160000, 320000] testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") strikeFXRate = 1.60 for numPaths in numPathsList: callOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.EUROPEAN_CALL, 1000000, "USD") value = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) start = time.time() valueMC = callOption.valueMC(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model, numPaths) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC, duration) ########################################################################## spotFXRates = np.arange(100, 200, 10) spotFXRates = spotFXRates / 100.0 numPaths = 100000 testCases.header("NUMPATHS", "CALL_VALUE_BS", "CALL_VALUE_MC", "TIME") for spotFXRate in spotFXRates: callOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.EUROPEAN_CALL, 1000000, "USD") value = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) start = time.time() valueMC = callOption.valueMC(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model, numPaths) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC, duration) ########################################################################## spotFXRates = np.arange(100, 200, 10) / 100.0 numPaths = 100000 testCases.header("SPOT FX RATE", "PUT_VALUE_BS", "PUT_VALUE_MC", "TIME") for spotFXRate in spotFXRates: putOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.EUROPEAN_PUT, 1000000, "USD") value = putOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) start = time.time() valueMC = putOption.valueMC(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model, numPaths) end = time.time() duration = end - start testCases.print(spotFXRate, value, valueMC, duration) ########################################################################## spotFXRates = np.arange(100, 200, 10) / 100.0 testCases.header("SPOT FX RATE", "CALL_VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for spotFXRate in spotFXRates: callOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.EUROPEAN_CALL, 1000000, "USD") value = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) delta = callOption.delta(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) vega = callOption.vega(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) theta = callOption.theta(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) # callOption.rho(valueDate,stockPrice, interestRate, # dividendYield, modelType, modelParams) rho = 999 testCases.print(spotFXRate, value, delta, vega, theta, rho) testCases.header("SPOT FX RATE", "PUT_VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for spotFXRate in spotFXRates: putOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.EUROPEAN_PUT, 1000000, "USD") value = putOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) delta = putOption.delta(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) vega = putOption.vega(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) theta = putOption.theta(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) # putOption.rho(valueDate,stockPrice, interestRate, dividendYield, # modelType, modelParams) rho = 999 testCases.print(spotFXRate, value, delta, vega, theta, rho) ########################################################################## testCases.header("SPOT FX RATE", "VALUE_BS", "VOL_IN", "IMPLD_VOL") spotFXRates = np.arange(100, 200, 10) / 100.0 for spotFXRate in spotFXRates: callOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.EUROPEAN_CALL, 1000000, "USD") value = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model)['v'] impliedVol = callOption.impliedVolatility(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, value) testCases.print(spotFXRate, value, volatility, impliedVol)
def test_FinLiborDepositsFRAsSwaps(): valuationDate = FinDate(2019, 9, 18) dccType = FinDayCountTypes.THIRTY_E_360_ISDA depos = [] spotDays = 0 settlementDate = valuationDate.addWorkDays(spotDays) depositRate = 0.050 maturityDate = settlementDate.addMonths(1) depo = FinLiborDeposit(settlementDate, maturityDate, depositRate, dccType) depos.append(depo) maturityDate = settlementDate.addMonths(2) depo = FinLiborDeposit(settlementDate, maturityDate, depositRate, dccType) depos.append(depo) maturityDate = settlementDate.addMonths(3) depo = FinLiborDeposit(settlementDate, maturityDate, depositRate, dccType) depos.append(depo) maturityDate = settlementDate.addMonths(6) depo = FinLiborDeposit(settlementDate, maturityDate, depositRate, dccType) depos.append(depo) maturityDate = settlementDate.addMonths(9) depo = FinLiborDeposit(settlementDate, maturityDate, depositRate, dccType) depos.append(depo) maturityDate = settlementDate.addMonths(12) depo = FinLiborDeposit(settlementDate, maturityDate, depositRate, dccType) depos.append(depo) fras = [] # 1 x 4 FRA fraRate = 0.04 fraSettlementDate = settlementDate.addMonths(9) fraMaturityDate = settlementDate.addMonths(13) fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, dccType) fras.append(fra) # 4 x 7 FRA fraRate = 0.03 fraSettlementDate = settlementDate.addMonths(13) fraMaturityDate = settlementDate.addMonths(17) fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, dccType) fras.append(fra) # 4 x 7 FRA fraRate = 0.07 fraSettlementDate = settlementDate.addMonths(17) fraMaturityDate = settlementDate.addMonths(21) fra = FinLiborFRA(fraSettlementDate, fraMaturityDate, fraRate, dccType) fras.append(fra) swaps = [] fixedDCCType = FinDayCountTypes.ACT_365F fixedFreqType = FinFrequencyTypes.SEMI_ANNUAL swapRate = 0.05 # maturityDate = settlementDate.addMonths(24) # swap = FinLiborSwap(settlementDate, maturityDate, swapRate, fixedFreqType, # fixedDCCType) # swaps.append(swap) swapType = FinLiborSwapTypes.PAYER maturityDate = settlementDate.addMonths(36) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(48) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(60) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(72) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(84) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(96) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(108) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(120) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(132) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(144) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(180) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(240) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(300) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) maturityDate = settlementDate.addMonths(360) swap = FinLiborSwap(settlementDate, maturityDate, swapType, swapRate, fixedFreqType, fixedDCCType) swaps.append(swap) liborCurve = FinLiborCurve(valuationDate, depos, fras, swaps) df = liborCurve.df(settlementDate) testCases.header("SETTLEMENT DATE", "DF") testCases.print(str(settlementDate), df) testCases.header("DATE", "DF") for deposit in depos: df = liborCurve.df(deposit._maturityDate) testCases.print(str(deposit._maturityDate), df) for swap in swaps: df = liborCurve.df(swap._maturityDate) testCases.print(str(swap._maturityDate), df)
def test_FinFXAmericanOption(): # There is no FXAmericanOption class. It is embedded in the FXVanillaOption # class. This test just compares it to the European valueDate = FinDate(13, 2, 2018) expiryDate = FinDate(13, 2, 2019) # In BS the FX rate is the price in domestic of one unit of foreign # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR # DOM = USD , FOR = EUR ccy1 = "EUR" ccy2 = "USD" ccy1CCRate = 0.030 # EUR ccy2CCRate = 0.025 # USD currencyPair = ccy1 + ccy2 # Always ccy1ccy2 spotFXRate = 1.20 strikeFXRate = 1.250 volatility = 0.10 domDiscountCurve = FinDiscountCurveFlat(valueDate, ccy2CCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, ccy1CCRate) model = FinFXModelBlackScholes(volatility) # Two examples to show that changing the notional currency and notional # keeps the value unchanged testCases.header("SPOT FX RATE", "VALUE_BS", "VOL_IN", "IMPLD_VOL") spotFXRates = np.arange(50, 200, 10) / 100.0 for spotFXRate in spotFXRates: callOption = FinFXVanillaOption(expiryDate, strikeFXRate, currencyPair, FinOptionTypes.EUROPEAN_CALL, 1000000, "USD") valueEuropean = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model)['v'] callOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.AMERICAN_CALL, 1000000, "USD") valueAmerican = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model)['v'] diff = (valueAmerican - valueEuropean) testCases.print(spotFXRate, valueEuropean, valueAmerican, diff) for spotFXRate in spotFXRates: callOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.EUROPEAN_PUT, 1000000, "USD") valueEuropean = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model)['v'] callOption = FinFXVanillaOption(expiryDate, strikeFXRate, "EURUSD", FinOptionTypes.AMERICAN_PUT, 1000000, "USD") valueAmerican = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model)['v'] diff = (valueAmerican - valueEuropean) testCases.print(spotFXRate, valueEuropean, valueAmerican, diff)
def test_derivativePricingExample(): valuationDate = FinDate(10, 11, 2011) dccType = FinDayCountTypes.ACT_360 depos = [] # We do the O/N rate which settles on trade date spotDays = 0 settlementDate = valuationDate.addWorkDays(spotDays) depositRate = 0.001410 depo = FinLiborDeposit(settlementDate, "ON", depositRate, dccType) depos.append(depo) spotDays = 1 settlementDate = valuationDate.addWorkDays(spotDays) depositRate = 0.001410 depo = FinLiborDeposit(settlementDate, "TN", depositRate, dccType) depos.append(depo) spotDays = 2 settlementDate = valuationDate.addWorkDays(spotDays) depositRate = 0.001910 depo = FinLiborDeposit(settlementDate, "1W", depositRate, dccType) depos.append(depo) depositRate = 0.002090 depo = FinLiborDeposit(settlementDate, "2W", depositRate, dccType) depos.append(depo) depositRate = 0.002490 depo = FinLiborDeposit(settlementDate, "1M", depositRate, dccType) depos.append(depo) depositRate = 0.003450 depo = FinLiborDeposit(settlementDate, "2M", depositRate, dccType) depos.append(depo) depositRate = 0.004570 depo = FinLiborDeposit(settlementDate, "3M", depositRate, dccType) depos.append(depo) depositRate = 0.005230 depo = FinLiborDeposit(settlementDate, "4M", depositRate, dccType) depos.append(depo) depositRate = 0.005860 depo = FinLiborDeposit(settlementDate, "5M", depositRate, dccType) depos.append(depo) depositRate = 0.006540 depo = FinLiborDeposit(settlementDate, "6M", depositRate, dccType) depos.append(depo) depositRate = 0.007080 depo = FinLiborDeposit(settlementDate, "7M", depositRate, dccType) depos.append(depo) depositRate = 0.007540 depo = FinLiborDeposit(settlementDate, "8M", depositRate, dccType) depos.append(depo) depositRate = 0.008080 depo = FinLiborDeposit(settlementDate, "9M", depositRate, dccType) depos.append(depo) depositRate = 0.008570 depo = FinLiborDeposit(settlementDate, "10M", depositRate, dccType) depos.append(depo) depositRate = 0.009130 depo = FinLiborDeposit(settlementDate, "11M", depositRate, dccType) depos.append(depo) fras = [] swaps = [] dayCountType = FinDayCountTypes.THIRTY_E_360_ISDA # dayCountType = FinDayCountTypes.ACT_360 freqType = FinFrequencyTypes.SEMI_ANNUAL swapType = FinLiborSwapTypes.PAYER swapRate = 0.0058 swap = FinLiborSwap(settlementDate, "1Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) swapRate = 0.0060 swap = FinLiborSwap(settlementDate, "2Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) swapRate = 0.0072 swap = FinLiborSwap(settlementDate, "3Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) swapRate = 0.0096 swap = FinLiborSwap(settlementDate, "4Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) swapRate = 0.0124 swap = FinLiborSwap(settlementDate, "5Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) swapRate = 0.0173 swap = FinLiborSwap(settlementDate, "7Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) swapRate = 0.0219 swap = FinLiborSwap(settlementDate, "10Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) swapRate = 0.0283 swap = FinLiborSwap(settlementDate, "30Y", swapType, swapRate, freqType, dayCountType) swaps.append(swap) numRepeats = 10 start = time.time() for _ in range(0, numRepeats): _ = FinLiborCurve(valuationDate, depos, fras, swaps, FinInterpTypes.FLAT_FORWARDS) end = time.time() elapsed1 = end - start start = time.time() for _ in range(0, numRepeats): _ = FinLiborCurve(valuationDate, depos, fras, swaps, FinInterpTypes.LINEAR_SWAP_RATES) end = time.time() elapsed2 = end - start testCases.header("METHOD", "TIME") testCases.print("NON-LINEAR SOLVER BOOTSTRAP", elapsed1 / numRepeats) testCases.print("LINEAR SWAP BOOTSTRAP", elapsed2 / numRepeats)
def test_FinIborCapFloorVolCurve(): ''' Aim here is to price cap and caplets using cap and caplet vols and to demonstrate they are the same - NOT SURE THAT HULLS BOOKS FORMULA WORKS FOR OPTIONS. ''' todayDate = FinDate(20, 6, 2019) valuationDate = todayDate maturityDate = valuationDate.addTenor("3Y") dayCountType = FinDayCountTypes.THIRTY_E_360 frequency = FinFrequencyTypes.ANNUAL k = 0.04 capFloorType = FinCapFloorTypes.CAP capFloor = FinIborCapFloor(valuationDate, maturityDate, capFloorType, k, None, frequency, dayCountType) capVolDates = FinSchedule(valuationDate, valuationDate.addTenor("10Y"), frequency)._generate() flatRate = 0.04 liborCurve = FinDiscountCurveFlat(valuationDate, flatRate, frequency, dayCountType) flat = False if flat is True: capVolatilities = [20.0] * 11 capVolatilities[0] = 0.0 else: capVolatilities = [ 0.00, 15.50, 18.25, 17.91, 17.74, 17.27, 16.79, 16.30, 16.01, 15.76, 15.54 ] capVolatilities = np.array(capVolatilities) / 100.0 capVolatilities[0] = 0.0 volCurve = FinIborCapVolCurve(valuationDate, capVolDates, capVolatilities, dayCountType) # print(volCurve._capletGammas) # Value cap using a single flat cap volatility tcap = (maturityDate - valuationDate) / gDaysInYear vol = volCurve.capVol(maturityDate) model = FinModelBlack(vol) valueCap = capFloor.value(valuationDate, liborCurve, model) # print("CAP T", tcap, "VOL:", vol, "VALUE OF CAP:", valueCap) # Value cap by breaking it down into caplets using caplet vols vCaplets = 0.0 capletStartDate = capFloor._capFloorLetDates[1] testCases.header("START", "END", "VOL", "VALUE") for capletEndDate in capFloor._capFloorLetDates[2:]: vol = volCurve.capletVol(capletEndDate) modelCaplet = FinModelBlack(vol) vCaplet = capFloor.valueCapletFloorLet(valuationDate, capletStartDate, capletEndDate, liborCurve, modelCaplet) vCaplets += vCaplet testCases.print("%12s" % capletStartDate, "%s" % capletEndDate, "%9.5f" % (vol * 100.0), "%9.5f" % vCaplet) capletStartDate = capletEndDate testCases.header("LABEL", "VALUE") testCases.print("CAPLETS->CAP: ", vCaplets)
def test_FinSwaptionVolSurface1(verboseCalibration): ########################################################################### if 1 == 1: # https://fr.mathworks.com/help/fininst/pricing-a-swaption-using-the-sabr-model.html valueDate = FinDate(12, 6, 2013) # These are 3M, 1Y, 2Y, 3Y, 4Y, 5Y, 7Y, 10Y exerciseDates = [ FinDate(12, 9, 2013), FinDate(12, 6, 2014), FinDate(12, 6, 2015), FinDate(12, 6, 2016), FinDate(12, 6, 2017), FinDate(12, 6, 2018), FinDate(12, 6, 2020), FinDate(12, 6, 2023) ] # First dimension is the strike, then the expiry date marketVolatilities = [[57.6, 53.7, 49.4, 45.6, 44.1, 41.1, 35.2, 32.0], [46.6, 46.9, 44.8, 41.6, 39.8, 37.4, 33.4, 31.0], [35.9, 39.3, 39.6, 37.9, 37.2, 34.7, 30.5, 28.9], [34.1, 36.5, 37.8, 36.6, 35.0, 31.9, 28.1, 26.6], [41.0, 41.3, 39.5, 37.8, 36.0, 32.6, 29.0, 26.0], [45.8, 43.4, 41.9, 39.2, 36.9, 33.2, 29.6, 26.3], [50.3, 46.9, 44.0, 40.0, 37.5, 33.8, 30.2, 27.3]] marketVolatilities = np.array(marketVolatilities) / 100.0 # First dimension is the strike, then the expiry date marketStrikes = [[1.00, 1.25, 1.68, 2.00, 2.26, 2.41, 2.58, 2.62], [1.50, 1.75, 2.18, 2.50, 2.76, 2.91, 3.08, 3.12], [2.00, 2.25, 2.68, 3.00, 3.26, 3.41, 3.58, 3.62], [2.50, 2.75, 3.18, 3.50, 3.76, 3.91, 4.08, 4.12], [3.00, 3.25, 3.68, 4.00, 4.26, 4.41, 4.58, 4.62], [3.50, 3.75, 4.18, 4.50, 4.76, 4.91, 5.08, 5.12], [4.00, 4.25, 4.68, 5.00, 5.26, 5.41, 5.58, 5.62]] marketStrikes = np.array(marketStrikes) / 100.0 fwdSwapRates = marketStrikes[3] atmVols = marketVolatilities[3] rfrRate = 0.020 # USD discountCurve = FinDiscountCurveFlat(valueDate, rfrRate) divRate = 0.010 # USD dividendCurve = FinDiscountCurveFlat(valueDate, divRate) volFunctionType = FinVolFunctionTypes.SABR_BETA_HALF swaptionSurface = FinSwaptionVolSurface(valueDate, exerciseDates, fwdSwapRates, marketStrikes, marketVolatilities, volFunctionType) tol = 1e-4 swaptionSurface.checkCalibration(False, tol) if 1 == 1: # PLOT_GRAPHS: swaptionSurface.plotVolCurves()
def test_FinIborCapFloorQLExample(): valuationDate = FinDate(14, 6, 2016) dates = [ FinDate(14, 6, 2016), FinDate(14, 9, 2016), FinDate(14, 12, 2016), FinDate(14, 6, 2017), FinDate(14, 6, 2019), FinDate(14, 6, 2021), FinDate(15, 6, 2026), FinDate(16, 6, 2031), FinDate(16, 6, 2036), FinDate(14, 6, 2046) ] rates = [ 0.000000, 0.006616, 0.007049, 0.007795, 0.009599, 0.011203, 0.015068, 0.017583, 0.018998, 0.020080 ] freqType = FinFrequencyTypes.ANNUAL dayCountType = FinDayCountTypes.ACT_ACT_ISDA discountCurve = FinDiscountCurveZeros(valuationDate, dates, rates, freqType, dayCountType, FinInterpTypes.LINEAR_ZERO_RATES) startDate = FinDate(14, 6, 2016) endDate = FinDate(14, 6, 2026) calendarType = FinCalendarTypes.US busDayAdjustType = FinBusDayAdjustTypes.MODIFIED_FOLLOWING freqType = FinFrequencyTypes.QUARTERLY dateGenRuleType = FinDateGenRuleTypes.FORWARD lastFixing = 0.0065560 notional = 1000000 dayCountType = FinDayCountTypes.ACT_360 optionType = FinCapFloorTypes.CAP strikeRate = 0.02 cap = FinIborCapFloor(startDate, endDate, optionType, strikeRate, lastFixing, freqType, dayCountType, notional, calendarType, busDayAdjustType, dateGenRuleType) blackVol = 0.547295 model = FinModelBlack(blackVol) start = time.time() numRepeats = 10 for i in range(0, numRepeats): v = cap.value(valuationDate, discountCurve, model) end = time.time() period = end - start
def test_FinNelsonSiegelCurve(): tau = 2.0 times = np.linspace(0.0, 10.0, 5) curveDate = FinDate(6, 6, 2019) dates = curveDate.addYears(times) curve1 = FinDiscountCurveNS(curveDate, 1, 0, 0, tau) factor1loading = curve1.zeroRate(dates) curve2 = FinDiscountCurveNS(curveDate, 0, 1, 0, tau) factor2loading = curve2.zeroRate(dates) curve3 = FinDiscountCurveNS(curveDate, 0, 0, 1, tau) factor3loading = curve3.zeroRate(dates) testCases.header("FACTOR LOADING ON ZERO RATES") testCases.print(factor1loading) testCases.print(factor2loading) testCases.print(factor3loading) if PLOT_GRAPHS: plt.figure(figsize=(6, 4)) plt.plot(times, scale(factor1loading, 1), label='beta1') plt.plot(times, scale(factor2loading, 1), label='beta2') plt.plot(times, scale(factor3loading, 1), label='beta3') plt.ylim((0, 1.05)) plt.title('Factor Loadings in Nelson-Siegel Model') plt.xlabel('Time (years)') plt.ylabel('Loading') plt.legend(loc='best') ########################################################################### testCases.header("BETA1", "BETA2", "BETA3", "ZEROS") beta1 = 0.03 beta2 = -0.02 beta3 = 0.02 curve1 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates1 = curve1.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates1) beta1 = 0.04 beta2 = -0.02 beta3 = 0.02 curve2 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates2 = curve2.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates2) beta1 = 0.05 beta2 = -0.02 beta3 = 0.02 curve3 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates3 = curve3.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates3) beta1 = 0.06 beta2 = -0.02 beta3 = 0.02 curve4 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates4 = curve4.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates4) beta1 = 0.07 beta2 = -0.02 beta3 = 0.02 curve5 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates5 = curve5.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates5) if PLOT_GRAPHS: plt.figure(figsize=(6, 4)) plt.plot(times, scale(zeroRates1, 100), label='beta1=3%') plt.plot(times, scale(zeroRates2, 100), label='beta1=4%') plt.plot(times, scale(zeroRates3, 100), label='beta1=5%') plt.plot(times, scale(zeroRates4, 100), label='beta1=6%') plt.plot(times, scale(zeroRates5, 100), label='beta1=7%') plt.ylim((0, 7.5)) plt.title('Nelson-Siegel Zero Rate Curves') plt.xlabel('Time (years)') plt.ylabel('Zero Rate (%)') plt.legend(loc='lower right', frameon=False) ########################################################################### beta1 = 0.06 beta2 = -0.04 beta3 = 0.02 curve1 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates1 = curve1.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates1) beta1 = 0.06 beta2 = -0.02 beta3 = 0.02 curve2 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates2 = curve2.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates2) beta1 = 0.06 beta2 = 0.00 beta3 = 0.02 curve3 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates3 = curve3.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates3) beta1 = 0.06 beta2 = 0.02 beta3 = 0.02 curve4 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates4 = curve4.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates4) beta1 = 0.06 beta2 = 0.04 beta3 = 0.02 curve5 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates5 = curve5.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates5) if PLOT_GRAPHS: plt.figure(figsize=(6, 4)) plt.plot(times, scale(zeroRates1, 100), label='beta2=-4%') plt.plot(times, scale(zeroRates2, 100), label='beta2=-2%') plt.plot(times, scale(zeroRates3, 100), label='beta2=0%') plt.plot(times, scale(zeroRates4, 100), label='beta2=2%') plt.plot(times, scale(zeroRates5, 100), label='beta2=4%') plt.ylim((0, 10)) plt.title('Nelson-Siegel Zero Rate Curves: Varying beta2') plt.xlabel('Time (years)') plt.ylabel('Zero Rate (%)') plt.legend(loc='lower right', frameon=False) beta1 = 0.06 beta2 = -0.02 beta3 = -0.02 curve1 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates1 = curve1.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates1) beta1 = 0.06 beta2 = -0.02 beta3 = 0.00 curve2 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates2 = curve2.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates2) beta1 = 0.06 beta2 = -0.02 beta3 = 0.02 curve3 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates3 = curve3.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates3) beta1 = 0.06 beta2 = -0.02 beta3 = 0.04 curve4 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates4 = curve4.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates4) beta1 = 0.06 beta2 = -0.02 beta3 = 0.06 curve5 = FinDiscountCurveNS(curveDate, beta1, beta2, beta3, tau) zeroRates5 = curve5.zeroRate(dates) testCases.print(beta1, beta2, beta3, zeroRates5) if PLOT_GRAPHS: plt.figure(figsize=(6, 4)) plt.plot(times, scale(zeroRates1, 100), label='beta3=-2%') plt.plot(times, scale(zeroRates2, 100), label='beta3=0%') plt.plot(times, scale(zeroRates3, 100), label='beta3=2%') plt.plot(times, scale(zeroRates4, 100), label='beta3=4%') plt.plot(times, scale(zeroRates5, 100), label='beta3=6%') plt.ylim((3.5, 7.5)) plt.title('Nelson-Siegel Zero Rate Curves: Varying beta3') plt.xlabel('Time (years)') plt.ylabel('Zero Rate (%)') plt.legend(loc='lower right', frameon=False)
def test_FinIborCapFloor(): todayDate = FinDate(20, 6, 2019) valuationDate = todayDate startDate = todayDate.addWeekDays(2) maturityDate = startDate.addTenor("1Y") liborCurve = test_FinIborDepositsAndSwaps(todayDate) # The capfloor has begun # lastFixing = 0.028 ########################################################################## # COMPARISON OF MODELS ########################################################################## strikes = np.linspace(0.02, 0.08, 5) testCases.header("LABEL", "STRIKE", "BLK", "BLK_SHFTD", "SABR", "SABR_SHFTD", "HW", "BACH") model1 = FinModelBlack(0.20) model2 = FinModelBlackShifted(0.25, 0.0) model3 = FinModelSABR(0.013, 0.5, 0.5, 0.5) model4 = FinModelSABRShifted(0.013, 0.5, 0.5, 0.5, -0.008) model5 = FinModelRatesHW(0.30, 0.01) model6 = FinModelBachelier(0.01) for k in strikes: capFloorType = FinCapFloorTypes.CAP capfloor = FinIborCapFloor(startDate, maturityDate, capFloorType, k) cvalue1 = capfloor.value(valuationDate, liborCurve, model1) cvalue2 = capfloor.value(valuationDate, liborCurve, model2) cvalue3 = capfloor.value(valuationDate, liborCurve, model3) cvalue4 = capfloor.value(valuationDate, liborCurve, model4) cvalue5 = capfloor.value(valuationDate, liborCurve, model5) cvalue6 = capfloor.value(valuationDate, liborCurve, model6) testCases.print("CAP", k, cvalue1, cvalue2, cvalue3, cvalue4, cvalue5, cvalue6) testCases.header("LABEL", "STRIKE", "BLK", "BLK_SHFTD", "SABR", "SABR_SHFTD", "HW", "BACH") for k in strikes: capFloorType = FinCapFloorTypes.FLOOR capfloor = FinIborCapFloor(startDate, maturityDate, capFloorType, k) fvalue1 = capfloor.value(valuationDate, liborCurve, model1) fvalue2 = capfloor.value(valuationDate, liborCurve, model2) fvalue3 = capfloor.value(valuationDate, liborCurve, model3) fvalue4 = capfloor.value(valuationDate, liborCurve, model4) fvalue5 = capfloor.value(valuationDate, liborCurve, model5) fvalue6 = capfloor.value(valuationDate, liborCurve, model6) testCases.print("FLR", k, fvalue1, fvalue2, fvalue3, fvalue4, fvalue5, fvalue6) ############################################################################### # PUT CALL CHECK ############################################################################### testCases.header("LABEL", "STRIKE", "BLK", "BLK_SHFTD", "SABR", "SABR SHFTD", "HW", "BACH") for k in strikes: capFloorType = FinCapFloorTypes.CAP capfloor = FinIborCapFloor(startDate, maturityDate, capFloorType, k) cvalue1 = capfloor.value(valuationDate, liborCurve, model1) cvalue2 = capfloor.value(valuationDate, liborCurve, model2) cvalue3 = capfloor.value(valuationDate, liborCurve, model3) cvalue4 = capfloor.value(valuationDate, liborCurve, model4) cvalue5 = capfloor.value(valuationDate, liborCurve, model5) cvalue6 = capfloor.value(valuationDate, liborCurve, model6) capFloorType = FinCapFloorTypes.FLOOR capfloor = FinIborCapFloor(startDate, maturityDate, capFloorType, k) fvalue1 = capfloor.value(valuationDate, liborCurve, model1) fvalue2 = capfloor.value(valuationDate, liborCurve, model2) fvalue3 = capfloor.value(valuationDate, liborCurve, model3) fvalue4 = capfloor.value(valuationDate, liborCurve, model4) fvalue5 = capfloor.value(valuationDate, liborCurve, model5) fvalue6 = capfloor.value(valuationDate, liborCurve, model6) pcvalue1 = cvalue1 - fvalue1 pcvalue2 = cvalue2 - fvalue2 pcvalue3 = cvalue3 - fvalue3 pcvalue4 = cvalue4 - fvalue4 pcvalue5 = cvalue5 - fvalue5 pcvalue6 = cvalue6 - fvalue6 testCases.print("PUT_CALL", k, pcvalue1, pcvalue2, pcvalue3, pcvalue4, pcvalue5, pcvalue6)
def test_FinEquityVanillaOption(): valueDate = FinDate(2015, 1, 1) expiryDate = FinDate(2015, 7, 1) stockPrice = 100 volatility = 0.30 interestRate = 0.05 dividendYield = 0.01 model = FinEquityModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) numPathsList = [10000, 20000, 40000, 80000, 160000, 320000] testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") for numPaths in numPathsList: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) start = time.time() valueMC = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC, duration) ############################################################################### stockPrices = range(80, 120, 10) numPaths = 100000 testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") useSobol = True for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) start = time.time() useSobol = False valueMC1 = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, useSobol) useSobol = True valueMC2 = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, useSobol) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC, duration) ############################################################################### stockPrices = range(80, 120, 10) numPaths = 100000 testCases.header("STOCK PRICE", "VALUE_BS", "VALUE_MC", "TIME") for stockPrice in stockPrices: putOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) start = time.time() valueMC = putOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths) end = time.time() duration = end - start testCases.print(stockPrice, value, valueMC, duration) ############################################################################### stockPrices = range(80, 120, 10) testCases.header("STOCK PRICE", "VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) delta = callOption.delta(valueDate, stockPrice, discountCurve, dividendYield, model) vega = callOption.vega(valueDate, stockPrice, discountCurve, dividendYield, model) theta = callOption.theta(valueDate, stockPrice, discountCurve, dividendYield, model) # callOption.rho(valueDate,stockPrice, interestRate, dividendYield, modelType, modelParams) rho = 999 testCases.print(stockPrice, value, delta, vega, theta, rho) testCases.header("STOCK PRICE", "VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for stockPrice in stockPrices: putOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) delta = putOption.delta(valueDate, stockPrice, discountCurve, dividendYield, model) vega = putOption.vega(valueDate, stockPrice, discountCurve, dividendYield, model) theta = putOption.theta(valueDate, stockPrice, discountCurve, dividendYield, model) # putOption.rho(valueDate,stockPrice, interestRate, dividendYield, # modelType, modelParams) rho = 999 testCases.print(stockPrice, value, delta, vega, theta, rho) ############################################################################### testCases.header("STOCK PRICE", "VALUE_BS", "VOL_IN", "IMPLD_VOL") stockPrices = range(60, 150, 10) for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) impliedVol = callOption.impliedVolatility(valueDate, stockPrice, discountCurve, dividendYield, value) testCases.print(stockPrice, value, volatility, impliedVol)
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 frequencyType = 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, frequencyType, 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))