Skip to contents

Builds an amortization schedule under a fixed annual interest-rate specification, allowing extra principal payments and optional adjustment of either the remaining term or the remaining payment amount.

Usage

amort_schedule(
  principal,
  n,
  i,
  i_type = "effective",
  m = 1L,
  k = 1L,
  timing = c("immediate", "due"),
  payment = NULL,
  extra_principal = NULL,
  adjust = c("none", "term", "payment"),
  tol = 1e-08
)

Arguments

principal

Numeric scalar. Initial outstanding balance.

n

Positive integer. Number of contractual periods.

i

Numeric scalar. Annual interest-rate input.

i_type

Character string indicating the annual interest-rate type: "effective", "nominal_interest", "nominal_discount", or "force".

m

Positive integer. Conversion frequency for nominal annual rates.

k

Positive integer. Number of amortization periods per year.

timing

Character string. One of "immediate" or "due".

payment

Optional numeric scalar. Initial regular payment per period. If NULL, it is computed from the loan data.

extra_principal

Optional extra principal payments. Can be:

  • NULL,

  • a scalar,

  • an unnamed numeric vector of length n,

  • a named numeric vector with names interpreted as period numbers.

adjust

Character string. One of "none", "term", or "payment".

tol

Finite positive numeric tolerance in monetary units for zero-balance detection.

Value

A tibble with one row per realized period and columns:

period

Period index.

ob_start

Outstanding balance at the start of the period.

interest

Interest charged during the period.

payment

Regular payment in the period.

extra_principal

Extra principal paid in the period.

principal

Principal repaid through the regular payment.

total_principal

Total principal repaid in the period.

cashflow

Total payment made in the period.

ob_end

Outstanding balance at the end of the period.

i_effective_annual

Equivalent annual effective rate.

i_effective_period

Equivalent effective rate per schedule period.

k

Schedule frequency.

timing

Payment timing convention.

adjust

Adjustment rule used.

Details

The annual rate is converted internally to an effective rate per schedule period using k.

Adjustment policies after extra principal payments:

  • "none": keep the original payment and contractual term, unless the loan is fully repaid early.

  • "term": keep the regular payment and shorten the term. No special logic is needed: the loop exits naturally when the outstanding balance reaches zero.

  • "payment": keep the remaining contractual term and recalculate the regular payment after each period.

The original log accumulation rate determines the effective period rate and the level payment, avoiding cancellation near zero and saturation of the annual equivalent. The periodic rate must remain finite and greater than -1. The balance tolerance is in monetary units and does not classify nonzero interest rates as zero. Here n counts periods, so the contractual term in years is n / k.

This function follows the compact actuarial notation used throughout tidyactuarial: i is the interest rate, i_type is the interest-rate type, m is the conversion frequency for nominal annual rates, and k is the number of amortization periods per year.

For timing = "immediate" (annuity-immediate), interest accrues on the outstanding balance during the period, and the payment is made at the end. For timing = "due" (annuity-due), the payment is made at the start of the period and interest accrues on the balance after the payment.

If the user supplies a custom payment that is smaller than the periodic interest, principal repayment will be negative (negative amortization). This is permitted but the user should be aware.

Named extra payments must identify exact integer periods; repeated names are summed. On a payoff row, requested extra principal has priority and the regular payment is reduced to the remaining amount due. Interest still follows the selected timing, and no rows follow full payoff. The general schedule uses a different allocation priority; see amort_schedule_general.

With adjust = "payment", the payment is recalculated after every realized period for the remaining contractual periods, even if no extra payment occurred. A supplied payment is the initial payment. The "none" and "term" policies keep the regular amount; both stop when the debt is repaid and may realize fewer than n rows. A requested loan below tol may produce an empty schedule. Calculated payments for active balances must be representable and positive; non-finite monetary ledger entries cause an explicit error. This does not require a representable displayed annual effective equivalent. The schedule allocates up to n rows; feasible terms are limited by integer indexing and available memory.

Examples

