Оценка облигаций QuantLib с кредитным спредом не работает после установки значений ключевой ставки - PullRequest
0 голосов
/ 03 июля 2019

Я использую класс SpreadedLinearZeroInterpolatedTermStructure для определения цены облигации. У меня 35 ключевых ставок, от 1М до 30Г У меня также есть дневная кривая спота. Поэтому я хочу ввести 35 ключевых ставок, извлеченных из дневной кривой спот, в класс, а затем изменить ключевые ставки, чтобы узнать, какова цена облигации.

Даем кредит ГБ и его статье здесь: http://gouthamanbalaraman.com/blog/bonds-with-spreads-quantlib-python.html

Я следовал его методу, который хорошо работал, цена облигации меняется из-за различных значений, установленных для ключевых ставок.

Затем я заменил его плоскую кривую моей дневной кривой спота, его список ручек - моими ручками (в нем 35 ручек), а его две даты - моими 35 датами.

Я установил значения для некоторых ключевых скоростей, пока NPV оставалась неподвижной (даже я сильно потряс). Я также попытался дать только две ключевые ставки на нулевой кривой, и это сработало. Я думаю, это потому, что 35 ключевых показателей - это слишком Любая помощь приветствуется

import QuantLib as ql

# =============================================================================
# normal yc term structure
# =============================================================================
todaysDate = ql.Date(24,5,2019)
ql.Settings.instance().evaluationDate = todaysDate

KR1 = [0, 1, 3, 6, 9] # KR in month unit
KR2 = [x for x in range(1,31)] # KR in year unit
spotDates = [] # starting from today
for kr in KR1:
    p = ql.Period(kr,ql.Months)
    spotDates.append(todaysDate+p)
for kr in KR2:
    p = ql.Period(kr,ql.Years)
    spotDates.append(todaysDate+p)

spotRates = [0.02026,
             0.021569,
             0.02326,
             0.025008,
             0.026089,
             0.026679,
             0.028753,
             0.029376,
             0.030246,
             0.031362,
             0.033026,
             0.034274,
             0.033953,
             0.033474,
             0.033469,
             0.033927,
             0.03471,
             0.035596,
             0.036396,
             0.036994,
             0.037368,
             0.037567,
             0.037686,
             0.037814,
             0.037997,
             0.038247,
             0.038562,
             0.038933,
             0.039355,
             0.039817,
             0.040312,
             0.040832,
             0.041369,
             0.041922,
             0.042487] # matching points
dayCount = ql.Thirty360()
calendar = ql.China()
interpolation = ql.Linear()
compounding = ql.Compounded
compoundingFrequency = ql.Annual
spotCurve = ql.ZeroCurve(spotDates, spotRates, dayCount, calendar, 
                         interpolation,compounding, compoundingFrequency)
spotCurveHandle = ql.YieldTermStructureHandle(spotCurve)

# =============================================================================
# bond settings
# =============================================================================
issue_date = ql.Date(24,5,2018)
maturity_date = ql.Date(24,5,2023)
tenor = ql.Period(ql.Semiannual)
calendar = ql.China()
business_convention = ql.Unadjusted
date_generation = ql.DateGeneration.Backward
month_end = False
schedule = ql.Schedule(issue_date,maturity_date,tenor,calendar,
                       business_convention, business_convention,
                       date_generation,month_end)
settlement_days = 0
day_count = ql.Thirty360()
coupon_rate = 0.03
coupons = [coupon_rate]

face_value = 100
fixed_rate_bond = ql.FixedRateBond(settlement_days,
                                   face_value,
                                   schedule,
                                   coupons,
                                   day_count)
#bond_engine = ql.DiscountingBondEngine(spotCurveHandle)
#fixed_rate_bond.setPricingEngine(bond_engine)
#print(fixed_rate_bond.NPV())


# =============================================================================
# non-parallel shift of yc
# =============================================================================

#def KRshocks(kr0=0.0, kr_1M=0.0, kr_3M=0.0, kr_6M=0.0, kr_9M=0.0, 
#             kr_1Y=0.0,kr_2Y=0.0, kr_3Y=0.0, kr_4Y=0.0, kr_5Y=0.0, kr_6Y=0.0,
#             kr_7Y=0.0, kr_8Y=0.0, kr_9Y=0.0, kr_10Y=0.0, kr_11Y=0.0, kr_12Y=0.0,
#             kr_13Y=0.0, kr_14Y=0.0, kr_15Y=0.0, kr_16Y=0.0, kr_17Y=0.0, kr_18Y=0.0,
#             kr_19Y=0.0, kr_20Y=0.0, kr_21Y=0.0, kr_22Y=0.0, kr_23Y=0.0, kr_24Y=0.0,
#             kr_25Y=0.0, kr_26Y=0.0, kr_27Y=0.0, kr_28Y=0.0, kr_29Y=0.0, kr_30Y=0.0):
#    '''
#    
#    Parameters:
#        Input shocks for each key rate.
#        kr0 = today's spot rate shock;
#        kr_1M = 0.083 year(1 month) later spot rate shock;
#        kr_1Y = 1 year later spot rate shock;
#        .
#        .
#        .
#        
#    '''
#    
#    krs = list(locals().keys())
#    KRHandles = {}
#    for k in krs:
#        KRHandles['{}handle'.format(k)] = ql.QuoteHandle(ql.SimpleQuote(locals()[k]))

#    return list(KRHandles.values())

#handles = KRshocks()

