Python
Python 中的 QuantLib:與交換/存款 RateHelper 相比,使用 OISRateHelper 的執行時間
我一直在使用雙曲線引導法對利率掉期進行估值。為此,我使用 OISRateHelper 使用 OIS 費率創建折扣期限結構。下面的整個程式碼:
import QuantLib as ql ql.IndexManager.instance().clearHistories() import math import numpy as np import pandas as pd import datetime as dt #### INPUTS date0 = dt.datetime.strptime("2012-07-05", "%Y-%m-%d") date1 = dt.datetime.strptime("2012-07-06", "%Y-%m-%d") calculation_dates = [ql.Date(date0.day,date0.month,date0.year), ql.Date(date1.day,date1.month,date1.year)] fwd_start = 0 ois_mat = [ql.Period(x) for x in ['1D', '2W', '1M', '2M', '3M', '4M', '5M', '6M', '7M', '8M', '9M', '10M', '11M', '12M', '18M', '2Y', '30M', '3Y', '4Y', '5Y', '6Y', '7Y', '8Y', '9Y', '10Y', '11Y', '12Y', '15Y', '20Y', '25Y', '30Y', '35Y', '40Y', '50Y']] ois_rates0 = [0.331, 0.162, 0.1525, 0.138, 0.136, 0.134, 0.133, 0.132, 0.135, 0.133, 0.134, 0.133, 0.134, 0.135, 0.146, 0.168, 0.197, 0.263, 0.419, 0.622, 0.8364, 1.006, 1.1625, 1.302, 1.429, 1.544, 1.64, 1.839, 1.93, 1.964, 1.999, 2.0465, 2.097, 2.1675] ois_rates1 = [0.329, 0.145, 0.134, 0.129, 0.13, 0.1235, 0.125, 0.145, 0.126, 0.12, 0.127, 0.122, 0.123, 0.125, 0.141, 0.165, 0.192, 0.253, 0.402, 0.595, 0.795, 0.976, 1.131, 1.27, 1.4049, 1.517, 1.611, 1.811, 1.901, 1.94, 1.963, 2.0265, 2.091, 2.173] ois_dict0 = dict(zip(ois_mat, [x/100 for x in ois_rates0])) ois_dict1 = dict(zip(ois_mat, [x/100 for x in ois_rates1])) list_ois_rates_dict = [ois_dict0, ois_dict1] deposit_mat = [ql.Period(1, ql.Months), ql.Period(3, ql.Months), ql.Period(6, ql.Months)]#, ql.Period(12, ql.Months)] deposit_rates0 = [0.00362, 0.00641, 0.0092] deposit_rates1 = [0.00255, 0.00549, 0.00831] deposit_dict0 = dict(zip(deposit_mat, deposit_rates0)) deposit_dict1 = dict(zip(deposit_mat, deposit_rates1)) list_deposit_rates_dict = [deposit_dict0, deposit_dict1] swap_mats = [ql.Period(x, ql.Years) for x in [1,2,3,4,5,6,7,8,9,10,12,15,20,25,30]] swap_rates0 = [0.00515, 0.00806, 0.00883, 0.01029, 0.01213, 0.0139, 0.01544, 0.01677, 0.01793, 0.01897, 0.02073, 0.02232, 0.02279, 0.02293, 0.02307] swap_rates1 = [0.00465, 0.00744, 0.00802, 0.00931, 0.01104, 0.01288, 0.0145, 0.01591, 0.01713, 0.01824, 0.02006, 0.0217, 0.02229, 0.02246, 0.02263] swap_dict0 = dict(zip(swap_mats, swap_rates0)) swap_dict1 = dict(zip(swap_mats, swap_rates1)) list_swap_curve_rates_dict = [swap_dict0, swap_dict1] libor_rates_dict = deposit_dict0.copy() swap_rates_dict = swap_dict0.copy() swap_libor_tenors = [ql.Period(x, ql.Months) for x in [6,6,6,6,6,6,6,6,6,6,6,6,6,6,6]] settlement_days = 0 face_value = 100 fixed_day_count = ql.Thirty360() float_day_count = ql.Actual360() ois_day_count = ql.Actual360() calendar = ql.TARGET() list_fixed_coupon_frequency = [ql.Annual for x in range(len(swap_libor_tenors))] currency = ql.EURCurrency() spread = 0 business_convention = ql.ModifiedFollowing date_generation = ql.DateGeneration.Forward end_of_month = False ### CALCULATIONS fixed_npv = [] float_npv = [] swap_npv = [] swap_fair_rate = [] ql.IndexManager.instance().clearHistories() date_t0 = calculation_dates[0] ql.Settings.instance().evaluationDate = date_t0 effective_start_date = calendar.advance(date_t0, settlement_days + fwd_start, ql.Days) discount_term_structure = ql.RelinkableYieldTermStructureHandle() forecast_term_structure = ql.RelinkableYieldTermStructureHandle() oindex = ql.OvernightIndex("", settlement_days, currency, calendar, ois_day_count, discount_term_structure) ###################### t5 = dt.datetime.now() ###################### ois_quote_map = {} ois_helpers_t0 = [] for r,m in zip(list_ois_rates_dict[0].values(), list_ois_rates_dict[0].keys()): quote = ql.SimpleQuote(r) helper= ql.OISRateHelper(settlement_days, m, ql.QuoteHandle(quote), oindex) ois_helpers_t0.append(helper) ois_quote_map[m]=quote ###################### t6 = dt.datetime.now() ###################### deposit_quote_map = {} deposit_helpers_t0 = [] for r,m in zip(list_deposit_rates_dict[0].values(), list_deposit_rates_dict[0].keys()): quote = ql.SimpleQuote(r) helper = ql.DepositRateHelper(ql.QuoteHandle(quote),m,settlement_days,calendar, business_convention,end_of_month,float_day_count) deposit_helpers_t0.append(helper) deposit_quote_map[m] = quote swap_ibor_indices = [ ql.IborIndex("", x, settlement_days, currency, calendar, business_convention, False, float_day_count, forecast_term_structure) for x in swap_libor_tenors] for sib in swap_ibor_indices: sib.addFixing(date_t0, libor_rates_dict[sib.tenor()]) swap_quote_map = {} swap_helpers_t0 = [] for r,m, ibor_index,f in zip(list_swap_curve_rates_dict[0].values(), list_swap_curve_rates_dict[0].keys(), swap_ibor_indices, list_fixed_coupon_frequency): quote = ql.SimpleQuote(r) helper = ql.SwapRateHelper(ql.QuoteHandle(quote),m,calendar,f,business_convention,fixed_day_count, ibor_index, ql.QuoteHandle(ql.SimpleQuote(0)),ql.Period(0, ql.Days), discount_term_structure, settlement_days) swap_helpers_t0.append(helper) swap_quote_map[m] = quote ###################### t10 = dt.datetime.now() ###################### helpers_t0 = deposit_helpers_t0 + swap_helpers_t0 swap_curve_t0 = ql.PiecewiseLogCubicDiscount(settlement_days, calendar, helpers_t0, fixed_day_count) discount_curve_t0 = ql.PiecewiseLogCubicDiscount(settlement_days, calendar, ois_helpers_t0, fixed_day_count) swap_curve_t0.enableExtrapolation() discount_curve_t0.enableExtrapolation() discount_term_structure.linkTo(discount_curve_t0) forecast_term_structure.linkTo(swap_curve_t0) swap_engine = ql.DiscountingSwapEngine(discount_term_structure) list_irs = [] for i in range(len(swap_mats)): swap_rate = list(swap_rates_dict.values())[i] fixed_tenor = ql.Period(list_fixed_coupon_frequency[i]) float_tenor = swap_ibor_indices[i].tenor() fixed_schedule = ql.Schedule(effective_start_date, calendar.advance(effective_start_date, list(swap_rates_dict.keys())[i]), fixed_tenor, calendar, business_convention, business_convention, date_generation, end_of_month) float_schedule = ql.Schedule(effective_start_date, calendar.advance(effective_start_date, list(swap_rates_dict.keys())[i]), float_tenor, calendar, business_convention, business_convention, date_generation, end_of_month) irs_temp = ql.VanillaSwap(ql.VanillaSwap.Receiver, face_value, fixed_schedule, swap_rate, fixed_day_count, float_schedule, swap_ibor_indices[i], spread, float_day_count) irs_temp.setPricingEngine(swap_engine) if fwd_start > 0: fair_swap_rate = irs_temp.fairRate() irs = ql.VanillaSwap(ql.VanillaSwap.Receiver, face_value, fixed_schedule, fair_swap_rate, fixed_day_count, float_schedule, swap_ibor_indices[i], spread, float_day_count) irs.setPricingEngine(swap_engine) list_irs.append(irs) else: list_irs.append(irs_temp) fixed_npv.append([x.fixedLegNPV() for x in list_irs]) float_npv.append([x.floatingLegNPV() for x in list_irs]) swap_npv.append([x.NPV() for x in list_irs]) swap_fair_rate.append([x.fairRate() for x in list_irs]) print("ois helpers on date0: " + str((t6 - t5))) print("other helpers on date0: " + str((t10 - t6))) ###################### t19 = dt.datetime.now() ###################### tdelta = dt.timedelta() if len(calculation_dates) > 1: for i in range(1, len(calculation_dates)): ###################### t19_1 = dt.datetime.now() ###################### date_ti = calculation_dates[i] ql.Settings.instance().evaluationDate = date_ti ###################### t19_2 = dt.datetime.now() ###################### for k in list_ois_rates_dict[i].keys(): ois_quote_map[k].setValue(list_ois_rates_dict[i][k]) for k in list_deposit_rates_dict[i].keys(): deposit_quote_map[k].setValue(list_deposit_rates_dict[i][k]) for k in list_swap_curve_rates_dict[i].keys(): swap_quote_map[k].setValue(list_swap_curve_rates_dict[i][k]) fixed_npv.append([x.fixedLegNPV() for x in list_irs]) float_npv.append([x.floatingLegNPV() for x in list_irs]) swap_npv.append([x.NPV() for x in list_irs]) swap_fair_rate.append([x.fairRate() for x in list_irs]) ###################### tdelta = tdelta + (t19_2 - t19_1) ###################### ###################### t20 = dt.datetime.now() ###################### print("Calculations for other dates: " + str((t20 - t19))) print("Setting evaluation dates for other dates: " + str(tdelta))
我計算了創建 OISRateHelpers 實例的執行時間,並將它們與創建 DepositRateHelpers 和 SwapRateHelpers 實例的執行時間進行了比較。
ois helpers on date0: 0:00:00.299389 other helpers on date0: 0:00:00.000999
輸出顯示兩者之間存在重大差異。
此外,在重新計算掉期時,在其他日期(date0 除外),ql.Settings.instance().evaluationDate會佔用更多時間。
Calculations for other dates: 0:00:09.596271 Setting evaluation dates for other dates: 0:00:09.554356
從這個執行緒中,我了解到設置新日期會更改之前聲明的所有實例的參考日期。
我試圖理解:
- 為什麼創建 OISRateHelpers 實例比創建 SwapRateHelpers/DepositRateHelpers 實例需要更長的時間?
- 事實上,更改評估日期非常耗時,OISRateHelper 是否有可能創建“冗餘”依賴項,這也需要通知評估日期的更改?因此在 ql.Settings 中重置評估日期會很耗時?
謝謝!
我向 quantlib 郵件列表發送了同樣的問題。解決方案是
telescopicValueDates = True
為 OISRateHelpers 設置。OISRateHelper 創建一個包含很多日期的時間表;對於曲線引導而言,這並不是真正必要的,您可以通過將參數 telescopicValueDates 設置為 true 來避免它,這將加快速度(當然不會改變結果曲線)。