简体   繁体   English

Python中的QuantLib cpibond bond示例

[英]QuantLib cpibond bond example in Python

I am trying to get the official C++ cpibond example working in Python. 我试图让正式的C ++ cpibond示例在Python中运行。 The original example is here: https://github.com/lballabio/quantlib/blob/master/QuantLib/test-suite/inflationcpibond.cpp and for scala here: https://github.com/lballabio/quantlib/blob/master/QuantLib-SWIG/Scala/examples/CPIBond.scala 最初的例子如下: https//github.com/lballabio/quantlib/blob/master/QuantLib/test-suite/inflationcpibond.cpp和scala: https//github.com/lballabio/quantlib/blob/主/ QuantLib-SWIG /斯卡拉/示例/ CPIBond.scala

When I run what I have attempted I get this error: 当我运行我尝试过的时候,我得到了这个错误:

RuntimeError: 1st iteration: failed at 1st alive instrument, maturity September 1st, 2010, reference date September 1st, 2009: 2nd leg: Missing UK RPI fixing for September 1st, 2009 RuntimeError:第一次迭代:在第一次活着的仪器上失败,到期日2010年9月1日,参考日期2009年9月1日:第二站:2009年9月1日错过英国RPI修复

Here is my attempt: 这是我的尝试:

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()

Most of my problem is that I am finding it difficult to get to grips with how the objects fit together. 我的大多数问题是我发现很难掌握物体如何组合在一起。

got the above example working: 让上面的例子工作:

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

The issue it seems was that the inflationIndex object needed one date instead of multiple index points. 似乎问题是inflationIndex对象需要一个日期而不是多个索引点。 My assumption was it would pull out the latest valid point. 我的假设是它会提出最新的有效点。

The way the pricer works is that the real coupons are increased by the inflation rate curve term structure, zciisData. pricer的工作方式是通过通胀率曲线项结构zciisData增加真实的优惠券。 The result therefore becomes a nominal future cash flow. 因此,结果成为名义上的未来现金流。 To price then the bondpricer simply discounts these by the nominal term structure. 为了定价,债券经济商只需按名义期限结构对这些进行折扣即可。 I added some additional code to print the determined cash flows and the "growth factor" and then the discount rate. 我添加了一些额外的代码来打印确定的现金流量和“增长因子”,然后是贴现率。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM