QuantLib 金融計算——案例之主成分久期(PCD)


QuantLib 金融計算——案例之主成分久期(PCD)

概述

關鍵期限上利率的變動通常有較強的相關性,所以,使用 KRD 天然的存在着“共線性”的隱患。

處理共線性的常見手段是主成分分析(PCA),這也就引出了主成分久期(PCD)的概念——債券價格關於主成分的敏感性。

主成分久期

關於主成分久期的高級內容請見《《Interest Rate Risk Modeling》閱讀筆記——第十章》

主成分是原始變量的線性組合,可以證明 PCD 也是 KRD 的線性組合,因此計算 PCD 需要分三步:

  1. 算出關鍵利率的 KRD;
  2. 對關鍵利率做 PCA;
  3. 根據 KRD 和 PCA 的載荷矩陣(loading)計算 PCD

計算案例

沿用《案例之 KRD、Fisher-Weil 久期及久期的解釋能力》的數據,KRD 的計算略過,直接使用最終結果。

利率變化的主成分分析

需要注意的是,這里不需要對數據做標准化(standardize),否則最終計算 KRD 時要做一次尺度變換。但遵照《Interest Rate Risk Modeling》的做法,最終的主成分因子做了歸一化(normalize)。

import pandas as pd
import statsmodels.api as sm
import seaborn as sns

ratesChg = pd.read_csv(
    'ratesChg.csv', parse_dates=True, index_col='date')
returns = pd.read_csv(
    'returns.csv', parse_dates=True, index_col='date')

pca = sm.PCA(
    ratesChg,
    standardize=False,
    demean=True,
    normalize=True)

print(pca.loadings)

'''
      comp_00   comp_01   comp_02  ...   comp_11   comp_12   comp_13
1D   0.471356  0.877932 -0.060239  ...  0.015957  0.024632  0.006903
6M   0.047785  0.023852  0.897648  ... -0.001783  0.012518 -0.018913
1Y   0.298379 -0.136045  0.227319  ... -0.132121 -0.011556 -0.044387
2Y   0.310444 -0.149192  0.123286  ...  0.645939 -0.030575  0.140874
3Y   0.342030 -0.157388  0.033696  ... -0.385047 -0.121084  0.023274
4Y   0.342225 -0.187096  0.013315  ...  0.023240  0.393166 -0.008804
5Y   0.303104 -0.174121  0.034038  ...  0.066626 -0.031194 -0.094945
6Y   0.266243 -0.131857 -0.053863  ... -0.499595 -0.316239 -0.183736
7Y   0.224635 -0.120262 -0.054711  ...  0.102571 -0.247733  0.106077
8Y   0.218911 -0.138575 -0.168238  ... -0.150574  0.655571 -0.091769
9Y   0.217848 -0.115892 -0.188426  ...  0.132909 -0.470151  0.134931
10Y  0.136793 -0.117408 -0.208336  ...  0.180370  0.058729  0.088273
15Y  0.135273 -0.106458 -0.087883  ...  0.259897 -0.024268 -0.592554
20Y  0.102095 -0.090580 -0.020611  ... -0.106187  0.108275  0.733208
'''

下面計算一下每個成分因子對回報率的解釋能力。

R2 = pd.DataFrame(
    data=[sm.OLS(endog=returns, exog=pca.factors.iloc[:, i]).fit().rsquared for i in range(pca._ncomp)],
    index=pca.loadings.columns)

print(R2)

'''
comp_00  0.442932
comp_01  0.098024
comp_02  0.039253
comp_03  0.129587
comp_04  0.035543
comp_05  0.036428
comp_06  0.055197
comp_07  0.000370
comp_08  0.045802
comp_09  0.000013
comp_10  0.004617
comp_11  0.000724
comp_12  0.018448
comp_13  0.000376
'''

上一篇中構造的水平因子的解釋能力大約是 50%,而前四個主成分因子的解釋能力大約能達到 70%(0.7 = 0.442932 + 0.098024 + 0.039253 + 0.129587)。

pcReg = sm.OLS(
    endog=returns, exog=pca.factors).fit()

# print(pcReg.summary())

idx = [0, 1, 2, 3, 4, 5, 6, 8, 10, 12]

pcReg = sm.OLS(
    endog=returns, exog=pca.factors.iloc[:, idx]).fit()

print(pcReg.summary())

