日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

QuantLib 金融计算——案例之固息债的关键利率久期(KRD)

發(fā)布時(shí)間:2023/12/13 综合教程 37 生活家
生活随笔 收集整理的這篇文章主要介紹了 QuantLib 金融计算——案例之固息债的关键利率久期(KRD) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄QuantLib 金融計(jì)算——案例之固息債的關(guān)鍵利率久期(KRD)概述關(guān)鍵利率久期的基本概念從擾動(dòng)的角度計(jì)算 KRD計(jì)算案例Quote 類和引用帶來的便利參考文獻(xiàn)擴(kuò)展閱讀

QuantLib 金融計(jì)算——案例之固息債的關(guān)鍵利率久期(KRD)

概述

作為利率風(fēng)險(xiǎn)系列的第二篇,本文將以《Interest Rate Risk Modeling》為藍(lán)本,介紹關(guān)鍵利率久期(KRD)的基本概念,并依托 QuantLib 展示相關(guān)的計(jì)算案例。

有關(guān) KRD 的高級(jí)內(nèi)容請(qǐng)見《《Interest Rate Risk Modeling》閱讀筆記——第九章》。

關(guān)鍵利率久期的基本概念

上一篇《案例之固息債的價(jià)格、久期、凸性和 BPS》中出現(xiàn)的久期和凸性均是基于到期利率(YTM)的風(fēng)險(xiǎn)度量指標(biāo)。使用 YTM 分析債券隱含了一個(gè)重要假設(shè):利率期限結(jié)構(gòu)上各期限的利率同步變化。這個(gè)隱含的假設(shè)與現(xiàn)實(shí)有所出入,盡管期限結(jié)構(gòu)上各期限的利率變化高度相關(guān),但并非 100% 一致。顯然,傳統(tǒng)的久期無法描述債券價(jià)格對(duì)期限結(jié)構(gòu)非平行變化的敏感性。

若要更精細(xì)地刻畫債券關(guān)于利率變化的敏感性,需要分別考慮不同期限上利率變化對(duì)債券價(jià)格的影響,這要求把期限結(jié)構(gòu)本身作為一個(gè)動(dòng)態(tài)變量。

一個(gè)期限結(jié)構(gòu)其實(shí)可以看做是一個(gè)無限維的向量,任意一個(gè)期限均是一個(gè)維度。考慮一個(gè)無限維的向量是一個(gè)高深的數(shù)學(xué)問題,然而基于經(jīng)驗(yàn)觀察,期限結(jié)構(gòu)的平滑性相當(dāng)好,所以只需要選取幾個(gè)特殊期限作為“錨點(diǎn)”,實(shí)踐中就可以幾乎完全把握整個(gè)曲線的變化。

關(guān)鍵利率久期(KRD)就是債券價(jià)格關(guān)于這些錨點(diǎn)期限上利率的敏感性,一組 KRD 也就描述了債券價(jià)格對(duì)期限結(jié)構(gòu)非平行變化的敏感性。

從擾動(dòng)的角度計(jì)算 KRD

假設(shè)根據(jù)當(dāng)前期限結(jié)構(gòu)算出來的債券價(jià)格是 (P),此時(shí)某個(gè)關(guān)鍵期限 (K) 上的利率出現(xiàn)了一個(gè)微小的擾動(dòng) (Delta y),擾動(dòng)出現(xiàn)后重新計(jì)算出的債券價(jià)格是 (P^{prime}),那么債券價(jià)格關(guān)于 (K) 期限利率的敏感性就近似是

[frac{P^{prime} - P}{P imes Delta y}
]

也可以采用精度更高的近似方法,正負(fù)擾動(dòng)對(duì)應(yīng)的價(jià)格分別是 (P^{+}) 和 (P^{-}),敏感性近似是

[frac{P^{+} - P^{-}}{2 P imes Delta y}
]

為保證期限結(jié)構(gòu)的平滑性,擾動(dòng)不能只影響一個(gè)特定期限,其影響要平滑地?cái)U(kuò)散到臨近的期限。在 KRD 分析中,要求擾動(dòng)以線性遞減的形式擴(kuò)展到左右相鄰的期限,而不會(huì)影響相距更遠(yuǎn)的期限。例如,選定 5、7、10 年三個(gè)相鄰期限,7 年期上 1 bp 的擾動(dòng)只能影響到 5 和 10 年期。并且,7-5 年之間,擾動(dòng)以每年 0.5 bp 的速度遞減,7-10 年之間,擾動(dòng)以每年 1/3 bp 的速度遞減。

計(jì)算案例

繼續(xù)以上一篇《案例之固息債的價(jià)格、久期、凸性和 BPS》中出現(xiàn)的 200205 為例,計(jì)算 2020-07-28 這一天的久期和 KRD。

首先從中國貨幣網(wǎng)查詢債券的基本信息,用以配置 FixedRateBond 對(duì)象。

