【手把手教你】固定收益和衍生品分析利器QuantLib入门

2023-10-30 21:50

本文主要是介绍【手把手教你】固定收益和衍生品分析利器QuantLib入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

QuantLib是一个专门用于利率、债券与衍生品等金融工具定价分析的库,可以说是固定收益和金融衍生品分析的一个利器。QuantLib本身是使用C++写的,通过SWING技术封装后可以在Python调用。直接使用pip安装可能会报错,建议下载安装包的whl文件,然后再用pip进行安装。

https://www.lfd.uci.edu/~gohlke/pythonlibs/#quantlib (建议收藏,涵盖了Python大部分第三方包),找到与自己电脑和Python相对应的版本下载,如我的电脑是64位,Python3.7,选择第一个下载,将下载的文件放在当前工作目录,然后进入cmd模式(cmd模式下的地址即为当前工作目录),输入:

“pip install QuantLib_Python‑1.11‑cp37‑cp37m‑win_amd64.whl”即可,如果import QuantLib没有报错说明安装成功。

在公众号后台回复“quantlib”可以获取quantilib的使用手册(英文版)

如何查看系统环境、包的版本号和当前工作路径呢?

#先pip安装watermark
#查看系统环境和module的版本号
%load_ext watermark
%watermark
%watermark -p pandas,numpy,QuantLib,matplotlib

输出结果:

#查看当前工作目录
import os
os.getcwd()
#输出结果:
'C:\\Users\\zjy'引入QuantLib包
#引入QuantLib
import QuantLib as ql
QuantLib基础模块:Dates

日期模块Dates包含了Date,Period,Calendar,DayCounter,Schedule,DateGeneration等,是QuantLib的基础模块,包含了时间、日期、日历等的定义、生成和逻辑运算等,是数学建模和量化分析的重要基础。

Date:日期

Date是日期格式,日期范围是1901-01-01至2199-12-31。有三种写法:(1)Date(n),与Excel类似,其中n的范围是367-109574之间的数字(含),其他超出该范围的数字都会报错;(2)Date(day,month,year),即日,月,年的输入格式,其中日和年必须是数字,而月可以是其他格式,如ql.June(相当于输入6)。(3)Date(日期,格式),如:Date('20-09-2020', '%d-%m-%Y')

应用实例:定义日期“2020年11月11日”

d1=ql.Date(11,11,2020)
d2=ql.Date('2020-11-11','%Y-%m-%d')
d3=ql.Date('20201111','%Y%m%d')
d4=ql.Date(44146)
#四种写法等价
print(d1==d2==d3==d4)
#输出结果:True


日期定义与运算

today=ql.Date(11,11,2020)
print('初始日期:', today)
print('ISO格式:', today.ISO())
#返回一周七天对应的数字:注意周日(Sunday)是1,周六(Saturday)是7
print('一周中第几天:', today.weekday())
print('该月的第几天:', today.dayOfMonth())
print('本年的第几天:', today.dayOfYear())
print('月份:', today.month())
print('年份:', today.year())
#相当于第一种写法的逆运算
print('日期数字:', today.serialNumber())

输出结果:
初始日期: November 11th, 2020
ISO格式: 2020-11-11
一周中第几天: 4
该月的第几天: 11
本年的第几天: 316
月份: 11
年份: 2020
日期数字: 44146

#逻辑判断
print(today == ql.Date(12, 11, 2020))
print(today > ql.Date(11, 10, 2020))
print(today < ql.Date(1, 12, 2020))
print(today != ql.Date(11, 9, 2020))

输出结果:False、True、True、True

获取Date内置日期和运算函数

