龙空技术网

「手把手教你」使用QuantLib进行债券估值和期权定价分析

Python金融量化 563

前言:

此刻看官们对“bs公式d1 d2”都比较关注,兄弟们都需要了解一些“bs公式d1 d2”的相关内容。那么小编也在网上汇集了一些对于“bs公式d1 d2””的相关知识,希望小伙伴们能喜欢,咱们快快来了解一下吧!

01 引言

QuantLib是固定收益和金融衍生品分析的一大利器,为量化金融建模提供了完整的分析框架,但是由于本身使用C++编写,通过SWING技术封装后在Python调用,各种类(class)之间的调用非常庞杂和繁琐,又很难查看其源代码,所以学习起来相对困难。公众号通过参考官方学习文档,分享QuantLib系列学习笔记。《【手把手教你】固定收益和衍生品分析利器QuantLib入门》主要介绍了QuantLib入门的基础模块Dates日期和InterestRate利率类的基本概念和应用,本文在此基础上,简要介绍QuantLib的金融工具和定价引擎(黑盒子的调用方法),以固定利率债券和普通期权为例,演示了如何利用QuantLib对金融工具进行定价分析。

02 金融工具与定价引擎概览

QuantLib是基于欧美成熟金融市场开发的大型金融产品定价分析框架,其涵盖的金融工具(Instruments)主要分为四类:固定收益(Fixed Income)、期权(Option)、信贷(Credit)和通胀(Inflation)。每一个大类又包含了多个金融工具或衍生品,比如固定收益产品包括远期(Forward)、债券(Bonds)和互换(Swaps)等。QuantLib使用金融工具的英文全称来构建该金融工具的类(函数),比如远期利率互换,在QuantLib框架中使用ql.ForwardRateAgreement(参数)来调用,具体参数设置可以参考:QuantLib金融工具链接地址()。

构建完金融合约(即Instruments)后,进入下一步的定价引擎(Pricing Engine),可以理解为使用哪个定价模型对该金融工具进行建模。根据金融工具的类别,定价引擎主要分为六大类,包括:Bond Pricing Engines(债券定价)、Cap Pricing Engines(价格上限定价法)、Swap Pricing Engines(互换定价法)、Swaption Pricing Engines(掉期期权定价法)、Credit Pricing Engines(信贷定价法)和Option Pricing Engines(期权定价法)。

其调用方法也是以金融工具的英文全称加参数,比如债券里最常用的贴现定价模型:ql.DiscountingBondEngine(discountCurve)。

关于各个定价引擎的具体参数和调用方式可以参照:定价引擎链接地址

()。

03 金融工具定价应用实例

实例1:固定利率债券定价

直接借用《QuantLib Python Cookbook》上的例子:

假设有一种债券,票面价值为100,年息6%,于2015年1月15日发行,2016年1月15日到期。该债券将于2015年7月15日和2016年1月15日支付息票。100的票面金额也会在2016年1月15日支付。

为了简化问题,假设已经知道2015年1月15日美国国债的即期汇率,年化即期汇率为6个月0.5%,1年0.7%,计算该债券的公允价值。

根据贴现公式直接使用Python进行计算:

import QuantLib as ql#定义当前日期(本例子是2015年1月15日)todaysDate = ql.Date(15, 1, 2015)#将评估日设定为当前日期ql.Settings.instance().evaluationDate = todaysDate#即期利率对应日期spotDates = [ql.Date(15, 1, 2015), ql.Date(15, 7, 2015), ql.Date(15, 1, 2016)]#即期利率,初始设定为0spotRates = [0.0, 0.005, 0.007]#天数计数规则dayCount = ql.Thirty360()#例子是美国国债,因此设定为美国日历calendar = ql.UnitedStates()#插值方法为线性interpolation = ql.Linear()#计息方式为复利compounding = ql.Compounded#计息频率为年compoundingFrequency = ql.Annual#即期利率假设满足零息债券收益率曲线spotCurve = ql.ZeroCurve(spotDates, spotRates, dayCount, calendar, interpolation,                             compounding, compoundingFrequency)#利率的期限结构spotCurveHandle = ql.YieldTermStructureHandle(spotCurve)
#输出结果:债券定价为:105.2765

使用QuantLib的债券定价引擎计算

