Skip to content

Instantly share code, notes, and snippets.

@jlinoff
Last active January 24, 2023 18:41
Show Gist options
  • Save jlinoff/f3fd81748b0bcb0a3b033b921e8ee85a to your computer and use it in GitHub Desktop.
Save jlinoff/f3fd81748b0bcb0a3b033b921e8ee85a to your computer and use it in GitHub Desktop.
social security plot showing cumulative benefits for different starts crossover point using matplotlib

simple line plot example using matplotlib

This example shows the cumulative payout of social security using a normalized base value. It can be used to determine the best time to start collecting social security.

Here are some things the graph tells us.

If you believe that social security will remain viable for your entire life and you expect to live past age 79, then it is better to start collecting social security as late as possible (age 70) because it maximizes your cumulative return.

If you believe that social security will remain viable for your entire life and you expect to die before age 75, then it is better to start collecting social security as early as possible (age 62) because it maximizes your cumulative return.

If you believe that social security will not remain viable after you are age 75 or, perhaps 79, then it is better to start collecting social security as early as possible (age 62) because it maximizes your cumulative return.

Run it like this.

git clone https://gist.github.com/f3fd81748b0bcb0a3b033b921e8ee85a.git ssa
cd ssa
pipenv install pylint matplotlib pyqt5
pipenv run ./ssa.py

Note that it assumes you are using a recent version of python3.

You can get console debug messages like this:

DEBUG=1 pipenv run ./ssa.py

This gist was tested on Ubuntu 22.04 and MacOS Ventura 13.1.

#!/usr/bin/env python3
'''
Find SSA crossover point.
% pipenv install pylint matplotlib pyqt5
% pipenv run ./ssa.py
% DEBUG=1 pipenv run ./ssa.py
Built and tested in ubuntu/gnome 22.04 on an old Macbook 2013 laptop.
'''
import os
import matplotlib.pyplot as plt
import numpy as np
DEBUG = int(os.getenv('DEBUG', '0'))
def ssa(base: float=1.0, # starting (base) renumeration
ipm: float=0.6666 # interest per month
):
'''SSA plot - annual with crossover'''
#base = 1 # base rate in dollars
#interest = 0.6666
ipa = ipm*12 # interest
fac = 1 + ipa / 100.
end = 25
ynas = []
for i in range(9):
age = 62 + i
# Note that the following loop is 1 based rather than 0 based
# because the value is for the end of each year.
xna = np.array([j+age for j in range(1, 1+end+(9-i))])
yna = (base * (xna - age))*(fac**i)
label = f'Age {age}'
plt.plot(xna, yna, label=label)
ynas.append(yna)
if DEBUG:
for i, arr in enumerate(ynas):
print(f'yna[{i}]:')
print(arr)
yna0 = ynas[0]
cages = [] # cross over ages
for i, arr in enumerate(ynas[1:], start=1):
for j, val in enumerate(arr):
k = j+i
if val > yna0[k]:
age = 62 + k
cages.append(age)
if DEBUG:
print(f'DEBUG: yna[{i}][{j}]: {val:>5.2f} '
f'k={k} yna0[{k}]={yna0[k]} age={age}')
break
xminca = min(cages)
xmaxca = max(cages)
plt.axvline(x=xminca, color='green', linestyle='dotted', label=f'first crossover {xminca}')
if xminca < xmaxca:
plt.axvline(x=xmaxca, color='red', linestyle='dotted', label=f'last crossover {xmaxca}')
#plt.annotate(f'Cumulative crossover @{xmaxca}', xy=(xmaxca+1, 13))
plt.xlabel("Recipient Age")
plt.ylabel('Normalized Cumulative Payout\n'
f'Assuming a Base Benefit of ${base} per year') # starting at $1 per year
plt.title('Social Security Payment Analysis\n'
f'Assuming {ipa:2.1f}% per month\nfor {end+9-1} years')
plt.legend()
plt.show()
def main():
'''main'''
ssa()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment