Canadian Mortgage Calculator

Calculate your Canadian mortgage payments with ease. Our tool is designed to help you make informed financial decisions.

Loan Details

Taxes, Insurance & Fees (Optional)

Advanced Settings (Currency & Frequency)

How to Use This Calculator

Enter the loan amount, annual interest rate, and amortization term for your Canadian mortgage. Optionally include extra principal contributions and escrow-related costs, then click Calculate to refresh the results. The monthly equivalent payment shows the total you would pay each month based on the selected frequency.

Use the advanced settings to switch currencies (CAD default) and payment frequency (monthly, bi-weekly, or weekly). The calculator keeps the values consistent with the selected frequency so you can compare payment options.

Methodology

This calculator uses standard mortgage formulas to provide accurate estimates. All calculations are based on data from the Government of Canada and industry standards.

  • The periodic payment is computed using a fixed-rate amortization model and then scaled to a monthly equivalent amount for easier comparison.
  • Escrow costs—taxes, insurance, mortgage insurance, and HOA-style fees—are converted to monthly installments and added to the monthly equivalent payment.
  • The payoff line shows how many payments are required with the current settings plus a rough estimate of the time to repay the loan.
Results are estimates and may differ from lender quotes; consult a licensed advisor for credit- and jurisdiction-specific decisions.

About the author

Ugo Candido builds practical financial tools to help readers make confident decisions with transparent models that mirror how lenders calculate payments and total ownership costs.

Contact: info@calcdomain.com

Editorial policy

CalcDomain content is created for educational purposes and reviewed for clarity, accuracy, and transparency. Inputs and assumptions are visible in the interface so you can trace exactly how results are produced.

Full original guide (expanded)

Glossary of Terms

  • Loan Amount: The principal amount borrowed.
  • Interest Rate: The annual interest rate on the loan.
  • Loan Term: The duration of the loan in years.
  • Monthly Payment: The amount paid monthly.
  • Total Interest Paid: The total interest paid over the loan term.
  • Total Payment: The total amount paid (principal + interest).

Frequently Asked Questions (FAQ)

What is a mortgage calculator?

A mortgage calculator helps you estimate your monthly payments based on loan amount, interest rate, and term.

How accurate is this mortgage calculator?

The calculator provides estimates based on your inputs. For precise advice, consult a financial professional.

Formulas

Fixed-Rate Amortization:

M = P × [r(1+r)ⁿ] / [(1+r)ⁿ - 1]

where P is the loan amount, r is the periodic rate (annual rate ÷ payments per year), and n is the total number of payments.

Formula (LaTeX)

P = \frac{L \cdot c \cdot (1 + c)^n}{(1 + c)^n - 1}

Citations

Home — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/

Finance — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/finance

Mortgage & Real Estate — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/subcategories/finance-mortgage-real-estate

Mortgage Payment Calculator - Monthly Payment Estimator with Taxes & Insurance — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/mortgage-payment

Mortgage Points Calculator — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/mortgage-points

Refinance Calculator — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/refinance-calculator

Adjustable-Rate Mortgage (ARM) Calculator — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/arm

Private Mortgage Insurance (PMI) Calculator — calcdomain.com · Accessed 2026-01-19
https://calcdomain.com/pmi

Changelog

Version: 0.1.0-draft · 2026-01-19

  • Initial audit spec draft generated from HTML extraction (review required).
  • Verify formulas match the calculator engine and convert any text-only formulas to LaTeX.
  • Confirm sources are authoritative and relevant to the calculator methodology.
Verified by Ugo Candido · 2026-01-19 Profile: calcDomain.com/ugocandido LinkedIn: /in/ugocandido92821/
Version 1.5.0
: '; return fallbackSymbol + round2(safe).toFixed(2); } }; const payoffLabel = (count, freq) => { const years = count / freq; const wholeYears = Math.floor(years); const remMonths = Math.round((years - wholeYears) * 12); if (wholeYears <= 0) return `${Math.max(1, remMonths)} months`; if (remMonths <= 0) return `${wholeYears} years`; return `${wholeYears} yrs ${remMonths} mos`; }; const els = { loanAmount: document.getElementById('loanAmount'), interestRate: document.getElementById('interestRate'), loanTermYears: document.getElementById('loanTermYears'), extraPrincipal: document.getElementById('extraPrincipal'), annualTax: document.getElementById('annualTax'), annualInsurance: document.getElementById('annualInsurance'), monthlyPMI: document.getElementById('monthlyPMI'), monthlyHOA: document.getElementById('monthlyHOA'), currency: document.getElementById('currency'), paymentsPerYear: document.getElementById('paymentsPerYear'), totalMonthly: document.getElementById('totalMonthly'), piMonthly: document.getElementById('piMonthly'), tiMonthly: document.getElementById('tiMonthly'), totalInterest: document.getElementById('totalInterest'), totalPayment: document.getElementById('totalPayment'), payoffTime: document.getElementById('payoffTime'), errorBox: document.getElementById('errorBox'), scheduleWrap: document.getElementById('scheduleWrap'), scheduleBody: document.getElementById('scheduleBody'), toggleSchedule: document.getElementById('toggleSchedule'), downloadCsv: document.getElementById('downloadCsv'), calcBtn: document.getElementById('calcBtn'), resetBtn: document.getElementById('resetBtn') }; let currentSchedule = []; function parseInputs() { return { principal: parseFloat(els.loanAmount.value), annualRatePct: parseFloat(els.interestRate.value), years: parseFloat(els.loanTermYears.value), extraPerPayment: parseFloat(els.extraPrincipal.value) || 0, paymentsPerYear: parseInt(els.paymentsPerYear.value, 10), currency: els.currency.value, annualTax: parseFloat(els.annualTax.value) || 0, annualInsurance: parseFloat(els.annualInsurance.value) || 0, monthlyPMI: parseFloat(els.monthlyPMI.value) || 0, monthlyHOA: parseFloat(els.monthlyHOA.value) || 0 }; } function validate(inputs) { const errors = []; const allowedFreq = new Set([12, 26, 52]); if (!Number.isFinite(inputs.principal) || inputs.principal <= 0) errors.push('Loan amount must be greater than 0.'); if (!Number.isFinite(inputs.years) || inputs.years <= 0) errors.push('Term (years) must be greater than 0.'); if (!Number.isFinite(inputs.annualRatePct) || inputs.annualRatePct < 0) errors.push('Interest rate must be 0 or greater.'); if (!Number.isFinite(inputs.extraPerPayment) || inputs.extraPerPayment < 0) errors.push('Extra principal must be 0 or greater.'); if (!allowedFreq.has(inputs.paymentsPerYear)) errors.push('Payment frequency is invalid.'); if (inputs.annualTax < 0 || inputs.annualInsurance < 0 || inputs.monthlyPMI < 0 || inputs.monthlyHOA < 0) { errors.push('Taxes, insurance, and fees must be 0 or greater.'); } return { ok: errors.length === 0, errors }; } function compute(inputs) { const principal = inputs.principal; const paymentsCount = Math.round(inputs.years * inputs.paymentsPerYear); const periodicRate = (inputs.annualRatePct / 100) / inputs.paymentsPerYear; if (!(principal > 0) || !(paymentsCount > 0) || !Number.isFinite(periodicRate)) return null; let paymentPerPeriod; if (periodicRate === 0) paymentPerPeriod = principal / paymentsCount; else paymentPerPeriod = principal * (periodicRate * Math.pow(1 + periodicRate, paymentsCount)) / (Math.pow(1 + periodicRate, paymentsCount) - 1); if (!Number.isFinite(paymentPerPeriod) || paymentPerPeriod <= 0) return null; let balance = principal; let totalInterest = 0; const schedule = []; const MAX_ITERS = paymentsCount + 5000; let sumPayments = 0; for (let i = 1; i <= MAX_ITERS; i++) { if (balance <= 0.005) break; const interest = balance * periodicRate; let principalPaid = paymentPerPeriod - interest; if (principalPaid < 0) return null; let extra = inputs.extraPerPayment; if (principalPaid + extra > balance) { extra = Math.max(0, balance - principalPaid); principalPaid = Math.min(principalPaid, balance); } balance = balance - principalPaid - extra; if (!Number.isFinite(balance)) return null; totalInterest += interest; const periodTotal = paymentPerPeriod + extra; sumPayments += periodTotal; schedule.push({ num: i, total: round2(periodTotal), int: round2(interest), prin: round2(principalPaid), extra: round2(extra), bal: round2(Math.max(0, balance)) }); } if (schedule.length === 0) return null; return { paymentPerPeriod, totalInterest: round2(totalInterest), totalPayment: round2(sumPayments), schedule }; } function format(outputs, inputs) { const monthlyPI = outputs.paymentPerPeriod * (inputs.paymentsPerYear / 12); const monthlyEscrow = (inputs.annualTax + inputs.annualInsurance) / 12 + inputs.monthlyPMI + inputs.monthlyHOA; return { totalMonthly: fmtCurrency(monthlyPI + monthlyEscrow, inputs.currency), piMonthly: fmtCurrency(monthlyPI, inputs.currency), tiMonthly: fmtCurrency(monthlyEscrow, inputs.currency), totalInterest: fmtCurrency(outputs.totalInterest, inputs.currency), totalPayment: fmtCurrency(outputs.totalPayment, inputs.currency), payoffLabel: `${outputs.schedule.length} payments (~${payoffLabel(outputs.schedule.length, inputs.paymentsPerYear)})`, currency: inputs.currency }; } function renderError(errors) { if (!errors || errors.length === 0) { els.errorBox.style.display = 'none'; els.errorBox.textContent = ''; return; } els.errorBox.style.display = 'block'; els.errorBox.textContent = errors.join(' '); } function renderTable(currency) { els.scheduleBody.innerHTML = ''; const rows = currentSchedule.slice(0, 360); const fragment = document.createDocumentFragment(); rows.forEach((row) => { const tr = document.createElement('tr'); tr.innerHTML = ` ${row.num} ${fmtCurrency(row.total, currency)} ${fmtCurrency(row.int, currency)} ${fmtCurrency(row.prin, currency)} ${fmtCurrency(row.extra, currency)} ${fmtCurrency(row.bal, currency)} `; fragment.appendChild(tr); }); els.scheduleBody.appendChild(fragment); } function render(formatted, errors = []) { renderError(errors); if (!formatted) { els.totalMonthly.textContent = '$0.00'; els.piMonthly.textContent = '$0.00'; els.tiMonthly.textContent = '$0.00'; els.totalInterest.textContent = '$0.00'; els.totalPayment.textContent = '$0.00'; els.payoffTime.textContent = '—'; els.downloadCsv.disabled = true; return; } els.totalMonthly.textContent = formatted.totalMonthly; els.piMonthly.textContent = formatted.piMonthly; els.tiMonthly.textContent = formatted.tiMonthly; els.totalInterest.textContent = formatted.totalInterest; els.totalPayment.textContent = formatted.totalPayment; els.payoffTime.textContent = formatted.payoffLabel; els.downloadCsv.disabled = currentSchedule.length === 0; if (els.scheduleWrap.style.display === 'block' && currentSchedule.length > 0) { renderTable(formatted.currency); } } function update() { const inputs = parseInputs(); const validation = validate(inputs); if (!validation.ok) { currentSchedule = []; render(null, validation.errors); els.downloadCsv.disabled = true; return; } const outputs = compute(inputs); if (!outputs) { currentSchedule = []; render(null, ['Calculation failed. Please adjust your inputs.']); els.downloadCsv.disabled = true; return; } currentSchedule = outputs.schedule; const formatted = format(outputs, inputs); render(formatted); } els.toggleSchedule.addEventListener('click', () => { const isHidden = els.scheduleWrap.style.display !== 'block'; els.scheduleWrap.style.display = isHidden ? 'block' : 'none'; els.toggleSchedule.textContent = isHidden ? 'Hide Amortization Schedule' : 'View Amortization Schedule'; if (isHidden && currentSchedule.length > 0) { renderTable(els.currency.value); } }); els.downloadCsv.addEventListener('click', () => { if (currentSchedule.length === 0) return; const cur = els.currency.value; let csv = '#,Total Payment,Interest,Principal,Extra,Balance\n'; currentSchedule.forEach((row) => { csv += `${row.num},${row.total},${row.int},${row.prin},${row.extra},${row.bal}\n`; }); const blob = new Blob([csv], { type: 'text/csv' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = 'amortization-schedule.csv'; link.click(); URL.revokeObjectURL(url); }); els.calcBtn.addEventListener('click', update); els.resetBtn.addEventListener('click', () => { els.loanAmount.value = '350000'; els.interestRate.value = '6.5'; els.loanTermYears.value = '25'; els.extraPrincipal.value = '0'; els.annualTax.value = '0'; els.annualInsurance.value = '0'; els.monthlyPMI.value = '0'; els.monthlyHOA.value = '0'; els.currency.value = 'CAD'; els.paymentsPerYear.value = '12'; els.scheduleWrap.style.display = 'none'; els.toggleSchedule.textContent = 'View Amortization Schedule'; const debouncedUpdate = debounce(update, 100); document.querySelectorAll('#inputsCard input, #inputsCard select, #inputsCard textarea') .forEach((el) => { el.addEventListener('input', debouncedUpdate); el.addEventListener('change', debouncedUpdate); }); update(); }); el.addEventListener('change', debouncedUpdate); }); update(); })();