程式

QuantLib python ql.schedule 獲取月末日期

  • January 6, 2021

我正在嘗試獲取每季度支付息票的債券的支付時間表。起息日為 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

ScheduleQuantLib 中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 功能是展示假期日曆的好地方。

引用自:https://quant.stackexchange.com/questions/60330