Python

使用 QuantLib Python 計算掉期的滾動

  • November 17, 2017

我想使用 QuantLib Python 來計算 5 年掉期的 6 個月滾降。

我相信我需要做的計算如下:

$ Rolldown=r_{0,5Y}-r_{0,4.5Y} $

在哪裡 $ r_{0,5Y} $ 是 5 年即期匯率和 $ r_{0,4.5Y} $ 是 4 年即期匯率。

您可以在以下連結中找到 roll-down 的定義:

https://e-markets.nordea.com/api/research/attachment/2796

http://www.gioa.us/presentations/2012/4-Rajappa.pdf

請讓我知道我的方程式是否正確。

假設我的等式是正確的,以下是我嘗試使用 QuantLib Python 計算掉期滾動的方法:

from QuantLib import *

# global data
calendar = TARGET()
todaysDate = Date(6,November,2001);
Settings.instance().evaluationDate = todaysDate
settlementDate = Date(8,November,2001);

# market quotes
deposits = { (1,Weeks): 0.0382,
            (1,Months): 0.0372,
            (3,Months): 0.0363,
            (6,Months): 0.0353,
            (9,Months): 0.0348,
            (1,Years): 0.0345 }

swaps = { (2,Years): 0.037125,
         (3,Years): 0.0398,
         (5,Years): 0.0443,
         (10,Years): 0.05165,
         (15,Years): 0.055175 }

# convert them to Quote objects
for n,unit in deposits.keys():
   deposits[(n,unit)] = SimpleQuote(deposits[(n,unit)])
for n,unit in swaps.keys():
   swaps[(n,unit)] = SimpleQuote(swaps[(n,unit)])

# build rate helpers

dayCounter = Actual360()
settlementDays = 2
depositHelpers = [ DepositRateHelper(QuoteHandle(deposits[(n,unit)]),
                                    Period(n,unit), settlementDays,
                                    calendar, ModifiedFollowing,
                                    False, dayCounter)
                  for n, unit in [(1,Weeks),(1,Months),(3,Months),
                                  (6,Months),(9,Months),(1,Years)] ]

fixedLegFrequency = Annual
fixedLegTenor = Period(1,Years)
fixedLegAdjustment = Unadjusted
fixedLegDayCounter = Thirty360()
floatingLegFrequency = Semiannual
floatingLegTenor = Period(6,Months)
floatingLegAdjustment = ModifiedFollowing
swapHelpers = [ SwapRateHelper(QuoteHandle(swaps[(n,unit)]),
                              Period(n,unit), calendar,
                              fixedLegFrequency, fixedLegAdjustment,
                              fixedLegDayCounter, Euribor6M())
               for n, unit in swaps.keys() ]

# term structure handles

discountTermStructure = RelinkableYieldTermStructureHandle()
forecastTermStructure = RelinkableYieldTermStructureHandle()

# term-structure construction

helpers = depositHelpers + swapHelpers
depoSwapCurve = PiecewiseFlatForward(settlementDate, helpers, Actual360())

swapEngine = DiscountingSwapEngine(discountTermStructure)

# 5Y Swap 

nominal = 1000000
maturity1 = calendar.advance(settlementDate,5,Years)

fixedLegFrequency = Annual
fixedLegAdjustment = Unadjusted
fixedLegDayCounter = Thirty360()
fixedRate = 0.04

floatingLegFrequency = Semiannual
spread = 0.0
fixingDays = 2
index = Euribor6M(forecastTermStructure)
floatingLegAdjustment = ModifiedFollowing
floatingLegDayCounter = index.dayCounter()

fixedSchedule1 = Schedule(settlementDate, maturity1,
                        fixedLegTenor, calendar,
                        fixedLegAdjustment, fixedLegAdjustment,
                        DateGeneration.Forward, False)
floatingSchedule1 = Schedule(settlementDate, maturity1,
                           floatingLegTenor, calendar,
                           floatingLegAdjustment, floatingLegAdjustment,
                           DateGeneration.Forward, False)

spot1 = VanillaSwap(VanillaSwap.Receiver, nominal,
                  fixedSchedule1, fixedRate, fixedLegDayCounter,
                  floatingSchedule1, index, spread,
                  floatingLegDayCounter)
spot1.setPricingEngine(swapEngine)


# 4.5Y Swap 

rolldown_period = Period(6, Months)

maturity2 = calendar.advance(maturity1, -rolldown_period)

fixedSchedule2 = Schedule(settlementDate, maturity2,
                        fixedLegTenor, calendar,
                        fixedLegAdjustment, fixedLegAdjustment,
                        DateGeneration.Forward, False)
floatingSchedule2 = Schedule(settlementDate, maturity2,
                           floatingLegTenor, calendar,
                           floatingLegAdjustment, floatingLegAdjustment,
                           DateGeneration.Forward, False)

spot2 = VanillaSwap(VanillaSwap.Receiver, nominal,
                  fixedSchedule2, fixedRate, fixedLegDayCounter,
                  floatingSchedule2, index, spread,
                  floatingLegDayCounter)
spot2.setPricingEngine(swapEngine)

# price on two different evaluation dates

discountTermStructure.linkTo(depoSwapCurve)
forecastTermStructure.linkTo(depoSwapCurve)

spot5Y = spot1.fairRate()
spot4Y6M = spot2.fairRate()

print('5Y spot rate')
print(spot5Y)
print('4.5Y spot rate')
print(spot4Y6M)
print('6 month roll down')
print(spot5Y - spot4Y6M)

我在如何使用 QuantLib Python 計算 5 年掉期的 6 個月滾降方面是否正確?是否有必要像我所做的那樣創建 2 個交換對象來計算交換滾動?

