def test_united_states_calendar(self): uscal = UnitedStates() holiday_date = Date(4, Jul, 2010) self.assertTrue(uscal.is_holiday(holiday_date)) uscal = UnitedStates(market=NYSE) holiday_date = Date(5, Sep, 2011) # Labor day self.assertTrue(uscal.is_holiday(holiday_date))
class CalendarFactory: _lookup = dict([(cal.name(), cal) for cal in [ TARGET(), NullCalendar(), Germany(), Germany(EUREX), Germany(FrankfurtStockExchange), Germany(GER_SETTLEMENT), Germany(EUWAX), Germany(XETRA), UnitedKingdom(), UnitedKingdom(EXCHANGE), UnitedKingdom(METALS), UnitedKingdom(UK_SETTLEMENT), UnitedStates(), UnitedStates(GOVERNMENTBOND), UnitedStates(NYSE), UnitedStates(NERC), UnitedStates(US_SETTLEMENT) ]])
def test_bucketanalysis_bond(self): face_amount = 100.0 redemption = 100.0 issue_date = Date(27, January, 2011) maturity_date = Date(1, January, 2021) coupon_rate = 0.055 fixed_bond_schedule = Schedule.from_rule( issue_date, maturity_date, Period(Semiannual), UnitedStates(market=GovernmentBond), Unadjusted, Unadjusted, Backward, False) bond = FixedRateBond( self.settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(Bond), Unadjusted, redemption, issue_date ) pricing_engine = DiscountingBondEngine(self.ts) bond.set_pricing_engine(pricing_engine) self.assertAlmostEqual(bond.npv, 100.82127876105724) quotes = [rh.quote for rh in self.rate_helpers] delta, gamma = bucket_analysis(quotes, [bond]) self.assertEqual(len(quotes), len(delta)) old_values = [q.value for q in quotes] delta_manual = [] gamma_manual = [] pv = bond.npv shift = 1e-4 for v, q in zip(old_values, quotes): q.value = v + shift pv_plus = bond.npv q.value = v - shift pv_minus = bond.npv delta_manual.append((pv_plus - pv_minus) * 0.5 / shift) gamma_manual.append((pv_plus - 2 * pv + pv_minus) / shift ** 2) q.value = v assert_allclose(delta, delta_manual) assert_allclose(gamma, gamma_manual, atol=1e-4)
def test_joint(self): ukcal = UnitedKingdom() uscal = UnitedStates() bank_holiday_date = Date(3, May, 2010) #Early May Bank Holiday thanksgiving_holiday_date = Date(22, Nov, 2012) jtcal = JointCalendar(ukcal, uscal, JOINHOLIDAYS) self.assertFalse(jtcal.is_business_day(bank_holiday_date)) self.assertFalse(jtcal.is_business_day(thanksgiving_holiday_date)) jtcal = JointCalendar(ukcal, uscal, JOINBUSINESSDAYS) self.assertTrue(jtcal.is_business_day(bank_holiday_date)) self.assertTrue(jtcal.is_business_day(thanksgiving_holiday_date))
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))
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))
def test_pricing_bond(self): '''Inspired by the C++ code from http://quantcorner.wordpress.com/.''' 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 discounting_term_structure = YieldTermStructure(relinkable=True) 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 discounting_term_structure.link_to(flat_term_structure) #Rate fixed_bond_schedule = Schedule(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) bond.set_pricing_engine(discounting_term_structure) # tests self.assertTrue(Date(27, January, 2011), bond.issue_date) self.assertTrue(Date(31, August, 2020), bond.maturity_date) self.assertTrue(settings.evaluation_date, bond.valuation_date) # the following assertion fails but must be verified self.assertAlmostEqual(101.1, bond.clean_price, 1) self.assertAlmostEqual(101.1, bond.net_present_value, 1) self.assertAlmostEqual(101.1, bond.dirty_price) self.assertAlmostEqual(0.009851, bond.accrued_amount()) print(settings.evaluation_date) print('Principal: {}'.format(face_amount)) print('Issuing date: {} '.format(bond.issue_date)) print('Maturity: {}'.format(bond.maturity_date)) print('Coupon rate: {:.4%}'.format(coupon_rate)) print('Yield: {:.4%}'.format(bond_yield)) print('Net present value: {:.4f}'.format(bond.net_present_value)) print('Clean price: {:.4f}'.format(bond.clean_price)) print('Dirty price: {:.4f}'.format(bond.dirty_price)) print('Accrued coupon: {:.6f}'.format(bond.accrued_amount())) print('Accrued coupon: {:.6f}'.format( bond.accrued_amount(Date(1, March, 2011))))
def test_excel_example_with_floating_rate_bond(self): todays_date = Date(25, August, 2011) settings = Settings() settings.evaluation_date = todays_date calendar = TARGET() effective_date = Date(10, Jul, 2006) termination_date = calendar.advance(effective_date, 10, Years, convention=Unadjusted) settlement_date = calendar.adjust(Date(28, January, 2011)) settlement_days = 3 #1 face_amount = 13749769.27 #2 coupon_rate = 0.05 redemption = 100.0 float_bond_schedule = Schedule(effective_date, termination_date, Period(Annual), calendar, ModifiedFollowing, ModifiedFollowing, Backward) #3 flat_discounting_term_structure = YieldTermStructure(relinkable=True) forecastTermStructure = YieldTermStructure(relinkable=True) dc = Actual360() ibor_index = Euribor6M(forecastTermStructure) #5 fixing_days = 2 #6 gearings = [1, 0.0] #7 spreads = [1, 0.05] #8 caps = [] #9 floors = [] #10 pmt_conv = ModifiedFollowing #11 issue_date = effective_date float_bond = FloatingRateBond(settlement_days, face_amount, float_bond_schedule, ibor_index, dc, fixing_days, gearings, spreads, caps, floors, pmt_conv, redemption, issue_date) flat_term_structure = FlatForward(settlement_days=1, forward=0.055, calendar=NullCalendar(), daycounter=Actual365Fixed(), compounding=Continuous, frequency=Annual) flat_discounting_term_structure.link_to(flat_term_structure) forecastTermStructure.link_to(flat_term_structure) engine = DiscountingBondEngine(flat_discounting_term_structure) float_bond.set_pricing_engine(engine) cons_option_vol = ConstantOptionletVolatility(settlement_days, UnitedStates(SETTLEMENT), pmt_conv, 0.95, Actual365Fixed()) coupon_pricer = BlackIborCouponPricer(cons_option_vol) set_coupon_pricer(float_bond, coupon_pricer) self.assertEquals(Date(10, Jul, 2016), termination_date) self.assertEquals(calendar.advance(todays_date, 3, Days), float_bond.settlement_date()) self.assertEquals(Date(11, Jul, 2016), float_bond.maturity_date) self.assertAlmostEqual( 0.6944, float_bond.accrued_amount(float_bond.settlement_date()), 4) self.assertAlmostEqual(98.2485, float_bond.dirty_price, 4) self.assertAlmostEqual(13500805.2469, float_bond.npv, 4)
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( 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.from_reference_date( BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, 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.yld(bond, 102.0, ActualActual(ISDA), Compounded, Semiannual, settlement_date, 1e-6, 100, 0.5) dur = bf.duration(bond, yld, ActualActual(ISDA), Compounded, Semiannual, 2, settlement_date) yld_disco = bf.yld(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, 2, 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_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])
class Calendars(dict): ''' Wrapper for quantlib Calendar objects and methods. Accepts python.datetime objects and strings instead of pyql.quantlib dates. :adjust: Adjust date to business day :advance: Advance date by specified period :is_business_day: Checks date can be used as a dict using name property of pyql.quantlib.calendar objects for example: Calendars()['TARGET'] returns TARGET calendar ''' from quantlib.time.calendar import TARGET from quantlib.time.calendars.null_calendar import NullCalendar from quantlib.time.calendars.germany import ( Germany, EUREX, FrankfurtStockExchange, SETTLEMENT as GER_SETTLEMENT, EUWAX, XETRA ) from quantlib.time.calendars.united_kingdom import ( EXCHANGE, METALS, SETTLEMENT as UK_SETTLEMENT, UnitedKingdom ) from quantlib.time.calendars.united_states import ( UnitedStates, GOVERNMENTBOND, NYSE, NERC, SETTLEMENT as US_SETTLEMENT ) _lookup = dict([(cal.name(), cal) for cal in [TARGET(), NullCalendar(), Germany(), Germany(EUREX), Germany( FrankfurtStockExchange), Germany(GER_SETTLEMENT), Germany( EUWAX), Germany(XETRA), UnitedKingdom(), UnitedKingdom(EXCHANGE), UnitedKingdom(METALS), UnitedKingdom(UK_SETTLEMENT), UnitedStates(), UnitedStates(GOVERNMENTBOND), UnitedStates( NYSE), UnitedStates(NERC), UnitedStates(US_SETTLEMENT)] ] ) def __init__(self, *args): dict.__init__(self, self._lookup) self.update(*args) @classmethod def adjust(cls, date, calendar=None, convention=None): if not calendar: calendar = cls.TARGET() elif not hasattr(calendar, "adjust"): return None if not convention: convention = BusinessDayConventions.Following qldate = qldate_from_pydate(pydate(date)) try: return pydate_from_qldate(calendar.adjust(qldate, convention)) except: try: return pydate_from_qldate(calendar().adjust(qldate, convention)) except: return None @classmethod def advance(cls, date, n, timeunit=None, calendar=None, convention=None): """ Advance pydate according the specified calendar and convention :pydate: e.g. 19600809, date(1964, 9, 29), '5-23-1993' :n: integer :timeunit: e.g., enums.TimeUnits.Days usage ----- Note 9/6/1980 is a weekend >>> Calendars.advance(19800906, 1) datetime.date(1980, 9, 8) """ if not calendar: calendar = cls.TARGET() elif not hasattr(calendar, "advance"): return None if not convention: convention = BusinessDayConventions.Following if not timeunit: timeunit = TimeUnits.Days qldate = qldate_from_pydate(pydate(date)) try: return pydate_from_qldate(calendar.advance(qldate, n, timeunit)) except: try: return pydate_from_qldate( calendar().advance(qldate, n, timeunit) ) except: print("failure {}".format(qldate)) return None @classmethod def is_business_day(cls, date, calendar=None): if not calendar: calendar = cls.TARGET() elif not hasattr(calendar, "advance"): return None qldate = qldate_from_pydate(pydate(date)) try: return calendar.is_business_day(qldate) except: try: return calendar().is_business_day(qldate) except: return None