QuantLib python ql.schedule 獲取月末日期
我正在嘗試獲取每季度支付息票的債券的支付時間表。起息日為 2020 年 4 月 1 日,首張票息日為 2020 年 6 月 30 日,到期日為 2022 年 9 月 30 日。所以我希望有一個日期列表:
2020-04-01
2020-06-30
2020-09-30
2020-12-31
2021-03-31
2021-06-30
2021-09-30
2021-12-31
2022-03-31
2022-06-30
2022-09-30
但是,當我使用如下時間表時
list(ql.Schedule( ql.Date('01-04-2020', '%d-%m-%Y'), ql.Date('30-09-2022', '%d-%m-%Y'), ql.Period("3m"), ql.UnitedStates(), ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Forward, False, ql.Date('30-06-2020', '%d-%m-%Y'), ))
我得到了以下輸出,三月和十二月不是月底。我可以看到有 endOfMonth 但如果我將其設置為 true 它也會將 2020-04-01 更改為 2020-04-30 我不希望它發生。根據doc,如果開始日期在月底,則可以使用endOfMonth,是否需要在月底安排其他日期(最後日期除外)。就我而言,開始日期不在月底。有什麼建議可以實現正確的優惠券支付日期?
2020-04-01
2020-06-30
2020-09-30
2020-12-30
2021-03-30
2021-06-30
2021-09-30
2021-12-30
2022-03-30
2022-06-30
2022-09-30
Schedule
QuantLib 中a 的建構子是:ql.Schedule(effectiveDate, terminationDate, tenor, calendar, convention, terminationDateConvention, rule, endOfMonth, firstDate=Date(), nextToLastDate=Date() )
按照您定義的方式,您基本上是在 30 日滾動,這就是為什麼您在這 4 個日期中有所不同:
mydates = [ '2020-04-01', '2020-06-30', '2020-09-30', '2020-12-31', '2021-03-31', '2021-06-30', '2021-09-30', '2021-12-31', '2022-03-31', '2022-06-30', '2022-09-30', ] schedule = ql.Schedule( ql.Date('01-04-2020', '%d-%m-%Y'), ql.Date('30-09-2022', '%d-%m-%Y'), ql.Period("3m"), ql.UnitedStates(), ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Forward, False, ql.Date('30-06-2020', '%d-%m-%Y')) pd.DataFrame({ "mydates": mydates, "qlDates": [dt.ISO() for dt in schedule] }).style.apply(lambda row: ["background: red; color: white"]*2 if row[0] != row[1] else [""]*2, axis = 1)
此外,請注意列表中的日期之一不是
ql.UnitedStated
日曆中的工作日,因此您無法使用調整後的工作日約定生成這些日期:cal = ql.UnitedStates() [cal.isBusinessDay(ql.Date(dt, '%Y-%m-%d')) for dt in mydates]
$$ True, True, True, True, True, True, True, False, True, True, True $$ 所以我的建議是:
- 將約定更改為未調整,因為您想要一個不是工作日的日期
- 將 endOfMonth 更改為 True
- 將日期生成規則更改為向後
- 鬆開 firstDate 參數,因為您沒有任何存根(實際上您將滾動日期設置為 30 日)
schedule = ql.Schedule( ql.Date('01-04-2020', '%d-%m-%Y'), ql.Date('30-09-2022', '%d-%m-%Y'), ql.Period("3m"), ql.UnitedStates(), ql.Unadjusted, ql.Unadjusted, ql.DateGeneration.Backward, True) pd.DataFrame({ "mydates": mydates, "qlDates": [dt.ISO() for dt in schedule] }).style.apply(lambda row: ["background: red"]*2 if row[0] != row[1] else [""]*2, axis = 1)
評論後編輯: 正如 Dimitri 很好地指出的那樣,沒有單一的“美元假期”日曆,您所擁有的是不同市場/資產類別/交易所使用的美國假期的幾種組合。
在 QuantLib 中,您可以指定其中的一些。例如,該日期(31-12-2021)將在整個備選方案中以不同方式處理:
mydate = ql.Date(31,12,2021) cal = ql.UnitedStates() alts = ['FederalReserve', 'GovernmentBond', 'LiborImpact', 'NERC', 'NYSE', 'Settlement'] for alt in alts: mycalendar = eval(f'ql.UnitedStates(ql.UnitedStates.{alt})') print(alt, mycalendar.isBusinessDay(mydate))
FederalReserve True
GovernmentBond True
LiborImpact False
NERC True
NYSE True
Settlement False
關於“初級生成”的時間表也是一個很好的觀點,我已經看過幾次了。一些時間表,可能是債券或衍生品,根本無法由市場慣例規則生成,在極端情況下,您可能只需要手動插入它們。在 QuantLib 中,您可以這樣做:
schedule = ql.Schedule([ql.Date(dt, '%Y-%m-%d') for dt in mydates]) print([*schedule])
我想為 David Duarte 的出色回答增添一些色彩。
當公司或新興市場債券發行時,一些初級人員負責為招股說明書編制票息日期清單。如今,他們通常使用一種了解常用約定的工具,但幾十年前他們手動完成,有時會搞砸。我曾經檢查以確保我的庫(不是 ql,而是一個類似的調度程序,更靈活一點)與招股說明書中的日期匹配,最後編寫了幾行 C++ 程式碼,將招股說明書中的日期作為輸入和 Bloomberg 終端上的參數(如果可用),並嘗試了調度程序參數的不同組合以匹配日期。有時我們會遇到失敗的債券,因此招股說明書中的時間表必須是自定義的日期列表。現在很少發生這種情況,你的債券不需要,
該程式碼還指示您是否需要為奇數的第一個週期指定 firstDate 和為奇數的最後一個週期指定倒數第二個 (nextToLastDate)。在我看來,如果它們是多餘的,最好不要通過它們 - 只有在它們有所作為時才通過它們。許多債券的首期和/或末期都是奇數。(很少有債券在時間表中間有奇數期。)
您可能想為 QL 計劃編寫這樣的工具並將其貢獻給社區。
請記住,沒有“美元假期”之類的東西。雖然對於許多其他貨幣,每個人都使用一種日曆,因此可以將倫敦日曆稱為“英鎊日曆”,但這對美國不起作用。美國的股票(紐約證券交易所)和債券以及其他一些假期也有不同的假期。使用 ql.UnitedStates() 而不指定您指的是哪個日曆(例如 GovernmentBond)可能會導致混淆。查看https://www.sifma.org/resources/general/holiday-schedule/並向下滾動到“美國假期建議”。點擊 2021,觀察它顯示“提前關閉(東部時間下午 2:00):2021 年 12 月 31 日,星期五”。
讓我們在 QL 中嘗試您有問題的日期:
NewYearsEve = ql.Date(31,12,2021)
# 因為元旦,2022 年 1 月 1 日是星期六,所以一些假期日曆在這裡有一個觀察假期
ql.UnitedStates().isBusinessDay(NewYearsEve)
# 壞的!
ql.UnitedStates(ql.UnitedStates.Settlement).isBusinessDay(NewYearsEve)
ql.UnitedStates(ql.UnitedStates.LiborImpact).isBusinessDay(NewYearsEve)
是假的,但是
ql.UnitedStates(ql.UnitedStates.NYSE).isBusinessDay(NewYearsEve)
ql.UnitedStates(ql.UnitedStates.GovernmentBond).isBusinessDay(NewYearsEve)
ql.UnitedStates(ql.UnitedStates.NERC).isBusinessDay(NewYearsEve)
ql.UnitedStates(ql.UnitedStates.FederalReserve).isBusinessDay(NewYearsEve)
是真的。我認為沒有理由在這個日期沒有債券息票。
使用不同日曆的股票和債券範例
IndigenousPeoplesDay = ql.Date(11,10,2021)
# 又名加拿大感恩節,哥倫布日
ql.UnitedStates().isBusinessDay(IndigenousPeoplesDay)
# 壞的!
ql.UnitedStates(ql.UnitedStates.Settlement).isBusinessDay(IndigenousPeoplesDay) )
ql.UnitedStates(ql.UnitedStates.GovernmentBond).isBusinessDay(IndigenousPeoplesDay)
是假的,但是
ql.UnitedStates(ql.UnitedStates.NYSE).isBusinessDay(IndigenousPeoplesDay)
是真的 - 你可以交易股票。
如果您有興趣,彭博終端上的 CDR 功能是展示假期日曆的好地方。