債券起息日:2020-03-10
到期兌付日:2030-03-10
債券期限:10 年
面值(元):100.00
計(jì)息基準(zhǔn):A/A
息票類型:附息式固定利率
付息頻率:年
票面利率(%):3.0700
結(jié)算方式:T+1

import QuantLib as ql
import prettytable as pt
import seaborn as sns

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

settlementDays = 1
faceAmount = 100.0

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)

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)

在上海清算所查詢估值。由于使用的是估值,也就是到期利率,所以當(dāng)前的期限結(jié)構(gòu)用 FlatForward 類表示。對(duì)于水平的期限結(jié)構(gòu)而言,遠(yuǎn)期利率、即期利率和到期利率三者相等。

bondYield = 3.4124 / 100.0

compounding = ql.Compounded
frequency = ql.Annual

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

計(jì)算 KRD 的時(shí)候需要向當(dāng)前的期限結(jié)構(gòu)添加關(guān)鍵期限上的擾動(dòng),為此可以借助 QuantLib 中的 InterpolatedPiecewiseZeroSpreadedTermStructure 類模板,它需要一個(gè)模板參數(shù) Interpolator,表示所使用的插值方法類。對(duì)于 KRD 的計(jì)算來說,選擇 Linear 作為模板參數(shù),以表示線性插值。

要配置實(shí)例化后的類 InterpolatedPiecewiseZeroSpreadedTermStructure<Linear>,需要提供三個(gè)核心參數(shù):

一個(gè) Handle<YieldTermStructure> 對(duì)象,也就是當(dāng)前的期限結(jié)構(gòu),關(guān)鍵期限上的擾動(dòng)將被施加在此期限結(jié)構(gòu)上;
一列 Handle<Quote> 對(duì)象,表示關(guān)鍵期限上的利率擾動(dòng);
一列 Date 對(duì)象,表示擾動(dòng)對(duì)應(yīng)的關(guān)鍵期限。

具體到 python 環(huán)境下,實(shí)例化后的類 InterpolatedPiecewiseZeroSpreadedTermStructure<Linear> 被包裝并重命名為 SpreadedLinearZeroInterpolatedTermStructure 類。

在計(jì)算 KRD 之前,所有擾動(dòng)的初始值被設(shè)置成零。關(guān)鍵期限有 11 個(gè),分別是 6 個(gè)月和 1~10 年,均勻地覆蓋每個(gè)付息周期。

initValue = 0.0
rate6m = ql.SimpleQuote(initValue)
rate1y = ql.SimpleQuote(initValue)
rate2y = ql.SimpleQuote(initValue)
rate3y = ql.SimpleQuote(initValue)
rate4y = ql.SimpleQuote(initValue)
rate5y = ql.SimpleQuote(initValue)
rate6y = ql.SimpleQuote(initValue)
rate7y = ql.SimpleQuote(initValue)
rate8y = ql.SimpleQuote(initValue)
rate9y = ql.SimpleQuote(initValue)
rate10y = ql.SimpleQuote(initValue)

rate6mHandle = ql.QuoteHandle(rate6m)
rate1yHandle = ql.QuoteHandle(rate1y)
rate2yHandle = ql.QuoteHandle(rate2y)
rate3yHandle = ql.QuoteHandle(rate3y)
rate4yHandle = ql.QuoteHandle(rate4y)
rate5yHandle = ql.QuoteHandle(rate5y)
rate6yHandle = ql.QuoteHandle(rate6y)
rate7yHandle = ql.QuoteHandle(rate7y)
rate8yHandle = ql.QuoteHandle(rate8y)
rate9yHandle = ql.QuoteHandle(rate9y)
rate10yHandle = ql.QuoteHandle(rate10y)

spreads = ql.QuoteHandleVector()
spreads.append(rate6mHandle)
spreads.append(rate1yHandle)
spreads.append(rate2yHandle)
spreads.append(rate3yHandle)
spreads.append(rate4yHandle)
spreads.append(rate5yHandle)
spreads.append(rate6yHandle)
spreads.append(rate7yHandle)
spreads.append(rate8yHandle)
spreads.append(rate9yHandle)
spreads.append(rate10yHandle)

