Mortgage calculations in JS: annuity and fixed principal
Published on in JavaScript
Instead of spending 5 minutes to look for and use an existing mortgage calculator, I wasted time figuring out how to do the calculations from scratch.
Table of contents
Annuity vs fixed principal
- In annuity the monthly payment is fixed (until the interest rate changes).
- In fixed principal the monthly payment gets smaller after each month; the first payment is the largest and larger than in annuity.
- Fixed principal is cheaper over the whole mortgage period (less total interest fees), but annuity is more affordable in the short term.
I recall reading recently that annuity is used in like 99% of mortgages in Finland. I can't find that article anymore though, so I don't know if it's actually 99% or more like 90%.
Btw, MathJax
Enable MathJax by clicking the button below for a better reading experience. It's opt-in because it's a largish download (300+ KB).
(It would be nice to run MathJax during the website's build process, but I'm too lazy to do that now. I just want to publish this post.)
Annuity
Wikipedia has a clear annuity formula:
$$ A = \frac{P \times i} {(1 - (1 + i)^{-n})} $$
Where:
- \(A\) = monthly payment amount (= monthly principal + monthly interest)
- \(P\) = total loan amount
- \(i\) = monthly interest rate (percentage)
- \(n\) = total number of payments (= number of months)
On that same Wikipedia page, there's a formula for calculating the remaining loan amount after \(t\) months (function \(p(t)\)):
$$ p(t) = Pr^t - A \frac{r^t - 1}{r - 1} $$
Where:
$$r = 1 + i$$
It's clearer to use \(1 + i\) in place of \(r\):
$$ p(t) = P(1 + i)^t - A \frac{(1 + i)^t - 1}{(1 + i) - 1} $$
Because now we can simplify \((1 + i) - 1\) to just \(i\):
$$ p(t) = P(1 + i)^t - A \frac{(1 + i)^t - 1}{i} $$
In JavaScript, with an opening fee and extra monthly fees (not included in the formulas above):
const calculateAnnuity = ({
loanAmount,
monthlyFee,
monthlyInterestPercentage,
months,
openingFee,
}) => {
const monthlyAnnuity =
(loanAmount * monthlyInterestPercentage) /
(1 - (1 + monthlyInterestPercentage) ** -months)
const monthlyPayment = monthlyAnnuity + monthlyFee
const totalPayable = openingFee + monthlyPayment * months
const totalFees = totalPayable - loanAmount
const loanAmountLeftAfterOneYear =
loanAmount * (1 + monthlyInterestPercentage) ** 12 -
monthlyAnnuity *
(((1 + monthlyInterestPercentage) ** 12 - 1) / monthlyInterestPercentage)
return {
monthlyPayment,
totalPayable,
totalFees,
loanAmountLeftAfterOneYear,
}
}
Fixed principal
The formulas are much simpler because the monthly principal amount is fixed:
- monthly payment amount = monthly principal + interest for the remaining loan amount
- monthly principal = loan amount / number of months
- interest for the remaining loan amount = remaining loan amount × monthly interest rate
- loan left after \(t\) months = loan amount - monthly principal × \(t\)
In JavaScript:
const calculateFixedPrincipal = ({
loanAmount,
monthlyFee,
monthlyInterestPercentage,
months,
openingFee,
}) => {
const monthlyPrincipal = loanAmount / months
const monthlyPayments = Array.from({ length: months }, (_, monthIndex) => {
const interest =
(loanAmount - monthlyPrincipal * monthIndex) * monthlyInterestPercentage
return monthlyPrincipal + interest + monthlyFee
})
const firstMonthPayment = monthlyPayments[0]
const lastMonthPayment = monthlyPayments.at(-1)
const sum = (array) => array.reduce((a, b) => a + b, 0)
const totalPayable = openingFee + sum(monthlyPayments)
const totalFees = totalPayable - loanAmount
const loanAmountLeftAfterOneYear = loanAmount - monthlyPrincipal * 12
return {
firstMonthPayment,
lastMonthPayment,
totalPayable,
totalFees,
loanAmountLeftAfterOneYear,
}
}
Example
const referenceRate = 1.482 // E.g. Euribor 12
const margin = 0.55
const specs = {
loanAmount: 135_000,
monthlyFee: 2.5,
monthlyInterestPercentage: (referenceRate + margin) / 12 / 100,
months: 25 * 12,
openingFee: 150,
}
calculateAnnuity(specs)
//=> {
// monthlyPayment: 576.81,
// totalPayable: 173_192.65,
// totalFees: 38_192.65,
// loanAmountLeftAfterOneYear: 130_812.64,
// }
calculateFixedPrincipal(specs)
//=> {
// firstMonthPayment: 681.10,
// lastMonthPayment: 453.26,
// totalPayable: 170_304.30,
// totalFees: 35_304.30,
// loanAmountLeftAfterOneYear: 129_600.00,
// }
As you can see, fixed principal is more expensive in the beginning but cheaper in the long term (less total fees). Also, at some point the monthly payments become less than in annuity.
Thoughts
At first I though that fixed principal would be better because it incurs less total fees, but on the other hand:
- With my specs (see above) the difference in total fees is only 2,888.35 € over 25 years – that's only 115.53 € per year, or 9.63 € per month. Not very much.
- Less than ten bucks per month is not a high price to pay to get consistent monthly payments and more affordable payments in the beginning. Especially the second point (more affordable payments in the beginning) feels more important than slightly smaller total fees over a long period of time (25 years! I'm hardly that old myself).
Here's why I wanted to calculate how much of the loan amount would be left after one year:
- Interest rates have recently been increasing rapidly.
- My reference rate is tied to Euribor 12, i.e. the rate is updated every 12 months.
- I wanted to check how much the monthly payments would be after one year if the interest rate had raised to 6% (stress test) – would it matter whether I had been paying the first year with annuity or fixed principal?
- The difference in the remaining loan amount after one year is only 1,212.64 €,
so the effect on the stress test scenario is negligible.
So no, it doesn't really matter which payment type I use in the first year.
- There is something I could do to make my life easier in a stress test scenario: choosing annuity would make the first monthly payments significantly cheaper (around 250 € in my case).
To help me choose:
- I should choose fixed principal if I want to:
- Save less than 3k € in 25 years. Not a compelling reason.
- Pay less each month after some point. Not very interesting because that would be in the distant future.
- I should choose annuity if I want to:
- Pay about 100 € less each month (in the beginning). This sounds good; I could instead invest the money (either in an index fund or in cheese! I like cheese).
- Pay less in a stress test scenario (6% interest rate). This would increase my peace of mind.
I think I might go with annuity.
Demo
I started building a calculator for comparing mortgages but lost interest quite quickly, so here's a half-baked demo: