互換

Quantlib:來回將面值掉期利率轉換為零利率

  • June 3, 2020

我從通用面值掉期利率曲線(步驟 1)中建構了一條零息曲線,我試圖從零息曲線恢復掉期曲線(步驟 2)。

第 1 步有效,但第 2 步無效。我得到緊密的引號,但它們不完全匹配。有人知道我的第 2 步有什麼問題嗎?

我的猜測是它不是來自日曆問題,因為我使用的是理論日曆、日計數器和索引,沒有調整。

這是我的程式碼:

步驟1:

# define constants
face_amount = 100
settlementDays = 0
calendar = ql.NullCalendar()
fixedLegAdjustment = ql.Unadjusted
floatingLegAdjustment = ql.Unadjusted
fixedLegDayCounter = ql.SimpleDayCounter()
floatingLegDayCounter = ql.SimpleDayCounter()
fixedLegFrequency = ql.Semiannual
end_of_month = False
floating_rate = ql.IborIndex("MyIndex", ql.Period(3, ql.Months), settlementDays, ql.USDCurrency(), calendar, floatingLegAdjustment, end_of_month, floatingLegDayCounter)

# irs is a DataFrame with one line and the column as maturities (from 3M to 120M)
deposits = [irs.columns[0]]
swaps = irs.columns[1:]

# curve dates
zero_rates = {}
curve_date = ql.DateParser.parseFormatted(str("2017-01-01"), "%Y-%m-%d")
ql.Settings.instance().evaluationDate = curve_date
spot_date = calendar.advance(curve_date, settlementDays, ql.Days)

# deposit helper
deposit_helpers_mat = []
for tenor in deposits:
   deposit_helpers_mat.append([ql.Period(int(tenor), ql.Months), ql.QuoteHandle(ql.SimpleQuote(irs[int(tenor)] / 100))])

deposit_helper = [ql.DepositRateHelper(tenors_deposit, settlementDays, calendar, fixedLegAdjustment, end_of_month, fixedLegDayCounter) for tenors_deposit, deposit_rates in deposit_helpers_mat]

# swap helper
swap_helpers_mat = []
for tenor in swaps:
   swap_helpers_mat.append([ql.Period(int(tenor), ql.Months), ql.QuoteHandle(ql.SimpleQuote(irs[int(tenor)] / 100))])

swap_helper = [ql.SwapRateHelper(swap_rates, tenors_swap, calendar, fixedLegFrequency, fixedLegAdjustment, fixedLegDayCounter, floating_rate) for tenors_swap, swap_rates in swap_helpers_mat]

# aggregate helpers
helper = deposit_helper + swap_helper

# build curve
zc_curve = ql.PiecewiseCubicZero(curve_date, helper, ql.SimpleDayCounter())
zero_rate = []
tenors = []
# loop over maturities
for tenor in np.arange(3, 120 + 1, 3):
   maturity_date = calendar.advance(spot_date, ql.Period(int(tenor), ql.Months))
   zero_rate_curve = (zc_curve.zeroRate(maturity_date, ql.SimpleDayCounter(), ql.Compounded, ql.Annual).rate()* 100)
   zero_rate.append(zero_rate_curve)
   tenors.append(tenor)

# build the zero curve representation into a DataFrame
zero_rates = pd.DataFrame(np.transpose(list(zip(zero_rate))), columns=list(tenors))

第2步:

# constant
fixedRate = 0.02
spread =0
TENORS = np.arange(3, 120 + 1, 3)

# pre-allocate
irs_rates = {}
# calculate dates
curve_date = ql.DateParser.parseFormatted(str("2017-01-01"), "%Y-%m-%d")
ql.Settings.instance().evaluationDate = curve_date
spot_date = calendar.advance(curve_date, settlementDays, ql.Days)

# zero curve
irs_rate = []
tenors = []
maturity_dates = []
zc_rates = []
# loop over maturities
for tenor in TENORS:
   # maturity date
   maturity_date = calendar.advance(spot_date, ql.Period(int(tenor), ql.Months))
   # gather maturity dates
   maturity_dates.append(maturity_date)
   # gather zc rates
   zc_rates.append(zero_rates[int(tenor)] / 100)


