如果未做特别说明,文中的程序都是 Python3 代码。

2019-08-08 更新:修复代码中的错误

QuantLib 金融计算——收益率曲线之构建曲线(2)

理论和实践上有多种方法可以构建与市场一致的收益率曲线,背后的方法论取决于市场上的可获得金融工具的流动性。在构建收益率曲线时有两个选项必须选定好:拟合方法和所选的金融工具。

quantlib-python 允许构建下列两大类收益率曲线:

  • 第一类,根据数值和对应日期构建:

    • DiscountCurve,根据贴现因子构建
    • 若干 *ZeroCurve 型的收益率曲线,根据债券零息收益率构建(前缀表示具体的构建方法)
    • ForwardCurve,根据远期收益率构建
  • 第二类,根据若干固定收益类对象(如 FixedRateBond)构建:
    • 若干 Piecewise** 型的收益率曲线,根据若干不同类型金融工具(存款收益率、收益率远期合约和互换等等)的报价分段构建(后缀表示具体的构建方法和曲线类型)
    • FittedBondDiscountCurve,根据若干债券的价格构建

本文介绍第二种。

载入 QuantLib:

import QuantLib as ql

print(ql.__version__)
1.12

YieldTermStructure

事实上,所有上述类都派生自基类 YieldTermStructure,该基类实现了一些常用的功能。例如,实现了返回基准日期、天数计算规则、日历的函数,以及返回收益率的最小或最大日期的函数。

YieldTermStructure 常用的成员函数:

  • discount(d, extrapolate = False):浮点数,dDate 对象, extrapolate 是布尔型。返回贴现因子大小。
  • zeroRate(d, resultDayCounter, comp, freq = Annual, extrapolate = False)InterestRatedDate 对象,resultDayCounterDayCounter 对象,compfreq 是预置整数,extrapolate 是布尔型。返回等价的零息收益率对象。
  • forwardRate(d1, d2, dc, comp, freq = Annual, extrapolate = false)InterestRated1d2Date 对象,resultDayCounterDayCounter 对象,compfreq 是 quantlib-python 预置整数(表示付息方式和频率),extrapolate 是布尔型。返回 d1d2 之间的远期收益率对象。

问题描述

以货币网 2018-07-23 发布的国债收盘收益率曲线为基准,构造一组样本券:

  • 样本券的期限分别为收益率曲线的关键期限,如 1、5、15 年等;
  • 样本券的付息频率为每年付息一次;
  • 样本券的票息率为对应期限的到期收益率;
  • 样本券的当前价格为 100 元

此时,这些样本券确定的“到期”收益率曲线即为发布的收盘收益率曲线,因为对于每年付息一次的固息债,全价等于 100 时票息率恰好等于到期收益率。

下面,从上述样本券中构造出满足某种限制条件的“即期”收益率曲线。理论上,重新构造出的即期收益率应当与货币网发布的即期收益率非常接近,甚至相等。

期限 到期收益率 即期收益率
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)

这些变量的类型和解释如下:

  • referenceDateDate 对象,构造曲线的基准日期
  • settlementDays:整数,结算日天数
  • calendarCalendar 对象,市场对应的日历表
  • instruments:一列 *Helper 类的对象,特定金融工具的辅助类,用于拆解计算。
  • dayCounterDayCounter 对象,市场对应的天数计算规则
  • jumps:一列 RelinkableQuoteHandle 对象,收益率跳跃的幅度,默认是空的
  • jumpDates:一列 Date 对象,收益率跳跃的日期,默认是空的
  • accuracy:浮点数,收敛精度,默认是 1e-12
  • iMonotonicLogCubic 对象,插值方法,默认是 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)

这些变量的类型和解释如下:

  • referenceDateDate 对象,构造曲线的基准日期
  • settlementDays:整数,结算日天数
  • calendarCalendar 对象,市场对应的日历表
  • helps:一列 *Helper 类的对象,固息债的辅助类,用于拆解计算。
  • dayCounterDayCounter 对象,市场对应的天数计算规则
  • fittingMethodFittingMethod 对象,规定理论曲线的函数形式。
  • accuracy:浮点数,收敛精度,默认是 1e-10
  • maxEvaluations:整数,数值优化计算中的最大迭代次数
  • guess:一列浮点数,数值优化计算的初始参数,默认是空的
  • simplexLambda:浮点数,单纯型算法中的尺度,默认是 1.0

FittedBondDiscountCurve 常用的成员函数均继承自基类 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_1 + c_2)(\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\) 是需要确定的参数。

拟合曲线

下面分别用 PiecewiseLogCubicDiscountFittedBondDiscountCurve 拟合“问题描述”中构造出的样本券对应的即期收益率曲线,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.QuoteHandle()] * numberOfBonds
# for i in range(len(quoteHandle)):
# quoteHandle[i].linkTo(quote[i])
quoteHandle = [ql.QuoteHandle(q) for q in quote] 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
ql.Settings.instance().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 3.054 3.075
2.000 3.157 3.156 3.149
3.000 3.253 3.253 3.218
4.000 3.274 3.280 3.283
5.000 3.296 3.298 3.345
6.000 3.409 3.409 3.403
7.000 3.524 3.523 3.458
8.000 3.526 3.526 3.510
9.000 3.530 3.530 3.558
10.000 3.534 3.535 3.604
15.000 3.852 3.854 3.793
20.000 3.888 3.886 3.925
30.000 4.094 4.092 4.067
50.000 4.072 4.049 4.061
[ -0.00407737; 0.0336154; -0.00836815; 0.0408907; 0.00186543; 0.0397046 ]

