The graphs/formulas below are based on the book "Early Retirement Extreme". I'll use the term "Financial Independence" in place of "Early Retirement", but I mean that same thing as the author of that book.
import math
from ipywidgets import interact, interactive, IntSlider, FloatSlider
from matplotlib import pyplot
This formula calculates the length (in years) that a fund w/ starting_fund_years of value will last given an average of interest_rate return. Note that at some point, the fund will last indefinitely (handled in the "except" clause below).
$\frac{\log(\frac{1}{1 - \frac{P}{p}*\frac{i}{1 + i}})}{\log(1 + i)}$
def years_fund_will_last(starting_fund_years, interest_rate):
try:
a = starting_fund_years * (interest_rate / (1 + interest_rate))
denom = (1 - a)
first = 1 / denom
second = 1 + interest_rate
return math.log(first) / math.log(second)
except (ValueError, ZeroDivisionError):
return math.inf
So let's get a sense of how this works:
%matplotlib inline
@interact(fund_years=IntSlider(min=1, max=30, step=1, value=5),
interest_rate=IntSlider(min=1, max=30, step=1, value=5))
def details(fund_years, interest_rate):
years_lasted = round(years_fund_will_last(fund_years, interest_rate / 100), 2)
s = f'At a {interest_rate}% interest rate, a fund designed to last {fund_years} years will actually last {years_lasted} years'
print(s)
For the purposes of financial independence, we are interested in finding when an account becomes self-sustaining.
So let's approach it this way: Given an interest rate, how long of a fund would one need to have a self-sustaining fund?
%matplotlib inline
@interact(interest_rate=IntSlider(min=1, max=30, step=1, value=5))
def self_sustaining_based_on_interest_rate(interest_rate):
self_sustaining_years = None
for fund_years in range(0, 100):
if years_fund_will_last(fund_years, interest_rate / 100) == math.inf:
self_sustaining_years = fund_years
break
s = f'At a {interest_rate}% interest rate, you will need a fund of {self_sustaining_years} years to be self-sustaining.'
print(s)
Now, given a starting fund size, what kind of interest rate is necessary to make it self-sustaining?
%matplotlib inline
@interact(fund_years=IntSlider(min=1, max=20, step=1, value=5))
def self_sustaining_based_on_fund_size(fund_years):
self_sustaining_interest_rate = None
for interest_rate in range(1, 100):
if years_fund_will_last(fund_years, interest_rate / 100) == math.inf:
self_sustaining_interest_rate = interest_rate
break
s = f'For fund of {fund_years} years to be self-sustaining, you will need an interest rate of {self_sustaining_interest_rate}%.'
print(s)
Now, let's explore interest rates across funds of different sizes. Note that the graph will stop once the fund becomes self-sustaining.
%matplotlib inline
@interact(interest_rate=IntSlider(min=1, max=20, step=1, value=10))
def graph(interest_rate):
x = range(0, 21)
y = [years_fund_will_last(i, (interest_rate / 100)) for i in x]
pyplot.plot(x, y, marker='o', label='years')
for x, y in zip(x, y):
label = round(y, 2)
pyplot.annotate(str(label), (x, y),
xycoords='data',
textcoords='offset points',
xytext=(0, 5), ha='center')
pyplot.xlabel('Starting Fund Size (years)')
pyplot.ylabel('Years')
pyplot.legend()
Now, let's explore fund sizes across different interest rates. Note that the graph will stop once the fund becomes self-sustaining.
%matplotlib inline
@interact(fund_years=IntSlider(min=1, max=20, step=1, value=10))
def graph(fund_years):
x = range(0, 21)
y = [years_fund_will_last(fund_years, (i / 100)) for i in x]
pyplot.plot(x, y, marker='o', label='years')
for x, y in zip(x, y):
label = round(y, 2)
pyplot.annotate(str(label), (x, y),
xycoords='data',
textcoords='offset points',
xytext=(0, 5), ha='center')
pyplot.xlabel('Interest Rate (%)')
pyplot.ylabel('Years')
pyplot.legend()