kr = ['kr0', 'kr_1M', 'kr_3M', 'kr_6M', 'kr_9M', 'kr_1Y','kr_2Y', 'kr_3Y', 
      'kr_4Y', 'kr_5Y', 'kr_6Y','kr_7Y', 'kr_8Y', 'kr_9Y', 'kr_10Y', 'kr_11Y', 
      'kr_12Y', 'kr_13Y', 'kr_14Y', 'kr_15Y', 'kr_16Y', 'kr_17Y', 'kr_18Y', 
      'kr_19Y', 'kr_20Y', 'kr_21Y', 'kr_22Y', 'kr_23Y', 'kr_24Y','kr_25Y', 
      'kr_26Y', 'kr_27Y', 'kr_28Y', 'kr_29Y', 'kr_30Y']

#KRQuotes = {}
handles = []
#for k in range(len(kr)):
#    KRQuotes['{}'.format(kr[k])] = ql.SimpleQuote(spotRates[k])
#    handles.append(ql.QuoteHandle(ql.SimpleQuote(spotRates[k])))

kr0 = ql.SimpleQuote(spotRates[0])
kr_1M = ql.SimpleQuote(spotRates[1])
kr_3M = ql.SimpleQuote(spotRates[2])
kr_6M = ql.SimpleQuote(spotRates[3])
kr_9M = ql.SimpleQuote(spotRates[4])
kr_1Y = ql.SimpleQuote(spotRates[5])
kr_2Y = ql.SimpleQuote(spotRates[6])
kr_3Y = ql.SimpleQuote(spotRates[7])
kr_4Y = ql.SimpleQuote(spotRates[8])
kr_5Y = ql.SimpleQuote(spotRates[9])
kr_6Y = ql.SimpleQuote(spotRates[10])
kr_7Y = ql.SimpleQuote(spotRates[11])
kr_8Y = ql.SimpleQuote(spotRates[12])
kr_9Y = ql.SimpleQuote(spotRates[13])
kr_10Y = ql.SimpleQuote(spotRates[14])
kr_11Y = ql.SimpleQuote(spotRates[15])
kr_12Y = ql.SimpleQuote(spotRates[16])
kr_13Y = ql.SimpleQuote(spotRates[17])
kr_14Y = ql.SimpleQuote(spotRates[18])
kr_15Y = ql.SimpleQuote(spotRates[19])
kr_16Y = ql.SimpleQuote(spotRates[20])
kr_17Y = ql.SimpleQuote(spotRates[21])
kr_18Y = ql.SimpleQuote(spotRates[22])
kr_19Y = ql.SimpleQuote(spotRates[23])
kr_20Y = ql.SimpleQuote(spotRates[24])
kr_21Y = ql.SimpleQuote(spotRates[25])
kr_22Y = ql.SimpleQuote(spotRates[26])
kr_23Y = ql.SimpleQuote(spotRates[27])
kr_24Y = ql.SimpleQuote(spotRates[28])
kr_25Y = ql.SimpleQuote(spotRates[29])
kr_26Y = ql.SimpleQuote(spotRates[30])
kr_27Y = ql.SimpleQuote(spotRates[31])
kr_28Y = ql.SimpleQuote(spotRates[32])
kr_29Y = ql.SimpleQuote(spotRates[33])
kr_30Y = ql.SimpleQuote(spotRates[34])

handles.append(ql.QuoteHandle(kr0))
handles.append(ql.QuoteHandle(kr_1M))
handles.append(ql.QuoteHandle(kr_3M))
handles.append(ql.QuoteHandle(kr_6M))
handles.append(ql.QuoteHandle(kr_9M))
handles.append(ql.QuoteHandle(kr_1Y))
handles.append(ql.QuoteHandle(kr_2Y))
handles.append(ql.QuoteHandle(kr_3Y))
handles.append(ql.QuoteHandle(kr_4Y))
handles.append(ql.QuoteHandle(kr_5Y))
handles.append(ql.QuoteHandle(kr_6Y))
handles.append(ql.QuoteHandle(kr_7Y))
handles.append(ql.QuoteHandle(kr_8Y))
handles.append(ql.QuoteHandle(kr_9Y))
handles.append(ql.QuoteHandle(kr_10Y))
handles.append(ql.QuoteHandle(kr_11Y))
handles.append(ql.QuoteHandle(kr_12Y))
handles.append(ql.QuoteHandle(kr_13Y))
handles.append(ql.QuoteHandle(kr_14Y))
handles.append(ql.QuoteHandle(kr_15Y))
handles.append(ql.QuoteHandle(kr_16Y))
handles.append(ql.QuoteHandle(kr_17Y))
handles.append(ql.QuoteHandle(kr_18Y))
handles.append(ql.QuoteHandle(kr_19Y))
handles.append(ql.QuoteHandle(kr_20Y))
handles.append(ql.QuoteHandle(kr_21Y))
handles.append(ql.QuoteHandle(kr_22Y))
handles.append(ql.QuoteHandle(kr_23Y))
handles.append(ql.QuoteHandle(kr_24Y))
handles.append(ql.QuoteHandle(kr_25Y))
handles.append(ql.QuoteHandle(kr_26Y))
handles.append(ql.QuoteHandle(kr_27Y))
handles.append(ql.QuoteHandle(kr_28Y))
handles.append(ql.QuoteHandle(kr_29Y))
handles.append(ql.QuoteHandle(kr_30Y))

ts_spreaded2 = ql.SpreadedLinearZeroInterpolatedTermStructure(spotCurveHandle,
                                                              handles,
                                                              spotDates)
ts_spreaded_handle2 = ql.YieldTermStructureHandle(ts_spreaded2)
bond_engine = ql.DiscountingBondEngine(ts_spreaded_handle2)
fixed_rate_bond.setPricingEngine(bond_engine)
#print(fixed_rate_bond.NPV())
kr0.setValue(0.1)
kr_10Y.setValue(0.2)
kr_12Y.setValue(0.2)
print(fixed_rate_bond.NPV())

ошибок не возникло, но цена облигации совпадает с ценой до добавления спредов

...