my-markdown-library 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/F24LS_md/ Lecture 4 - Public.md +347 -0
  3. data/F24LS_md/Lecture 1 - Introduction and Overview.md +327 -0
  4. data/F24LS_md/Lecture 10 - Development_.md +631 -0
  5. data/F24LS_md/Lecture 11 - Econometrics.md +345 -0
  6. data/F24LS_md/Lecture 12 - Finance.md +692 -0
  7. data/F24LS_md/Lecture 13 - Environmental Economics.md +299 -0
  8. data/F24LS_md/Lecture 15 - Conclusion.md +272 -0
  9. data/F24LS_md/Lecture 2 - Demand.md +349 -0
  10. data/F24LS_md/Lecture 3 - Supply.md +329 -0
  11. data/F24LS_md/Lecture 5 - Production C-D.md +291 -0
  12. data/F24LS_md/Lecture 6 - Utility and Latex.md +440 -0
  13. data/F24LS_md/Lecture 7 - Inequality.md +607 -0
  14. data/F24LS_md/Lecture 8 - Macroeconomics.md +704 -0
  15. data/F24LS_md/Lecture 8 - Macro.md +700 -0
  16. data/F24LS_md/Lecture 9 - Game Theory_.md +436 -0
  17. data/F24LS_md/summary.yaml +105 -0
  18. data/F24Lec_MD/LecNB_summary.yaml +206 -0
  19. data/F24Lec_MD/lec01/lec01.md +267 -0
  20. data/F24Lec_MD/lec02/Avocados_demand.md +425 -0
  21. data/F24Lec_MD/lec02/Demand_Steps_24.md +126 -0
  22. data/F24Lec_MD/lec02/PriceElasticity.md +83 -0
  23. data/F24Lec_MD/lec02/ScannerData_Beer.md +171 -0
  24. data/F24Lec_MD/lec02/demand-curve-Fa24.md +213 -0
  25. data/F24Lec_MD/lec03/3.0-CubicCostCurve.md +239 -0
  26. data/F24Lec_MD/lec03/3.1-Supply.md +274 -0
  27. data/F24Lec_MD/lec03/3.2-sympy.md +332 -0
  28. data/F24Lec_MD/lec03/3.3a-california-energy.md +120 -0
  29. data/F24Lec_MD/lec03/3.3b-a-really-hot-tuesday.md +121 -0
  30. data/F24Lec_MD/lec04/lec04-CSfromSurvey-closed.md +335 -0
  31. data/F24Lec_MD/lec04/lec04-CSfromSurvey.md +331 -0
  32. data/F24Lec_MD/lec04/lec04-Supply-Demand-closed.md +519 -0
  33. data/F24Lec_MD/lec04/lec04-Supply-Demand.md +514 -0
  34. data/F24Lec_MD/lec04/lec04-four-plot-24.md +34 -0
  35. data/F24Lec_MD/lec04/lec04-four-plot.md +34 -0
  36. data/F24Lec_MD/lec05/Lec5-Cobb-Douglas.md +131 -0
  37. data/F24Lec_MD/lec05/Lec5-CobbD-AER1928.md +283 -0
  38. data/F24Lec_MD/lec06/6.1-Sympy-Differentiation.md +253 -0
  39. data/F24Lec_MD/lec06/6.2-3D-utility.md +287 -0
  40. data/F24Lec_MD/lec06/6.3-QuantEcon-Optimization.md +399 -0
  41. data/F24Lec_MD/lec06/6.4-latex.md +138 -0
  42. data/F24Lec_MD/lec06/6.5-Edgeworth.md +269 -0
  43. data/F24Lec_MD/lec07/7.1-inequality.md +283 -0
  44. data/F24Lec_MD/lec07/7.2-historical-inequality.md +237 -0
  45. data/F24Lec_MD/lec08/macro-fred-api.md +313 -0
  46. data/F24Lec_MD/lec09/lecNB-prisoners-dilemma.md +88 -0
  47. data/F24Lec_MD/lec10/Lec10.2-waterguard.md +401 -0
  48. data/F24Lec_MD/lec10/lec10.1-mapping.md +199 -0
  49. data/F24Lec_MD/lec11/11.1-slr.md +305 -0
  50. data/F24Lec_MD/lec11/11.2-mlr.md +171 -0
  51. data/F24Lec_MD/lec12/Lec12-4-PersonalFinance.md +590 -0
  52. data/F24Lec_MD/lec12/lec12-1_Interest_Payments.md +267 -0
  53. data/F24Lec_MD/lec12/lec12-2-stocks-options.md +235 -0
  54. data/F24Lec_MD/lec13/Co2_ClimateChange.md +139 -0
  55. data/F24Lec_MD/lec13/ConstructingMAC.md +213 -0
  56. data/F24Lec_MD/lec13/EmissionsTracker.md +170 -0
  57. data/F24Lec_MD/lec13/KuznetsHypothesis.md +219 -0
  58. data/F24Lec_MD/lec13/RoslingPlots.md +217 -0
  59. data/F24Lec_MD/lec15/vibecession.md +485 -0
  60. data/F24Textbook_MD/00-intro/index.md +292 -0
  61. data/F24Textbook_MD/01-demand/01-demand.md +152 -0
  62. data/F24Textbook_MD/01-demand/02-example.md +131 -0
  63. data/F24Textbook_MD/01-demand/03-log-log.md +284 -0
  64. data/F24Textbook_MD/01-demand/04-elasticity.md +248 -0
  65. data/F24Textbook_MD/01-demand/index.md +15 -0
  66. data/F24Textbook_MD/02-supply/01-supply.md +203 -0
  67. data/F24Textbook_MD/02-supply/02-eep147-example.md +86 -0
  68. data/F24Textbook_MD/02-supply/03-sympy.md +138 -0
  69. data/F24Textbook_MD/02-supply/04-market-equilibria.md +204 -0
  70. data/F24Textbook_MD/02-supply/index.md +16 -0
  71. data/F24Textbook_MD/03-public/govt-intervention.md +73 -0
  72. data/F24Textbook_MD/03-public/index.md +10 -0
  73. data/F24Textbook_MD/03-public/surplus.md +351 -0
  74. data/F24Textbook_MD/03-public/taxes-subsidies.md +282 -0
  75. data/F24Textbook_MD/04-production/index.md +15 -0
  76. data/F24Textbook_MD/04-production/production.md +178 -0
  77. data/F24Textbook_MD/04-production/shifts.md +296 -0
  78. data/F24Textbook_MD/05-utility/budget-constraints.md +166 -0
  79. data/F24Textbook_MD/05-utility/index.md +15 -0
  80. data/F24Textbook_MD/05-utility/utility.md +136 -0
  81. data/F24Textbook_MD/06-inequality/historical-inequality.md +253 -0
  82. data/F24Textbook_MD/06-inequality/index.md +15 -0
  83. data/F24Textbook_MD/06-inequality/inequality.md +226 -0
  84. data/F24Textbook_MD/07-game-theory/bertrand.md +257 -0
  85. data/F24Textbook_MD/07-game-theory/cournot.md +333 -0
  86. data/F24Textbook_MD/07-game-theory/equilibria-oligopolies.md +96 -0
  87. data/F24Textbook_MD/07-game-theory/expected-utility.md +61 -0
  88. data/F24Textbook_MD/07-game-theory/index.md +19 -0
  89. data/F24Textbook_MD/07-game-theory/python-classes.md +340 -0
  90. data/F24Textbook_MD/08-development/index.md +35 -0
  91. data/F24Textbook_MD/09-macro/CentralBanks.md +101 -0
  92. data/F24Textbook_MD/09-macro/Indicators.md +77 -0
  93. data/F24Textbook_MD/09-macro/fiscal_policy.md +36 -0
  94. data/F24Textbook_MD/09-macro/index.md +14 -0
  95. data/F24Textbook_MD/09-macro/is_curve.md +76 -0
  96. data/F24Textbook_MD/09-macro/phillips_curve.md +70 -0
  97. data/F24Textbook_MD/10-finance/index.md +10 -0
  98. data/F24Textbook_MD/10-finance/options.md +178 -0
  99. data/F24Textbook_MD/10-finance/value-interest.md +60 -0
  100. data/F24Textbook_MD/11-econometrics/index.md +16 -0
  101. data/F24Textbook_MD/11-econometrics/multivariable.md +218 -0
  102. data/F24Textbook_MD/11-econometrics/reading-econ-papers.md +25 -0
  103. data/F24Textbook_MD/11-econometrics/single-variable.md +483 -0
  104. data/F24Textbook_MD/11-econometrics/statsmodels.md +58 -0
  105. data/F24Textbook_MD/12-environmental/KuznetsHypothesis-Copy1.md +187 -0
  106. data/F24Textbook_MD/12-environmental/KuznetsHypothesis.md +187 -0
  107. data/F24Textbook_MD/12-environmental/MAC.md +254 -0
  108. data/F24Textbook_MD/12-environmental/index.md +36 -0
  109. data/F24Textbook_MD/LICENSE.md +11 -0
  110. data/F24Textbook_MD/intro.md +26 -0
  111. data/F24Textbook_MD/references.md +25 -0
  112. data/F24Textbook_MD/summary.yaml +414 -0
  113. metadata +155 -0
@@ -0,0 +1,590 @@
1
+ ---
2
+ title: "Lec12-4-PersonalFinance"
3
+ type: lecture-notebook
4
+ week: 12
5
+ source_path: "/Users/ericvandusen/Documents/Data88E-ForTraining/F24Lec_NBs/lec12/Lec12-4-PersonalFinance.ipynb"
6
+ ---
7
+
8
+ <table style="width: 100%;" id="nb-header">
9
+ <tr style="background-color: transparent;"><td>
10
+ <img src="https://data-88e.github.io/assets/images/blue_text.png" width="250px" style="margin-left: 0;" />
11
+ </td><td>
12
+ <p style="text-align: right; font-size: 10pt;"><strong>Economic Models</strong>, Fall 24 <br>
13
+ Dr. Eric Van Dusen
14
+ <br>
15
+ </table>
16
+
17
+ ```python
18
+ from datascience import Table
19
+ import numpy as np
20
+ import matplotlib.pyplot as plt
21
+ import ipywidgets as widgets
22
+ from IPython.display import display
23
+ %matplotlib inline
24
+ ```
25
+
26
+ ```python
27
+ try: import yfinance as yf
28
+ except:
29
+ !pip install yfinance
30
+ import yfinance as yf
31
+ ```
32
+
33
+ ## Personal Finance Demo
34
+
35
+ ### This notebook will demonstrate some basic concepts in personal finance, over time, using Python.
36
+ - Rate of Savings
37
+ - Impact of Fees on Returns over Time
38
+ - Monte Carlo Simulation of Retirement Savings
39
+ - Historical Returns of Stocks and Bonds
40
+
41
+
42
+ The notebook will also motivate the use of widgets in Jupyter notebooks to interact with the data and see the impact of different parameters on the results.
43
+
44
+ ### Part 1: Rate of Savings
45
+
46
+ ```python
47
+ annual_income_widget = widgets.FloatText(
48
+ value=50000,
49
+ description='Annual Income:',
50
+ style={'description_width': 'initial'}
51
+ )
52
+
53
+ savings_rate_widget = widgets.FloatSlider(
54
+ value=0.2,
55
+ min=0,
56
+ max=1,
57
+ step=0.01,
58
+ description='Savings Rate (%):',
59
+ style={'description_width': 'initial'}
60
+ )
61
+
62
+ years_widget = widgets.IntSlider(
63
+ value=30,
64
+ min=1,
65
+ max=50,
66
+ step=1,
67
+ description='Years:',
68
+ style={'description_width': 'initial'}
69
+ )
70
+
71
+ annual_return_widget = widgets.FloatSlider(
72
+ value=0.05,
73
+ min=0,
74
+ max=0.2,
75
+ step=0.01,
76
+ description='Annual Return (%):',
77
+ style={'description_width': 'initial'}
78
+ )
79
+ display(annual_income_widget, savings_rate_widget, years_widget, annual_return_widget)
80
+ ```
81
+
82
+ Save these values as variables
83
+
84
+ ```python
85
+ annual_income = annual_income_widget.value
86
+ savings_rate = savings_rate_widget.value
87
+ years = years_widget.value
88
+ annual_return = annual_return_widget.value
89
+ ```
90
+
91
+ Set a formula for the rate of savings
92
+
93
+ ```python
94
+ annual_savings = annual_income * savings_rate
95
+ ```
96
+
97
+ Create an array of years
98
+
99
+ ```python
100
+ years_array = np.arange(1, years + 1)
101
+ savings_growth = []
102
+ ```
103
+
104
+ Calculate the savings for each year, create total savings appending each year's savings to the previous year's savings
105
+
106
+ ```python
107
+ total_savings = 0
108
+ for year in years_array:
109
+ # Add annual savings and apply growth
110
+ total_savings += annual_savings
111
+ total_savings *= (1 + annual_return)
112
+ savings_growth.append(total_savings)
113
+ ```
114
+
115
+ Create a Table to store the results
116
+
117
+ ```python
118
+ savings_table = Table().with_columns(
119
+ "Year", years_array,
120
+ "Total Savings ($)", savings_growth
121
+ )
122
+
123
+ savings_table
124
+ ```
125
+
126
+ ```python
127
+
128
+ plt.figure(figsize=(10, 6))
129
+ plt.plot(years_array, savings_growth, marker='o')
130
+ plt.title("Savings Growth Over Time")
131
+ plt.xlabel("Years")
132
+ plt.ylabel("Total Savings ($)")
133
+ plt.grid(True)
134
+ plt.show()
135
+ ```
136
+
137
+ ## Part 2 - Retirement Planning & Fees on Investments
138
+
139
+ ```python
140
+ initial_investment_widget = widgets.FloatText(
141
+ value=10000,
142
+ description='Initial Investment ($):',
143
+ style={'description_width': 'initial'}
144
+ )
145
+
146
+ annual_return_widget_fee = widgets.FloatSlider(
147
+ value=0.07,
148
+ min=0,
149
+ max=0.2,
150
+ step=0.01,
151
+ description='Annual Return (%):',
152
+ style={'description_width': 'initial'}
153
+ )
154
+
155
+ years_widget_fee = widgets.IntSlider(
156
+ value=30,
157
+ min=1,
158
+ max=50,
159
+ step=1,
160
+ description='Investment Duration (Years):',
161
+ style={'description_width': 'initial'}
162
+ )
163
+
164
+ fee_percentage_widget = widgets.FloatSlider(
165
+ value=0.01,
166
+ min=0,
167
+ max=0.05,
168
+ step=0.005,
169
+ description='Annual Fee (%):',
170
+ style={'description_width': 'initial'}
171
+ )
172
+ second_fee_percentage_widget = widgets.FloatSlider(
173
+ value=0.02,
174
+ min=0,
175
+ max=0.05,
176
+ step=0.005,
177
+ description='Annual Fee Comparison (%):',
178
+ style={'description_width': 'initial'}
179
+ )
180
+
181
+ display(initial_investment_widget, annual_return_widget_fee, years_widget_fee, fee_percentage_widget, second_fee_percentage_widget)
182
+ ```
183
+
184
+ Retrieve widget values for calculations
185
+
186
+ ```python
187
+ initial_investment = initial_investment_widget.value
188
+ annual_return = annual_return_widget_fee.value
189
+ years = years_widget_fee.value
190
+ annual_fee = fee_percentage_widget.value
191
+ annual_fee_2 = second_fee_percentage_widget.value
192
+ ```
193
+
194
+ Initialize arrays for growth with and without fees
195
+
196
+ Set starting values for investments
197
+
198
+ ```python
199
+ years_array = np.arange(1, years + 1)
200
+ growth_without_fees = []
201
+ growth_with_fee_1 = []
202
+ growth_with_fee_2 = []
203
+
204
+ investment_without_fees = initial_investment
205
+ investment_with_fee_1 = initial_investment
206
+ investment_with_fee_2 = initial_investment
207
+ ```
208
+
209
+ Build a growth path for the three options
210
+
211
+ ```python
212
+ for year in years_array:
213
+ # Growth without fees
214
+ investment_without_fees *= (1 + annual_return)
215
+ growth_without_fees.append(investment_without_fees)
216
+
217
+ # Growth with fee 1
218
+ net_return_1 = annual_return - annual_fee
219
+ investment_with_fee_1 *= (1 + net_return_1)
220
+ growth_with_fee_1.append(investment_with_fee_1)
221
+
222
+ # Growth with fee 2
223
+ net_return_2 = annual_return - annual_fee_2
224
+ investment_with_fee_2 *= (1 + net_return_2)
225
+ growth_with_fee_2.append(investment_with_fee_2)
226
+ ```
227
+
228
+ Create a Table to store the results
229
+
230
+ ```python
231
+ fees_table = Table().with_columns(
232
+ "Year", years_array,
233
+ "Growth Without Fees ($)", growth_without_fees,
234
+ "Growth With Fees ($)", growth_with_fee_1,
235
+ "Growth With Fees 2 ($)", growth_with_fee_2
236
+ )
237
+
238
+
239
+ fees_table.show()
240
+ ```
241
+
242
+ ```python
243
+ # Plot the growth over time
244
+ plt.figure(figsize=(10, 6))
245
+ plt.plot(years_array, growth_without_fees, label="Without Fees", marker='o')
246
+ plt.plot(years_array, growth_with_fee_1, label=f"With Fees ({annual_fee*100:.2f}%)", marker='o', linestyle='--')
247
+ plt.plot(years_array, growth_with_fee_2, label=f"With Fee 2 ({annual_fee_2*100:.2f}%)", marker='o', linestyle=':')
248
+ plt.title("Investment Growth Over Time with and without Fees")
249
+ plt.xlabel("Years")
250
+ plt.ylabel("Investment Value ($)")
251
+ plt.legend()
252
+ plt.grid(True)
253
+ plt.show()
254
+ ```
255
+
256
+ ```python
257
+
258
+ ```
259
+
260
+ ## Part 3: Allocation of Assets
261
+
262
+ Let's simulate the impact of different asset allocations on the growth of investments over time.
263
+
264
+ In this example we will consider two asset classes: Stocks and Bonds.
265
+
266
+ We will use a simple model of the growth of investments in each asset class over time but with variable returns in each time period.
267
+
268
+ This model will be for a one time initial investment, but we will simulate the growth over multiple time periods.
269
+
270
+ Set up the widgets
271
+
272
+ ```python
273
+ initial_investment_widget_alloc = widgets.FloatText(
274
+ value=10000,
275
+ description='Initial Investment ($):',
276
+ style={'description_width': 'initial'}
277
+ )
278
+
279
+ years_widget_alloc = widgets.IntSlider(
280
+ value=30,
281
+ min=1,
282
+ max=50,
283
+ step=1,
284
+ description='Investment Duration (Years):',
285
+ style={'description_width': 'initial'}
286
+ )
287
+
288
+ stock_allocation_widget = widgets.FloatSlider(
289
+ value=0.6,
290
+ min=0,
291
+ max=1,
292
+ step=0.05,
293
+ description='Stock Allocation (%):',
294
+ style={'description_width': 'initial'}
295
+ )
296
+
297
+
298
+ display(initial_investment_widget_alloc, years_widget_alloc, stock_allocation_widget)
299
+ ```
300
+
301
+ Set up average returns and standard deviations for stocks and bonds
302
+
303
+ ( these are hard coded for now - but could be widgets as well)
304
+
305
+ ```python
306
+ average_stock_return = 0.08 # 8% average annual return for stocks
307
+ average_bond_return = 0.03 # 3% average annual return for bonds
308
+ std_dev_stock = 0.15 # 15% annual standard deviation for stocks
309
+ std_dev_bond = 0.05 # 5% annual standard deviation for bonds
310
+ ```
311
+
312
+ ```python
313
+ initial_investment = initial_investment_widget_alloc.value
314
+ years = years_widget_alloc.value
315
+ stock_allocation = stock_allocation_widget.value
316
+ bond_allocation = 1 - stock_allocation
317
+ ```
318
+
319
+ ```python
320
+ years_array = np.arange(1, years + 1)
321
+ growth_allocation = []
322
+ ```
323
+
324
+ Calculate growth based on random returns derived from asset allocation
325
+
326
+ This will use the command 'np.random.normal' to generate random returns based on the average and standard deviation of returns for stocks and bonds
327
+
328
+ The arguments to 'np.random.normal' are the average return, the standard deviation of returns, that we hard coded above.
329
+
330
+ Think about it as each year the return is a random number drawn from a normal distribution with the average return and standard deviation we set above.
331
+
332
+ This will create a random path of returns for each year, as we rerun the cell, we will get a different path of returns. We could set a seed to get the same path of returns each time.
333
+
334
+ ```python
335
+ #set_seed(42)
336
+ investment_value = initial_investment
337
+ for year in years_array:
338
+ stock_return = np.random.normal(average_stock_return, std_dev_stock)
339
+ bond_return = np.random.normal(average_bond_return, std_dev_bond)
340
+
341
+ # Calculate the portfolio's annual return based on the allocation
342
+ portfolio_return = (stock_allocation * stock_return) + (bond_allocation * bond_return)
343
+
344
+ # Update the investment value based on the portfolio return
345
+ investment_value *= (1 + portfolio_return)
346
+ growth_allocation.append(investment_value)
347
+ ```
348
+
349
+ Create a Table to store the results
350
+
351
+ ```python
352
+ allocation_table = Table().with_columns(
353
+ "Year", years_array,
354
+ f"Growth with {stock_allocation*100:.0f}% Stocks / {bond_allocation*100:.0f}% Bonds ($)", growth_allocation
355
+ )
356
+
357
+ # Display the table
358
+ allocation_table.show()
359
+ ```
360
+
361
+ ```python
362
+
363
+ plt.figure(figsize=(10, 6))
364
+ plt.plot(years_array, growth_allocation, label=f"{stock_allocation*100:.0f}% Stocks / {bond_allocation*100:.0f}% Bonds", marker='o')
365
+ plt.title("Investment Growth Over Time with Asset Allocation (Including Volatility)")
366
+ plt.xlabel("Years")
367
+ plt.ylabel("Investment Value ($)")
368
+ plt.legend()
369
+ plt.grid(True)
370
+ plt.show()
371
+ ```
372
+
373
+ ## Part 4 Monte Carlo Simulation
374
+ What is the role of uncertainty in financial planning?
375
+
376
+ In the previous example, we have a single path for the growth of investments. However, in reality, the growth of investments is more complicated!
377
+
378
+ We can use Monte Carlo simulation to simulate the growth of investments over time. This would allow us to see the range of possible outcomes for our investments. Think of it as generating many paths of returns and seeing the range of outcomes. This is a powerful tool for financial planning.
379
+
380
+ Step 1 - Set up the widgets
381
+
382
+ We can add a widget for the number of simulations we want to run. This will allow us to see the range of outcomes for our investments.
383
+
384
+ ```python
385
+ initial_investment_widget_alloc = widgets.FloatText(
386
+ value=10000,
387
+ description='Initial Investment ($):',
388
+ style={'description_width': 'initial'}
389
+ )
390
+
391
+ years_widget_alloc = widgets.IntSlider(
392
+ value=30,
393
+ min=1,
394
+ max=50,
395
+ step=1,
396
+ description='Investment Duration (Years):',
397
+ style={'description_width': 'initial'}
398
+ )
399
+
400
+ stock_allocation_widget = widgets.FloatSlider(
401
+ value=0.6,
402
+ min=0,
403
+ max=1,
404
+ step=0.05,
405
+ description='Stock Allocation (%):',
406
+ style={'description_width': 'initial'}
407
+ )
408
+
409
+ simulations_widget = widgets.IntSlider(
410
+ value=1000,
411
+ min=100,
412
+ max=5000,
413
+ step=100,
414
+ description='Number of Simulations:',
415
+ style={'description_width': 'initial'}
416
+ )
417
+
418
+ # Display the widgets
419
+ display(initial_investment_widget_alloc, years_widget_alloc, stock_allocation_widget, simulations_widget)
420
+ ```
421
+
422
+ Again we will hard code the average returns and standard deviations for stocks and bonds. ( for a future project we could make these widgets as well! )
423
+
424
+ ```python
425
+ average_stock_return = 0.08
426
+ average_bond_return = 0.03
427
+ std_dev_stock = 0.15 # 15% annual standard deviation for stocks
428
+ std_dev_bond = 0.05 # 5% annual standard deviation for bonds
429
+ ```
430
+
431
+ ```python
432
+ # Retrieve widget values for calculations
433
+ initial_investment = initial_investment_widget_alloc.value
434
+ years = years_widget_alloc.value
435
+ stock_allocation = stock_allocation_widget.value
436
+ bond_allocation = 1 - stock_allocation
437
+ num_simulations = simulations_widget.value
438
+
439
+ # Initialize a list to store the final investment values of each simulation
440
+ final_values = []
441
+ ```
442
+
443
+ Build a loop to simulate the growth of investments over time. Running the simulaton multiple times is called a *Monte Carlo Simulation*.
444
+
445
+ This will be similar to the previous example, but we will run the simulation multiple times to see the range of outcomes. The inner loop is the same as the previous example, but in the outer loop we will run the simulation multiple times.
446
+
447
+ Create a Table to store the results `final-values`
448
+
449
+ Calculate the average and standard deviation of the results `final-values`
450
+
451
+ This entire function is wrapped in a plot function that will plot the results of each run of the Monte Carlo simulation. Think of it as 1000 different plots that map out the range of outcomes for the investments.
452
+
453
+ In the plot we have set the alpha to 0.1 so that we can see the overlap of the different paths. Alpha is a parameter that sets the transparency of the plot. So, the lower the alpha, the more transparent the plot.
454
+
455
+
456
+ We will also plot the average and standard deviation of the results. This will give us a sense of the range of outcomes for our investments.
457
+
458
+ ```python
459
+
460
+ plt.figure(figsize=(12, 8))
461
+ # Outer loop for running multiple simulations
462
+ for _ in range(num_simulations):
463
+ investment_value = initial_investment
464
+ growth_path = []
465
+
466
+ # Inner loop for each simulation
467
+ for year in range(years):
468
+ # Generate random returns for stocks and bonds based on mean and standard deviation
469
+ stock_return = np.random.normal(average_stock_return, std_dev_stock)
470
+ bond_return = np.random.normal(average_bond_return, std_dev_bond)
471
+
472
+ portfolio_return = (stock_allocation * stock_return) + (bond_allocation * bond_return)
473
+
474
+ investment_value *= (1 + portfolio_return)
475
+ growth_path.append(investment_value)
476
+
477
+ # Store the final investment value for this simulation
478
+ final_values.append(investment_value)
479
+
480
+ # Plot this simulation's growth path
481
+ plt.plot(range(1, years + 1), growth_path, color='blue', alpha=0.05) # alpha is the transparency level
482
+
483
+ # Calculate summary statistics of the final values across all simulations
484
+ mean_final_value = np.mean(final_values)
485
+ median_final_value = np.median(final_values)
486
+ percentile_10 = np.percentile(final_values, 10)
487
+ percentile_90 = np.percentile(final_values, 90)
488
+
489
+ # Plot the summary statistics on the chart
490
+ plt.title("Monte Carlo Simulation of Investment Growth with Asset Allocation")
491
+ plt.xlabel("Years")
492
+ plt.ylabel("Investment Value ($)")
493
+ plt.grid(True)
494
+ plt.axhline(mean_final_value, color='green', linestyle='--', label=f"Mean Final Value: ${mean_final_value:,.2f}")
495
+ plt.axhline(median_final_value, color='orange', linestyle='--', label=f"Median Final Value: ${median_final_value:,.2f}")
496
+ plt.axhline(percentile_10, color='red', linestyle='--', label=f"10th Percentile: ${percentile_10:,.2f}")
497
+ plt.axhline(percentile_90, color='purple', linestyle='--', label=f"90th Percentile: ${percentile_90:,.2f}")
498
+ plt.legend()
499
+ plt.show()
500
+ ```
501
+
502
+ ## Appendix (Part 4) - get the parameters for return and sd from the markets
503
+
504
+ We can get the average returns and standard deviations for stocks and bonds from the markets. This will allow us to use real data in our simulations.
505
+
506
+ We have hard coded the values for now, but we could use the market values to update our hard coded values above This would allow us to use real data in our simulations.
507
+
508
+ We will use the `yfinance` package to get the data from the markets. This package allows us to get data from Yahoo Finance in a simple way, no API key, and in the format we want.
509
+
510
+ We will use the `yfinance` package to get the data for the **S&P 500** and the **10 year treasury** bond. We will call the tickers for these assets `^GSPC` and `^TNX` respectively.
511
+
512
+ We will use the data to calculate the average annual returns and standard deviations for stocks and bonds. Using annual returns and standard deviations is clearly one limitation of this model, but it is a simple way to get a sense of the range of outcomes for our investments.
513
+
514
+ There are two important choices in the following code:
515
+ - The time period for the data
516
+ - The index for the data
517
+
518
+ *Note for Data 88E: There is a little Pandas manipulaton in the code to calculate the average annual returns and standard deviations for stocks and bonds. We will use the `ffill` and `resample` methods to fill in any missing values and to resample the data to get the annual returns and standard deviations. We will use the `dropna` method to remove any missing values from the data.*
519
+
520
+ ```python
521
+ start_date = "2000-01-01"
522
+ end_date = "2023-01-01"
523
+ ```
524
+
525
+ ```python
526
+ # Fetch historical data for S&P 500 (stocks) and TLT (bonds) using yfinance
527
+ stock_data = yf.download('^GSPC', start=start_date, end=end_date)
528
+ bond_data = yf.download('TLT', start=start_date, end=end_date)
529
+
530
+ # Convert to annual adjusted close prices by resampling to year-end and forward-filling
531
+ stock_data = stock_data['Adj Close'].resample('Y').ffill()
532
+ bond_data = bond_data['Adj Close'].resample('Y').ffill()
533
+
534
+ # Calculate annual returns as percentage change for stocks and bonds
535
+ stock_returns = stock_data.pct_change().dropna()
536
+ bond_returns = bond_data.pct_change().dropna()
537
+ ```
538
+
539
+ ```python
540
+ # Create datascience Tables for annual returns
541
+ stock_table = Table().with_columns("Year", stock_data.index.year[1:], "Stock Returns", stock_returns.values)
542
+ bond_table = Table().with_columns("Year", bond_data.index.year[1:], "Bond Returns", bond_returns.values)
543
+ ```
544
+
545
+ ```python
546
+ # Calculate mean and standard deviation using the Table methods
547
+ average_stock_return_data = stock_table.column("Stock Returns").mean()
548
+ std_dev_stock_data = stock_table.column("Stock Returns").std()
549
+ average_bond_return_data = bond_table.column("Bond Returns").mean()
550
+ std_dev_bond_data = bond_table.column("Bond Returns").std()
551
+ ```
552
+
553
+ ```python
554
+ # Display the results
555
+ print(f"Average Stock Return (Market Data): {average_stock_return_data * 100:.2f}%")
556
+ print(f"Stock Return Standard Deviation (Market Data): {std_dev_stock_data * 100:.2f}%")
557
+ print(f"Average Bond Return (Market Data): {average_bond_return_data * 100:.2f}%")
558
+ print(f"Bond Return Standard Deviation (Market Data): {std_dev_bond_data * 100:.2f}%")
559
+ ```
560
+
561
+ ## Updating the Monte Carlo Simulation with Market Data !?
562
+
563
+ - How do these results compare to the parameters that we hard coded above?
564
+ - What are the implications for financial planning?
565
+ - How do the results change if we use real data from the markets?
566
+
567
+ ```python
568
+ print( " Actual - Data")
569
+ print(f"Difference in Average Stock Return: {(average_stock_return - average_stock_return_data) * 100:.2f}%")
570
+ print(f"Difference in Stock Return Standard Deviation: {(std_dev_stock - std_dev_stock_data) * 100:.2f}%")
571
+ print(f"Difference in Average Bond Return: {(average_bond_return - average_bond_return_data) * 100:.2f}%")
572
+ print(f"Difference in Bond Return Standard Deviation: {(std_dev_bond - std_dev_bond_data) * 100:.2f}%")
573
+ ```
574
+
575
+ Looks like our hard-coded values were a bit optimistic?
576
+ - We overestimanted returns
577
+ - We underestimated volatility
578
+
579
+ ```python
580
+
581
+ ```
582
+
583
+ ```python
584
+
585
+ ```
586
+
587
+ ```python
588
+
589
+ ```
590
+