def test_swap_QL(self): """ Test that a swap with fixed coupon = fair rate has an NPV=0 Create from QL objects """ nominal = 100.0 fixedConvention = Unadjusted floatingConvention = ModifiedFollowing fixedFrequency = Annual floatingFrequency = Semiannual fixedDayCount = Thirty360() floatDayCount = Thirty360() calendar = TARGET() settlement_days = 2 eval_date = Date(2, January, 2014) settings = Settings() settings.evaluation_date = eval_date settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) termStructure = YieldTermStructure(relinkable=True) termStructure.link_to( FlatForward(settlement_date, 0.05, Actual365Fixed())) index = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360(), termStructure) length = 5 fixedRate = .05 floatingSpread = 0.0 maturity = calendar.advance(settlement_date, length, Years, convention=floatingConvention) fixedSchedule = Schedule(settlement_date, maturity, Period(fixedFrequency), calendar, fixedConvention, fixedConvention, Forward, False) floatSchedule = Schedule(settlement_date, maturity, Period(floatingFrequency), calendar, floatingConvention, floatingConvention, Forward, False) engine = DiscountingSwapEngine(termStructure, False, settlement_date, settlement_date) for swap_type in [Payer, Receiver]: swap = VanillaSwap(swap_type, nominal, fixedSchedule, fixedRate, fixedDayCount, floatSchedule, index, floatingSpread, floatDayCount, fixedConvention) swap.set_pricing_engine(engine) fixed_leg = swap.fixed_leg floating_leg = swap.floating_leg f = swap.fair_rate print('fair rate: %f' % f) p = swap.net_present_value print('NPV: %f' % p) swap = VanillaSwap(swap_type, nominal, fixedSchedule, f, fixedDayCount, floatSchedule, index, floatingSpread, floatDayCount, fixedConvention) swap.set_pricing_engine(engine) p = swap.net_present_value print('NPV: %f' % p) self.assertAlmostEqual(p, 0)
def get_term_structure(df_libor, dtObs): settings = Settings() # Market information calendar = TARGET() # must be a business day eval_date = calendar.adjust(dateToDate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date); depositData =[[1, Months, 'Libor1M'], [3, Months, 'Libor3M'], [6, Months, 'Libor6M']] swapData = [[ 1, Years, 'Swap1Y'], [ 2, Years, 'Swap2Y'], [ 3, Years, 'Swap3Y'], [ 4, Years, 'Swap4Y'], [ 5, Years, 'Swap5Y'], [ 7, Years, 'Swap7Y'], [ 10, Years,'Swap10Y'], [ 30, Years,'Swap30Y']] rate_helpers = [] end_of_month = True for m, period, label in depositData: tenor = Period(m, Months) rate = df_libor.get_value(dtObs, label) helper = DepositRateHelper(float(rate/100), tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) endOfMonth = True liborIndex = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, ModifiedFollowing, endOfMonth, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, label in swapData: rate = df_libor.get_value(dtObs, label) helper = SwapRateHelper(SimpleQuote(rate/100), Period(m, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = term_structure_factory('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) return ts
def test_deposit_swap(self): settings = Settings() # Market information calendar = TARGET() todays_date = Date(1, Mar, 2012) # must be a business day eval_date = calendar.adjust(todays_date) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) depositData = [[1, Months, 4.581], [2, Months, 4.573], [3, Months, 4.557], [6, Months, 4.496], [9, Months, 4.490]] swapData = [[1, Years, 4.54], [5, Years, 4.99], [10, Years, 5.47], [20, Years, 5.89], [30, Years, 5.96]] rate_helpers = [] end_of_month = True for m, period, rate in depositData: tenor = Period(m, Months) helper = DepositRateHelper(SimpleQuote(rate / 100), tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) liborIndex = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, rate in swapData: helper = SwapRateHelper.from_tenor(SimpleQuote(rate / 100), Period(m, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) self.assertEqual(settlement_date, ts.reference_date) # this is not a real test ... self.assertAlmostEqual( 0.9103, ts.discount(calendar.advance(todays_date, 2, Years)), 3) self.assertAlmostEqual( 0.7836, ts.discount(calendar.advance(todays_date, 5, Years)), 3) self.assertAlmostEqual( 0.5827, ts.discount(calendar.advance(todays_date, 10, Years)), 3) self.assertAlmostEqual( 0.4223, ts.discount(calendar.advance(todays_date, 15, Years)), 3)
def test_zero_curve_on_swap_index(self): todays_date = today() calendar = UnitedStates() # INPUT dayCounter = Actual360() # INPUT currency = USDCurrency() # INPUT Settings.instance().evaluation_date = todays_date settlement_days = 2 settlement_date = calendar.advance(todays_date, period=Period( settlement_days, Days)) liborRates = [ SimpleQuote(0.002763), SimpleQuote(0.004082), SimpleQuote(0.005601), SimpleQuote(0.006390), SimpleQuote(0.007125), SimpleQuote(0.007928), SimpleQuote(0.009446), SimpleQuote(0.01110) ] liborRatesTenor = [ Period(tenor, Months) for tenor in [1, 2, 3, 4, 5, 6, 9, 12] ] Libor_dayCounter = Actual360() swapRates = [ SimpleQuote(0.005681), SimpleQuote(0.006970), SimpleQuote(0.009310), SimpleQuote(0.012010), SimpleQuote(0.014628), SimpleQuote(0.016881), SimpleQuote(0.018745), SimpleQuote(0.020260), SimpleQuote(0.021545) ] swapRatesTenor = [Period(i, Years) for i in range(2, 11)] # description of the fixed leg of the swap Swap_fixedLegTenor = Period(12, Months) # INPUT Swap_fixedLegConvention = ModifiedFollowing # INPUT Swap_fixedLegDayCounter = Actual360() # INPUT # description of the float leg of the swap Swap_iborIndex = Libor("USDLibor", Period(3, Months), settlement_days, USDCurrency(), UnitedStates(), Actual360()) SwapFamilyName = currency.name + "swapIndex" instruments = [] # ++++++++++++++++++++ Creation of the vector of RateHelper (need for the Yield Curve construction) # ++++++++++++++++++++ Libor LiborFamilyName = currency.name + "Libor" instruments = [] for rate, tenor in zip(liborRates, liborRatesTenor): # Index description ___ creation of a Libor index liborIndex = Libor(LiborFamilyName, tenor, settlement_days, currency, calendar, Libor_dayCounter) # Initialize rate helper # the DepositRateHelper link the recording rate with the Libor # index instruments.append(DepositRateHelper(rate, index=liborIndex)) for tenor, rate in zip(swapRatesTenor, swapRates): # swap description ___ creation of a swap index. The floating leg is described in the index 'Swap_iborIndex' swapIndex = SwapIndex(SwapFamilyName, tenor, settlement_days, currency, calendar, Swap_fixedLegTenor, Swap_fixedLegConvention, Swap_fixedLegDayCounter, Swap_iborIndex) # Initialize rate helper __ the SwapRateHelper links the swap index width his rate instruments.append(SwapRateHelper.from_index(rate, swapIndex)) # ++++++++++++++++++ Now the creation of the yield curve tolerance = 1.0e-15 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.ZeroYield, Interpolator.Linear, settlement_date, instruments, dayCounter, tolerance) self.assertEqual(settlement_date, ts.reference_date)
def get_term_structure(df_libor, dtObs): settings = Settings() # Market information calendar = TARGET() # must be a business day eval_date = calendar.adjust(Date.from_datetime(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) depositData = [[1, Months, 'Libor1M'], [3, Months, 'Libor3M'], [6, Months, 'Libor6M']] swapData = [[1, Years, 'Swap1Y'], [2, Years, 'Swap2Y'], [3, Years, 'Swap3Y'], [4, Years, 'Swap4Y'], [5, Years, 'Swap5Y'], [7, Years, 'Swap7Y'], [10, Years, 'Swap10Y'], [30, Years, 'Swap30Y']] rate_helpers = [] end_of_month = True for m, period, label in depositData: tenor = Period(m, Months) rate = df_libor.get_value(dtObs, label) helper = DepositRateHelper(SimpleQuote(rate / 100.0), tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) liborIndex = Libor('USD Libor', Period(3, Months), settlement_days, USDCurrency(), calendar, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, label in swapData: rate = df_libor.get_value(dtObs, label) helper = SwapRateHelper.from_tenor(SimpleQuote(rate / 100.0), Period(m, Years), calendar, Semiannual, ModifiedFollowing, Thirty360(), liborIndex, spread, fwdStart) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) ts.extrapolation = True return ts
def test_display(self): settings = Settings() # Date setup calendar = TARGET() # Settlement date settlement_date = calendar.adjust(Date(28, January, 2011)) # Evaluation date fixing_days = 1 settlement_days = 1 todays_date = calendar.advance( settlement_date, -fixing_days, Days ) settings.evaluation_date = todays_date # Bound attributes face_amount = 100.0 redemption = 100.0 issue_date = Date(27, January, 2011) maturity_date = Date(31, August, 2020) coupon_rate = 0.03625 bond_yield = 0.034921 flat_discounting_term_structure = YieldTermStructure() flat_term_structure = FlatForward( reference_date = settlement_date, forward = bond_yield, daycounter = Actual365Fixed(), #actual_actual.ActualActual(actual_actual.Bond), compounding = Compounded, frequency = Semiannual) # have a look at the FixedRateBondHelper to simplify this # construction flat_discounting_term_structure.link_to(flat_term_structure) #Rate fixed_bond_schedule = Schedule.from_rule( issue_date, maturity_date, Period(Semiannual), UnitedStates(market=GovernmentBond), Unadjusted, Unadjusted, Backward, False); bond = FixedRateBond( settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(Bond), Unadjusted, redemption, issue_date ) d=bf.startDate(bond) zspd=bf.zSpread(bond, 100.0, flat_term_structure, Actual365Fixed(), Compounded, Semiannual, settlement_date, 1e-6, 100, 0.5) #Also need a test case for a PiecewiseTermStructure... depositData = [[ 1, Months, 4.581 ], [ 2, Months, 4.573 ], [ 3, Months, 4.557 ], [ 6, Months, 4.496 ], [ 9, Months, 4.490 ]] swapData = [[ 1, Years, 4.54 ], [ 5, Years, 4.99 ], [ 10, Years, 5.47 ], [ 20, Years, 5.89 ], [ 30, Years, 5.96 ]] rate_helpers = [] end_of_month = True for m, period, rate in depositData: tenor = Period(m, Months) helper = DepositRateHelper(SimpleQuote(rate/100), tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) liborIndex = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360(), YieldTermStructure(relinkable=False)) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, rate in swapData: helper = SwapRateHelper.from_tenor( SimpleQuote(rate/100), Period(m, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart ) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve[BootstrapTrait.Discount, LogLinear].from_reference_date( settlement_date, rate_helpers, ts_day_counter, accuracy=tolerance) pyc_zspd=bf.zSpread(bond, 102.0, ts, ActualActual(ISDA), Compounded, Semiannual, Date(1, April, 2015), 1e-6, 100, 0.5) pyc_zspd_disco=bf.zSpread(bond, 95.0, ts, ActualActual(ISDA), Compounded, Semiannual, settlement_date, 1e-6, 100, 0.5) yld = bf.bond_yield(bond, 102.0, ActualActual(ISDA), Compounded, Semiannual, settlement_date, 1e-6, 100, 0.5) dur = bf.duration(bond, yld, ActualActual(ISDA), Compounded, Semiannual, bf.Modified, settlement_date) yld_disco = bf.bond_yield(bond, 95.0, ActualActual(ISDA), Compounded, Semiannual, settlement_date, 1e-6, 100, 0.5) dur_disco = bf.duration(bond, yld_disco, ActualActual(ISDA), Compounded, Semiannual, bf.Modified, settlement_date) self.assertEqual(round(zspd, 6), 0.001281) self.assertEqual(round(pyc_zspd, 4), -0.0264) self.assertEqual(round(pyc_zspd_disco, 4), -0.0114) self.assertEqual(round(yld, 4), 0.0338) self.assertEqual(round(yld_disco, 4), 0.0426) self.assertEqual(round(dur, 4), 8.0655) self.assertEqual(round(dur_disco, 4), 7.9702)
def test_coupon_pricing(self): tol = 1e-6 cms10y = EuriborSwapIsdaFixA(Period(10, Years), self.yts) cms2y = EuriborSwapIsdaFixA(Period(2, Years), self.yts) cms10y2y = SwapSpreadIndex("cms10y2y", cms10y, cms2y) value_date = cms10y2y.value_date(self.ref_date) pay_date = value_date + Period(1, Years) cpn1a = CmsCoupon(pay_date, 10000., value_date, pay_date, cms10y.fixing_days, cms10y, 1., 0., Date(), Date(), Actual360(), False) cpn1b = CmsCoupon(pay_date, 10000., value_date, pay_date, cms2y.fixing_days, cms2y, 1., 0., Date(), Date(), Actual360(), False) cpn1 = CmsSpreadCoupon(pay_date, 10000., value_date, pay_date, cms10y2y.fixing_days, cms10y2y, 1., 0., Date(), Date(), Actual360(), False) cpn1a.set_pricer(self.cms_pricer_ln) cpn1b.set_pricer(self.cms_pricer_ln) cpn1.set_pricer(self.cms_spread_pricer_ln) self.assertEqual(cpn1.rate , cpn1a.rate - cpn1b.rate) cms10y.add_fixing(self.ref_date, 0.05) self.assertEqual(cpn1.rate , cpn1a.rate - cpn1b.rate) cms2y.add_fixing(self.ref_date, 0.03) self.assertEqual(cpn1.rate , cpn1a.rate - cpn1b.rate) cpn2a = CmsCoupon(Date(23, 2, 2029), 10000., Date(23, 2, 2028), Date(23, 2, 2029), 2, cms10y, 1., 0., Date(), Date(), Actual360(), False) cpn2b = CmsCoupon(Date(23, 2, 2029), 10000., Date(23, 2, 2028), Date(23, 2, 2029), 2, cms2y, 1., 0., Date(), Date(), Actual360(), False) plain_cpn = CappedFlooredCmsSpreadCoupon( Date(23, 2, 2029), 10000., Date(23, 2, 2028), Date(23, 2, 2029), 2, cms10y2y, 1., 0., day_counter=Actual360()) capped_cpn = CappedFlooredCmsSpreadCoupon( Date(23, 2, 2029), 10000., Date(23, 2, 2028), Date(23, 2, 2029), 2, cms10y2y, 1., 0., 0.03, day_counter=Actual360()) floored_cpn = CappedFlooredCmsSpreadCoupon( Date(23, 2, 2029), 10000., Date(23, 2, 2028), Date(23, 2, 2029), 2, cms10y2y, 1., 0., QL_NULL_REAL, 0.01, day_counter=Actual360()) collared_cpn = CappedFlooredCmsSpreadCoupon( Date(23, 2, 2029), 10000., Date(23, 2, 2028), Date(23, 2, 2029), 2, cms10y2y, 1., 0., 0.03, 0.01, day_counter=Actual360()) cpn2a.set_pricer(self.cms_pricer_ln) cpn2b.set_pricer(self.cms_pricer_ln) plain_cpn.set_pricer(self.cms_spread_pricer_ln) capped_cpn.set_pricer(self.cms_spread_pricer_ln) floored_cpn.set_pricer(self.cms_spread_pricer_ln) collared_cpn.set_pricer(self.cms_spread_pricer_ln) r = self.mc_reference_value(cpn2a, cpn2b, self.swLn, self.correlation.value) self.assertAlmostEqual(r.mean(), plain_cpn.rate) self.assertAlmostEqual(np.clip(r, None, 0.03).mean(), capped_cpn.rate, 5) self.assertAlmostEqual(np.clip(r, 0.01, None).mean(), floored_cpn.rate, 5) self.assertAlmostEqual(np.clip(r, 0.01, 0.03).mean(), collared_cpn.rate, 5) cpn2a.set_pricer(self.cms_pricer_sln) cpn2b.set_pricer(self.cms_pricer_sln) plain_cpn.set_pricer(self.cms_spread_pricer_sln) capped_cpn.set_pricer(self.cms_spread_pricer_sln) floored_cpn.set_pricer(self.cms_spread_pricer_sln) collared_cpn.set_pricer(self.cms_spread_pricer_sln) r = self.mc_reference_value(cpn2a, cpn2b, self.swSLn, self.correlation.value) self.assertAlmostEqual(r.mean(), plain_cpn.rate) self.assertAlmostEqual(np.clip(r, None, 0.03).mean(), capped_cpn.rate, 5) self.assertAlmostEqual(np.clip(r, 0.01, None).mean(), floored_cpn.rate, 5) self.assertAlmostEqual(np.clip(r, 0.01, 0.03).mean(), collared_cpn.rate, 5) cpn2a.set_pricer(self.cms_pricer_n) cpn2b.set_pricer(self.cms_pricer_n) plain_cpn.set_pricer(self.cms_spread_pricer_n) capped_cpn.set_pricer(self.cms_spread_pricer_n) floored_cpn.set_pricer(self.cms_spread_pricer_n) collared_cpn.set_pricer(self.cms_spread_pricer_n) r = self.mc_reference_value(cpn2a, cpn2b, self.swN, self.correlation.value) self.assertAlmostEqual(r.mean(), plain_cpn.rate) self.assertAlmostEqual(np.clip(r, None, 0.03).mean(), capped_cpn.rate, 5) self.assertAlmostEqual(np.clip(r, 0.01, None).mean(), floored_cpn.rate, 5) self.assertAlmostEqual(np.clip(r, 0.01, 0.03).mean(), collared_cpn.rate, 5)
from quantlib.quotes import SimpleQuote from quantlib.termstructures.yields.api import FlatForward from quantlib.time.api import Actual360, Date, NullCalendar, TARGET logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) calendar = TARGET() date_today = Date(6,9,2011) date_payment = Date(6,12,2000) settlement_days = 2 quote = SimpleQuote(value=0.03) term_structure = FlatForward( settlement_days = settlement_days, quote = quote, calendar = NullCalendar(), daycounter = Actual360() ) try: df_1 = term_structure.discount(date_payment) print('rate: %f df_1: %f' % (quote.value, df_1)) except RuntimeError as exc: logger.error('Evaluation date and discount date issue.') logger.exception(exc)
def dividendOption(): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++ General Parameter for all the computation +++++++++++++++++++++++ # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # declaration of the today's date (date where the records are done) todaysDate = Date(24 , Jan ,2012) # INPUT Settings.instance().evaluation_date = todaysDate #!\ IMPORTANT COMMAND REQUIRED FOR ALL VALUATIONS calendar = UnitedStates() # INPUT settlement_days = 2 # INPUT # Calcul of the settlement date : need to add a period of 2 days to the todays date settlementDate = calendar.advance( todaysDate, period=Period(settlement_days, Days) ) dayCounter = Actual360() # INPUT currency = USDCurrency() # INPUT print("Date of the evaluation: ", todaysDate) print("Calendar used: ", calendar.name) print("Number of settlement Days: ", settlement_days) print("Date of settlement: ", settlementDate) print("Convention of day counter: ", dayCounter.name) print("Currency of the actual context:\t\t", currency.name) # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++ Description of the underlying +++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ underlying_name = "IBM" underlying_price = 191.75 # INPUT underlying_vol = 0.2094 # INPUT print("**********************************") print("Name of the underlying: ", underlying_name) print("Price of the underlying at t0: ", underlying_price) print("Volatility of the underlying: ", underlying_vol) # For a great managing of price and vol objects --> Handle underlying_priceH = SimpleQuote(underlying_price) # We suppose the vol constant : his term structure is flat --> BlackConstantVol object flatVolTS = BlackConstantVol(settlementDate, calendar, underlying_vol, dayCounter) # ++++++++++++++++++++ Description of Yield Term Structure # Libor data record print("**********************************") print("Description of the Libor used for the Yield Curve construction") Libor_dayCounter = Actual360(); liborRates = [] liborRatesTenor = [] # INPUT : all the following data are input : the rate and the corresponding tenor # You could make the choice of more or less data # --> However you have tho choice the instruments with different maturities liborRates = [ 0.002763, 0.004082, 0.005601, 0.006390, 0.007125, 0.007928, 0.009446, 0.01110] liborRatesTenor = [Period(tenor, Months) for tenor in [1,2,3,4,5,6,9,12]] for tenor, rate in zip(liborRatesTenor, liborRates): print(tenor, "\t\t\t", rate) # Swap data record # description of the fixed leg of the swap Swap_fixedLegTenor = Period(12, Months) # INPUT Swap_fixedLegConvention = ModifiedFollowing # INPUT Swap_fixedLegDayCounter = Actual360() # INPUT # description of the float leg of the swap Swap_iborIndex = Libor( "USDLibor", Period(3,Months), settlement_days, USDCurrency(), UnitedStates(), Actual360() ) print("Description of the Swap used for the Yield Curve construction") print("Tenor of the fixed leg: ", Swap_fixedLegTenor) print("Index of the floated leg: ", Swap_iborIndex.name) print("Maturity Rate ") swapRates = [] swapRatesTenor = [] # INPUT : all the following data are input : the rate and the corresponding tenor # You could make the choice of more or less data # --> However you have tho choice the instruments with different maturities swapRates = [0.005681, 0.006970, 0.009310, 0.012010, 0.014628, 0.016881, 0.018745, 0.020260, 0.021545] swapRatesTenor = [Period(i, Years) for i in range(2, 11)] for tenor, rate in zip(swapRatesTenor, swapRates): print(tenor, "\t\t\t", rate) # ++++++++++++++++++++ Creation of the vector of RateHelper (need for the Yield Curve construction) # ++++++++++++++++++++ Libor LiborFamilyName = currency.name + "Libor" instruments = [] for rate, tenor in zip(liborRates, liborRatesTenor): # Index description ___ creation of a Libor index liborIndex = Libor(LiborFamilyName, tenor, settlement_days, currency, calendar, Libor_dayCounter) # Initialize rate helper ___ the DepositRateHelper link the recording rate with the Libor index instruments.append(DepositRateHelper(rate, index=liborIndex)) # +++++++++++++++++++++ Swap SwapFamilyName = currency.name + "swapIndex"; for tenor, rate in zip(swapRatesTenor, swapRates): # swap description ___ creation of a swap index. The floating leg is described in the index 'Swap_iborIndex' swapIndex = SwapIndex (SwapFamilyName, tenor, settlement_days, currency, calendar, Swap_fixedLegTenor, Swap_fixedLegConvention, Swap_fixedLegDayCounter, Swap_iborIndex) # Initialize rate helper __ the SwapRateHelper links the swap index width his rate instruments.append(SwapRateHelper.from_index(rate,swapIndex)) # ++++++++++++++++++ Now the creation of the yield curve riskFreeTS = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.ZeroYield, Interpolator.Linear, settlementDate, instruments, dayCounter) # ++++++++++++++++++ build of the underlying process : with a Black-Scholes model print('Creating process') bsProcess = BlackScholesProcess(underlying_priceH, riskFreeTS, flatVolTS) # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++ Description of the option +++++++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Option_name = "IBM Option" maturity = Date(26, Jan,2013) strike = 190 option_type = 'call' # Here, as an implementation exemple, we make the test with borth american and european exercise europeanExercise = EuropeanExercise(maturity) # The emericanExercise need also the settlement date, as his right to exerce the buy or call start at the settlement date! #americanExercise = AmericanExercise(settlementDate, maturity) americanExercise = AmericanExercise(maturity, settlementDate) print("**********************************") print("Description of the option: ", Option_name) print("Date of maturity: ", maturity) print("Type of the option: ", option_type) print("Strike of the option: ", strike) # ++++++++++++++++++ Description of the discrete dividends # INPUT You have to determine the frequece and rates of the discrete dividend. Here is a sollution, but she's not the only one. # Last know dividend: dividend = 0.75 #//0.75 next_dividend_date = Date(10,Feb,2012) # HERE we have make the assumption that the dividend will grow with the quarterly croissance: dividendCroissance = 1.03 dividendfrequence = Period(3, Months) dividendDates = [] dividends = [] d = next_dividend_date while d <= maturity: dividendDates.append(d) dividends.append(dividend) d = d + dividendfrequence dividend *= dividendCroissance print("Discrete dividends ") print("Dates Dividends ") for date, div in zip(dividendDates, dividends): print(date, " ", div) # ++++++++++++++++++ Description of the final payoff payoff = PlainVanillaPayoff(option_type, strike) # ++++++++++++++++++ The OPTIONS : (American and European) with their dividends description: dividendEuropeanOption = DividendVanillaOption( payoff, europeanExercise, dividendDates, dividends ) dividendAmericanOption = DividendVanillaOption( payoff, americanExercise, dividendDates, dividends ) # just too test europeanOption = VanillaOption(payoff, europeanExercise) americanOption = VanillaOption(payoff, americanExercise) # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++ Description of the pricing +++++++++++++++++++++++++++++++++++++ # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # For the european options we have a closed analytic formula: The Black Scholes: dividendEuropeanEngine = AnalyticDividendEuropeanEngine(bsProcess) # For the american option we have make the choice of the finite difference model with the CrankNicolson scheme # this model need to precise the time and space step # More they are greater, more the calul will be precise. americanGirdPoints = 600 americanTimeSteps = 600 dividendAmericanEngine = FDDividendAmericanEngine('CrankNicolson', bsProcess,americanTimeSteps, americanGirdPoints) # just to test europeanEngine = AnalyticEuropeanEngine(bsProcess) americanEngine = FDAmericanEngine('CrankNicolson', bsProcess,americanTimeSteps, americanGirdPoints) # ++++++++++++++++++++ Valorisation ++++++++++++++++++++++++++++++++++++++++ # Link the pricing Engine to the option dividendEuropeanOption.set_pricing_engine(dividendEuropeanEngine) dividendAmericanOption.set_pricing_engine(dividendAmericanEngine) # just to test europeanOption.set_pricing_engine(europeanEngine) americanOption.set_pricing_engine(americanEngine) # Now we make all the needing calcul # ... and final results print("NPV of the European Option with discrete dividends=0: {:.4f}".format(dividendEuropeanOption.npv)) print("NPV of the European Option without dividend: {:.4f}".format(europeanOption.npv)) print("NPV of the American Option with discrete dividends=0: {:.4f}".format(dividendAmericanOption.npv)) print("NPV of the American Option without dividend: {:.4f}".format(americanOption.npv)) # just a single test print("ZeroRate with a maturity at ", maturity, ": ", \ riskFreeTS.zero_rate(maturity, dayCounter, Simple))
(10,Years): 0.05165, (15,Years): 0.055175 } # convert them to Quote objects #for n,unit in deposits.keys(): # deposits[(n,unit)] = SimpleQuote(deposits[(n,unit)]) for n,m in FRAs.keys(): FRAs[(n,m)] = SimpleQuote(FRAs[(n,m)]) for d in futures.keys(): futures[d] = SimpleQuote(futures[d]) #for n,unit in swaps.keys(): # swaps[(n,unit)] = SimpleQuote(swaps[(n,unit)]) # build rate helpers dayCounter = Actual360() settlementDays = 2 depositHelpers = [ DepositRateHelper(deposits[(n,unit)], Period(n,unit), settlementDays, calendar, ModifiedFollowing, False, dayCounter) for n, unit in [(1,Weeks),(1,Months),(3,Months), (6,Months),(9,Months),(1,Years)] ] dayCounter = Actual360() settlementDays = 2 fraHelpers = [ FraRateHelper(FRAs[(n,m)], n, m, settlementDays, calendar, ModifiedFollowing, False, dayCounter) for n, m in FRAs.keys() ]
def test_zero_curve(self): try: settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) print('dt Obs: %s\ndt Eval: %s\ndt Settle: %s' % (dtObs, eval_date, settlement_date)) depositData = [[1, Months, 'Libor1M', 5.32], [3, Months, 'Libor3M', 5.35], [6, Months, 'Libor6M', 5.35]] swapData = [[1, Years, 'Swap1Y', 5.31], [2, Years, 'Swap2Y', 5.06], [3, Years, 'Swap3Y', 5.00], [4, Years, 'Swap4Y', 5.01], [5, Years, 'Swap5Y', 5.04], [7, Years, 'Swap7Y', 5.12], [10, Years, 'Swap10Y', 5.22], [30, Years, 'Swap30Y', 5.44]] rate_helpers = [] end_of_month = True for m, period, label, rate in depositData: tenor = Period(m, Months) helper = DepositRateHelper(SimpleQuote(rate / 100.0), tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) liborIndex = Libor('USD Libor', Period(3, Months), settlement_days, USDCurrency(), calendar, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, label, rate in swapData: helper = SwapRateHelper.from_tenor(SimpleQuote(rate / 100.0), Period(m, Years), calendar, Semiannual, ModifiedFollowing, Thirty360(), liborIndex, spread, fwdStart) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception... dtMax = ts.max_date print('max date: %s' % dtMax) except RuntimeError as e: print('Exception (expected):\n%s' % e) self.assertTrue(True) except Exception: self.assertFalse()
class CreditDefaultSwapTest(unittest.TestCase): calendar = TARGET() today_date = today() Settings().evaluation_date = today_date hazard_rate = SimpleQuote(0.01234) probability_curve = FlatHazardRate(0, calendar, hazard_rate, Actual360()) discount_curve = FlatForward(today_date, 0.06, Actual360()) issue_date = today_date #calendar.advance(today_date, -1, Years) maturity = calendar.advance(issue_date, 10, Years) convention = Following schedule = Schedule(issue_date, maturity, Period("3M"), calendar, convention, convention, TwentiethIMM) recovery_rate = 0.4 engine = MidPointCdsEngine(probability_curve, recovery_rate, discount_curve, True) def test_fair_spread(self): fixed_rate = 0.001 day_count = Actual360() notional = 10000 cds = CreditDefaultSwap(SELLER, notional, fixed_rate, self.schedule, self.convention, day_count, True, True) cds.set_pricing_engine(self.engine) fair_rate = cds.fair_spread fair_cds = CreditDefaultSwap(SELLER, notional, fair_rate, self.schedule, self.convention, day_count, True, True) fair_cds.set_pricing_engine(self.engine) self.assertAlmostEqual(fair_cds.npv, 0.) def test_fair_upfront(self): fixed_rate = 0.05 upfront = 0.001 day_count = Actual360() notional = 10000 cds = CreditDefaultSwap.from_upfront(SELLER, notional, upfront, fixed_rate, self.schedule, self.convention, day_count, True, True) cds.set_pricing_engine(self.engine) fair_upfront = cds.fair_upfront fair_cds = CreditDefaultSwap.from_upfront(SELLER, notional, fair_upfront, fixed_rate, self.schedule, self.convention, day_count, True, True) fair_cds.set_pricing_engine(self.engine) self.assertAlmostEqual(fair_cds.npv, 0.) # same with null upfront upfront = 0. cds2 = CreditDefaultSwap.from_upfront(SELLER, notional, upfront, fixed_rate, self.schedule, self.convention, day_count, True, True) cds2.set_pricing_engine(self.engine) fair_upfront2 = cds.fair_upfront fair_cds2 = CreditDefaultSwap.from_upfront(SELLER, notional, fair_upfront, fixed_rate, self.schedule, self.convention, day_count, True, True) fair_cds2.set_pricing_engine(self.engine) self.assertAlmostEqual(fair_cds2.npv, 0.)
def example02(): print("example 2:\n") todays_date = Date(25, 9, 2014) Settings.instance().evaluation_date = todays_date calendar = TARGET() term_date = calendar.adjust(todays_date + Period(2, Years), Following) cds_schedule = Schedule(todays_date, term_date, Period(Quarterly), WeekendsOnly(), ModifiedFollowing, ModifiedFollowing, date_generation_rule=Rule.CDS) for date in cds_schedule: print(date) print() todays_date = Date(21, 10, 2014) Settings.instance().evaluation_date = todays_date quotes = [0.00006, 0.00045, 0.00081, 0.001840, 0.00256, 0.00337] tenors = [1, 2, 3, 6, 9, 12] deps = [ DepositRateHelper(q, Period(t, Months), 2, calendar, ModifiedFollowing, False, Actual360()) for q, t in zip(quotes, tenors) ] tenors = [2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 30] quotes = [ 0.00223, 0.002760, 0.003530, 0.004520, 0.005720, 0.007050, 0.008420, 0.009720, 0.010900, 0.012870, 0.014970, 0.017, 0.01821 ] swaps = [ SwapRateHelper.from_tenor(q, Period(t, Years), calendar, Annual, ModifiedFollowing, Thirty360(), Euribor6M(), SimpleQuote(0)) for q, t in zip(quotes, tenors) ] helpers = deps + swaps YC = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, todays_date, helpers, Actual365Fixed()) YC.extrapolation = True print("ISDA rate curve:") for h in helpers: print("{0}: {1:.6f}\t{2:.6f}".format( h.latest_date, YC.zero_rate(h.latest_date, Actual365Fixed(), 2).rate, YC.discount(h.latest_date))) defaultTs0 = FlatHazardRate(0, WeekendsOnly(), 0.016739207493630, Actual365Fixed()) cds_schedule = Schedule.from_rule(Date(22, 9, 2014), Date(20, 12, 2019), Period(3, Months), WeekendsOnly(), Following, Unadjusted, Rule.CDS, False) nominal = 100000000 trade = CreditDefaultSwap(Side.Buyer, nominal, 0.01, cds_schedule, Following, Actual360(), True, True, Date(22, 10, 2014), Actual360(True), True) engine = IsdaCdsEngine(defaultTs0, 0.4, YC, False) trade.set_pricing_engine(engine) print("reference trade NPV = {0}\n".format(trade.npv))
def test_bucketanalysis_bond(self): settings = Settings() calendar = TARGET() settlement_date = calendar.adjust(Date(28, January, 2011)) simple_quotes = [] fixing_days = 1 settlement_days = 1 todays_date = calendar.advance(settlement_date, -fixing_days, Days) settings.evaluation_date = todays_date face_amount = 100.0 redemption = 100.0 issue_date = Date(27, January, 2011) maturity_date = Date(1, January, 2021) coupon_rate = 0.055 bond_yield = 0.034921 flat_discounting_term_structure = YieldTermStructure() flat_term_structure = FlatForward(reference_date=settlement_date, forward=bond_yield, daycounter=Actual365Fixed(), compounding=Compounded, frequency=Semiannual) flat_discounting_term_structure.link_to(flat_term_structure) fixed_bond_schedule = Schedule.from_rule( issue_date, maturity_date, Period(Semiannual), UnitedStates(market=GovernmentBond), Unadjusted, Unadjusted, Backward, False) bond = FixedRateBond(settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(Bond), Unadjusted, redemption, issue_date) zspd = bf.zSpread(bond, 100.0, flat_term_structure, Actual365Fixed(), Compounded, Semiannual, settlement_date, 1e-6, 100, 0.5) depositData = [[1, Months, 4.581], [2, Months, 4.573], [3, Months, 4.557], [6, Months, 4.496], [9, Months, 4.490]] swapData = [[1, Years, 4.54], [5, Years, 4.99], [10, Years, 5.47], [20, Years, 5.89], [30, Years, 5.96]] rate_helpers = [] end_of_month = True for m, period, rate in depositData: tenor = Period(m, Months) sq_rate = SimpleQuote(rate / 100) helper = DepositRateHelper(sq_rate, tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) simple_quotes.append(sq_rate) rate_helpers.append(helper) liborIndex = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, rate in swapData: sq_rate = SimpleQuote(rate / 100) helper = SwapRateHelper.from_tenor(sq_rate, Period(m, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart) simple_quotes.append(sq_rate) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) discounting_term_structure = YieldTermStructure() discounting_term_structure.link_to(ts) pricing_engine = DiscountingBondEngine(discounting_term_structure) bond.set_pricing_engine(pricing_engine) self.assertAlmostEqual(bond.npv, 100.83702940160767) ba = bucket_analysis([simple_quotes], [bond], [1], 0.0001, 1) self.assertTrue(2, ba) self.assertTrue(type(tuple), ba) self.assertEqual(len(simple_quotes), len(ba[0][0])) self.assertEqual(0, ba[0][0][8])
def setUp(self): self.day_counter = Actual360()
def get_term_structure(df_libor, dtObs): settings = Settings() # libor as fixed in London, but cash-flows are determined according to # US calendar, hence the need to combine both holidays lists calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = calendar.adjust(dateToDate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) depositData = [[1, Months, 'Libor1M'], [3, Months, 'Libor3M'], [6, Months, 'Libor6M']] swapData = [[1, Years, 'Swap1Y'], [2, Years, 'Swap2Y'], [3, Years, 'Swap3Y'], [4, Years, 'Swap4Y'], [5, Years, 'Swap5Y'], [7, Years, 'Swap7Y'], [10, Years, 'Swap10Y'], [30, Years, 'Swap30Y']] rate_helpers = [] end_of_month = True for m, period, label in depositData: tenor = Period(m, Months) rate = df_libor.get_value(dtObs, label) helper = DepositRateHelper(float(rate / 100), tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) endOfMonth = True liborIndex = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, label in swapData: rate = df_libor.get_value(dtObs, label) helper = SwapRateHelper.from_tenor(rate / 100., Period(m, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = term_structure_factory('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) return ts
# convert them to Quote objects #for n,unit in deposits.keys(): # deposits[(n,unit)] = SimpleQuote(deposits[(n,unit)]) for n,m in FRAs.keys(): FRAs[(n,m)] = SimpleQuote(FRAs[(n,m)]) for d in futures.keys(): futures[d] = SimpleQuote(futures[d]) for s in swaps.keys(): swaps[s] = SimpleQuote(swaps[s]) #for n,unit in swaps.keys(): # swaps[(n,unit)] = SimpleQuote(swaps[(n,unit)]) # build rate helpers day_counter = Actual360() settlementDays = 2 depositHelpers = [ DepositRateHelper(v, Period(n,unit), settlementDays, calendar, ModifiedFollowing, False, day_counter) for (n, unit), v in deposits.items()] day_counter = Actual360() settlementDays = 2 fraHelpers = [ FraRateHelper(v, n, m, settlementDays, calendar, ModifiedFollowing, False, day_counter) for (n, m), v in FRAs.items() ]
def test_black_calibration(self): # calibrate a Heston model to a constant volatility surface without # smile. expected result is a vanishing volatility of the volatility. # In addition theta and v0 should be equal to the constant variance todays_date = today() self.settings.evaluation_date = todays_date daycounter = Actual360() calendar = NullCalendar() risk_free_ts = flat_rate(0.04, daycounter) dividend_ts = flat_rate(0.50, daycounter) option_maturities = [ Period(1, Months), Period(2, Months), Period(3, Months), Period(6, Months), Period(9, Months), Period(1, Years), Period(2, Years) ] options = [] s0 = SimpleQuote(1.0) vol = SimpleQuote(0.1) volatility = vol.value for maturity in option_maturities: for moneyness in np.arange(-1.0, 2.0, 1.): tau = daycounter.year_fraction( risk_free_ts.reference_date, calendar.advance( risk_free_ts.reference_date, period=maturity) ) forward_price = s0.value * dividend_ts.discount(tau) / \ risk_free_ts.discount(tau) strike_price = forward_price * np.exp( -moneyness * volatility * np.sqrt(tau) ) options.append( HestonModelHelper( maturity, calendar, s0.value, strike_price, vol, risk_free_ts, dividend_ts ) ) for sigma in np.arange(0.1, 0.7, 0.2): v0 = 0.01 kappa = 0.2 theta = 0.02 rho = -0.75 process = HestonProcess( risk_free_ts, dividend_ts, s0, v0, kappa, theta, sigma, rho ) self.assertEqual(v0, process.v0) self.assertEqual(kappa, process.kappa) self.assertEqual(theta, process.theta) self.assertEqual(sigma, process.sigma) self.assertEqual(rho, process.rho) self.assertEqual(1.0, process.s0.value) model = HestonModel(process) engine = AnalyticHestonEngine(model, 96) for option in options: option.set_pricing_engine(engine) optimisation_method = LevenbergMarquardt(1e-8, 1e-8, 1e-8) end_criteria = EndCriteria(400, 40, 1.0e-8, 1.0e-8, 1.0e-8) model.calibrate(options, optimisation_method, end_criteria) tolerance = 3.0e-3 self.assertFalse(model.sigma > tolerance) self.assertAlmostEqual( model.kappa * model.theta, model.kappa * volatility ** 2, delta=tolerance ) self.assertAlmostEqual(model.v0, volatility ** 2, delta=tolerance)
(10,Years): 0.05165, (15,Years): 0.055175 } # convert them to Quote objects for n,unit in deposits.keys(): deposits[(n,unit)] = SimpleQuote(deposits[(n,unit)]) for n,m in FRAs.keys(): FRAs[(n,m)] = SimpleQuote(FRAs[(n,m)]) for d in futures.keys(): futures[d] = SimpleQuote(futures[d]) for n,unit in swaps.keys(): swaps[(n,unit)] = SimpleQuote(swaps[(n,unit)]) # build rate helpers dayCounter = Actual360() settlementDays = 2 depositHelpers = [ DepositRateHelper(deposits[(n,unit)], Period(n,unit), settlementDays, calendar, ModifiedFollowing, False, dayCounter) for n, unit in [(1,Weeks),(1,Months),(3,Months), (6,Months),(9,Months),(1,Years)] ] dayCounter = Actual360() settlementDays = 2 fraHelpers = [ FraRateHelper(FRAs[(n,m)], n, m, settlementDays, calendar, ModifiedFollowing, False, dayCounter) for n, m in FRAs.keys() ]