Por lo que entiendo, el precio sucio es la suma del precio limpio y el monto devengado y debe ser igual al Valor Presente (PV) de un bono a cierta tasa de rendimiento. Sin embargo, no puedo replicar este comportamiento en QuantLib-python (1.31.1) ya que los valores son diferentes utilizando la misma tasa de interés.
Código:
from datetime import date
import QuantLib as ql
# Define bond parameters
face_value = 1000
issue_date = ql.Date(27, 6, 2023)
coupon_rate = 0.05 # Tasa de cupón anual (5%)
frequency = ql.Semiannual
day_count = ql.ActualActual(ql.ActualActual.ISMA)
# Crear el calendario de bonos
dates = [issue_date.to_date(), date(2023, 12, 27), date(2024, 6, 27), date(2024, 12, 27), date(2025, 6, 27), date(2025, 12, 27), date(2026, 6, 27),
date(2026, 12, 27), date(2027, 6, 27), date(2027, 12, 27), date(2028, 6, 27), date(2028, 12, 27), date(2029, 6, 27)]
dates = [ql.Date(d.day, d.month, d.year) for d in dates]
schedule = ql.Schedule(dates)
# Crear el bono
bond = ql.FixedRateBond(0, face_value, schedule, [coupon_rate], day_count)
# Valoraciones
val_date = ql.Date(14,9,2023)
yield_rate_value = 0.05
yield_rate = ql.InterestRate(yield_rate_value, day_count, ql.Compounded, frequency)
pv = sum([c.amount()*yield_rate.discountFactor(val_date, c.date()) for c in bond.cashflows()])
clean_price = ql.BondFunctions.cleanPrice(bond, yield_rate, val_date)
accrued_amount = ql.BondFunctions.accruedAmount(bond, val_date)
dirty_price = clean_price + accrued_amount
print('Precio limpio:', clean_price)
print('Días devengados:', ql.BondFunctions.accruedDays(bond, val_date))
print('Período devengado:', ql.BondFunctions.accruedPeriod(bond, val_date))
print('Días de devengo:', ql.BondFunctions.accrualDays(bond, val_date))
print('Período de devengo:', ql.BondFunctions.accrualPeriod(bond, val_date))
print('Monto devengado:', accrued_amount)
print('Precio sucio:', dirty_price)
print('Valor presente:', pv*100/face_value)
import pandas as pd
print(pd.DataFrame([(c.date().to_date().isoformat(), c.amount(), yield_rate.discountFactor(val_date, c.date()), c.amount()*yield_rate.discountFactor(val_date, c.date()))
for c in bond.cashflows()]))
Salida del Terminal:
Precio limpio: 99.99243192098663
Días devengados: 79
Período devengado: 0.21584699453551912
Días de devengo: 183
Período de devengo: 0.5
Monto devengado: 1.0792349726775896
Precio sucio: 101.07166689366423
Valor presente: 101.24228365658294
0 1 2 3
0 2023-12-27 25.0 0.987730 24.693240
1 2024-06-27 25.0 0.963639 24.090966
2 2024-12-27 25.0 0.940135 23.503381
3 2025-06-27 25.0 0.917205 22.930128
4 2025-12-27 25.0 0.894834 22.370857
5 2026-06-27 25.0 0.873009 21.825226
6 2026-12-27 25.0 0.851716 21.292903
7 2027-06-27 25.0 0.830943 20.773564
8 2027-12-27 25.0 0.810676 20.266892
9 2028-06-27 25.0 0.790903 19.772578
10 2028-12-27 25.0 0.771613 19.290320
11 2029-06-27 25.0 0.752793 18.819824
12 2029-06-27 1000.0 0.752793 752.792958