The following example illustrates creating a loan repayment plan using R and Python.

Loan inputs:

#loan amount
amount <- 5000
#maturity (in months)
maturity <- 18
#yearly interest rate
ir.y <- 0.0649
#monthly interest rate
ir.m <- ir.y / 12

User-defined function that generates the loan repayment plan:

create.repayment.plan <- function(p, r, m) {
      #p - loan amount
      #r - monthly interest rate
      #m - loan maturity in months

      #annuity
      annuity <- p * r / (1 - (1 + r)^(-m))
      #prepare the repayment plan data frame
      rp <- data.frame(month = 1:m,  
                       remaining.principal = NA,
                       monthly.principal = NA,  
                       monthly.interest = NA,
                       annuity = rep(annuity, m))
      #assign the loan amount as a starting principal
      rp$remaining.principal[1] <- p
      #construct the repaymen plan
      for   (i in 1:m) {
            if    (i == m) {
                  rp$monthly.principal[i] <- rp$remaining.principal[i]
                  rp$monthly.interest[i] <- rp$annuity[i] - 
                                            rp$monthly.principal[i]
                  } else {
                  rp$monthly.interest[i] <- rp$remaining.principal[i] * r
                  rp$monthly.principal[i] <- rp$annuity[i] - 
                                             rp$monthly.interest[i]
                  rp$remaining.principal[i + 1] <- rp$remaining.principal[i] - 
                                                   rp$monthly.principal[i]
                  }
            }
return(rp)
}

Loan repayment plan:

rp <- create.repayment.plan(p = amount, 
                            r = ir.m, 
                            m = maturity)
rp
##    month remaining.principal monthly.principal monthly.interest  annuity
## 1      1           5000.0000          265.2262        27.041667 292.2678
## 2      2           4734.7738          266.6606        25.607235 292.2678
## 3      3           4468.1132          268.1028        24.165046 292.2678
## 4      4           4200.0104          269.5528        22.715056 292.2678
## 5      5           3930.4576          271.0106        21.257225 292.2678
## 6      6           3659.4470          272.4763        19.791509 292.2678
## 7      7           3386.9707          273.9500        18.317866 292.2678
## 8      8           3113.0207          275.4316        16.836254 292.2678
## 9      9           2837.5891          276.9212        15.346628 292.2678
## 10    10           2560.6679          278.4189        13.848946 292.2678
## 11    11           2282.2490          279.9247        12.343163 292.2678
## 12    12           2002.3243          281.4386        10.829237 292.2678
## 13    13           1720.8857          282.9607         9.307124 292.2678
## 14    14           1437.9250          284.4911         7.776778 292.2678
## 15    15           1153.4339          286.0297         6.238155 292.2678
## 16    16            867.4042          287.5766         4.691211 292.2678
## 17    17            579.8276          289.1319         3.135901 292.2678
## 18    18            290.6957          290.6957         1.572179 292.2678
#check net present value of the cash flow
sum(rp$annuity / ((1 + ir.m)^(1:maturity)))
## [1] 5000

Annuity structure: An alternative approach is available for those seeking a more advanced solution that offers precise values for the remaining principal, principal, and interest portion in an annuity at a certain period. The subsequent code demonstrates the calculation of the principal portion in the annuity for the 5th month. The remaining steps in the repayment plan calculation are straightforward and are left for the reader to complete.

#annuity 
a <-  amount * ir.m / (1 - (1 + ir.m)^(-maturity))
#define the nth period
n <- 5
#principal portion in the annuity at the 5th period
(a - amount * ir.m) * ((1 + ir.m)^(n - 1))
## [1] 271.0106

Loan repayment plan in Python:

import pandas as pd
import numpy as np

#input parameters
#loan amount
amount = 5000
#maturity (in months)
maturity = 18
#yearly interest rate
ir_y = 0.0649
#monthly interest rate
ir_m = ir_y / 12

#loan repayment function
def create_repayment_plan(p, r, m): 
    #p - loan amount
    #r - monthly interest rate
    #m - loan maturity in months
    
    #annuity
    annuity = p * r / (1 - (1 + r)**(-m))
    #prepare the repayment plan data frame
    rp = pd.DataFrame({"month" : [*range(1, m + 1)],  
                       "remaining_principal" : [None]*m,
                       "monthly_principal" : [None]*m,  
                       "monthly_interest" : [None]*m,
                       "annuity" : [annuity]*m
                      })
    #assign loan amount as a starting principal
    rp.loc[0, "remaining_principal"] = p
    #construct the repaymen plan
    for i in rp.index: 
        if (i == rp.index[-1]): 
            rp.loc[i, "monthly_principal"] = rp.remaining_principal[i]
            rp.loc[i, "monthly_interest"] = rp.annuity[i] - \
                                            rp.monthly_principal[i]
        else:
            rp.loc[i, "monthly_interest"] = rp.remaining_principal[i] * r
            rp.loc[i, "monthly_principal"] = rp.annuity[i] - \
                                             rp.monthly_interest[i]
            rp.loc[i + 1, "remaining_principal"] = rp.remaining_principal[i] - \
                                                   rp.monthly_principal[i]
    return(rp)

    
#create repayment plan
rp = create_repayment_plan(p = amount, 
                           r = ir_m, 
                           m = maturity)
rp
##     month remaining_principal monthly_principal monthly_interest     annuity
## 0       1                5000        265.226177        27.041667  292.267843
## 1       2         4734.773823        266.660608        25.607235  292.267843
## 2       3         4468.113215        268.102798        24.165046  292.267843
## 3       4         4200.010417        269.552787        22.715056  292.267843
## 4       5          3930.45763        271.010618        21.257225  292.267843
## 5       6         3659.447012        272.476334        19.791509  292.267843
## 6       7         3386.970678        273.949977        18.317866  292.267843
## 7       8         3113.020701         275.43159        16.836254  292.267843
## 8       9         2837.589112        276.921216        15.346628  292.267843
## 9      10         2560.667896        278.418898        13.848946  292.267843
## 10     11         2282.248998         279.92468        12.343163  292.267843
## 11     12         2002.324318        281.438606        10.829237  292.267843
## 12     13         1720.885712         282.96072         9.307124  292.267843
## 13     14         1437.924992        284.491066         7.776778  292.267843
## 14     15         1153.433927        286.029688         6.238155  292.267843
## 15     16          867.404239        287.576632         4.691211  292.267843
## 16     17          579.827607        289.131942         3.135901  292.267843
## 17     18          290.695664        290.695664         1.572179  292.267843
#check net present value of the cash flow
np.sum(rp["annuity"] / (1 + ir_m) ** np.arange(1, maturity + 1))
## 5000.000000000088
#annuity
a = amount * ir_m / (1 - (1 + ir_m)**(-maturity))
#define the nth period
n = 5
#principal portion in the annuity at the nth period
(a - amount * ir_m) * ((1 + ir_m)**(n - 1))
## 271.0106182999124