Coffee Space


Listen:

Silver and Gold

Preview Image

I am thinking about the possibility of buying silver and/or gold, and want to explain my thinking here so that others may inspect my rationale.

Motivation

I have been earning an okay city wage for over a year now, and I have paid off debts I had accumulated whilst studying my PhD (that I will one day finish). I now have money sitting in the bank, and I am coming close to exhausting all investment options that they offer.

Even so, I have several concerns holding money in the bank:

  1. EU negative interest rate experiment: The EU experimented with negative interest rates for corporations over the best part of 10 years as German banks reduced their vault cash. This in turn incentivised people to keep money moving, rather than stored in German banks. One could imagine that this could be used as a mechanism to keep money moving in a stalling economy.
  2. China’s economy is dying: China, the place that makes most things, is dying, in part due to a lack of foreign investment and trade. Everybody is tightening their belts and nobody is buying what China is selling. Eventually this will cause a complete economic collapse in China, and the result will be a complete collapse in the remaining profitable trade. This will likely trigger an enormous global recession as Western Countries hardly manufacture any more, thus they won’t be able to produce the things that support their economies. We saw during COVID the impact on various industries that were not able to get hold of Chinese chips - imagine this but far worse. It’s not if, it’s when.
  3. Failure of fractional reserve banking: The entire world uses fractional reserve banking, and it comes with several massive risks. Systemic risk can arise where the failure of one bank can propagate throughout the entire banking network, even across borders. It has also caused an enormous inflation of the money supply, which is why buying a house becomes more expensive, as the availability of money is out of control.
  4. Central Bank Digital Currency (CBDC): The BoE’s CBDC proposal is to switch to an entirely digital currency, as they force people to use cash less and less. The problem is that it has even less worth than normal currency, with the worst attributes. The IMF for example have played with the idea of controlling precisely what you can or can’t spend your CBDC on. With CBDCs they are proposing a micro-tax on all transactions, which is simply another way to keep your indefinitely poor. Various supermarkets throughout the UK are beginning to stop accepting cash, so we can expect a cashless society is just around the corner.

There are many other reasons, but these will suffice for now.

The final objective is to store wealth in a robust way, that could be later be used to make a large purchase, such as a house.

Research Questions

Like any good project, we should define some research questions:

  1. Which precious metal realises a greater return on investment, silver or gold?
  2. How historically volatile is each metal, when compared to a fixed-interest rate with a bank?
  3. How long may each metal need to be held to safely realise a profit on investment?

Historic Values

The first thing we can do is grab the historic values for silver and gold (using this website) as 20 year tracking (the largest they provide).

Note: In 2010 there were two January closes, skipping February and onto March. Given the low resolution we treat the data, the 31st31^{st} of January 2010 was manually set to 1st1^{st} of February 2010. In the grand scheme of things it makes no difference to the result.

0001 import csv
0002 from datetime import datetime
0003 import math
0004 # Process silver closing prices
0005 history_silver = { "date": [], "close": [] }
0006 with open("silver-and-gold/AGX-USD-2592000-20241014230807.csv") as silver_csv :
0007   silver_reader = csv.reader(silver_csv, delimiter = ",", quotechar= '"')
0008   for row in silver_reader :
0009     if row[0] == "Date" : continue
0010     row[0] = datetime.strptime(row[0], "%H:%M:%S %d-%b-%Y")
0011     for i in range(1, len(row)) :
0012       if len(row[i]) > 0 : row[i] = float(row[i])
0013     history_silver["date"] += [ row[0].year + ((1 / 12.0) * (row[0].month - 1)) ]
0014     history_silver["close"] += [ math.log(row[3], 10) ]
0015 # Process gold closing prices
0016 history_gold = { "date": [], "close": [] }
0017 with open("silver-and-gold/AUX-USD-2592000-20241014230833.csv") as gold_csv :
0018   gold_reader = csv.reader(gold_csv, delimiter = ",", quotechar= '"')
0019   for row in gold_reader :
0020     if row[0] == "Date" : continue
0021     row[0] = datetime.strptime(row[0], "%H:%M:%S %d-%b-%Y")
0022     for i in range(1, len(row)) :
0023       if len(row[i]) > 0 : row[i] = float(row[i])
0024     history_gold["date"] += [ row[0].year + ((1 / 12.0) * (row[0].month - 1)) ]
0025     history_gold["close"] += [ math.log(row[3], 10) ]
0026 # Plot that graph
0027 p = Plott(
0028   title = "Gold and Silver vs USD",
0029   x_title = "Date (as float)",
0030   y_title = "Close (USD, log base 10)",
0031   fg = "#FFF",
0032   bg = "#222"
0033 )
0034 p.plot(history_silver["date"], history_silver["close"], "Silver", colour = "#C0C0C0")
0035 p.plot(history_gold["date"], history_gold["close"], "Gold", colour = "#FFD700")
0036 print(p.to_uri())