print('当前日期:', ql.Date.todaysDate())
print('系统支持最小日期 :', ql.Date.minDate())
print('系统支持最大日期 :', ql.Date.maxDate())
#判断是否闰年
print('是闰年吗? :', ql.Date.isLeap(2020))
print('该月的最后一天:', ql.Date.endOfMonth(ql.Date(11, ql.November, 2020)))
print('是该月的最后一天吗? :', ql.Date.isEndOfMonth(ql.Date(30, 11, 2020)))
print('该日期的下个星期一 :', ql.Date.nextWeekday(ql.Date(11, 11, 2020), ql.Monday))
print('该月的第2个星期五 :', ql.Date.nthWeekday(2, ql.Friday, 11, 2020))

输出结果:
当前日期: November 11th, 2020
系统支持最小日期 : January 1st, 1901
系统支持最大日期 : December 31st, 2199
是闰年吗?: True
该月的最后一天: November 30th, 2020
是该月的最后一天吗?: True
该日期的下个星期一 : November 16th, 2020
该月的第2个星期五 : November 13th, 2020

Period:周期

Period可以生成日期频数,如多少日(周、月、年)等。主要有三种写法:(1)ql.Period(n, units),其中units可以是日:ql.Days,周:ql.Weeks,月:ql.Months,年:ql.Years。(2)ql.Period(periodString),其中periodString可以是日:'1D',周:'1W',月:'1M'和年:'1Y'。(3)ql.Period(frequency),如每年,ql.Annual。

#一年的等价写法
ql.Period('1Y')==ql.Period(1,ql.Years)==ql.Period(ql.Annual)
#输出结果:True

Period主要是用于Date的运算。

today=ql.Date(11,11,2020)
print(f'{today}三天后是{today+3}')
print(f'{today}前一天是{today-1}')
print(f'{today}下一周是{today+ql.Period(1,ql.Weeks)}')
print(f'{today}下一个月是{today+ql.Period(1,ql.Months)}')
print(f'{today}下一年是{today+ql.Period(1,ql.Years)}')

输出结果:
November 11th, 2020三天后是November 14th, 2020
November 11th, 2020前一天是November 10th, 2020
November 11th, 2020下一周是November 18th, 2020
November 11th, 2020下一个月是December 11th, 2020
November 11th, 2020下一年是November 11th, 2021

Calendar:日历

Date对象没有考虑假期因素,而实际应用中,证券交易需要考虑指定交易所或者国家的假期,Calendar对主要的交易所给出了交易日历,包括:Argentina : [‘Merval’];Brazil : [‘Exchange’,‘Settlement’],Canada : [‘Settlement’, ‘TSX’]、China : [‘IB’, ‘SSE’];CzechRepublic : [‘PSE’],France : [‘Exchange’, ‘Settlement’];Germany : [‘Eurex’, ‘FrankfurtStockExchange’, ‘Settlement’, ‘Xetra’],HongKong : [‘HKEx’],Iceland : [‘ICEX’],India : [‘NSE’],Indonesia : [‘BEJ’, ‘JSX’],Israel : [‘Settlement’, ‘TASE’],Italy : [‘Exchange’, ‘Settlement’],Mexico : [‘BMV’],Russia : [‘MOEX’, ‘Settlement’],SaudiArabia : [‘Tadawul’],Singapore :[‘SGX’],Slovakia : [‘BSSE’],SouthKorea : [‘KRX’, ‘Settlement’],Taiwan : [‘TSEC’],Ukraine : [‘USE’],UnitedKingdom : [‘Exchange’, ‘Metals’, ‘Settlement’];UnitedStates :[‘FederalReserve’,‘GovernmentBond’,‘LiborImpact’, ‘NERC’, ‘NYSE’, ‘Settlement’]

calendar1 = ql.UnitedKingdom(ql.UnitedKingdom.Exchange)
calendar2 = ql.UnitedStates(ql.UnitedStates.NYSE)
calendar3 = ql.China(ql.China.SSE)
day1=ql.Date(1,1,2020)
day2=ql.Date(31,12,2020)
uk_bday=calendar1.businessDaysBetween(day1,day2)
us_bday=calendar2.businessDaysBetween(day1,day2)
ch_bday=calendar3.businessDaysBetween(day1,day2)
print(day1,'至',day2,'之间有',uk_bday,'个英国交易日')
print(day1,'至',day2,'之间有',us_bday,'个美国交易日')
print(day1,'至',day2,'之间有',ch_bday,'个中国交易日')

