using System.Collections.Generic;
public static void Main()
var amorTable = new AmortizationTable(1000000, 0.045m, 30, 12, DateTime.Parse("2021-09-01"));
public class AmortizationTable {
public decimal LoanAmount { get; }
public decimal AnnualInterestRate { get; }
public int LoanTermInYears { get; }
public int PaymentsPerYear { get; }
public DateTime LoanStartDate { get; }
public int LoanTermInMonths => LoanTermInYears * 12;
public decimal MonthlyInterestRate => AnnualInterestRate / 12;
public decimal MonthlyPayment => Decimal.Round((MonthlyInterestRate * LoanAmount) / (1 - (decimal)Math.Pow((double)(1 + MonthlyInterestRate), -LoanTermInMonths)), 2);
public IList<AmortizationEntry> Table { get; }
public AmortizationTable(decimal loanAmount, decimal annualInterestRate, int loanTermInYears, int paymentsPerYear, DateTime loanStartDate) {
Table = new List<AmortizationEntry>();
AnnualInterestRate = annualInterestRate;
LoanTermInYears = loanTermInYears;
PaymentsPerYear = paymentsPerYear;
LoanStartDate = loanStartDate;
public void Calculate() {
var firstEntry = new AmortizationEntry(1, LoanStartDate.AddMonths(1), MonthlyInterestRate, LoanAmount, MonthlyPayment);
for (int i = 2; i <= LoanTermInMonths; i++) {
var lastEntry = Table.Last();
var newEntry = new AmortizationEntry(i, lastEntry.PaymentDate.AddMonths(1), MonthlyInterestRate, lastEntry.EndingBalance, MonthlyPayment);
Console.WriteLine($"Interest Rates: {AnnualInterestRate:P4} ({AnnualInterestRate}) / {MonthlyInterestRate:P4} ({MonthlyInterestRate})");
Console.WriteLine($"Loan Terms: {LoanTermInYears} / {LoanTermInMonths}");
Console.WriteLine($"Monthly Payment: {MonthlyPayment:C}");
Console.WriteLine($"Payment Date Monthly Principal Interest Balance");
foreach(var entry in Table) {
Console.WriteLine($"{entry.PaymentNumber,7} {(entry.PaymentDate.ToString("MMM/yyyy")),-8} {entry.PaymentAmount,-10:C} {entry.Principal,-10:C} {entry.Interest,-10:C} {entry.EndingBalance:C}");
public class AmortizationEntry {
public int PaymentNumber { get; }
public DateTime PaymentDate { get; }
public decimal MonthlyInterestRate { get; }
public decimal StartingBalance { get; }
public decimal PaymentAmount { get; }
public decimal Principal => PaymentAmount - Interest;
public decimal Interest => StartingBalance * MonthlyInterestRate;
public decimal EndingBalance => StartingBalance - Principal;
public AmortizationEntry(int paymentNumber, DateTime paymentDate, decimal monthlyInterestRate, decimal startingBalance, decimal paymentAmount) {
PaymentNumber = paymentNumber;
PaymentDate = paymentDate;
MonthlyInterestRate = monthlyInterestRate;
StartingBalance = startingBalance;
PaymentAmount = paymentAmount > (StartingBalance + Interest) ? (StartingBalance + Interest) : paymentAmount;