owlplanner 2025.6.3__tar.gz → 2025.7.1__tar.gz
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.
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/PKG-INFO +6 -4
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/README.md +5 -3
- owlplanner-2025.7.1/RELEASE_NOTES.md +12 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/owl.pdf +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/owl.tex +184 -80
- owlplanner-2025.7.1/examples/case_drawdowncalc-comparison-1.toml +56 -0
- owlplanner-2025.7.1/examples/case_jack+jill.toml +57 -0
- owlplanner-2025.7.1/examples/case_joe.toml +54 -0
- owlplanner-2025.7.1/examples/case_john+sally.toml +53 -0
- owlplanner-2025.7.1/examples/case_jon+jane.toml +56 -0
- owlplanner-2025.7.1/examples/case_kim+sam-bequest.toml +56 -0
- owlplanner-2025.7.1/examples/case_kim+sam-spending.toml +56 -0
- owlplanner-2025.7.1/examples/jack+jill.xlsx +0 -0
- owlplanner-2025.7.1/examples/joe.xlsx +0 -0
- owlplanner-2025.7.1/examples/john+sally.xlsx +0 -0
- owlplanner-2025.7.1/examples/jon+jane.xlsx +0 -0
- owlplanner-2025.7.1/examples/kim+sam.xlsx +0 -0
- owlplanner-2025.7.1/examples/template.xlsx +0 -0
- owlplanner-2025.7.1/examples.new/case_drawdowncalc-comparison-1.toml +56 -0
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/case_jack+jill.toml +0 -1
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/case_joe.toml +0 -1
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/case_john+sally.toml +0 -1
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/case_jon+jane.toml +1 -2
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/case_kim+sam-bequest.toml +1 -2
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/case_kim+sam-spending.toml +1 -2
- owlplanner-2025.7.1/examples.new/jack+jill.xlsx +0 -0
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/joe.xlsx +0 -0
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/john+sally.xlsx +0 -0
- owlplanner-2025.7.1/examples.new/jon+jane.xlsx +0 -0
- owlplanner-2025.7.1/examples.new/kim+sam.xlsx +0 -0
- {owlplanner-2025.6.3/examples → owlplanner-2025.7.1/examples.new}/template.xlsx +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/notebooks/kim+sam.ipynb +0 -1
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/notebooks/template.ipynb +959 -961
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/notebooks/tutorial_1.ipynb +1078 -1080
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/notebooks/tutorial_2.ipynb +0 -1
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/notebooks/tutorial_3.ipynb +0 -1
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/pyproject.toml +1 -1
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/requirements.txt +2 -1
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/config.py +0 -2
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/plan.py +153 -76
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/tax2025.py +42 -9
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/timelists.py +11 -10
- owlplanner-2025.7.1/src/owlplanner/version.py +1 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_regressions.py +0 -1
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_repro.py +26 -15
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/About_Owl.py +12 -9
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Create_Case.py +17 -14
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Current_Assets.py +15 -9
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Documentation.py +102 -54
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Optimization_Parameters.py +7 -7
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Output_Files.py +13 -13
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Quick_Start.py +7 -6
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Rates_Selection.py +3 -8
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Settings.py +28 -1
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Wages_and_Contributions.py +33 -14
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/main.py +4 -2
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/owlbridge.py +20 -13
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/sskeys.py +6 -5
- owlplanner-2025.7.1/ui/tomlexamples.py +31 -0
- owlplanner-2025.6.3/examples/jack+jill.xlsx +0 -0
- owlplanner-2025.6.3/examples/jon+jane.xlsx +0 -0
- owlplanner-2025.6.3/src/owlplanner/version.py +0 -1
- owlplanner-2025.6.3/ui/tomlexamples.py +0 -16
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/.devcontainer/devcontainer.json +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/.flake8 +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/.gitattributes +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/.github/workflows/github-actions-runtests.yml +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/.gitignore +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/.streamlit/config.toml +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/.streamlit/fullconfig.toml +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/INSTALL.md +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/LICENSE +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/USER_GUIDE.md +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docker/Dockerfile.build +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docker/Dockerfile.run +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docker/README.md +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docker/buildentrypoint.sh +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docker/docker-compose.yml +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docker/runentrypoint.sh +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/AD-taxDef.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/AD-taxFree.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/AD-taxable.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/Hist_Bequest.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/Hist_Spending.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/MC-tutorial2a.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/MC-tutorial2b.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/OwlUI.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/allocations.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/owl.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/profile.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/ratesCorrelations.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/ratesPlot.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/savingsPlot.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/sourcesPlot.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/spendingPlot.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/taxIncomePlot.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/docs/images/taxesPlot.png +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/notebooks/john+sally.ipynb +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/owlplanner.cmd +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/owlplanner.sh +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/pytest.ini +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/__init__.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/abcapi.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/data/__init__.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/data/rates.csv +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/mylogging.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/plotting/__init__.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/plotting/base.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/plotting/factory.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/plotting/matplotlib_backend.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/plotting/plotly_backend.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/progress.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/rates.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/src/owlplanner/utils.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_logger.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_toml_cases.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_ui_asset_allocation.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_ui_compare_summaries.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_ui_sskeys.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/tests/test_units.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Asset_Allocation.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Fixed_Income.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Graphs.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Historical_Range.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Logs.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Monte_Carlo.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/README.md +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/Worksheets.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/__init__.py +0 -0
- {owlplanner-2025.6.3 → owlplanner-2025.7.1}/ui/progress.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: owlplanner
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.7.1
|
|
4
4
|
Summary: Owl: Retirement planner with great wisdom
|
|
5
5
|
Project-URL: HomePage, https://github.com/mdlacasse/owl
|
|
6
6
|
Project-URL: Repository, https://github.com/mdlacasse/owl
|
|
@@ -837,6 +837,8 @@ which are all tracked separately for married individuals. Asset transition to th
|
|
|
837
837
|
is done according to beneficiary fractions for each type of savings account.
|
|
838
838
|
Tax status covers married filing jointly and single, depending on the number of individuals reported.
|
|
839
839
|
|
|
840
|
+
Maturation rules for Roth contributions and conversions are implemented as constraints
|
|
841
|
+
limiting withdrawal amounts to cover Roth account balances for 5 years after the events.
|
|
840
842
|
Medicare and IRMAA calculations are performed through a self-consistent loop on cash flow constraints.
|
|
841
843
|
Future values are simple projections of current values with the assumed inflation rates.
|
|
842
844
|
|
|
@@ -885,7 +887,7 @@ assets to support, even with no estate being left.
|
|
|
885
887
|
- Streamlit Community Cloud [Streamlit](https://streamlit.io)
|
|
886
888
|
- Contributors: Josh (noimjosh@gmail.com) for Docker image code,
|
|
887
889
|
Dale Seng (sengsational) for great insights and suggestions,
|
|
888
|
-
Robert E. Anderson (NH-RedAnt) for bug fixes and suggestions.
|
|
890
|
+
Robert E. Anderson (NH-RedAnt) for bug fixes and suggestions, Clark Jefcoat (hubcity) for fruitful interactions.
|
|
889
891
|
|
|
890
892
|
---------------------------------------------------------------------
|
|
891
893
|
|
|
@@ -893,8 +895,8 @@ Copyright © 2024 - Martin-D. Lacasse
|
|
|
893
895
|
|
|
894
896
|
Disclaimers: This code is for educatonal purposes only and does not constitute financial advice.
|
|
895
897
|
|
|
896
|
-
Code output has been verified with analytical solutions and
|
|
897
|
-
Nevertheless, accuracy of results
|
|
898
|
+
Code output has been verified with analytical solutions when applicable, and comparative approaches otherwise.
|
|
899
|
+
Nevertheless, accuracy of results is not guaranteed.
|
|
898
900
|
|
|
899
901
|
--------------------------------------------------------
|
|
900
902
|
|
|
@@ -131,6 +131,8 @@ which are all tracked separately for married individuals. Asset transition to th
|
|
|
131
131
|
is done according to beneficiary fractions for each type of savings account.
|
|
132
132
|
Tax status covers married filing jointly and single, depending on the number of individuals reported.
|
|
133
133
|
|
|
134
|
+
Maturation rules for Roth contributions and conversions are implemented as constraints
|
|
135
|
+
limiting withdrawal amounts to cover Roth account balances for 5 years after the events.
|
|
134
136
|
Medicare and IRMAA calculations are performed through a self-consistent loop on cash flow constraints.
|
|
135
137
|
Future values are simple projections of current values with the assumed inflation rates.
|
|
136
138
|
|
|
@@ -179,7 +181,7 @@ assets to support, even with no estate being left.
|
|
|
179
181
|
- Streamlit Community Cloud [Streamlit](https://streamlit.io)
|
|
180
182
|
- Contributors: Josh (noimjosh@gmail.com) for Docker image code,
|
|
181
183
|
Dale Seng (sengsational) for great insights and suggestions,
|
|
182
|
-
Robert E. Anderson (NH-RedAnt) for bug fixes and suggestions.
|
|
184
|
+
Robert E. Anderson (NH-RedAnt) for bug fixes and suggestions, Clark Jefcoat (hubcity) for fruitful interactions.
|
|
183
185
|
|
|
184
186
|
---------------------------------------------------------------------
|
|
185
187
|
|
|
@@ -187,8 +189,8 @@ Copyright © 2024 - Martin-D. Lacasse
|
|
|
187
189
|
|
|
188
190
|
Disclaimers: This code is for educatonal purposes only and does not constitute financial advice.
|
|
189
191
|
|
|
190
|
-
Code output has been verified with analytical solutions and
|
|
191
|
-
Nevertheless, accuracy of results
|
|
192
|
+
Code output has been verified with analytical solutions when applicable, and comparative approaches otherwise.
|
|
193
|
+
Nevertheless, accuracy of results is not guaranteed.
|
|
192
194
|
|
|
193
195
|
--------------------------------------------------------
|
|
194
196
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
### Version 2025.07.01
|
|
2
|
+
|
|
3
|
+
- Added Net Investment Income Tax calculations in self-consistent loop
|
|
4
|
+
- Added capability to load example Excel sheet directly in UI
|
|
5
|
+
- Added constraint for 5-year maturation rule on Roth conversions
|
|
6
|
+
- Added capability to read last 5 years in Wages and Contributions file
|
|
7
|
+
- Added option in UI to turn off sticky header
|
|
8
|
+
- Added RELEASE_NOTES file
|
|
9
|
+
- Improved color scheme in header gradient for visibility
|
|
10
|
+
- Removed long-term capital tax rate from options. Rate is now automatically calculated in self-consistent loop.
|
|
11
|
+
- Added option to use HiGHS library through PuLP for speed comparison with DrawdownCalc. Using HiGHS diretly is by far the fastest option.
|
|
12
|
+
- Add option for menu position thanks to Streamlit 1.46.
|
|
Binary file
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
\documentclass{report}[fleqn,12pt]
|
|
2
2
|
\usepackage{amsmath}
|
|
3
|
+
\usepackage{amsfonts}
|
|
3
4
|
\usepackage{enumitem}
|
|
4
5
|
\usepackage{bm}
|
|
5
6
|
\usepackage{blindtext}
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
\begin{document}
|
|
33
34
|
\title{Formulation of the optimization model in Owl}
|
|
34
35
|
\author{Martin-D. Lacasse}
|
|
35
|
-
\date{
|
|
36
|
+
\date{June 13, 2025}
|
|
36
37
|
\maketitle
|
|
37
38
|
\thispagestyle{fancy}
|
|
38
39
|
\fancyfoot[R]{\copyright\ 2024 - Martin-D. Lacasse}
|
|
@@ -115,12 +116,12 @@ to take only non-negative values ($\ge 0$ inequality).
|
|
|
115
116
|
sometimes be less that the standard exemption $\bar{\sigma}_n$, leading to a
|
|
116
117
|
negative taxable income if the inflation-adjusted standard exemption is simply subtracted
|
|
117
118
|
from the gross taxable income $G_n$.
|
|
118
|
-
\item [$f_{
|
|
119
|
+
\item [$f_{tn}$]
|
|
119
120
|
Fraction of tax bracket $t$ filled, so that taxable ordinary income $G_n$ can be expressed as
|
|
120
121
|
\begin{eqnarray}
|
|
121
122
|
\label{Eq:Tx1}
|
|
122
|
-
G_n = \sum_t f_{
|
|
123
|
-
0 \leq f_{
|
|
123
|
+
G_n = \sum_t f_{tn}\bar{\Delta}_{tn},\\
|
|
124
|
+
0 \leq f_{tn} \leq 1.
|
|
124
125
|
\end{eqnarray}
|
|
125
126
|
A definition of $\Delta$ can be found in the section describing the parameters below.
|
|
126
127
|
\item [$g_n$]
|
|
@@ -135,11 +136,12 @@ to take only non-negative values ($\ge 0$ inequality).
|
|
|
135
136
|
\item [$x_{in}$]
|
|
136
137
|
Roth conversion performed by individual $i$ during year $n$.
|
|
137
138
|
These events are taxable as ordinary income.
|
|
139
|
+
\item [$z_{xn}$]
|
|
140
|
+
Variables denoted $z$ are reserved for binary variables.
|
|
138
141
|
\end{description}
|
|
139
142
|
|
|
140
143
|
\section{Parameters}
|
|
141
|
-
For more easily distinguishing parameters from variables, all parameters will be expressed either in Greek letters
|
|
142
|
-
or using caligraphic fonts.
|
|
144
|
+
For more easily distinguishing parameters from variables, all parameters will be expressed either in Greek letters.
|
|
143
145
|
Parameter values are either set by the user, historical data, or by the tax code.
|
|
144
146
|
\begin{description}[leftmargin=4em,style=multiline]
|
|
145
147
|
\item [$\beta_{ij}$]
|
|
@@ -155,9 +157,8 @@ Parameter values are either set by the user, historical data, or by the tax code
|
|
|
155
157
|
\gamma_n = \prod_{n' = 0}^{n-1} (1 + \tau_{3n'}),
|
|
156
158
|
\end{equation}
|
|
157
159
|
with $\gamma_0 := 1$, and where $n'$ is a dummy index.
|
|
158
|
-
As the time span of interest goes from the first year to the beginning
|
|
159
|
-
of the year following the last year,
|
|
160
|
-
variable $\gamma_n$ will have $N_n + 1$ elements.
|
|
160
|
+
As the time span of interest goes from the beginning of the first year to the beginning
|
|
161
|
+
of the year following the last year, variable $\gamma_n$ will have $N_n + 1$ elements.
|
|
161
162
|
Parameters indexed for inflation will be indicated by a bar on top as in $\bar{\sigma}_n$.
|
|
162
163
|
\item [$\sigma_n$]
|
|
163
164
|
Standard deduction. It can be adjusted for inflation as follows
|
|
@@ -177,7 +178,7 @@ Parameter values are either set by the user, historical data, or by the tax code
|
|
|
177
178
|
The {\em smile} can be implemented using a cosine superimposed over a gentle linear increase
|
|
178
179
|
such as in
|
|
179
180
|
\begin{equation}
|
|
180
|
-
\xi_n = 1 + a_1
|
|
181
|
+
\xi_n = 1 + a_1*\cos(2n\pi/(N_n-1)) + a_2n/(N_n-1),
|
|
181
182
|
\end{equation}
|
|
182
183
|
and then normalized by factor $N_n/(\sum_n \xi_n )$ to be sum-neutral with respect to a flat profile.
|
|
183
184
|
Values of $a_1 = 15\%$ and $a_2=12\%$ provide curves that are similar to realistic
|
|
@@ -229,9 +230,10 @@ Parameter values are either set by the user, historical data, or by the tax code
|
|
|
229
230
|
Then, intermediate values are interpolated either using
|
|
230
231
|
a linear relation,
|
|
231
232
|
\begin{equation}
|
|
232
|
-
\alpha_{ijkn} = a + \frac{n}{
|
|
233
|
+
\alpha_{ijkn} = a + \frac{n}{N - 1} (b - a),
|
|
233
234
|
\end{equation}
|
|
234
|
-
|
|
235
|
+
where $N$ is either $n_d$ or $N_n$,
|
|
236
|
+
or using an s-curve as in
|
|
235
237
|
\begin{equation}
|
|
236
238
|
\alpha_{ijkn} = a + \frac{(b - a)}{2}
|
|
237
239
|
(\tanh((n-n_1)/n_2) + 1),
|
|
@@ -252,8 +254,8 @@ or an s-curve as in
|
|
|
252
254
|
\begin{eqnarray}
|
|
253
255
|
k_{11} &=& \frac{1}{2}(1 + \tanh(n_1/n_2)) \nonumber \\
|
|
254
256
|
k_{12} &=& \frac{1}{2}(1 - \tanh(n_1/n_2)) \nonumber \\
|
|
255
|
-
k_{21} &=& \frac{1}{2}(1 - \tanh((
|
|
256
|
-
k_{22} &=& \frac{1}{2}(1 + \tanh((
|
|
257
|
+
k_{21} &=& \frac{1}{2}(1 - \tanh((N-1-n_1)/n_2)) \nonumber \\
|
|
258
|
+
k_{22} &=& \frac{1}{2}(1 + \tanh((N-1-n_1)/n_2)).
|
|
257
259
|
\end{eqnarray}
|
|
258
260
|
These interpolation functions allow the allocation ratios to gradually change
|
|
259
261
|
or {\em glide} during retirement. Fig.~(\ref{Fig:allocations}) provides an example
|
|
@@ -318,7 +320,7 @@ or an s-curve as in
|
|
|
318
320
|
Sum of wages obtained by individual $i$ during year $n$.
|
|
319
321
|
Do not confuse wages $\omega$ with withdrawals $w$.
|
|
320
322
|
\item [$\mu$]
|
|
321
|
-
Dividend return rate for equities in taxable accounts. Average is little
|
|
323
|
+
Dividend return rate for equities in taxable accounts. Average is little below 2\% for S\&P 500.
|
|
322
324
|
\item [$\nu$]
|
|
323
325
|
Heirs income tax rate to be applied on the tax-deferred portion of the estate. This is not an estate tax
|
|
324
326
|
but rather the federal income marginal tax rate for the heirs.
|
|
@@ -343,80 +345,49 @@ or an s-curve as in
|
|
|
343
345
|
when $\phi_j \neq 1, \forall j$, it is recommended that $\eta$ be set to $i_d$ so that
|
|
344
346
|
all surplus get deposited to $i_d$'s accounts,
|
|
345
347
|
thus avoid loopholes when optimizing for the final bequest.
|
|
346
|
-
\item [$\mathcal{M}_n$]
|
|
347
|
-
Costs of Medicare and its Income Related Monthly Adjusted Adjustment (IRMAA).
|
|
348
|
-
As this additional adjustment
|
|
349
|
-
is a step function, it would have to be computed using binary variables and mixed-integer linear
|
|
350
|
-
programming. In the current tax code, this adjustment
|
|
351
|
-
depends on the modified adjusted gross income (MAGI) from 2 years earlier. For the
|
|
352
|
-
MAGI, we simply use $G_{n-2} + e_{n-2}$ (i.e., gross taxable income
|
|
353
|
-
plus standard deduction (exemption) from 2 years ago) and ignore the additional IRS
|
|
354
|
-
rules around tax-free interests which are insignificant in most cases. If the plan
|
|
355
|
-
has individuals above 63 years old, values of MAGI for previous years are requested from the user.
|
|
356
348
|
|
|
357
|
-
There are $q=5$ levels
|
|
358
|
-
of step adjustments adjusted for inflation,
|
|
359
|
-
$\bar{L}_{qn} = L_q\gamma_n$ and each of them introduces
|
|
360
|
-
an annual additional Medicare
|
|
361
|
-
cost of $\bar{C}_{qn} = C_q\gamma_n$, also adjusted for inflation.
|
|
362
|
-
One could use binary variables $z_{inq}$ and the following {\em big M} constraint
|
|
363
|
-
\begin{equation}
|
|
364
|
-
e_{n-2} -\bar{L}_{qn} \le z_{inq} M - G_{n-2}
|
|
365
|
-
\le M - \bar{L}_{qn} + e_{n-2},
|
|
366
|
-
\end{equation}
|
|
367
|
-
so that the IRMAA adjustments can be computed as
|
|
368
|
-
\begin{equation}
|
|
369
|
-
\label{Eq:IRMAA}
|
|
370
|
-
\mathcal{M}_n = \sum_{iq} z_{iqn} \bar{C}_{qn}.
|
|
371
|
-
\end{equation}
|
|
372
|
-
If the plan needs data from 1 or 2 years ago as Medicare has already started or will in the next years,
|
|
373
|
-
values for years before current year need to be provided.
|
|
374
|
-
|
|
375
|
-
While this approach has been implemented and tested, the robustness of the {\em big M} approach
|
|
376
|
-
is not guaranteed. Moreover, the introduction of a large number ($5\times N_i\times N_m$,
|
|
377
|
-
where $N_m$ is the number of years eligible for Medicare) of integer variables with
|
|
378
|
-
disjonctive constraints makes the
|
|
379
|
-
convergence to a solution very slow in most situations.
|
|
380
|
-
|
|
381
|
-
A more practical approach is to implement a self-consistent loop that
|
|
382
|
-
optimizes the spending or bequest, and updates the Medicare/IRMAA premiums accordingly.
|
|
383
|
-
Therefore, the value will be computed from the MAGI
|
|
384
|
-
as $\mathcal{M}_n^\ell(G_{n-2} + e_{n-2})$, where the value is at iteration $\ell$.
|
|
385
|
-
After only a few iterations, the solution is converging to within a dollar over the
|
|
386
|
-
sum of all variables in the plan. This approach, however, does not guarantee convergence
|
|
387
|
-
as there can be cases where the premiums affect the solution which can oscillate between
|
|
388
|
-
two solutions, but these cases are detected and a slight change in parameters
|
|
389
|
-
solves this issue. As these premiums are introduced as parameters in the constraints,
|
|
390
|
-
there is no direct optimization being performed on Medicare costs.
|
|
391
349
|
\end{description}
|
|
392
350
|
|
|
393
351
|
\section{Intermediate variables}
|
|
394
352
|
We use intermediate variables for conciseness or clarity,
|
|
395
353
|
but they are ultimately replaced in the final formulation.
|
|
396
|
-
All intermediate variables are in uppercase letters.
|
|
354
|
+
All intermediate variables are in uppercase letters or in double-struck fonts.
|
|
397
355
|
\begin{description}[leftmargin=4em,style=multiline]
|
|
398
|
-
\item [$
|
|
399
|
-
Taxable
|
|
400
|
-
from tax-deferred accounts, including Roth conversions
|
|
401
|
-
(i.e., all gains except those from the $(k=0)$ equities)
|
|
402
|
-
in the ($j=0$) taxable account, including contributions $\kappa$, minus the standard deduction,
|
|
356
|
+
\item [$W_n$]
|
|
357
|
+
Taxable wages and withdrawals in year $n$. Sum of wages, pensions, social security benefits,
|
|
358
|
+
all withdrawals from tax-deferred accounts, including Roth conversions:
|
|
403
359
|
\begin{eqnarray}
|
|
404
|
-
\label{Eq:
|
|
405
|
-
|
|
406
|
-
\sum_{i} [\omega_{in} + .85\bar\zeta_{in} + \pi_{in}]
|
|
407
|
-
- e_n +
|
|
408
|
-
\nonumber \\
|
|
409
|
-
&& \sum_{i} [w_{i1n} + x_{in}] +
|
|
410
|
-
\nonumber \\
|
|
411
|
-
&& \sum_{ik}
|
|
412
|
-
[(1-\delta(k, 0))(b_{i0n} - w_{i0n} + d_{in} + .5\kappa_{i0n})\alpha_{i0kn}\tau_{kn}]
|
|
360
|
+
\label{Eq:Wn}
|
|
361
|
+
W_n &=&
|
|
362
|
+
\sum_{i} [\omega_{in} + .85\bar\zeta_{in} + \pi_{in} + w_{i1n} + x_{in}].
|
|
413
363
|
\end{eqnarray}
|
|
414
364
|
Social security is indexed for inflation and is assumed to be taxed at 85\%.
|
|
415
365
|
Pensions can optionally be indexed for inflation.
|
|
416
|
-
|
|
417
|
-
|
|
366
|
+
All these are taxed as ordinary income.
|
|
367
|
+
|
|
368
|
+
\item [$I_n$]
|
|
369
|
+
Income from interests obtained in year $n$. This only involves gains from securities
|
|
370
|
+
in the taxable account:
|
|
371
|
+
\begin{eqnarray}
|
|
372
|
+
\label{Eq:In}
|
|
373
|
+
I_n &=& \sum_{ik}
|
|
374
|
+
[(1-\delta(k, 0))(b_{i0n} - w_{i0n} + d_{in} + .5\kappa_{i0n})\alpha_{i0kn}\tau_{kn}].
|
|
375
|
+
\end{eqnarray}
|
|
376
|
+
Here, we assumed that
|
|
418
377
|
withdrawals and deposits in the taxable account are taking place at the beginning of the year, while
|
|
419
378
|
contributions, if any, are taking place in mid-year.
|
|
379
|
+
We use a discrete Kronecker $\delta$ function for selecting gains from non-equity assets in
|
|
380
|
+
taxable accounts.
|
|
381
|
+
All these are also taxed as ordinary income.
|
|
382
|
+
|
|
383
|
+
\item [$G_n$]
|
|
384
|
+
Taxable ordinary income in year $n$. Sum of wages, pension, social security benefits,
|
|
385
|
+
all withdrawals from tax-deferred accounts, including Roth conversions and gains from securities,
|
|
386
|
+
minus the standard deduction,
|
|
387
|
+
\begin{eqnarray}
|
|
388
|
+
\label{Eq:Tx2}
|
|
389
|
+
G_n &=& W_n + I_n - e_n.
|
|
390
|
+
\end{eqnarray}
|
|
420
391
|
|
|
421
392
|
\item [$Q_n$]
|
|
422
393
|
Qualified dividends and long-term capital gains obtained in year $n$.
|
|
@@ -444,6 +415,17 @@ All intermediate variables are in uppercase letters.
|
|
|
444
415
|
the taxable savings account is being depleted slowly. An implementation keeping track
|
|
445
416
|
of stock purchases and sales is beyond the goal of providing a guide for retirement decisions.
|
|
446
417
|
|
|
418
|
+
\item [$\mathbb{G}_n$]
|
|
419
|
+
For Owl, we define the Modified Adjusted Gross Income (MAGI) as
|
|
420
|
+
\begin{eqnarray}
|
|
421
|
+
\label{Eq:MAGI}
|
|
422
|
+
\mathbb{G}_n &=& G_n + Q_n + e_n, \nonumber \\
|
|
423
|
+
&=& W_n + I_n + Q_n + e_n.
|
|
424
|
+
\end{eqnarray}
|
|
425
|
+
It includes all wages, social security benefits, pensions,
|
|
426
|
+
withdrawals, Roth conversions, interests, and dividends, plus
|
|
427
|
+
the standard deduction for that year.
|
|
428
|
+
|
|
447
429
|
\item [$P_n$]
|
|
448
430
|
Amount of 10\% early withdrawal penalty in year $n$,
|
|
449
431
|
\begin{equation}
|
|
@@ -493,6 +475,93 @@ All intermediate variables are in uppercase letters.
|
|
|
493
475
|
|
|
494
476
|
\end{description}
|
|
495
477
|
|
|
478
|
+
\section{Derived variables}
|
|
479
|
+
These variables could be additional variables in the original formulation. However, their
|
|
480
|
+
calculations involve the use of binary variables that can considerably impact the solution
|
|
481
|
+
performance. For that reason, these variables are currently computed after the optimization
|
|
482
|
+
step and reintroduced as constraints in the next, self-consistent solution.
|
|
483
|
+
We will use caligraphic letters to represent these variables.
|
|
484
|
+
\begin{description}[leftmargin=4em,style=multiline]
|
|
485
|
+
\item [$\mathcal{M}_n$]
|
|
486
|
+
Costs of Medicare and its Income Related Monthly Adjusted Adjustment (IRMAA).
|
|
487
|
+
As this additional adjustment
|
|
488
|
+
is a step function, it would have to be computed using binary variables and mixed-integer linear
|
|
489
|
+
programming. In the current tax code, this adjustment
|
|
490
|
+
depends on the modified adjusted gross income (MAGI) from 2 years earlier. The
|
|
491
|
+
MAGI $\mathbb{G}_{n-2}$ from 2 years ago as defined below. It ignores the additional IRS
|
|
492
|
+
rules around tax-free interests which are insignificant in most cases. If the plan
|
|
493
|
+
has individuals above 63 years old, values of MAGI for previous years are requested from the user.
|
|
494
|
+
|
|
495
|
+
There are $q=5$ levels
|
|
496
|
+
of step adjustments adjusted for inflation,
|
|
497
|
+
$\bar{L}_{qn} = L_q\gamma_n$ and each of them introduces
|
|
498
|
+
an annual additional Medicare
|
|
499
|
+
cost of $\bar{C}_{qn} = C_q\gamma_n$, also adjusted for inflation.
|
|
500
|
+
One could use binary variables $z_{inq}$ and the following {\em big M} constraint
|
|
501
|
+
\begin{equation}
|
|
502
|
+
e_{n-2} -\bar{L}_{qn} \le z_{inq} M - \mathbb{G}_{n-2}
|
|
503
|
+
\le M - \bar{L}_{qn} + e_{n-2},
|
|
504
|
+
\end{equation}
|
|
505
|
+
so that the IRMAA adjustments can be computed as
|
|
506
|
+
\begin{equation}
|
|
507
|
+
\label{Eq:IRMAA}
|
|
508
|
+
\mathcal{M}_n = \sum_{iq} z_{iqn} \bar{C}_{qn}.
|
|
509
|
+
\end{equation}
|
|
510
|
+
If the plan needs data from 1 or 2 years ago as Medicare has already started or will in the next years,
|
|
511
|
+
values for years before current year need to be provided.
|
|
512
|
+
|
|
513
|
+
While this approach has been implemented and tested, the robustness of the {\em big M} approach
|
|
514
|
+
is not guaranteed. Moreover, the introduction of a large number ($5\times N_i\times N_m$,
|
|
515
|
+
where $N_m$ is the number of years eligible for Medicare) of integer variables with
|
|
516
|
+
disjonctive constraints makes the
|
|
517
|
+
convergence to a solution very slow in most situations.
|
|
518
|
+
|
|
519
|
+
A more practical approach is to implement a self-consistent loop that
|
|
520
|
+
optimizes the spending or bequest, and updates the Medicare/IRMAA premiums accordingly.
|
|
521
|
+
Therefore, the value will be computed from the MAGI
|
|
522
|
+
as $\mathcal{M}_n^\ell(\mathbb{G}_{n-2})$, where the value is at iteration $\ell$.
|
|
523
|
+
After only a few iterations, the solution is converging to within a dollar over the
|
|
524
|
+
sum of all variables in the plan. This approach, however, does not guarantee convergence
|
|
525
|
+
as there can be cases where the premiums affect the solution which can oscillate between
|
|
526
|
+
two solutions, but these cases are detected and a slight change in parameters
|
|
527
|
+
solves this issue. As these premiums are introduced as parameters in the constraints,
|
|
528
|
+
there is no direct optimization being performed on Medicare costs.
|
|
529
|
+
|
|
530
|
+
\item [$\mathcal{J}_n$]
|
|
531
|
+
This variable represents the Net Investment Income Tax (NIIT) that was introduced in 2013.
|
|
532
|
+
This additional tax is meant to finance the Affordable Care Act though a 3.8\% tax on
|
|
533
|
+
income that does not involve direct work.
|
|
534
|
+
These include dividends, interests, rents, and the like.
|
|
535
|
+
This tax is applied on individuals having a MAGI ($\mathbb{G}_n$)
|
|
536
|
+
more than $\mathbb{G}_{\max}$ = \$200k (single)
|
|
537
|
+
or $\mathbb{G}_{\max}$ = \$250k for couples (married filing jointly).
|
|
538
|
+
These threshold values are not adjusted for inflation.
|
|
539
|
+
This additional tax can be implemented using binary variables $z_n$ and
|
|
540
|
+
the big $M$ method through the following constraints:
|
|
541
|
+
\begin{eqnarray}
|
|
542
|
+
\label{Eq:bigMAGI}
|
|
543
|
+
\mathbb{G}_n - \mathbb{G}_{\max} &\leq& M z_n, \nonumber\\
|
|
544
|
+
\mathbb{G}_n - \mathbb{G}_{\max} &>& -M (1 - z_n),
|
|
545
|
+
\end{eqnarray}
|
|
546
|
+
where $M$ is a number larger than any possible MAGI.
|
|
547
|
+
The twist of this rule is that the taxable amount is the smallest between the MAGI excedent and
|
|
548
|
+
the investment income per se. Therefore, another decision needs to be made on the object
|
|
549
|
+
on which the tax should be applied:
|
|
550
|
+
\begin{eqnarray}
|
|
551
|
+
\mathcal{J}_n &=& 0.038 * z_n \min(I_n + Q_n, \mathbb{G}_n - \mathbb{G}_{\max}).
|
|
552
|
+
\end{eqnarray}
|
|
553
|
+
This requires the introduction of another binary variable, and $2N_n$ more constraints as
|
|
554
|
+
in Eq.~\ref{Eq:bigMAGI} to linearize the $\min$ function. Alternatively, $\mathcal{J}^\ell_n$
|
|
555
|
+
can also be computed self-consistently as its (optimization) impact will be small
|
|
556
|
+
in most cases, unless near the MAGI threshold.
|
|
557
|
+
The NIIT amount is relevant for those with large taxable investments
|
|
558
|
+
or rent income, both has little to no room for optimization.
|
|
559
|
+
Current code does not account for rent income, but that could be easily added in the
|
|
560
|
+
future through an additional column in the {\em Wages and Contributions} input file.
|
|
561
|
+
|
|
562
|
+
\end{description}
|
|
563
|
+
|
|
564
|
+
|
|
496
565
|
\chapter{Formulation with imposed asset allocation ratios}
|
|
497
566
|
We first present the case where the sums of assets in each savings accounts $b_{ijn}$ are known
|
|
498
567
|
over which we assume a prescribed asset allocation ratios.
|
|
@@ -709,6 +778,41 @@ add the market returns to the savings balances.
|
|
|
709
778
|
x_{in} \le \min(b_{i1n}, x_{max}).
|
|
710
779
|
\end{equation}
|
|
711
780
|
|
|
781
|
+
Gains on Roth contributions are governed by a 5-year maturation rule for withdrawals.
|
|
782
|
+
Roth conversions are also governed by a 5-year maturation rule for withdrawals covering
|
|
783
|
+
both conversions and gains.
|
|
784
|
+
Some Roth contributions can sometimes be done through a backdoor
|
|
785
|
+
by converting from an IRA, therefore requiring a hold on both the contributions and their gains.
|
|
786
|
+
To stay on the safe side, we impose that
|
|
787
|
+
withdrawals need to be smaller than the balance minus the sum of all contributions
|
|
788
|
+
and conversions that happened over the last 5 years.
|
|
789
|
+
For that purpose, the {\em Wages and Contributions}
|
|
790
|
+
file which stores $\omega_{in}, \kappa_{ijn}, \ldots$, goes back 5 years, and the Roth
|
|
791
|
+
conversions in that year range are interpreted as having actually happened. We use
|
|
792
|
+
the same arrays and store previous conversions and contributions at the end of the array so that
|
|
793
|
+
they can be retrieved with negative indices in Python. Mathematically, we want that
|
|
794
|
+
\begin{equation}
|
|
795
|
+
w_{i2n} \le b_{i2n} -
|
|
796
|
+
\sum_{n'=n-5}^{n-1} [ \kappa_{i2n'} + x_{in'}] \prod_{n''=n'}^{n-1}\mathcal{T}^1_{in''}
|
|
797
|
+
\end{equation}
|
|
798
|
+
where the compounded gain is computed from
|
|
799
|
+
\begin{equation}
|
|
800
|
+
\mathcal{T}^1_{in} = 1 + \sum_k \alpha_{i2kn}\tau_{kn}.
|
|
801
|
+
\end{equation}
|
|
802
|
+
However, conversions are sometimes a decision variable $x_{in}$
|
|
803
|
+
and sometimes a parameter $X_{in}$, depending on the sign of $n$.
|
|
804
|
+
This leads to
|
|
805
|
+
\begin{eqnarray}
|
|
806
|
+
b_{i2n} - w_{i2n} -
|
|
807
|
+
\sum_{n'=\max(n-5, 0)}^{n-1} x_{in'}
|
|
808
|
+
\prod_{n''=n'}^{n-1}\mathcal{T}^1_{in''}
|
|
809
|
+
&\ge&
|
|
810
|
+
\sum_{n'=n-5}^{n-1} \kappa_{i2n'}
|
|
811
|
+
\prod_{n''=n'}^{n-1} \mathcal{T}^1_{in''} \nonumber \\
|
|
812
|
+
&& + \sum_{n'=n-5}^{\min(-1, n-1)} X_{in'}
|
|
813
|
+
\prod_{n''=n'}^{\min(-1, n-1)}\mathcal{T}^1_{in''}.
|
|
814
|
+
\end{eqnarray}
|
|
815
|
+
|
|
712
816
|
\paragraph*{Net spending}
|
|
713
817
|
For calculating the net spending $g_n$, we consider the cash flow of all withdrawals,
|
|
714
818
|
wages, social security and pension benefits, and big-ticket items.
|
|
@@ -716,7 +820,7 @@ add the market returns to the savings balances.
|
|
|
716
820
|
\begin{eqnarray}
|
|
717
821
|
g_n = \sum_i [\omega_{in} + \bar{\zeta}_{in} + \pi_{in} ]
|
|
718
822
|
+ \sum_{ij} w_{ijn} + \sum_i \Lambda^\pm_{in} - s_{n}
|
|
719
|
-
- P_n - T_n - U_n - \mathcal{M}^\ell_n.
|
|
823
|
+
- P_n - T_n - U_n - \mathcal{M}^\ell_n - \mathcal{J}^\ell_n.
|
|
720
824
|
\end{eqnarray}
|
|
721
825
|
When both spouses are alive, surplus $s_n$ gets deposited in the taxable accounts
|
|
722
826
|
according to variable $\eta$ as described in Eq.~(\ref{Eq:eta}),
|
|
@@ -736,13 +840,13 @@ add the market returns to the savings balances.
|
|
|
736
840
|
+ w_{i0n}\max(0, \tau_{0n-1})\right]
|
|
737
841
|
&=& \sum_i [\omega_{in} + \bar{\zeta}_{in} + \pi_{in} ] \nonumber\\
|
|
738
842
|
&& + \sum_i [\Lambda^\pm_{in} - .5\psi\alpha_{i00n}\mu\kappa_{i0n}] \nonumber\\
|
|
739
|
-
&& - \mathcal{M}_n^\ell.
|
|
843
|
+
&& - \mathcal{M}_n^\ell - \mathcal{J}^\ell_n.
|
|
740
844
|
\end{eqnarray}
|
|
741
845
|
Notice that we do not consider market losses as we use $\max(0, \tau)$, and that
|
|
742
846
|
rates from only the previous year are used. Tax-loss
|
|
743
847
|
harvesting is beyond the scope of this model, as is the tracking of stocks
|
|
744
848
|
purchased over the years.
|
|
745
|
-
For clarity, we did not express $\mathcal{M}_n^\ell(G_n+e_n)$ in terms of the modified
|
|
849
|
+
For clarity, we did not express $\mathcal{M}_n^\ell(G_n+Q_n+e_n)$ in terms of the modified
|
|
746
850
|
adjusted gross income (MAGI), but this term is there to indicate that there is a self-consistent
|
|
747
851
|
loop solving for it and that we are at iteration $\ell$.
|
|
748
852
|
|
|
@@ -1050,7 +1154,7 @@ we add $N_n$ more rows to $A_ey = v$ as
|
|
|
1050
1154
|
where $v$ is
|
|
1051
1155
|
\begin{equation}
|
|
1052
1156
|
v[J_2(n)] = \sum_i [\omega_{in} + \bar\zeta_{in} + \pi_{in}
|
|
1053
|
-
+ \Lambda^\pm_{in} - .5\psi\mu\alpha_{i00n}\kappa_{i0n}] - \mathcal{M}_n^\ell.
|
|
1157
|
+
+ \Lambda^\pm_{in} - .5\psi\mu\alpha_{i00n}\kappa_{i0n}] - \mathcal{M}_n^\ell - \mathcal{J}^\ell_n.
|
|
1054
1158
|
\end{equation}
|
|
1055
1159
|
|
|
1056
1160
|
The condition of having a predictable net spending expressed as an
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"Plan Name" = "drawdowncalc-comparison-1"
|
|
2
|
+
Description = "This is a case involving a single individual. Case is used for comparing with @hugcity's DrawdownCalc. For max bequest, it should yield $90,792, while an $80k net spending should leave $673,156 as a bequest."
|
|
3
|
+
|
|
4
|
+
["Basic Info"]
|
|
5
|
+
Status = "single"
|
|
6
|
+
Names = [ "Charles",]
|
|
7
|
+
"Birth year" = [ 1966,]
|
|
8
|
+
"Life expectancy" = [ 89,]
|
|
9
|
+
"Start date" = "2025-01-01"
|
|
10
|
+
|
|
11
|
+
[Assets]
|
|
12
|
+
"taxable savings balances" = [ 250.0,]
|
|
13
|
+
"tax-deferred savings balances" = [ 600.0,]
|
|
14
|
+
"tax-free savings balances" = [ 600.0,]
|
|
15
|
+
|
|
16
|
+
["Wages and Contributions"]
|
|
17
|
+
"Contributions file name" = "edited values"
|
|
18
|
+
|
|
19
|
+
["Fixed Income"]
|
|
20
|
+
"Pension amounts" = [ 0.0,]
|
|
21
|
+
"Pension ages" = [ 65,]
|
|
22
|
+
"Pension indexed" = [ true,]
|
|
23
|
+
"Social security amounts" = [ 36.0,]
|
|
24
|
+
"Social security ages" = [ 70,]
|
|
25
|
+
|
|
26
|
+
["Rates Selection"]
|
|
27
|
+
"Heirs rate on tax-deferred estate" = 0.0
|
|
28
|
+
"Dividend rate" = 0.0
|
|
29
|
+
"TCJA expiration year" = 2099
|
|
30
|
+
Method = "user"
|
|
31
|
+
Values = [ 6.5, 0.0, 0.0, 2.8,]
|
|
32
|
+
From = 1928
|
|
33
|
+
To = 2024
|
|
34
|
+
|
|
35
|
+
["Asset Allocation"]
|
|
36
|
+
"Interpolation method" = "s-curve"
|
|
37
|
+
"Interpolation center" = 15.0
|
|
38
|
+
"Interpolation width" = 5.0
|
|
39
|
+
Type = "individual"
|
|
40
|
+
generic = [ [ [ 100, 0, 0, 0,], [ 100, 0, 0, 0,],],]
|
|
41
|
+
|
|
42
|
+
["Optimization Parameters"]
|
|
43
|
+
"Spending profile" = "flat"
|
|
44
|
+
"Surviving spouse spending percent" = 60
|
|
45
|
+
Objective = "maxBequest"
|
|
46
|
+
|
|
47
|
+
["Solver Options"]
|
|
48
|
+
netSpending = 80.0
|
|
49
|
+
maxRothConversion = 50
|
|
50
|
+
startRothConversions = 2025
|
|
51
|
+
withMedicare = false
|
|
52
|
+
solver = "HiGHS"
|
|
53
|
+
spendingSlack = 0
|
|
54
|
+
|
|
55
|
+
[Results]
|
|
56
|
+
"Default plots" = "today"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"Plan Name" = "jack+jill"
|
|
2
|
+
Description = "This example aims to demonstrate some of Owl's capabilities. Jack and Jill are a married couple a few years from retirement. A wages and contributions file called 'jack+jill.xlsx' is associated with this case. This case uses the historical rate sequence of 1969 as a test case for guiding spending amounts from a near worst-case historical scenario. This case also demonstrates that the optimal strategy for Roth conversions does not necessarily involve surfing a tax bracket. \nA good exercise for learning Owl's capabilities is to duplicate this case and compare two scenarios: one with optimized Roth conversions and one without. Another possible exercise could involve comparing a historical retirement in 1969 vs. one taken in 1966. Or anything else you can think of..."
|
|
3
|
+
|
|
4
|
+
["Basic Info"]
|
|
5
|
+
Status = "married"
|
|
6
|
+
Names = [ "Jack", "Jill",]
|
|
7
|
+
"Birth year" = [ 1962, 1965,]
|
|
8
|
+
"Life expectancy" = [ 89, 92,]
|
|
9
|
+
"Start date" = "01-01"
|
|
10
|
+
|
|
11
|
+
[Assets]
|
|
12
|
+
"taxable savings balances" = [ 120.5, 60.2,]
|
|
13
|
+
"tax-deferred savings balances" = [ 600.2, 150.0,]
|
|
14
|
+
"tax-free savings balances" = [ 280.6, 260.8,]
|
|
15
|
+
"Beneficiary fractions" = [ 1, 1, 1,]
|
|
16
|
+
"Spousal surplus deposit fraction" = 0.0
|
|
17
|
+
|
|
18
|
+
["Wages and Contributions"]
|
|
19
|
+
"Contributions file name" = "jack+jill.xlsx"
|
|
20
|
+
|
|
21
|
+
["Fixed Income"]
|
|
22
|
+
"Pension amounts" = [ 0.0, 10.5,]
|
|
23
|
+
"Pension ages" = [ 65, 65,]
|
|
24
|
+
"Pension indexed" = [ false, false,]
|
|
25
|
+
"Social security amounts" = [ 28.4, 19.7,]
|
|
26
|
+
"Social security ages" = [ 70, 62,]
|
|
27
|
+
|
|
28
|
+
["Rates Selection"]
|
|
29
|
+
"Heirs rate on tax-deferred estate" = 30.0
|
|
30
|
+
"Dividend rate" = 1.8
|
|
31
|
+
"TCJA expiration year" = 2026
|
|
32
|
+
Method = "historical"
|
|
33
|
+
From = 1969
|
|
34
|
+
To = 2002
|
|
35
|
+
|
|
36
|
+
["Asset Allocation"]
|
|
37
|
+
"Interpolation method" = "s-curve"
|
|
38
|
+
"Interpolation center" = 15
|
|
39
|
+
"Interpolation width" = 5
|
|
40
|
+
Type = "individual"
|
|
41
|
+
generic = [ [ [ 60, 40, 0, 0,], [ 70, 30, 0, 0,],], [ [ 60, 40, 0, 0,], [ 80, 0, 10, 10,],],]
|
|
42
|
+
|
|
43
|
+
["Optimization Parameters"]
|
|
44
|
+
"Spending profile" = "smile"
|
|
45
|
+
"Smile dip" = 15
|
|
46
|
+
"Smile increase" = 12
|
|
47
|
+
"Smile delay" = 0
|
|
48
|
+
"Surviving spouse spending percent" = 60
|
|
49
|
+
Objective = "maxSpending"
|
|
50
|
+
|
|
51
|
+
["Solver Options"]
|
|
52
|
+
maxRothConversion = 100
|
|
53
|
+
bequest = 500
|
|
54
|
+
noRothConversions = "Jill"
|
|
55
|
+
|
|
56
|
+
[Results]
|
|
57
|
+
"Default plots" = "today"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"Plan Name" = "joe"
|
|
2
|
+
Description = "This is an example of a case involving a single individual. Joe is single and will retire in a few years. His wages and contributions are contained in the 'joe.xlsx' spreadsheet."
|
|
3
|
+
|
|
4
|
+
["Basic Info"]
|
|
5
|
+
Status = "single"
|
|
6
|
+
Names = [ "Joe",]
|
|
7
|
+
"Birth year" = [ 1966,]
|
|
8
|
+
"Life expectancy" = [ 89,]
|
|
9
|
+
"Start date" = "01-01"
|
|
10
|
+
|
|
11
|
+
[Assets]
|
|
12
|
+
"taxable savings balances" = [ 338.5,]
|
|
13
|
+
"tax-deferred savings balances" = [ 650.2,]
|
|
14
|
+
"tax-free savings balances" = [ 60.6,]
|
|
15
|
+
|
|
16
|
+
["Wages and Contributions"]
|
|
17
|
+
"Contributions file name" = "joe.xlsx"
|
|
18
|
+
|
|
19
|
+
["Fixed Income"]
|
|
20
|
+
"Pension amounts" = [ 18.0,]
|
|
21
|
+
"Pension ages" = [ 65,]
|
|
22
|
+
"Pension indexed" = [ true,]
|
|
23
|
+
"Social security amounts" = [ 28.4,]
|
|
24
|
+
"Social security ages" = [ 67,]
|
|
25
|
+
|
|
26
|
+
["Rates Selection"]
|
|
27
|
+
"Heirs rate on tax-deferred estate" = 30.0
|
|
28
|
+
"Dividend rate" = 1.8
|
|
29
|
+
"TCJA expiration year" = 2026
|
|
30
|
+
Method = "historical average"
|
|
31
|
+
From = 1969
|
|
32
|
+
To = 2002
|
|
33
|
+
|
|
34
|
+
["Asset Allocation"]
|
|
35
|
+
"Interpolation method" = "s-curve"
|
|
36
|
+
"Interpolation center" = 15
|
|
37
|
+
"Interpolation width" = 5
|
|
38
|
+
Type = "individual"
|
|
39
|
+
generic = [ [ [ 60, 40, 0, 0,], [ 70, 30, 0, 0,],],]
|
|
40
|
+
|
|
41
|
+
["Optimization Parameters"]
|
|
42
|
+
"Spending profile" = "smile"
|
|
43
|
+
"Smile dip" = 15
|
|
44
|
+
"Smile increase" = 12
|
|
45
|
+
"Smile delay" = 0
|
|
46
|
+
"Surviving spouse spending percent" = 60
|
|
47
|
+
Objective = "maxSpending"
|
|
48
|
+
|
|
49
|
+
["Solver Options"]
|
|
50
|
+
maxRothConversion = 50
|
|
51
|
+
bequest = 300
|
|
52
|
+
|
|
53
|
+
[Results]
|
|
54
|
+
"Default plots" = "nominal"
|