Now we want a function to be able to retrieve the price of silver or gold given a year or month:

0037 # get_close()
0038 #
0039 # For a given year, get the closing value for a given metal.
0040 #
0041 # @param metal The chosen metal, silver or gold.
0042 # @param year The year to be checked.
0043 # @param month The month to be checked.
0044 # @return The closing value for the given metal, or None if not found.
0045 def get_close(metal = "silver", year = 2024, month = 1) :
0046   close = None
0047   date = year + ((1 / 12.0) * (month - 1))
0048   data = { "date": [], "close": [] }
0049   if metal == "silver" :
0050     data["date"] = history_silver["date"]
0051     data["close"] = history_silver["close"]
0052   elif metal == "gold" :
0053     data["date"] = history_gold["date"]
0054     data["close"] = history_gold["close"]
0055   for i in range(len(data["date"])) :
0056     if data["date"][i] == date :
0057       close = 10 ** data["close"][i]
0058       break
0059   return close
0060 
0061 print("January 2007 gold was " + str(get_close("gold", 2007, 1)))
0062 print("January 2007 silver was " + str(get_close("silver", 2007, 1)))
January 2007 gold was 21498.709999999985
January 2007 silver was 449.4699999999999

Manually inspecting the result, this looks good!

Current Prices

For this, I manually had to pull the values from the Royal Mint. I wanted to use their JSON API, but it literally returns HTML! There are two raw files of text I scraped, one for silver and one for gold.

This isn’t perfect, but it’s the easiest data to collect. We parse it like so:

0063 # read_royal_mint()
0064 #
0065 # Read the text manually copied and pasted from the Royal Mint product
0066 # listings. A reasonable attempt is then made to parse the data and pull out
0067 # important information.
0068 #
0069 # @param files The files to be parsed.
0070 # @return The parsed data.
0071 def read_royal_mint(files = []) :
0072   weights = [
0073     " 1/4oz ",
0074     " 1oz ", " 2oz ", " 5oz ", " 10oz ", " 20oz ", " 50oz ", " 100oz ",
0075     " 1g ", " 2g ", " 5g ", " 10g ", " 20g ", " 50g ", " 100g ", " 500g ", " 1kg ",
0076     " Kilo ",
0077     " 50p ", " £5 ",
0078     " $2.5 ", " $5 ", " $10 ", " $20 ",
0079     " Sixpence ", " Dollar ", "Penny", "Quarter", "Half", " Francs ",
0080     "Sovereign", "Coin", "Medal", "Set", "Crown", "Guinea", "Unite", "Mohur", "Shield", "Africa", "Birthday",
0081   ]
0082   data = []
0083   group = { "break": False, "line": 1, "other": [] }
0084   for f in files :
0085     with open(f) as file :
0086       line_no = 1
0087       for line in file :
0088         line = line.strip()
0089         if not group["break"] :
0090           if len(line) <= 0 :
0091             if not "type" in group : group["type"] = "Unknown"
0092             if not "title" in group : group["title"] = "Unknown"
0093             if not "title_full" in group : group["title_full"] = "Unknown"
0094             if not "edition" in group : group["edition"] = "Unknown"
0095             if "price" in group : group.pop("price")
0096             group["break"] = True
0097           elif not "type" in group :
0098             group["type"] = line
0099             if "Silver" in line : group["metal"] = "Silver"
0100             elif "Gold" in line : group["metal"] = "Gold"
0101             else :
0102               #print(f + "::" + str(line_no) + " Unknown metal '" + line + "'")
0103               group["metal"] = "Unknown"
0104           elif not "title" in group :
0105             # Sometimes the type is not provided
0106             if line.startswith(group["type"]) :
0107               group["title_full"] = line
0108               group["title"] = group["type"]
0109               group["metal"] = "Unknown"
0110               group["type"] = "Unknown"
0111               #print(f + "::" + str(line_no) + " Unknown metal (late)")
0112             else :
0113               group["title"] = line
0114           elif not "title_full" in group and line.startswith(group["title"]) :
0115             group["title_full"] = line
0116           elif not "title_full" in group :
0117             group["other"] += [ line ]
0118           else :
0119             group["other"] += [ line ]
0120         else :
0121           if not "price" in group and line.startswith("Price") :
0122             group["price"] = line
0123             group["price_raw"] = float(line.split(" ")[-1].replace(",", "")[1:])
0124           elif "price" in group : # Group collected
0125             group["stock"] = line
0126             # Pull out the weight
0127             msg = group["title"]
0128             if "title_full" in group : msg += " " + group["title_full"]
0129             for weight in weights :
0130               if weight in msg :
0131                 group["weight"] = weight.strip()
0132                 break
0133             if not "weight" in group :
0134               print(f + "::" + str(line_no) + " No weight found: " + str(group))
0135               group["weight"] = "Unknown"
0136             # Store it
0137             data += [ group ]
0138             group = { "break": False, "line": line_no + 1, "other": [] }
0139           else : print(f + "::" + str(line_no) + " Parse failure '" + line + "'")
0140         line_no += 1
0141   return data
0142 
0143 # Process files
0144 royal_mint = read_royal_mint(["silver-and-gold/royal_mint_silver_2024_10_15.txt", "silver-and-gold/royal_mint_gold_2024_10_15.txt"])
silver-and-gold/royal_mint_gold_2024_10_15.txt::676 No weight found: {'break': True, 'line': 670, 'other': ['The Great Seals of the Realm - King Henry VIII - 1oz Fine Gold', 'Limited Edition 175'], 'type': 'The Great Seals of the Realm - King Henry VIII - 1oz Fine Gold', 'metal': 'Gold', 'title': 'only 175 available', 'title_full': 'Unknown', 'edition': 'Unknown', 'price': 'Price: £3,500.00', 'price_raw': 3500.0, 'stock': 'In Stock'}

There are some errors and it is not a great parsing, but it will do. Next let’s get some data.

0145 royal_mint_silver = []
0146 royal_mint_gold = []
0147 royal_mint_rejected = []
0148 for r in royal_mint :
0149   if r["metal"] == "Silver" or r["metal"] == "Gold" :
0150     if r["weight"] == "1/4oz" :
0151       r["weight_kg"] = 0.02834952 * 0.25
0152     elif r["weight"].endswith("oz") :
0153       # NOTE: Calculation is in troy ounces!
0154       r["weight_kg"] = float(r["weight"][:-2]) * 0.0311034768
0155     elif r["weight"] == "Kilo" :
0156       r["weight_kg"] = 1
0157     elif r["weight"].endswith("kg") :
0158       r["weight_kg"] = float(r["weight"][:-2])
0159     elif r["weight"].endswith("g") :
0160       r["weight_kg"] = float(r["weight"][:-1]) * 0.001
0161     if not "weight_kg" in r : royal_mint_rejected += [ r ]
0162     else :
0163       if r["metal"] == "Silver" : royal_mint_silver += [ r ]
0164       elif r["metal"] == "Gold" : royal_mint_gold += [ r ]
0165       else : royal_mint_rejected += [ r ]
0166   else : royal_mint_rejected += [ r ]
0167 
0168 print("Useful data: " + str(
0169   100.0 * (
0170   (len(royal_mint_silver) + len(royal_mint_gold)) /
0171   (len(royal_mint_silver) + len(royal_mint_gold) + len(royal_mint_rejected))
0172   )) + "%")
Useful data: 49.72067039106145%

Near enough 50% is usable, that’ll do. Let’s process this data:

0173 rm_silver_cost = []
0174 rm_silver_weight = []
0175 rm_gold_cost = []
0176 rm_gold_weight = []
0177 for r in royal_mint_silver :
0178   rm_silver_cost += [ math.log(r["price_raw"], 10) ]
0179   rm_silver_weight += [ math.log(r["weight_kg"], 10) ]
0180 for r in royal_mint_gold :
0181   rm_gold_cost += [ math.log(r["price_raw"], 10) ]
0182   rm_gold_weight += [ math.log(r["weight_kg"], 10) ]
0183 # Plot that graph
0184 p = Plott(
0185   title = "Gold and Silver: Weight per Cost",
0186   x_title = "Cost (log base 10 GBP)",
0187   y_title = "Weight (log base 10 kg)",
0188   fg = "#FFF",
0189   bg = "#222"
0190 )
0191 p.plot(rm_silver_cost, rm_silver_weight, "Silver", colour = "#C0C0C0")
0192 p.plot(rm_gold_cost, rm_gold_weight, "Gold", colour = "#FFD700")
0193 print(p.to_uri())

To get good value for money, you want the largest weight possible with the lowest cost possible - or put more simply, the best weight per cost ratio. Let’s see it:

0194 def sort_key_kg_gbp(e) :
0195   return e["weight_kg"] / e["price_raw"]
0196 
0197 royal_mint_silver.sort(key = sort_key_kg_gbp, reverse = True)
0198 royal_mint_gold.sort(key = sort_key_kg_gbp, reverse = True)
0199 
0200 print("Weight\tCost\tg/GBP\tTitle")
0201 for r in (royal_mint_silver[:5] + royal_mint_gold[:5]) :
0202   print(
0203     str(round(r["weight_kg"], 3)) + "kg\t£" +
0204     str(int(r["price_raw"])) + "\t" +
0205     str(round(r["weight_kg"] * 1000 / r["price_raw"], 5)) + "\t" +
0206     r["title"]
0207   )
Weight	Cost	g/GBP	Title
0.311kg	£273	1.13616	The Royal Tudor Beasts 2024 Tudor Dragon Silver 10oz Bullion Coin
0.311kg	£273	1.13616	The Royal Tudor Beasts 2024 Seymour Unicorn 10oz Silver Bullion Coin
0.311kg	£273	1.13616	Little John 2024 10oz Silver Bullion Coin
0.031kg	£28	1.10413	Best Value 1oz Silver Bullion Coin
0.031kg	£28	1.10413	The Best Value Britannia 1oz Silver Bullion Coin
1.0kg	£66906	0.01495	1kg Gold Bullion Cast Bar
0.5kg	£33518	0.01492	500g Gold Bullion Cast Bar
0.031kg	£2085	0.01492	Best Value Gold 1oz Bullion Coin
0.031kg	£2117	0.01469	Britannia 2025 1oz Gold Bullion Coin
0.031kg	£2117	0.01469	Britannia 2024 1oz Gold Bullion Coin

This was a useful exercise! I realised the following:

  1. I was calculating the weights on ounces and not troy ounces - a big difference!
  2. The silver bullion coins I originally discounted actually represent great value, especially being CGT free!

These values overlayed on the original graph:

0208 rm_best_silver_cost = []
0209 rm_best_silver_weight = []
0210 rm_best_gold_cost = []
0211 rm_best_gold_weight = []
0212 for r in royal_mint_silver[:5] :
0213   rm_best_silver_cost += [ math.log(r["price_raw"], 10) ]
0214   rm_best_silver_weight += [ math.log(r["weight_kg"], 10) ]
0215 for r in royal_mint_gold[:5] :
0216   rm_best_gold_cost += [ math.log(r["price_raw"], 10) ]
0217   rm_best_gold_weight += [ math.log(r["weight_kg"], 10) ]
0218 p.plot(rm_best_silver_cost, rm_best_silver_weight, "Silver (Best)", colour = "#FF0088")
0219 p.plot(rm_best_gold_cost, rm_best_gold_weight, "Gold (Best)", colour = "#00CC00")
0220 print(p.to_uri())

And we can see we have correctly pulled out the most top left values quite well.

Predicting Profit

An interesting fact is that with gold you don’t pay VAT, and is CGT exempt on coins, whereas with silver you pay VAT, but don’t pay CGT. Let us write a function to allow us to predict the potential gains (or losses) given some simulations:

0221 vat = 0.2 # 20%
0222 cgt = 0.28 # 28%
0223 cgt_limit = 12300
0224 
0225 # sim_buy_sell()
0226 #
0227 # Simulate buying and selling of precious metals using historic data.
0228 #
0229 # @param metal The precious metal being traded, silver or gold.
0230 # @param kg The amount of precious metal being traded.
0231 # @param buy_year The buy-in year.
0232 # @param buy_month The buy-in month.
0233 # @param sell_year The sell-out year.
0234 # @param sell_month The sell-out month.
0235 # @return Key metrics, including the buy-in price, the sell-out price, the
0236 # costs in trading (if it applies) and the profist/loss difference made
0237 # overall.
0238 def sim_buy_sell(metal = "silver", kg = 1, buy_year = 2024, buy_month = 1, sell_year = 2024, sell_month = 1) :
0239   buy_market = get_close(metal, buy_year, buy_month)
0240   sell_market = get_close(metal, sell_year, sell_month)
0241   ratio_market = sell_market / buy_market
0242   costs = 0
0243   buy_price = 0
0244   if metal == "silver" :
0245     buy_price = (royal_mint_silver[0]["price_raw"] / royal_mint_silver[0]["weight_kg"]) * kg
0246     costs += buy_price * vat
0247   elif metal == "gold" :
0248     buy_price = (royal_mint_gold[0]["price_raw"] / royal_mint_gold[0]["weight_kg"]) * kg
0249   # NOTE: We avoid CGT for both as coins.
0250   sell_price = ratio_market * buy_price
0251   return { "buy": buy_price, "sell": sell_price, "diff": sell_price - (buy_price + costs), "costs": costs }
0252 
0253 print(sim_buy_sell("silver", 1, 2007, 1, 2024, 1))
0254 print(sim_buy_sell("gold", 0.01325, 2007, 1, 2024, 1))
{'buy': 880.1588380627595, 'sell': 1474.829530084248, 'diff': 418.63892440893665, 'costs': 176.0317676125519}
{'buy': 886.5088725, 'sell': 2669.2656048860813, 'diff': 1782.7567323860812, 'costs': 0}

We assume that we buy in at ~£880 in January 2007 and sell January 2024. I roughly balanced the two metals buy value (not considering tax). We see that our return on silver is ~50%, but our return on gold is ~200%. Of that profit, as it is CGT exempt, it is non-taxable too!

Possibly more useful is being able to define an investment gbp, i.e. an investment available, which would account for any payable taxes.

Normally tax is calculated at (where vat=0.2vat = 0.2 (20%)):

total=cost×(1+vat) total = cost \times (1 + vat)

Instead we know how much we want our total investment to be, so we calculate as follows:

total1+vat=cost \frac{total}{1 + vat} = cost

0255 # sim_invest()
0256 #
0257 # Similar to sim_buy_sell(), except we set an investment amount rather than
0258 # weight. We then simulate buying and selling of precious metals using historic
0259 # data.
0260 #
0261 # @param metal The precious metal being traded, silver or gold.
0262 # @param gbp The total investment, including incurred costs.
0263 # @param buy_year The buy-in year.
0264 # @param buy_month The buy-in month.
0265 # @param sell_year The sell-out year.
0266 # @param sell_month The sell-out month.
0267 # @return Key metrics, including the buy-in price, the sell-out price, the
0268 # costs in trading (if it applies) and the profist/loss difference made
0269 # overall.
0270 def sim_invest(metal = "silver", gbp = 1000, buy_year = 2024, buy_month = 1, sell_year = 2024, sell_month = 1) :
0271   kg = 0
0272   if metal == "silver" :
0273     kg = (royal_mint_silver[0]["weight_kg"] / royal_mint_silver[0]["price_raw"]) * gbp
0274     kg = kg / (1.0 + vat)
0275   elif metal == "gold" :
0276     kg = (royal_mint_gold[0]["weight_kg"] / royal_mint_gold[0]["price_raw"]) * gbp
0277   return sim_buy_sell(metal, kg, buy_year, buy_month, sell_year, sell_month)
0278 
0279 print(sim_invest("silver", 1000, 2007, 1, 2024, 1))
0280 print(sim_invest("gold", 1000, 2007, 1, 2024, 1))
{'buy': 833.3333333333333, 'sell': 1396.3668320466318, 'diff': 396.3668320466319, 'costs': 166.66666666666666}
{'buy': 1000.0, 'sell': 3010.9857754255936, 'diff': 2010.9857754255936, 'costs': 0}

We see gold has a buy-in of £1000, whereas silver has a buy-in of ~£833 + ~£167 of costs for a total of £1000. Great!

Multi-Year Hold

The market data goes back to February 2005, and up to October 2024. We can make some predictions about different holding times based on historic data.

Additionally, let’s consider how the money may fair in the bank with some simplistic flat interest returns:

  • Zero line - No interest applied at all.
  • 0.5% - Represents an unhealthy economy.
  • 1% - A relatively normal interest rate.
  • 2% - A healthy economy interest rate.
  • 5% - High interest account, which are usually fixed-year and have an investment risk.

Note: Money made over a CGT threshold in interest is subject to CGT (capital gains tax), especially these high-interest accounts where stocks and investments are concerned.

Let’s write a method to plot multi-year holdings and simulate!