将结果可视化。蓝色线表示到期曲线,橙色线表示即期曲线,绿色线是 PiecewiseLogCubicDiscount 拟合的结果,红色线是 FittedBondDiscountCurve 拟合的 Svensson-Nelson-Siegel 模型,与预期完全一致。

QuantLib 金融计算——收益率曲线之构建曲线(2)的更多相关文章

  1. QuantLib 金融计算——收益率曲线之构建曲线(1)

    目录 QuantLib 金融计算--收益率曲线之构建曲线(1) YieldTermStructure DiscountCurve DiscountCurve 对象的构造 ZeroCurve ZeroC ...

  2. QuantLib 金融计算——收益率曲线之构建曲线(3)

    目录 QuantLib 金融计算--收益率曲线之构建曲线(3) 概述 估算期限结构的步骤 读取样本券数据 一些基本配置 配置 *Helper 对象 配置期限结构 估算期限结构 汇总结果 当前实现存在的 ...

  3. QuantLib 金融计算——收益率曲线之构建曲线(4)

    [TOC] 如果未做特别说明,文中的程序都是 C++11 代码. QuantLib 金融计算--收益率曲线之构建曲线(4) 本文代码对应的 QuantLib 版本是 1.15.相关源代码可以在 Qua ...

  4. QuantLib 金融计算——收益率曲线之构建曲线(5)

    目录 QuantLib 金融计算--收益率曲线之构建曲线(5) 概述 Nelson-Siegel 模型家族的成员 Nelson-Siegel 模型 Svensson 模型 修正 Svensson 模型 ...

  5. QuantLib 金融计算

    我的微信:xuruilong100 <Implementing QuantLib>译后记 QuantLib 金融计算 QuantLib 入门 基本组件之 Date 类 基本组件之 Cale ...

  6. QuantLib 金融计算——自己动手封装 Python 接口(1)

    目录 QuantLib 金融计算--自己动手封装 Python 接口(1) 概述 QuantLib 如何封装 Python 接口? 自己封装 Python 接口 封装 Array 和 Matrix 类 ...

  7. QuantLib 金融计算——自己动手封装 Python 接口(2)

    目录 QuantLib 金融计算--自己动手封装 Python 接口(2) 概述 如何封装一项复杂功能? 寻找最小功能集合的策略 实践 估计期限结构参数 修改官方接口文件 下一步的计划 QuantLi ...

  8. QuantLib 金融计算——数学工具之插值

    目录 QuantLib 金融计算--数学工具之插值 概述 一维插值方法 二维插值方法 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之插值 载入模块 ...

  9. QuantLib 金融计算——高级话题之模拟跳扩散过程

    目录 QuantLib 金融计算--高级话题之模拟跳扩散过程 跳扩散过程 模拟算法 面临的问题 "脏"的方法 "干净"的方法 实现 示例 参考文献 如果未做特别 ...

随机推荐

  1. Linux下删除文件系统空间不释放的问题

    删除了Linux下的一个文件,但是系统空间并没有被释放. 如下:/home/hadmin/data/hadoop 使用了1.3T的空间,但是实际只使用了600多G 原因是我删除了一个600多G的文件, ...

  2. 关于Android控件EditText的属性InputType的一些经验,java组合多个参数

    关于Android控件EditText的属性InputType的一些经验 2013-11-14 15:08:02|  分类: 默认分类|举报|字号 订阅       1.InputType属性在代码中 ...

  3. 实战:MySQL Sending data导致查询很慢的问题详细分析(转)

    出处:http://blog.csdn.net/yunhua_lee/article/details/8573621 这两天帮忙定位一个MySQL查询很慢的问题,定位过程综合各种方法.理论.工具,很有 ...

  4. linux数据库备份

    linux数据库备份 服务端启用二进制日志 如果日志没有启开,必须启用binlog,要重启mysql,首先,关闭mysql,打开/etc/my.cnf,加入以下几行: [mysqld] log-bin ...

  5. 23 DesignPatterns学习笔记:C++语言实现 --- 2.7 Proxy

    23 DesignPatterns学习笔记:C++语言实现 --- 2.7 Proxy 2016-07-18 (www.cnblogs.com/icmzn) 模式理解

  6. VS中的Debug 和 Release 编译方式的本质区别

    VS中的Debug 和 Release 编译方式的本质区别 Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序.Release 称为发布版本,它往往是进行了各种优化,使 ...

  7. FORM 错误:此责任无可用函数。 更改责任或与您的系统管理员联系。

    错误:此责任无可用函数. 更改责任或与您的系统管理员联系. 2014-07-02 12:20:47 分类: Oracle Symptom 访问Help->Diagnostics->Exam ...

  8. NETSH.EXE操作SSL

    NETSH.EXE操作SSL 程序位置:c:\windows\syswow64\netsh.exe 查看当前端口配置 netsh http show sslcert 将 SSL 证书绑定至端口号 ne ...

  9. 咏南中间件+开发框架支持最新的DELPHI 10.2 TOKYO

    咏南中间件+开发框架支持最新的DELPHI 10.2 TOKYO 价格十分优惠.有意者请向本人索取演示程序! 你只需花一套中间件的价格,就可获得:中间件,CS开发框架一套(赠送),BS开发框架一套(赠 ...

  10. SQL Server创建表超出行最大限制解决方法

    问题的现象在创建表A的时候,出现“信息 511,级别 16,状态 1,第 5 行  无法创建大小为 的行,该值大于允许的最大值 8060.”的信息提示.很奇怪,网上查了一下,是因为要插入表的数据类型的 ...