owlplanner 2025.3.14__tar.gz → 2025.3.16__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.3.14 → owlplanner-2025.3.16}/PKG-INFO +1 -1
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/owl.pdf +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/owl.tex +53 -39
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/pyproject.toml +1 -1
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/plan.py +9 -13
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/rates.py +3 -0
- owlplanner-2025.3.16/src/owlplanner/version.py +1 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/requirements.txt +1 -1
- owlplanner-2025.3.14/src/owlplanner/version.py +0 -1
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.devcontainer/devcontainer.json +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.flake8 +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.gitattributes +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.github/workflows/github-actions-runtests.yml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.gitignore +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/INSTALL.md +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/LICENSE +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/FE00006821-Class-VI-Injection-Permit--Salient-Features-and-Regulatory-Challenges_Final.pdf +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/Kou-OptionPricingDouble-2004.pdf +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/Multi-Period Mean Expected-Shortfall Strategies Cut Your Losses and Ride Your Gains .pdf +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/Optimal Asset Allocation for Retirement Saving Deterministic Vs. Time Consistent Adaptive Strategies.pdf +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/Rule-based_strategies_for_dynamic_life_cycle_inves.pdf +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/s10436-006-0062-y.pdf +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/README.md +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/USER_GUIDE.md +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/Dockerfile +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/README.md +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/docker-compose.yml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/fastentrypoint.sh +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/AD-taxDef.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/AD-taxFree.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/AD-taxable.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/Hist_Bequest.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/Hist_Spending.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/MC-tutorial2a.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/MC-tutorial2b.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/OwlUI.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/allocations.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/owl.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/profile.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/ratesCorrelations.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/ratesPlot.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/savingsPlot.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/sourcesPlot.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/spendingPlot.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/taxIncomePlot.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/taxesPlot.png +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_jack+jill.toml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_joe.toml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_john+sally.toml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_jon+jane.toml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_kim+sam-bequest.toml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_kim+sam-spending.toml +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/jack+jill.xlsx +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/joe.xlsx +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/john+sally.xlsx +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/jon+jane.xlsx +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/template.xlsx +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/john+sally.ipynb +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/kim+sam.ipynb +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/template.ipynb +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/tutorial_1.ipynb +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/tutorial_2.ipynb +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/tutorial_3.ipynb +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/owlplanner.cmd +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/owlplanner.sh +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/requirements.txt +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/__init__.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/abcapi.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/config.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/data/__init__.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/data/rates.csv +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/logging.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/progress.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/tax2025.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/timelists.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/utils.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_logger.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_regressions.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_repro.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_toml_cases.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_units.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ttt.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/About_Owl.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Asset_Allocation.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Create_Case.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Current_Assets.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Documentation.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Fixed_Income.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Graphs.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Historical_Range.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Logs.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Monte_Carlo.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Optimization_Parameters.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Output_Files.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Quick_Start.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/README.md +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Rates_Selection.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Settings.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Wages_And_Contributions.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Worksheets.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/main+fonts.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/main.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/owlbridge.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/plots.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/progress.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/sskeys.py +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/style.css +0 -0
- {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/tomlexamples.py +0 -0
|
Binary file
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
\begin{document}
|
|
33
33
|
\title{Formulation of the optimization model in Owl}
|
|
34
34
|
\author{Martin-D. Lacasse}
|
|
35
|
+
\date{March 14, 2025}
|
|
35
36
|
\maketitle
|
|
36
37
|
\thispagestyle{fancy}
|
|
37
38
|
\fancyfoot[R]{\copyright\ 2024 - Martin-D. Lacasse}
|
|
@@ -87,7 +88,7 @@ index name as a subscript, e.g., $N_i$ for index $i$.
|
|
|
87
88
|
More asset classes could be considered at the cost of increasing
|
|
88
89
|
the complexity of the problem while not generating much more insights.
|
|
89
90
|
\item [$n$]
|
|
90
|
-
|
|
91
|
+
Index of year being modeled. Period being modeled runs from the beginning of year 0 to
|
|
91
92
|
the end of year $N_n-1$, and therefore $N_n + 1$ years are considered.
|
|
92
93
|
Year $N_n$ is the first year following the passing of all
|
|
93
94
|
individuals in the plan. The time period for all decision variables is annual.
|
|
@@ -112,8 +113,8 @@ to take only non-negative values ($\ge 0$ inequality).
|
|
|
112
113
|
\item [$e_{n}$]
|
|
113
114
|
Standard exemption for year $n$. This is a variable as the taxable income can
|
|
114
115
|
sometimes be less that the standard exemption $\bar{\sigma}_n$, leading to a
|
|
115
|
-
negative taxable income if the inflation
|
|
116
|
-
from gross taxable income $G_n$.
|
|
116
|
+
negative taxable income if the inflation-adjusted standard exemption is simply subtracted
|
|
117
|
+
from the gross taxable income $G_n$.
|
|
117
118
|
\item [$f_{t n}$]
|
|
118
119
|
Fraction of tax bracket $t$ filled, so that taxable ordinary income $G_n$ can be expressed as
|
|
119
120
|
\begin{eqnarray}
|
|
@@ -141,19 +142,13 @@ For more easily distinguishing parameters from variables, all parameters will be
|
|
|
141
142
|
or using caligraphic fonts.
|
|
142
143
|
Parameter values are either set by the user, historical data, or by the tax code.
|
|
143
144
|
\begin{description}[leftmargin=4em,style=multiline]
|
|
144
|
-
\item [$\
|
|
145
|
+
\item [$\beta_{ij}$]
|
|
145
146
|
Initial balances in savings accounts. These amounts are used to initialize $b_{ij0}$.
|
|
146
147
|
\item [$\tau_{kn}$]
|
|
147
148
|
Annual rate of return for asset class $k$ in year $n$.
|
|
148
149
|
A time series of annual return rates for each class of asset.
|
|
149
150
|
Here, inflation and the rate of return of $(k=3)$ cash are assumed to be the same.
|
|
150
|
-
In other words, investing in cash yields constant dollars (just inflation).
|
|
151
|
-
\item[$\mathcal{T}_{ijn}$]
|
|
152
|
-
When the allocation ratios $\alpha_{ijkn}$ are prescribed,
|
|
153
|
-
it is more convenient to express the return rates as
|
|
154
|
-
\begin{equation}
|
|
155
|
-
\mathcal{T}_{ijn} = \sum_k \alpha_{ijkn} \tau_{kn}.
|
|
156
|
-
\end{equation}
|
|
151
|
+
In other words, investing in cash yields constant dollars (return just matches inflation).
|
|
157
152
|
\item [$\gamma_n$]
|
|
158
153
|
Cumulative inflation at the beginning of year $n$ computed as the product
|
|
159
154
|
\begin{equation}
|
|
@@ -172,12 +167,12 @@ Parameter values are either set by the user, historical data, or by the tax code
|
|
|
172
167
|
and can be modified for additional exemptions after 65 of age, for example.
|
|
173
168
|
It is a simple time series
|
|
174
169
|
which can include any foreseeable changes in the tax code, or change in filing status due to the
|
|
175
|
-
passing of one spouse for $n\ge n_d$. The value of $\bar{\sigma}_n$ is an upper bound for $e_n$.
|
|
170
|
+
passing of one spouse for $n\ge n_d$. The value of $\bar{\sigma}_n$ is an upper bound for variable $e_n$.
|
|
176
171
|
\item [$\xi_{n}$]
|
|
177
|
-
Spending profile. This is a time series that multiplies the desired net spending amount.
|
|
172
|
+
Spending profile. This is a time series that multiplies a basis for the desired net spending amount.
|
|
178
173
|
It is $\xi_n =1$ for
|
|
179
174
|
a flat profile, or can be a {\em smile} profile allowing for more money at the start
|
|
180
|
-
of retirement. Parameter
|
|
175
|
+
of retirement and modulating it over retirement. Parameter
|
|
181
176
|
$\xi_n$ can also contain spending adjustments typically made at the passing of one spouse.
|
|
182
177
|
The {\em smile} can be implemented using a cosine superimposed over a gentle linear increase
|
|
183
178
|
such as in
|
|
@@ -186,14 +181,14 @@ Parameter values are either set by the user, historical data, or by the tax code
|
|
|
186
181
|
\end{equation}
|
|
187
182
|
and then normalized by factor $N_n/(\sum_n \xi_n )$ to be sum-neutral with respect to a flat profile.
|
|
188
183
|
Values of $a_1 = 15\%$ and $a_2=12\%$ provide curves that are similar to realistic
|
|
189
|
-
|
|
184
|
+
spending profiles reported in the literature. See Fig.~\ref{Fig:profile} for an example.
|
|
190
185
|
At the passing of one spouse, both profiles are reduced by a factor $\chi$ for $n \ge n_d$,
|
|
191
186
|
and the normalizing factor needs to be adjusted accordingly.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
187
|
+
\begin{figure}[t]
|
|
188
|
+
\includegraphics{profile.png}
|
|
189
|
+
\caption{\small Example of a spending profile with 15\% cosine factor and a 12\% linear
|
|
190
|
+
profile. \label{Fig:profile}}
|
|
191
|
+
\end{figure}
|
|
197
192
|
\item [$\chi$]
|
|
198
193
|
Factor to reduce spending profile after the passing of one spouse. It is typically
|
|
199
194
|
assumed to be 0.6.
|
|
@@ -230,7 +225,8 @@ Parameter values are either set by the user, historical data, or by the tax code
|
|
|
230
225
|
individuals and accounts as $\alpha_{kn}$, for example.
|
|
231
226
|
When specified by the user, allocation ratios typically involve two values, one at the
|
|
232
227
|
beginning of the plan $\alpha_{ijk0}$ and the other at the end
|
|
233
|
-
$\alpha_{ijkN_{n-1}}
|
|
228
|
+
$\alpha_{ijkN_{n-1}}$, or $\alpha_{ijkn_d}$ for a spouse passing before the other.
|
|
229
|
+
Then, intermediate values are interpolated either using
|
|
234
230
|
a linear relation,
|
|
235
231
|
\begin{equation}
|
|
236
232
|
\alpha_{ijkn} = a + \frac{n}{N_n - 1} (b - a),
|
|
@@ -280,6 +276,13 @@ or an s-curve as in
|
|
|
280
276
|
\end{eqnarray}
|
|
281
277
|
depending on the scheme selected.
|
|
282
278
|
|
|
279
|
+
\item[$\mathcal{T}_{ijn}$]
|
|
280
|
+
When the allocation ratios $\alpha_{ijkn}$ are prescribed,
|
|
281
|
+
it is more convenient to express the return rates as
|
|
282
|
+
\begin{equation}
|
|
283
|
+
\mathcal{T}_{ijn} = \sum_k \alpha_{ijkn} \tau_{kn}.
|
|
284
|
+
\end{equation}
|
|
285
|
+
|
|
283
286
|
\item [$\Lambda^\pm_{in}$]
|
|
284
287
|
Big-ticket item requested by individual $i$ in year $n$.
|
|
285
288
|
These are large expenses or influx of money
|
|
@@ -287,8 +290,8 @@ or an s-curve as in
|
|
|
287
290
|
(e.g., sell a house, inheritance) or negative (e.g., buy a house, large gifts).
|
|
288
291
|
\item [$\pi_{in}$]
|
|
289
292
|
Sum of pension benefits for individual $i$ in year $n$. These amounts are typically
|
|
290
|
-
specified along with the ages at which these benefits begin.
|
|
291
|
-
can optionally be indexed for inflation.
|
|
293
|
+
specified along with the ages at which these benefits begin.
|
|
294
|
+
Pensions can optionally be indexed for inflation.
|
|
292
295
|
\item [$\zeta_{in}$]
|
|
293
296
|
Social security benefits for individual $i$ in year $n$. Starting age and the passing
|
|
294
297
|
of one individual for spouses will determine the time series. $\bar{\zeta}_{in}$ is
|
|
@@ -344,7 +347,8 @@ or an s-curve as in
|
|
|
344
347
|
depends on the modified adjusted gross income (MAGI) from 2 years earlier. For the
|
|
345
348
|
MAGI, we simply use $G_{n-2} + e_{n-2}$ (i.e., gross taxable income
|
|
346
349
|
plus standard deduction (exemption) from 2 years ago) and ignore the additional IRS
|
|
347
|
-
rules around tax-free interests which are insignificant in most cases.
|
|
350
|
+
rules around tax-free interests which are insignificant in most cases. If the plan
|
|
351
|
+
has individuals above 63 years old, values of MAGI for previous years are requested from the user.
|
|
348
352
|
|
|
349
353
|
There are $q=5$ levels
|
|
350
354
|
of step adjustments adjusted for inflation,
|
|
@@ -404,6 +408,7 @@ All intermediate variables are in uppercase letters.
|
|
|
404
408
|
[(1-\delta(k, 0))(b_{i0n} - w_{i0n} + d_{in} + .5\kappa_{i0n})\alpha_{i0kn}\tau_{kn}]
|
|
405
409
|
\end{eqnarray}
|
|
406
410
|
Social security is indexed for inflation and is assumed to be taxed at 85\%.
|
|
411
|
+
Pensions can optionally be indexed for inflation.
|
|
407
412
|
We use a discrete Kronecker $\delta$ function for selecting gains from non-equity assets in
|
|
408
413
|
taxable accounts. These gains are all taxed as ordinary income. Here, we assumed that
|
|
409
414
|
withdrawals and deposits in the taxable account are taking place at the beginning of the year, while
|
|
@@ -435,24 +440,32 @@ All intermediate variables are in uppercase letters.
|
|
|
435
440
|
the taxable savings account is being depleted slowly. An implementation keeping track
|
|
436
441
|
of stock purchases and sales is beyond the goal of providing a guide for retirement decisions.
|
|
437
442
|
|
|
443
|
+
\item [$P_n$]
|
|
444
|
+
Amount of 10\% early withdrawal penalty in year $n$,
|
|
445
|
+
\begin{equation}
|
|
446
|
+
\label{Eq:PenTax0}
|
|
447
|
+
P_n = 0.10 \sum_{i, j\neq0} (1 - \mathcal{H}(n - n_{i,59})) w_{ijn}.
|
|
448
|
+
\end{equation}
|
|
449
|
+
Here, $H(n - n_{i, 59})$ is a Heavyside step function which is 0 or 1, depending on the sign of
|
|
450
|
+
its argument:
|
|
451
|
+
\begin{equation}
|
|
452
|
+
\mathcal{H}(x) :=
|
|
453
|
+
\begin{cases}
|
|
454
|
+
0 & x < 0 \\
|
|
455
|
+
1 & x \geq 0.
|
|
456
|
+
\end{cases}
|
|
457
|
+
\end{equation}
|
|
458
|
+
The variable $n_{i, 59}$ is the year index when individual $i$ turns 59,
|
|
459
|
+
or 0 if already 59 years old or older.
|
|
460
|
+
|
|
438
461
|
\item [$T_n$]
|
|
439
462
|
Amount of income tax paid on taxable ordinary income $G_n$ in year $n$.
|
|
440
463
|
This is the taxes paid on ordinary income expressed as the sum of the amounts
|
|
441
464
|
paid in each tax bracket as
|
|
442
465
|
\begin{equation}
|
|
443
466
|
\label{Eq:IncTax0}
|
|
444
|
-
T_n = \sum_t f_{tn}\bar{\Delta}_{tn}\theta_{tn}
|
|
467
|
+
T_n = \sum_t f_{tn}\bar{\Delta}_{tn}\theta_{tn}.
|
|
445
468
|
\end{equation}
|
|
446
|
-
where $H(n - n_{i, 60})$ is a Heavyside step function which is 0 or 1, depending on the sign of
|
|
447
|
-
its argument:
|
|
448
|
-
\[
|
|
449
|
-
\mathcal{H}(x) \def
|
|
450
|
-
\begin{cases}
|
|
451
|
-
0 & x < 0 \\
|
|
452
|
-
1 & x \geq 0. \\
|
|
453
|
-
\end{cases}
|
|
454
|
-
\]
|
|
455
|
-
Here, $n_{i, 60}$ is the year when individual $i$ will turn 60.
|
|
456
469
|
Notice that $G_n$ is also defined by Eq.~(\ref{Eq:Tx1}), and that optimal
|
|
457
470
|
values of $f_{tn}$ have to
|
|
458
471
|
minimize $T_n$ when either the bequest or the desired net spending are maximized.
|
|
@@ -463,8 +476,9 @@ All intermediate variables are in uppercase letters.
|
|
|
463
476
|
filling in the lower brackets first when optimizing. In that case
|
|
464
477
|
\begin{equation}
|
|
465
478
|
\label{Eq:IncTax1}
|
|
466
|
-
T_n = \sum_t \bar{F}_{tn} \theta_{tn}
|
|
479
|
+
T_n = \sum_t \bar{F}_{tn} \theta_{tn}
|
|
467
480
|
\end{equation}
|
|
481
|
+
|
|
468
482
|
\item [$U_n$]
|
|
469
483
|
Amount of income tax paid on long-term capital gains and qualified dividends in year $n$,
|
|
470
484
|
\begin{equation}
|
|
@@ -698,7 +712,7 @@ add the market returns to the savings balances.
|
|
|
698
712
|
\begin{eqnarray}
|
|
699
713
|
g_n = \sum_i [\omega_{in} + \bar{\zeta}_{in} + \pi_{in} ]
|
|
700
714
|
+ \sum_{ij} w_{ijn} + \sum_i \Lambda^\pm_{in} - s_{n}
|
|
701
|
-
- T_n - U_n - \mathcal{M}^\ell_n.
|
|
715
|
+
- P_n - T_n - U_n - \mathcal{M}^\ell_n.
|
|
702
716
|
\end{eqnarray}
|
|
703
717
|
When both spouses are alive, surplus $s_n$ gets deposited in the taxable accounts
|
|
704
718
|
according to variable $\eta$ as described in Eq.~(\ref{Eq:eta}),
|
|
@@ -712,7 +726,7 @@ add the market returns to the savings balances.
|
|
|
712
726
|
Replacing intermediate variables and bringing all variables to the left-hand side, we get
|
|
713
727
|
\begin{eqnarray}
|
|
714
728
|
\label{Eq:C4}
|
|
715
|
-
g_n - \sum_{ij} w_{ijn} +
|
|
729
|
+
g_n - \sum_{ij} w_{ijn} + 0.1 \sum_{i,j\neq0} (1-\mathcal{H}(n - n_{i, 59})) w_{ijn} + s_n
|
|
716
730
|
+ \sum_t \bar{F}_{tn} \theta_{t n} &&\nonumber \\
|
|
717
731
|
+ \psi\alpha_{i00n} \sum_{i} \left[\mu(b_{i0n} - w_{i0n} + d_{in})
|
|
718
732
|
+ w_{i0n}\max(0, \tau_{0n-1})\right]
|
|
@@ -1020,7 +1034,7 @@ For the equality constraint on net spending expressed in Eq.~(\ref{Eq:C4}),
|
|
|
1020
1034
|
we add $N_n$ more rows to $A_ey = v$ as
|
|
1021
1035
|
\begin{eqnarray}
|
|
1022
1036
|
A_e[J_2(n), q_g(n)] &=& 1, \nonumber \\
|
|
1023
|
-
A_e[J_2(n), q_w(i, j ,n)] &=& -1 + \delta(j, 0)\psi\alpha_{i00n}(\max(0, \tau_{0n-1}) - \mu), \nonumber \\
|
|
1037
|
+
A_e[J_2(n), q_w(i, j ,n)] &=& -1 + .1(1-\delta(j, 0))(1-\mathcal{H}(n-n_{i, 59})) + \delta(j, 0)\psi\alpha_{i00n}(\max(0, \tau_{0n-1}) - \mu), \nonumber \\
|
|
1024
1038
|
A_e[J_2(n), q_d(i, n)] &=& 1 + \psi\mu\alpha_{i00n}, \nonumber \\
|
|
1025
1039
|
A_e[J_2(n), q_F(t, n)] &=& \theta_{t n}, \nonumber \\
|
|
1026
1040
|
A_e[J_2(n), q_b(i, 0, n)] &=& \psi\mu\alpha_{i00n}, \nonumber \\
|
|
@@ -1284,19 +1284,15 @@ class Plan(object):
|
|
|
1284
1284
|
# Minus capital gains on taxable withdrawals using last year's rate if >=0.
|
|
1285
1285
|
# Plus taxable account withdrawals, and all other withdrawals.
|
|
1286
1286
|
row.addElem(_q3(Cw, i, 0, n, Ni, Nj, Nn), fac * (tau_0prev[n] - self.mu) - 1)
|
|
1287
|
-
|
|
1288
|
-
row.addElem(_q3(Cw, i,
|
|
1287
|
+
penalty = 0.1 if n < self.n59[i] else 0
|
|
1288
|
+
row.addElem(_q3(Cw, i, 1, n, Ni, Nj, Nn), -1 + penalty)
|
|
1289
|
+
row.addElem(_q3(Cw, i, 2, n, Ni, Nj, Nn), -1 + penalty)
|
|
1289
1290
|
row.addElem(_q2(Cd, i, n, Ni, Nn), fac * self.mu)
|
|
1290
1291
|
|
|
1291
1292
|
# Minus tax on ordinary income, T_n.
|
|
1292
1293
|
for t in range(Nt):
|
|
1293
1294
|
row.addElem(_q2(CF, t, n, Nt, Nn), self.theta_tn[t, n])
|
|
1294
1295
|
|
|
1295
|
-
# Minus 10% penalty on early withdrawals.
|
|
1296
|
-
if n < self.n59[i]:
|
|
1297
|
-
row.addElem(_q3(Cw, i, 1, n, Ni, Nj, Nn), 0.1)
|
|
1298
|
-
row.addElem(_q3(Cw, i, 2, n, Ni, Nj, Nn), 0.1)
|
|
1299
|
-
|
|
1300
1296
|
A.addRow(row, rhs, rhs)
|
|
1301
1297
|
|
|
1302
1298
|
# Impose income profile.
|
|
@@ -1978,12 +1974,12 @@ class Plan(object):
|
|
|
1978
1974
|
self.G_n = np.sum(self.F_tn, axis=0)
|
|
1979
1975
|
self.T_tn = self.F_tn * self.theta_tn
|
|
1980
1976
|
self.T_n = np.sum(self.T_tn, axis=0)
|
|
1981
|
-
self.
|
|
1982
|
-
# Add early withdrawal
|
|
1977
|
+
self.P_n = np.zeros(Nn)
|
|
1978
|
+
# Add early withdrawal penalty if any.
|
|
1983
1979
|
for i in range(Ni):
|
|
1984
|
-
self.
|
|
1980
|
+
self.P_n[0:self.n59[i]] += 0.1*(self.w_ijn[i, 1, 0:self.n59[i]] + self.w_ijn[i, 2, 0:self.n59[i]])
|
|
1985
1981
|
|
|
1986
|
-
self.T_n += self.
|
|
1982
|
+
self.T_n += self.P_n
|
|
1987
1983
|
|
|
1988
1984
|
tau_0 = np.array(self.tau_kn[0, :])
|
|
1989
1985
|
tau_0[tau_0 < 0] = 0
|
|
@@ -2126,8 +2122,8 @@ class Plan(object):
|
|
|
2126
2122
|
dic[f"-- Subtotal in tax bracket {tname}"] = f"{u.d(taxPaidNow)}"
|
|
2127
2123
|
dic[f"-- [Subtotal in tax bracket {tname}]"] = f"{u.d(taxPaid)}"
|
|
2128
2124
|
|
|
2129
|
-
penaltyPaid = np.sum(self.
|
|
2130
|
-
penaltyPaidNow = np.sum(self.
|
|
2125
|
+
penaltyPaid = np.sum(self.P_n, axis=0)
|
|
2126
|
+
penaltyPaidNow = np.sum(self.P_n / self.gamma_n[:-1], axis=0)
|
|
2131
2127
|
dic["-- Subtotal in early withdrawal penalty"] = f"{u.d(penaltyPaidNow)}"
|
|
2132
2128
|
dic["-- [Subtotal in early withdrawal penalty]"] = f"{u.d(penaltyPaid)}"
|
|
2133
2129
|
|
|
@@ -110,6 +110,9 @@ def getRatesDistributions(frm, to, mylog=None):
|
|
|
110
110
|
# Build correlation matrix by dividing by the stdev for each column and row.
|
|
111
111
|
corr = covar / stdev[:, None]
|
|
112
112
|
corr = corr.T / stdev[:, None]
|
|
113
|
+
# Fold round-off errors in proper bounds.
|
|
114
|
+
corr[corr > 1] = 1
|
|
115
|
+
corr[corr < -1] = -1
|
|
113
116
|
mylog.print("correlation matrix: \n\t\t%s" % str(corr).replace("\n", "\n\t\t"))
|
|
114
117
|
|
|
115
118
|
return means, stdev, corr, covar
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2025.03.16"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2025.03.14"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|