输出结果:
January 1st, 2020 至 December 31st, 2020 之间有 253 个英国交易日
January 1st, 2020 至 December 31st, 2020 之间有 252 个美国交易日
January 1st, 2020 至 December 31st, 2020 之间有 260 个中国交易日

判断日期类型

cal1 = ql.China()
cal2 = ql.UnitedStates()
mydate = ql.Date(1, 10, 2020)
#判断交易日
print(mydate,'在中国是交易日吗? :', cal1.isBusinessDay(mydate))
print(mydate,'在美国是交易日吗? :', cal2.isBusinessDay(mydate))

输出结果:
October 1st, 2020 在中国是交易日吗?: True
October 1st, 2020 在美国是交易日吗?: True

cal = ql.China()
day1 = ql.Date(11, 11, 2020)
day2 = ql.Date(14, 11, 2020)
print('Is Business Day : ', cal.isBusinessDay(day1))
print('Is Business Day : ', cal.isBusinessDay(day2))
#添加或者移除节假日设定
cal.addHoliday(day1)
cal.removeHoliday(day2)
print('Is Business Day : ', cal.isBusinessDay(day1))
print('Is Business Day : ', cal.isBusinessDay(day2))

输出结果:
Is Business Day : True
Is Business Day : False
Is Business Day : False
Is Business Day : True

不同国家日历日和交易日的区别

date = ql.Date(11, 11, 2020)
us_calendar = ql.UnitedStates()
ch_calendar = ql.China()
raw_date = date + ql.Period(30, ql.Days)
us_date = us_calendar.advance(date, ql.Period(30, ql.Days))
ch_date = ch_calendar.advance(date, ql.Period(30, ql.Days))
print(date,"后推30个日历日:     ", raw_date)
print(date,"后推美国30个交易日: ", us_date)
print(date,"后推中国30个交易日: ", ch_date)

输出结果:
November 11th, 2020 后推30个日历日:December 11th, 2020
November 11th, 2020 后推美国30个交易日:December 24th, 2020
November 11th, 2020 后推中国30个交易日:December 22nd, 2020

DayCounter:天数计算

DayCounter可以统计某两个日期之间的天数,是固定收益类产品估值和分析的重要基础,常用的计数函数包括:

  • Actual360 : Actual / 360,一年按360天

  • Actual365Fixed : Actual / 365(Fixed),一年按365天

  • Standard:标准;Canadian:加拿大;NoLeap:即所有年份都是365天

  • ActualActual : 按每年实际天数

  • ISMA \ Bond\ ISDA\ Historical\ Actual365\ AFB\ Euro

  • Business252 : Business / 252,证券交易日

  • Thirty360 : 30 / 360,按月30天,年360天

  • SimpleDayCounter:简单的日计数

常用的函数有两个:

dayCount(d1,d2):计算 d1,d2 之间的天数

yearFraction(d1, d2):将 d1,d2 之间的天数年化

d1 = ql.Date(1,10,2020)
d2 = ql.Date(11,11,2020)
dc=ql.Business252()
dd=dc.dayCount(d1,d2)
yf=dc.yearFraction(startDate,endDate)
print(f'日历间隔天数:{d2-d1}')
print(f'Business252计算规则天数:{dd}')
print(f'Business252计算规则天数年化:{yf:.4f}')
日历间隔天数:41
Business252计算规则天数:27
Business252计算规则天数年化:0.1071
dayCounters = {'SimpleDayCounter': ql.SimpleDayCounter(),'Thirty360': ql.Thirty360(),'Actual360': ql.Actual360(),'Actual365Fixed': ql.Actual365Fixed(),'Actual365Fixed(Canadian)': ql.Actual365Fixed(ql.Actual365Fixed.Canadian),'Actual365NoLeap': ql.Actual365NoLeap(),'ActualActual': ql.ActualActual(),'Business252': ql.Business252()}
for name,dc in dayCounters.items():dd=dc.dayCount(startDate,endDate)print(name,'计算规则天数',dd)       

