ArtyomPanfutov / loan-amortization-calculator

A light-weight library that allows calculating annual loan amortization schedule with a capability of setting early (additional) payments.
MIT License
11 stars 6 forks source link

Monthly Principal and Interest amounts are wrong. #44

Open juanjoaquino05 opened 2 years ago

juanjoaquino05 commented 2 years ago

I compared the outputs with other calculators and the values provided doesn't match.

input: { "principal" : 100000, "interestRate" : 6, "periods" : 12 }

output: { "monthlyPaymentAmount": 8606.64, "overPaymentAmount": 3284.81, "monthlyPayments": [ { "monthNumber": 0, "loanBalanceAmount": 100000.0, "debtPaymentAmount": 8113.49, "interestPaymentAmount": 493.15, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2022-07-24" }, { "monthNumber": 1, "loanBalanceAmount": 91886.51, "debtPaymentAmount": 8138.40, "interestPaymentAmount": 468.24, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2022-08-24" }, { "monthNumber": 2, "loanBalanceAmount": 83748.11, "debtPaymentAmount": 8179.87, "interestPaymentAmount": 426.77, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2022-09-24" }, { "monthNumber": 3, "loanBalanceAmount": 75568.24, "debtPaymentAmount": 8233.97, "interestPaymentAmount": 372.67, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2022-10-24" }, { "monthNumber": 4, "loanBalanceAmount": 67334.27, "debtPaymentAmount": 8263.51, "interestPaymentAmount": 343.13, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2022-11-24" }, { "monthNumber": 5, "loanBalanceAmount": 59070.76, "debtPaymentAmount": 8315.33, "interestPaymentAmount": 291.31, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2022-12-24" }, { "monthNumber": 6, "loanBalanceAmount": 50755.43, "debtPaymentAmount": 8348.00, "interestPaymentAmount": 258.64, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2023-01-24" }, { "monthNumber": 7, "loanBalanceAmount": 42407.43, "debtPaymentAmount": 8390.54, "interestPaymentAmount": 216.10, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2023-02-24" }, { "monthNumber": 8, "loanBalanceAmount": 34016.89, "debtPaymentAmount": 8450.07, "interestPaymentAmount": 156.57, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2023-03-24" }, { "monthNumber": 9, "loanBalanceAmount": 25566.82, "debtPaymentAmount": 8476.35, "interestPaymentAmount": 130.29, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2023-04-24" }, { "monthNumber": 10, "loanBalanceAmount": 17090.47, "debtPaymentAmount": 8522.36, "interestPaymentAmount": 84.28, "paymentAmount": 8606.64, "additionalPaymentAmount": 0, "paymentDate": "2023-05-24" }, {

        "monthNumber": 11,
        "loanBalanceAmount": 8568.11,
        "debtPaymentAmount": 8568.11,
        "interestPaymentAmount": 43.66,
        "paymentAmount": 8611.77,
        "additionalPaymentAmount": 0,
        "paymentDate": "2023-06-24"
    }
],
"earlyPayments": {}

}

Screen Shot 2022-07-24 at 8 00 15 PM
juanjoaquino05 commented 2 years ago

So, reviewing code i figured it out. It seens like a start date thing, when we pass start date, the values differ.

joeyvmason commented 2 years ago

I also have discovered the same issue. It's slightly off

joeyvmason commented 2 years ago

@juanjoaquino05 Can you provide some info about the date issue? I might be able to fix it and submit a PR

juanjoaquino05 commented 2 years ago

Seens like when you enter an start date in the call the code its using another strategy and there is the interest difference. But when you don't you'll have to manually put the payment date in every month.

private BigDecimal calculateInterestAmount(Loan loan, BigDecimal currentLoanBalance, BigDecimal monthlyInterestRate, LocalDate paymentDate) { return paymentDate == null ? getInterestAmountByBalanceAndMonthlyInterestRate(currentLoanBalance, monthlyInterestRate) : getInterestAmountByBalanceRateAndDays( currentLoanBalance, loan.getRate(), paymentDate.minusMonths(1).lengthOfMonth(), paymentDate.minusMonths(1).lengthOfYear() ); }

ArtyomPanfutov commented 2 years ago

Well, there are different strategies for calculating the interest amount.

When you pass a first payment date, the actual/actual strategy is used to get the interest amount. Initially, I implemented it this way for my specific case. Unfortunately, this behavior is not documented and I should've made it configurable.