Оценка встроенной опции линейной отзывной ноты с нулевым купономPython

Программы на Python
Anonymous
Оценка встроенной опции линейной отзывной ноты с нулевым купоном

Сообщение Anonymous »

У меня возникли проблемы с оценкой встроенного опциона в рамках линейного отзывного векселя с нулевым купоном. Детали векселя следующие:
Эмитент: Citigroup, дата первого расчета (05.07.2024), срок погашения (05.07.2029)
Купон (начисляется и выплачивается единовременно на дату отзыва или срок погашения): 5,75%
График досрочного погашения:
05.07.25 по 105,75%
5.07.26 по 111,5%
05.07.27 по 117,25%
05.07.28 при 123,00%
Использование Bloomberg OAS и YAS, похоже, не дает правильных результатов, поскольку цена опциона немного низкая.
Я просто начал пытаться использовать QuantLib для определения цены опциона и изменил код из другого вопроса на форуме для своих целей, но возвращенный OAS отрицательный, и я не уверен, как вернуть цену опциона сам по себе. Я включил код ниже. Мы будем очень признательны за любую помощь.
Примечание. Нулевая кривая взята из кривой BVAL STRIPS.

Код: Выделить всё

import QuantLib as ql
import numpy as np
import pandas as pd

bf = ql.BondFunctions
qd = ql.DateParser.parseFormatted

# Conventions
accrual_convention = ql.Unadjusted
Rule = ql.DateGeneration.Backward
endofMonth = False
firstDate = None

#OAS
compounding = ql.Simple
frequency = ql.Once

calendar = ql.UnitedStates(ql.UnitedStates.NYSE)

a = 0.03
sigma = 0.27
grid_points = 100
face_amount = 100
mkt_price = 100

contract = {
'IssueDate': ql.Date(3,7,2024),
'MaturityDate': ql.Date(5,7,2029),
'SettlementDays': 2,
'RealValue': 0.0575,
'FirstCallDate': ql.Date(5,7,2025),
'OptionalityEndDate': ql.Date(5,7,2029),
'OperatingCountry': 'US',
'StrikeDate': [ql.Date(5,7,2025), ql.Date(5, 7,2026), ql.Date(5,7,2027), ql.Date(5,7,2028), ql.Date(5,7,2029)],
'OptionalityType': ['Call', 'Call', 'Call', 'Call', 'Call'],
'NoticeDays': [5, 5, 5, 5],
'StrikePrice':  [105.75, 111.5, 117.25, 123, 128.75]}

# Here is the zero curve:

times= np.array([ '0 MO', '3 MO', '6 MO', '1 YR', '2 YR', '3 YR',
'5 YR', '7 YR', '10 YR', '20 YR', '30 YR'], dtype=object)

dates = [
ql.Date(17,7, 2024), ql.Date(17,10,2024),ql.Date(17,1,2025), ql.Date(17,7,2025),
ql.Date(17,7,2026),ql.Date(17,7,2027), ql.Date(17,7,2029),
ql.Date(17,7,2031), ql.Date(17,7,2034),ql.Date(17,7,2044),
ql.Date(17,7,2054)]

rates = np.array([ 0.0533, 0.05699 , 0.05630 ,
0.05395  , 0.04865  , 0.04638 , 0.04528 , 0.04615  ,
0.04796  , 0.05055 , 0.04951 ])

day_count = ql.ActualActual(ql.ActualActual.ISDA)
calc_date = ql.Date(16,7,2024)
ql.Settings.instance().evaluationDate = calc_date

issue_date = contract["IssueDate"]
maturity_date = contract["MaturityDate"]
tenor = ql.Period(ql.Annual)

coupon = contract["RealValue"]
settlement_days = contract["SettlementDays"]

# Determine Schedule
schedule = ql.Schedule(issue_date,
maturity_date,
tenor,
calendar,
accrual_convention,
accrual_convention,
Rule,
endofMonth)

# Initiate Zero Curve
curve = ql.ZeroCurve(dates,
rates,
ql.ActualActual(ql.ActualActual.ISDA),
calendar,
ql.Linear())
curve.enableExtrapolation()
ts_handle = ql.YieldTermStructureHandle(curve)

def get_call_schedule(df, period=ql.Period(ql.Annual)):
dates = df["StrikeDate"]
prices = df["StrikePrice"]
callability_schedule = ql.CallabilitySchedule()
null_calendar = ql.NullCalendar()
call_date = df["StrikeDate"][0]
for time in range(len(df["StrikeDate"])):
callability_price  = ql.BondPrice(prices[time],
ql.BondPrice.Clean)
callability_schedule.append(ql.Callability(callability_price,
ql.Callability.Call,
dates[time]))
call_date = null_calendar.advance(call_date, period)
return callability_schedule

callability_schedule = get_call_schedule(contract)

bond = ql.CallableFixedRateBond(settlement_days,
face_amount,
schedule,
[coupon],
day_count,
ql.Following,
face_amount,
calc_date,
callability_schedule)

def value_bond(a, s, ts_handle, grid_points, bond):
model = ql.HullWhite(ts_handle, a, s)
engine = ql.TreeCallableFixedRateBondEngine(model, grid_points)
bond.setPricingEngine(engine)
return bond

bondprice = value_bond(a, sigma, ts_handle, grid_points, bond)
OAS = bondprice.OAS(mkt_price,
ts_handle,
day_count, compounding, frequency)
bond_yield = bondprice.bondYield(mkt_price,
day_count,
compounding,
frequency)

print(OAS)
print(bond_yield)
print(bondprice)
Пыталась найти OAS отзывной ноты, но вернула отрицательное число. Я хотел бы найти цену опциона, ожидаемую дату отзыва на основе модели процентных ставок, а также OAS.

Подробнее здесь: https://stackoverflow.com/questions/787 ... lable-note

Вернуться в «Python»