import QuantLib as ql#定义当前日期(本例子是2015年1月15日)todaysDate = ql.Date(15, 1, 2015)#将评估日设定为当前日期ql.Settings.instance().evaluationDate = todaysDate#即期利率对应日期spotDates = [ql.Date(15, 1, 2015), ql.Date(15, 7, 2015), ql.Date(15, 1, 2016)]#即期利率,初始设定为0spotRates = [0.0, 0.005, 0.007]#天数计数规则dayCount = ql.Thirty360()#例子是美国国债,因此设定为美国日历calendar = ql.UnitedStates()#插值方法为线性interpolation = ql.Linear()#计息方式为复利compounding = ql.Compounded#计息频率为年compoundingFrequency = ql.Annual#即期利率假设满足零息债券收益率曲线spotCurve = ql.ZeroCurve(spotDates, spotRates, dayCount, calendar, interpolation,                             compounding, compoundingFrequency)#利率的期限结构spotCurveHandle = ql.YieldTermStructureHandle(spotCurve)

上述操作创建了期限结构,接下来构建固定利率债券。

#发行日期issueDate = ql.Date(15, 1, 2015)#到期日期maturityDate = ql.Date(15, 1, 2016)#付息期限tenor = ql.Period(ql.Semiannual)#日历calendar = ql.UnitedStates()#遇到假期的调整情况bussinessConvention = ql.Unadjusted#日期的生成规则(向后推)dateGeneration = ql.DateGeneration.Backward#是否月最后一日monthEnd = False#生成时间表schedule = ql.Schedule (issueDate, maturityDate, tenor, calendar, bussinessConvention,                            bussinessConvention , dateGeneration, monthEnd)print(list(schedule))
[Date(15,1,2015), Date(15,7,2015), Date(15,1,2016)]
#息票率dayCount = ql.Thirty360()couponRate = .06coupons = [couponRate]#构建固定利率债券settlementDays = 0faceValue = 100fixedRateBond = ql.FixedRateBond(settlementDays, faceValue, schedule, coupons, dayCount)# 以期限结构作为输入值,创建债券定价引擎# 使用贴现模型进行估值bondEngine = ql.DiscountingBondEngine(spotCurveHandle)fixedRateBond.setPricingEngine(bondEngine)# 债券估值print(f'固定利率债券估值为:{fixedRateBond.NPV():.4f}')
#输出结果:固定利率债券估值为:105.2765

得出的结果与使用Python直接套用公式计算是一致的,但过程明显复杂很多,调用了QuantLib的各种类(class),该过程可以作为其他固定收益工具定价的参考模板。

实例2:普通期权定价

以一个欧式看涨期权为例,标的资产价格为100,执行价格假定为100,无风险利率为5%,波动率为0.20,估值日为2020年11月18日,到期日为2021年11月18日。

使用Black-Scholes模型直接计算

模型公式为:

其中,St、K、T、r、σ分别为标的资产价格、执行价格、期限、无风险利率和波动率。根据上述公式和已知参数可以很容易计算普通欧式期权的价格。

# 基于Black - Scholes 公式的期权定价公式from math import log, sqrt, expfrom scipy.stats import normdef BSM(S0, E, T, r, sigma):    d1 = (log(S0/E) + (r + 0.5 * sigma**2) * T) / sigma / sqrt(T)    d2 = d1 - sigma * sqrt(T)    Callprice = S0 * norm.cdf(d1) - E * exp(-r*T) * norm.cdf(d2)    #Putprice=-S0*norm.cdf(-d1)+E*exp(-r*T)*norm.cdf(-d2)    print("看涨期权价格: %.4f" % Callprice)    #print("看跌期权价格: %.4f" % Putprice)
#参数S0=100.0E=100.0T=1.0r=0.05sigma=0.20BSM(S0, E, T, r, sigma)
看涨期权价格: 10.4506使用QuantLib进行计算

使用QuantLib进行计算

#设定全局估值日today = ql.Date(18, 11, 2020)ql.Settings.instance().evaluationDate = today#构建期权#普通看涨期权payoff=ql.PlainVanillaPayoff(ql.Option.Call, 100.0)#到期日期europeanExercise=ql.EuropeanExercise(ql.Date(18, 11, 2021))option = ql.EuropeanOption(payoff, europeanExercise)
#输入参数——标的资产价格,无风险利率,标的资产波动率u = ql.SimpleQuote(100.0)      #标的资产价值r = ql.SimpleQuote(0.05)       #无风险利率sigma = ql.SimpleQuote(0.20)    #波动率
#假定无风险利率和波动率曲线是平的riskFreeCurve = ql.FlatForward(0, ql.TARGET(), ql.QuoteHandle(r), ql.Actual360())volatility = ql.BlackConstantVol(0, ql.TARGET(), ql.QuoteHandle(sigma), ql.Actual360())
#初始化BS过程,并构造engineprocess = ql.BlackScholesProcess(ql.QuoteHandle(u),                              ql.YieldTermStructureHandle(riskFreeCurve),                              ql.BlackVolTermStructureHandle(volatility))engine = ql.AnalyticEuropeanEngine(process)#对期权设定该engineoption.setPricingEngine(engine)print(f'看涨期权的当前价值为:{option.NPV():.4f}')

