I am using QuantLib to compute prices of fixed rate bonds in different scenarios. In the first step I would like to replicate the current market price by adjusting the yield curve with the zspread. Using the function BondFunctions.zSpread I get close (in the example below (97.85 versus a market price of 98) but I am wondering why we do not converge to the exact same price when altering the spread continuously. Am I missing something?
The following code adapts Simple QuantLib Bond Math
import pytest
import QuantLib as ql
from QuantLib import *
# Construct yield curve
calc_date = Date(1, 1, 2017)
Settings.instance().evaluationDate = calc_date
spot_dates = [Date(1,1,2017), Date(1,1,2018), Date(1,1,2027)]
# corrected!
# spot_rates = [0.0, 0.04, 0.04]
spot_rates = [0.04, 0.04, 0.04]
day_count = SimpleDayCounter()
calendar = NullCalendar()
interpolation = Linear()
compounding = Compounded
# corrected!
compounding_frequency = Annual
compounding_frequency = Semiannual
spot_curve = ZeroCurve(spot_dates, spot_rates, day_count, calendar,
interpolation, compounding,
compounding_frequency)
spot_curve_handle = YieldTermStructureHandle(spot_curve)
# Construct bond schedule
issue_date = Date(1, 1, 2017)
maturity_date = Date(1, 1, 2022)
tenor = Period(Semiannual)
calendar = NullCalendar()
business_convention = Unadjusted
date_generation = DateGeneration.Backward
month_end = False
schedule = Schedule(issue_date, maturity_date, tenor, calendar,
business_convention, business_convention,
date_generation, month_end)
# Create FixedRateBond Object
coupon_rate = 0.05
coupons = [coupon_rate]
settlement_days = 0
face_value = 100
fixed_rate_bond = FixedRateBond(settlement_days,
face_value,
schedule,
coupons,
day_count)
# Set Valuation engine
bond_engine = DiscountingBondEngine(spot_curve_handle)
fixed_rate_bond.setPricingEngine(bond_engine)
# Calculate present value
value = fixed_rate_bond.NPV()
assert value == pytest.approx(104.49, abs=1.e-2)
# fix a hypothetical market price
px = 98.
# compute the implied z spread
zspread = ql.BondFunctions.zSpread(fixed_rate_bond,
px,
spot_curve, day_count, compounding,
compounding_frequency, calc_date, 1.e-16, 1000000, 0.)
def impl_clean_price(spread):
spread1 = ql.SimpleQuote(spread)
spread_handle1 = ql.QuoteHandle(spread1)
ts_spreaded1 = ql.ZeroSpreadedTermStructure(spot_curve_handle,
spread_handle1)
ts_spreaded_handle1 = ql.YieldTermStructureHandle(ts_spreaded1)
ycsin = ts_spreaded_handle1
fixed_rate_bond = FixedRateBond(settlement_days,
face_value,
schedule,
coupons,
day_count)
# Set Valuation engine
bond_engine = DiscountingBondEngine(ycsin)
fixed_rate_bond.setPricingEngine(bond_engine)
value = fixed_rate_bond.cleanPrice()
return value
# the two clean prices are 98 and 97.8517891975
print px
print impl_clean_price(zspread)
print abs(px-impl_clean_price(zspread))