# build zero coupon curve object
zero_curve = ql.YieldTermStructureHandle(ql.CubicZeroCurve(maturity_dates, zc_rates, fixedLegDayCounter, calendar))
# libor curve
libor_curve = ql.YieldTermStructureHandle(ql.CubicZeroCurve(maturity_dates, zc_rates, floatingLegDayCounter, calendar))
# floating rate
floating_rate = ql.IborIndex("MyIndex", ql.Period(3, ql.Months), settlementDays, ql.USDCurrency(), calendar, floatingLegAdjustment, end_of_month, floatingLegDayCounter, libor_curve)

# build swap curve
# loop over maturities
j = 0
for maturity in maturity_dates:
   # fixed leg tenor
   fixedLegTenor = ql.Period(3, ql.Months)
   # fixed leg coupon schedule
   fixedLegSchedule = ql.Schedule(spot_date, maturity, fixedLegTenor, calendar, fixedLegAdjustment, fixedLegAdjustment, ql.DateGeneration.Forward, end_of_month)

   # floating leg tenor
   floatingLegTenor = ql.Period(3, ql.Months)
   # floating leg coupon schedule
   floatingLegSchedule = ql.Schedule(spot_date, maturity, floatingLegTenor, calendar, floatingLegAdjustment, floatingLegAdjustment, ql.DateGeneration.Forward, end_of_month)

   # build swap pricer
   swap_rate = ql.VanillaSwap(ql.VanillaSwap.Payer, face_amount, fixedLegSchedule, fixedRate, fixedLegDayCounter, floatingLegSchedule, floating_rate, spread, floatingLegDayCounter)

   # build swap curve
   swap_curve = ql.DiscountingSwapEngine(zero_curve)
   # get swap rate
   swap_rate.setPricingEngine(swap_curve)

   # gather par irs rate
   irs_rate.append(swap_rate.fairRate() * 100)
   # gather irs tenor
   tenor = int(TENORS[j])
   j = j + 1
   tenors.append(tenor)
   # build the swap curve representation into a DataFrame
   irs_rates = pd.DataFrame(np.transpose(list(zip(irs_rate))), columns=list(tenors))

非常感謝您的幫助!

也許你應該從一個簡單的例子開始,因為你有這麼多活動元件,很難弄清楚區別在哪裡。您的助手和您嘗試定價的工具之間很可能存在一些不同的約定。

import QuantLib as ql

today = ql.Date().todaysDate()
calendar = ql.TARGET()
spot = calendar.advance(today, 2, ql.Days)

helpers = ql.RateHelperVector()
helpers.append( ql.DepositRateHelper(0.01, ql.Euribor6M()) )

swaps = [
   ('1Y', 0.015),
   ('2Y', 0.02),
   ('3Y', 0.025)
]
for tenor, rate in swaps:
   swapIndex = ql.EurLiborSwapIsdaFixA(ql.Period(tenor))
   helpers.append( ql.SwapRateHelper(rate, swapIndex) )

curve = ql.PiecewiseLogLinearDiscount(spot, helpers, ql.Actual360())
yts = ql.YieldTermStructureHandle(curve)
engine = ql.DiscountingSwapEngine(yts)

index = ql.Euribor6M(yts)

print("maturity, market, model")
for tenor, rate in swaps:
   swap = ql.MakeVanillaSwap(ql.Period(tenor), index, 0.01, ql.Period('0D'), pricingEngine=engine)    
   print(f"{tenor}, {rate:.6f}, {swap.fairRate():.6f}")

成熟度、市場、型號

​​ 1Y, 0.015000, 0.015000

2Y, 0.020000, 0.020000

3Y, 0.025000, 0.025000

要回答您評論中的問題:

  1. 什麼是 3M 掉期利率?要麼是固定利率與較短期限(例如:1m),要麼是固定利率與相同期限但遠期(在本例中為 FRA),或者如果它是起始點,那麼它與零利率相同,因為它必須中間付款。
  2. 浮動利率慣例在浮動指數的定義中。此外,您可以使用以下模板:ql.USDLibor(ql.Period(‘3M’))
  3. 要指定您的助手,您可以使用已定義約定的模板(例如:ql.UsdLiborSwapIsdaFixAm)或使用多個建構子之一。在此處查看更多資訊:https ://quantlib-python-docs.readthedocs.io/en/latest/thelpers.html#swapratehelper

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