日期与惯例
约定
复利计算
ql.Simple
ql.Compounded
ql.Continuous
ql.SimpleThenCompounded
ql.CompoundedThenSimple
频率
ql.NoFrequency : 无利息;
ql.Once : 仅支付一次利息,常见于零息债券;
ql.Annual : 每年支付一次利息;
ql.Semiannual : 半年期利息,每半年支付一次;
ql.EveryFourthMonth : 每4个月;
ql.Quarterly : 季度 quarterly;
ql.Bimonthly : 每两个月支付一次利息;
ql.Monthly : 按月支付利息;
ql.EveryFourthWeek : 每4周;
ql.Biweekly : 每两周支付一次的利息;
ql.Weekly : 每周支付一次;
ql.Daily : 每天支付一次利息。
工作日调整
ql.Following : 日期将调整为下一个工作日。
ql.ModifiedFollowing : 日期会被调整至之后的第一个工作日,除非该工作日落在下个月;如果调整后的工作日属于下个月,则日期会被修正为之前的最后一个工作日,以确保原始日期与修正后的日期处于同一个月。
ql.Preceding : 将日期修正为前一个工作日。
ql.ModifiedPreceding : 将日期修改为之前最后一个工作日,除非调整后的工作日已属于上个月;如果调整后的工作日确实属于上个月,则将日期修改为原日期之后的第一个工作日。确保原日期和调整后的日期始终处于同一个月。
ql.Unadjusted : 不做调整。
日期生成
许多产品的估值依赖于对未来现金流的分析,因此准确生成未来现金流的日期列表至关重要。 在给定开始和结束日期后,可以以"反向法"或"正向法"的方式生成日期列表。
示例:
从开始日期2020年7月5日到结束日期2020年8月15日的月度周期:
start = ql.Date(7,5,2020)
end = ql.Date(15,8,2020)
rules = {
'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.MakeSchedule(start, end, ql.Period('1m'), rule=rule)
print(name, [dt for dt in schedule])
日期
构造函数
- ql.Date(serialNumber)
serialNumber是一个整数,例如24214,1对应1899-12-31。其用法与Excel中相同。(serialNumber的范围限制在367至109574之间,对应的日期范围为1901-01-01至2199-12-31。)
ql.Date(44000)
- ql.Date(day, month, year)
其中day和year是整数;month可以是整数或quantlib-python中专门用于表示月份的特定对象(ql.January(等于1),...,ql.December(等于12))
ql.Date(18, 6, 2020)
ql.Date(18, ql.June, 2020)
- ql.Date(dateString, formatString)
ql.Date('18-06-2020', '%d-%m-%Y')
成员函数
ISO
weekday() : 返回对应星期数的整数值: - 星期日: 1 - … - 星期六: 7
dayOfMonth() : integer, 返回的日期是该月的第几天
dayOfYear() : integer, 返回的日期是该年中的第几天
month() : 返回一个整数,表示日期对应的月份
year() : 返回一个整数,表示日期对应的年份
serialNumber() integer, 返回日期对应的天数(从1899-12-31开始计算)
print('Original Date:', today)
print('ISO format:', today.ISO())
print('Weekday:', today.weekday())
print('Day of Month:', today.dayOfMonth())
print('Day of Year:', today.dayOfYear())
print('Month:', today.month())
print('Year:', today.year())
print('Serial Number:', today.serialNumber())
静态函数
Date.todaysDate() : Date对象,返回系统的当前日期。
Date.minDate() : Date对象,返回QuantLib能表示的最小日期。
Date.maxDate() : Date对象,返回QuantLib能表示的最大日期。
Date.isLeap(y) : 布尔值,用于判断y是否为闰年
Date.endOfMonth(d) : 返回日期对象,该对象对应于日期d所在月份的最后一天
Date.isEndOfMonth(d) : 布尔值,用于判断d是否为月末日期
Date.nextWeekday(d, w) : 日期对象,返回日期d之后第一个星期w对应的日期(例如2018-03-12之后的第一个星期五)
Date.nthWeekday(n, w, m, y) : 日期对象,返回给定月份m和年份y中第n周w对应的日期(例如,2010年7月的第三个星期三)
print('Today :', ql.Date.todaysDate())
print('Min Date :', ql.Date.minDate())
print('Max Date :', ql.Date.maxDate())
print('Is Leap :', ql.Date.isLeap(2011))
print('End of Month :', ql.Date.endOfMonth(ql.Date(4, ql.August, 2009)))
print('Is Month End :', ql.Date.isEndOfMonth(ql.Date(29, ql.September, 2009)))
print('Is Month End :', ql.Date.isEndOfMonth(ql.Date(30, ql.September, 2009)))
print('Next WD :', ql.Date.nextWeekday(ql.Date(1, ql.September, 2009), ql.Friday))
print('n-th WD :', ql.Date.nthWeekday(3, ql.Wednesday, ql.September, 2009))
周期
- ql.Period(n, units)
ql.Period(1, ql.Days)
- ql.Period(periodString)
ql.Period('1d')
- ql.Period(frequency)
ql.Period(ql.Annual)
日历
ql.Calendar 类提供了判断某个日期在特定交易所或国家是否为工作日或假日的接口,以及将日期增加/减少指定数量工作日的功能。
可用日历
阿根廷, 澳大利亚, 奥地利, 定制日历, 博茨瓦纳, 巴西, 加拿大, 中国, 捷克共和国, 丹麦, 芬兰, 法国, 德国, 香港, 匈牙利, 冰岛, 印度, 印度尼西亚, 以色列, 意大利, 日本, 联合日历, 墨西哥, 新西兰, 挪威, 空日历, 波兰, 罗马尼亚, 俄罗斯, 沙特阿拉伯, 新加坡, 斯洛伐克, 南非, 韩国, 瑞典, 瑞士, 台湾, 目标日历, 泰国, 土耳其, 乌克兰, 英国, 美国, 仅周末
calendar1 = ql.UnitedKingdom()
calendar2 = ql.TARGET()
日历市场
calendar1 = ql.UnitedKingdom(ql.UnitedKingdom.Metals)
calendar2 = ql.UnitedStates(ql.UnitedStates.NYSE)
一些常用的成员函数:
isBusinessDay(d) : 一个布尔值,用于判断d是否为工作日。
isHoliday(d) : 一个布尔值,用于判断d是否为节假日。
isWeekend(w) : 一个布尔值,用于判断w是否为周末(在某些国家,周末不一定安排在周六和周日)。
isEndOfMonth(d) : 一个布尔值,用于判断d是否为该月最后一个工作日。
endOfMonth(d) : date, 返回日期d所在月份的最后工作日。
cal = ql.TARGET()
mydate = ql.Date(1, ql.May, 2017)
print('Is BD :', cal.isBusinessDay(mydate))
print('Is Holiday :', cal.isHoliday(mydate))
print('Is Weekend :', cal.isWeekend(ql.Friday))
print('Is Last BD :', cal.isEndOfMonth(ql.Date(5, ql.April, 2018)))
print('Last BD :', cal.endOfMonth(mydate))
自定义节假日列表
QuantLib中的Calendar对象可以方便地实现自定义节假日。通常只需要以下两个函数:
addHoliday(d) : 将d添加为假期。
removeHoliday(d) : 从节假日表中移除d。
cal = ql.TARGET()
day1 = ql.Date(26, 2, 2020)
day2 = ql.Date(10, 4, 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))
myCalendar = ql.WeekendsOnly()
days = [1,14,15,1,21,26,2,16,15,18,19,9,27,1,19,8,17,25,31]
months = [1,4,4,5,5,6,8,9,9,10,10,11,12,12,12,12]
name = ['Año Nuevo','Viernes Santo','Sabado Santo','Dia del Trabajo','Dia de las Glorias Navales','San Pedro y San Pablo','Elecciones Primarias','Dia de la Virgen del Carmen','Asuncion de la Virgen','Independencia Nacional','Glorias del Ejercito','Encuentro de dos mundos','Día de las Iglesias Evangélicas y Protestantes','Día de todos los Santos','Elecciones Presidenciales y Parlamentarias','Inmaculada Concepción','Segunda vuelta Presidenciales','Navidad','Feriado Bancario']
start_year = 2018
n_years = 10
for i in range(n_years+1):
for x,y in zip(days,months):
date = ql.Date(x,y,start_year+i)
myCalendar.addHoliday(date)
节假日列表
返回两个日期之间的节假日。
- ql.Calendar.holidayList(calendar, from, to, includeWeekEnds=False)
ql.Calendar.holidayList(ql.TARGET(), ql.Date(1,12,2019), ql.Date(31,12,2019))
Calendar对象使用以下两个函数来修改日期:
adjust(d, convention) : 日期, 根据惯例转换模式修改d。
advance(d, period, convention, endOfMonth) : date,将日期按时间间隔period向后移动,然后根据转换模式convention进行调整;参数endOfMonth表示如果d是月末日期,则调整后的日期也应为月末。
最后,可以使用以下函数计算两天之间的工作日天数:
businessDaysBetween(from, to, includeFirst, includeLast) : 计算从from日期到to日期之间的工作日数量(无论是否包含这两个日期)。
cal = ql.TARGET()
firstDate = ql.Date(31, ql.January, 2018)
secondDate = ql.Date(1, ql.April, 2018)
print('Date 2 Adj :', cal.adjust(secondDate, ql.Preceding))
print('Date 2 Adj :', cal.adjust(secondDate, ql.ModifiedPreceding))
mat = ql.Period(2, ql.Months)
print('Date 1 Month Adv :',
cal.advance(firstDate, mat, ql.Following, False))
print('Date 1 Month Adv :',
cal.advance(firstDate, mat, ql.ModifiedFollowing, False))
print('Business Days Between :',
cal.businessDaysBetween(
ql.Date(5, ql.March, 2018), ql.Date(30, ql.March, 2018),
True, True))
联合日历
- ql.JointCalendar(calendar1, calendar2, calendar3, calendar4, JointCalendarRule=JoinHolidays)
joint_calendar = ql.JointCalendar(ql.TARGET(), ql.Poland())
DayCounter
https://www.isda.org/a/pIJEE/The-Actual-Actual-Day-Count-Fraction-1999.pdf
"日计数惯例"对于金融产品的估值至关重要,特别是固定收益产品。QuantLib提供以下常见规则:
Actual360 : 实际天数/360天
Actual365Fixed : 实际天数 / 365(固定)
标准
加拿大
无闰日
ActualActual : 实际天数/实际天数
国际证券市场协会
债券
国际掉期与衍生品协会(ISDA)
历史数据
实际天数/365
AFB
欧元
Business252 : 工作日 / 252
Thirty360 : 30天/360天
美国
债券基差
欧式
欧洲债券基差
- - Italian
德语
国际证券市场协会(ISMA)
国际掉期与衍生品协会(ISDA)
- NASD - SimpleDayCounter
dayCounters = {
'SimpleDayCounter': ql.SimpleDayCounter(),
'Thirty360': ql.Thirty360(ql.Thirty360.ISDA),
'Actual360': ql.Actual360(),
'Actual365Fixed': ql.Actual365Fixed(),
'Actual365Fixed(Canadian)': ql.Actual365Fixed(ql.Actual365Fixed.Canadian),
'Actual365FixedNoLeap': ql.Actual365Fixed(ql.Actual365Fixed.NoLeap),
'ActualActual': ql.ActualActual(ql.ActualActual.ISDA),
'Business252': ql.Business252()
}
startDate = ql.Date(15,5,2015)
endDate = ql.Date(15,6,2015)
r = 0.05
nominal = 100e6
for name, dc in dayCounters.items():
amount = ql.FixedRateCoupon(endDate, nominal, r, dc, startDate, endDate).amount()
print(name, f"{amount:,.2f}")
时间表
- Schedule(effectiveDate, terminationDate, tenor, calendar, convention, terminationDateConvention, rule, endOfMonth, firstDate=Date(), nextToLastDate=Date())
这些变量的类型和说明如下:
effectiveDate, terminationDate : Date, 日历列表的开始和结束日期,例如债券的起息日和到期日。
tenor : Period对象,表示两个相邻日期之间的间隔,例如债券付息频率(1年或6个月)或利率互换利率(3个月)。
calendar : 一个日历表,用于生成遵循特定规则的日期日历。
convention : 整数,表示如何调整非工作日(最后日期除外),取值范围是quantlib-python的一些保留变量。
terminationDateConvention : Integer, 如果最后一天是非工作日,如何调整它,取值范围是quantlib-python的一些保留变量。
规则 : DateGeneration 的一个成员,用于生成日期的规则。
endOfMonth : 如果起始日期是月末,是否要求其他日期也安排在月末(最后一个日期除外)。
firstDate : nextToLastDate (可选): Date, 为生成的方法规则提供的开始和结束日期(不常用)。
effectiveDate = ql.Date(15,6,2020)
terminationDate = ql.Date(15,6,2022)
frequency = ql.Period('6M')
calendar = ql.TARGET()
convention = ql.ModifiedFollowing
terminationDateConvention = ql.ModifiedFollowing
rule = ql.DateGeneration.Backward
endOfMonth = False
schedule = ql.Schedule(effectiveDate, terminationDate, frequency, calendar, convention, terminationDateConvention, rule, endOfMonth)
MakeSchedule
- ql.MakeSchedule(effectiveDate, terminationDate, frequency)
可选参数:
calendar=None
convention=None
terminalDateConvention=None,
规则=无
forwards=False
backwards=False,
endOfMonth=None
firstDate=None
nextToLastDate=None
effectiveDate = ql.Date(15,6,2020)
terminationDate = ql.Date(15,6,2022)
frequency = ql.Period('6M')
schedule = ql.MakeSchedule(effectiveDate, terminationDate, frequency)
时间网格
- ql.TimeGrid(end, steps)
t = ql.TimeGrid(10, 5)
t.dt(4)
如果有某些时间点需要出现在TimeGrid中,请将它们以列表形式传入
- ql.TimeGrid(requiredTimes, steps)
[t for t in ql.TimeGrid([1, 2.5, 4], 10)]