Estoy empezando a familiarizarme con QuantLib (en particular, con las funciones de fijación de precios de los bonos a tipo fijo). He leído una serie de ejemplos, a partir de los cuales soy capaz de calcular el precio y el rendimiento de los bonos.
El siguiente script utiliza un rendimiento de entrada (0,057154825761367800000) para calcular el precio del bono (96,9073930899788536), utilizando bond.cleanPrice.
A continuación, tomé el precio del bono calculado y lo introduje de nuevo en el cálculo de bond.bondYield (sin cambiar el resto de datos de entrada), esperando obtener el rendimiento de entrada original.
He comprobado que el rendimiento calculado a posteriori se aproxima, pero no tanto como yo esperaba ingenuamente (coincide con 8 decimales). ¿He hecho algo mal? ¿Es esta precisión aceptable basada en las iteraciones máximas del solucionador numérico? ¿Algo más?
import QuantLib as ql
def calculate_bond_price():
settlementDays = 0
faceValue = 100
issueDate = ql.Date(11, 2, 2020)
maturityDate = ql.Date(11, 2, 2025)
tenor = ql.Period(ql.Quarterly)
calendar = ql.NullCalendar()
businessConvention = ql.Following
dateGeneration = ql.DateGeneration.Backward
monthEnd = False
schedule = ql.Schedule (issueDate, maturityDate, tenor, calendar, businessConvention, businessConvention, dateGeneration, monthEnd)
coupon_rate = 0.05
coupons = [coupon_rate]
dayCount = ql.Thirty360()
bond = ql.FixedRateBond(settlementDays, faceValue, schedule, coupons, dayCount)
## manually specify a yield rate to 16 decimal places
## this is the value I expect to get back from bond.bondYield calculation
yield_rate = 0.057154825761367800000
bond_price = bond.cleanPrice(yield_rate, dayCount, ql.Simple, ql.Quarterly)
print(f'PRICE >> calculated={bond_price:20,.16f}')
# OUTPUTS: PRICE >> calculated= 96.9073930899788536
# feed the calculated bond price back into a bond.bondYield calculation with exact same (dayCount, Simple, Quarterly) inputs
# expect to get back the yield_rate (16 decimal); but only match to 8 decimals
back_calculate_bond_yield = bond.bondYield(bond_price, dayCount, ql.Simple, ql.Quarterly)
print(f'YIELD >> calculated={back_calculate_bond_yield:20,.16f} | expected={yield_rate:20,.16f} | diff={back_calculate_bond_yield-yield_rate:20,.16f}')
# OUTPUTS: YIELD >> calculated= 0.0571548314094543 | expected= 0.0571548257613678 | diff= 0.0000000056480865
if __name__ == '__main__':
calculate_bond_price()
0 votos
En mi opinión, igualar más allá de 8 decimales parece absolutamente irrelevante desde el punto de vista económico.
3 votos
@skoestlmeier - en la vida real, sí. Pero mostrando una coincidencia "perfecta" será más fácil convencer a Vetting de que mi código hace lo que debe.