def test_BondOptionAmericanConvergenceONE(): # Build discount curve settlement_date = Date(1, 12, 2019) discount_curve = DiscountCurveFlat(settlement_date, 0.05) # Bond details issue_date = Date(1, 9, 2014) maturity_date = Date(1, 9, 2025) 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) # Option Details expiry_date = Date(1, 12, 2020) strike_price = 100.0 face = 100.0 testCases.header("TIME", "N", "PUT_AMER", "PUT_EUR", "CALL_AME", "CALL_EUR") timeSteps = range(100, 500, 100) for num_time_steps in timeSteps: sigma = 0.05 a = 0.1 start = time.time() option_type = FinOptionTypes.AMERICAN_PUT bond_option1 = BondOption(bond, expiry_date, strike_price, face, option_type) model1 = HWTree(sigma, a, num_time_steps) v1put = bond_option1.value(settlement_date, discount_curve, model1) option_type = FinOptionTypes.EUROPEAN_PUT bond_option2 = BondOption(bond, expiry_date, strike_price, face, option_type) model2 = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_ONLY) v2put = bond_option2.value(settlement_date, discount_curve, model2) option_type = FinOptionTypes.AMERICAN_CALL bond_option1 = BondOption(bond, expiry_date, strike_price, face, option_type) model1 = HWTree(sigma, a, num_time_steps) v1call = bond_option1.value(settlement_date, discount_curve, model1) option_type = FinOptionTypes.EUROPEAN_CALL bond_option2 = BondOption(bond, expiry_date, strike_price, face, option_type) model2 = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_TREE) v2call = bond_option2.value(settlement_date, discount_curve, model2) end = time.time() period = end - start testCases.print(period, num_time_steps, v1put, v2put, v1call, v2call)
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, FinOptionTypes.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, FinOptionTypes.EUROPEAN_CALL) v_ec = europeanCallBondOption.value(settlement_date, discount_curve, bkModel) americanCallBondOption = BondOption(bond, expiry_date, K, face, FinOptionTypes.AMERICAN_CALL) v_ac = americanCallBondOption.value(settlement_date, discount_curve, bkModel) europeanPutBondOption = BondOption(bond, expiry_date, K, face, FinOptionTypes.EUROPEAN_PUT) v_ep = europeanPutBondOption.value(settlement_date, discount_curve, bkModel) americanPutBondOption = BondOption(bond, expiry_date, K, face, FinOptionTypes.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_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 = FinOptionTypes.EUROPEAN_CALL bond_option1 = BondOption(bond, expiry_date, strike_price, face, option_type) v1 = bond_option1.value(settlement_date, discount_curve, model) option_type = FinOptionTypes.AMERICAN_CALL bond_option2 = BondOption(bond, expiry_date, strike_price, face, option_type) v2 = bond_option2.value(settlement_date, discount_curve, model) option_type = FinOptionTypes.EUROPEAN_PUT bond_option3 = BondOption(bond, expiry_date, strike_price, face, option_type) v3 = bond_option3.value(settlement_date, discount_curve, model) option_type = FinOptionTypes.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_BondEmbeddedOptionQUANTLIB(): # Based on example at the nice blog on Quantlib at # http://gouthamanbalaraman.com/blog/callable-bond-quantlib-python.html # I get a price of 68.97 for 1000 time steps which is higher than the # 68.38 found in blog article. But this is for 40 grid points. # Note also that a basis point vol of 0.120 is 12% which is VERY HIGH! valuation_date = Date(16, 8, 2016) settlement_date = valuation_date.addWeekDays(3) ########################################################################### discount_curve = DiscountCurveFlat(valuation_date, 0.035, FrequencyTypes.SEMI_ANNUAL) ########################################################################### issue_date = Date(15, 9, 2010) maturity_date = Date(15, 9, 2022) coupon = 0.025 freq_type = FrequencyTypes.QUARTERLY accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) ########################################################################### # Set up the call and put times and prices ########################################################################### nextCallDate = Date(15, 9, 2016) call_dates = [nextCallDate] call_prices = [100.0] for _ in range(1, 24): nextCallDate = nextCallDate.addMonths(3) call_dates.append(nextCallDate) call_prices.append(100.0) put_dates = [] put_prices = [] # the value used in blog of 12% bp vol is unrealistic sigma = 0.12 # basis point volatility a = 0.03 puttableBond = BondEmbeddedOption(issue_date, maturity_date, coupon, freq_type, accrual_type, call_dates, call_prices, put_dates, put_prices) testCases.header("BOND PRICE", "PRICE") v = bond.clean_price_from_discount_curve(settlement_date, discount_curve) testCases.print("Bond Pure Price:", v) testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure") timeSteps = range(100, 1000, 100) values = [] for numTimeSteps in timeSteps: model = FinModelRatesHW(sigma, a, numTimeSteps) start = time.time() v = puttableBond.value(settlement_date, discount_curve, model) end = time.time() period = end - start testCases.print(period, numTimeSteps, v['bondwithoption'], v['bondpure']) values.append(v['bondwithoption']) if plotGraphs: plt.figure() plt.title("Puttable Bond Price Convergence") plt.plot(timeSteps, values)
def test_EquityOneTouchOption(): # Examples Haug Page 180 Table 4-22 # Agreement not exact at t is not exactly 0.50 valuation_date = Date(1, 1, 2016) expiry_date = Date(2, 7, 2016) interest_rate = 0.10 volatility = 0.20 barrier_level = 100.0 # H model = BlackScholes(volatility) dividend_yield = 0.03 num_paths = 10000 num_steps_per_year = 252 discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) stock_price = 105.0 payment_size = 15.0 testCases.header("================================= CASH ONLY") downTypes = [ FinTouchOptionPayoffTypes.DOWN_AND_IN_CASH_AT_HIT, FinTouchOptionPayoffTypes.DOWN_AND_IN_CASH_AT_EXPIRY, FinTouchOptionPayoffTypes.DOWN_AND_OUT_CASH_OR_NOTHING ] testCases.header("TYPE", "VALUE", "VALUE_MC") for downType in downTypes: option = EquityOneTouchOption(expiry_date, downType, barrier_level, payment_size) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % downType, "%9.5f" % v, "%9.5f" % v_mc) stock_price = 95.0 payment_size = 15.0 upTypes = [ FinTouchOptionPayoffTypes.UP_AND_IN_CASH_AT_HIT, FinTouchOptionPayoffTypes.UP_AND_IN_CASH_AT_EXPIRY, FinTouchOptionPayoffTypes.UP_AND_OUT_CASH_OR_NOTHING ] testCases.header("TYPE", "VALUE", "VALUE_MC") for upType in upTypes: option = EquityOneTouchOption(expiry_date, upType, barrier_level, payment_size) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % upType, "%9.5f" % v, "%9.5f" % v_mc) ########################################################################### stock_price = 105.0 testCases.banner("================= ASSET ONLY") downTypes = [ FinTouchOptionPayoffTypes.DOWN_AND_IN_ASSET_AT_HIT, FinTouchOptionPayoffTypes.DOWN_AND_IN_ASSET_AT_EXPIRY, FinTouchOptionPayoffTypes.DOWN_AND_OUT_ASSET_OR_NOTHING ] testCases.header("TYPE", "VALUE", "VALUE_MC") for downType in downTypes: option = EquityOneTouchOption(expiry_date, downType, barrier_level) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % downType, "%9.5f" % v, "%9.5f" % v_mc) stock_price = 95.0 upTypes = [ FinTouchOptionPayoffTypes.UP_AND_IN_ASSET_AT_HIT, FinTouchOptionPayoffTypes.UP_AND_IN_ASSET_AT_EXPIRY, FinTouchOptionPayoffTypes.UP_AND_OUT_ASSET_OR_NOTHING ] for upType in upTypes: option = EquityOneTouchOption(expiry_date, upType, barrier_level) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % upType, "%9.5f" % v, "%9.5f" % v_mc)
def test_FinInflationBondStack(): ########################################################################## # https://stackoverflow.com/questions/57676724/failing-to-obtain-correct-accrued-interest-with-quantlib-inflation-bond-pricer-i ########################################################################## testCases.banner("=============================") testCases.banner("QUANT FINANCE US TIPS EXAMPLE") testCases.banner("=============================") settlement_date = Date(23, 8, 2019) issue_date = Date(25, 9, 2013) maturity_date = Date(22, 3, 2068) coupon = 0.00125 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA face = 100.0 baseCPIValue = 249.70 ########################################################################### # Discount curve discount_curve = DiscountCurveFlat(settlement_date, 0.01033692, FrequencyTypes.ANNUAL, DayCountTypes.ACT_ACT_ISDA) lag = 3 fixingCPI = 244.65884 fixingDate = settlement_date.add_months(-lag) ########################################################################### # Create Index Curve months = range(0, 12, 1) fixingDates = Date(31, 8, 2018).add_months(months) fixingRates = [ 284.2, 284.1, 284.5, 284.6, 285.6, 283.0, 285.0, 285.1, 288.2, 289.2, 289.6, 289.5 ] inflationIndex = FinInflationIndexCurve(fixingDates, fixingRates, lag) # print(inflationIndex) ########################################################################### zciisData = [(Date(31, 7, 2020), 3.1500000000137085), (Date(31, 7, 2021), 3.547500000013759), (Date(31, 7, 2022), 3.675000000013573), (Date(31, 7, 2023), 3.7250000000134342), (Date(31, 7, 2024), 3.750000000013265), (Date(31, 7, 2025), 3.7430000000129526), (Date(31, 7, 2026), 3.741200000012679), (Date(31, 7, 2027), 3.7337000000123632), (Date(31, 7, 2028), 3.725000000011902), (Date(31, 7, 2029), 3.720000000011603), (Date(31, 7, 2030), 3.712517289063011), (Date(31, 7, 2031), 3.7013000000108764), (Date(31, 7, 2032), 3.686986039205209), (Date(31, 7, 2033), 3.671102614032895), (Date(31, 7, 2034), 3.655000000009778), (Date(31, 7, 2035), 3.6394715951305834), (Date(31, 7, 2036), 3.624362044800966), (Date(31, 7, 2037), 3.6093619727979087), (Date(31, 7, 2038), 3.59421438364369), (Date(31, 7, 2039), 3.5787000000081948), (Date(31, 7, 2040), 3.5626192748395624), (Date(31, 7, 2041), 3.545765016376823), (Date(31, 7, 2042), 3.527943521613608), (Date(31, 7, 2043), 3.508977137925462), (Date(31, 7, 2044), 3.48870000000685), (Date(31, 7, 2045), 3.467083068721011), (Date(31, 7, 2046), 3.4445738220594935), (Date(31, 7, 2047), 3.4216470902302065), (Date(31, 7, 2048), 3.3986861494999188), (Date(31, 7, 2049), 3.376000000005752), (Date(31, 7, 2050), 3.3538412080641233), (Date(31, 7, 2051), 3.3324275806807746), (Date(31, 7, 2052), 3.311938788306623), (Date(31, 7, 2053), 3.2925208131865835), (Date(31, 7, 2054), 3.274293040759302), (Date(31, 7, 2055), 3.2573541974782794), (Date(31, 7, 2056), 3.241787355503245), (Date(31, 7, 2057), 3.227664186159851), (Date(31, 7, 2058), 3.2150486140060774), (Date(31, 7, 2059), 3.204000000004159), (Date(31, 7, 2060), 3.1945334946674064), (Date(31, 7, 2061), 3.1865047145143377), (Date(31, 7, 2062), 3.179753073456304), (Date(31, 7, 2063), 3.1741427790361154), (Date(31, 7, 2064), 3.1695593261025223), (Date(31, 7, 2065), 3.1659065919088736), (Date(31, 7, 2066), 3.163104428386987), (Date(31, 7, 2067), 3.1610866681252903), (Date(31, 7, 2068), 3.1597994770515836), (Date(31, 7, 2069), 3.159200000003204), (Date(31, 7, 2070), 3.159242349440139), (Date(31, 7, 2071), 3.1598400898057433), (Date(31, 7, 2072), 3.16090721831932), (Date(31, 7, 2073), 3.162369676612098), (Date(31, 7, 2074), 3.1641636543027207)] zcDates = [] zcRates = [] for i in range(0, len(zciisData)): zcDates.append(zciisData[i][0]) zcRates.append(zciisData[i][1] / 100.0) inflationZeroCurve = DiscountCurveZeros(settlement_date, zcDates, zcRates, FrequencyTypes.ANNUAL, DayCountTypes.ACT_ACT_ISDA) # print(inflationZeroCurve) ########################################################################### bond = FinInflationBond(issue_date, maturity_date, coupon, freq_type, accrual_type, face, baseCPIValue) testCases.header("FIELD", "VALUE") clean_price = 104.03502 yld = bond.current_yield(clean_price) testCases.print("Current Yield = ", yld) return ########################################################################### # Inherited functions that just calculate real yield without CPI adjustments ########################################################################### ytm = bond.yield_to_maturity(settlement_date, clean_price, YTMCalcType.UK_DMO) testCases.print("UK DMO REAL Yield To Maturity = ", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, YTMCalcType.US_STREET) testCases.print("US STREET REAL Yield To Maturity = ", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, YTMCalcType.US_TREASURY) testCases.print("US TREASURY REAL Yield To Maturity = ", ytm) full_price = bond.full_price_from_ytm(settlement_date, ytm) testCases.print("Full Price from REAL YTM = ", full_price) clean_price = bond.clean_price_from_ytm(settlement_date, ytm) testCases.print("Clean Price from Real YTM = ", clean_price) accddays = bond._accrued_days testCases.print("Accrued Days = ", accddays) accrued_interest = bond._accrued_interest testCases.print("REAL Accrued Interest = ", accrued_interest) ########################################################################### # Inflation functions that calculate nominal yield with CPI adjustment ########################################################################### ########################################################################### clean_price = bond.clean_price_from_ytm(settlement_date, ytm) testCases.print("Clean Price from Real YTM = ", clean_price) inflationAccd = bond.calc_inflation_accrued_interest( settlement_date, refCPIValue) testCases.print("Inflation Accrued = ", inflationAccd) lastCpnCPIValue = 244.61839 clean_price = bond.flat_price_from_yield_to_maturity( settlement_date, ytm, lastCpnCPIValue, YTMCalcType.US_TREASURY) testCases.print("Flat Price from Real YTM = ", clean_price) principal = bond.inflation_principal(settlement_date, ytm, refCPIValue, YTMCalcType.US_TREASURY) testCases.print("Inflation Principal = ", principal) ########################################################################### 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_bloombergPricingExample(): """ This is an example of a replication of a BBG example from https://github.com/vilen22/curve-building/blob/master/Bloomberg%20Curve%20Building%20Replication.xlsx """ valuation_date = Date(6, 6, 2018) # We do the O/N rate which settles on trade date spot_days = 0 settlement_date = valuation_date.add_weekdays(spot_days) depoDCCType = DayCountTypes.ACT_360 depos = [] deposit_rate = 0.0231381 maturity_date = settlement_date.add_months(3) depo = IborDeposit(settlement_date, maturity_date, deposit_rate, depoDCCType) depos.append(depo) futs = [] fut = IborFuture(valuation_date, 1); futs.append(fut) fut = IborFuture(valuation_date, 2); futs.append(fut) fut = IborFuture(valuation_date, 3); futs.append(fut) fut = IborFuture(valuation_date, 4); futs.append(fut) fut = IborFuture(valuation_date, 5); futs.append(fut) fut = IborFuture(valuation_date, 6); futs.append(fut) fras = [None]*6 fras[0] = futs[0].to_fra(97.6675, -0.00005) fras[1] = futs[1].to_fra(97.5200, -0.00060) fras[2] = futs[2].to_fra(97.3550, -0.00146) fras[3] = futs[3].to_fra(97.2450, -0.00263) fras[4] = futs[4].to_fra(97.1450, -0.00411) fras[5] = futs[5].to_fra(97.0750, -0.00589) accrual = DayCountTypes.THIRTY_E_360 freq = FrequencyTypes.SEMI_ANNUAL spot_days = 2 settlement_date = valuation_date.add_weekdays(spot_days) notional = ONE_MILLION fixed_leg_type = SwapTypes.PAY interp_type = InterpTypes.FLAT_FWD_RATES swaps = [] swap = IborSwapOLD(settlement_date, "2Y", fixed_leg_type, (2.77417+2.77844)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "3Y", fixed_leg_type, (2.86098+2.86582)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "4Y", fixed_leg_type, (2.90240+2.90620)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "5Y", fixed_leg_type, (2.92944+2.92906)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "6Y", fixed_leg_type, (2.94001+2.94499)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "7Y", fixed_leg_type, (2.95352+2.95998)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "8Y", fixed_leg_type, (2.96830+2.97400)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "9Y", fixed_leg_type, (2.98403+2.98817)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "10Y", fixed_leg_type, (2.99716+3.00394)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "11Y", fixed_leg_type, (3.01344+3.01596)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "12Y", fixed_leg_type, (3.02276+3.02684)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "15Y", fixed_leg_type, (3.04092+3.04508)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "20Y", fixed_leg_type, (3.04417+3.05183)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "25Y", fixed_leg_type, (3.03219+3.03621)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "30Y", fixed_leg_type, (3.01030+3.01370)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "40Y", fixed_leg_type, (2.96946+2.97354)/200, freq, accrual); swaps.append(swap) swap = IborSwapOLD(settlement_date, "50Y", fixed_leg_type, (2.91552+2.93748)/200, freq, accrual); swaps.append(swap) libor_curve = FinIborSingleCurveOLD(valuation_date, depos, fras, swaps, interp_type, True) principal = 0.0 testCases.banner("======================================================") testCases.banner("SINGLE CURVE VALUATION") testCases.header("LABEL", "VALUE") testCases.print("VALUE:", swaps[0].value(valuation_date, libor_curve, libor_curve, None)) testCases.print("FIXED:", swaps[0].fixed_leg_value(valuation_date, libor_curve)) testCases.print("FLOAT:", swaps[0].float_leg_value(valuation_date, libor_curve, libor_curve, None)) testCases.banner("======================================================") testCases.banner("SINGLE CURVE VALUATION TO SWAP SETTLEMENT DATE") testCases.header("LABEL", "VALUE") testCases.print("VALUE:", swaps[0].value(settlement_date, libor_curve, libor_curve, None)) testCases.print("FIXED:", swaps[0].fixed_leg_value(settlement_date, libor_curve)) testCases.print("FLOAT:", swaps[0].float_leg_value(settlement_date, libor_curve, libor_curve, None)) testCases.banner("======================================================") # swaps[0].print_fixed_leg_pv() # swaps[0].print_float_leg_pv() oisCurve = buildOIS(valuation_date) # print(oisCurve) liborDualCurve = FinIborDualCurveOLD(valuation_date, oisCurve, depos, fras, swaps, InterpTypes.FLAT_FWD_RATES, True) # print(liborDualCurve) # The valuation of 53714.55 is very close to the spreadsheet value 53713.96 testCases.header("VALUATION TO TODAY DATE"," PV") testCases.print("VALUE:", swaps[0].value(valuation_date, oisCurve, liborDualCurve, None)) testCases.print("FIXED:", swaps[0].fixed_leg_value(valuation_date, oisCurve)) testCases.print("FLOAT:", swaps[0].float_leg_value(valuation_date, oisCurve, libor_curve, None)) testCases.header("VALUATION TO SWAP SETTLEMENT DATE"," PV") testCases.print("VALUE:", swaps[0].value(settlement_date, oisCurve, liborDualCurve, None)) testCases.print("FIXED:", swaps[0].fixed_leg_value(settlement_date, oisCurve)) testCases.print("FLOAT:", swaps[0].float_leg_value(settlement_date, oisCurve, liborDualCurve, None, )) # swaps[0].print_fixed_leg_pv() # swaps[0].print_float_leg_pv() PLOT = False if PLOT is True: years = np.linspace(0, 5, 21) dates = settlement_date.add_years(years) singleCurveFwds = libor_curve.fwd(dates) plt.plot(years, singleCurveFwds, label="Single Libor Curve") oisCurveFwds = oisCurve.fwd(dates) plt.plot(years, oisCurveFwds, label="OIS Curve") index_curveFwds = liborDualCurve.fwd(dates) plt.plot(years, index_curveFwds, label="Libor Index Curve") plt.legend()
def test_FinEquityVanillaOptionFactored(): valuation_date = Date(1, 1, 2015) expiry_date = Date(1, 7, 2015) stock_price = 100 volatility = 0.30 interestRate = 0.05 dividendYield = 0.01 model = FinModelBlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interestRate) num_pathsList = [10000, 20000, 40000, 80000, 160000, 320000] testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") for num_paths in num_pathsList: callOption = FinEquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valuation_date, stock_price, discount_curve, dividendYield, model) start = time.time() valueMC = callOption.valueMC(valuation_date, stock_price, discount_curve, dividendYield, model, num_paths) end = time.time() duration = end - start testCases.print(num_paths, value, valueMC, duration) ############################################################################### stock_prices = range(80, 120, 10) num_paths = 100000 testCases.header("NUMPATHS", "CALL_VALUE_BS", "CALL_VALUE_MC", "CALL_VALUE_MC_SOBOL", "TIME") useSobol = True for stock_price in stock_prices: callOption = FinEquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valuation_date, stock_price, discount_curve, dividendYield, model) start = time.time() useSobol = False valueMC1 = callOption.valueMC(valuation_date, stock_price, discount_curve, dividendYield, model, num_paths, useSobol) useSobol = True valueMC2 = callOption.valueMC(valuation_date, stock_price, discount_curve, dividendYield, model, num_paths, useSobol) end = time.time() duration = end - start testCases.print(num_paths, value, valueMC1, valueMC2, duration) ############################################################################### stock_prices = range(80, 120, 10) num_paths = 100000 testCases.header("NUMPATHS", "PUT_VALUE_BS", "PUT_VALUE_MC", "PUT_VALUE_MC_SOBOL", "TIME") for stock_price in stock_prices: putOption = FinEquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valuation_date, stock_price, discount_curve, dividendYield, model) start = time.time() useSobol = False valueMC1 = putOption.valueMC(valuation_date, stock_price, discount_curve, dividendYield, model, num_paths, useSobol) useSobol = True valueMC2 = putOption.valueMC(valuation_date, stock_price, discount_curve, dividendYield, model, num_paths, useSobol) end = time.time() duration = end - start testCases.print(num_paths, value, valueMC1, valueMC2, duration) ############################################################################### stock_prices = range(80, 120, 10) testCases.header("STOCK PRICE", "CALL_VALUE_BS", "CALL_DELTA_BS", "CALL_VEGA_BS", "CALL_THETA_BS", "CALL_RHO_BS") for stock_price in stock_prices: callOption = FinEquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valuation_date, stock_price, discount_curve, dividendYield, model) delta = callOption.delta(valuation_date, stock_price, discount_curve, dividendYield, model) vega = callOption.vega(valuation_date, stock_price, discount_curve, dividendYield, model) theta = callOption.theta(valuation_date, stock_price, discount_curve, dividendYield, model) rho = callOption.rho(valuation_date, stock_price, discount_curve, dividendYield, model) testCases.print(stock_price, value, delta, vega, theta, rho) ########################################################################### testCases.header("STOCK PRICE", "PUT_VALUE_BS", "PUT_DELTA_BS", "PUT_VEGA_BS", "PUT_THETA_BS", "PUT_RHO_BS") for stock_price in stock_prices: putOption = FinEquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valuation_date, stock_price, discount_curve, dividendYield, model) delta = putOption.delta(valuation_date, stock_price, discount_curve, dividendYield, model) vega = putOption.vega(valuation_date, stock_price, discount_curve, dividendYield, model) theta = putOption.theta(valuation_date, stock_price, discount_curve, dividendYield, model) rho = putOption.rho(valuation_date, stock_price, discount_curve, dividendYield, model) testCases.print(stock_price, value, delta, vega, theta, rho) ############################################################################### testCases.header("STOCK PRICE", "VALUE_BS", "VOL_IN", "IMPLD_VOL") stock_prices = range(60, 150, 10) for stock_price in stock_prices: callOption = FinEquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valuation_date, stock_price, discount_curve, dividendYield, model) impliedVol = callOption.impliedVolatility(valuation_date, stock_price, discount_curve, dividendYield, value) testCases.print(stock_price, value, volatility, impliedVol)
############################################################################### # Copyright (C) 2018, 2019, 2020 Dominic O'Kane ############################################################################### from financepy.utils.global_types import OptionTypes from financepy.products.equity.equity_digital_option import EquityDigitalOption, FinDigitalOptionTypes from financepy.models.black_scholes import BlackScholes from financepy.market.curves.discount_curve_flat import DiscountCurveFlat from financepy.utils.date import Date import sys sys.path.append("./..") 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) num_paths = 40000 def test_value():
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 testImpliedVolatility_NEW(): valuation_date = Date(1, 1, 2015) stock_price = 100.0 interestRate = 0.05 dividendYield = 0.03 discount_curve = DiscountCurveFlat(valuation_date, interestRate) dividendCurve = DiscountCurveFlat(valuation_date, dividendYield) strikes = np.linspace(50, 150, 11) timesToExpiry = [0.003, 0.01, 0.1, 0.5, 1.0, 2.0, 5.0] sigmas = np.arange(1, 100, 5) / 100.0 optionTypes = [FinOptionTypes.EUROPEAN_CALL, FinOptionTypes.EUROPEAN_PUT] testCases.header("OPT_TYPE", "TEXP", "STOCK_PRICE", "STRIKE", "INTRINSIC", "VALUE", "INPUT_VOL", "IMPLIED_VOL") tol = 1e-5 numTests = 0 numFails = 0 for vol in sigmas: model = FinModelBlackScholes(vol) for timeToExpiry in timesToExpiry: expiry_date = valuation_date.addYears(timeToExpiry) for strike in strikes: for optionType in optionTypes: option = FinEquityVanillaOption(expiry_date, strike, optionType) value = option.value(valuation_date, stock_price, discount_curve, dividendCurve, model) intrinsic = option.intrinsic(valuation_date, stock_price, discount_curve, dividendCurve) # I remove the cases where the time value is zero # This is arbitrary but 1e-10 seems good enough to me impliedVol = -999 if value - intrinsic > 1e-10: impliedVol = option.impliedVolatility( valuation_date, stock_price, discount_curve, dividendCurve, value) numTests += 1 errVol = np.abs(impliedVol - vol) if errVol > tol: testCases.print(optionType, timeToExpiry, stock_price, strike, intrinsic, value, vol, impliedVol) # These fails include ones due to the zero time value numFails += 1 testCases.print(optionType, timeToExpiry, stock_price, strike, stock_price, value, vol, impliedVol) assert numFails == 694, "Num Fails has changed."
def test_full_priceCDSIndexOption(): tradeDate = Date(1, 8, 2007) step_in_date = tradeDate.addDays(1) valuation_date = step_in_date libor_curve = buildIborCurve(tradeDate) maturity3Y = tradeDate.nextCDSDate(36) maturity5Y = tradeDate.nextCDSDate(60) maturity7Y = tradeDate.nextCDSDate(84) maturity10Y = tradeDate.nextCDSDate(120) path = os.path.join(os.path.dirname(__file__), './/data//CDX_NA_IG_S7_SPREADS.csv') f = open(path, 'r') data = f.readlines() f.close() issuer_curves = [] for row in data[1:]: splitRow = row.split(",") creditName = splitRow[0] spd3Y = float(splitRow[1]) / 10000.0 spd5Y = float(splitRow[2]) / 10000.0 spd7Y = float(splitRow[3]) / 10000.0 spd10Y = float(splitRow[4]) / 10000.0 recovery_rate = float(splitRow[5]) cds3Y = FinCDS(step_in_date, maturity3Y, spd3Y) cds5Y = FinCDS(step_in_date, maturity5Y, spd5Y) cds7Y = FinCDS(step_in_date, maturity7Y, spd7Y) cds10Y = FinCDS(step_in_date, maturity10Y, spd10Y) cds_contracts = [cds3Y, cds5Y, cds7Y, cds10Y] issuer_curve = FinCDSCurve(valuation_date, cds_contracts, libor_curve, recovery_rate) issuer_curves.append(issuer_curve) ########################################################################## ########################################################################## 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) ] indexRecovery = 0.40 testCases.banner( "======================= CDS INDEX OPTION ==========================") index_coupon = 0.004 volatility = 0.50 expiry_date = Date(1, 2, 2008) maturity_date = Date(20, 12, 2011) notional = 10000.0 tolerance = 1e-6 testCases.header("TIME", "STRIKE", "INDEX", "PAY", "RECEIVER", "G(K)", "X", "EXPH", "ABPAY", "ABREC") for index in np.linspace(20, 60, 10): ####################################################################### cds_contracts = [] for dt in indexMaturityDates: cds = FinCDS(valuation_date, dt, index / 10000.0) cds_contracts.append(cds) index_curve = FinCDSCurve(valuation_date, cds_contracts, libor_curve, indexRecovery) if 1 == 1: indexSpreads = [index / 10000.0] * 4 indexPortfolio = FinCDSIndexPortfolio() adjustedIssuerCurves = indexPortfolio.hazardRateAdjustIntrinsic( valuation_date, issuer_curves, indexSpreads, indexUpfronts, indexMaturityDates, indexRecovery, tolerance) else: indexSpread = index / 10000.0 issuer_curve = buildFlatIssuerCurve(tradeDate, libor_curve, indexSpread, indexRecovery) adjustedIssuerCurves = [] for iCredit in range(0, 125): adjustedIssuerCurves.append(issuer_curve) ####################################################################### for strike in np.linspace(20, 60, 20): start = time.time() option = FinCDSIndexOption(expiry_date, maturity_date, index_coupon, strike / 10000.0, notional) v_pay_1, v_rec_1, strikeValue, mu, expH = option.valueAnderson( valuation_date, adjustedIssuerCurves, indexRecovery, volatility) end = time.time() elapsed = end - start end = time.time() v_pay_2, v_rec_2 = option.valueAdjustedBlack( valuation_date, index_curve, indexRecovery, libor_curve, volatility) elapsed = end - start testCases.print(elapsed, strike, index, v_pay_1, v_rec_1, strikeValue, mu, expH, v_pay_2, v_rec_2)
def test_BDTExampleThree(): # Valuation of a swaption as in Leif Andersen's paper - see Table 1 on # SSRN-id155208.pdf settlement_date = Date(1, 1, 2020) times = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]) dates = settlement_date.add_years(times) rate = 0.06 dfs = 1.0 / (1.0 + rate / 2.0)**(2.0 * times) curve = DiscountCurve(settlement_date, dates, dfs) coupon = 0.06 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA strike_price = 100.0 face = 100.0 # Andersen paper num_time_steps = 200 exercise_type = FinExerciseTypes.EUROPEAN years_to_maturity = 4.0 expiryYears = 2.0 maturity_date = settlement_date.add_years(years_to_maturity) issue_date = Date(maturity_date._d, maturity_date._m, 2000) sigma = 0.2012 expiry_date = settlement_date.add_years(expiryYears) tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency for flow_date in bond._coupon_dates: if flow_date > expiry_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) price = bond.clean_price_from_discount_curve(settlement_date, curve) model = BDTTree(sigma, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bermudan_swaption(texp, tmat, strike_price, face, coupon_times, coupon_flows, exercise_type) assert round(price, 5) == 100.01832 assert round(v['pay'] * 100, 2) == 0.00 assert round(v['rec'] * 100, 2) == 8883.21 exercise_type = FinExerciseTypes.BERMUDAN years_to_maturity = 10.0 expiryYears = 5.0 maturity_date = settlement_date.add_years(years_to_maturity) issue_date = Date(maturity_date._d, maturity_date._m, 2000) sigma = 0.1522 expiry_date = settlement_date.add_years(expiryYears) tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency for flow_date in bond._coupon_dates: if flow_date > expiry_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) price = bond.clean_price_from_discount_curve(settlement_date, curve) model = BDTTree(sigma, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bermudan_swaption(texp, tmat, strike_price, face, coupon_times, coupon_flows, exercise_type) assert round(price, 5) == 100.08625 assert round(v['pay'] * 100, 2) == 263.28 assert round(v['rec'] * 100, 2) == 7437.00
def test_BDTExampleTwo(): # Valuation of a European option on a coupon bearing bond # This follows example in Fig 28.11 of John Hull's book (6th Edition) # but does not have the exact same dt so there are some differences settlement_date = Date(1, 12, 2019) issue_date = Date(1, 12, 2015) expiry_date = settlement_date.add_tenor("18m") maturity_date = settlement_date.add_tenor("10Y") coupon = 0.05 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) coupon_times = [] coupon_flows = [] cpn = bond._coupon / bond._frequency num_flows = len(bond._coupon_dates) for i in range(1, num_flows): pcd = bond._coupon_dates[i - 1] ncd = bond._coupon_dates[i] if pcd < settlement_date and ncd > settlement_date: flow_time = (pcd - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) for flow_date in bond._coupon_dates: if flow_date > settlement_date: flow_time = (flow_date - settlement_date) / gDaysInYear coupon_times.append(flow_time) coupon_flows.append(cpn) coupon_times = np.array(coupon_times) coupon_flows = np.array(coupon_flows) strike_price = 105.0 face = 100.0 tmat = (maturity_date - settlement_date) / gDaysInYear texp = (expiry_date - settlement_date) / gDaysInYear times = np.linspace(0, tmat, 11) dates = settlement_date.add_years(times) dfs = np.exp(-0.05 * times) curve = DiscountCurve(settlement_date, dates, dfs) price = bond.clean_price_from_discount_curve(settlement_date, curve) assert round(price, 4) == 99.5420 sigma = 0.20 # Test convergence num_time_steps = 5 exercise_type = FinExerciseTypes.AMERICAN model = BDTTree(sigma, num_time_steps) model.build_tree(tmat, times, dfs) v = model.bond_option(texp, strike_price, face, coupon_times, coupon_flows, exercise_type) assert round(v['call'], 4) == 0.5043 assert round(v['put'], 4) == 8.2242
def test_IborCapFloorQLExample(): valuation_date = Date(14, 6, 2016) dates = [ Date(14, 6, 2016), Date(14, 9, 2016), Date(14, 12, 2016), Date(14, 6, 2017), Date(14, 6, 2019), Date(14, 6, 2021), Date(15, 6, 2026), Date(16, 6, 2031), Date(16, 6, 2036), Date(14, 6, 2046) ] rates = [ 0.000000, 0.006616, 0.007049, 0.007795, 0.009599, 0.011203, 0.015068, 0.017583, 0.018998, 0.020080 ] freq_type = FrequencyTypes.ANNUAL day_count_type = DayCountTypes.ACT_ACT_ISDA discount_curve = DiscountCurveZeros(valuation_date, dates, rates, freq_type, day_count_type, InterpTypes.LINEAR_ZERO_RATES) start_date = Date(14, 6, 2016) end_date = Date(14, 6, 2026) calendar_type = CalendarTypes.UNITED_STATES bus_day_adjust_type = BusDayAdjustTypes.MODIFIED_FOLLOWING freq_type = FrequencyTypes.QUARTERLY date_gen_rule_type = DateGenRuleTypes.FORWARD lastFixing = 0.0065560 notional = 1000000 day_count_type = DayCountTypes.ACT_360 option_type = FinCapFloorTypes.CAP strike_rate = 0.02 cap = IborCapFloor(start_date, end_date, option_type, strike_rate, lastFixing, freq_type, day_count_type, notional, calendar_type, bus_day_adjust_type, date_gen_rule_type) blackVol = 0.547295 model = Black(blackVol) start = time.time() numRepeats = 10 for i in range(0, numRepeats): v = cap.value(valuation_date, discount_curve, model) end = time.time() period = end - start
def test_addDays(): assert Date(1, 1, 2018).addDays(-1).addDays(1) == Date(1, 1, 2018)
def test_IborCapFloor(): todayDate = Date(20, 6, 2019) valuation_date = todayDate start_date = todayDate.add_weekdays(2) maturity_date = start_date.add_tenor("1Y") libor_curve = test_ibor_depositsAndSwaps(todayDate) # The capfloor has begun # lastFixing = 0.028 ########################################################################## # COMPARISON OF MODELS ########################################################################## strikes = np.linspace(0.02, 0.08, 5) testCases.header("LABEL", "STRIKE", "BLK", "BLK_SHFTD", "SABR", "SABR_SHFTD", "HW", "BACH") model1 = Black(0.20) model2 = BlackShifted(0.25, 0.0) model3 = SABR(0.013, 0.5, 0.5, 0.5) model4 = SABRShifted(0.013, 0.5, 0.5, 0.5, -0.008) model5 = HWTree(0.30, 0.01) model6 = Bachelier(0.01) for k in strikes: capFloorType = FinCapFloorTypes.CAP capfloor = IborCapFloor(start_date, maturity_date, capFloorType, k) cvalue1 = capfloor.value(valuation_date, libor_curve, model1) cvalue2 = capfloor.value(valuation_date, libor_curve, model2) cvalue3 = capfloor.value(valuation_date, libor_curve, model3) cvalue4 = capfloor.value(valuation_date, libor_curve, model4) cvalue5 = capfloor.value(valuation_date, libor_curve, model5) cvalue6 = capfloor.value(valuation_date, libor_curve, model6) testCases.print("CAP", k, cvalue1, cvalue2, cvalue3, cvalue4, cvalue5, cvalue6) testCases.header("LABEL", "STRIKE", "BLK", "BLK_SHFTD", "SABR", "SABR_SHFTD", "HW", "BACH") for k in strikes: capFloorType = FinCapFloorTypes.FLOOR capfloor = IborCapFloor(start_date, maturity_date, capFloorType, k) fvalue1 = capfloor.value(valuation_date, libor_curve, model1) fvalue2 = capfloor.value(valuation_date, libor_curve, model2) fvalue3 = capfloor.value(valuation_date, libor_curve, model3) fvalue4 = capfloor.value(valuation_date, libor_curve, model4) fvalue5 = capfloor.value(valuation_date, libor_curve, model5) fvalue6 = capfloor.value(valuation_date, libor_curve, model6) testCases.print("FLR", k, fvalue1, fvalue2, fvalue3, fvalue4, fvalue5, fvalue6) ############################################################################### # PUT CALL CHECK ############################################################################### testCases.header("LABEL", "STRIKE", "BLK", "BLK_SHFTD", "SABR", "SABR SHFTD", "HW", "BACH") for k in strikes: capFloorType = FinCapFloorTypes.CAP capfloor = IborCapFloor(start_date, maturity_date, capFloorType, k) cvalue1 = capfloor.value(valuation_date, libor_curve, model1) cvalue2 = capfloor.value(valuation_date, libor_curve, model2) cvalue3 = capfloor.value(valuation_date, libor_curve, model3) cvalue4 = capfloor.value(valuation_date, libor_curve, model4) cvalue5 = capfloor.value(valuation_date, libor_curve, model5) cvalue6 = capfloor.value(valuation_date, libor_curve, model6) capFloorType = FinCapFloorTypes.FLOOR capfloor = IborCapFloor(start_date, maturity_date, capFloorType, k) fvalue1 = capfloor.value(valuation_date, libor_curve, model1) fvalue2 = capfloor.value(valuation_date, libor_curve, model2) fvalue3 = capfloor.value(valuation_date, libor_curve, model3) fvalue4 = capfloor.value(valuation_date, libor_curve, model4) fvalue5 = capfloor.value(valuation_date, libor_curve, model5) fvalue6 = capfloor.value(valuation_date, libor_curve, model6) pcvalue1 = cvalue1 - fvalue1 pcvalue2 = cvalue2 - fvalue2 pcvalue3 = cvalue3 - fvalue3 pcvalue4 = cvalue4 - fvalue4 pcvalue5 = cvalue5 - fvalue5 pcvalue6 = cvalue6 - fvalue6 testCases.print("PUT_CALL", k, pcvalue1, pcvalue2, pcvalue3, pcvalue4, pcvalue5, pcvalue6)
def test_DateEOM(): dt = Date(29, 2, 2000) assert dt.isEOM() == True dt = Date(28, 2, 2001) assert dt.isEOM() == True dt = Date(29, 2, 2004) assert dt.isEOM() == True dt = Date(28, 2, 2005) assert dt.isEOM() == True dt = Date(31, 3, 2003) assert dt.isEOM() == True dt = Date(30, 4, 2004) assert dt.isEOM() == True dt = Date(31, 5, 2004) assert dt.isEOM() == True dt = Date(31, 12, 2010) assert dt.isEOM() == True dt = Date(2, 2, 2000) assert dt.EOM().isEOM() == True dt = Date(24, 2, 2001) assert dt.EOM().isEOM() == True dt = Date(22, 2, 2004) assert dt.EOM().isEOM() == True dt = Date(1, 2, 2005) assert dt.EOM().isEOM() == True dt = Date(1, 3, 2003) assert dt.EOM().isEOM() == True dt = Date(3, 4, 2004) assert dt.EOM().isEOM() == True dt = Date(5, 5, 2004) assert dt.EOM().isEOM() == True dt = Date(7, 12, 2010) assert dt.EOM().isEOM() == True
def test_FinInflationBondBBG(): ########################################################################## # https://data.bloomberglp.com/bat/sites/3/2017/07/SF-2017_Paul-Fjeldsted.pdf # Look for CPI Bond example ########################################################################## testCases.banner("BLOOMBERG US TIPS EXAMPLE") settlement_date = Date(21, 7, 2017) issue_date = Date(15, 7, 2010) maturity_date = Date(15, 7, 2020) coupon = 0.0125 freq_type = FrequencyTypes.SEMI_ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA face = 100.0 baseCPIValue = 218.08532 bond = FinInflationBond(issue_date, maturity_date, coupon, freq_type, accrual_type, face, baseCPIValue) testCases.header("FIELD", "VALUE") clean_price = 104.03502 yld = bond.current_yield(clean_price) testCases.print("Current Yield = ", yld) ########################################################################### # Inherited functions that just calculate real yield without CPI adjustments ########################################################################### ytm = bond.yield_to_maturity(settlement_date, clean_price, YTMCalcType.UK_DMO) testCases.print("UK DMO REAL Yield To Maturity = ", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, YTMCalcType.US_STREET) testCases.print("US STREET REAL Yield To Maturity = ", ytm) ytm = bond.yield_to_maturity(settlement_date, clean_price, YTMCalcType.US_TREASURY) testCases.print("US TREASURY REAL Yield To Maturity = ", ytm) full_price = bond.full_price_from_ytm(settlement_date, ytm) testCases.print("Full Price from REAL YTM = ", full_price) clean_price = bond.clean_price_from_ytm(settlement_date, ytm) testCases.print("Clean Price from Real YTM = ", clean_price) accddays = bond._accrued_days testCases.print("Accrued Days = ", accddays) accrued_interest = bond._accrued_interest testCases.print("REAL Accrued Interest = ", accrued_interest) ########################################################################### # Inflation functions that calculate nominal yield with CPI adjustment ########################################################################### refCPIValue = 244.65884 ########################################################################### clean_price = bond.clean_price_from_ytm(settlement_date, ytm) testCases.print("Clean Price from Real YTM = ", clean_price) inflationAccd = bond.calc_inflation_accrued_interest( settlement_date, refCPIValue) testCases.print("Inflation Accrued = ", inflationAccd) lastCpnCPIValue = 244.61839 clean_price = bond.flat_price_from_yield_to_maturity( settlement_date, ytm, lastCpnCPIValue, YTMCalcType.US_TREASURY) testCases.print("Flat Price from Real YTM = ", clean_price) principal = bond.inflation_principal(settlement_date, ytm, refCPIValue, YTMCalcType.US_TREASURY) testCases.print("Inflation Principal = ", principal) ########################################################################### 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_from_string(): assert Date.fromString("1-1-2018", "%d-%m-%Y") == Date(1, 1, 2018)
def test_swapValuationExample(): # Example from # https://blog.deriscope.com/index.php/en/excel-interest-rate-swap-price-dual-bootstrapping-curve vBloomberg = 388147 valuation_date = Date(30, 11, 2018) start_date = Date(27, 12, 2017) maturity_date = Date(27, 12, 2067) notional = 10 * ONE_MILLION fixed_leg_type = SwapTypes.RECEIVE fixedRate = 0.0150 fixedDCCType = DayCountTypes.THIRTY_360_BOND fixedFreqType = FrequencyTypes.ANNUAL float_spread = 0.0 floatDCCType = DayCountTypes.ACT_360 floatFreqType = FrequencyTypes.SEMI_ANNUAL offMarketSwap = IborSwapOLD(start_date, maturity_date, fixed_leg_type, fixedRate, fixedFreqType, fixedDCCType, notional, float_spread, floatFreqType, floatDCCType) interp_type = InterpTypes.LINEAR_ZERO_RATES depoDCCType = DayCountTypes.ACT_360 depos = [] ########################################################################### # MARKET ########################################################################### spot_days = 0 settlement_date = valuation_date.add_weekdays(spot_days) depo = IborDeposit(settlement_date, "6M", -0.2510 / 100.0, depoDCCType); depos.append(depo) fras = [] fraDCCType = DayCountTypes.ACT_360 fra = IborFRA(settlement_date.add_tenor("1M"), "6M", -0.2450 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("2M"), "6M", -0.2435 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("3M"), "6M", -0.2400 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("4M"), "6M", -0.2360 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("5M"), "6M", -0.2285 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("6M"), "6M", -0.2230 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("7M"), "6M", -0.2110 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("8M"), "6M", -0.1990 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("9M"), "6M", -0.1850 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("10M"), "6M", -0.1680 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("11M"), "6M", -0.1510 / 100.0, fraDCCType); fras.append(fra) fra = IborFRA(settlement_date.add_tenor("12M"), "6M", -0.1360 / 100.0, fraDCCType); fras.append(fra) swaps = [] fixed_leg_type = SwapTypes.PAY fixedDCCType = DayCountTypes.THIRTY_360_BOND fixedFreqType = FrequencyTypes.ANNUAL swap = IborSwapOLD(settlement_date, "2Y", fixed_leg_type, -0.1525/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "3Y", fixed_leg_type, -0.0185/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "4Y", fixed_leg_type, 0.1315/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "5Y", fixed_leg_type, 0.2745/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "6Y", fixed_leg_type, 0.4135/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "7Y", fixed_leg_type, 0.5439/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "8Y", fixed_leg_type, 0.6652/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "9Y", fixed_leg_type, 0.7784/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "10Y", fixed_leg_type, 0.8799/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "11Y", fixed_leg_type, 0.9715/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "12Y", fixed_leg_type, 1.0517/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "15Y", fixed_leg_type, 1.2369/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "20Y", fixed_leg_type, 1.3965/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "25Y", fixed_leg_type, 1.4472/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "30Y", fixed_leg_type, 1.4585/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "35Y", fixed_leg_type, 1.4595/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "40Y", fixed_leg_type, 1.4535/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "45Y", fixed_leg_type, 1.4410/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = IborSwapOLD(settlement_date, "50Y", fixed_leg_type, 1.4335/100.0, fixedFreqType, fixedDCCType); swaps.append(swap) iborDepos = depos.copy() iborFras = fras.copy() ibor_swaps = swaps.copy() iborCurve = FinIborSingleCurve(valuation_date, iborDepos, iborFras, ibor_swaps, interp_type) v1 = offMarketSwap.value(valuation_date, iborCurve, iborCurve, -0.268/100.0) testCases.banner("DERISCOPE EXAMPLE REPLICATION") testCases.header("LABEL", "VALUE") testCases.print("BBG VALUE", vBloomberg) testCases.print("FP ONE CURVE VALUE", v1) ############################################################################### depoDCCType = DayCountTypes.ACT_360 depos = [] spot_days = 0 settlement_date = valuation_date.add_weekdays(spot_days) depo = IborDeposit(settlement_date, "1D", -0.3490 / 100.0, depoDCCType); depos.append(depo) fras = [] swaps = [] fixed_leg_type = SwapTypes.PAY fixedDCCType = DayCountTypes.ACT_365F fixedFreqType = FrequencyTypes.ANNUAL # Standard OIS with standard annual terms swap = OIS(settlement_date, "2W", fixed_leg_type, -0.3600 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "1M", fixed_leg_type, -0.3560 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "2M", fixed_leg_type, -0.3570 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "3M", fixed_leg_type, -0.3580 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "4M", fixed_leg_type, -0.3575 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "5M", fixed_leg_type, -0.3578 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "6M", fixed_leg_type, -0.3580 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "7M", fixed_leg_type, -0.3600 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "8M", fixed_leg_type, -0.3575 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "9M", fixed_leg_type, -0.3569 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "10M", fixed_leg_type, -0.3553 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "11M", fixed_leg_type, -0.3534 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "12M", fixed_leg_type, -0.3496 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "18M", fixed_leg_type, -0.3173 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "2Y", fixed_leg_type, -0.2671 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "30M", fixed_leg_type, -0.2070 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "3Y", fixed_leg_type, -0.1410 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "4Y", fixed_leg_type, -0.0060 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "5Y", fixed_leg_type, 0.1285 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "6Y", fixed_leg_type, 0.2590 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "7Y", fixed_leg_type, 0.3830 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "8Y", fixed_leg_type, 0.5020 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "9Y", fixed_leg_type, 0.6140 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "10Y", fixed_leg_type, 0.7160 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "11Y", fixed_leg_type, 0.8070 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "12Y", fixed_leg_type, 0.8890 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "15Y", fixed_leg_type, 1.0790 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "20Y", fixed_leg_type, 1.2460 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "25Y", fixed_leg_type, 1.3055 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "30Y", fixed_leg_type, 1.3270 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "35Y", fixed_leg_type, 1.3315 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "40Y", fixed_leg_type, 1.3300 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) swap = OIS(settlement_date, "50Y", fixed_leg_type, 1.3270 / 100.0, fixedFreqType, fixedDCCType); swaps.append(swap) oisDepos = depos.copy() oisFras = fras.copy() oisSwaps = swaps.copy() # oisCurveFF = FinOISCurve(valuation_date, oisDepos, oisFras, oisSwaps, interp_type) iborDualCurve = FinIborDualCurve(valuation_date, oisCurveFF, iborDepos, iborFras, ibor_swaps, interp_type)
def test_weekday(): assert Date(3, 3, 2021)._weekday == Date.WED
def test_BondEmbeddedOptionMATLAB(): # https://fr.mathworks.com/help/fininst/optembndbyhw.html # I FIND THAT THE PRICE CONVERGES TO 102.88 WHICH IS CLOSE TO 102.9127 # FOUND BY MATLAB ALTHOUGH THEY DO NOT EXAMINE THE ASYMPTOTIC PRICE # WHICH MIGHT BE A BETTER MATCH settlement_date = Date(1, 1, 2007) valuation_date = settlement_date ########################################################################### dcType = DayCountTypes.THIRTY_E_360 fixedFreq = FrequencyTypes.ANNUAL fixed_legType = FinSwapTypes.PAY swap1 = FinIborSwap(settlement_date, "1Y", fixed_legType, 0.0350, fixedFreq, dcType) swap2 = FinIborSwap(settlement_date, "2Y", fixed_legType, 0.0400, fixedFreq, dcType) swap3 = FinIborSwap(settlement_date, "3Y", fixed_legType, 0.0450, fixedFreq, dcType) swaps = [swap1, swap2, swap3] discount_curve = IborSingleCurve(valuation_date, [], [], swaps) ########################################################################### issue_date = Date(1, 1, 2004) maturity_date = Date(1, 1, 2010) coupon = 0.0525 freq_type = FrequencyTypes.ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) call_dates = [] call_prices = [] put_dates = [] put_prices = [] putDate = Date(1, 1, 2008) for _ in range(0, 24): put_dates.append(putDate) put_prices.append(100) putDate = putDate.addMonths(1) testCases.header("BOND PRICE", "PRICE") v = bond.clean_price_from_discount_curve(settlement_date, discount_curve) testCases.print("Bond Pure Price:", v) sigma = 0.01 # basis point volatility a = 0.1 puttableBond = BondEmbeddedOption(issue_date, maturity_date, coupon, freq_type, accrual_type, call_dates, call_prices, put_dates, put_prices) testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure") timeSteps = range(50, 1000, 10) values = [] for numTimeSteps in timeSteps: model = FinModelRatesHW(sigma, a, numTimeSteps) start = time.time() v = puttableBond.value(settlement_date, discount_curve, model) end = time.time() period = end - start testCases.print(period, numTimeSteps, v['bondwithoption'], v['bondpure']) values.append(v['bondwithoption']) if plotGraphs: plt.figure() plt.plot(timeSteps, values)
def test_excel_representation(): assert Date(5, 1, 1900)._excelDate == 5 assert Date(1, 3, 2020)._excelDate == 43891
def test_CDSIndexPortfolio(): tradeDate = Date(1, 8, 2007) step_in_date = tradeDate.addDays(1) valuation_date = step_in_date libor_curve = buildIborCurve(tradeDate) maturity3Y = tradeDate.nextCDSDate(36) maturity5Y = tradeDate.nextCDSDate(60) maturity7Y = tradeDate.nextCDSDate(84) maturity10Y = tradeDate.nextCDSDate(120) path = os.path.join(os.path.dirname(__file__), './/data//CDX_NA_IG_S7_SPREADS.csv') f = open(path, 'r') data = f.readlines() f.close() 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 = FinCDS(step_in_date, maturity3Y, spd3Y) cds5Y = FinCDS(step_in_date, maturity5Y, spd5Y) cds7Y = FinCDS(step_in_date, maturity7Y, spd7Y) cds10Y = FinCDS(step_in_date, maturity10Y, spd10Y) cds_contracts = [cds3Y, cds5Y, cds7Y, cds10Y] issuer_curve = FinCDSCurve(valuation_date, cds_contracts, libor_curve, recovery_rate) issuer_curves.append(issuer_curve) ########################################################################## # Now determine the average spread of the index ########################################################################## cdsIndex = FinCDSIndexPortfolio() averageSpd3Y = cdsIndex.averageSpread(valuation_date, step_in_date, maturity3Y, issuer_curves) * 10000.0 averageSpd5Y = cdsIndex.averageSpread(valuation_date, step_in_date, maturity5Y, issuer_curves) * 10000.0 averageSpd7Y = cdsIndex.averageSpread(valuation_date, step_in_date, maturity7Y, issuer_curves) * 10000.0 averageSpd10Y = cdsIndex.averageSpread( 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 = FinCDSIndexPortfolio() intrinsicSpd3Y = cdsIndex.intrinsicSpread( valuation_date, step_in_date, maturity3Y, issuer_curves) * 10000.0 intrinsicSpd5Y = cdsIndex.intrinsicSpread( valuation_date, step_in_date, maturity5Y, issuer_curves) * 10000.0 intrinsicSpd7Y = cdsIndex.intrinsicSpread( valuation_date, step_in_date, maturity7Y, issuer_curves) * 10000.0 intrinsicSpd10Y = cdsIndex.intrinsicSpread( 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)
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_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 = FinOptionTypes.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 = FinOptionTypes.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 = FinOptionTypes.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 = FinOptionTypes.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_IborCapFloorVolCurve(): """ Aim here is to price cap and caplets using cap and caplet vols and to demonstrate they are the same - NOT SURE THAT HULLS BOOKS FORMULA WORKS FOR OPTIONS. """ todayDate = Date(20, 6, 2019) valuation_date = todayDate maturity_date = valuation_date.add_tenor("3Y") day_count_type = DayCountTypes.THIRTY_E_360 frequency = FrequencyTypes.ANNUAL k = 0.04 capFloorType = FinCapFloorTypes.CAP capFloor = IborCapFloor(valuation_date, maturity_date, capFloorType, k, None, frequency, day_count_type) capVolDates = Schedule(valuation_date, valuation_date.add_tenor("10Y"), frequency)._generate() flat_rate = 0.04 libor_curve = DiscountCurveFlat(valuation_date, flat_rate, frequency, day_count_type) flat = False if flat is True: capVolatilities = [20.0] * 11 capVolatilities[0] = 0.0 else: capVolatilities = [ 0.00, 15.50, 18.25, 17.91, 17.74, 17.27, 16.79, 16.30, 16.01, 15.76, 15.54 ] capVolatilities = np.array(capVolatilities) / 100.0 capVolatilities[0] = 0.0 volCurve = IborCapVolCurve(valuation_date, capVolDates, capVolatilities, day_count_type) # print(volCurve._capletGammas) # Value cap using a single flat cap volatility tcap = (maturity_date - valuation_date) / gDaysInYear vol = volCurve.cap_vol(maturity_date) model = Black(vol) valueCap = capFloor.value(valuation_date, libor_curve, model) # print("CAP T", tcap, "VOL:", vol, "VALUE OF CAP:", valueCap) # Value cap by breaking it down into caplets using caplet vols vCaplets = 0.0 capletStartDate = capFloor._capFloorLetDates[1] testCases.header("START", "END", "VOL", "VALUE") for capletEndDate in capFloor._capFloorLetDates[2:]: vol = volCurve.caplet_vol(capletEndDate) modelCaplet = Black(vol) vCaplet = capFloor.value_caplet_floor_let(valuation_date, capletStartDate, capletEndDate, libor_curve, modelCaplet) vCaplets += vCaplet testCases.print("%12s" % capletStartDate, "%s" % capletEndDate, "%9.5f" % (vol * 100.0), "%9.5f" % vCaplet) capletStartDate = capletEndDate testCases.header("LABEL", "VALUE") testCases.print("CAPLETS->CAP: ", vCaplets)
def 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_BondOptionEuropeanConvergence(): # CONVERGENCE TESTS # COMPARE AMERICAN TREE VERSUS JAMSHIDIAN IN EUROPEAN LIMIT TO CHECK THAT # TREE HAS BEEN CORRECTLY CONSTRUCTED. FIND VERY GOOD AGREEMENT. # Build discount curve settlement_date = Date(1, 12, 2019) discount_curve = DiscountCurveFlat(settlement_date, 0.05, FrequencyTypes.CONTINUOUS) # Bond details issue_date = Date(1, 12, 2015) maturity_date = Date(1, 12, 2020) coupon = 0.05 freq_type = FrequencyTypes.ANNUAL accrual_type = DayCountTypes.ACT_ACT_ICMA bond = Bond(issue_date, maturity_date, coupon, freq_type, accrual_type) # Option Details - put expiry in the middle of a coupon period expiry_date = Date(1, 3, 2020) strike_price = 100.0 face = 100.0 timeSteps = range(100, 400, 100) strike_price = 100.0 testCases.header("TIME", "N", "PUT_JAM", "PUT_TREE", "CALL_JAM", "CALL_TREE") for num_time_steps in timeSteps: sigma = 0.05 a = 0.1 start = time.time() option_type = FinOptionTypes.EUROPEAN_PUT bond_option1 = BondOption(bond, expiry_date, strike_price, face, option_type) model1 = HWTree(sigma, a, num_time_steps) v1put = bond_option1.value(settlement_date, discount_curve, model1) bond_option2 = BondOption(bond, expiry_date, strike_price, face, option_type) model2 = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_ONLY) v2put = bond_option2.value(settlement_date, discount_curve, model2) option_type = FinOptionTypes.EUROPEAN_CALL bond_option1 = BondOption(bond, expiry_date, strike_price, face, option_type) model1 = HWTree(sigma, a, num_time_steps) v1call = bond_option1.value(settlement_date, discount_curve, model1) bond_option2 = BondOption(bond, expiry_date, strike_price, face, option_type) model2 = HWTree(sigma, a, num_time_steps, FinHWEuropeanCalcType.EXPIRY_TREE) v2call = bond_option2.value(settlement_date, discount_curve, model2) end = time.time() period = end - start testCases.print(period, num_time_steps, v1put, v2put, v1call, v2call)