def test_FinInterpolatedForwards(): import matplotlib.pyplot as plt tValues = np.array([0.0, 3.0, 5.0, 10.0]) rValues = np.array([0.04, 0.07, 0.08, 0.09]) df_values = np.exp(-tValues*rValues) tInterpValues = np.linspace(0.0, 12.0, 49) curve_date = Date(1, 1, 2019) tDates = curve_date.add_years(tValues) tInterpDates = curve_date.add_years(tInterpValues) for interp_type in InterpTypes: discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) fwdInterpValues = discount_curve.fwd(tInterpDates) zeroInterpValues = discount_curve.zero_rate(tInterpDates) if PLOT_GRAPHS: plt.figure(figsize=(8, 6)) plt.plot(tValues, df_values, 'o', color='g', label="DFS:") plt.plot(tInterpValues, dfInterpValues, color='r', label="DF:" + str(interp_type)) plt.legend() plt.figure(figsize=(8, 6)) plt.plot(tInterpValues, fwdInterpValues, color='r', label="FWD:" + str(interp_type)) plt.plot(tInterpValues, zeroInterpValues, color='b', label="ZERO:" + str(interp_type)) plt.plot(tValues, rValues, 'o', color='g', label="ZERO RATES") plt.legend()
def test_CDSFastApproximation(): valuation_date = Date(20, 6, 2018) # I build a discount curve that requires no bootstrap times = np.linspace(0, 10.0, 11) r = 0.05 discount_factors = np.power((1.0 + r), -times) dates = valuation_date.add_years(times) libor_curve = DiscountCurve(valuation_date, dates, discount_factors, InterpTypes.FLAT_FWD_RATES) ########################################################################## maturity_date = valuation_date.next_cds_date(120) t = (maturity_date - valuation_date) / 365.242 z = libor_curve.df(maturity_date) r = -np.log(z) / t recovery_rate = 0.40 contractCoupon = 0.010 testCases.header("MKT_SPD", "EXACT_VALUE", "APPROX_VALUE", "DIFF(%NOT)") for mktCoupon in np.linspace(0.000, 0.05, 21): cds_contracts = [] cdsMkt = CDS(valuation_date, maturity_date, mktCoupon, ONE_MILLION) cds_contracts.append(cdsMkt) issuer_curve = CDSCurve(valuation_date, cds_contracts, libor_curve, recovery_rate) cds_contract = CDS(valuation_date, maturity_date, contractCoupon) v_exact = cds_contract.value(valuation_date, issuer_curve, recovery_rate)['full_pv'] v_approx = cds_contract.value_fast_approx(valuation_date, r, mktCoupon, recovery_rate)[0] pctdiff = (v_exact - v_approx) / ONE_MILLION * 100.0 testCases.print(mktCoupon * 10000, v_exact, v_approx, pctdiff)
def test_IssuerCurveBuild(): """ Test issuer curve build with simple libor curve to isolate cds curve building time cost. """ valuation_date = Date(20, 6, 2018) times = np.linspace(0.0, 10.0, 11) r = 0.05 discount_factors = np.power((1.0 + r), -times) dates = valuation_date.add_years(times) libor_curve = DiscountCurve(valuation_date, dates, discount_factors, InterpTypes.FLAT_FWD_RATES) recovery_rate = 0.40 cds_contracts = [] cdsCoupon = 0.005 # 50 bps maturity_date = valuation_date.add_months(12) cds = CDS(valuation_date, maturity_date, cdsCoupon) cds_contracts.append(cds) cdsCoupon = 0.0055 maturity_date = valuation_date.add_months(24) cds = CDS(valuation_date, maturity_date, cdsCoupon) cds_contracts.append(cds) cdsCoupon = 0.0060 maturity_date = valuation_date.add_months(36) cds = CDS(valuation_date, maturity_date, cdsCoupon) cds_contracts.append(cds) cdsCoupon = 0.0065 maturity_date = valuation_date.add_months(60) cds = CDS(valuation_date, maturity_date, cdsCoupon) cds_contracts.append(cds) cdsCoupon = 0.0070 maturity_date = valuation_date.add_months(84) cds = CDS(valuation_date, maturity_date, cdsCoupon) cds_contracts.append(cds) cdsCoupon = 0.0073 maturity_date = valuation_date.add_months(120) cds = CDS(valuation_date, maturity_date, cdsCoupon) cds_contracts.append(cds) issuer_curve = CDSCurve(valuation_date, cds_contracts, libor_curve, recovery_rate) return cds_contracts, issuer_curve
def test_BondOption(): settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) tmat = (maturity_date - settlement_date) / gDaysInYear times = np.linspace(0, tmat, 20) dates = settlement_date.add_years(times) dfs = np.exp(-0.05*times) discount_curve = DiscountCurve(settlement_date, dates, dfs) expiry_date = settlement_date.add_tenor("18m") strike_price = 105.0 face = 100.0 ########################################################################### strikes = [80, 85, 90, 95, 100, 105, 110, 115, 120] option_type = OptionTypes.EUROPEAN_CALL testCases.header("LABEL", "VALUE") price = bond.full_price_from_discount_curve( settlement_date, discount_curve) testCases.print("Fixed Income Price:", price) num_time_steps = 20 testCases.header("OPTION TYPE AND MODEL", "STRIKE", "VALUE") for strike_price in strikes: sigma = 0.20 a = 0.1 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a, num_time_steps) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("EUROPEAN CALL - BK", strike_price, v) for strike_price in strikes: sigma = 0.20 a = 0.05 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a, num_time_steps) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("EUROPEAN CALL - BK", strike_price, v) ########################################################################### option_type = OptionTypes.AMERICAN_CALL price = bond.full_price_from_discount_curve( settlement_date, discount_curve) testCases.header("LABEL", "VALUE") testCases.print("Fixed Income Price:", price) testCases.header("OPTION TYPE AND MODEL", "STRIKE", "VALUE") for strike_price in strikes: sigma = 0.01 a = 0.1 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("AMERICAN CALL - BK", strike_price, v) for strike_price in strikes: sigma = 0.20 a = 0.05 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("AMERICAN CALL - BK", strike_price, v) ########################################################################### option_type = OptionTypes.EUROPEAN_PUT price = bond.full_price_from_discount_curve( settlement_date, discount_curve) for strike_price in strikes: sigma = 0.01 a = 0.1 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("EUROPEAN PUT - BK", strike_price, v) for strike_price in strikes: sigma = 0.20 a = 0.05 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("EUROPEAN PUT - BK", strike_price, v) ########################################################################### option_type = OptionTypes.AMERICAN_PUT price = bond.full_price_from_discount_curve( settlement_date, discount_curve) for strike_price in strikes: sigma = 0.02 a = 0.1 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("AMERICAN PUT - BK", strike_price, v) for strike_price in strikes: sigma = 0.20 a = 0.05 bond_option = BondOption( bond, expiry_date, strike_price, face, option_type) model = BKTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print("AMERICAN PUT - BK", strike_price, v)
def test_BKExampleTwo(): # Valuation of a European option on a coupon bearing bond # This follows example in Fig 28.11 of John Hull's book but does not # have the exact same dt so there are some differences settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) expiry_date = settlement_date.add_tenor("18m") maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency num_flows = len(bond._flow_dates) for i in range(1, num_flows): pcd = bond._flow_dates[i - 1] ncd = bond._flow_dates[i] if pcd < settlement_date and ncd > settlement_date: flow_time = (pcd - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) for flow_date in bond._flow_dates: if flow_date > settlement_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) strike_price = 105.0 face = 100.0 tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear times = np.linspace(0, tmat, 11) dates = settlement_date.add_years(times) dfs = np.exp(-0.05 * times) curve = DiscountCurve(settlement_date, dates, dfs) price = bond.clean_price_from_discount_curve(settlement_date, curve) testCases.header("LABEL", "VALUE") testCases.print("Fixed Income Price:", price) sigma = 0.20 a = 0.05 num_time_steps = 26 model = BKTree(sigma, a, num_time_steps) model.build_tree(tmat, times, dfs) exercise_type = FinExerciseTypes.AMERICAN v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) # Test convergence num_steps_list = [100, 200, 300, 500, 1000] exercise_type = FinExerciseTypes.AMERICAN testCases.header("TIMESTEPS", "TIME", "VALUE") treeVector = [] for num_time_steps in num_steps_list: start = time.time() model = BKTree(sigma, a, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) end = time.time() period = end - start treeVector.append(v) testCases.print(num_time_steps, period, v) # plt.plot(num_steps_list, treeVector) # Value in Hill converges to 0.699 with 100 time steps while I get 0.700 if 1 == 0: print("RT") print_tree(model._rt, 5) print("Q") print_tree(model._Q, 5)
def test_BKExampleTwo(): # Valuation of a European option on a coupon bearing bond # This follows example in Fig 28.11 of John Hull's book but does not # have the exact same dt so there are some differences settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) expiry_date = settlement_date.add_tenor("18m") maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency num_flows = len(bond._coupon_dates) for i in range(1, num_flows): pcd = bond._coupon_dates[i - 1] ncd = bond._coupon_dates[i] if pcd < settlement_date and ncd > settlement_date: flow_time = (pcd - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) for flow_date in bond._coupon_dates: if flow_date > settlement_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) strike_price = 105.0 face = 100.0 tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear times = np.linspace(0, tmat, 11) dates = settlement_date.add_years(times) dfs = np.exp(-0.05 * times) curve = DiscountCurve(settlement_date, dates, dfs) price = bond.clean_price_from_discount_curve(settlement_date, curve) assert round(price, 4) == 99.5420 sigma = 0.20 a = 0.05 num_time_steps = 26 model = BKTree(sigma, a, num_time_steps) model.build_tree(tmat, times, dfs) exercise_type = FinExerciseTypes.AMERICAN v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) # Test convergence num_time_steps = 200 exercise_type = FinExerciseTypes.AMERICAN treeVector = [] model = BKTree(sigma, a, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) treeVector.append(v) assert round(v['call'], 4) == 0.6998 assert round(v['put'], 4) == 7.9605
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() settlement_date = Date(1, 1, 2020) times = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]) dates = settlement_date.add_years(times) rate = 0.06 dfs = 1.0 / (1.0 + rate / 2.0)**(2.0 * times) curve = DiscountCurve(settlement_date, dates, dfs) coupon = 0.06 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA strike_price = 100.0 face = 100.0 # Andersen paper num_time_steps = 200 testCases.header("ExerciseType", "Sigma", "NumSteps", "Texp", "Tmat", "V_Fixed", "V_pay", "V_rec") for exercise_type in [ FinExerciseTypes.EUROPEAN, FinExerciseTypes.BERMUDAN ]: for years_to_maturity in [4.0, 5.0, 10.0, 20.0]: maturity_date = settlement_date.add_years(years_to_maturity) issue_date = Date(maturity_date._d, maturity_date._m, 2000) if years_to_maturity == 4.0 or years_to_maturity == 5.0: sigma = 0.2012 elif years_to_maturity == 10.0: sigma = 0.1522 elif years_to_maturity == 20.0: sigma = 0.1035 for expiryYears in range( int(years_to_maturity / 2) - 1, int(years_to_maturity)): expiry_date = settlement_date.add_years(expiryYears) tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency for flow_date in bond._flow_dates: if flow_date > expiry_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) price = bond.clean_price_from_discount_curve( settlement_date, curve) model = BDTTree(sigma, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bermudan_swaption(texp, tmat, strike_price, face, coupon_times, coupon_flows, exercise_type) testCases.print("%s" % exercise_type, "%9.5f" % sigma, "%9.5f" % num_time_steps, "%9.5f" % expiryYears, "%9.5f" % years_to_maturity, "%9.5f" % price, "%9.2f" % (v['pay'] * 100.0), "%9.2f" % (v['rec'] * 100.0))
def test_FinDiscountCurve(): # Create a curve from times and discount factors start_date = Date(1, 1, 2018) years = np.linspace(0, 10, 6) rate = 0.05 + 0.005*years - 0.0003*years*years dfs = np.exp(-rate * years) dates = start_date.add_years(years) curve = DiscountCurve(start_date, dates, dfs, InterpTypes.FLAT_FWD_RATES) testCases.header("T", "DF", "ZERORATE", "CC_FWD", "MM_FWD", "SURVPROB") plotYears = np.linspace(0, 12, 12*12+1)[1:] plotDates = start_date.add_years(plotYears) # Examine dependency of curve on compounding rate zero_rates_A = curve.zero_rate(plotDates, FrequencyTypes.ANNUAL) zero_rates_S = curve.zero_rate(plotDates, FrequencyTypes.SEMI_ANNUAL) zero_rates_Q = curve.zero_rate(plotDates, FrequencyTypes.QUARTERLY) zero_rates_M = curve.zero_rate(plotDates, FrequencyTypes.MONTHLY) zero_rates_C = curve.zero_rate(plotDates, FrequencyTypes.CONTINUOUS) if PLOT_GRAPHS: plt.figure(figsize=(6, 4)) plt.plot(plotYears, scale(zero_rates_A, 100), label='A') plt.plot(plotYears, scale(zero_rates_S, 100), label='S') plt.plot(plotYears, scale(zero_rates_Q, 100), label='Q') plt.plot(plotYears, scale(zero_rates_M, 100), label='M') plt.plot(plotYears, scale(zero_rates_C, 100), label='C') plt.ylim((5, 8)) plt.title('Discount Curves') plt.xlabel('Time (years)') plt.ylabel('Zero Rate (%)') plt.legend(loc='lower right', frameon=False) # Examine dependency of fwd curve on the interpolation scheme for interp in InterpTypes: curve = DiscountCurve(start_date, dates, dfs, interp) fwd_rates = curve.fwd(plotDates) zero_rates = curve.zero_rate(plotDates, FrequencyTypes.ANNUAL) parRates = curve.swap_rate( start_date, plotDates, FrequencyTypes.ANNUAL) if PLOT_GRAPHS: plt.figure(figsize=(6, 4)) plt.plot(plotYears, scale(fwd_rates, 100), label='FWD RATES') plt.plot(plotYears, scale(zero_rates, 100), label='ZERO RATES') plt.plot(plotYears, scale(parRates, 100), label='PAR RATES') plt.ylim((3.0, 8.5)) plt.title('Forward Curves using ' + str(interp)) plt.xlabel('Time (years)') plt.ylabel('Fwd Rate (%)') plt.legend(loc='lower right', frameon=False)
from financepy.utils.date import Date import numpy as np settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) tmat = (maturity_date - settlement_date) / gDaysInYear times = np.linspace(0, tmat, 20) dates = settlement_date.add_years(times) dfs = np.exp(-0.05 * times) discount_curve = DiscountCurve(settlement_date, dates, dfs) expiry_date = settlement_date.add_tenor("18m") face = 100.0 num_time_steps = 100 def test_european_call_bk(): option_type = OptionTypes.EUROPEAN_CALL strike_price = 100 bond_option = BondOption(bond, expiry_date, strike_price, face, option_type) sigma = 0.20
def test_dp_example(): # http://www.derivativepricing.com/blogpage.asp?id=8 start_date = Date(14, 11, 2011) end_date = Date(14, 11, 2016) fixedFreqType = FrequencyTypes.SEMI_ANNUAL swapCalendarType = CalendarTypes.TARGET bus_day_adjust_type = BusDayAdjustTypes.MODIFIED_FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD fixed_day_count_type = DayCountTypes.THIRTY_E_360_ISDA fixed_leg_type = SwapTypes.PAY fixed_coupon = 0.0124 notional = ONE_MILLION swap = IborSwap(start_date, end_date, fixed_leg_type, fixed_coupon=fixed_coupon, fixed_freq_type=fixedFreqType, fixed_day_count_type=fixed_day_count_type, float_freq_type=FrequencyTypes.SEMI_ANNUAL, float_day_count_type=DayCountTypes.ACT_360, notional=notional, calendar_type=swapCalendarType, bus_day_adjust_type=bus_day_adjust_type, date_gen_rule_type=date_gen_rule_type) # swap.printFixedLegFlows() dts = [ Date(14, 11, 2011), Date(14, 5, 2012), Date(14, 11, 2012), Date(14, 5, 2013), Date(14, 11, 2013), Date(14, 5, 2014), Date(14, 11, 2014), Date(14, 5, 2015), Date(16, 11, 2015), Date(16, 5, 2016), Date(14, 11, 2016) ] dfs = [ 0.9999843, 0.9966889, 0.9942107, 0.9911884, 0.9880738, 0.9836490, 0.9786276, 0.9710461, 0.9621778, 0.9514315, 0.9394919 ] valuation_date = start_date curve = DiscountCurve(valuation_date, dts, np.array(dfs), InterpTypes.FLAT_FWD_RATES) v = swap.value(valuation_date, curve, curve) # swap.print_fixed_leg_pv() # swap.print_float_leg_pv() # This is essentially zero testCases.header("LABEL", "VALUE") testCases.print("Swap Value on a Notional of $1M:", v)
def test_FinDiscountCurves(): # Create a curve from times and discount factors valuation_date = Date(1, 1, 2018) years = [1.0, 2.0, 3.0, 4.0, 5.0] dates = valuation_date.add_years(years) years2 = [] for dt in dates: y = (dt - valuation_date) / gDaysInYear years2.append(y) rates = np.array([0.05, 0.06, 0.065, 0.07, 0.075]) discount_factors = np.exp(-np.array(rates) * np.array(years2)) curvesList = [] finDiscountCurve = DiscountCurve(valuation_date, dates, discount_factors, InterpTypes.FLAT_FWD_RATES) curvesList.append(finDiscountCurve) finDiscountCurveFlat = DiscountCurveFlat(valuation_date, 0.05) curvesList.append(finDiscountCurveFlat) finDiscountCurveNS = DiscountCurveNS(valuation_date, 0.0305, -0.01, 0.08, 10.0) curvesList.append(finDiscountCurveNS) finDiscountCurveNSS = DiscountCurveNSS(valuation_date, 0.035, -0.02, 0.09, 0.1, 1.0, 2.0) curvesList.append(finDiscountCurveNSS) finDiscountCurvePoly = DiscountCurvePoly(valuation_date, [0.05, 0.002, -0.00005]) curvesList.append(finDiscountCurvePoly) finDiscountCurvePWF = DiscountCurvePWF(valuation_date, dates, rates) curvesList.append(finDiscountCurvePWF) finDiscountCurvePWL = DiscountCurvePWL(valuation_date, dates, rates) curvesList.append(finDiscountCurvePWL) finDiscountCurveZeros = DiscountCurveZeros(valuation_date, 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 = valuation_date.add_years(years) testCases.banner("######################################################") testCases.banner("SINGLE CALLS") testCases.banner("######################################################") for name, curve in zip(curveNames, curvesList): for fwdMaturityDate in fwdMaturityDates: tenor = "3M" zero_rate = curve.zero_rate(fwdMaturityDate) fwd = curve.fwd(fwdMaturityDate) fwd_rate = curve.fwd_rate(fwdMaturityDate, tenor) swap_rate = curve.swap_rate(valuation_date, fwdMaturityDate) df = curve.df(fwdMaturityDate) testCases.print("%-20s" % name, "%-12s" % fwdMaturityDate, "%7.6f" % (zero_rate), "%8.7f" % (df), "%7.6f" % (fwd), "%7.6f" % (fwd_rate), "%7.6f" % (swap_rate)) # Examine vectorisation testCases.banner("######################################################") testCases.banner("VECTORISATIONS") testCases.banner("######################################################") for name, curve in zip(curveNames, curvesList): tenor = "3M" zero_rate = curve.zero_rate(fwdMaturityDates) fwd = curve.fwd(fwdMaturityDates) fwd_rate = curve.fwd_rate(fwdMaturityDates, tenor) swap_rate = curve.swap_rate(valuation_date, fwdMaturityDates) df = curve.df(fwdMaturityDates) for i in range(0, len(fwdMaturityDates)): testCases.print("%-20s" % name, "%-12s" % fwdMaturityDate, "%7.6f" % (zero_rate[i]), "%8.7f" % (df[i]), "%7.6f" % (fwd[i]), "%7.6f" % (fwd_rate[i]), "%7.6f" % (swap_rate[i])) if PLOT_GRAPHS: years = np.linspace(0, 10, 121) years2 = years + 1.0 fwdDates = valuation_date.add_years(years) fwdDates2 = valuation_date.add_years(years2) plt.figure() for name, curve in zip(curveNames, curvesList): zero_rates = curve.zero_rate(fwdDates) plt.plot(years, zero_rates, label=name) plt.legend() plt.title("Zero Rates") plt.figure() for name, curve in zip(curveNames, curvesList): fwd_rates = curve.fwd(fwdDates) plt.plot(years, fwd_rates, label=name) plt.legend() plt.title("CC Fwd Rates") plt.figure() for name, curve in zip(curveNames, curvesList): fwd_rates = curve.fwd_rate(fwdDates, fwdDates2) plt.plot(years, fwd_rates, 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")
def test_FinInterpolatedForwards(): interp_type = InterpTypes.FLAT_FWD_RATES discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855, 0.840, 0.825, 0.811, 0.792, 0.773, 0.755, 0.737, 0.720, 0.703, 0.687, 0.670, 0.654, 0.638, 0.622, 0.607, 0.592, 0.577, 0.563, 0.549, 0.536, 0.523, 0.510, 0.497, 0.485, 0.473, 0.461, 0.450, 0.439, 0.428, 0.417, 0.407, 0.397, 0.387, 0.378, 0.368, 0.359, 0.350, 0.342, 0.333] interp_type = InterpTypes.LINEAR_FWD_RATES discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855, 0.840, 0.825, 0.811, 0.796, 0.781, 0.764, 0.747, 0.729, 0.710, 0.691, 0.671, 0.655, 0.639, 0.624, 0.609, 0.595, 0.580, 0.566, 0.552, 0.539, 0.526, 0.513, 0.500, 0.488, 0.475, 0.463, 0.451, 0.440, 0.429, 0.418, 0.407, 0.397, 0.387, 0.378, 0.368, 0.359, 0.350, 0.342, 0.333] interp_type = InterpTypes.LINEAR_ZERO_RATES discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855, 0.840, 0.825, 0.811, 0.794, 0.776, 0.759, 0.741, 0.724, 0.706, 0.688, 0.671, 0.656, 0.641, 0.626, 0.612, 0.598, 0.584, 0.570, 0.556, 0.542, 0.529, 0.516, 0.503, 0.490, 0.478, 0.465, 0.453, 0.441, 0.430, 0.418, 0.407, 0.398, 0.389, 0.380, 0.372, 0.364, 0.356, 0.348, 0.340] interp_type = InterpTypes.FINCUBIC_ZERO_RATES discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.983, 0.966, 0.950, 0.934, 0.918, 0.903, 0.888, 0.873, 0.858, 0.843, 0.827, 0.811, 0.795, 0.778, 0.760, 0.742, 0.725, 0.707, 0.688, 0.671, 0.653, 0.636, 0.620, 0.603, 0.588, 0.573, 0.558, 0.544, 0.530, 0.517, 0.504, 0.491, 0.480, 0.468, 0.457, 0.446, 0.436, 0.426, 0.416, 0.407, 0.398, 0.389, 0.381, 0.372, 0.365, 0.357, 0.349, 0.342] interp_type = InterpTypes.NATCUBIC_LOG_DISCOUNT discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.985, 0.969, 0.954, 0.939, 0.924, 0.908, 0.893, 0.877, 0.861, 0.845, 0.828, 0.811, 0.794, 0.776, 0.758, 0.740, 0.723, 0.705, 0.688, 0.671, 0.654, 0.638, 0.622, 0.607, 0.592, 0.577, 0.563, 0.549, 0.536, 0.523, 0.510, 0.497, 0.485, 0.473, 0.461, 0.450, 0.439, 0.428, 0.417, 0.407, 0.397, 0.387, 0.378, 0.368, 0.359, 0.350, 0.342, 0.333] interp_type = InterpTypes.NATCUBIC_ZERO_RATES discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.983, 0.966, 0.950, 0.934, 0.918, 0.903, 0.888, 0.873, 0.858, 0.843, 0.827, 0.811, 0.795, 0.778, 0.760, 0.742, 0.724, 0.707, 0.688, 0.671, 0.653, 0.636, 0.620, 0.604, 0.589, 0.574, 0.559, 0.545, 0.531, 0.518, 0.505, 0.493, 0.481, 0.470, 0.458, 0.447, 0.437, 0.427, 0.417, 0.407, 0.397, 0.388, 0.379, 0.370, 0.361, 0.352, 0.343, 0.334] interp_type = InterpTypes.PCHIP_ZERO_RATES discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.983, 0.966, 0.949, 0.932, 0.916, 0.901, 0.885, 0.869, 0.855, 0.840, 0.825, 0.811, 0.796, 0.780, 0.762, 0.743, 0.725, 0.706, 0.687, 0.670, 0.655, 0.639, 0.623, 0.608, 0.593, 0.578, 0.564, 0.549, 0.535, 0.522, 0.508, 0.495, 0.483, 0.471, 0.459, 0.447, 0.437, 0.426, 0.416, 0.407, 0.398, 0.390, 0.382, 0.374, 0.368, 0.362, 0.356, 0.351] interp_type = InterpTypes.PCHIP_LOG_DISCOUNT discount_curve = DiscountCurve( curve_date, tDates, df_values, interp_type) dfInterpValues = discount_curve.df(tInterpDates) assert [round(x, 3) for x in dfInterpValues] == \ [1.0, 0.986, 0.972, 0.957, 0.941, 0.925, 0.910, 0.893, 0.877, 0.861, 0.844, 0.827, 0.811, 0.794, 0.777, 0.758, 0.740, 0.722, 0.705, 0.687, 0.670, 0.654, 0.639, 0.623, 0.608, 0.594, 0.579, 0.565, 0.551, 0.538, 0.525, 0.512, 0.499, 0.487, 0.475, 0.463, 0.451, 0.440, 0.429, 0.418, 0.407, 0.397, 0.387, 0.376, 0.367, 0.357, 0.348, 0.339, 0.330]
def test_BDTExampleThree(): # Valuation of a swaption as in Leif Andersen's paper - see Table 1 on # SSRN-id155208.pdf settlement_date = Date(1, 1, 2020) times = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]) dates = settlement_date.add_years(times) rate = 0.06 dfs = 1.0 / (1.0 + rate / 2.0)**(2.0 * times) curve = DiscountCurve(settlement_date, dates, dfs) coupon = 0.06 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA strike_price = 100.0 face = 100.0 # Andersen paper num_time_steps = 200 exercise_type = FinExerciseTypes.EUROPEAN years_to_maturity = 4.0 expiryYears = 2.0 maturity_date = settlement_date.add_years(years_to_maturity) issue_date = Date(maturity_date._d, maturity_date._m, 2000) sigma = 0.2012 expiry_date = settlement_date.add_years(expiryYears) tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency for flow_date in bond._coupon_dates: if flow_date > expiry_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) price = bond.clean_price_from_discount_curve(settlement_date, curve) model = BDTTree(sigma, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bermudan_swaption(texp, tmat, strike_price, face, coupon_times, coupon_flows, exercise_type) assert round(price, 5) == 100.01832 assert round(v['pay'] * 100, 2) == 0.00 assert round(v['rec'] * 100, 2) == 8883.21 exercise_type = FinExerciseTypes.BERMUDAN years_to_maturity = 10.0 expiryYears = 5.0 maturity_date = settlement_date.add_years(years_to_maturity) issue_date = Date(maturity_date._d, maturity_date._m, 2000) sigma = 0.1522 expiry_date = settlement_date.add_years(expiryYears) tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency for flow_date in bond._coupon_dates: if flow_date > expiry_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) price = bond.clean_price_from_discount_curve(settlement_date, curve) model = BDTTree(sigma, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bermudan_swaption(texp, tmat, strike_price, face, coupon_times, coupon_flows, exercise_type) assert round(price, 5) == 100.08625 assert round(v['pay'] * 100, 2) == 263.28 assert round(v['rec'] * 100, 2) == 7437.00
def test_BondOption(): settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) times = np.linspace(0, 10.0, 21) dfs = np.exp(-0.05 * times) dates = settlement_date.add_years(times) discount_curve = DiscountCurve(settlement_date, dates, dfs) expiry_date = settlement_date.add_tenor("18m") strike_price = 105.0 face = 100.0 ########################################################################### strikes = [80, 90, 100, 110, 120] option_type = OptionTypes.EUROPEAN_CALL testCases.header("LABEL", "VALUE") price = bond.clean_price_from_discount_curve(settlement_date, discount_curve) testCases.print("Fixed Income Price:", price) num_time_steps = 50 testCases.banner("HW EUROPEAN CALL") testCases.header("STRIKE", "VALUE") for strike_price in strikes: sigma = 0.01 a = 0.1 bond_option = BondOption(bond, expiry_date, strike_price, face, option_type) model = HWTree(sigma, a, num_time_steps) v = bond_option.value(settlement_date, discount_curve, model) testCases.print(strike_price, v) ########################################################################### option_type = OptionTypes.AMERICAN_CALL price = bond.clean_price_from_discount_curve(settlement_date, discount_curve) testCases.header("LABEL", "VALUE") testCases.print("Fixed Income Price:", price) testCases.banner("HW AMERICAN CALL") testCases.header("STRIKE", "VALUE") for strike_price in strikes: sigma = 0.01 a = 0.1 bond_option = BondOption(bond, expiry_date, strike_price, face, option_type) model = HWTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print(strike_price, v) ########################################################################### option_type = OptionTypes.EUROPEAN_PUT testCases.banner("HW EUROPEAN PUT") testCases.header("STRIKE", "VALUE") price = bond.clean_price_from_discount_curve(settlement_date, discount_curve) for strike_price in strikes: sigma = 0.01 a = 0.1 bond_option = BondOption(bond, expiry_date, strike_price, face, option_type) model = HWTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print(strike_price, v) ########################################################################### option_type = OptionTypes.AMERICAN_PUT testCases.banner("HW AMERICAN PUT") testCases.header("STRIKE", "VALUE") price = bond.clean_price_from_discount_curve(settlement_date, discount_curve) for strike_price in strikes: sigma = 0.02 a = 0.1 bond_option = BondOption(bond, expiry_date, strike_price, face, option_type) model = HWTree(sigma, a) v = bond_option.value(settlement_date, discount_curve, model) testCases.print(strike_price, v)