输出结果:
SimpleDayCounter 计算规则天数 40
Thirty360 计算规则天数 40
Actual360 计算规则天数 41
Actual365Fixed 计算规则天数 41
Actual365Fixed(Canadian) 计算规则天数 41
Actual365NoLeap 计算规则天数 41
ActualActual 计算规则天数 41
Business252 计算规则天数 27

Schedule:时间表

Schedule(effectiveDate, terminationDate, tenor, calendar, convention, terminationDateConvention, rule, endOfMonth, firstDate=Date(), nextToLastDate=Date()),各变量分别代表:

  • effectiveDate, terminationDate : 日历列表的起始和终止日期, 比如债券的定价和到期日期

  • tenor : Period对象, 两个日期的间隔, 如债券发行频率(1年或6个月)或利率掉期利率(3个月)。

  • calendar : 一个日历表,用于生成要遵循的日期的特定日历。

  • convention : 整数型,如何调整非工作天(最后一天除外),值范围是quantlib-python的一些保留变量。

  • terminationDateConvention : 整数型,如果最后的日期是非工作日,如何调整它,值范围是quantlib-python的一些保留变量。

  • Rule : 日期生成的一个成员,用于为日期生成规则。

  • endOfMonth : 如果开始日期在月底,是否需要在月底安排其他日期(最后日期除外)。

  • firstDate : nextToLastDate(可选):Date,为生成的方法规则提供的开始和结束日期(不常用)。

Schedule对象的行为和list类似,是一种存储Date对象的序列容器。使用len(sch):返回 Schedule 对象sch内日期的个数,[i]:返回第 i 个日期,Schedule对象是可迭代的。

effectiveDate = ql.Date(1,1,2018)
terminationDate = ql.Date(15,6,2020)
frequency = ql.Period('6M')
#默认使用当前系统日期
calendar = ql.TARGET()
convention = ql.ModifiedFollowing
terminationDateConvention = ql.ModifiedFollowing
#Forward是以初始日期向后推算,Backward是以结束日期向前推算
rule = ql.DateGeneration.Forward
endOfMonth = False
mysch = ql.Schedule(effectiveDate, terminationDate, frequency, calendar, convention, terminationDateConvention, rule, endOfMonth)
for i,d in enumerate(mysch):print(i+1,d)

输出结果:
1 January 2nd, 2018
2 July 2nd, 2018
3 January 2nd, 2019
4 July 1st, 2019
5 January 2nd, 2020
6 June 15th, 2020

schedule常用的函数:

  • until(d):从日期列表中截取前半部分,并保证最后一个日期是d。

  • isRegular(i):判断第 i 个区间是否完整。如果一个Schedule对象有 n 个日期,该对象就有 n-1个区间,那么第 i 个区间的长度和事先规定的时间间隔一致,则判断该区间是完整的(Regular)。

mys=mysch.until(ql.Date(15, ql.June, 2019))
for i in range(len(mys)-1):print(mys[i],'至',mys[i+1],'该区间完整吗?',mys.isRegular(i+1))

输出结果:
January 2nd, 2018 至 July 2nd, 2018 该区间完整吗?True
July 2nd, 2018 至 January 2nd, 2019 该区间完整吗?True
January 2nd, 2019 至 June 15th, 2019 该区间完整吗?False

DateGeneration

许多产品的估值依赖于对未来现金流的分析,因此准确地列出未来现金流的日期是至关重要的。在给定开始和结束日期后,可以采用“反向方法”或“正向方法”生成日期列表。

