Building a Comprehensive Mortgage Overpayment Calculator Buil...

Building a Comprehensive Mortgage Overpayment Calculator

Building a Comprehensive Mortgage Overpayment Calculator: How quickly can I be debt-free?

Most mortgage overpayment calculators ask you one simple question: "How much extra do you want to pay each month?" But that's not how real life works. Your income changes, expenses fluctuate, you have emergency funds to maintain, and mortgage rates don't stay fixed forever. So I built something more realistic.

The problem with existing calculators

The standard mortgage calculators you find online are frustratingly simplistic. They assume you can magically pull £100 or £200 out of thin air each month without considering your actual financial situation. They ignore the fact that most mortgages have multiple rate periods, and they certainly don't account for life changes like childcare ending or new expenses starting.

I wanted to build something that could answer the crucial question: "What's the absolute fastest I could pay off my mortgage given my real financial situation?" - while still maintaining proper emergency funds and financial security.

The comprehensive approach

Rather than just asking for an overpayment amount, my calculator takes a holistic view of your finances:

Your complete financial picture: Current income, monthly expenses, and how both are likely to change over time through annual growth rates.

Real mortgage structures: Multiple fixed-rate periods before reverting to the standard variable rate - because that's how most UK mortgages actually work.

Financial safety: Emergency fund requirements and existing savings with their own growth rates and tax implications.

Life changes: Specific expense changes you can plan for - like when childcare costs end or a new car payment begins.

Strategic overpayment timing: The calculator automatically makes lump sum overpayments at the end of each fixed rate period, plus annual overpayments during variable rate periods (subject to typical 10% limits).

The core algorithm then calculates month-by-month the maximum you can afford to overpay while maintaining your emergency fund - showing you the absolute fastest payoff timeline possible. You can also adjust the minimum overpayment threshold to explore more conservative scenarios.

The mathematics behind it

The calculation engine runs a month-by-month simulation over your chosen time period. For each month, it:

  1. Calculates available funds: monthly_income - monthly_expenses with growth applied
  2. Applies the current interest rate: Using the appropriate fixed rate or SVR based on timing
  3. Makes strategic overpayments: Lump sums at the end of fixed periods, annual overpayments during variable periods
  4. Updates payment amounts: Recalculates monthly payments when transitioning between rate periods
  5. Maintains emergency fund: Ensures adequate cash reserves before any overpayments
# Simplified core logic
for month in range(simulation_months):
    # Apply annual growth to income and expenses
    if month > 0 and month % 12 == 0:
        monthly_income *= (1 + income_growth_rate)
        monthly_expenses *= (1 + expense_growth_rate)
    
    # Apply any planned expense changes
    if month in expense_changes:
        monthly_expenses -= expense_changes[month]  # Negative for reductions
    
    # Check for end of fixed period - make lump sum overpayment
    for period_start, period_end, rate in fixed_periods:
        if month == period_end:
            available_lump_sum = max(0, cash_savings - emergency_buffer)
            if available_lump_sum > min_threshold:
                payment_to_mortgage = min(available_lump_sum, mortgage_balance)
                mortgage_balance -= payment_to_mortgage
                cash_savings -= payment_to_mortgage
                
                # Recalculate monthly payment for remaining term
                remaining_months = total_term - month
                next_rate = get_next_rate(month, fixed_periods, svr_rate)
                monthly_payment = calculate_payment(next_rate, remaining_months, mortgage_balance)
    
    # Annual overpayment during variable rate periods (10% limit)
    if not in_fixed_period and not overpayment_made_this_year:
        yearly_limit = 0.10 * mortgage_balance
        available_cash = max(0, cash_savings - emergency_buffer)
        if available_cash >= min_threshold:
            annual_overpayment = min(available_cash, yearly_limit, mortgage_balance)
            mortgage_balance -= annual_overpayment
            cash_savings -= annual_overpayment
            overpayment_made_this_year = True
    
    # Regular mortgage payment and savings growth
    make_monthly_payment(mortgage_balance, current_rate)
    apply_savings_interest_with_tax(cash_savings, savings_rate, tax_rate)

What makes this different

The key insight is that mortgage overpayments aren't just about mortgage mathematics - they're about cash flow management. The calculator ensures you never compromise your financial security to overpay your mortgage.

Intelligent overpayment timing: Rather than fixed monthly amounts, the calculator strategically times overpayments - making lump sum payments at the end of each fixed rate period when you have maximum flexibility, plus annual overpayments during variable rate periods.

10% annual overpayment limits: The calculator respects typical mortgage overpayment restrictions, automatically calculating 10% of your current balance as the annual limit.

Emergency fund protection: The calculator maintains your emergency fund as a multiple of your current income, automatically adjusting as your salary changes.

Rate period modeling: The calculator updates your monthly payment whenever you transition between fixed periods, using proper amortisation calculations for the remaining term.

Growth projections with tax: Both income and expenses grow over time, while savings interest is calculated with tax deductions applied.

The results interface

The output is designed to answer the key questions immediately:

  • 🎉 Mortgage-Free In: Shows both the timeline (e.g., "7y 8m") and years saved compared to minimum payments
  • 💰 Interest Paid: Total interest with savings amount (e.g., "£17,019, -£42,994 saved")
  • 🏦 Final Savings: Your cash position at the end of the simulation
  • 🚀 Total Overpayments: The cumulative extra payments made over the period

The calculator also shows a detailed overpayment schedule, breaking down exactly when each lump sum or annual payment occurs, whether it's at the end of a fixed period or during a variable rate year.

The charts show the progression over time - mortgage balance declining, savings growing, and the impact of rate changes as you move between fixed periods.

Real-world insights

Testing the calculator with various scenarios reveals some interesting patterns:

The emergency fund buffer matters: People often want to throw every spare penny at the mortgage, but maintaining liquidity is crucial. The calculator finds the sweet spot.

Rate period timing is critical: If you're approaching the end of a low fixed rate, the calculations change dramatically when you hit the higher SVR.

Life changes have massive impact: When major expenses like childcare end, the additional overpayment capacity can accelerate mortgage payoff by years.

Income growth compounds: Even modest annual pay rises create exponentially more overpayment capacity over time.

The technical implementation

Built with Streamlit for the interface and NumPy Financial for mortgage calculations. The interface uses expandable sections to manage complexity - essential inputs are prominent while advanced features like planned expense changes are tucked away in collapsible sections.

The calculation engine uses proper amortisation formulas from numpy_financial.pmt() to calculate payments, and recalculates them whenever the mortgage balance or rate changes. Interactive Plotly charts show the progression over time, optimised for both desktop and mobile viewing.

One interesting technical challenge was handling the transitions between fixed rate periods - the calculator needs to recalculate the monthly payment based on the remaining balance and term whenever rates change, which affects all subsequent calculations.

Practical applications

This tool answers my key question:

"What's the absolute fastest I could be mortgage-free?" - The default calculation shows maximum acceleration using all available funds after maintaining financial security.

It's particularly useful for:

  • Ambitious payers who want to see their absolute maximum potential
  • Conservative planners exploring modest overpayment impacts
  • New homeowners planning their long-term financial strategy
  • People approaching rate changes who want to understand the impact of higher rates
  • Parents modeling what happens when major expenses like childcare end

Limitations and assumptions

The calculator assumes you can actually make the calculated overpayments (no spending on holidays, emergencies, etc.). The only mortgage overpayment limit it considers is the 10% per calendar year, and it assumes constant tax rates and savings interest rates where specified.

Most importantly, it doesn't consider the opportunity cost of mortgage overpayments versus other investments - that's a separate analysis entirely.

Try it yourself

The calculator is available at mortgage-calculator-prd.streamlit.app. All calculations happen in your browser - no data is stored or transmitted.

Input your real financial situation and discover your mortgage payoff potential. Many people are shocked to see they could be mortgage-free years earlier than expected by maximising their overpayments. Others prefer to adjust the minimum threshold to explore more modest approaches that still deliver significant savings.

What I learned

Building this reinforced that personal finance tools need to reflect personal finance reality. Simple calculators give simple answers, but real financial decisions require modeling the complexity of actual life.

The most powerful feature isn't the mortgage mathematics - it's the cash flow management that ensures you can sustain your overpayment strategy while maintaining financial security.

Sometimes the best financial decision isn't the most aggressive one - it's the one you can actually stick to.

Like many Americans and non-Americans alike, I've been glued to the terrifying coverage of the US 2016 Presidential Election.  With only...

Like many Americans and non-Americans alike, I've been glued to the terrifying coverage of the US 2016 Presidential Election.  With only a day to go, I decided to join the large array of blogs and news outlets that have performed a review of the vast quantities of polling data available.

The source

