互換
Quantlib:來回將面值掉期利率轉換為零利率
我從通用面值掉期利率曲線(步驟 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
要回答您評論中的問題:
- 什麼是 3M 掉期利率?要麼是固定利率與較短期限(例如:1m),要麼是固定利率與相同期限但遠期(在本例中為 FRA),或者如果它是起始點,那麼它與零利率相同,因為它必須中間付款。
- 浮動利率慣例在浮動指數的定義中。此外,您可以使用以下模板:ql.USDLibor(ql.Period(‘3M’))
- 要指定您的助手,您可以使用已定義約定的模板(例如:ql.UsdLiborSwapIsdaFixAm)或使用多個建構子之一。在此處查看更多資訊:https ://quantlib-python-docs.readthedocs.io/en/latest/thelpers.html#swapratehelper