Hay muchas cosas mal aquí:
- WSJ no parece mostrar las citas correctamente. Según el sitio web, Tullett Prebon es la fuente. Tullett es un broker muy reputado con datos de alta calidad. Lo más probable es que las comillas se reciban siguiendo la norma del mercado, que consiste en cotizar en 1/32. Cuando hizo la pregunta, la comilla era 98-25+, lo que equivale a 98 + 25/32 + 1/64 ~98,7968.
- Tu recuento de días es erróneo porque necesitas utilizar ACT/ACT y el periodo del último pago del cupón es de sólo 181 días.
- La forma en que resuelves el YTM tampoco es como suele funcionar. Generalmente, VAN = flujo de caja / (1+ytm*dcf), donde dcf significa fracción de recuento diario y VAN es el valor actual neto (el precio actual del bono).
A continuación figura una captura de pantalla de Bloomberg YAS
el día que hiciste la pregunta. Utilizo el precio de oferta porque mi YAS
está configurado por defecto para pujar. No hay ninguna diferencia de cálculo.
A continuación, reproduciré el cálculo en Julia . No es necesario conocer el idioma. He utilizado nombres similares a los de la pantalla de Bloomberg y el código consiste principalmente en expresiones "matemáticas". El código relevante está en 3 secciones:
- En primer lugar, calculo todas las fechas relevantes y las fracciones de recuento de días.
- En segundo lugar, se calcula el precio limpio, los intereses devengados y el precio sucio
- Por último, se utiliza ytm para mostrar que el valor final es efectivamente el resultado de precio sucio * ytm (ajustado para el recuento de días adecuado). Yo calculo manualmente YTM y muestro que la lógica que el OP utiliza para calcular YTM se llama Equiv 1/año en Bloomberg. Sin embargo, no es el rendimiento calculado convencionalmente para los bonos del Tesoro.
En general, los cálculos de rendimiento suelen depender de muchos detalles y, por ejemplo, las letras del Tesoro se calculan de forma diferente, como puede verse aquí .
Todo a partir de #combinar resultados en una tabla puede ignorarse, ya que simplemente prepara los datos en un formato legible.
# import relevant tables
using Dates, DataFrames, PrettyTables
# compute dates
today = Date(2023,02,08)
accrued_days = Day(86)
start = today - accrued_days
settle_date = Date(2023,05,15)
days_to_settle = Day(1)
coupon_date = settle_date-days_to_settle
days_to_next_coupon = coupon_date - today
accrued_days_between_coupon = coupon_date - start
dcf_next_coupon = (days_to_next_coupon/accrued_days_between_coupon)/2
dcf_accrued = accrued_days/accrued_days_between_coupon/2
# compute clean price, accrued interest and dirty price
price_clean = 98+25/32+1/64
accrued = dcf_accrued*(1/8)
price_dirty = price_clean + accrued
# ytm as quoted
ytm = 4.765459
# final cashflow (notional plus interest)
final_cashflow = 100 + (1/8)/2
# compute final cashflow based on ytm
final_cf_computed = round(price_dirty*(1+ytm/100*(dcf_next_coupon)), digits = 6)
# compute YTM
ytm_computed = (final_cash_flow/price_dirty - 1)/(yf)*200
op_logic = ((final_cash_flow/price_dirty)^(1/(yf/2))-1)*100
# combine results in a table
yield_comp = ["Price and Yield", "Price Clean", "Accrued Interest", "Price Dirty", "Final Cashflow", "Yield to Maturity (YTM)", "Final Cashflow according to YTM", "YTM computed", "Equiv 1/Yr (OP Logic)"]
yields = ["",price_clean, accrued, price_dirty, final_cashflow, ytm, final_cf_computed, ytm_computed, op_logic]
text = ["Dates", "Today", "Coupon Date", "Days To Next Coupon", "Coupon Start Date", "Accrued Days between coupons", "Daycount Fraction Accrued","Daycount Fraction next coupon" ]
date_vals = ["", today, coupon_date, days_to_next_coupon, start, accrued_days_between_coupon, dcf_accrued , dcf_next_coupon]
df_res = DataFrame(Fields = append!(text, yield_comp), Values = append!(date_vals, yields) )
# pretty print
hl_1 = Highlighter((data,i,j) -> data[i,1] == "Dates", crayon"bg:dark_gray white bold")
hl_2 = Highlighter((data,i,j) -> data[i,1] == "Price and Yield", crayon"bg:dark_gray white bold")
PrettyTables.pretty_table(df_res, border_crayon = Crayons.crayon"blue", header_crayon = Crayons.crayon"bold green", formatters = ft_printf("%.6f", [2]), highlighters = (hl_1, hl_2))