前言
在使用 QuantLib Python建構金融商品或是利率衍生商品現金流時,Date、Calendar 與 Schedule 是最基本且重要的元件。這些元件看似簡單,實際上在處理展期邏輯、畸零天期(odd dates)與地區性假日時,扮演著重要的角色。
本文將從實務角度出發,說明這三個元件的用途、彼此關係,以及在 Schedule 展開時需要注意的細節。
Date:金融計算的基礎單位
QuantLib Python的 Date 類別代表一個單一的金融日期,它具備以下幾個常見操作:
日期初始化與指定全域日期變數:
import QuantLib as ql
today = ql.Date(18, ql.April, 2025) # or ql.Date(18, 4, 2025)
ql.Settings.instance().evaluationDate = today
print(f'Today is {today}')
Today is April 18th, 2025常見操作還包括加減天數、判斷月份等:
date1 = today + 30 # add 30 days
print(date1.ISO()) # use ISO() function, date output format: YYYY-MM-DD
date2 = today + ql.Period(3, ql.Months) # add 3 Month
print(date2.ISO())
days = date2 - date1 # days between date1 and date2
print(f"days between {date1.ISO()} and {date2.ISO()} is {days}")
print(f"Month of {date2.ISO()} is {date2.month()}")
2025-05-18
2025-07-18
days between 2025-05-18 and 2025-07-18 is 61
Month of 2025-07-18 is 7
Calendar:處理假期與日期調整規則
Calendar 是用來處理不同市場或地區的假期與週末定義,以及判斷日期是否為營業日或假日。這在生成 Schedule 或調整支付日等邏輯時非常重要,下面示範Calendar物件的宣告以及常用方式:
# define US calendar.
us_calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond)
# check if today is business-day based on US calendar
isbusdate = us_calendar.isBusinessDay(today)
# 2025/4/18 is US Good Friday, so it's not business day.
print(f"the date {today.ISO()} is business day: {isbusdate}")
# find next business day.
next_bus_day = us_calendar.adjust(today, ql.Following)
print(f"the next business day is {next_bus_day.ISO()}")
# calculate how many business days between date1 and date2
bus_days = us_calendar.businessDaysBetween(date1, date2)
print(f"the business days between {date1.ISO()} and {date2.ISO()} is {bus_days}")
# use TW calendar as example to demo addHoliday function
tw_calendar = ql.Taiwan(ql.Taiwan.TSEC)
Qingming_date = ql.Date(4, 4, 2025)
print(f"the date {Qingming_date.ISO()} is business day: {tw_calendar.isBusinessDay(Qingming_date)}")
# add Qingming to TW holidays
tw_calendar.addHoliday(Qingming_date)
print(f"the date {Qingming_date.ISO()} is business day: {tw_calendar.isBusinessDay(Qingming_date)}")
the date 2025-04-18 is business day: False
the next business day is 2025-04-21
the business days between 2025-05-18 and 2025-07-18 is 41
the date 2025-04-04 is business day: True
the date 2025-04-04 is business day: False
QuantLib Python提供了各地市場的 Calendar,如 TARGET()、UnitedStates(), Taiwan()等。另外要注意的是,在初始這些Calendar物件時,也要給定對應的市場資訊,例如Taiwan calendar,初始化參數要給定ql.Taiwan.TESC才會正確喔!
Composite Calendar:結合多地市場假期邏輯
在跨市場的商品設計中,常會遇到需要同時考慮多個市場的營業日(例如 USD/TWD 外匯交易,必須考慮美國與台灣是否皆為營業日)。QuantLib 提供了 JointCalendar 來結合多個 Calendar,可支援以下兩種模式:
a. Intersection(交集模式)
只有當所有市場都是營業日時,才視為營業日。
# use JointCalendar - JoinHolidays
print(f"Qingming is a business day in TW: {tw_calendar.isBusinessDay(Qingming_date)}")
print(f"Qingming is a business day in US: {us_calendar.isBusinessDay(Qingming_date)}")
composite = ql.JointCalendar(tw_calendar, us_calendar, ql.JoinHolidays)
print(f"Qingming is a business day in both the US and TW: {composite.isBusinessDay(Qingming_date)}")
Qingming is a business day in TW: False
Qingming is a business day in US: True
Qingming is a business day in both the US and TW: False
b. Union(聯集模式)
只要任一市場是營業日,就視為營業日,較少用於 Schedule。
# use JointCalendar - JoinBusinessDays
composite2 = ql.JointCalendar(tw_calendar, us_calendar, ql.JoinBusinessDays)
print(f"Qingming is a business day in both the US and TW: {composite2.isBusinessDay(Qingming_date)}")
Qingming is a business day in both the US and TW: True實務上,金融商品交易通常是使用交集模式,避免遇到一邊休市、一邊支付的問題。
Schedule:生成現金流或利率交換的日期序列
Schedule 是用來建立一組根據一定規則產生的日期序列,通常用在利率交換、債券、或其他固定收益商品上。
基本建立方式
# generate schedule by DateGeneration.Forward
start_date = ql.Date(18, 4, 2024)
end_date = ql.Date(18, 4, 2026)
schedule = ql.Schedule(
start_date,
end_date,
ql.Period(ql.Semiannual),
us_calendar,
ql.ModifiedFollowing,
ql.ModifiedFollowing,
ql.DateGeneration.Forward,
False
)
for d in schedule.dates():
print(d.ISO())
2024-04-18
2024-10-18
2025-04-21
2025-10-20
2026-04-20
DateGeneration.Forward vs Backward 的差異
這個參數定義了 Schedule 的展開方向:
- Forward:從起始日向終止日展開,適合週期固定的商品。
- Backward:從終止日往起始日反推,通常用在債券或其他已知終止日的商品。
兩者在遇到不整齊的期間(例如非整數的年/月)時會導致不同的第一期或最後一期天數,進而影響利息計算。若遇到畸零期,可以使用 DateGeneration.Backward,並觀察生成的日期是否與預期一致。
# generate schedule by DateGeneration.Backward
# assume first period is 2024/4/18~2024/6/18
start_date = ql.Date(18, 4, 2024)
end_date = ql.Date(18, 6, 2026)
schedule = ql.Schedule(
start_date,
end_date,
ql.Period(ql.Semiannual),
us_calendar,
ql.ModifiedFollowing,
ql.ModifiedFollowing,
ql.DateGeneration.Backward,
False
)
for d in schedule.dates():
print(d.ISO())
2024-04-18
2024-06-18
2024-12-18
2025-06-18
2025-12-18
2026-06-18
Schedule 與利息計算結合範例
start_date = ql.Date(18, 4, 2024)
end_date = ql.Date(20, 4, 2026)
schedule = ql.Schedule(
start_date,
end_date,
ql.Period(ql.Semiannual),
us_calendar,
ql.ModifiedFollowing,
ql.ModifiedFollowing,
ql.DateGeneration.Forward,
False
)
rate = 0.05
amount = 1000000.0
for i in range(len(schedule) - 1):
d1 = schedule[i]
d2 = schedule[i+1]
interest = rate * amount* (d2 - d1)/360.0
print(f"{d1.ISO()} -> {d2.ISO()}: interest = {interest:.2f}")
2024-04-18 -> 2024-10-18: interest = 25416.67
2024-10-18 -> 2025-04-21: interest = 25694.44
2025-04-21 -> 2025-10-20: interest = 25277.78
2025-10-20 -> 2026-04-20: interest = 25277.78
實務上,金融商品的利息計算方式會受到很多條件的影響,例如計息利率是固定還是浮動,計息區間是用ACT/360還是ACT/365(Fixed)等內容。在QuantLib Python已有對應已經寫好的物件Coupon類別來處理,我們在後續的文章就會看到它的身影。
結語
掌握 Date、Calendar 與 Schedule 的使用,能讓你在 QuantLib Python 建構利率商品與現金流量時更精確,也能避免因假期與天期處理不當導致的錯誤。建議在實務上多用 schedule.dates() 做交叉驗證,也能結合 CashFlowor Coupon 類別進行模擬與測試。
參考資料
- Ballabio, Luigi. Implementing QuantLib. Online resource
- Goutham Balaraman, Luigi Ballabio. QuantLib Python Cookbook. Leanpub, 2020. https://leanpub.com/quantlibpythoncookbook
附註: 本文Python程式示範是基於QuantLib Python版本1.37
















