0
$\begingroup$

I'm trying to build up a US treasury curves using Bills and bonds with the FixedRateBond class, however when I compared the ParYield from .bondYield() and zero_rate from yield curve instance. The yield has large monthly jump in very front end (<1Y), but the zero rate looks smooth..

I check that curve.zeroRate(ql.Date(20, 11, 2023), day_count, ql.Compounded) looks normal ->5.42% however the discount factor from curve gives large implied rate: (1/curve.discount(ql.Date(20, 11, 2023)))**(365/(16))

Is there a bug in Quantlib bondYield() method..?

calc_date = ql.Date(today,'%Y%m%d')
ql.Settings.instance().evaluationDate = calc_date
bump = 50 # bps

calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond)
bussiness_convention = ql.Unadjusted
day_count = ql.ActualActual(ql.ActualActual.Bond)
end_of_month = False
settlement_days = 1
face_amount = 100
coupon_frequency = ql.Period(ql.Semiannual)

depo_helpers = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(r/100.0)),
                                     m,
                                     settlement_days,
                                     calendar,
                                     bussiness_convention,
                                     end_of_month,
                                     day_count )
                for r, m in zip(depo_rates, depo_maturities)]

bond_helpers = []
for r, m,p in zip(bond_coupons, bond_maturities,bond_px):
    termination_date =  m
    schedule = ql.Schedule(calc_date,
                   termination_date,
                   coupon_frequency,
                   calendar,
                   bussiness_convention,
                   bussiness_convention,
                   ql.DateGeneration.Backward,
                   end_of_month)

    helper = ql.FixedRateBondHelper(ql.QuoteHandle(ql.SimpleQuote(p)),
                                        settlement_days,
                                        face_amount,
                                        schedule,
                                        [r/100.0],
                                        day_count,
                                        bussiness_convention,
                                        )

    bond_helpers.append(helper)
    
rate_helpers = depo_helpers + bond_helpers
yieldcurve = ql.PiecewiseLogCubicDiscount(calc_date,
                             rate_helpers,
                             day_count)
CurveHandle = ql.YieldTermStructureHandle(yieldcurve)

couponRate = cpn/100
coupons = [couponRate]
dayCount = ql.ActualActual(ql.ActualActual.Bond)
issueDate = ql.Date(iss_date.day, iss_date.month, iss_date.year)
maturityDate = ql.Date(mat_date.day, mat_date.month, mat_date.year)
tenor = ql.Period(ql.Semiannual)
calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond)
bussinessConvention = ql.Unadjusted
dateGeneration = ql.DateGeneration.Backward
monthEnd = False

schedule = ql.Schedule (issueDate, maturityDate, tenor, calendar, bussinessConvention,
                            bussinessConvention , dateGeneration, monthEnd)

fixedRateBond = ql.FixedRateBond(settlement_days, face_amount, schedule, coupons, dayCount)


spread1 = ql.SimpleQuote(bump/10000)
spread_handle1 = ql.QuoteHandle(spread1)
ts_spreaded1 = ql.ZeroSpreadedTermStructure(CurveHandle, spread_handle1)
ts_spreaded_handle1 = ql.YieldTermStructureHandle(ts_spreaded1)


bondEngine = ql.DiscountingBondEngine(ts_spreaded_handle1)
fixedRateBond.setPricingEngine(bondEngine)


# get spot rates
spots = []
pars = []
tenors = []
#for d in tqdm(base_curve.dates()[1:]):
curve_date = [to_qldate(x) for x in us_bus_day][5:]
for d in tqdm(curve_date):
    d_str = pd.Timestamp(d.year(), d.month(), d.dayOfMonth()).strftime("%Y%m%d")
    yrs = day_count.yearFraction(calc_date, d)
    compounding = ql.Compounded
    freq = ql.Semiannual
    zero_rate = base_curve.zeroRate(yrs, compounding, freq)
    tenors.append(yrs)
    eq_rate = zero_rate.equivalentRate(day_count,
                                       compounding,
                                       freq,
                                       calc_date,
                                       d).rate()

    par_bond = ust_curve.PriceFixedBond(base_curve_h,5,(pd.Timestamp(d_str) - pd.DateOffset(years= round((pd.Timestamp(d_str)-pd.Timestamp.today()).days/365)+1)).strftime("%Y%m%d"),\
                            d_str,\
                       face_amount = 100,settlement_days = 1,
                      dayCount = ql.ActualActual(ql.ActualActual.Bond),\
                      tenor = ql.Period(ql.Semiannual),\
                       calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond),\
                      bussinessConvention = ql.Unadjusted,\
                      dateGeneration = ql.DateGeneration.Backward,
                      monthEnd = False)
    pars.append(par_bond.bondYield( ql.ActualActual(ql.ActualActual.Bond),ql.Compounded,ql.Semiannual)*100)
    
    spots.append(100*eq_rate)
spot_rate = pd.DataFrame({'Spot Rate':spots,'Par Rate':pars},index =tenors )
spot_rate['date'] = [qldate_to_pddate(x) for x in curve_date] #base_curve.dates()[1:]
spot_rate = spot_rate.set_index('date')

enter image description here

$\endgroup$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.