Computes the level annual coupon rate that makes a bond's time-zero dirty
price equal to its face value, using the spot discount factors at each
coupon date. Unlike bond_ytm(), it does not solve for a flat yield.
Usage
par_rate(
.data = NULL,
t = NULL,
i = NULL,
n = NULL,
face = 100,
k = 1L,
R = NULL,
i_type = "effective",
m = 1L,
col_t = "t",
col_i = "i",
tol = 1e-10
)Arguments
- .data
Optional data frame containing a spot curve as numeric columns, or multiple curves as list-columns. For pipe-friendly usage.
- t
Numeric vector of curve maturities (years) when
.data = NULL.- i
Numeric vector of observed spot rates when
.data = NULL.- n
Bond maturity in years. Defaults to the maximum maturity of each curve; may also be a scalar or one value per curve.
- face
Strictly positive face value; scalar or one value per curve.
- k
Positive integer coupon frequency per year; scalar or one value per curve. Coupon dates are
seq_len(n * k) / k.- R
Redemption amount, scalar or one value per curve; defaults to
face.- i_type
Spot rate type (
"effective","nominal_interest","nominal_discount", or"force"). Passed todiscount_factor_spot(). Must have length one or one value per curve node.- m
Conversion frequency for nominal spot rates, passed to
discount_factor_spot(). Must have length one or one per curve node.- col_t
Name of the spot maturity column in
.data.- col_i
Name of the spot rate column in
.data.- tol
Positive numerical tolerance for aligning coupon dates and curve maturities. Does not authorize interpolation.
Value
One tibble row per curve, containing the supplied curve columns
and n, face, k, R, annuity_factor, v_n, c_par,
coupon_per_period, repriced_price, and repricing_error.
The c_par value is the nominal annual coupon rate as a proportion;
coupon_per_period is its monetary coupon amount. repricing_error
is the reconstructed dirty price minus the face value.
Details
For a bond with face value \(F > 0\), redemption \(R\), term \(n\), and \(k\) coupon payments per year, the price equation is $$P = (F c/k) \sum_{j=1}^{nk} v(j/k) + R v(n).$$ Setting the dirty price \(P = F\) and solving for the nominal annual coupon rate gives $$c_{par} = k [F - R v(n)] / [F \sum_{j=1}^{nk} v(j/k)].$$ When redemption equals face value, this reduces to $$c_{par} = k [1 - v(n)] / \sum_{j=1}^{nk} v(j/k).$$
Spot inputs use annual effective rates by default, with
\(v(t) = (1 + i_t)^{-t}\). Other supported interest conventions are
converted using discount_factor_spot(). The calculation uses only
observed nodes: every coupon date must match one curve maturity; there is
no interpolation or extrapolation. Small floating-point discrepancies
within tol are accepted as identical dates.
Input can be (1) numeric vectors t and i, (2) a data frame with
numeric t and i columns, such as bootstrap_spot_curve() output, or
(3) a tibble with t and i list-columns, such as yield_curve() output.
In the third form each row describes one curve, and the input columns are
retained. n, face, k, and R may be scalars or have one value per
curve. For a single curve, n = NULL uses the largest observed maturity.
A coupon rate can be negative when the implied financial terms require it;
the function does not impose a contractual zero floor.
This model assumes regular coupons paid in arrears, no stub periods,
no accrued interest, and a deterministic redemption at maturity.
Calculation separates the dimensionless rate from monetary amounts and uses
the original log spot growth at maturity to retain small coupon rates.
Final amounts and the positive coupon discount sum must be representable.
repricing_error reports the floating-point price discrepancy; extreme
cancellation, especially with negative coupons, can still limit precision.
Examples
# An annual-pay bond whose spot curve was obtained from market prices.
curve <- tibble::tibble(
t = c(1, 2, 3),
i = c(0.04, 0.045, 0.05)
)
curve |> par_rate(face = 100, k = 1)
#> # A tibble: 1 × 12
#> t i n face k R annuity_factor v_n c_par
#> <list> <list> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 <dbl [3]> <dbl [3]> 3 100 1 100 2.74 0.864 0.0497
#> # ℹ 3 more variables: coupon_per_period <dbl>, repriced_price <dbl>,
#> # repricing_error <dbl>
# A two-year bond with semiannual coupons: spot nodes every six months.
par_rate(
t = c(0.5, 1, 1.5, 2),
i = rep(0.04, 4),
n = 2,
k = 2
)
#> # A tibble: 1 × 12
#> t i n face k R annuity_factor v_n c_par
#> <list> <list> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 <dbl [4]> <dbl [4]> 2 100 2 100 3.81 0.925 0.0396
#> # ℹ 3 more variables: coupon_per_period <dbl>, repriced_price <dbl>,
#> # repricing_error <dbl>
# A one-row curve returned by yield_curve() is also accepted.
yield_curve(t = 1:3, i = c(0.04, 0.045, 0.05)) |>
par_rate()
#> # A tibble: 1 × 14
#> t i v i_effective n face k R annuity_factor v_n
#> <list> <lis> <lis> <list> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 <int [3]> <dbl> <dbl> <dbl [3]> 3 100 1 100 2.74 0.864
#> # ℹ 4 more variables: c_par <dbl>, coupon_per_period <dbl>,
#> # repriced_price <dbl>, repricing_error <dbl>