def test_FinIborCapletHull(): # Hull Page 703, example 29.3 todayDate = Date(20, 6, 2019) valuation_date = todayDate maturity_date = valuation_date.addTenor("2Y") libor_curve = DiscountCurveFlat(valuation_date, 0.070, FrequencyTypes.QUARTERLY, DayCountTypes.THIRTY_E_360) k = 0.08 capFloorType = FinCapFloorTypes.CAP capFloor = FinIborCapFloor(valuation_date, maturity_date, capFloorType, k, None, FrequencyTypes.QUARTERLY, DayCountTypes.THIRTY_E_360) # Value cap using a single flat cap volatility model = FinModelBlack(0.20) capFloor.value(valuation_date, libor_curve, model) # Value cap by breaking it down into caplets using caplet vols capletStartDate = valuation_date.addTenor("1Y") capletEndDate = capletStartDate.addTenor("3M") vCaplet = capFloor.valueCapletFloorLet(valuation_date, capletStartDate, capletEndDate, libor_curve, model) # Cannot match Hull due to dates being adjusted testCases.header("CORRECT PRICE", "MODEL_PRICE") testCases.print(517.29, vCaplet)
def test_FinDayCount(): testCases.header("DAY_COUNT_METHOD", "START", "END", "ALPHA") finFreq = FrequencyTypes.ANNUAL for day_count_method in DayCountTypes: start_date = Date(1, 1, 2019) next_date = start_date numDays = 20 day_count = DayCount(day_count_method) for _ in range(0, numDays): next_date = next_date.add_days(7) dcf = day_count.year_frac( start_date, next_date, next_date, finFreq) testCases.print( str(day_count_method), str(start_date), str(next_date), dcf[0])
def test_FinFXMktVolSurface1(capsys): # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARK") valuation_date = Date(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD dom_discount_curve = DiscountCurveFlat(valuation_date, domCCRate) for_discount_curve = DiscountCurveFlat(valuation_date, forCCRate) currency_pair = forName + domName spot_fx_rate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atm_vols = [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] notional_currency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA vol_functionType = VolFunctionTypes.CLARK fxMarket = FXVolSurface(valuation_date, spot_fx_rate, currency_pair, notional_currency, dom_discount_curve, for_discount_curve, tenors, atm_vols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod, vol_functionType) fxMarket.check_calibration(verboseCalibration, tol=1e-5) captured = capsys.readouterr() assert captured.out == ""
def test_FinFXMktVolSurface3(capsys): # EURUSD Example from Paper by Uwe Wystup using Tables 4 # print("EURUSD EXAMPLE WYSTUP") valuation_date = Date(20, 1, 2009) forName = "EUR" domName = "USD" forCCRate = 0.020113 # EUR domCCRate = 0.003525 # USD dom_discount_curve = DiscountCurveFlat(valuation_date, domCCRate) for_discount_curve = DiscountCurveFlat(valuation_date, forCCRate) currency_pair = forName + domName spot_fx_rate = 1.3088 tenors = ['1M'] atm_vols = [21.6215] marketStrangle25DeltaVols = [0.7375] riskReversal25DeltaVols = [-0.50] notional_currency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA fxMarket = FXVolSurface(valuation_date, spot_fx_rate, currency_pair, notional_currency, dom_discount_curve, for_discount_curve, tenors, atm_vols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod) fxMarket.check_calibration(verboseCalibration) captured = capsys.readouterr() assert captured.out == ""
def test_FinFXMktVolSurface2(capsys): # Example from Book extract by Iain Clark using Tables 3.3 and 3.4 # print("EURJPY EXAMPLE CLARK") valuation_date = Date(10, 4, 2020) forName = "EUR" domName = "JPY" forCCRate = 0.0294 # EUR domCCRate = 0.0171 # USD dom_discount_curve = DiscountCurveFlat(valuation_date, domCCRate) for_discount_curve = DiscountCurveFlat(valuation_date, forCCRate) currency_pair = forName + domName spot_fx_rate = 90.72 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atm_vols = [21.50, 20.50, 19.85, 18.00, 15.95, 14.009] marketStrangle25DeltaVols = [0.35, 0.325, 0.300, 0.225, 0.175, 0.100] riskReversal25DeltaVols = [-8.350, -8.650, -8.950, -9.250, -9.550, -9.500] notional_currency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL_PREM_ADJ deltaMethod = FinFXDeltaMethod.SPOT_DELTA_PREM_ADJ fxMarket = FXVolSurface(valuation_date, spot_fx_rate, currency_pair, notional_currency, dom_discount_curve, for_discount_curve, tenors, atm_vols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod) fxMarket.check_calibration(verboseCalibration, tol=0.0005) captured = capsys.readouterr() assert captured.out == ""
def test_FinFXMktVolSurface1(verboseCalibration): ########################################################################### if 1 == 1: # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARK") valuation_date = Date(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD dom_discount_curve = DiscountCurveFlat(valuation_date, domCCRate) for_discount_curve = DiscountCurveFlat(valuation_date, forCCRate) currency_pair = forName + domName spot_fx_rate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atm_vols = [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] notional_currency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA vol_functionType = VolFunctionTypes.CLARK fxMarket = FXVolSurface(valuation_date, spot_fx_rate, currency_pair, notional_currency, dom_discount_curve, for_discount_curve, tenors, atm_vols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod, vol_functionType) fxMarket.check_calibration(verboseCalibration) # EXPLORE AND TEST DIFFERENT CATEGORICAL PARAMETERS # for atmMethod in FinFXATMMethod: # for deltaMethod in FinFXDeltaMethod: # for vol_functionType in VolFunctionTypes: # fxMarket = FinFXVolSurface(valuation_date, # spot_fx_rate, # currency_pair, # notional_currency, # dom_discount_curve, # for_discount_curve, # tenors, # atm_vols, # marketStrangle25DeltaVols, # riskReversal25DeltaVols, # atmMethod, # deltaMethod, # vol_functionType) # fxMarket.check_calibration(verboseCalibration) if PLOT_GRAPHS: fxMarket.plot_vol_curves() dbns = fxMarket.implied_dbns(0.00001, 5.0, 10000) for i in range(0, len(dbns)): plt.plot(dbns[i]._x, dbns[i]._densitydx) plt.title(vol_functionType) print("SUM:", dbns[i].sum())
def test_BondOptionZEROVOLConvergence(): # Build discount curve settlement_date = Date(1, 9, 2019) rate = 0.05 discount_curve = DiscountCurveFlat( settlement_date, rate, FrequencyTypes.ANNUAL) # Bond details issue_date = Date(1, 9, 2014) maturity_date = Date(1, 9, 2025) coupon = 0.06 freq_type = FrequencyTypes.ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) # Option Details expiry_date = Date(1, 12, 2021) face = 100.0 dfExpiry = discount_curve.df(expiry_date) fwdCleanValue = bond.clean_price_from_discount_curve( expiry_date, discount_curve) fwdFullValue = bond.full_price_from_discount_curve( expiry_date, discount_curve) # print("BOND FwdCleanBondPx", fwdCleanValue) # print("BOND FwdFullBondPx", fwdFullValue) # print("BOND Accrued:", bond._accrued_interest) spotCleanValue = bond.clean_price_from_discount_curve( settlement_date, discount_curve) testCases.header("STRIKE", "STEPS", "CALL_INT", "CALL_INT_PV", "CALL_EUR", "CALL_AMER", "PUT_INT", "PUT_INT_PV", "PUT_EUR", "PUT_AMER") num_time_steps = range(100, 1000, 100) strike_prices = [90, 100, 110, 120] for strike_price in strike_prices: callIntrinsic = max(spotCleanValue - strike_price, 0) putIntrinsic = max(strike_price - spotCleanValue, 0) callIntrinsicPV = max(fwdCleanValue - strike_price, 0) * dfExpiry putIntrinsicPV = max(strike_price - fwdCleanValue, 0) * dfExpiry for num_steps in num_time_steps: sigma = 0.0000001 a = 0.1 model = BKTree(sigma, a, num_steps) option_type = OptionTypes.EUROPEAN_CALL bond_option1 = BondOption( bond, expiry_date, strike_price, face, option_type) v1 = bond_option1.value(settlement_date, discount_curve, model) option_type = OptionTypes.AMERICAN_CALL bond_option2 = BondOption( bond, expiry_date, strike_price, face, option_type) v2 = bond_option2.value(settlement_date, discount_curve, model) option_type = OptionTypes.EUROPEAN_PUT bond_option3 = BondOption( bond, expiry_date, strike_price, face, option_type) v3 = bond_option3.value(settlement_date, discount_curve, model) option_type = OptionTypes.AMERICAN_PUT bond_option4 = BondOption( bond, expiry_date, strike_price, face, option_type) v4 = bond_option4.value(settlement_date, discount_curve, model) testCases.print(strike_price, num_steps, callIntrinsic, callIntrinsicPV, v1, v2, putIntrinsic, putIntrinsicPV, v3, v4)
def test_BondOptionAmericanConvergenceTWO(): # Build discount curve settlement_date = Date(1, 12, 2019) discount_curve = DiscountCurveFlat(settlement_date, 0.05, FrequencyTypes.CONTINUOUS) # Bond details issue_date = Date(1, 9, 2014) maturity_date = Date(1, 9, 2025) coupon = 0.05 freq_type = FrequencyTypes.ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) expiry_date = settlement_date.add_tenor("18m") face = 100.0 spotValue = bond.full_price_from_discount_curve( settlement_date, discount_curve) testCases.header("LABEL", "VALUE") testCases.print("BOND PRICE", spotValue) testCases.header("TIME", "N", "EUR_CALL", "AMER_CALL", "EUR_PUT", "AMER_PUT") sigma = 0.2 a = 0.1 bkModel = BKTree(sigma, a) K = 101.0 vec_ec = [] vec_ac = [] vec_ep = [] vec_ap = [] if 1 == 1: K = 100.0 bkModel = BKTree(sigma, a, 100) europeanCallBondOption = BondOption(bond, expiry_date, K, face, OptionTypes.EUROPEAN_CALL) v_ec = europeanCallBondOption.value(settlement_date, discount_curve, bkModel) testCases.header("LABEL", "VALUE") testCases.print("OPTION", v_ec) num_stepsVector = range(100, 100, 1) # should be 100-400 for num_steps in num_stepsVector: bkModel = BKTree(sigma, a, num_steps) start = time.time() europeanCallBondOption = BondOption(bond, expiry_date, K, face, OptionTypes.EUROPEAN_CALL) v_ec = europeanCallBondOption.value(settlement_date, discount_curve, bkModel) americanCallBondOption = BondOption(bond, expiry_date, K, face, OptionTypes.AMERICAN_CALL) v_ac = americanCallBondOption.value(settlement_date, discount_curve, bkModel) europeanPutBondOption = BondOption(bond, expiry_date, K, face, OptionTypes.EUROPEAN_PUT) v_ep = europeanPutBondOption.value(settlement_date, discount_curve, bkModel) americanPutBondOption = BondOption(bond, expiry_date, K, face, OptionTypes.AMERICAN_PUT) v_ap = americanPutBondOption.value(settlement_date, discount_curve, bkModel) end = time.time() period = end - start testCases.print(period, num_steps, v_ec, v_ac, v_ep, v_ap) vec_ec.append(v_ec) vec_ac.append(v_ac) vec_ep.append(v_ep) vec_ap.append(v_ap) if plotGraphs: plt.figure() plt.plot(num_stepsVector, vec_ec, label="European Call") plt.legend() plt.figure() plt.plot(num_stepsVector, vec_ac, label="American Call") plt.legend() plt.figure() plt.plot(num_stepsVector, vec_ep, label="European Put") plt.legend() plt.figure() plt.plot(num_stepsVector, vec_ap, label="American Put") plt.legend()
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_FinFXVanillaOptionHullExample(): # Example from Hull 4th edition page 284 valuation_date = Date(1, 1, 2015) expiry_date = valuation_date.add_months(4) spot_fx_rate = 1.60 volatility = 0.1411 dom_interest_rate = 0.08 forInterestRate = 0.11 model = BlackScholes(volatility) dom_discount_curve = DiscountCurveFlat(valuation_date, dom_interest_rate) for_discount_curve = DiscountCurveFlat(valuation_date, forInterestRate) num_paths_list = [10000, 20000, 40000, 80000, 160000, 320000] testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC") strike_fx_rate = 1.60 for num_paths in num_paths_list: call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_CALL, 1000000, "USD") value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) start = time.time() value_mc = call_option.value_mc(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model, num_paths) end = time.time() duration = end - start testCases.print(num_paths, value, value_mc) ########################################################################## spot_fx_rates = np.arange(100, 200, 10) spot_fx_rates = spot_fx_rates / 100.0 num_paths = 100000 testCases.header("NUMPATHS", "CALL_VALUE_BS", "CALL_VALUE_MC") for spot_fx_rate in spot_fx_rates: call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_CALL, 1000000, "USD") value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) start = time.time() value_mc = call_option.value_mc(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model, num_paths) end = time.time() duration = end - start testCases.print(num_paths, value, value_mc) ########################################################################## spot_fx_rates = np.arange(100, 200, 10) / 100.0 num_paths = 100000 testCases.header("SPOT FX RATE", "PUT_VALUE_BS", "PUT_VALUE_MC") for spot_fx_rate in spot_fx_rates: put_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_PUT, 1000000, "USD") value = put_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) start = time.time() value_mc = put_option.value_mc(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model, num_paths) end = time.time() duration = end - start testCases.print(spot_fx_rate, value, value_mc) ########################################################################## spot_fx_rates = np.arange(100, 200, 10) / 100.0 testCases.header("SPOT FX RATE", "CALL_VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for spot_fx_rate in spot_fx_rates: call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_CALL, 1000000, "USD") value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) delta = call_option.delta(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) vega = call_option.vega(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) theta = call_option.theta(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) # call_option.rho(valuation_date,stock_price, interest_rate, # dividend_yield, modelType, model_params) rho = 999 testCases.print(spot_fx_rate, value, delta, vega, theta, rho) testCases.header("SPOT FX RATE", "PUT_VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for spot_fx_rate in spot_fx_rates: put_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_PUT, 1000000, "USD") value = put_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) delta = put_option.delta(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) vega = put_option.vega(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) theta = put_option.theta(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) # put_option.rho(valuation_date,stock_price, interest_rate, dividend_yield, # modelType, model_params) rho = 999 testCases.print(spot_fx_rate, value, delta, vega, theta, rho) ########################################################################## testCases.header("SPOT FX RATE", "VALUE_BS", "VOL_IN", "IMPLD_VOL") spot_fx_rates = np.arange(100, 200, 10) / 100.0 for spot_fx_rate in spot_fx_rates: call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_CALL, 1000000, "USD") value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model)['v'] impliedVol = call_option.implied_volatility(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, value) testCases.print(spot_fx_rate, value, volatility, impliedVol)
def testFinIborCashSettledSwaption(): testCases.header("LABEL", "VALUE") valuation_date = Date(1, 1, 2020) settlement_date = Date(1, 1, 2020) depoDCCType = DayCountTypes.THIRTY_E_360_ISDA depos = [] depo = IborDeposit(settlement_date, "1W", 0.0023, depoDCCType) depos.append(depo) depo = IborDeposit(settlement_date, "1M", 0.0023, depoDCCType) depos.append(depo) depo = IborDeposit(settlement_date, "3M", 0.0023, depoDCCType) depos.append(depo) depo = IborDeposit(settlement_date, "6M", 0.0023, depoDCCType) depos.append(depo) # No convexity correction provided so I omit interest rate futures settlement_date = Date(2, 1, 2020) swaps = [] accType = DayCountTypes.ACT_365F fixedFreqType = FrequencyTypes.SEMI_ANNUAL fixed_leg_type = SwapTypes.PAY swap = IborSwap(settlement_date, "3Y", fixed_leg_type, 0.00790, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "4Y", fixed_leg_type, 0.01200, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "5Y", fixed_leg_type, 0.01570, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "6Y", fixed_leg_type, 0.01865, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "7Y", fixed_leg_type, 0.02160, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "8Y", fixed_leg_type, 0.02350, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "9Y", fixed_leg_type, 0.02540, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "10Y", fixed_leg_type, 0.0273, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "15Y", fixed_leg_type, 0.0297, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "20Y", fixed_leg_type, 0.0316, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "25Y", fixed_leg_type, 0.0335, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "30Y", fixed_leg_type, 0.0354, fixedFreqType, accType) swaps.append(swap) libor_curve = IborSingleCurve(valuation_date, depos, [], swaps, InterpTypes.LINEAR_ZERO_RATES) exercise_date = settlement_date.add_tenor("5Y") swapMaturityDate = exercise_date.add_tenor("5Y") swapFixedCoupon = 0.040852 swapFixedFrequencyType = FrequencyTypes.SEMI_ANNUAL swapFixedDayCountType = DayCountTypes.THIRTY_E_360_ISDA swapFloatFrequencyType = FrequencyTypes.QUARTERLY swapFloatDayCountType = DayCountTypes.ACT_360 swapNotional = 1000000 fixed_leg_type = SwapTypes.PAY swaption = IborSwaption(settlement_date, exercise_date, swapMaturityDate, fixed_leg_type, swapFixedCoupon, swapFixedFrequencyType, swapFixedDayCountType, swapNotional, swapFloatFrequencyType, swapFloatDayCountType) model = Black(0.1533) v = swaption.value(settlement_date, libor_curve, model) testCases.print("Swaption No-Arb Value:", v) fwdSwapRate1 = libor_curve.swap_rate(exercise_date, swapMaturityDate, swapFixedFrequencyType, swapFixedDayCountType) testCases.print("Curve Fwd Swap Rate:", fwdSwapRate1) fwdSwap = IborSwap(exercise_date, swapMaturityDate, fixed_leg_type, swapFixedCoupon, swapFixedFrequencyType, swapFixedDayCountType) fwdSwapRate2 = fwdSwap.swap_rate(settlement_date, libor_curve) testCases.print("Fwd Swap Swap Rate:", fwdSwapRate2) model = Black(0.1533) v = swaption.cash_settled_value(valuation_date, libor_curve, fwdSwapRate2, model) testCases.print("Swaption Cash Settled Value:", v)
def test_FinBinomialTree(): stock_price = 50.0 riskFreeRate = 0.06 dividendYield = 0.04 volatility = 0.40 valuation_date = Date(1, 1, 2016) expiry_date = Date(1, 1, 2017) model = FinModelBlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, riskFreeRate) dividendCurve = DiscountCurveFlat(valuation_date, dividendYield) num_stepsList = [100, 500, 1000, 2000, 5000] strikePrice = 50.0 testCases.banner("================== EUROPEAN PUT =======================") putOption = FinEquityVanillaOption(expiry_date, strikePrice, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valuation_date, stock_price, discount_curve, dividendCurve, model) delta = putOption.delta(valuation_date, stock_price, discount_curve, dividendCurve, model) gamma = putOption.gamma(valuation_date, stock_price, discount_curve, dividendCurve, model) theta = putOption.theta(valuation_date, stock_price, discount_curve, 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 num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration) testCases.banner("================== AMERICAN PUT =======================") payoff = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.AMERICAN params = np.array([-1, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration) testCases.banner( "================== EUROPEAN CALL =======================") callOption = FinEquityVanillaOption(expiry_date, strikePrice, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valuation_date, stock_price, discount_curve, dividendCurve, model) delta = callOption.delta(valuation_date, stock_price, discount_curve, dividendCurve, model) gamma = callOption.gamma(valuation_date, stock_price, discount_curve, dividendCurve, model) theta = callOption.theta(valuation_date, stock_price, discount_curve, 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 num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, 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 num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration)
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 ] zero_rates = [ 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(zero_rates) / 100.0 dfs = np.exp(-zeros * times) start_date = Date(1, 12, 2019) sigma = 0.01 a = 0.1 strike = 63.0 face = 100.0 expiry_date = start_date.add_tenor("3Y") maturity_date = start_date.add_tenor("9Y") texp = (expiry_date - start_date) / gDaysInYear tmat = (maturity_date - start_date) / gDaysInYear num_time_steps = None model = HWTree(sigma, a, num_time_steps) vAnal = model.option_on_zcb(texp, tmat, strike, face, times, dfs) # Test convergence num_steps_list = 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 num_time_steps in num_steps_list: start = time.time() model = HWTree(sigma, a, num_time_steps) model.build_tree(texp, times, dfs) vTree1 = model.option_on_zero_coupon_bond_tree(texp, tmat, strike, face) model = HWTree(sigma, a, num_time_steps + 1) model.build_tree(texp, times, dfs) vTree2 = model.option_on_zero_coupon_bond_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(num_time_steps, period, vTreeCall, vAnal['call'], vTreePut, vAnal['put'], diffC, diffP)
def test_HullWhiteCallableBond(): # Valuation of a European option on a coupon bearing bond settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2018) maturity_date = settlement_date.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 for flow_date in bond._coupon_dates[1:]: 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) ########################################################################### # Set up the call and put times and prices ########################################################################### call_dates = [] call_prices = [] callPx = 120.0 call_dates.append(settlement_date.add_tenor("2Y")) call_prices.append(callPx) call_dates.append(settlement_date.add_tenor("3Y")) call_prices.append(callPx) call_dates.append(settlement_date.add_tenor("4Y")) call_prices.append(callPx) call_dates.append(settlement_date.add_tenor("5Y")) call_prices.append(callPx) call_dates.append(settlement_date.add_tenor("6Y")) call_prices.append(callPx) call_dates.append(settlement_date.add_tenor("7Y")) call_prices.append(callPx) call_dates.append(settlement_date.add_tenor("8Y")) call_prices.append(callPx) call_times = [] for dt in call_dates: t = (dt - settlement_date) / gDaysInYear call_times.append(t) put_dates = [] put_prices = [] putPx = 98.0 put_dates.append(settlement_date.add_tenor("2Y")) put_prices.append(putPx) put_dates.append(settlement_date.add_tenor("3Y")) put_prices.append(putPx) put_dates.append(settlement_date.add_tenor("4Y")) put_prices.append(putPx) put_dates.append(settlement_date.add_tenor("5Y")) put_prices.append(putPx) put_dates.append(settlement_date.add_tenor("6Y")) put_prices.append(putPx) put_dates.append(settlement_date.add_tenor("7Y")) put_prices.append(putPx) put_dates.append(settlement_date.add_tenor("8Y")) put_prices.append(putPx) put_times = [] for dt in put_dates: t = (dt - settlement_date) / gDaysInYear put_times.append(t) ########################################################################### tmat = (maturity_date - settlement_date) / gDaysInYear curve = DiscountCurveFlat(settlement_date, 0.05, FrequencyTypes.CONTINUOUS) dfs = [] times = [] for dt in bond._coupon_dates: if dt > settlement_date: t = (dt - settlement_date) / gDaysInYear df = curve.df(dt) times.append(t) dfs.append(df) dfs = np.array(dfs) times = np.array(times) ########################################################################### v1 = bond.clean_price_from_discount_curve(settlement_date, curve) sigma = 0.02 # basis point volatility a = 0.01 # Test convergence num_steps_list = [100, 200, 500, 1000] tmat = (maturity_date - settlement_date) / gDaysInYear testCases.header("NUMSTEPS", "TIME", "BOND_ONLY", "CALLABLE_BOND") for num_time_steps in num_steps_list: start = time.time() model = HWTree(sigma, a, num_time_steps) model.build_tree(tmat, times, dfs) v2 = model.callable_puttable_bond_tree(coupon_times, coupon_flows, call_times, call_prices, put_times, put_prices, 100.0) end = time.time() period = end - start testCases.print(num_time_steps, period, v1, v2)
def test_HullWhiteBondOption(): # Valuation of a European option on a coupon bearing bond 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 ncd > settlement_date: if len(coupon_times) == 0: flow_time = (pcd - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) flow_time = (ncd - 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 = 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 = HWTree(sigma, a, None) # Test convergence num_steps_list = range(50, 500, 50) texp = (expiry_date - settlement_date) / gDaysInYear vJam = model.european_bond_option_jamshidian(texp, strike_price, face, coupon_times, coupon_flows, 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 num_time_steps in num_steps_list: start = time.time() model = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_ONLY) model.build_tree(texp, times, dfs) exercise_type = FinExerciseTypes.EUROPEAN v1 = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) model = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_TREE) model.build_tree(texp, times, dfs) v2 = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) end = time.time() period = end - start testCases.print(num_time_steps, period, v1, v2, vJam) # plt.plot(num_steps_list, treeVector) if 1 == 0: print("RT") print_tree(model._rt, 5) print("BOND") print_tree(model._bond_values, 5) print("OPTION") print_tree(model._option_values, 5)
def test_EquityDigitalOption(): underlying_type = FinDigitalOptionTypes.CASH_OR_NOTHING valuation_date = Date(1, 1, 2015) expiry_date = Date(1, 1, 2016) stock_price = 100.0 volatility = 0.30 interest_rate = 0.05 dividend_yield = 0.01 discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) model = BlackScholes(volatility) import time call_option_values = [] call_option_valuesMC = [] num_paths_list = [ 10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000 ] testCases.header("NumLoops", "ValueBS", "ValueMC", "TIME") for num_paths in num_paths_list: call_option = EquityDigitalOption(expiry_date, 100.0, OptionTypes.EUROPEAN_CALL, underlying_type) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) start = time.time() value_mc = call_option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths) end = time.time() duration = end - start testCases.print(num_paths, value, value_mc, duration) call_option_values.append(value) call_option_valuesMC.append(value_mc) # plt.figure(figsize=(10,8)) # plt.plot(num_paths_list, call_option_values, color = 'b', label="Call Option") # plt.plot(num_paths_list, call_option_valuesMC, color = 'r', label = "Call Option MC") # plt.xlabel("Num Loops") # plt.legend(loc='best') ########################################################################## stock_prices = range(50, 150, 50) call_option_values = [] call_optionDeltas = [] call_optionVegas = [] call_optionThetas = [] for stock_price in stock_prices: call_option = EquityDigitalOption(expiry_date, 100.0, OptionTypes.EUROPEAN_CALL, underlying_type) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = call_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) vega = call_option.vega(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = call_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) call_option_values.append(value) call_optionDeltas.append(delta) call_optionVegas.append(vega) call_optionThetas.append(theta) put_option_values = [] put_optionDeltas = [] put_optionVegas = [] put_optionThetas = [] for stock_price in stock_prices: put_option = EquityDigitalOption(expiry_date, 100.0, OptionTypes.EUROPEAN_PUT, underlying_type) value = put_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = put_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) vega = put_option.vega(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = put_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) put_option_values.append(value) put_optionDeltas.append(delta) put_optionVegas.append(vega) put_optionThetas.append(theta)
def test_IborSwaptionQLExample(): valuation_date = Date(4, 3, 2014) settlement_date = Date(4, 3, 2014) depoDCCType = DayCountTypes.THIRTY_E_360_ISDA depos = [] depo = IborDeposit(settlement_date, "1W", 0.0023, depoDCCType) depos.append(depo) depo = IborDeposit(settlement_date, "1M", 0.0023, depoDCCType) depos.append(depo) depo = IborDeposit(settlement_date, "3M", 0.0023, depoDCCType) depos.append(depo) depo = IborDeposit(settlement_date, "6M", 0.0023, depoDCCType) depos.append(depo) # No convexity correction provided so I omit interest rate futures swaps = [] accType = DayCountTypes.ACT_365F fixedFreqType = FrequencyTypes.SEMI_ANNUAL fixed_leg_type = SwapTypes.PAY swap = IborSwap(settlement_date, "3Y", fixed_leg_type, 0.00790, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "4Y", fixed_leg_type, 0.01200, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "5Y", fixed_leg_type, 0.01570, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "6Y", fixed_leg_type, 0.01865, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "7Y", fixed_leg_type, 0.02160, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "8Y", fixed_leg_type, 0.02350, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "9Y", fixed_leg_type, 0.02540, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "10Y", fixed_leg_type, 0.0273, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "15Y", fixed_leg_type, 0.0297, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "20Y", fixed_leg_type, 0.0316, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "25Y", fixed_leg_type, 0.0335, fixedFreqType, accType) swaps.append(swap) swap = IborSwap(settlement_date, "30Y", fixed_leg_type, 0.0354, fixedFreqType, accType) swaps.append(swap) libor_curve = IborSingleCurve(valuation_date, depos, [], swaps, InterpTypes.LINEAR_ZERO_RATES) exercise_date = settlement_date.add_tenor("5Y") swapMaturityDate = exercise_date.add_tenor("5Y") swapFixedCoupon = 0.040852 swapFixedFrequencyType = FrequencyTypes.SEMI_ANNUAL swapFixedDayCountType = DayCountTypes.THIRTY_E_360_ISDA swapFloatFrequencyType = FrequencyTypes.QUARTERLY swapFloatDayCountType = DayCountTypes.ACT_360 swapNotional = 1000000 swaptionType = SwapTypes.PAY swaption = IborSwaption(settlement_date, exercise_date, swapMaturityDate, swaptionType, swapFixedCoupon, swapFixedFrequencyType, swapFixedDayCountType, swapNotional, swapFloatFrequencyType, swapFloatDayCountType) testCases.header("MODEL", "VALUE") model = Black(0.1533) v = swaption.value(settlement_date, libor_curve, model) testCases.print(model.__class__, v) model = BlackShifted(0.1533, -0.008) v = swaption.value(settlement_date, libor_curve, model) testCases.print(model.__class__, v) model = SABR(0.132, 0.5, 0.5, 0.5) v = swaption.value(settlement_date, libor_curve, model) testCases.print(model.__class__, v) model = SABRShifted(0.352, 0.5, 0.15, 0.15, -0.005) v = swaption.value(settlement_date, libor_curve, model) testCases.print(model.__class__, v) model = HWTree(0.010000000, 0.00000000001) v = swaption.value(settlement_date, libor_curve, model) testCases.print(model.__class__, v)
def test_CDSIndexAdjustSpreads(): tradeDate = Date(1, 8, 2007) step_in_date = tradeDate.add_days(1) valuation_date = tradeDate libor_curve = build_Ibor_Curve(tradeDate) maturity3Y = tradeDate.next_cds_date(36) maturity5Y = tradeDate.next_cds_date(60) maturity7Y = tradeDate.next_cds_date(84) maturity10Y = tradeDate.next_cds_date(120) path = dirname(__file__) filename = "CDX_NA_IG_S7_SPREADS.csv" full_filename_path = join(path, "data", filename) f = open(full_filename_path, 'r') data = f.readlines() issuer_curves = [] for row in data[1:]: splitRow = row.split(",") spd3Y = float(splitRow[1]) / 10000.0 spd5Y = float(splitRow[2]) / 10000.0 spd7Y = float(splitRow[3]) / 10000.0 spd10Y = float(splitRow[4]) / 10000.0 recovery_rate = float(splitRow[5]) cds3Y = CDS(step_in_date, maturity3Y, spd3Y) cds5Y = CDS(step_in_date, maturity5Y, spd5Y) cds7Y = CDS(step_in_date, maturity7Y, spd7Y) cds10Y = CDS(step_in_date, maturity10Y, spd10Y) cds_contracts = [cds3Y, cds5Y, cds7Y, cds10Y] issuer_curve = CDSCurve(valuation_date, cds_contracts, libor_curve, recovery_rate) issuer_curves.append(issuer_curve) ########################################################################## # Now determine the average spread of the index ########################################################################## cdsIndex = CDSIndexPortfolio() averageSpd3Y = cdsIndex.average_spread(valuation_date, step_in_date, maturity3Y, issuer_curves) * 10000.0 averageSpd5Y = cdsIndex.average_spread(valuation_date, step_in_date, maturity5Y, issuer_curves) * 10000.0 averageSpd7Y = cdsIndex.average_spread(valuation_date, step_in_date, maturity7Y, issuer_curves) * 10000.0 averageSpd10Y = cdsIndex.average_spread( valuation_date, step_in_date, maturity10Y, issuer_curves) * 10000.0 testCases.header("LABEL", "VALUE") testCases.print("AVERAGE SPD 3Y", averageSpd3Y) testCases.print("AVERAGE SPD 5Y", averageSpd5Y) testCases.print("AVERAGE SPD 7Y", averageSpd7Y) testCases.print("AVERAGE SPD 10Y", averageSpd10Y) ########################################################################## # Now determine the intrinsic spread of the index to the same maturity dates # As the single name CDS contracts ########################################################################## cdsIndex = CDSIndexPortfolio() intrinsicSpd3Y = cdsIndex.intrinsic_spread( valuation_date, step_in_date, maturity3Y, issuer_curves) * 10000.0 intrinsicSpd5Y = cdsIndex.intrinsic_spread( valuation_date, step_in_date, maturity5Y, issuer_curves) * 10000.0 intrinsicSpd7Y = cdsIndex.intrinsic_spread( valuation_date, step_in_date, maturity7Y, issuer_curves) * 10000.0 intrinsicSpd10Y = cdsIndex.intrinsic_spread( valuation_date, step_in_date, maturity10Y, issuer_curves) * 10000.0 ########################################################################## ########################################################################## testCases.header("LABEL", "VALUE") testCases.print("INTRINSIC SPD 3Y", intrinsicSpd3Y) testCases.print("INTRINSIC SPD 5Y", intrinsicSpd5Y) testCases.print("INTRINSIC SPD 7Y", intrinsicSpd7Y) testCases.print("INTRINSIC SPD 10Y", intrinsicSpd10Y) ########################################################################## ########################################################################## index_coupons = [0.002, 0.0037, 0.0050, 0.0063] indexUpfronts = [0.0, 0.0, 0.0, 0.0] indexMaturityDates = [ Date(20, 12, 2009), Date(20, 12, 2011), Date(20, 12, 2013), Date(20, 12, 2016) ] indexRecoveryRate = 0.40 tolerance = 1e-7 import time start = time.time() indexPortfolio = CDSIndexPortfolio() adjustedIssuerCurves = indexPortfolio.spread_adjust_intrinsic( valuation_date, issuer_curves, index_coupons, indexUpfronts, indexMaturityDates, indexRecoveryRate, tolerance) end = time.time() testCases.header("TIME") testCases.print(end - start) cdsIndex = CDSIndexPortfolio() intrinsicSpd3Y = cdsIndex.intrinsic_spread(valuation_date, step_in_date, indexMaturityDates[0], adjustedIssuerCurves) * 10000.0 intrinsicSpd5Y = cdsIndex.intrinsic_spread(valuation_date, step_in_date, indexMaturityDates[1], adjustedIssuerCurves) * 10000.0 intrinsicSpd7Y = cdsIndex.intrinsic_spread(valuation_date, step_in_date, indexMaturityDates[2], adjustedIssuerCurves) * 10000.0 intrinsicSpd10Y = cdsIndex.intrinsic_spread(valuation_date, step_in_date, indexMaturityDates[3], adjustedIssuerCurves) * 10000.0 # If the adjustment works then this should equal the index spreads testCases.header("LABEL", "VALUE") testCases.print("ADJUSTED INTRINSIC SPD 3Y:", intrinsicSpd3Y) testCases.print("ADJUSTED INTRINSIC SPD 5Y:", intrinsicSpd5Y) testCases.print("ADJUSTED INTRINSIC SPD 7Y", intrinsicSpd7Y) testCases.print("ADJUSTED INTRINSIC SPD 10Y", intrinsicSpd10Y)
def testIborSwaptionMatlabExamples(): # We value a European swaption using Black's model and try to replicate a # ML example at https://fr.mathworks.com/help/fininst/swaptionbyblk.html testCases.header("=======================================") testCases.header("MATLAB EXAMPLE WITH FLAT TERM STRUCTURE") testCases.header("=======================================") valuation_date = Date(1, 1, 2010) libor_curve = DiscountCurveFlat(valuation_date, 0.06, FrequencyTypes.CONTINUOUS, DayCountTypes.THIRTY_E_360) settlement_date = Date(1, 1, 2011) exercise_date = Date(1, 1, 2016) maturity_date = Date(1, 1, 2019) fixed_coupon = 0.062 fixed_frequency_type = FrequencyTypes.SEMI_ANNUAL fixed_day_count_type = DayCountTypes.THIRTY_E_360_ISDA notional = 100.0 # Pricing a PAY swaptionType = SwapTypes.PAY swaption = IborSwaption(settlement_date, exercise_date, maturity_date, swaptionType, fixed_coupon, fixed_frequency_type, fixed_day_count_type, notional) model = Black(0.20) v_finpy = swaption.value(valuation_date, libor_curve, model) v_matlab = 2.071 testCases.header("LABEL", "VALUE") testCases.print("FP Price:", v_finpy) testCases.print("MATLAB Prix:", v_matlab) testCases.print("DIFF:", v_finpy - v_matlab) ############################################################################### testCases.header("===================================") testCases.header("MATLAB EXAMPLE WITH TERM STRUCTURE") testCases.header("===================================") valuation_date = Date(1, 1, 2010) dates = [ Date(1, 1, 2011), Date(1, 1, 2012), Date(1, 1, 2013), Date(1, 1, 2014), Date(1, 1, 2015) ] zero_rates = [0.03, 0.034, 0.037, 0.039, 0.040] contFreq = FrequencyTypes.CONTINUOUS interp_type = InterpTypes.LINEAR_ZERO_RATES day_count_type = DayCountTypes.THIRTY_E_360 libor_curve = DiscountCurveZeros(valuation_date, dates, zero_rates, contFreq, day_count_type, interp_type) settlement_date = Date(1, 1, 2011) exercise_date = Date(1, 1, 2012) maturity_date = Date(1, 1, 2017) fixed_coupon = 0.03 fixed_frequency_type = FrequencyTypes.SEMI_ANNUAL fixed_day_count_type = DayCountTypes.THIRTY_E_360 float_frequency_type = FrequencyTypes.SEMI_ANNUAL float_day_count_type = DayCountTypes.THIRTY_E_360 notional = 1000.0 # Pricing a put swaptionType = SwapTypes.RECEIVE swaption = IborSwaption(settlement_date, exercise_date, maturity_date, swaptionType, fixed_coupon, fixed_frequency_type, fixed_day_count_type, notional, float_frequency_type, float_day_count_type) model = Black(0.21) v_finpy = swaption.value(valuation_date, libor_curve, model) v_matlab = 0.5771 testCases.header("LABEL", "VALUE") testCases.print("FP Price:", v_finpy) testCases.print("MATLAB Prix:", v_matlab) testCases.print("DIFF:", v_finpy - v_matlab) ############################################################################### testCases.header("===================================") testCases.header("MATLAB EXAMPLE WITH SHIFTED BLACK") testCases.header("===================================") valuation_date = Date(1, 1, 2016) dates = [ Date(1, 1, 2017), Date(1, 1, 2018), Date(1, 1, 2019), Date(1, 1, 2020), Date(1, 1, 2021) ] zero_rates = np.array([-0.02, 0.024, 0.047, 0.090, 0.12]) / 100.0 contFreq = FrequencyTypes.ANNUAL interp_type = InterpTypes.LINEAR_ZERO_RATES day_count_type = DayCountTypes.THIRTY_E_360 libor_curve = DiscountCurveZeros(valuation_date, dates, zero_rates, contFreq, day_count_type, interp_type) settlement_date = Date(1, 1, 2016) exercise_date = Date(1, 1, 2017) maturity_date = Date(1, 1, 2020) fixed_coupon = -0.003 fixed_frequency_type = FrequencyTypes.SEMI_ANNUAL fixed_day_count_type = DayCountTypes.THIRTY_E_360_ISDA float_frequency_type = FrequencyTypes.SEMI_ANNUAL float_day_count_type = DayCountTypes.THIRTY_E_360_ISDA notional = 1000.0 # Pricing a PAY swaptionType = SwapTypes.PAY swaption = IborSwaption(settlement_date, exercise_date, maturity_date, swaptionType, fixed_coupon, fixed_frequency_type, fixed_day_count_type, notional, float_frequency_type, float_day_count_type) model = BlackShifted(0.31, 0.008) v_finpy = swaption.value(valuation_date, libor_curve, model) v_matlab = 12.8301 testCases.header("LABEL", "VALUE") testCases.print("FP Price:", v_finpy) testCases.print("MATLAB Prix:", v_matlab) testCases.print("DIFF:", v_finpy - v_matlab) ############################################################################### testCases.header("===================================") testCases.header("MATLAB EXAMPLE WITH HULL WHITE") testCases.header("===================================") # https://fr.mathworks.com/help/fininst/swaptionbyhw.html valuation_date = Date(1, 1, 2007) dates = [ Date(1, 1, 2007), Date(1, 7, 2007), Date(1, 1, 2008), Date(1, 7, 2008), Date(1, 1, 2009), Date(1, 7, 2009), Date(1, 1, 2010), Date(1, 7, 2010), Date(1, 1, 2011), Date(1, 7, 2011), Date(1, 1, 2012) ] zero_rates = np.array([0.075] * 11) interp_type = InterpTypes.FLAT_FWD_RATES day_count_type = DayCountTypes.THIRTY_E_360_ISDA contFreq = FrequencyTypes.SEMI_ANNUAL libor_curve = DiscountCurveZeros(valuation_date, dates, zero_rates, contFreq, day_count_type, interp_type) settlement_date = valuation_date exercise_date = Date(1, 1, 2010) maturity_date = Date(1, 1, 2012) fixed_coupon = 0.04 fixed_frequency_type = FrequencyTypes.SEMI_ANNUAL fixed_day_count_type = DayCountTypes.THIRTY_E_360_ISDA notional = 100.0 swaptionType = SwapTypes.RECEIVE swaption = IborSwaption(settlement_date, exercise_date, maturity_date, swaptionType, fixed_coupon, fixed_frequency_type, fixed_day_count_type, notional) model = HWTree(0.05, 0.01) v_finpy = swaption.value(valuation_date, libor_curve, model) v_matlab = 2.9201 testCases.header("LABEL", "VALUE") testCases.print("FP Price:", v_finpy) testCases.print("MATLAB Prix:", v_matlab) testCases.print("DIFF:", v_finpy - v_matlab) ############################################################################### testCases.header("====================================") testCases.header("MATLAB EXAMPLE WITH BLACK KARASINSKI") testCases.header("====================================") # https://fr.mathworks.com/help/fininst/swaptionbybk.html valuation_date = Date(1, 1, 2007) dates = [ Date(1, 1, 2007), Date(1, 7, 2007), Date(1, 1, 2008), Date(1, 7, 2008), Date(1, 1, 2009), Date(1, 7, 2009), Date(1, 1, 2010), Date(1, 7, 2010), Date(1, 1, 2011), Date(1, 7, 2011), Date(1, 1, 2012) ] zero_rates = np.array([0.07] * 11) interp_type = InterpTypes.FLAT_FWD_RATES day_count_type = DayCountTypes.THIRTY_E_360_ISDA contFreq = FrequencyTypes.SEMI_ANNUAL libor_curve = DiscountCurveZeros(valuation_date, dates, zero_rates, contFreq, day_count_type, interp_type) settlement_date = valuation_date exercise_date = Date(1, 1, 2011) maturity_date = Date(1, 1, 2012) fixed_frequency_type = FrequencyTypes.SEMI_ANNUAL fixed_day_count_type = DayCountTypes.THIRTY_E_360_ISDA notional = 100.0 model = BKTree(0.1, 0.05, 200) fixed_coupon = 0.07 swaptionType = SwapTypes.PAY swaption = IborSwaption(settlement_date, exercise_date, maturity_date, swaptionType, fixed_coupon, fixed_frequency_type, fixed_day_count_type, notional) v_finpy = swaption.value(valuation_date, libor_curve, model) v_matlab = 0.3634 testCases.header("LABEL", "VALUE") testCases.print("FP Price:", v_finpy) testCases.print("MATLAB Prix:", v_matlab) testCases.print("DIFF:", v_finpy - v_matlab) fixed_coupon = 0.0725 swaptionType = SwapTypes.RECEIVE swaption = IborSwaption(settlement_date, exercise_date, maturity_date, swaptionType, fixed_coupon, fixed_frequency_type, fixed_day_count_type, notional) v_finpy = swaption.value(valuation_date, libor_curve, model) v_matlab = 0.4798 testCases.header("LABEL", "VALUE") testCases.print("FP Price:", v_finpy) testCases.print("MATLAB Prix:", v_matlab) testCases.print("DIFF:", v_finpy - v_matlab) ############################################################################### testCases.header("====================================") testCases.header("MATLAB EXAMPLE WITH BLACK-DERMAN-TOY") testCases.header("====================================") # https://fr.mathworks.com/help/fininst/swaptionbybdt.html valuation_date = Date(1, 1, 2007) dates = [ Date(1, 1, 2007), Date(1, 7, 2007), Date(1, 1, 2008), Date(1, 7, 2008), Date(1, 1, 2009), Date(1, 7, 2009), Date(1, 1, 2010), Date(1, 7, 2010), Date(1, 1, 2011), Date(1, 7, 2011), Date(1, 1, 2012) ] zero_rates = np.array([0.06] * 11) interp_type = InterpTypes.FLAT_FWD_RATES day_count_type = DayCountTypes.THIRTY_E_360_ISDA contFreq = FrequencyTypes.ANNUAL libor_curve = DiscountCurveZeros(valuation_date, dates, zero_rates, contFreq, day_count_type, interp_type) settlement_date = valuation_date exercise_date = Date(1, 1, 2012) maturity_date = Date(1, 1, 2015) fixed_frequency_type = FrequencyTypes.ANNUAL fixed_day_count_type = DayCountTypes.THIRTY_E_360_ISDA notional = 100.0 fixed_coupon = 0.062 swaptionType = SwapTypes.PAY swaption = IborSwaption(settlement_date, exercise_date, maturity_date, swaptionType, fixed_coupon, fixed_frequency_type, fixed_day_count_type, notional) model = BDTTree(0.20, 200) v_finpy = swaption.value(valuation_date, libor_curve, model) v_matlab = 2.0592 testCases.header("LABEL", "VALUE") testCases.print("FP Price:", v_finpy) testCases.print("MATLAB Prix:", v_matlab) testCases.print("DIFF:", v_finpy - v_matlab)
def test_FinFXOptionSABR(): # UNFINISHED # There is no FXAmericanOption class. It is embedded in the FXVanillaOption # class. This test just compares it to the European valuation_date = Date(13, 2, 2018) expiry_date = Date(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 ccy1CCRate = 0.030 # EUR ccy2CCRate = 0.025 # USD spot_fx_rate = 1.20 strike_fx_rate = 1.250 volatility = 0.10 notional = 1000000.0 dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate) for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate) model = BlackScholes(volatility) # Two examples to show that changing the notional currency and notional # keeps the value unchanged notional = 1000000.0 spot_fx_rates = np.arange(50, 200, 10)/100.0 testCases.header("OPTION", "FX_RATE", "VALUE_BS", "VOL_IN", "DIFF") for spot_fx_rate in spot_fx_rates: call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_CALL, notional, "USD") valueEuropean = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model)['v'] call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.AMERICAN_CALL, 1000000, "USD") valueAmerican = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model)['v'] diff = (valueAmerican - valueEuropean) testCases.print("CALL:", "%9.6f" % spot_fx_rate, "%9.7f" % valueEuropean, "%9.7f" % valueAmerican, "%9.7f" % diff) testCases.header("OPTION", "FX_RATE", "VALUE_BS", "VOL_IN", "DIFF") for spot_fx_rate in spot_fx_rates: call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_PUT, 1000000, "USD") valueEuropean = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model)['v'] call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.AMERICAN_PUT, 1000000, "USD") valueAmerican = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model)['v'] diff = (valueAmerican - valueEuropean) testCases.print("PUT:", "%9.6f" % spot_fx_rate, "%9.7f" % valueEuropean, "%9.7f" % valueAmerican, "%9.7f" % diff)
def test_FinCDSBasket(): tradeDate = Date(1, 3, 2007) step_in_date = tradeDate.add_days(1) valuation_date = tradeDate.add_days(1) libor_curve = build_Ibor_Curve(tradeDate) basketMaturity = Date(20, 12, 2011) cdsIndex = CDSIndexPortfolio() ########################################################################## testCases.banner( "===================================================================") testCases.banner( "====================== INHOMOGENEOUS CURVE ==========================" ) testCases.banner( "===================================================================") num_credits = 5 spd3Y = 0.0012 spd5Y = 0.0025 spd7Y = 0.0034 spd10Y = 0.0046 testCases.header("LABELS", "VALUE") if 1 == 0: issuer_curves = loadHomogeneousSpreadCurves(valuation_date, libor_curve, spd3Y, spd5Y, spd7Y, spd10Y, num_credits) else: issuer_curves = loadHeterogeneousSpreadCurves(valuation_date, libor_curve) issuer_curves = issuer_curves[0:num_credits] intrinsicSpd = cdsIndex.intrinsic_spread( valuation_date, step_in_date, basketMaturity, issuer_curves) * 10000.0 testCases.print("INTRINSIC SPD BASKET MATURITY", intrinsicSpd) totalSpd = cdsIndex.total_spread(valuation_date, step_in_date, basketMaturity, issuer_curves) * 10000.0 testCases.print("SUMMED UP SPD BASKET MATURITY", totalSpd) minSpd = cdsIndex.min_spread(valuation_date, step_in_date, basketMaturity, issuer_curves) * 10000.0 testCases.print("MINIMUM SPD BASKET MATURITY", minSpd) maxSpd = cdsIndex.max_spread(valuation_date, step_in_date, basketMaturity, issuer_curves) * 10000.0 testCases.print("MAXIMUM SPD BASKET MATURITY", maxSpd) seed = 1967 basket = CDSBasket(valuation_date, basketMaturity) testCases.banner( "===================================================================") testCases.banner( "======================= GAUSSIAN COPULA ===========================") testCases.banner( "===================================================================") testCases.header("TIME", "Trials", "RHO", "NTD", "SPRD", "SPRD_HOMO") for ntd in range(1, num_credits + 1): for beta in [0.0, 0.5]: rho = beta * beta beta_vector = np.ones(num_credits) * beta corr_matrix = corr_matrix_generator(rho, num_credits) for num_trials in [1000]: # [1000,5000,10000,20000,50000,100000]: start = time.time() v1 = basket.value_gaussian_mc(valuation_date, ntd, issuer_curves, corr_matrix, libor_curve, num_trials, seed) v2 = basket.value_1f_gaussian_homo(valuation_date, ntd, issuer_curves, beta_vector, libor_curve) end = time.time() period = (end - start) testCases.print(period, num_trials, rho, ntd, v1[2] * 10000, v2[3] * 10000) testCases.banner( "===================================================================") testCases.banner( "==================== STUDENT'S-T CONVERGENCE ======================") testCases.banner( "===================================================================") testCases.header("TIME", "TRIALS", "RHO", "DOF", "NTD", "SPRD") for beta in [0.0, 0.5]: rho = beta**2 corr_matrix = corr_matrix_generator(rho, num_credits) for ntd in range(1, num_credits + 1): for doF in [3, 6]: start = time.time() v = basket.value_student_t_mc(valuation_date, ntd, issuer_curves, corr_matrix, doF, libor_curve, num_trials, seed) end = time.time() period = (end - start) testCases.print(period, num_trials, rho, doF, ntd, v[2] * 10000) start = time.time() v = basket.value_gaussian_mc(valuation_date, ntd, issuer_curves, corr_matrix, libor_curve, num_trials, seed) end = time.time() period = (end - start) testCases.print(period, num_trials, rho, "GC", ntd, v[2] * 10000) testCases.banner( "===================================================================") testCases.banner( "=================== STUDENT'S T WITH DOF = 5 ======================") testCases.banner( "===================================================================") doF = 5 testCases.header("TIME", "NUMTRIALS", "RHO", "NTD", "SPD") for beta in [0.0, 0.5]: rho = beta**2 corr_matrix = corr_matrix_generator(rho, num_credits) for ntd in range(1, num_credits + 1): for num_trials in [1000]: start = time.time() v = basket.value_student_t_mc(valuation_date, ntd, issuer_curves, corr_matrix, doF, libor_curve, num_trials, seed) end = time.time() period = (end - start) testCases.print(period, num_trials, rho, ntd, v[2] * 10000)
def test_Bond(): 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']) freq_type = FrequencyTypes.SEMI_ANNUAL settlement_date = Date(19, 9, 2012) face = ONE_MILLION for accrual_type in DayCountTypes: testCases.header("MATURITY", "COUPON", "CLEAN_PRICE", "ACCD_DAYS", "ACCRUED", "YTM") for _, bond in bondDataFrame.iterrows(): dateString = bond['maturity'] matDatetime = dt.datetime.strptime(dateString, '%d-%b-%y') maturityDt = fromDatetime(matDatetime) issueDt = Date(maturityDt._d, maturityDt._m, 2000) coupon = bond['coupon'] / 100.0 clean_price = bond['mid'] bond = Bond(issueDt, maturityDt, coupon, freq_type, accrual_type, 100) ytm = bond.yield_to_maturity(settlement_date, clean_price) accrued_interest= bond._accruedInterest accd_days = bond._accrued_days testCases.print("%18s" % maturityDt, "%8.4f" % coupon, "%10.4f" % clean_price, "%6.0f" % accd_days, "%10.4f" % accrued_interest, "%8.4f" % ytm) ########################################################################### # EXAMPLE FROM http://bondtutor.com/btchp4/topic6/topic6.htm accrualConvention = DayCountTypes.ACT_ACT_ICMA y = 0.062267 settlement_date = Date(19, 4, 1994) issue_date = Date(15, 7, 1990) maturity_date = Date(15, 7, 1997) coupon = 0.085 face = ONE_MILLION freq_type = FrequencyTypes.SEMI_ANNUAL bond = Bond(issue_date, maturity_date, coupon, freq_type, accrualConvention, face) testCases.header("FIELD", "VALUE") full_price = bond.full_price_from_ytm(settlement_date, y) testCases.print("Full Price = ", full_price) clean_price = bond.clean_price_from_ytm(settlement_date, y) testCases.print("Clean Price = ", clean_price) accrued_interest= bond._accruedInterest testCases.print("Accrued = ", accrued_interest) ytm = bond.yield_to_maturity(settlement_date, clean_price) testCases.print("Yield to Maturity = ", ytm) bump = 1e-4 priceBumpedUp = bond.full_price_from_ytm(settlement_date, y + bump) testCases.print("Price Bumped Up:", priceBumpedUp) priceBumpedDn = bond.full_price_from_ytm(settlement_date, y - bump) testCases.print("Price Bumped Dn:", priceBumpedDn) durationByBump = -(priceBumpedUp - full_price) / bump testCases.print("Duration by Bump = ", durationByBump) duration = bond.dollar_duration(settlement_date, y) testCases.print("Dollar Duration = ", duration) testCases.print("Duration Difference:", duration - durationByBump) modified_duration = bond.modified_duration(settlement_date, y) testCases.print("Modified Duration = ", modified_duration) macauley_duration = bond.macauley_duration(settlement_date, y) testCases.print("Macauley Duration = ", macauley_duration) conv = bond.convexity_from_ytm(settlement_date, y) testCases.print("Convexity = ", conv) # ASSET SWAP SPREAD # When the libor curve is the flat bond curve then the ASW is zero by # definition flatCurve = DiscountCurveFlat(settlement_date, ytm, FrequencyTypes.SEMI_ANNUAL) testCases.header("FIELD", "VALUE") clean_price = bond.clean_price_from_ytm(settlement_date, ytm) asw = bond.asset_swap_spread(settlement_date, clean_price, flatCurve) testCases.print("Discounted on Bond Curve ASW:", asw * 10000) # When the libor curve is the Libor curve then the ASW is positive libor_curve = buildIborCurve(settlement_date) asw = bond.asset_swap_spread(settlement_date, clean_price, libor_curve) oas = bond.option_adjusted_spread(settlement_date, clean_price, libor_curve) testCases.print("Discounted on LIBOR Curve ASW:", asw * 10000) testCases.print("Discounted on LIBOR Curve OAS:", oas * 10000) p = 90.0 asw = bond.asset_swap_spread(settlement_date, p, libor_curve) oas = bond.option_adjusted_spread(settlement_date, p, libor_curve) testCases.print("Deep discount bond at 90 ASW:", asw * 10000) testCases.print("Deep discount bond at 90 OAS:", oas * 10000) p = 100.0 asw = bond.asset_swap_spread(settlement_date, p, libor_curve) oas = bond.option_adjusted_spread(settlement_date, p, libor_curve) testCases.print("Par bond at 100 ASW:", asw * 10000) testCases.print("Par bond at 100 OAS:", oas * 10000) p = 120.0 asw = bond.asset_swap_spread(settlement_date, p, libor_curve) oas = bond.option_adjusted_spread(settlement_date, p, libor_curve) testCases.print("Above par bond at 120 ASW:", asw * 10000) testCases.print("Above par bond at 120 OAS:", oas * 10000) ########################################################################## # https://data.bloomberglp.com/bat/sites/3/2017/07/SF-2017_Paul-Fjeldsted.pdf # Page 10 TREASURY NOTE SCREENSHOT ########################################################################## testCases.banner("BLOOMBERG US TREASURY EXAMPLE") settlement_date = Date(21, 7, 2017) issue_date = Date(15, 5, 2010) maturity_date = Date(15, 5, 2027) coupon = 0.02375 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA face = 100.0 bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type, face) testCases.header("FIELD", "VALUE") clean_price = 99.7808417 yld = bond.current_yield(clean_price) testCases.print("Current Yield = ", yld) ytm = bond.yield_to_maturity(settlement_date, clean_price, FinYTMCalcType.UK_DMO) testCases.print("UK DMO Yield To Maturity = ", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, FinYTMCalcType.US_STREET) testCases.print("US STREET Yield To Maturity = ", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, FinYTMCalcType.US_TREASURY) testCases.print("US TREASURY Yield To Maturity = ", ytm) full_price = bond.full_price_from_ytm(settlement_date, ytm) testCases.print("Full Price = ", full_price) clean_price = bond.clean_price_from_ytm(settlement_date, ytm) testCases.print("Clean Price = ", clean_price) accrued_interest= bond._accruedInterest testCases.print("Accrued = ", accrued_interest) accddays = bond._accrued_days testCases.print("Accrued Days = ", accddays) duration = bond.dollar_duration(settlement_date, ytm) testCases.print("Dollar Duration = ", duration) modified_duration = bond.modified_duration(settlement_date, ytm) testCases.print("Modified Duration = ", modified_duration) macauley_duration = bond.macauley_duration(settlement_date, ytm) testCases.print("Macauley Duration = ", macauley_duration) conv = bond.convexity_from_ytm(settlement_date, ytm) testCases.print("Convexity = ", conv) ########################################################################## # Page 11 APPLE NOTE SCREENSHOT ########################################################################## testCases.banner("BLOOMBERG APPLE CORP BOND EXAMPLE") settlement_date = Date(21, 7, 2017) issue_date = Date(13, 5, 2012) maturity_date = Date(13, 5, 2022) coupon = 0.027 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.THIRTY_E_360_ISDA face = 100.0 bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type, face) testCases.header("FIELD", "VALUE") clean_price = 101.581564 yld = bond.current_yield(clean_price) testCases.print("Current Yield", yld) ytm = bond.yield_to_maturity(settlement_date, clean_price, FinYTMCalcType.UK_DMO) testCases.print("UK DMO Yield To Maturity", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, FinYTMCalcType.US_STREET) testCases.print("US STREET Yield To Maturity", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, FinYTMCalcType.US_TREASURY) testCases.print("US TREASURY Yield To Maturity", ytm) full_price = bond.full_price_from_ytm(settlement_date, ytm) testCases.print("Full Price", full_price) clean_price = bond.clean_price_from_ytm(settlement_date, ytm) testCases.print("Clean Price", clean_price) accddays = bond._accrued_days testCases.print("Accrued Days", accddays) accrued_interest= bond._accruedInterest testCases.print("Accrued", accrued_interest) duration = bond.dollar_duration(settlement_date, ytm) testCases.print("Dollar Duration", duration) modified_duration = bond.modified_duration(settlement_date, ytm) testCases.print("Modified Duration", modified_duration) macauley_duration = bond.macauley_duration(settlement_date, ytm) testCases.print("Macauley Duration", macauley_duration) conv = bond.convexity_from_ytm(settlement_date, ytm) testCases.print("Convexity", conv)
def test_FinSchedule(): ########################################################################### # BACKWARD SCHEDULES TESTING DIFFERENT FREQUENCIES ########################################################################### d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.SEMI_ANNUAL calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD termination_dateAdjust = True schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("BACKWARD SEMI-ANNUAL FREQUENCY", schedule) d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.QUARTERLY calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("BACKWARD QUARTERLY FREQUENCY", schedule) d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.MONTHLY calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("BACKWARD MONTHLY FREQUENCY", schedule) ########################################################################### # FORWARD SCHEDULES TESTING DIFFERENT FREQUENCIES ########################################################################### d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.ANNUAL calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.FORWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("FORWARD ANNUAL", schedule) d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.SEMI_ANNUAL calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type) dumpSchedule("FORWARD SEMI-ANNUAL", schedule) d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.MONTHLY calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("FORWARD MONTHLY", schedule) ########################################################################### # BACKWARD SHORT STUB AT FRONT ########################################################################### d1 = Date(20, 8, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.QUARTERLY calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("BACKWARD GEN WITH SHORT END STUB", schedule) ########################################################################### # BACKWARD SUPER SHORT STUB AT FRONT ########################################################################### d1 = Date(19, 9, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.QUARTERLY calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("BACKWARD GEN WITH VERY SHORT END STUB", schedule) ########################################################################### # FORWARD SHORT STUB AT END ########################################################################### d1 = Date(20, 8, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.SEMI_ANNUAL calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.FORWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("FORWARD GEN WITH END STUB", schedule) d1 = Date(19, 9, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.QUARTERLY calendar_type = CalendarTypes.TARGET bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.FORWARD schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type) dumpSchedule("FORWARD GEN WITH VERY SHORT END STUB", schedule) d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.SEMI_ANNUAL calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD termination_dateAdjust = True schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust) dumpSchedule("TERMINATION DATE ADJUSTED", schedule) d1 = Date(20, 6, 2018) d2 = Date(20, 6, 2020) freq_type = FrequencyTypes.SEMI_ANNUAL calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.MODIFIED_FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD termination_dateAdjust = True eomFlag = True schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust, eomFlag) dumpSchedule("END OF MONTH - NOT EOM TERM DATE - USING MOD FOLL", schedule) d1 = Date(30, 6, 2018) d2 = Date(30, 6, 2020) freq_type = FrequencyTypes.SEMI_ANNUAL calendar_type = CalendarTypes.WEEKEND bus_day_adjust_type = BusDayAdjustTypes.MODIFIED_FOLLOWING date_gen_rule_type = DateGenRuleTypes.BACKWARD termination_dateAdjust = True eomFlag = True schedule = Schedule(d1, d2, freq_type, calendar_type, bus_day_adjust_type, date_gen_rule_type, termination_dateAdjust, eomFlag) dumpSchedule("END OF MONTH - EOM TERM DATE - USING MOD FOLL", schedule)
def buildFullIssuerCurve1(mktSpreadBump, irBump): # https://www.markit.com/markit.jsp?jsppage=pv.jsp # YIELD CURVE 8-AUG-2019 SNAP AT 1600 tradeDate = Date(9, 8, 2019) valuation_date = tradeDate.add_days(1) m = 1.0 # 0.00000000000 dcType = DayCountTypes.ACT_360 depos = [] depo1 = IborDeposit(valuation_date, "1D", m * 0.0220, dcType) depos.append(depo1) spot_days = 2 settlement_date = valuation_date.add_days(spot_days) maturity_date = settlement_date.add_months(1) depo1 = IborDeposit(settlement_date, maturity_date, m * 0.022009, dcType) maturity_date = settlement_date.add_months(2) depo2 = IborDeposit(settlement_date, maturity_date, m * 0.022138, dcType) maturity_date = settlement_date.add_months(3) depo3 = IborDeposit(settlement_date, maturity_date, m * 0.021810, dcType) maturity_date = settlement_date.add_months(6) depo4 = IborDeposit(settlement_date, maturity_date, m * 0.020503, dcType) maturity_date = settlement_date.add_months(12) depo5 = IborDeposit(settlement_date, maturity_date, m * 0.019930, dcType) depos.append(depo1) depos.append(depo2) depos.append(depo3) depos.append(depo4) depos.append(depo5) fras = [] swaps = [] dcType = DayCountTypes.THIRTY_E_360_ISDA fixedFreq = FrequencyTypes.SEMI_ANNUAL maturity_date = settlement_date.add_months(24) swap1 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.015910 + irBump, fixedFreq, dcType) swaps.append(swap1) maturity_date = settlement_date.add_months(36) swap2 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.014990 + irBump, fixedFreq, dcType) swaps.append(swap2) maturity_date = settlement_date.add_months(48) swap3 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.014725 + irBump, fixedFreq, dcType) swaps.append(swap3) maturity_date = settlement_date.add_months(60) swap4 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.014640 + irBump, fixedFreq, dcType) swaps.append(swap4) maturity_date = settlement_date.add_months(72) swap5 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.014800 + irBump, fixedFreq, dcType) swaps.append(swap5) maturity_date = settlement_date.add_months(84) swap6 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.014995 + irBump, fixedFreq, dcType) swaps.append(swap6) maturity_date = settlement_date.add_months(96) swap7 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.015180 + irBump, fixedFreq, dcType) swaps.append(swap7) maturity_date = settlement_date.add_months(108) swap8 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.015610 + irBump, fixedFreq, dcType) swaps.append(swap8) maturity_date = settlement_date.add_months(120) swap9 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.015880 + irBump, fixedFreq, dcType) swaps.append(swap9) maturity_date = settlement_date.add_months(144) swap10 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.016430 + irBump, fixedFreq, dcType) swaps.append(swap10) libor_curve = IborSingleCurve(valuation_date, depos, fras, swaps) cdsMarketContracts = [] cdsCoupon = 0.04 + mktSpreadBump maturity_date = valuation_date.next_cds_date(6) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(12) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(24) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(36) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(48) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(60) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(84) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(120) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) maturity_date = valuation_date.next_cds_date(180) cds = CDS(valuation_date, maturity_date, cdsCoupon) cdsMarketContracts.append(cds) recovery_rate = 0.40 issuer_curve = CDSCurve(valuation_date, cdsMarketContracts, libor_curve, recovery_rate) return libor_curve, 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_full_priceCDS1(): mktSpread = 0.040 testCases.header("Example", "Markit 9 Aug 2019") libor_curve, issuer_curve = buildFullIssuerCurve1(0.0, 0.0) # This is the 10 year contract at an off market coupon maturity_date = Date(20, 6, 2029) cdsCoupon = 0.0150 notional = ONE_MILLION long_protection = True tradeDate = Date(9, 8, 2019) valuation_date = tradeDate.add_days(1) effective_date = valuation_date cds_contract = CDS(effective_date, maturity_date, cdsCoupon, notional, long_protection) cdsRecovery = 0.40 testCases.header("LABEL", "VALUE") spd = cds_contract.par_spread(valuation_date, issuer_curve, cdsRecovery) * 10000.0 testCases.print("PAR_SPREAD", spd) v = cds_contract.value(valuation_date, issuer_curve, cdsRecovery) testCases.print("FULL_VALUE", v['full_pv']) testCases.print("CLEAN_VALUE", v['clean_pv']) p = cds_contract.clean_price(valuation_date, issuer_curve, cdsRecovery) testCases.print("CLEAN_PRICE", p) # MARKIT PRICE IS 168517 accrued_days = cds_contract.accrued_days() testCases.print("ACCRUED_DAYS", accrued_days) accrued_interest = cds_contract.accrued_interest() testCases.print("ACCRUED_COUPON", accrued_interest) prot_pv = cds_contract.protection_leg_pv(valuation_date, issuer_curve, cdsRecovery) testCases.print("PROTECTION_PV", prot_pv) premPV = cds_contract.premium_leg_pv(valuation_date, issuer_curve, cdsRecovery) testCases.print("PREMIUM_PV", premPV) fullRPV01, cleanRPV01 = cds_contract.risky_pv01(valuation_date, issuer_curve) testCases.print("FULL_RPV01", fullRPV01) testCases.print("CLEAN_RPV01", cleanRPV01) # cds_contract.print_flows(issuer_curve) bump = 1.0 / 10000.0 # 1 bp libor_curve, issuer_curve = buildFullIssuerCurve1(bump, 0) v_bump = cds_contract.value(valuation_date, issuer_curve, cdsRecovery) dv = v_bump['full_pv'] - v['full_pv'] testCases.print("CREDIT_DV01", dv) # Interest Rate Bump libor_curve, issuer_curve = buildFullIssuerCurve1(0, bump) v_bump = cds_contract.value(valuation_date, issuer_curve, cdsRecovery) dv = v_bump['full_pv'] - v['full_pv'] testCases.print("INTEREST_DV01", dv) t = (maturity_date - valuation_date) / gDaysInYear z = libor_curve.df(maturity_date) r = -np.log(z) / t v_approx = cds_contract.value_fast_approx(valuation_date, r, mktSpread, cdsRecovery) testCases.print("FULL APPROX VALUE", v_approx[0]) testCases.print("CLEAN APPROX VALUE", v_approx[1]) testCases.print("APPROX CREDIT DV01", v_approx[2]) testCases.print("APPROX INTEREST DV01", v_approx[3])
def test_FinOptionImpliedDbn(): if 1 == 1: # Example from Book extract by Iain Clark using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARK") valuation_date = Date(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD dom_discount_curve = DiscountCurveFlat(valuation_date, domCCRate) for_discount_curve = DiscountCurveFlat(valuation_date, forCCRate) currency_pair = forName + domName spot_fx_rate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atm_vols = [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] notional_currency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA fxMarket = FXVolSurface(valuation_date, spot_fx_rate, currency_pair, notional_currency, dom_discount_curve, for_discount_curve, tenors, atm_vols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod) # fxMarket.check_calibration(True) PLOT_GRAPHS = False if PLOT_GRAPHS: fxMarket.plot_vol_curves() for iTenor in range(0, len(fxMarket._tenors)): F = fxMarket._F0T[iTenor] texp = fxMarket._texp[iTenor] startFX = F * 0.05 endFX = F * 5.0 num_steps = 10000 dFX = (endFX - startFX) / num_steps domDF = dom_discount_curve._df(texp) forDF = for_discount_curve._df(texp) rd = -np.log(domDF) / texp rf = -np.log(forDF) / texp params = fxMarket._parameters[iTenor] strikes = [] vols = [] for iK in range(0, num_steps): strike = startFX + iK * dFX vol = vol_function_clark(params, F, strike, texp) strikes.append(strike) vols.append(vol) strikes = np.array(strikes) vols = np.array(vols)
def buildFullIssuerCurve2(mktSpreadBump, irBump): # https://www.markit.com/markit.jsp?jsppage=pv.jsp # YIELD CURVE 20 August 2020 SNAP AT 1600 m = 1.0 valuation_date = Date(24, 8, 2020) settlement_date = Date(24, 8, 2020) dcType = DayCountTypes.ACT_360 depos = [] maturity_date = settlement_date.add_months(1) depo1 = IborDeposit(settlement_date, maturity_date, m * 0.001709, dcType) maturity_date = settlement_date.add_months(2) depo2 = IborDeposit(settlement_date, maturity_date, m * 0.002123, dcType) maturity_date = settlement_date.add_months(3) depo3 = IborDeposit(settlement_date, maturity_date, m * 0.002469, dcType) maturity_date = settlement_date.add_months(6) depo4 = IborDeposit(settlement_date, maturity_date, m * 0.003045, dcType) maturity_date = settlement_date.add_months(12) depo5 = IborDeposit(settlement_date, maturity_date, m * 0.004449, dcType) depos.append(depo1) depos.append(depo2) depos.append(depo3) depos.append(depo4) depos.append(depo5) swaps = [] dcType = DayCountTypes.THIRTY_E_360_ISDA fixedFreq = FrequencyTypes.SEMI_ANNUAL maturity_date = settlement_date.add_months(24) swap1 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.002155 + irBump, fixedFreq, dcType) swaps.append(swap1) maturity_date = settlement_date.add_months(36) swap2 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.002305 + irBump, fixedFreq, dcType) swaps.append(swap2) maturity_date = settlement_date.add_months(48) swap3 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.002665 + irBump, fixedFreq, dcType) swaps.append(swap3) maturity_date = settlement_date.add_months(60) swap4 = IborSwap(settlement_date, maturity_date, SwapTypes.PAY, m * 0.003290 + irBump, fixedFreq, dcType) swaps.append(swap4) libor_curve = IborSingleCurve(valuation_date, depos, [], swaps) cdsCoupon = 0.01 + mktSpreadBump cdsMarketContracts = [] effective_date = Date(21, 8, 2020) cds = CDS(effective_date, "6M", cdsCoupon) cdsMarketContracts.append(cds) cds = CDS(effective_date, "1Y", cdsCoupon) cdsMarketContracts.append(cds) cds = CDS(effective_date, "2Y", cdsCoupon) cdsMarketContracts.append(cds) cds = CDS(effective_date, "3Y", cdsCoupon) cdsMarketContracts.append(cds) cds = CDS(effective_date, "4Y", cdsCoupon) cdsMarketContracts.append(cds) cds = CDS(effective_date, "5Y", cdsCoupon) cdsMarketContracts.append(cds) cds = CDS(effective_date, "7Y", cdsCoupon) cdsMarketContracts.append(cds) cds = CDS(effective_date, "10Y", cdsCoupon) cdsMarketContracts.append(cds) recovery_rate = 0.40 issuer_curve = CDSCurve(settlement_date, cdsMarketContracts, libor_curve, recovery_rate) testCases.header("DATE", "DISCOUNT_FACTOR", "SURV_PROB") years = np.linspace(0.0, 10.0, 20) dates = settlement_date.add_years(years) for dt in dates: df = libor_curve.df(dt) q = issuer_curve.survival_prob(dt) testCases.print("%16s" % dt, "%12.8f" % df, "%12.8f" % q) return libor_curve, issuer_curve
def test_FinSwaptionVolSurface1(verboseCalibration): ########################################################################### if 1 == 1: # https://fr.mathworks.com/help/fininst/pricing-a-swaption-using-the-sabr-model.html valuation_date = Date(12, 6, 2013) # These are 3M, 1Y, 2Y, 3Y, 4Y, 5Y, 7Y, 10Y exerciseDates = [Date(12, 9, 2013), Date(12, 6, 2014), Date(12, 6, 2015), Date(12, 6, 2016), Date(12, 6, 2017), Date(12, 6, 2018), Date(12, 6, 2020), Date(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 discount_curve = DiscountCurveFlat(valuation_date, rfrRate) divRate = 0.010 # USD dividendCurve = DiscountCurveFlat(valuation_date, divRate) volFunctionType = FinVolFunctionTypes.SABR_BETA_HALF swaptionSurface = FinSwaptionVolSurface(valuation_date, exerciseDates, fwdSwapRates, marketStrikes, marketVolatilities, volFunctionType) tol = 1e-4 swaptionSurface.checkCalibration(False, tol) if 1==1: # PLOT_GRAPHS: swaptionSurface.plotVolCurves()
def test_full_priceCDSModelCheck(): testCases.print("Example", "MARKIT CHECK 19 Aug 2020") libor_curve, issuer_curve = buildFullIssuerCurve2(0.0, 0.0) # This is the 10 year contract at an off market coupon maturity_date = Date(20, 6, 2025) cdsCoupon = 0.050 notional = ONE_MILLION long_protection = True tradeDate = Date(20, 8, 2020) effective_date = Date(21, 8, 2020) valuation_date = tradeDate cds_contract = CDS(effective_date, maturity_date, cdsCoupon, notional, long_protection) cdsRecovery = 0.40 testCases.header("LABEL", "VALUE") spd = cds_contract.par_spread(valuation_date, issuer_curve, cdsRecovery) * 10000.0 testCases.print("PAR_SPREAD", spd) v = cds_contract.value(valuation_date, issuer_curve, cdsRecovery) testCases.print("FULL_VALUE", v['full_pv']) testCases.print("CLEAN_VALUE", v['clean_pv']) p = cds_contract.clean_price(valuation_date, issuer_curve, cdsRecovery) testCases.print("CLEAN_PRICE", p) accrued_days = cds_contract.accrued_days() testCases.print("ACCRUED_DAYS", accrued_days) accrued_interest = cds_contract.accrued_interest() testCases.print("ACCRUED_COUPON", accrued_interest) prot_pv = cds_contract.protection_leg_pv(valuation_date, issuer_curve, cdsRecovery) testCases.print("PROTECTION_PV", prot_pv) premPV = cds_contract.premium_leg_pv(valuation_date, issuer_curve, cdsRecovery) testCases.print("PREMIUM_PV", premPV) rpv01 = cds_contract.risky_pv01(valuation_date, issuer_curve) testCases.print("FULL_RPV01", rpv01['full_rpv01']) testCases.print("CLEAN_RPV01", rpv01['clean_rpv01']) credit_dv01 = cds_contract.credit_dv01(valuation_date, issuer_curve, cdsRecovery) testCases.print("CREDIT DV01", credit_dv01) interest_dv01 = cds_contract.interest_dv01(valuation_date, issuer_curve, cdsRecovery) testCases.print("INTEREST DV01", interest_dv01) # Consider fast approximation t = (maturity_date - valuation_date) / gDaysInYear z = libor_curve.df(maturity_date) r = -np.log(z) / t mktSpread = 0.01 v_approx = cds_contract.value_fast_approx(valuation_date, r, mktSpread, cdsRecovery) testCases.header("FAST VALUATIONS", "VALUE") testCases.print("FULL APPROX VALUE", v_approx[0]) testCases.print("CLEAN APPROX VALUE", v_approx[1]) testCases.print("APPROX CREDIT DV01", v_approx[2]) testCases.print("APPROX INTEREST DV01", v_approx[3])