-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnew_estimate_cost_to_retire.py
82 lines (71 loc) · 4.55 KB
/
new_estimate_cost_to_retire.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# Import Yahoo finance data using yfinance
import numpy as np
import yfinance as yf
def main():
# Download historical s&p 500 data
data = yf.download('SPY', interval='1mo', start='1993-02-01')
# drop nan values
data = data.dropna()
# Calculate monthly returns
data['Returns'] = data['Adj Close'].pct_change()
data = data.dropna()
weekly_cost_of_living = 285
monthly_cost_of_living = weekly_cost_of_living * 4.33
annual_cost_of_living = monthly_cost_of_living * 12
n_years_liquid = 2
n_years_remaining = 87 - 30
long_term_investments_term = n_years_remaining - n_years_liquid
inflation = 0.015
short_term_interest_rate = 0.045
long_term_interest_rate = 0.09
pv_n_years_liquid_growing_annuity = annual_cost_of_living / (short_term_interest_rate - inflation) * (1 - ((1 + inflation) / (1 + short_term_interest_rate)) ** (n_years_liquid))
print(f'PV of {n_years_liquid} years of expenses growing at {inflation} inflation with {short_term_interest_rate} interest: {pv_n_years_liquid_growing_annuity}')
pv_fv_n_years_illiquid_growing_annuity = annual_cost_of_living * (1 + inflation)**n_years_liquid / (long_term_interest_rate - inflation) * (1 - ((1 + inflation) / (1 + long_term_interest_rate)) ** (long_term_investments_term))
pv_n_years_illiquid_growing_annuity = pv_fv_n_years_illiquid_growing_annuity / (1 + long_term_interest_rate)**n_years_liquid
print(f'PV of {long_term_investments_term} years of expenses growing at {inflation} inflation with {long_term_interest_rate} returns: {pv_n_years_illiquid_growing_annuity}')
total_required = pv_n_years_liquid_growing_annuity + pv_n_years_illiquid_growing_annuity
print(f'Total required: {total_required}')
# Simulate the ending value of a portfolio with the historical returns of the S&P 500
n_simulations = 100
# Calculate the ending value of the portfolio
months_survived = []
buffer = 220000 - total_required
for i in range(n_simulations):
illiquid_balance = pv_n_years_illiquid_growing_annuity + buffer
liquid_balance = pv_n_years_liquid_growing_annuity
new_cost_of_living = monthly_cost_of_living
# Simulate the ending value of a portfolio with the historical returns of the S&P 500
for j in range(n_years_remaining * 12):
new_cost_of_living = new_cost_of_living * (1 + inflation)**(1/12)
rand_return = data['Returns'].sample().iloc[0]
if liquid_balance - new_cost_of_living > 0:
liquid_balance = liquid_balance * (1 + short_term_interest_rate)**(1/12) - new_cost_of_living
elif illiquid_balance - new_cost_of_living > 0:
illiquid_balance = max(0, illiquid_balance * (1 + rand_return))
else:
# print(f'Failed to retire after {j+1} months')
months_survived.append(j+1)
break
top_up_amount = (new_cost_of_living * 12 / (short_term_interest_rate - inflation) * (1 - ((1 + inflation) / (1 + short_term_interest_rate)) ** (n_years_liquid)) - liquid_balance)
top_up_amount = min(illiquid_balance * rand_return, top_up_amount)
if top_up_amount > 0 and rand_return > 0 and illiquid_balance > 0:
liquid_balance = liquid_balance + min(top_up_amount, illiquid_balance * (1 + rand_return) - top_up_amount)
illiquid_balance = max(0, illiquid_balance * (1 + rand_return) - top_up_amount)
else:
illiquid_balance = illiquid_balance * (1 + rand_return)
# print(f'Month {j+1} liquid_balance: {liquid_balance}, illiquid_balance: {illiquid_balance}, rand_return: {rand_return}, top_up_amount: {top_up_amount}, monthly_cost_of_living: {new_cost_of_living}')
if (liquid_balance + illiquid_balance) <= 0:
# print(f'Failed to retire after {j+1} months')
months_survived.append(j+1)
break
if j == n_years_remaining * 12 - 1:
# print(f'Successfully retired after {j+1} months')
months_survived.append(j+1)
break
print(f'Average months survived: {np.mean(months_survived)}')
print(f'Median months survived: {np.median(months_survived)}')
print(f'95th percentile months survived: {np.percentile(months_survived, 95)}')
print(f'99th percentile months survived: {np.percentile(months_survived, 99)}')
print(f'Percent of simulations that failed: {len([x for x in months_survived if x < n_years_remaining * 12]) / n_simulations * 100}')
if __name__ == '__main__':
main()