看涨期权的当前价值为:10.5395。得到的结果与上面直接使用BS公式计算结果基本上一致,当然QuantLib的过程也是更加复杂和繁琐,而且无法看到背后计算的逻辑(公式)。QuantLib构建完Instruments(这里是期权option)和设置定价引擎(Prcing Engines)后,除了可以获取价格(NPV),还有很多扩展功能,包括计算期权的希腊字母(即期权价格关于标的价格、时间、波动率等的变化率衡量指标)。

#计算期权的希腊字母print("%-12s: %4.4f" %("Delta", option.delta() ))print("%-12s: %4.4f" %("Gamma", option.gamma() ))print("%-12s: %4.4f" %("Theta", option.vega()))
Delta       : 0.6377Gamma       : 0.0186Theta       : 37.7516

如果对上面一些参数(如标的资产价值,无风险利率等)做出修改,engine会自动重新计算期权的价值。

#如果当前标的资产的价值为105#以看涨期权为例payoff=ql.PlainVanillaPayoff(ql.Option.Call, 100.0)option = ql.EuropeanOption(payoff, europeanExercise)option.setPricingEngine(engine)u.setValue(105.0)print(f'看涨期权的当前价值为:{option.NPV():.4f}')
看涨期权的当前价值为:13.9496
#也可以同时改变多个参数u.setValue(98.0)r.setValue(0.04)sigma.setValue(0.25)print(f'看涨期权的当前价值为:{option.NPV():.4f}')
看涨期权的当前价值为:10.7357
import numpy as npimport matplotlib.pyplot as plt%matplotlib inline   plt.style.use('ggplot')#正常显示画图时出现的中文和负号from pylab import mplmpl.rcParams['font.sans-serif']=['SimHei']mpl.rcParams['axes.unicode_minus']=False
#不断改变当前标的资产的价值,可以查看其对期权价值的影响f, ax = plt.subplots(figsize=(10,6))X = np.linspace(80.0, 120.0, 400)cv = []for i in X:    u.setValue(i)    cv.append(option.NPV())ax.set_title('期权价值——标的资产价值')_ = ax.plot(X, cv,linewidth=2)plt.show()
#修改估值日期ql.Settings.instance().evaluationDate = ql.Date(18, 6, 2021)print(f'看涨期权的当前价值为:{option.NPV():.4f}')
看涨期权的当前价值为:22.6307
#不同估值日期对比y = []for i in X:    u.setValue(i)    y.append(option.NPV())plt.figure(figsize=(10,6))plt.plot(X, y, '--',linewidth=2,color='b',label='估值日:2021.6.18')plt.plot(X,cv,linewidth=2,color='r',label='估值日:2020.11.18')plt.legend()plt.title('不同估值日下期权价值-标的资产价值',size=15)plt.show()

图中显示,对于同一个到期日的欧式期权(2021年11月18日到期),站在202年6月18日进行估值,相比于2020年11月18日,期权价值是整体下降的。从上述分析可知,在计算期权价格时,直接使用BS公式可以简洁的得出结果,而QuantLib的定价引擎就像个黑箱子,但是其扩展功能较多,可以通过改变定价方法、相关参数等快速对期权进行重新定价。

04 结语

本文主要介绍了QuantLib的金融工具和定价引擎的基本构成,同时以固定利率债券和普通期权定价为例,为大家展示了如何使用QuantLib对金融工具进行定价,其他不同种类的金融工具的定价过程与此相似。QuantLib的整个定价过程看起来是非常繁琐和庞杂的,就像一个黑夹子,但仔细分析又是有迹可循的,其遵循的定价框架围绕金融工程的思想,通过构建金融工具或合约,选择某个定价引擎进行分析建模。QuantLib框架涵盖的内容实在太多,而可供参考的文档又非常有限,因此要深入的学习还是有一定困难的。这里再推荐一个由QuantLib作者Luigi Ballabio写的一本书 《Implementing QuantLib》。

参考资料:

1. Luigi Ballabio and Goutham Balaraman,2017,《QuantLib Python Cookbook》.

2. QuantLib官方网上英文教程:

标签: #bs公式d1 d2