0281 # plot_hold()
0282 #
0283 # A helper function for plotting the outcome of holding onto precious metals
0284 # over time given historic data.
0285 #
0286 # @param beg_year The year to run the simulations from.
0287 # @param beg_month The month to run the simulations from.
0288 # @param end_year The year to run the simulations to.
0289 # @param end_month The month to run the simulations to.
0290 # @param hold_years The number of years to hold the precious metal before selling.
0291 # @param bank_interest Compare against leaving money in the bank at different rates.
0292 def plot_hold(beg_year = 2005, beg_month = 2, end_year = 2024, end_month = 10, hold_years = 2, bank_interest = [ 0.005, 0.01, 0.02, 0.05 ]) :
0293   investment = 1000
0294   silver_x = []
0295   silver_y = []
0296   gold_x = []
0297   gold_y = []
0298   zero_y = []
0299   # Calculate metals investment
0300   for year in range(beg_year, end_year + 1 - hold_years) :
0301     for month in range(1, 12 + 1) :
0302       if beg_year == year and beg_month > month : continue
0303       if end_year - hold_years == year and end_month < month : break
0304       x = year + ((1.0 / 12) * (month - 1))
0305       silver_predict = sim_invest("silver", investment, year, month, year + hold_years, month)
0306       silver_x += [ x ]
0307       if silver_predict["diff"] >= 0 : silver_y += [ math.log(silver_predict["diff"], 10) ]
0308       elif silver_predict["diff"] == 0 : silver_y += [ silver_predict["diff"] ]
0309       else : silver_y += [ -math.log(-silver_predict["diff"], 10) ]
0310       gold_predict = sim_invest("gold", investment, year, month, year + hold_years, month)
0311       gold_x += [ x ]
0312       if gold_predict["diff"] >= 0 : gold_y += [ math.log(gold_predict["diff"], 10) ]
0313       elif gold_predict["diff"] == 0 : gold_y += [ gold_predict["diff"] ]
0314       else : gold_y += [ -math.log(-gold_predict["diff"], 10) ]
0315   zero_y = [ 0 ] * len(silver_x)
0316   bank = []
0317   # Show equivalent simplisitc bank investment
0318   for interest in bank_interest :
0319     i = investment
0320     for year in range(hold_years) :
0321       i *= 1.0 + interest
0322     profit = i - investment
0323     profit -= profit * cgt # Apply CGT (capital gains tax)
0324     bank += [ [ math.log(profit, 10) ] * len(silver_x) ]
0325   # Plot that data
0326   p = Plott(
0327     title = "Gold and Silver: " + str(hold_years) + " Year Hold Historic Predictions",
0328     x_title = "Buy Year",
0329     y_title = "Profit (log base 10 GBP)",
0330     fg = "#FFF",
0331     bg = "#222"
0332   )
0333   p.plot(silver_x, zero_y, "Zero line", colour = "#FF0000")
0334   p.plot(silver_x, silver_y, "Silver", colour = "#C0C0C0")
0335   p.plot(gold_x, gold_y, "Gold", colour = "#FFD700")
0336   for z in range(len(bank)) :
0337     p.plot(silver_x, bank[z], "Bank flat interest " + str(round(bank_interest[z] * 100, 2)) + "%")
0338   print(p.to_uri())
0339   return

Now let’s take a look!

0340 plot_hold(hold_years = 1)

Holding onto silver or gold for just a year does not seem wise. Unless you are lucky at you buy-in, you could very easily make a loss after holding for just a year. Why is this important? It means you are unlikely confidently hold for just a year and be able to liquidate your investment if you need it.

Over just a year, holding silver or gold could even be a worse investment than considering a fixed-interest investment with the bank.

0341 plot_hold(hold_years = 2)

With a two year hold on silver and gold it becomes clearer that gold falls last and recovers first. Events where silver outperforms gold exist, but are rare. You could be left holding silver or gold for a long time, which may represent significantly less value than banking the money.

0342 plot_hold(hold_years = 5)

When holding for 5 years, it seems clear that there could be large periods where you are unable to sell your investment without making a significant loss. Gold is begins to display significantly greater stability too. If you find yourself holding during a recession, you may be holding for a long time, especially if the buy-in was wrong.

Interestingly, the best thing you could probably do is double-down on your position and buy the metals at the new lower price.

0343 plot_hold(hold_years = 10)

Holding gold over a period of 10 years is far more stable in gold than silver. Gold represents nearly as good an investment as a fixed high interest account.

0344 plot_hold(hold_years = 15)

Holding gold for longer than 15 years is almost always a better investment than a high interest account. Bare in mind that this doesn’t account for risk, something that our historic simulations attempt to account for!

Finally

Let us consider each of the original research questions…

  1. Which precious metal realises a greater return on investment, silver or gold?

Other than some weird short-term edge-cases, it appears that gold is consistently a better investment than silver, especially when holding for two years or more.

  1. How historically volatile is each metal, when compared to a fixed-interest rate with a bank?

We have ultimately made a massive assumption with the interest rates that banks can provide, and yet have a relatively realistic expectation of how volatile silver and gold can be expected to be.

  1. How long may each metal need to be held to safely realise a profit on investment?

It really depends on the buy-in market. With a 5 year hold the market is relatively stable, but this position could translate to a 10 year or 15 year hold to realise full gains.

If I do invest in silver and gold, it will be a case of watching the stock market and investing at a good price. Ideally I would wait for a drop in the price of precious metals.