'''
                                 OLS Regression Results                                
=======================================================================================
Dep. Variable:                 return   R-squared (uncentered):                   0.906
Model:                            OLS   Adj. R-squared (uncentered):              0.902
Method:                 Least Squares   F-statistic:                              228.9
Date:                Wed, 18 Nov 2020   Prob (F-statistic):                   4.81e-116
Time:                        15:22:48   Log-Likelihood:                          1424.0
No. Observations:                 248   AIC:                                     -2828.
Df Residuals:                     238   BIC:                                     -2793.
Df Model:                          10                                                  
Covariance Type:            nonrobust                                                  
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
comp_00       -0.0265      0.001    -33.458      0.000      -0.028      -0.025
comp_01        0.0125      0.001     15.740      0.000       0.011       0.014
comp_02        0.0079      0.001      9.960      0.000       0.006       0.009
comp_03       -0.0143      0.001    -18.097      0.000      -0.016      -0.013
comp_04       -0.0075      0.001     -9.478      0.000      -0.009      -0.006
comp_05        0.0076      0.001      9.595      0.000       0.006       0.009
comp_06        0.0094      0.001     11.811      0.000       0.008       0.011
comp_08       -0.0085      0.001    -10.759      0.000      -0.010      -0.007
comp_10       -0.0027      0.001     -3.416      0.001      -0.004      -0.001
comp_12        0.0054      0.001      6.828      0.000       0.004       0.007
==============================================================================
Omnibus:                      130.528   Durbin-Watson:                   1.924
Prob(Omnibus):                  0.000   Jarque-Bera (JB):             7723.672
Skew:                          -1.214   Prob(JB):                         0.00
'''

從所有主成分因子中篩選掉少數不顯著的因子,總的解釋能力已達到了 90%。

計算 PCD

根據這里的推導,PCD 向量等於 KRD 向量與載荷矩陣的乘積。

計算 PCD 時有一個的問題需要注意,即載荷向量(載荷矩陣的某列)元素的符號。單純從 PCA 的角度來看,載荷向量元素的符號不構成一個問題,如果 \(l\) 是載荷向量,\(-l\) 也能充當載荷向量。但是元素的符號為載荷向量賦予經濟含義,具體到利率期限結構的分析來說,通常約定

  • 水平因子(h)對應的向量所有元素都必須為正;
  • 斜率因子(s)對應的向量在短期限一端為負,在長期限一端為正;
  • 曲率因子(c)對應的向量在中間期限為正,在兩端為負。

因此,計算 PCD 之前需要調整載荷向量的符號。

krd = pd.DataFrame(
    data=[
        -0.00273973, 0.01761345, 0.02607589, 0.06751827, 0.09790298,
        0.12608806, 0.15196510, 0.17540198, 0.19649419, 3.12947679,
        3.35232738, 0.00000000, 0.00000000, 0.00000000],
    index=pca.loadings.index,
    columns=['KRD'])

hsc = pca.loadings[['comp_00','comp_01','comp_03']]
hsc.columns = ['h','s','c']

# print(hsc)

hsc.loc[:,'s'] = -hsc.loc[:,'s']
hsc.loc[:,'c'] = -hsc.loc[:,'c']

print(hsc)

hsc.plot(marker='o')

'''
            h         s         c
1D   0.471356 -0.877932 -0.027072
6M   0.047785 -0.023852 -0.426987
1Y   0.298379  0.136045  0.416754
2Y   0.310444  0.149192  0.261607
3Y   0.342030  0.157388  0.222109
4Y   0.342225  0.187096  0.086126
5Y   0.303104  0.174121  0.047247
6Y   0.266243  0.131857 -0.176602
7Y   0.224635  0.120262 -0.063345
8Y   0.218911  0.138575 -0.288706
9Y   0.217848  0.115892 -0.352268
10Y  0.136793  0.117408 -0.506713
15Y  0.135273  0.106458 -0.108318
20Y  0.102095  0.090580 -0.068624
'''

因子的選擇其實見仁見智,綜合考慮曲線的形狀和解釋能力,第四個主成分因子更適合做曲率因子。

pcd = (hsc * krd.values).sum()

print(pcd)

pcdNormalize = pcd * np.sqrt(pca.eigenvals[0:3]).values

print(pcdNormalize)

'''
h    1.657201
s    0.950000
c   -2.066973

h    0.026187
s    0.012167
c   -0.013483
'''

pcd 是債券關於主成分因子的敏感性,pcdNormalize 是債券關於歸一化后主成分的敏感性(和書中的約定一樣),可以看出 pcdNormalize 的值和回歸系數大體保持一致(注意到符號的轉換)。

第一主成分和上一篇的水平因子經濟含義相似,但當前得到的 pcd 的值和上一篇中的 Fisher-Weil 久期相去甚遠,這主要是因為主成分因子做了尺度縮放。對於水平因子來說,消除尺度縮放

pcd['h'] * pca.loadings['comp_00'].sum()
# 5.662857296706285

這樣第一主成分就變成了利率變動的加權平均,結果與 Fisher-Weil 久期的值接近,且數量級保持一致。

擴展閱讀

《QuantLib 金融計算》系列合集


免責聲明!

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



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