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.
Files changed (108) hide show
  1. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/PKG-INFO +1 -1
  2. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/owl.pdf +0 -0
  3. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/owl.tex +53 -39
  4. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/pyproject.toml +1 -1
  5. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/plan.py +9 -13
  6. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/rates.py +3 -0
  7. owlplanner-2025.3.16/src/owlplanner/version.py +1 -0
  8. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/requirements.txt +1 -1
  9. owlplanner-2025.3.14/src/owlplanner/version.py +0 -1
  10. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.devcontainer/devcontainer.json +0 -0
  11. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.flake8 +0 -0
  12. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.gitattributes +0 -0
  13. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.github/workflows/github-actions-runtests.yml +0 -0
  14. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/.gitignore +0 -0
  15. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/INSTALL.md +0 -0
  16. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/LICENSE +0 -0
  17. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/FE00006821-Class-VI-Injection-Permit--Salient-Features-and-Regulatory-Challenges_Final.pdf +0 -0
  18. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/Kou-OptionPricingDouble-2004.pdf +0 -0
  19. {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
  20. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/Optimal Asset Allocation for Retirement Saving Deterministic Vs. Time Consistent Adaptive Strategies.pdf +0 -0
  21. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/Rule-based_strategies_for_dynamic_life_cycle_inves.pdf +0 -0
  22. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/Papers/s10436-006-0062-y.pdf +0 -0
  23. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/README.md +0 -0
  24. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/USER_GUIDE.md +0 -0
  25. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/Dockerfile +0 -0
  26. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/README.md +0 -0
  27. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/docker-compose.yml +0 -0
  28. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docker/fastentrypoint.sh +0 -0
  29. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/AD-taxDef.png +0 -0
  30. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/AD-taxFree.png +0 -0
  31. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/AD-taxable.png +0 -0
  32. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/Hist_Bequest.png +0 -0
  33. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/Hist_Spending.png +0 -0
  34. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/MC-tutorial2a.png +0 -0
  35. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/MC-tutorial2b.png +0 -0
  36. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/OwlUI.png +0 -0
  37. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/allocations.png +0 -0
  38. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/owl.png +0 -0
  39. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/profile.png +0 -0
  40. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/ratesCorrelations.png +0 -0
  41. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/ratesPlot.png +0 -0
  42. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/savingsPlot.png +0 -0
  43. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/sourcesPlot.png +0 -0
  44. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/spendingPlot.png +0 -0
  45. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/taxIncomePlot.png +0 -0
  46. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/docs/images/taxesPlot.png +0 -0
  47. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_jack+jill.toml +0 -0
  48. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_joe.toml +0 -0
  49. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_john+sally.toml +0 -0
  50. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_jon+jane.toml +0 -0
  51. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_kim+sam-bequest.toml +0 -0
  52. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/case_kim+sam-spending.toml +0 -0
  53. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/jack+jill.xlsx +0 -0
  54. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/joe.xlsx +0 -0
  55. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/john+sally.xlsx +0 -0
  56. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/jon+jane.xlsx +0 -0
  57. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/examples/template.xlsx +0 -0
  58. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/john+sally.ipynb +0 -0
  59. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/kim+sam.ipynb +0 -0
  60. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/template.ipynb +0 -0
  61. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/tutorial_1.ipynb +0 -0
  62. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/tutorial_2.ipynb +0 -0
  63. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/notebooks/tutorial_3.ipynb +0 -0
  64. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/owlplanner.cmd +0 -0
  65. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/owlplanner.sh +0 -0
  66. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/requirements.txt +0 -0
  67. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/__init__.py +0 -0
  68. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/abcapi.py +0 -0
  69. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/config.py +0 -0
  70. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/data/__init__.py +0 -0
  71. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/data/rates.csv +0 -0
  72. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/logging.py +0 -0
  73. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/progress.py +0 -0
  74. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/tax2025.py +0 -0
  75. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/timelists.py +0 -0
  76. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/src/owlplanner/utils.py +0 -0
  77. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_logger.py +0 -0
  78. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_regressions.py +0 -0
  79. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_repro.py +0 -0
  80. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_toml_cases.py +0 -0
  81. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/tests/test_units.py +0 -0
  82. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ttt.py +0 -0
  83. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/About_Owl.py +0 -0
  84. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Asset_Allocation.py +0 -0
  85. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Create_Case.py +0 -0
  86. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Current_Assets.py +0 -0
  87. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Documentation.py +0 -0
  88. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Fixed_Income.py +0 -0
  89. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Graphs.py +0 -0
  90. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Historical_Range.py +0 -0
  91. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Logs.py +0 -0
  92. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Monte_Carlo.py +0 -0
  93. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Optimization_Parameters.py +0 -0
  94. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Output_Files.py +0 -0
  95. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Quick_Start.py +0 -0
  96. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/README.md +0 -0
  97. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Rates_Selection.py +0 -0
  98. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Settings.py +0 -0
  99. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Wages_And_Contributions.py +0 -0
  100. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/Worksheets.py +0 -0
  101. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/main+fonts.py +0 -0
  102. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/main.py +0 -0
  103. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/owlbridge.py +0 -0
  104. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/plots.py +0 -0
  105. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/progress.py +0 -0
  106. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/sskeys.py +0 -0
  107. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/style.css +0 -0
  108. {owlplanner-2025.3.14 → owlplanner-2025.3.16}/ui/tomlexamples.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.3.14
3
+ Version: 2025.3.16
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
@@ -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
- Year being modeled. Period being modeled runs from the beginning of year 0 to
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 adjusted standard deviation is simply subtracted
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 [$\beta{ij}$]
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
- spending profiles reported in the literature. See Fig.~\ref{Fig:profile} for an example.
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
- \begin{figure}[t]
193
- \includegraphics{profile.png}
194
- \caption{\small Example of a spending profile with 15\% cosine factor and a 12\% linear
195
- profile. \label{Fig:profile}}
196
- \end{figure}
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}}$. Then, intermediate values are interpolated either using
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. Pensions
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} + 0.10 \sum_i (1 - \mathcal{H}(n - n_{i,60})) w_{i1n},
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} + s_{n}
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 \\
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "owlplanner"
7
- version = "2025.03.14"
7
+ version = "2025.03.16"
8
8
  authors = [
9
9
  { name="Martin-D. Lacasse", email="martin.d.lacasse@gmail.com" },
10
10
  ]
@@ -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
- row.addElem(_q3(Cw, i, 1, n, Ni, Nj, Nn), -1)
1288
- row.addElem(_q3(Cw, i, 2, n, Ni, Nj, Nn), -1)
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.penalty_n = np.zeros(Nn)
1982
- # Add early withdrawal penalties if any.
1977
+ self.P_n = np.zeros(Nn)
1978
+ # Add early withdrawal penalty if any.
1983
1979
  for i in range(Ni):
1984
- self.penalty_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]])
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.penalty_n
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.penalty_n, axis=0)
2130
- penaltyPaidNow = np.sum(self.penalty_n / self.gamma_n[:-1], axis=0)
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"
@@ -7,4 +7,4 @@ scipy
7
7
  streamlit
8
8
  toml
9
9
  # --extra-index-url https://test.pypi.org/simple
10
- owlplanner >= 2025.03.14
10
+ owlplanner >= 2025.03.16
@@ -1 +0,0 @@
1
- __version__ = "2025.03.14"
File without changes
File without changes
File without changes
File without changes