QuantLib 中 Python 的 cpibond 债券示例
我正在尝试在Python中运行官方的C++ cpibond示例。原始示例可以在这里找到:https://github.com/lballabio/quantlib/blob/master/QuantLib/test-suite/inflationcpibond.cpp,而Scala的示例在这里:https://github.com/lballabio/quantlib/blob/master/QuantLib-SWIG/Scala/examples/CPIBond.scala
当我运行我尝试的代码时,出现了这个错误:
运行时错误:第一次迭代:在第一个有效工具上失败,到期日 2010年9月1日,参考日期2009年9月1日:第二部分: 缺少2009年9月1日的英国RPI修正值
这是我的尝试:
import QuantLib as ql
calendar = ql.UnitedKingdom()
dayCounter = ql.ActualActual();
convention = ql.ModifiedFollowing
today = ql.Date(20, 11, 2009)
evaluationDate = calendar.adjust(today)
ql.Settings.instance().setEvaluationDate(evaluationDate)
yTS = ql.YieldTermStructureHandle(ql.FlatForward(evaluationDate, 0.05, dayCounter))
from_date = ql.Date(20, ql.July, 2007);
to_date = ql.Date(20, ql.November, 2009);
tenor = ql.Period(1, ql.Months)
rpiSchedule = ql.Schedule(from_date, to_date, tenor, calendar,
convention, convention,
ql.DateGeneration.Backward, False)
cpiTS = ql.RelinkableZeroInflationTermStructureHandle()
inflationIndex = ql.UKRPI(False, cpiTS)
fixData = [206.1, 207.3, 208.0, 208.9, 209.7, 210.9,
209.8, 211.4, 212.1, 214.0, 215.1, 216.8,
216.5, 217.2, 218.4, 217.7, 216,
212.9, 210.1, 211.4, 211.3, 211.5,
212.8, 213.4, 213.4, 213.4, 214.4,213.4, 214.4]
dte_fixings=[dtes for dtes in rpiSchedule]
print len(dte_fixings)
print len(fixData)
#must be the same length
inflationIndex.addFixings(dte_fixings, fixData)
observationLag = ql.Period(2, ql.Months)
zciisData =[( ql.Date(25, ql.November, 2010), 3.0495 ),
( ql.Date(25, ql.November, 2011), 2.93 ),
( ql.Date(26, ql.November, 2012), 2.9795 ),
( ql.Date(25, ql.November, 2013), 3.029 ),
( ql.Date(25, ql.November, 2014), 3.1425 ),
( ql.Date(25, ql.November, 2015), 3.211 ),
( ql.Date(25, ql.November, 2016), 3.2675 ),
( ql.Date(25, ql.November, 2017), 3.3625 ),
( ql.Date(25, ql.November, 2018), 3.405 ),
( ql.Date(25, ql.November, 2019), 3.48 ),
( ql.Date(25, ql.November, 2021), 3.576 ),
( ql.Date(25, ql.November, 2024), 3.649 ),
( ql.Date(26, ql.November, 2029), 3.751 ),
( ql.Date(27, ql.November, 2034), 3.77225),
( ql.Date(25, ql.November, 2039), 3.77 ),
( ql.Date(25, ql.November, 2049), 3.734 ),
( ql.Date(25, ql.November, 2059), 3.714 )]
lRates=[rtes/100.0 for rtes in zip(*zciisData)[1]]
baseZeroRate = lRates[0]
zeroSwapHelpers = [ql.ZeroCouponInflationSwapHelper(a[1]/100,observationLag,
a[0], calendar, convention, dayCounter, inflationIndex) for a in zciisData]
cpiTS.linkTo(ql.PiecewiseZeroInflation(
evaluationDate, calendar, dayCounter, observationLag,
inflationIndex.frequency(), inflationIndex.interpolated(),
baseZeroRate,
yTS, zeroSwapHelpers, 1.0e-12, ql.Linear()))
notional = 1000000
fixedRates = [0.1]
fixedDayCounter = ql.Actual365Fixed()
fixedPaymentConvention = ql.ModifiedFollowing
fixedPaymentCalendar = ql.UnitedKingdom()
contractObservationLag = ql.Period(3, ql.Months)
observationInterpolation = ql.CPI.Flat
settlementDays = 3
growthOnly = True
baseCPI = 206.1
startDate = ql.Date(2, 10, 2007)
endDate = ql.Date(2, 10, 2052)
fixedSchedule = ql.Schedule(startDate, endDate,
ql.Period(6, ql.Months), fixedPaymentCalendar,
ql.Unadjusted,
ql.Unadjusted,
ql.DateGeneration.Backward, False)
bond = ql.CPIBond(settlementDays, notional, growthOnly,
baseCPI, contractObservationLag,
inflationIndex, observationInterpolation,
fixedSchedule, fixedRates, fixedDayCounter,
fixedPaymentConvention)
bondEngine=ql.DiscountingBondEngine(yTS)
bond.setPricingEngine(bondEngine)
print bond.NPV()
print bond.cleanPrice()
我遇到的大部分问题是,我发现很难理解这些对象是如何组合在一起的。
相关文章:
- 暂无相关问题
1 个回答
3
我把上面的例子搞定了:
import QuantLib as ql
import datetime as dt
calendar = ql.UnitedKingdom()
dayCounter = ql.ActualActual();
convention = ql.ModifiedFollowing
lag = 3
today = ql.Date(5,3,2008)
evaluationDate = calendar.adjust(today)
issue_date = calendar.advance(evaluationDate,-1, ql.Years)
maturity_date = ql.Date(2,9,2052)
fixing_date = calendar.advance(evaluationDate,-lag, ql.Months)
ql.Settings.instance().setEvaluationDate(evaluationDate)
yTS = ql.YieldTermStructureHandle(ql.FlatForward(evaluationDate, 0.05, dayCounter))
tenor = ql.Period(1, ql.Months)
from_date = ql.Date(20, ql.July, 2007);
to_date = ql.Date(20, ql.November, 2009);
rpiSchedule = ql.Schedule(from_date, to_date, tenor, calendar,
convention, convention,
ql.DateGeneration.Backward, False)
# this is the going to be holder the inflation curve.
cpiTS = ql.RelinkableZeroInflationTermStructureHandle()
inflationIndex = ql.UKRPI(False, cpiTS)
fixData = [206.1, 207.3, 208.0, 208.9, 209.7, 210.9,
209.8, 211.4, 212.1, 214.0, 215.1, 216.8,
216.5, 217.2, 218.4, 217.7, 216,
212.9, 210.1, 211.4, 211.3, 211.5,
212.8, 213.4, 213.4, 213.4, 214.4]
dte_fixings=[dtes for dtes in rpiSchedule]
print len(fixData)
print len(dte_fixings[:len(fixData)])
#must be the same length
#inflationIndex.addFixings(dte_fixings[:len(fixData)], fixData)
#Current CPI level
#last observed rate
fixing_rate = 214.4
inflationIndex.addFixing(fixing_date, fixing_rate)
observationLag = ql.Period(lag, ql.Months)
zciisData =[( ql.Date(25, ql.November, 2010), 3.0495 ),
( ql.Date(25, ql.November, 2011), 2.93 ),
( ql.Date(26, ql.November, 2012), 2.9795 ),
( ql.Date(25, ql.November, 2013), 3.029 ),
( ql.Date(25, ql.November, 2014), 3.1425 ),
( ql.Date(25, ql.November, 2015), 3.211 ),
( ql.Date(25, ql.November, 2016), 3.2675 ),
( ql.Date(25, ql.November, 2017), 3.3625 ),
( ql.Date(25, ql.November, 2018), 3.405 ),
( ql.Date(25, ql.November, 2019), 3.48 ),
( ql.Date(25, ql.November, 2021), 3.576 ),
( ql.Date(25, ql.November, 2024), 3.649 ),
( ql.Date(26, ql.November, 2029), 3.751 ),
( ql.Date(27, ql.November, 2034), 3.77225),
( ql.Date(25, ql.November, 2039), 3.77 ),
( ql.Date(25, ql.November, 2049), 3.734 ),
( ql.Date(25, ql.November, 2059), 3.714 )]
#lRates=[rtes/100.0 for rtes in zip(*zciisData)[1]]
#baseZeroRate = lRates[0]
zeroSwapHelpers = [ql.ZeroCouponInflationSwapHelper(rate/100,observationLag,
date, calendar, convention, dayCounter, inflationIndex) for date,rate in zciisData]
# the derived inflation curve
jj=ql.PiecewiseZeroInflation(
evaluationDate, calendar, dayCounter, observationLag,
inflationIndex.frequency(), inflationIndex.interpolated(),
zciisData[0][1],#baseZeroRate,
yTS, zeroSwapHelpers, 1.0e-12, ql.Linear())
cpiTS.linkTo(jj)
notional = 1000000
fixedRates = [0.1]
fixedDayCounter = ql.Actual365Fixed()
fixedPaymentConvention = ql.ModifiedFollowing
fixedPaymentCalendar = ql.UnitedKingdom()
contractObservationLag = ql.Period(3, ql.Months)
observationInterpolation = ql.CPI.Flat
settlementDays = 3
growthOnly = False
baseCPI = 206.1
fixedSchedule = ql.Schedule(issue_date,
maturity_date,
ql.Period(ql.Semiannual),
fixedPaymentCalendar,
ql.Unadjusted,
ql.Unadjusted,
ql.DateGeneration.Backward,
False)
bond = ql.CPIBond(settlementDays,
notional,
growthOnly,
baseCPI,
contractObservationLag,
inflationIndex,
observationInterpolation,
fixedSchedule,
fixedRates,
fixedDayCounter,
fixedPaymentConvention)
#bond2= ql.QuantLib.C
bondEngine=ql.DiscountingBondEngine(yTS)
bond.setPricingEngine(bondEngine)
print bond.NPV()
print bond.cleanPrice()
compounding = ql.Compounded
yield_rate = bond.bondYield(fixedDayCounter,compounding,ql.Semiannual)
y_curve = ql.InterestRate(yield_rate,fixedDayCounter,compounding,ql.Semiannual)
##Collate results
print "Clean Price:", bond.cleanPrice()
print "Dirty Price:", bond.dirtyPrice()
print "Notional:", bond.notional()
print "Yield:", yield_rate
print "Accrued Amount:", bond.accruedAmount()
print "Settlement Value:", bond.settlementValue()
#suspect there's more to this for TIPS
print "Duration:", ql.BondFunctions.duration(bond,y_curve)
print "Convexity:", ql.BondFunctions.convexity(bond,y_curve)
print "Bps:", ql.BondFunctions.bps(bond,y_curve)
print "Basis Point Value:", ql.BondFunctions.basisPointValue(bond,y_curve)
print "Yield Value Basis Point:", ql.BondFunctions.yieldValueBasisPoint(bond,y_curve)
print "NPV:", bond.NPV()
# get the cash flows:
#cf_list=[(cf.amount(),cf.date()) for cf in bond.cashflows()]
def to_datetime(d):
return dt.datetime(d.year(),d.month(), d.dayOfMonth())
for cf in bond.cashflows():
try:
amt=cf.amount()
rte=jj.zeroRate(cf.date())
zc=yTS.zeroRate(cf.date(),fixedDayCounter,compounding,ql.Semiannual).rate()
except:
amt=0
rte=0
zc=0
print to_datetime(cf.date()),amt,rte,zc
看起来问题在于inflationIndex这个对象需要一个日期,而不是多个指数点。我原以为它会提取最新的有效点。
这个定价器的工作原理是,实际的利息券会根据通货膨胀率曲线的结构(zciisData)进行调整。因此,结果就变成了一个名义上的未来现金流。然后,债券定价器只需根据名义利率结构对这些现金流进行折现。我还添加了一些额外的代码来打印出确定的现金流、"增长因子"和折现率。