dates = ql.DateVector()
dates.append(flatCurve.referenceDate() + ql.Period(6, ql.Months))
dates.append(flatCurve.referenceDate() + ql.Period(1, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(2, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(3, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(4, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(5, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(6, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(7, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(8, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(9, ql.Years))
dates.append(flatCurve.referenceDate() + ql.Period(10, ql.Years))

termStructure = ql.YieldTermStructureHandle(
    ql.SpreadedLinearZeroInterpolatedTermStructure(
        flatCurve,
        spreads,
        dates,
        compounding,
        frequency,
        accrualDayCounter))

債券定價(jià)引擎采用最常見的 DiscountingBondEngine

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

Quote 類和引用帶來的便利

在底層 C++ 代碼中,QuantLib 類的構(gòu)造函數(shù)和成員函數(shù)大量使用了常引用參數(shù)和觀察者模式,這使得作為參數(shù)的對(duì)象具有了“穿透性”,參數(shù)對(duì)象值的改變可以靠引用和觀察者模式串聯(lián)起來的鏈條影響關(guān)聯(lián)的所有其他對(duì)象。

具體到 KRD 的計(jì)算,無需重新配置定價(jià)引擎,只要改變關(guān)鍵利率的值就可以自動(dòng)觸發(fā)債券的計(jì)算。

擾動(dòng)的大小定為 1 bp,調(diào)用成員方法 setValue 便可改變 SimpleQuote 對(duì)象的值。

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


tab = pt.PrettyTable(['item', 'value'])
tab.add_row(['duration', duration])

# calculate KRDs

bp = 0.01 / 100.0
krdSum = 0.0
krds = []
times = []

# 6m KRD
rate6m.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate6m.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate6m.setValue(initValue)
krd6m = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd6m
krds.append(krd6m)
times.append(0.5)

tab.add_row(['krd6m', krd6m])

# 1y KRD
rate1y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate1y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate1y.setValue(initValue)
krd1y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd1y
krds.append(krd1y)
times.append(1.0)

tab.add_row(['krd1y', krd1y])

# 2y KRD
rate2y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate2y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate2y.setValue(initValue)
krd2y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd2y
krds.append(krd2y)
times.append(2.0)

tab.add_row(['krd2y', krd2y])

# 3y KRD
rate3y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate3y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate3y.setValue(initValue)
krd3y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd3y
krds.append(krd3y)
times.append(3.0)

tab.add_row(['krd3y', krd3y])

# 4y KRD
rate4y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate4y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate4y.setValue(initValue)
krd4y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd4y
krds.append(krd4y)
times.append(4.0)

tab.add_row(['krd4y', krd4y])

# 5y KRD
rate5y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate5y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate5y.setValue(initValue)
krd5y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd5y
krds.append(krd5y)
times.append(5.0)

tab.add_row(['krd5y', krd5y])

# 6y KRD
rate6y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate6y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate6y.setValue(initValue)
krd6y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd6y
krds.append(krd6y)
times.append(6.0)

tab.add_row(['krd6y', krd6y])

# 7y KRD
rate7y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate7y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate7y.setValue(initValue)
krd7y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd7y
krds.append(krd7y)
times.append(7.0)

tab.add_row(['krd7y', krd7y])

# 8y KRD
rate8y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate8y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate8y.setValue(initValue)
krd8y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd8y
krds.append(krd8y)
times.append(8.0)

tab.add_row(['krd8y', krd8y])

# 9y KRD
rate9y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate9y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate9y.setValue(initValue)
krd9y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd9y
krds.append(krd9y)
times.append(9.0)

tab.add_row(['krd9y', krd9y])

# 10y KRD
rate10y.setValue(bp)
dirtyPrice1 = bond.dirtyPrice()
rate10y.setValue(-bp)
dirtyPrice2 = bond.dirtyPrice()
rate10y.setValue(initValue)
krd10y = -(dirtyPrice1 - dirtyPrice2) / (2.0 * bp * dirtyPrice)
krdSum += krd10y
krds.append(krd10y)
times.append(10.0)

tab.add_row(['krd10y', krd10y])

tab.add_row(['krdSum', krdSum])

tab.float_format = '.8'

print(tab)
+----------+------------+
|   item   |   value    |
+----------+------------+
| duration | 8.07712202 |
|  krd6m   | 0.01412836 |
|  krd1y   | 0.02182248 |
|  krd2y   | 0.05615594 |
|  krd3y   | 0.08163788 |
|  krd4y   | 0.10535800 |
|  krd5y   | 0.12735475 |
|  krd6y   | 0.14771823 |
|  krd7y   | 0.16683071 |
|  krd8y   | 0.18443629 |
|  krd9y   | 0.11944279 |
|  krd10y  | 7.05223796 |
|  krdSum  | 8.07712340 |
+----------+------------+

從結(jié)果上看 KRD 有兩個(gè)局部高點(diǎn),一個(gè)是接近久期的關(guān)鍵期限(8 年),另一個(gè)是接近剩余期限(也就是現(xiàn)金流最大的時(shí)期)的關(guān)鍵期限(10 年)。

理論上,各個(gè) KRD 之和約等于修正久期,這是因?yàn)楦鱾€(gè)關(guān)鍵期限上同時(shí)發(fā)生擾動(dòng)的話就相當(dāng)于曲線發(fā)生了平行移動(dòng)。數(shù)值結(jié)果正好驗(yàn)證了這一點(diǎn)。

KRD 的曲線圖是這樣的:

sns.pointplot(
    x=times, y=krds, markers='o')

參考文獻(xiàn)

《Interest Rate Risk Modeling》
楊筱燕,《關(guān)鍵利率久期計(jì)算及實(shí)例分析》

擴(kuò)展閱讀

《QuantLib 金融計(jì)算》系列合集

總結(jié)

以上是生活随笔為你收集整理的QuantLib 金融计算——案例之固息债的关键利率久期(KRD)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。