不,我認為你得到了一個錯誤的數字。總體構想可能可行,但必須更改第二次交換的構造。(或者你可以只使用一個交換;我稍後會談到。)

當我閱讀您連結的文件時,第二次交換的想法是在 6 個月過去後模擬第一次交換。但是,讓我們看看這兩個交換。我將定義一個輔助函式來查看他們的優惠券:

def show_cashflows(leg):
   for c in leg:
       print '%20s | %s | %.4f%%' % (c.date(), c.amount(),
                                     as_coupon(c).rate()*100)

這就是 5 年互換的固定支腿所支付的……

show_cashflows(spot1.fixedLeg())

November 8th, 2002 | 40000.0 | 4.0000%
November 10th, 2003 | 40000.0 | 4.0000%
November 8th, 2004 | 40000.0 | 4.0000%
November 8th, 2005 | 40000.0 | 4.0000%
November 8th, 2006 | 40000.0 | 4.0000%

…這是浮動腿:

show_cashflows(spot1.floatingLeg())

     May 8th, 2002 | 17748.0555555 | 3.5300%
November 8th, 2002 | 16930.6254304 | 3.3125%
     May 8th, 2003 | 19219.7194265 | 3.8227%
November 10th, 2003 | 19755.8616671 | 3.8237%
    May 10th, 2004 | 22498.6599297 | 4.4503%
November 8th, 2004 | 22498.6599297 | 4.4503%
     May 9th, 2005 | 25550.9745581 | 5.0540%
November 8th, 2005 | 25693.1528497 | 5.0544%
     May 8th, 2006 | 25408.8159749 | 5.0537%
November 8th, 2006 | 25835.3508522 | 5.0547%

從 6 個月後的評估日期看,您的第二次交換應該給您相同的優惠券。浮動腿看起來一樣,除了一張優惠券不見了:

show_cashflows(spot2.floatingLeg())

     May 8th, 2002 | 17748.0555555 | 3.5300%
November 8th, 2002 | 16930.6254304 | 3.3125%
     May 8th, 2003 | 19219.7194265 | 3.8227%
November 10th, 2003 | 19755.8616671 | 3.8237%
    May 10th, 2004 | 22498.6599297 | 4.4503%
November 8th, 2004 | 22498.6599297 | 4.4503%
     May 9th, 2005 | 25550.9745581 | 5.0540%
November 8th, 2005 | 25693.1528497 | 5.0544%
     May 8th, 2006 | 25408.8159749 | 5.0537%

(看起來最後一張優惠券不見了,而不是第一張;但那是因為您假設曲線保持不變並隨時間變化,因此六個月內第二張優惠券的定價將等於第一個優惠券的定價現在優惠券。)

然而,下面是固定腿的樣子:

show_cashflows(spot2.fixedLeg())

November 8th, 2002 | 40000.0 | 4.0000%
November 10th, 2003 | 40000.0 | 4.0000%
November 8th, 2004 | 40000.0 | 4.0000%
November 8th, 2005 | 40000.0 | 4.0000%
     May 8th, 2006 | 20000.0 | 4.0000%

由於您創建了一個 4.5 年的時間表,因此最後一張優惠券更短,並且缺少一半的金額。當然,這會導致公平率偏離。

print spot2.fairRate()

0.0434536470094

您有幾種方法可以解決此問題。

首先,您可以從過去 6 個月開始創建 5 年的互換,而不是創建 4.5 年的互換:

issue2 = calendar.advance(settlementDate, -rolldown_period)
maturity2 = calendar.advance(issue2, 5, Years)

fixedSchedule2 = Schedule(issue2, maturity2,
                        fixedLegTenor, calendar,
                        fixedLegAdjustment, fixedLegAdjustment,
                        DateGeneration.Forward, False)
floatingSchedule2 = Schedule(issue2, maturity2,
                           floatingLegTenor, calendar,
                           floatingLegAdjustment, floatingLegAdjustment,
                           DateGeneration.Forward, False)

swap3 = VanillaSwap(VanillaSwap.Receiver, nominal,
                   fixedSchedule2, fixedRate, fixedLegDayCounter,
                   floatingSchedule2, index, spread,
                   floatingLegDayCounter)
swap3.setPricingEngine(swapEngine)

現在固定腿支付正確的金額……

show_cashflows(swap3.fixedLeg())

    May 8th, 2002 | 40000.0 | 4.0000%
    May 8th, 2003 | 40000.0 | 4.0000%
   May 10th, 2004 | 40000.0 | 4.0000%
    May 9th, 2005 | 40000.0 | 4.0000%
    May 8th, 2006 | 40000.0 | 4.0000%

…並且公平率會相應變化。

print swap3.fairRate()

0.0387677146311

正如您所建議的,解決它的第二種方法是使用單個交換。

您可以建構期限結構,使其隨評估日期移動;而不是明確地通過參考日期,而是告訴曲線參考日期應該是評估日期後的兩個工作日。

depoSwapCurve = PiecewiseFlatForward(2, TARGET(), helpers, Actual360())

其餘的初始化保持不變。spot1使用此設置,您可以在兩個不同的評估日期簡單地詢問掉期的公平率:

Settings.instance().evaluationDate = todaysDate
print spot1.fairRate()

0.0443

Settings.instance().evaluationDate = calendar.advance(todaysDate, 6, Months)
print spot1.fairRate()

0.038847797035

(6 個月後的公平利率相似,但與第一種方法計算的不完全相同。這可能是由於曲線有點不同;用於引導的存款期限可能等於不同數量的天數取決於現場日期。)

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