Calculating a mortgage in Javascript

9 min read

Written by Andrew Donald

on

Learn about the time value of money and how to calculate your mortgage using Homiro's open source JavaScript library.


Recently while learning how to program with Javascript I released my first library called mortgage quant.

This article is a review of what I learned about how mortgages work and how to calculate them in Javascript.

If you want to skip straight to the JavaScript calculators and fool around with them, either skip to the first calculator here or check out the GitHub repository here.

MortgageQuant Library

Check out our full library featuring each of these functions and descriptions of how to use them on our GitHub repository: https://github.com/homirodotcom/mortgage-quant/

The Time Value of Money

The time value of money theory serves to answer the question:

Is $100 now worth more than $100 a year from now?

On the surface it’s the same value so it doesn’t seem like it would make a difference what choice you make.

You've probably heard the saying: money is worth more today than it is tomorrow.

It's the fundamental reason why your mortgage will cost more than what you actually pay for your house.

If you're interested in learning about how lenders determine loan viability check out our article on the topic how-much-mortgage-can-i-afford.

To calculate a mortgage we will need to create four key functions that help us take into account exactly how much more money is worth in the present vs. the future.

  1. Future value
  2. Present value
  3. Monthly payment
  4. Amortization schedule

Future Value

A future value of money takes in to account exactly how we should value money today vs tomorrow. It helps answer questions like:

If I borrow $500,000 from the bank, how much will I have to pay in total over the lifetime of my mortgage?

or

If I purchase mortgage points/credits, will the savings be greater than what I can get from investmenting the up front costs elsewhere?

Mortgage points can be difficult to understand, but are a great example of how to use this function in a context that's useful to first time homebuyers.

Mortgage points are an opportunity to lower your interest rate over the course of your loan, in exchange for extra money paid into it now.

Let’s say you are choosing between the opportunity to take a higher rate with no cost or lower rate with a $15,000 initial cost:

  • Mortage amount: $500,000
  • Mortgage term: 30 years
Initial costInterest rateMonthly paymentTotal mortgage cost
$03.5% fixed$2,245.22$808,279.20
$15,0002.75% fixed$2,041.21$749,835.60

On the face of it it looks like we save $58,443.60 (minus the $15k initial).

However, what if we wanted to see the real value of those savings compared against what we could make in a 2.5% savings account? Or a broad equity index like the S&P500.

Which leads us to our first function to calculate the future value of the money we give up now vs the future value of our savings:

A future value function in Javascript:

In the context of a mortgage we will want to calculate the future value of the initially loaned amount PLUS the interest contribution of the fixed payments over the course of the loan:

export const futureValue = ({
  interestRate,
  payment,
  periods,
  presentValue,
}) => {
  interestRate = BigNumber(interestRate);
  periods      = BigNumber(periods);
  payment      = BigNumber(payment ?? 0);
  presentValue = BigNumber(presentValue ?? 0);

  const compoundInterestRate = interestRate.plus(1).exponentiatedBy(periods);
  const futureValueOfPresentValue = presentValue.times(compoundInterestRate);
  const paymentInterest = payment.times(compoundInterest.minus(1)).dividedBy(interestRate);

  return futureValueOfPresentValue.plus(paymentInterest)
};

This gives us a nice function we can use to calculate an answer to our original question:

import { futureValue } from "mortgage-quant";

const interestRate = 0.025; // 2.5%
const payment = 0; // since this is a lump sum investment annuity payments are 0
const periods = 360; // 30 years * 12 months per year
const presentValue = 15_000;

const result = futureValue(interestRate, payment, periods, presentValue); 
// returns $31,730.24

Therefore, the opportunity cost of putting the money into a low interest investment doesn’t beat the savings on the mortgage points we would have to buy but it lowers the value considerably.

Present Value

Present value is the inverse of future value and determines how much a future amount of money is worth in present dollars. It can answer questions like:

Given you can afford to pay $3265.93 and interest rates are 2.75% and you want a 30 year fixed mortgage, what is the maximum value you can borrow from a bank?

We put maximum here because in reality banks will charge varying amounts above your maximum, which is their profit and your cost.

A present value funciton in Javascript:

In our mortgage context the present value will have to account for the incremental payments we will make and the interest contribution of each payment made:

export const presentValue = ({
  interestRate,
  payment,
  periods
}) => {
  payment      = BigNumber(payment);
  interestRate = BigNumber(interestRate);
  periods      = BigNumber(periods);

  const one = BigNumber(1);
  const compoundInterest = interestRate.plus(one).exponentiatedBy(periods);
  const compoundPercentage = one.dividedBy(compoundInterest);
  const compoundGrowth = one.minus(compoundPercentage);
  const interestGenerated = compoundGrowth.dividedBy(interestRate);

  return payment.times(interestGenerated);
};

Which will allow us to calculate the total amount we can get from a bank given our requested payment:

import { presentValue } from "mortgage-quant";

const interestRate = 2.75 / 12.0; // 0.00229166666 -- for monthly compounding
const payment = 3265.93;
const periods = 360; // 30 years, 12 months per year

