定义固定利率国债
import QuantLib as ql
# 22附息国债19 - 220019.IB
# 债券期限 - 10年
# 债券起息日 - 2022-09-01
# 日历
calendar = ql.China(ql.China.IB)
# T+1 结算
settlementDays = 1
# 面值(元) - 100.00
faceAmount = 100.0
# 债券发行日 - 2022-08-31
issueDate = ql.Date(31, ql.August, 2022)
# 到期兑付日 - 2032-09-01
maturityDate = ql.Date(1, ql.September, 2032)
# 付息频率 - 半年
coupon_period = ql.Period(ql.Semiannual)
# 节假日调整规则
holidayConvention = ql.Unadjusted
terminationDateConvention = ql.Unadjusted
# 日期规则(?)
dateGenRule = ql.DateGeneration.Backward
# 是否月末(?)
endOfMonth = False
schedule = ql.Schedule(
issueDate,
maturityDate,
coupon_period,
calendar,
holidayConvention,
terminationDateConvention,
dateGenRule,
endOfMonth)
# print(list(schedule))
# 票面利率(%) - 2.6000
coupons = [2.60 / 100.0]
# 在构造 ActualActual 对象时要附加上债券现金流支付的日期表 schedule 对象)
# 见 https://quant.stackexchange.com/questions/12707/pricing-a-fixedratebond-in-quantlib-yield-vs-termstructure
# ql.ActualActual.Bond/ISMA 差异多大,怎么用?
accrualDayCounter = ql.ActualActual(ql.ActualActual.ISMA, schedule)
paymentConvention = ql.Unadjusted
bond = ql.FixedRateBond(
settlementDays,
faceAmount,
schedule,
coupons,
accrualDayCounter,
paymentConvention)
定义利率曲线
# 可以调整此数值看估值结果有何不同
bondYield = 2.7652 / 100.0
compounding = ql.Compounded
# 试验发现要与coupon period一致
frequency = ql.Semiannual
termStructure = ql.YieldTermStructureHandle(
ql.FlatForward(
settlementDays,
calendar,
bondYield,
ql.Thirty360(), # 这里是一个大坑,参考 https://www.youtube.com/watch?v=dQjd3hAshj4
compounding,
frequency))
engine = ql.DiscountingBondEngine(termStructure)
bond.setPricingEngine(engine)
注意利率曲线 day count 用的是 ql.Thirty360()
,原因参考这里:QuantLib notebooks: dangerous day count conventions
估值、与上清所估值对比
import prettytable as pt
cleanPrice = bond.cleanPrice()
dirtyPrice = bond.dirtyPrice()
accruedAmount = bond.accruedAmount()
duration = ql.BondFunctions.duration(
bond,
bondYield,
accrualDayCounter,
compounding,
frequency)
convexity = ql.BondFunctions.convexity(
bond,
bondYield,
accrualDayCounter,
compounding,
frequency)
bps = ql.BondFunctions.basisPointValue(
bond,
bondYield,
accrualDayCounter,
compounding,
frequency)
tab = pt.PrettyTable(['item', 'QuantLib', 'ShClearing'])
tab.add_row(['clean price', cleanPrice, 98.5787])
tab.add_row(['dirty price', dirtyPrice, 98.8516])
tab.add_row(['accrued amount', accruedAmount, 0.2729])
tab.add_row(['duration', duration, 8.6352])
tab.add_row(['convexity', convexity, 84.9296])
tab.add_row(['bps', abs(bps), 0.0854])
tab.float_format = '.4'
print(tab)
- 上清所估值结果