effectiveDate = ql.Date(5,1,2020)
terminationDate = ql.Date(20,4,2020)
frequency = ql.Period('1M')
#默认使用当前系统日期
calendar = ql.TARGET()
convention = ql.ModifiedFollowing
terminationDateConvention = ql.ModifiedFollowing
#Forward是以初始日期向后推算,Backward是以结束日期向前推算endOfMonth = Falserules = {'Backward': ql.DateGeneration.Backward,'Forward': ql.DateGeneration.Forward,'Zero': ql.DateGeneration.Zero,'ThirdWednesDay': ql.DateGeneration.ThirdWednesday,'Twentieth': ql.DateGeneration.Twentieth,'TwentiethIMM': ql.DateGeneration.TwentiethIMM,'CDS': ql.DateGeneration.CDS}for name, rule in rules.items():schedule = ql.Schedule(effectiveDate, terminationDate, frequency, calendar, convention, terminationDateConvention, rule, endOfMonth)print(name, [dt for dt in schedule])

输出结果:

InterestRate:利率类

InterestRate类可用于存储具有复利类型、日计数和复利频率的利率。下面我们将展示如何使用实际日计数惯例(Actual/Actual)创建8.0%复利年利率。

annual_rate = 0.08
day_count = ql.ActualActual()
compound_type = ql.Compounded
frequency = ql.Annual
interest_rate = ql.InterestRate(annual_rate,day_count,compound_type,frequency)

假设你以上述描述的利率投资一美元,利息对象中的复合因子法给出你的投资在任何时期后的价值。下面演示由复合因子返回的2年的值与预期的复利公式是一致的。

t = 2.0
print (interest_rate.compoundFactor(t))
print((1.0+annual_rate)**2) 

输出结果:1.1664  1.1664

discountFactor方法返回复合因子方法的倒数。在计算未来现金流的现值时,折现系数是非常实用的。

print (f'{interest_rate.discountFactor(t):.4f}')
print (f'{1.0/interest_rate.compoundFactor(t):.4f}')

输出结果:0.8573  0.8573

一个给定的利率可以转换为其他的复利类型和复利频率使用相等的中心方法。

compound_type= ql.Compounded
t=2.0
new_frequency = ql.Monthly
new_interest_rate =interest_rate.equivalentRate(compound_type, new_frequency,t)
new_annual_rate = new_interest_rate.rate()
print (f'{new_annual_rate:.4f}')

输出结果:0.0772

两个利率对象(interest_rate和new_interest_rate)的折现因子相同,如下所示。

print (f'{interest_rate.discountFactor(t):.4f}')
print (f'{new_interest_rate.discountFactor(t):.4f}')

输出结果:0.8573    0.8573

结语

QuantLib主要用于固定收益和衍生品的量化分析,内容包罗万象,涵盖的领域也比较广。本文主要介绍了QuantLib的基础模块——Dates日期类和InterestRate利率类。这两个类是后续利率、债券、金融衍生品估值和定价分析的重要基础。后续推文将以专题的形式介绍Quantlib在固定收益分析中的应用案例,敬请期待。

看完记得点赞和在看哦~

参考资料:

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

2. QuantLib官方网上英文教程:https://quantlib-python-docs.readthedocs.io/en/latest/dates.html

关于Python金融量化

专注于分享Python在金融量化领域的应用。加入知识星球,可以免费获取量化投资视频资料、量化金融相关PDF资料、公众号文章Python完整源码、量化投资前沿分析框架,与博主直接交流、结识圈内朋友等。

这篇关于【手把手教你】固定收益和衍生品分析利器QuantLib入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/310802

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

关于MyISAM和InnoDB对比分析

《关于MyISAM和InnoDB对比分析》:本文主要介绍关于MyISAM和InnoDB对比分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录开篇:从交通规则看存储引擎选择理解存储引擎的基本概念技术原理对比1. 事务支持:ACID的守护者2. 锁机制:并发控制的艺