First of all I had to get hold of some polling data.  Of course there are plenty of sources available on the internet, so I had a look at the following, but decided to go with the poll results collated by electionprojection.com, mainly because of the ease of obtaining.  Other such sources I found useful:
In order to get hold of the state by state data I wrote a small python script to parse the data from html tables on the electionprojection website:

# Get poll data
data = []
# 
for loop in range(0,len(electoral_college)):
    state = electoral_college['State'].iloc[loop]
    state = state.replace(" ","-")
    if state.lower() == 'district-of-columbia':
        continue
    url = 'http://www.electionprojection.com/latest-polls/'+state.lower()+\
    '-presidential-polls-trump-vs-clinton-vs-johnson-vs-stein.php'
    the_content = urlopen(url)
    soup = BeautifulSoup(the_content,"html.parser")
    table = soup.find('table',attrs={'class':'mb pollblock'})
    table.prettify()
    rows = table.find_all('tr')
    for row in rows:
        cols = row.find_all('td')
        cols = [ele.text.strip() for ele in cols]
        cols.insert(0,state)
        data.append([ele for ele in cols if ele])

data = pd.DataFrame(data)
data.columns=['State','Firm','Dates','Sample','Clinton','Trump','Johnson','Stein','Spread']
poll_data = data[data.Firm.notnull()] # remove null lines
poll_df = poll_data[poll_data.Firm != 'EP Poll Average']


Given the US system uses the electoral collage for determining the next president I needed to get the a list of votes for each state.  Wikipedia could help:

The simulation

To determine tomorrow's winner I took the poll results for each state, applied a random variable for each candidate, and ran it a tonne of times (Monte Carlo).  This approach estimates the winning candidate of each state which can then be attributed to a number of electoral votes.  Simply summing up the votes gives us the winner.  



This chart shows the percentage chance of victory based on the number of simulations run.  It's clear to see this quickly converges to 74% for Clinton, and 26% for Trump.  My random variable wasn't quite random enough to give Johnson or Stein a chance.

The conclusion

Well Nate Silver of fivethirtyeight.com estimates a 72% chance for a Clinton victory... So look at that.. Maybe I should be a look for a career change.

Analysing stars used to be my bread and butter, but it's still an area of great interest.  Therefore when I came across the Open Exoplan...

Analysing stars used to be my bread and butter, but it's still an area of great interest.  Therefore when I came across the Open Exoplanet Catalogue and found out it had host star information, I couldn't resist plotting out a Hertzsprung-Russell diagram:


I'm curious about those hot stars (blue cluster), their effective temperatures and luminosities are a bit odd.  I'd love to think they were blue dwarf stars, but as none have been seen before, I doubt it.

A note before we start, this is by no means an original analysis, just my attempt at learning something new.  With that said: A slow perio...

A note before we start, this is by no means an original analysis, just my attempt at learning something new.  With that said:

A slow period in work, and a desire to learn something has had me fumbling around with Python for data analysis over the last few weeks.  I've dabbled in Python before, mainly for parsing the rugby data collected in a previous post.  However this time I wanted to see what I could do with Python from start to finish.

Therefore I trawled the internet for resources and training material, and came across an excellent blog by yhat using their Rodeo IDE for data science. Be sure to check it out. So Rodeo downloaded, and my iPhone Health app's step counter data extracted, I decided to repeat their analysis and train my Python skills.

The source

First of all I extracted my Health app data from my iPhone and loaded into Rodeo to get a sense of the data it collects.  Depending on how much you utilise the Health app features there's actually quite a bit of data you can pull from it e.g. heart rates, distances, steps.  


Ok, so a quick time series doesn't show much, just that there was a period of time (around day 550) when either I didn't walk at all, or maybe just didn't have my phone.  The flat part of the time series, up to day 80 or so, is the period of time before I received the iPhone, and the first point is actually 9 steps; they must have been messing around with my phone in the factory.

The interesting


I'm pretty sure I walk much less during the weekend than the weekdays...


Yup- that definitely confirms it, the above plot shows a frequency distribution for my steps during the weekends (purple) and weekday (teal), that's a clear conclusion that I need to walk more during the weekends.  One can clearly see a bi-modal distribution in weekdays, and I believe this is due to the 'weekend' effect i.e. on bank holidays, I do very little walking, just like the weekends.

Now currently I'm using two phones, and tend to have them with me most days.  My second phone is an Android device, the WileyFox Swift.  I have the Google Fit app installed on this, therefore I could load up the step data from this device and perform a quick comparison between the two:


The negative step difference is due to Android, so it looks like there's actually plenty of occasions where I've forgotten to carry my iPhone. 

For this final plot, I've taken the max number of steps each day, for either iPhone or Android and then cut them based on whether the date falls before or after 14th July 2016.  Why this date? That's when PokemonGo came out in the UK...


One can clearly see the bi-modal distribution in the pre- and post-PokemonGo step distributions, however the standard deviation of the post-PokemonGo distribution is clearly larger.

The conclusion

Well what does all this tell me:
  1. I need to walk more on the weekends
  2. PokemonGo is helping with that, just not enough
So I'm going out for a walk.

For those unaware, tomorrow is a big day for British science and in particular space exploration.  Tim Peake, the first ESA astronaut select...

For those unaware, tomorrow is a big day for British science and in particular space exploration.  Tim Peake, the first ESA astronaut selected from the UK, will be heading up for a 6 month tour on the ISS.  Those that know me will understand my fascination with such an event.

I decided it would be nice to mark this occasion, in my own way, by pulling together another Tableau dashboard centred around the ISS.  Well in particular the astronauts.  A friend of mine was curious as to how long the astronauts are spending on the ISS, so I decided to look at this in terms of how far mankind could have travelled from the Earth in this time.

Now I took some major assumptions here:  The ISS travels on average at 27,600 km/h, and will execute 15.54 orbits of the Earth in a single 24 hour period.  Therefore with these assumptions, and knowing how long each expedition to the ISS has lasted (according to NASA), I calculated a very rough (back of the envelope, if you will) calculation to illustrate how far these astronauts could have gone from the Earth.



As you can see from above, I've included the Moon, Mars, and Jupiter as a bit of a reference, and it's clear that only the most experienced of astronauts like Gennady Padalka, has made it to the Red Planet at its average distance ~225 million km.

I'm really looking forward to launch tomorrow, and seeing some of the experiments Tim will be running while on board the ISS.  And of course adding Tim's data to the graphic above!

Edit: to include Jupiter, and a slight issue with my scale.. That's a reminder to have someone check your work before publishing


I'm a fan of rugby.  Not the biggest fan in the world, but I enjoy watching a game here or there, whenever I've the time really.  Ul...

I'm a fan of rugby.  Not the biggest fan in the world, but I enjoy watching a game here or there, whenever I've the time really.  Ulster games, however, I do try and make time for. Probably because of being from Northern Ireland and living a stones throw from Ravenhill (Kingspan stadium).

Many rugby fans will know It's a common occurrence during a game to see at least one yellow card get branded by the referee. And it's almost more common to hear the commentator state something along the lines of "a yellow card is worth 10 points to the opposition". Well is it?



I wanted to explore this commentator statistic to see if this has been the case for Ulster over the last few seasons.  The first Tableau graphic illustrates the average number of points each opponent loses during a yellow card, whilst playing Ulster.  These data have been accumulated for all Ulster games from the 2012/2013 season up to November 2015, but I decided to only go with Pro12 data for this graphic.  What I found of immediate interest is that Zebre, often considered the worst team in the Pro12, are only one of two teams that tend to come out the better side during a yellow card.  Granted this is a somewhat bias analysis only considering Ulster as the opposition. 

If I just take a simple average across all the teams it's clear Ulster don't benefit from the full 10 point average, but they still tend to see around a 7 point advantage. 

Ok so that was a quick and simple analysis and I have plenty of yellow card data to play with, so I'll have a look and consider who's the biggest culprit  for getting on the wrong side of the ref?




In this Tableau graphic I wanted to continue the theme of looking at the impact a yellow card can have on a team's performance.  This time I specifically looked at Ulster and how each of their yellow cards has affected a game.  I also wanted to highlight which players were more prone to getting on the wrong side of the ref.

As an Ulster fan it might be a bit of a surprise to see Iain Henderson and Rory Best near the top of the list. Or that four of the top ten are second rows, namely Iain Henderson, Dan Tuohy, Franco Van Der Merwe, and Lewis Stevenson. I also find it curious that Ulster really suffer with Dan Tuohy in the sin bin.

Although there isn't anything difficult in my analysis, it was an exercise I found enjoyable and something I haven't really seen done before. 

I still have plenty of yellow card data to look at, but I feel it would be more beneficial to have a full population - specifically all yellow card instances for all teams, and all major leagues.  I'm sure this will be something I'll return to soon enough.