QuantLib 金融計算——案例之固息債的價格、久期、凸性和 BPS


QuantLib 金融計算——案例之固息債的價格、久期、凸性和 BPS

概述

從本篇開始計划開啟一個系列,以《Interest Rate Risk Modeling》為藍本,介紹有關利率風險的計算案例,內容涉及從簡單的久期、凸性到主成分久期和久期向量模型等高階的度量指標。

cover

計算久期和凸性

固息債的久期、凸性和 BPS 是最常見的利率風險度量指標,下面將以 200205 為例,計算 2020-07-28 這一天的價格,以及久期、凸性和 BPS。

首先從中國貨幣網查詢債券的基本信息,用以配置 FixedRateBond 對象。

  • 債券起息日:2020-03-10
  • 到期兌付日:2030-03-10
  • 債券期限:10 年
  • 面值(元):100.00
  • 計息基准:A/A
  • 息票類型:附息式固定利率
  • 付息頻率:年
  • 票面利率(%):3.0700
  • 結算方式:T+1
import QuantLib as ql
import prettytable as pt

today = ql.Date(28, ql.July, 2020)
ql.Settings.instance().evaluationDate = today

settlementDays = 1
faceAmount = 100.0

settlementDays = 1 表示 T+1 結算,而估值日期就是 2020-07-28 這一天。

effectiveDate = ql.Date(10, ql.March, 2020)
terminationDate = ql.Date(10, ql.March, 2030)
tenor = ql.Period(1, ql.Years)
calendar = ql.China(ql.China.IB)
convention = ql.Unadjusted
terminationDateConvention = convention
rule = ql.DateGeneration.Backward
endOfMonth = False

schedule = ql.Schedule(
    effectiveDate,
    terminationDate,
    tenor,
    calendar,
    convention,
    terminationDateConvention,
    rule,
    endOfMonth)

# for s in schedule:
#     print(s)

coupons = ql.DoubleVector(1)
coupons[0] = 3.07 / 100.0
accrualDayCounter = ql.ActualActual(
    ql.ActualActual.Bond, schedule)
paymentConvention = ql.Unadjusted

bond = ql.FixedRateBond(
    settlementDays,
    faceAmount,
    schedule,
    coupons,
    accrualDayCounter,
    paymentConvention)

需要注意的是,日歷采用中國的銀行間市場,遇到假期不調整。

如果像下面一樣,采用基於期限結構的定價引擎,在構造 ActualActual 對象時要附加上債券現金流支付的日期表(Schedule 對象),否則在計算貼現因子的時候可能產生偏差,具體的討論請查看 StackExchange 上的討論:https://quant.stackexchange.com/questions/12707/pricing-a-fixedratebond-in-quantlib-yield-vs-termstructure

上海清算所查詢估值、價格和久期等數據,作為比較基准。

由於使用的是估值,也就是“到期利率”,這隱含要求於一個“水平”(flat)的期限結構,所以使用 FlatForward 類。對於水平的期限結構而言,遠期利率、即期利率和到期利率三者相等。

DiscountingBondEngine 是最常見的債券定價引擎,主要用於現金流的貼現計算。

bondYield = 3.4124 / 100.0

compounding = ql.Compounded
frequency = ql.Annual

termStructure = ql.YieldTermStructureHandle(
    ql.FlatForward(
        settlementDays,
        calendar,
        bondYield,
        accrualDayCounter,
        compounding,
        frequency))

engine = ql.DiscountingBondEngine(termStructure)
bond.setPricingEngine(engine)

價格信息可以通過 FixedRateBond 的成員函數獲得,而久期等指標的計算在 BondFunctions 的內部函數中實現(BondFunctions 的內部函數也可以依據到期利率計算價格信息)。

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, 97.2211])
tab.add_row(['dirty price', dirtyPrice, 98.4071])
tab.add_row(['accrued amount', accruedAmount, 1.1859])
tab.add_row(['duration', duration, 8.0771])
tab.add_row(['convexity', convexity, 79.2206])
tab.add_row(['bps', abs(bps), 0.0795])

tab.float_format = '.4'

print(tab)
+----------------+----------+------------+
|      item      | QuantLib | ShClearing |
+----------------+----------+------------+
|  clean price   | 97.2212  |  97.2211   |
|  dirty price   | 98.4071  |  98.4071   |
| accrued amount |  1.1859  |   1.1859   |
|    duration    |  8.0771  |   8.0771   |
|   convexity    | 79.2206  |  79.2206   |
|      bps       |  0.0795  |   0.0795   |
+----------------+----------+------------+

最終結果和上海清算所公布的幾乎一致。

ok

三種久期

BondFunctionsduration 函數可以計算三種久期,分別是簡單久期(Simple)、麥考利久期(Macaulay)和修正久期(Modified),只需配置久期類型參數即可,默認計算的是修正久期。

程序實現上,麥考利久期的計算依賴於修正久期。

所謂簡單久期,即現金流的期限關於現金流貼現值的加權平均。如果計息方式是復利,簡單久期等於麥考利久期。不過,如果是連續復利,計算麥考利久期將會報錯,簡單久期依然可以計算出來,更有普適性。連續復利的情況下,簡單久期等於修正久期。

durationSimple = ql.BondFunctions.duration(
    bond,
    bondYield,
    accrualDayCounter,
    compounding,
    frequency,
    ql.Duration.Simple)

durationModified = ql.BondFunctions.duration(
    bond,
    bondYield,
    accrualDayCounter,
    compounding,
    frequency,
    ql.Duration.Modified)

durationMacaulay = ql.BondFunctions.duration(
    bond,
    bondYield,
    accrualDayCounter,
    compounding,
    frequency,
    ql.Duration.Macaulay)

tabDuration = pt.PrettyTable(['type', 'value'])
tabDuration.add_row(['Simple', durationSimple])
tabDuration.add_row(['Modified', durationModified])
tabDuration.add_row(['Macaulay', durationMacaulay])

print(tabDuration)
+----------+-------------------+
|   type   |       value       |
+----------+-------------------+
|  Simple  | 8.352745733674992 |
| Modified | 8.077122021802985 |
| Macaulay | 8.352745733674992 |
+----------+-------------------+

擴展閱讀

《QuantLib 金融計算》系列合集


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM