Coffee Space


Listen:

UK Inflation

Preview Image

There was news recently that UK inflation has dropped from 3.4% to 3.2%, and that this is reason to celebrate.

We will be using the following data:

We will investigate how inflation actually affects the people of the UK and whether there is reason to celebrate.

Data Cleaning

We need to get the data into a format we can actually use it.

Inflation Data

We initially deleted all but the per-month data, producing a format like so:

0001 import csv
0002 
0003 inflate_file = open("uk-inflation/series-170424.csv", mode="r")
0004 inflate_reader = csv.reader(inflate_file) # Parse CSV
0005 
0006 def get_row(reader, num) :
0007   for row in reader:
0008     num -= 1
0009     if num <= 0 : return row
0010   return None
0011 
0012 print(str(get_row(inflate_reader, 1))) # Print first line
0013 inflate_file.seek(0) # Return to start of file
['1989 JAN', '5.7']

The first thing we should do is parse the line:

0014 def month_to_num(month_name) :
0015   month = None
0016   if   month_name.startswith("jan") : month =  1
0017   elif month_name.startswith("feb") : month =  2
0018   elif month_name.startswith("mar") : month =  3
0019   elif month_name.startswith("apr") : month =  4
0020   elif month_name.startswith("may") : month =  5
0021   elif month_name.startswith("jun") : month =  6
0022   elif month_name.startswith("jul") : month =  7
0023   elif month_name.startswith("aug") : month =  8
0024   elif month_name.startswith("sep") : month =  9
0025   elif month_name.startswith("oct") : month = 10
0026   elif month_name.startswith("nov") : month = 11
0027   elif month_name.startswith("dec") : month = 12
0028   else                              : month = -1
0029   return month
0030 
0031 def inflate_parse_line(row):
0032   if len(row) != 2 :
0033     print("Incorrect number of columns in row: " + str(len(row)))
0034     return (None, None, None)
0035   date_raw = row[0].split(" ")
0036   if len(date_raw) != 2 :
0037     print("Incorrect parts of date: " + str(len(date_raw)))
0038     return (None, None, None)
0039   # Convert year
0040   year = int(date_raw[0])
0041   # Convert month
0042   month_name = date_raw[1].lower()
0043   month = month_to_num(month_name)
0044   # Convert inflation
0045   inflation = float(row[1])
0046   return (year, month, inflation)
0047 
0048 year, month, inflation = inflate_parse_line(get_row(inflate_reader, 1))
0049 inflate_file.seek(0) # Return to start of file
0050 print("Year: " + str(year) + ", \tMonth: " + str(month) + ", \tInflation: " + str(inflation))
Year: 1989, 	Month: 1, 	Inflation: 5.7

And now we should be able to replicate the graph showing inflation over time:

0051 plot_raw = Plott(
0052   title = "Inflation and Interest Rates Over Time in the UK",
0053   x_title = "Time (months since January 1989)",
0054   y_title = "Inflation/Interest (percentage %)",
0055   fg = "#FFF",
0056   bg = "#222"
0057 )
0058 # Collect some stats
0059 min_year = 99999999
0060 max_year = -1
0061 # Setup X and Y axis
0062 win_size = 12 # Months
0063 x = []
0064 y = []
0065 z = []
0066 for row in inflate_reader :
0067   year, month, inflation = inflate_parse_line(row)
0068   if year > max_year : max_year = year
0069   if year < min_year : min_year = year
0070   x += [ ((year - 1989) * 12) + month ]
0071   y += [ inflation ]
0072   if len(y) >= win_size :
0073     t = 0
0074     for i in range(len(x) - win_size, len(y)) :
0075       t += y[i]
0076     z += [ t / win_size ]
0077   else : z += [ inflation ]
0078 plot_raw.plot(x, y, "Raw inflation values")
0079 plot_raw.plot(x, z, "Smoothed inflation values (window = " + str(win_size) + " months)")
0080 inflate_file.seek(0) # Reset the position into the file
0081 print(plot_raw.to_uri()) # Display the graph

Interest Data

Very import note: We assume that interest rates for saving are approximately the same as interest rates on borrowed money. In fact, it’s worse. The recent loan rates have not been passed onto bank savers.

As done previously, we need to read and parse the CSV data:

0082 import csv
0083 
0084 interest_file = open("uk-inflation/boe-interest.csv", mode="r")
0085 interest_reader = csv.reader(interest_file) # Parse CSV
0086 
0087 print(str(get_row(interest_reader, 1))) # Print first line
0088 interest_file.seek(0) # Return to start of file
['03 Aug 23', '5.25']