amort_schedule(
  principal = 100000,
  n = 12,
  i = 0.12,
  i_type = "nominal_interest",
  m = 12,
  k = 12
)
#> # A tibble: 12 × 14
#>    period ob_start interest payment extra_principal principal total_principal
#>     <int>    <dbl>    <dbl>   <dbl>           <dbl>     <dbl>           <dbl>
#>  1      1  100000    1000     8885.               0     7885.           7885.
#>  2      2   92115.    921.    8885.               0     7964.           7964.
#>  3      3   84151.    842.    8885.               0     8043.           8043.
#>  4      4   76108.    761.    8885.               0     8124.           8124.
#>  5      5   67984.    680.    8885.               0     8205.           8205.
#>  6      6   59779.    598.    8885.               0     8287.           8287.
#>  7      7   51492.    515.    8885.               0     8370.           8370.
#>  8      8   43122.    431.    8885.               0     8454.           8454.
#>  9      9   34668.    347.    8885.               0     8538.           8538.
#> 10     10   26130.    261.    8885.               0     8624.           8624.
#> 11     11   17507.    175.    8885.               0     8710.           8710.
#> 12     12    8797.     88.0   8885.               0     8797.           8797.
#> # ℹ 7 more variables: cashflow <dbl>, ob_end <dbl>, i_effective_annual <dbl>,
#> #   i_effective_period <dbl>, k <int>, timing <chr>, adjust <chr>

amort_schedule(
  principal = 100000,
  n = 24,
  i = 0.12,
  i_type = "nominal_interest",
  m = 12,
  k = 12,
  extra_principal = c("6" = 5000, "12" = 3000),
  adjust = "term"
)
#> # A tibble: 23 × 14
#>    period ob_start interest payment extra_principal principal total_principal
#>     <int>    <dbl>    <dbl>   <dbl>           <dbl>     <dbl>           <dbl>
#>  1      1  100000     1000    4707.               0     3707.           3707.
#>  2      2   96293.     963.   4707.               0     3744.           3744.
#>  3      3   92548.     925.   4707.               0     3782.           3782.
#>  4      4   88766.     888.   4707.               0     3820.           3820.
#>  5      5   84947.     849.   4707.               0     3858.           3858.
#>  6      6   81089.     811.   4707.            5000     3896.           8896.
#>  7      7   72192.     722.   4707.               0     3985.           3985.
#>  8      8   68207.     682.   4707.               0     4025.           4025.
#>  9      9   64182.     642.   4707.               0     4066.           4066.
#> 10     10   60116.     601.   4707.               0     4106.           4106.
#> # ℹ 13 more rows
#> # ℹ 7 more variables: cashflow <dbl>, ob_end <dbl>, i_effective_annual <dbl>,
#> #   i_effective_period <dbl>, k <int>, timing <chr>, adjust <chr>

amort_schedule(
  principal = 100000,
  n = 24,
  i = 0.12,
  i_type = "nominal_interest",
  m = 12,
  k = 12,
  extra_principal = c("6" = 5000, "12" = 3000),
  adjust = "payment"
)
#> # A tibble: 24 × 14
#>    period ob_start interest payment extra_principal principal total_principal
#>     <int>    <dbl>    <dbl>   <dbl>           <dbl>     <dbl>           <dbl>
#>  1      1  100000     1000    4707.               0     3707.           3707.
#>  2      2   96293.     963.   4707.               0     3744.           3744.
#>  3      3   92548.     925.   4707.               0     3782.           3782.
#>  4      4   88766.     888.   4707.               0     3820.           3820.
#>  5      5   84947.     849.   4707.               0     3858.           3858.
#>  6      6   81089.     811.   4707.            5000     3896.           8896.
#>  7      7   72192.     722.   4402.               0     3681.           3681.
#>  8      8   68512.     685.   4402.               0     3717.           3717.
#>  9      9   64795.     648.   4402.               0     3754.           3754.
#> 10     10   61040.     610.   4402.               0     3792.           3792.
#> # ℹ 14 more rows
#> # ℹ 7 more variables: cashflow <dbl>, ob_end <dbl>, i_effective_annual <dbl>,
#> #   i_effective_period <dbl>, k <int>, timing <chr>, adjust <chr>