如果未做特別說明,文中的程序都是 Python3 代碼。
QuantLib 金融計算——基本組件之 Calendar 類
針對相應國家編制一套日歷表用來推算假期、工作日和周末,這對於金融實務來說是一件基礎又非常重要的事。
載入 QuantLib:
import QuantLib as ql
print(ql.__version__)
1.10
Calendar
對象的構造
在 QuantLib 中可以很輕松的構造特定國家的日歷表。例如,通過 myCal = UnitedKingdom()
構造英國的日歷表,其他國家諸如美國、日本、加拿大等等也可以用類似的方式構造。在有些國家,不同的市場遵循不同的日歷表,例如在中國,銀行間市場和交易所市場遵循的日歷表是不一樣的(交易所市場在周六周日一定不開放,不管是否調休)。對於這一問題,可以通過配置特定參數將日歷表細化到具體的市場上,例如中國銀行間市場的日歷表可以通過 myCal = China(China.IB)
構造。China.IB
和 China.SSE
是 quantlib-python 的預留特殊變量,分別表示中國的銀行間市場和交易所市場。
一些常用的成員函數
下面是一些常用的成員函數:
isBusinessDay(d)
:布爾值,判斷d
是不是工作日。isHoliday(d)
:布爾值,判斷d
是不是假期。isWeekend(w)
:布爾值,判斷w
是不是周末(在有些國家,周末沒有安排在周六周日)。isEndOfMonth(d)
:布爾值,判斷d
是不是月末最后一個工作日。endOfMonth(d)
:日期,返回d
所在月的最后一個工作日。
例子 1:
def CalendarTesting1():
chinaCal = ql.China(ql.China.IB)
saudiArabCal = ql.SaudiArabia()
nyEve = ql.Date(3, ql.April, 2017)
print('Is BD :', chinaCal.isBusinessDay(nyEve))
print('Is Holiday :', chinaCal.isHoliday(nyEve))
print('Is Weekend in SA :', saudiArabCal.isWeekend(ql.Friday))
print('Is Weekend in CN :', chinaCal.isWeekend(ql.Friday))
print('Is Last BD :',
chinaCal.isEndOfMonth(ql.Date(5, ql.April, 2018)))
print('Last BD :', chinaCal.endOfMonth(nyEve))
Is BD : False
Is Holiday : True
Is Weekend in SA : True
Is Weekend in CN : False
Is Last BD : False
Last BD : April 28th, 2017
注意,在沙特阿拉伯周五周六是“周末”,這和中國不一樣。
自定義假期列表
QuantLib 對中國市場的支持比較有限,目前的版本假期列表僅僅維護到 2004-2017 年,要想正確推算其他年份的日歷表,用戶需要自行配置假期。QuantLib 中的 Calendar
對象可以方便的實現自定義假期,通常僅僅需要借助下列兩個函數:
addHoliday(d)
:添加d
為假期。removeHoliday(d)
:從假期表中移除d
。
將 2018 年清明節放假調休的安排配置到 Calendar
對象中。
例子 2:
def CalendarTesting2():
chinaCal = ql.China(ql.China.IB)
d1 = ql.Date(5, ql.April, 2018)
d2 = ql.Date(6, ql.April, 2018)
d3 = ql.Date(8, ql.April, 2018)
print('Is Business Day : ', chinaCal.isBusinessDay(d1))
print('Is Business Day : ', chinaCal.isBusinessDay(d2))
print('Is Business Day : ', chinaCal.isBusinessDay(d3))
chinaCal.addHoliday(d1)
chinaCal.addHoliday(d2)
chinaCal.removeHoliday(d3)
print('Is Business Day : ', chinaCal.isBusinessDay(d1))
print('Is Business Day : ', chinaCal.isBusinessDay(d2))
print('Is Business Day : ', chinaCal.isBusinessDay(d3))
Is Business Day : True
Is Business Day : True
Is Business Day : False
Is Business Day : False
Is Business Day : False
Is Business Day : True
工作日修正
將某個日期修正為工作日是一項必要的工作,QuantLib 中支持如下工作日轉換模式:
Following
:將日期修正為之后出現的第一個工作日。ModifiedFollowing
:將日期修正為之后出現的第一個工作日,除非這個工作日出現在次月;如果修正后的工作日出現在次月,就將日期修正為之前出現的最近一個工作日,保證原始日期和修正后的日期處在同一個月。Preceding
:將日期修正為之前出現的最近一個工作日。ModifiedPreceding
:將日期修正為之前出現的最近一個工作日,除非這個工作日出現在上一個月;如果修正后的工作日出現在上一個月,就將日期修正為之后出現的第一個工作日,保證原始日期和修正后的日期處在同一個月。Unadjusted
:不作調整。
Calendar
對象通過下列兩個函數實現修正日期的功能:
adjust(d, convention)
:日期,按照轉換模式convention
修正d
。advance(d, period, convention, endOfMonth)
:日期,將日期date
向后推移時間間隔period
后再按照轉換模式convention
修正;參數endOfMonth
表示,如果d
是月末的話,推移修正后的日期也要是在月末。
最后,可以通過下面的函數計算兩個日期間的工作日個數:
businessDaysBetween(from, to, includeFirst, includeLast)
:計算日期from
和to
之間的工作日個數(是否包括首尾日期)。
例子 3:
def CalendarTesting3():
chinaCal = ql.China(ql.China.IB)
firstDate = ql.Date(31, ql.January, 2018)
secondDate = ql.Date(1, ql.April, 2018)
print('Date 2 Adj :', chinaCal.adjust(secondDate, ql.Preceding))
print('Date 2 Adj :', chinaCal.adjust(secondDate, ql.ModifiedPreceding))
mat = ql.Period(2, ql.Months)
print('Date 1 Month Adv :',
chinaCal.advance(firstDate, mat, ql.Following, False))
print('Date 1 Month Adv :',
chinaCal.advance(firstDate, mat, ql.ModifiedFollowing, False))
print('Business Days Between :',
chinaCal.businessDaysBetween(
ql.Date(5, ql.March, 2018), ql.Date(30, ql.March, 2018),
True, True))
Date 2 Adj : March 30th, 2018
Date 2 Adj : April 2nd, 2018
Date 1 Month Adv : April 2nd, 2018
Date 1 Month Adv : March 30th, 2018
Business Days Between : 20