And each row needs to be parsed into a format we can use:

0089 def interest_parse_line(row):
0090   if len(row) != 2 :
0091     print("Incorrect number of columns in row: " + str(len(row)))
0092     return (None, None, None)
0093   date_raw = row[0].split(" ")
0094   if len(date_raw) != 3 :
0095     print("Incorrect parts of date: " + str(len(date_raw)))
0096     return (None, None, None)
0097   # Convert year
0098   year = int(date_raw[2])
0099   # Note: Terrible reporting format by the BoE.
0100   if year < 50 : year += 2000
0101   else : year + 1900
0102   # Convert month
0103   month_name = date_raw[1].lower()
0104   month = month_to_num(month_name)
0105   # Convert inflation
0106   interest = float(row[1])
0107   return (year, month, interest)
0108 
0109 year, month, interest = interest_parse_line(get_row(interest_reader, 1))
0110 interest_file.seek(0) # Return to start of file
0111 print("Year: " + str(year) + ", \tMonth: " + str(month) + ", \tInterest: " + str(interest))
Year: 2023, 	Month: 8, 	Interest: 5.25

Now we need to perform additional processing, as the data is not really as periodic as the ONS data. For a given month and year we want to estimate the interest rate.

0112 def get_interest_rate(reader, year, month) :
0113   date = ((year - 1989) * 12) + month
0114   just_below = [ date - 99999999, None, None, None ]
0115   just_above = [ date + 99999999, None, None, None ]
0116   for row in interest_reader :
0117     y, m, i = interest_parse_line(row)
0118     d = ((y - 1989) * 12) + m
0119     if d > date and d < just_above[0] :
0120       just_above = [ d, y, m, i ]
0121     if d < date and d > just_below[0] :
0122       just_below = [ d, y, m, i ]
0123   if just_above[3] != None :
0124     return (just_below[3] + just_above[3]) / 2
0125   else :
0126     return just_below[3]
0127 
0128 interest = get_interest_rate(interest_reader, 2022, 1) # Doesn't exist
0129 interest_file.seek(0) # Return to start of file
0130 print("Year: " + str(2022) + ", \tMonth: " + str(1) + ", \tInterest: " + str(interest))
Year: 2022, 	Month: 1, 	Interest: 0.375

Note: I am aware that this is not ideal and that there is data missing, but it is good enough to serve the point.

Now let us update our data:

0131 # Setup X and Y axis
0132 win_size = 12 # Months
0133 i = []
0134 for row in inflate_reader :
0135   year, month, inflation = inflate_parse_line(row)
0136   interest = get_interest_rate(interest_reader, year, month)
0137   interest_file.seek(0) # Return to start of file
0138   i += [ interest ]
0139 plot_raw.plot(x, i, "Interest values (interpolated)")
0140 inflate_file.seek(0) # Reset the position into the file
0141 print(plot_raw.to_uri()) # Display the graph

Note: We don’t smooth the interest values because the dataset is already sparse, and it is not clear if smoothing the data creates for a noise-reduced picture.

What It Looks Like

The thing about inflation is that it never goes away. This was something that was difficult to communicate, and why I ultimately ended up writing this article.

Let’s say you are a humble person, and you saved £10,000 since 2010 (after the 2008 financial recession)and put it in the bank.

0142 savings = 10000

Now to answer the question: How much is £10,000 worth now compared to £10,000 in the current market?

0143 plot_save = Plott(
0144   title = "Devaluation of Money in the UK",
0145   x_title = "Time (months since January 2010)",
0146   y_title = "Money (GBP £)",
0147   fg = "#FFF",
0148   bg = "#222"
0149 )
0150 # Setup X and Y axis
0151 x = [] # Date
0152 save = []
0153 zero = []
0154 y_carry = float(savings)
0155 y = [] # Accumalitive (de-)inflation
0156 z_carry = float(savings)
0157 z = [] # Accumalitive interest
0158 q_carry = float(savings)
0159 q = [] # Accumalitive combined
0160 for row in inflate_reader :
0161   year, month, inflation = inflate_parse_line(row)
0162   if year < 2010 : continue # Only since 2010
0163   x += [ ((year - 1989) * 12) + month ]
0164   save += [ savings ]
0165   zero += [ 0 ]
0166   # NOTE: Inflation is per annum, so must divide by 12 months.
0167   y_carry *= 100.0 / (100.0 + (inflation / 12))
0168   y += [ int(y_carry) ]
0169   interest = get_interest_rate(interest_reader, year, month)
0170   interest_file.seek(0) # Return to start of file
0171   z_carry *= (100.0 + (interest / 12)) / 100.0
0172   z += [ int(z_carry) ]
0173   q_carry *= 100.0 / (100.0 + (inflation / 12))
0174   q_carry *= (100.0 + (interest / 12)) / 100.0
0175   q += [ q_carry ]
0176 plot_save.plot(x, save, "£" + str(savings) + " fixed (0% inflation)")
0177 plot_save.plot(x, zero, "£0 (for context)")
0178 plot_save.plot(x, y, "£" + str(savings) + " at UK inflation")
0179 plot_save.plot(x, z, "£" + str(savings) + " at UK interest")
0180 plot_save.plot(x, q, "£" + str(savings) + " at UK interest under UK inflation (combined)")
0181 inflate_file.seek(0) # Reset the position into the file
0182 print(plot_save.to_uri()) # Display the graph
0183 print("In the time since 2010 (" + str(max_year - 2010) + " years)")
0184 print("Your £" + str(savings) + " since 2010 are now worth £" + str(q[-1]))
0185 eco_growth = (savings / q[-1]) * 100
0186 print("The economy appears to have grown by " + str(eco_growth) + "%")
0187 eco_growth_annual = (eco_growth - 100) / (max_year - 2010)
0188 print("Average annual growth by devaluing your savings: " + str(eco_growth_annual) + "%")

In the time since 2010 (14 years)
Your £10000 since 2010 are now worth £7579.712388452662
The economy appears to have grown by 131.93112729758104%
Average annual growth by devaluing your savings: 2.2807948069700745%

Even when considering the BoE set interest rates (which you may not be getting), the money sitting in the bank lost 25% of its value in 14 years. In the meantime, it looks as it the economy grew by 30+%!

Let that sink in for a minute.

Inflation is a form of tax for people who save money in the bank.3

Why? How?

By saving in the bank, the bank is allowed to lend out your money, whilst maintaining a reserve. The “bank’s money”, is in fact your money. For you allowing them to invest using you money (stocks, loans, etc), they in turn give you interest, and you in turn can store your money digitally and use it anywhere (in theory).

Where things get shit are as follows: Banks are risk adverse, so they only give you a small amount of the reward, and they handle the risk and additional profits. If for some reason they lose money, the UK government prints new money and increases inflation. In turn, all existing money has less purchasing power. As a result, the banks factor in the risk of inflation, and take further interest from your reward.

No matter the outcome, the following always remains true:

Unless

The average inflation rate since 2010 is calculated as:

0189 history = [
0190   [ 199, 0, 0 ], # Inflation since 1989
0191   [ 200, 0, 0 ],
0192   [ 201, 0, 0 ],
0193   [ 202, 0, 0 ],
0194 ]
0195 for row in inflate_reader :
0196   year, month, inflation = inflate_parse_line(row)
0197   for h in history :
0198     if year // 10 == h[0] :
0199       h[1] += inflation
0200       h[2] += 1
0201 inflate_file.seek(0) # Reset the position into the file
0202 for h in history :
0203   h[1] /= h[2]
0204   print("Average inflation in " + str(h[0] * 10) + ": " + str(h[1]) + "%")
Average inflation in 1990: 3.6241666666666665%
Average inflation in 2000: 1.9400000000000002%
Average inflation in 2010: 2.0666666666666678%
Average inflation in 2020: 4.519607843137256%

As you can see, inflation is on the rise. The incoming recession is far worse than anything since before the 1990s. The 2008 financial crisis is already nothing in comparison.

My suggestion is to invest in something with a >5% return on investment.

I would suggest you consider the following:

  1. What is the risk of this investment? For example, you could invest in Bitcoin, but most crypto has so far gone to zero.
  2. Am I over exposed to anything? For example, if you buy only gold and suddenly a golden cave is discovered, you’re screwed.
  3. How easily can I liquidate this investment? You could invest in bricks, a perfectly fine investment. The problem is that you can’t flood the local market with bricks, you will quickly saturate the market and the price goes to near zero.

I do not have the answer. Anybody claiming to do so is a liar, otherwise why aren’t they rich? If they are rich, how do you know you will also end up rich? Pyramid schemes rely on new buyers for growth… (I’m looking at you crypto.)

Good luck out there.


  1. CPIH Annual Rate 00: All Items 2025=100: https://www.ons.gov.uk/economy/inflationandpriceindices/timeseries/l55o/mm23.↩︎

  2. Official Bank Rate history: https://www.bankofengland.co.uk/boeapps/database/Bank-Rate.asp.↩︎

  3. Note that if you don’t save money in the bank, your prospects are slightly worse, but not by much.↩︎