目录python
若是未作特别说明,文中的程序都是 Python3 代码。算法
理论和实践上有多种方法能够构建与市场一致的收益率曲线,背后的方法论取决于市场上的可得到金融工具的流动性。在构建收益率曲线时有两个选项必须选定好:拟合方法和所选的金融工具。bootstrap
quantlib-python 容许构建下列两大类收益率曲线:app
DiscountCurve
,根据贴现因子构建*ZeroCurve
型的收益率曲线,根据债券零息收益率构建(前缀表示具体的构建方法)ForwardCurve
,根据远期收益率构建FixedRateBond
)构建:
Piecewise**
型的收益率曲线,根据若干不一样类型金融工具(存款收益率、收益率远期合约和互换等等)的报价分段构建(后缀表示具体的构建方法和曲线类型)FittedBondDiscountCurve
,根据若干债券的价格构建本文介绍第二种。函数
载入 QuantLib:工具
import QuantLib as ql print(ql.__version__)
1.12
YieldTermStructure
事实上,全部上述类都派生自基类 YieldTermStructure
,该基类实现了一些经常使用的功能。例如,实现了返回基准日期、天数计算规则、日历的函数,以及返回收益率的最小或最大日期的函数。优化
YieldTermStructure
经常使用的成员函数:lua
discount(d, extrapolate = False)
:浮点数,d
是 Date
对象, extrapolate
是布尔型。返回贴现因子大小。zeroRate(d, resultDayCounter, comp, freq = Annual, extrapolate = False)
:InterestRate
,d
是 Date
对象,resultDayCounter
是 DayCounter
对象,comp
和 freq
是预置整数,extrapolate
是布尔型。返回等价的零息收益率对象。forwardRate(d1, d2, dc, comp, freq = Annual, extrapolate = false)
:InterestRate
,d1
和 d2
是 Date
对象,resultDayCounter
是 DayCounter
对象,comp
和 freq
是 quantlib-python 预置整数(表示付息方式和频率),extrapolate
是布尔型。返回 d1
和 d2
之间的远期收益率对象。以货币网 2018-07-23 发布的国债收盘收益率曲线为基准,构造一组样本券:spa
此时,这些样本券肯定的“到期”收益率曲线即为发布的收盘收益率曲线,由于对于每一年付息一次的固息债,全价等于 100 时票息率刚好等于到期收益率。rest
下面,从上述样本券中构造出知足某种限制条件的“即期”收益率曲线。理论上,从新构造出的即期收益率应当与货币网发布的即期收益率很是接近,甚至相等。
期限 | 到期收益率 | 即期收益率 |
---|---|---|
1 | 3.0544 | 3.0544 |
2 | 3.1549 | 3.1565 |
3 | 3.2489 | 3.2531 |
4 | 3.2702 | 3.2744 |
5 | 3.2915 | 3.2964 |
6 | 3.3958 | 3.4092 |
7 | 3.5000 | 3.5237 |
8 | 3.5050 | 3.5264 |
9 | 3.5100 | 3.5298 |
10 | 3.5150 | 3.5337 |
15 | 3.7765 | 3.8517 |
20 | 3.8163 | 3.8884 |
30 | 3.9568 | 4.0943 |
50 | 3.9720 | 4.0720 |
Piecewise**
quantlib-python 提供的若干 Piecewise**
型的收益率曲线意为“分段收益率曲线”,能够根据若干固收类金融工具的报价推算出特按期限的收益率(或贴现因子),进而构建收益率曲线。
分段收益率曲线接受一组不一样期限的固收类金融工具(如固息债、利率互换和远期利率协议等等),根据具体金融工具的贴现方法、期限、价格等等因素拆解(bootstrap)出对应期限的即期收益率(或等价的贴现因子)。再经过某种插值手段——一般是样条插值,构造出与实际即期收益率(或贴现因子)最接近的理论收益率曲线。
Piecewise**
对象的构造PiecewiseLogCubicDiscount
从金融工具报价中拆解出贴现因子,并用对数三次样条插值构建理论贴现因子曲线。其构造函数具备如下实现
PiecewiseLogCubicDiscount(referenceDate, instruments, dayCounter, jumps, jumpDates, accuracy, i)
或
PiecewiseLogCubicDiscount(settlementDays, calendar, instruments, dayCounter, jumps, jumpDates, accuracy, i)
这些变量的类型和解释以下:
referenceDate
:Date
对象,构造曲线的基准日期settlementDays
:整数,结算日天数calendar
:Calendar
对象,市场对应的日历表instruments
:一列 *Helper
类的对象,特定金融工具的辅助类,用于拆解计算。dayCounter
:DayCounter
对象,市场对应的天数计算规则jumps
:一列 RelinkableQuoteHandle
对象,收益率跳跃的幅度,默认是空的jumpDates
:一列 Date
对象,收益率跳跃的日期,默认是空的accuracy
:浮点数,收敛精度,默认是 1e-12i
:MonotonicLogCubic
对象,插值方法,默认是 MonotonicLogCubic()
PiecewiseLogCubicDiscount
经常使用的成员函数均继承自基类 YieldTermStructure
。
PiecewiseLogCubicDiscount
对收益率曲线的形状没有“结构性”的限制,能够很好的拟合实际获得的收益率数据,代价是缺乏理论性的解释能力。
FittedBondDiscountCurve
和 PiecewiseLogCubicDiscount
相反,FittedBondDiscountCurve
对收益率曲线的形状提出了“结构性”的限制,最终拟合曲线的理论解释性更强,曲线也更光滑,但代价是拟合程度会下降。
FittedBondDiscountCurve
的原理FittedBondDiscountCurve
接受一组不一样期限的固息债对象,同时假设理论即期收益率(或贴现因子)知足某种特定的函数形式——一般由几个参数控制。用理论曲线对算出债券的理论价格,寻找最佳参数,使得理论价格和实际价格的距离最小。最佳参数肯定的曲线即是拟合出的理论曲线。
FittedBondDiscountCurve
的构造FittedBondDiscountCurve
从一列固息债对象中拆解出贴现因子,并用要求理论贴现因子曲线知足某种参数形式。其构造函数具备如下实现
FittedBondDiscountCurve(referenceDate, helpers, dayCounter, fittingMethod, accuracy, maxEvaluations, guess, simplexLambda)
或
FittedBondDiscountCurve(settlementDays, calendar, helpers, dayCounter, fittingMethod, accuracy, maxEvaluations, guess, simplexLambda)
这些变量的类型和解释以下:
referenceDate
:Date
对象,构造曲线的基准日期settlementDays
:整数,结算日天数calendar
:Calendar
对象,市场对应的日历表helps
:一列 *Helper
类的对象,固息债的辅助类,用于拆解计算。dayCounter
:DayCounter
对象,市场对应的天数计算规则fittingMethod
:FittingMethod
对象,规定理论曲线的函数形式。accuracy
:浮点数,收敛精度,默认是 1e-10maxEvaluations
:整数,数值优化计算中的最大迭代次数guess
:一列浮点数,数值优化计算的初始参数,默认是空的simplexLambda
:浮点数,单纯型算法中的尺度,默认是 1.0FittedBondDiscountCurve
经常使用的成员函数均继承自基类 YieldTermStructure
。
FittingMethod
类FittingMethod
是一个基类,quantlib-python 具体提供的 FittingMethod
子类有如下几个:
ExponentialSplinesFitting
:指数样条模型,贴现因子的形式为 \(d(t) = \sum_{i=1}^9 c_i \exp^{-\kappa \cdot i \cdot t}\),其中 \(c_i\) 和 \(\kappa\) 是须要肯定的参数。CubicBSplinesFitting
:三次 B-样条模型,贴现因子的形式为一组三次 B-样条 \(N_{i,3}(t)\) 的组合,\(d(t) = \sum_{i=0}^{n} c_i \cdot N_{i,3}(t)\),其中 \(c_i\) 是须要肯定的参数。SimplePolynomialFitting
:简单多项式模型,贴现因子的形式为多项式NelsonSiegelFitting
:Nelson-Siegel 模型,即期收益率的形式为 \(r(t) = c_0 + (c_1 + c_2) \cdot (1 - exp^{-\kappa \cdot t})/(\kappa \cdot t) - c_2 exp^{- \kappa \cdot t}\),其中 \(c_i\) 和 \(\kappa\) 是须要肯定的参数。SvenssonFitting
:Svensson-Nelson-Siegel 模型,即期收益率的形式为 \(r(t) = c_0 + (c_0 + c_1)(\frac {1 - exp^{-\kappa \cdot t}}{\kappa \cdot t}) - c_2exp^{ - \kappa \cdot t} + c_3{(\frac{1 - exp^{-\kappa_1 \cdot t}}{\kappa_1 \cdot t} -exp^{-\kappa_1 \cdot t})}\),其中 \(c_i\)、\(\kappa\) 和 \(\kappa_1\) 是须要肯定的参数。下面分别用 PiecewiseLogCubicDiscount
和 FittedBondDiscountCurve
拟合“问题描述”中构造出的样本券对应的即期收益率曲线,FittedBondDiscountCurve
方法使用 Svensson-Nelson-Siegel 模型。
理论上,PiecewiseLogCubicDiscount
拟合出的曲线应该很是接近货币网发布的即期收益率曲线,极可能是锯齿状的,不光滑的(因为市场的深度和广度有限)。FittedBondDiscountCurve
拟合出的曲线应该很是光滑,而且足够接近货币网发布的曲线。
例子,拟合曲线并输出 Svensson-Nelson-Siegel 模型的参数。
import QuantLib as ql import pandas as pd import seaborn as sb def testingYields3(): maturities = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 50] pars = [0.030544, 0.031549, 0.032489, 0.032702, 0.032915, 0.033958, 0.03500, 0.035050, 0.035100, 0.035150, 0.037765, 0.038163, 0.039568, 0.03972] spots = [0.030544, 0.031565, 0.032531, 0.032744, 0.032964, 0.034092, 0.035237, 0.035264, 0.035298, 0.035337, 0.038517, 0.038884, 0.040943, 0.040720] numberOfBonds = len(maturities) cleanPrice = [100.0] * numberOfBonds quote = [ql.SimpleQuote(c) for c in cleanPrice] quoteHandle = [ql.RelinkableQuoteHandle()] * numberOfBonds for i in range(len(quoteHandle)): quoteHandle[i].linkTo(quote[i]) frequency = ql.Annual dc = ql.ActualActual(ql.ActualActual.ISMA) accrualConvention = ql.ModifiedFollowing convention = ql.ModifiedFollowing redemption = 100.0 calendar = ql.China(ql.China.IB) today = calendar.adjust(ql.Date(23, 7, 2018)) ql.Settings.evaluationDate = today bondSettlementDays = 0 bondSettlementDate = calendar.advance( today, ql.Period(bondSettlementDays, ql.Days)) instruments = [] for j in range(len(maturities)): maturity = calendar.advance( bondSettlementDate, ql.Period(maturities[j], ql.Years)) schedule = ql.Schedule( bondSettlementDate, maturity, ql.Period(frequency), calendar, accrualConvention, accrualConvention, ql.DateGeneration.Backward, False) helper = ql.FixedRateBondHelper( quoteHandle[j], bondSettlementDays, 100.0, schedule, [pars[j]], dc, convention, redemption) instruments.append(helper) tolerance = 1.0e-10 max = 5000 svensson = ql.SvenssonFitting() ts0 = ql.PiecewiseLogCubicDiscount( bondSettlementDate, instruments, dc) ts1 = ql.FittedBondDiscountCurve( bondSettlementDate, instruments, dc, svensson, tolerance, max) spline = [] sv = [] print('{0:>9}{1:>9}{2:>9}{3:>9}'.format( "tenor", "spot", "spline", "svensson")) for i in range(len(instruments)): cfs = instruments[i].bond().cashflows() cfSize = len(instruments[i].bond().cashflows()) tenor = dc.yearFraction(today, cfs[cfSize - 1].date()) print( '{0:9.3f}{1:9.3f}{2:9.3f}{3:9.3f}'.format( tenor, 100.0 * spots[i], 100.0 * ts0.zeroRate(cfs[cfSize - 1].date(), dc, ql.Compounded, frequency).rate(), 100.0 * ts1.zeroRate(cfs[cfSize - 1].date(), dc, ql.Compounded, frequency).rate())) spline.append(ts0.zeroRate(cfs[cfSize - 1].date(), dc, ql.Compounded, frequency).rate()) sv.append(ts1.zeroRate(cfs[cfSize - 1].date(), dc, ql.Compounded, frequency).rate()) df = pd.DataFrame( dict( mat=maturities * 4, rate=pars + spots + spline + sv, type=['par'] * 14 + ['spot'] * 14 + ['spline'] * 14 + ['sv'] * 14)) print(ts1.fitResults().solution()) return df rs = testingYields3() sb.relplot( x='mat', y='rate', kind='line', hue='type', data=rs, height=5, aspect=1.6)
结果以下:
tenor spot spline svensson 1.000 3.054 2.993 3.011 2.000 3.157 3.121 3.104 3.000 3.253 3.226 3.187 4.000 3.274 3.258 3.262 5.000 3.296 3.281 3.330 6.000 3.409 3.393 3.392 7.000 3.524 3.507 3.448 8.000 3.526 3.512 3.499 9.000 3.530 3.517 3.547 10.000 3.534 3.523 3.591 15.000 3.852 3.843 3.771 20.000 3.888 3.877 3.906 30.000 4.094 4.085 4.084 50.000 4.072 4.044 4.025 [ -0.190874; 0.219538; 0.0953552; 0.586634; 0.0896221; 0.0226007 ]
将结果可视化。蓝色线表示到期曲线,橙色线表示即期曲线,绿色线是 PiecewiseLogCubicDiscount
拟合的结果,红色线是 FittedBondDiscountCurve
拟合的 Svensson-Nelson-Siegel 模型,与预期彻底一致。