const result = presentValue(
  interestRate,
  payment,
  periods
); // returns $800,000 -- the maximum loan you can get from a lender or bank

Monthly Payments

One of the most common questions mortgage borrowers are concerned with is:

what will I be paying monthly

Since most mortgages are of the 30 year fixed variety, and the payment remains the same over the course of the loan, finding out your monthly payment is quite useful.

To find your monthly payment you only need your total mortgage amount (the real loan amount, not the home price with your down payment included), the interest rate offered by your lender, and the loan term (most often 30 year fixed).

Calculating monthly payment for a mortgage in Javascript:

export const monthlyPayment = ({
  interestRate,
  periods,
  presentValue
}) => {
  interestRate = BigNumber(interestRate)
  presentValue = BigNumber(presentValue)

  const monthlyInterestRate = interestRatePerPeriod(interestRate, 12);
  const compoundInterest = monthlyInterestRate.plus(1).exponentiatedBy(periods);
  const numerator = monthlyInterestRate.times(presentValue).times(compoundInterest);
  const denominator = compoundInterest.minus(1);

  return numerator.dividedBy(denominator);
};

Which we can use to get our fixed monthly payment on our mortgage:

import { monthlyPayment } from "mortgage-quant";

const interestRate = 0.035; // 3.5%
const periods = 360; // 30 years * 12 months per year
const presentValue = 500_000;

const result = monthlyPayment({presentValue, interestRate, periods}); 
// returns $2,245.22 

Amortization Schedule

The amortization schedule is the most comprehensive source of data for information about your mortgage payments.

By inputting your monthly payment, interest rate, and outstanding loan balance you can get a birds eye view of your mortgage across its lifespan.

Every row of the chart is a month with payment, and each column featuring your:

  • remaining balance,
  • your percentage of equity,
  • how much of each payment goes into your outstanding loan balance,
  • how much of each payment goes into interest payments,
  • total principal paid, and
  • total interest paid

To get all this information, the only inputs the amortization schedule requires is:

  • present value (initial loan amount)
  • periods (number of times you'll make payments over the course of the loan)
  • interest rate (annual rate)

Using our Amortization Schedule function in Javascript:

import { formatSchedule, amortizationSchedule } from 'mortgage-quant';

const presentValue = 800_000; // your loan amount
const interestRate = 0.05; // interest rate (annual)
const periods = 360; // amount of times you'll be making payments (30 * 12)

// returns the raw numeric values as BigNumber
const schedule = amortizationSchedule({
	presentValue,
	periods,
	interestRate,
});

// returns the values formatted as strings
const formattedSchedule = formatSchedule(schedule);

console.log(formattedSchedule);
// returns [
// {
//  payment: '4_294.57',
//  remainingBalance: '799_038.76',
//  principal: '961.24',
//  totalInterestPaid: '3_333.33',
//  interest: '3_333.33',
//  totalPrincipal: '961.24',
//  percentEquity: '0.12%'
// },
// ... 358 more payments
// ];

This can be useful to gauge how much interest you’ll be paying across the lifetime of your mortgage, as well as checking your share of equity as you pay off your loan if you're thinking of refinancing, getting cash out, or opening a HELOC.

Dealing with floating point numbers

One of the biggest surprises many people have when programming exact math in JavaScript, is that JavaScript and other programs absolutely garble floating point numbers.

For the uninitiated, floating point numbers are just numbers with decimal places — in contrast to integers which are whole numbers. JavaScript and some other programming languages lack precision when dealing with floating point numbers, due to poor translation between binary (what the computer fundamentally deals in) and our base-10 number system we use everyday, and mostly take for granted.

Due to the nature of how computers do math (with each transistor being on or off representing a 1 or a 0), there isn’t infinite room to store numbers in memory. In fact JavaScript uses the IEEE Standard for Floating-Point Arithmetic, specifically the double precision standard, which stores all numbers in 64 bits of memory.

We won’t be going into heavy detail of the implications of this limited storage capacity and it’s consequences on precise math — suffice to say it’s impossible to get exact results while doing regular math functions in JavaScript without the help of some additional programming wizardry.

However, it’s probably helpful to at least give an example of this garbling. The following example comes from Codemag.com’s article on the subject:

let result = 0.1 + 0.2 === 0.3;
console.log(result); // prints false, as the value of 0.1 + 0.2 in JS is 0.30000000000000004

This slight difference might seem inconsequential here, but when we’re dealing with floating point numbers and compound interest rates, this problem creates wild inaccuracies. Which when we’re dealing with our own money, is something we’d probably like to avoid.

There's a few ways to get around this, but what I found simplest was to use a pre-made library called BigNumber, published by MikeMcl on GitHub: https://github.com/MikeMcl/bignumber.js/

Our library deals with BigNumbers, and you’ll likely see the BigNumber(number) **syntax around our code. Just know that the purpose is to return accurate figures, and get beyond binary-base 10 mistranslations.