Instructions
Objective
Write a python assignment to create GUI-for-wealth-management.
Requirements and Specifications
Create a GUI that calculates your wealth for each of the 70 years after you start work given the following inputs into the GUI:
- Mean Return (%) This is the average annual return of the investment above inflation
- Std Dev Return (%) This is a measure of the annual volatility of the investment
- Yearly Contribution ($)
- No. of Years of Contribution
- No. of Years to Retirement
- Annual Spend in Retirement
There should be Quit and Calculate buttons at the bottom. When you press calculate, a function should be called which uses the specified values to run the analysis 10 times, each time for 70 years. The GUI should display the average of those ten times of your wealth at retirement. The retirement should be in a label, not in an entry field!
Your python code should also plot your wealth as a function of year for each of the 10 analyses. The plot must show how much money is in the account for all 70 years. (If the money runs out before 70 years for a particular analysis, end the plot for that analysis the year the money runs out and have that curve terminate at the x axis. That is, you can't go below $0! And don't continue the line from where it goes to $0 to the end of the 70 years. The line ends when it hits the x axis.)
Following are example formulas to use for your calculations. Note that this is not the way you have to implement your code, just a way to clarify how values are calculated. (In fact, using the below equations in your code would not be very elegant...) The wealth in year (i+1) can be calculated from the wealth at year i as follows:
- From the start until contributions end: Wi+1=Wi(1+(r/100)+noise[i]) + Y
- From end of contributions until retirement: Wi+1=Wi(1+(r/100)+noise[i])
- From retirement to the end: Wi+1=Wi(1+(r/100)+noise[i]) - S
where r is the rate entered into the GUI, Y is the amount contributed each year (from the start until contributions stop), S is the amount spent each year in retirement (only following retirement), and noise is an array of 70 random values generated with
noise = (sigma/100)*np.random.randn(MAX_YEARS)
where sigma is the standard deviation entered into the GUI, and MAX_YEARS is 70 which, in your script, should be a constant!
NOTES:
- Start with $0 in year 0
- Contributions must stop at, or prior to, retirement.
- Withdrawals start the year after retirement
- If years to retirement is the same as years of contributions, then the function of equation (2) above is skipped
You may use either tkinter or PySimpleGui.
Write efficient code, that is, code that executes efficiently. Add comments!
Turn in a file called hw4.py.
Here are examples of the GUI and the resulting graphs. Note that, due to randomness, you'll not be able to duplicate these exact numbers. Note these are not drawn to scale...
Some installations of Python have a strange problem where the update to the average wealth at retirement doesn't show up until after the plot is closed. There are two possible ways to solve this problem. One, or both, may work for you:
Try either importing matplotlib like this:
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as pltOr
try doing plt.show() like this:
plt.show(block=False)
Source Code
from tkinter import *
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
import numpy as np
class GUI:
def __init__(self):
self.window = None
self.main_frame = None
# Number of simulations
self.N = 10
# Number of years
self.MAX_YEARS = 70
def run_analysis(self):
# Assume all inputs are correct
r = float(self.mean_return_txt.get())
sigma = float(self.std_return_txt.get())
Y = float(self.yearly_contrib_txt.get())
nyears_contrib = int(self.nyears_contrib_txt.get())
nyears_retirement = int(self.nyears_retir_txt.get())
S = float(self.annual_spend_txt.get())
# Create a NumpyArray to store all the simulations. This array will be size 10x70
self.W = np.zeros((self.N, self.MAX_YEARS+1))
# Start simulations
for n in range(self.N):
# Create the noise array
noise = (sigma/100)*np.random.randn(self.MAX_YEARS)
# Loop through years starting at year 1
for i in range(0, self.MAX_YEARS):
# Check if current year is less to year of contribution
if i <= nyears_contrib:
self.W[n,i+1] = self.W[n,i]*(1 + (r/100.0)+ noise[i]) + Y
elif i > nyears_contrib and i < (self.MAX_YEARS - nyears_retirement): # from end of contribution until retirement
self.W[n,i+1] = self.W[n,i]*(1 + (r/100.0) + noise[i])
elif i >= (self.MAX_YEARS - nyears_retirement): # from retirement to end
self.W[n,i+1] = self.W[n,i]*(1 + (r/100.0) + noise[i]) - S
# If the wealth for the current eyar is less than zero, stop the simulation
if self.W[n,i+1] < 0:
self.W[n,i+1] = 0
break
# Now that we have the results for 10 simulations (each one for 70 years) we calclate the average
self.Wavg = np.mean(self.W, axis = 0)
# Display result in label
self.result_lbl.config(text = "{:.2f}".format(self.Wavg[-1]))
# Plot
plt.plot(range(0, self.MAX_YEARS+1), self.Wavg)
plt.xlabel('Years')
plt.ylabel('Wealth ($)')
plt.grid(True)
plt.show(block=False)
def initialize(self):
"""
This function will create the main window and fill it with all the required
components such as buttons, labels, textboxes, etc
:return: Window (Tkinter object)
"""
# Create window
window = Tk()
window.geometry("330x300")
# Add a frame that will contains the labels to display results
main_frame = Frame(self.window)
main_frame.place(relx = 0.5, rely = 0.5, anchor = CENTER)
# Add Labels
mean_return_lbl = Label(main_frame, text = "Mean Return (%): ")
std_return_lbl = Label(main_frame, text = "Std Dev Return (%): ")
yearly_contrib_lbl = Label(main_frame, text = "Yearly Contribution ($): ")
nyears_contrib_lbl = Label(main_frame, text = "No. of Years of Contribution: ")
nyears_retir_lbl = Label(main_frame, text = "No. of Years to Retirement: ")
annual_spend_lbl = Label(main_frame, text = "Annual Spend in Retirement: ")
result_title_lbl = Label(main_frame, text = "Wealth after 70 years ($): ")
self.result_lbl = Label(main_frame, text = "0")
# Add textboxes
self.mean_return_txt = Entry(main_frame)
self.std_return_txt = Entry(main_frame)
self.yearly_contrib_txt = Entry(main_frame)
self.nyears_contrib_txt = Entry(main_frame)
self.nyears_retir_txt = Entry(main_frame)
self.annual_spend_txt = Entry(main_frame)
# pack
mean_return_lbl.grid(row = 0, column = 1)
std_return_lbl.grid(row = 1, column = 1)
yearly_contrib_lbl.grid(row = 2, column = 1)
nyears_contrib_lbl.grid(row = 3, column = 1)
nyears_retir_lbl.grid(row = 4, column = 1)
annual_spend_lbl.grid(row = 5, column = 1)
result_title_lbl.grid(row = 6, column = 1)
self.result_lbl.grid(row = 6, column = 2)
self.mean_return_txt.grid(row=0, column=2)
self.std_return_txt.grid(row = 1, column = 2)
self.yearly_contrib_txt.grid(row=2, column=2)
self.nyears_contrib_txt.grid(row=3, column=2)
self.nyears_retir_txt.grid(row=4, column=2)
self.annual_spend_txt.grid(row=5, column=2)
# Add a Frame that will contain the buttons at the bottom of the window
buttons_frame = Frame(window)
buttons_frame.pack(side = BOTTOM)
# Add the Calculate and Quit buttons
self.calculate_button = Button(buttons_frame, text="Calculate", command = self.run_analysis)
self.quit_button = Button(buttons_frame, text="Quit")
# pack
self.calculate_button.grid(row = 0, column = 1)
self.quit_button.grid(row = 0, column = 2)
self.window = window
self.window.mainloop()
if __name__ == '__main__':
app = GUI()
app.initialize()