owlplanner 2025.2.27__tar.gz → 2025.3.7__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.2.27 → owlplanner-2025.3.7}/.github/workflows/github-actions-runtests.yml +1 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/INSTALL.md +4 -3
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/PKG-INFO +9 -3
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/README.md +8 -2
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/pyproject.toml +1 -1
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/plan.py +20 -9
- owlplanner-2025.3.7/src/owlplanner/version.py +1 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Create_Case.py +2 -2
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Documentation.py +29 -13
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Output_Files.py +1 -2
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Quick_Start.py +2 -3
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/requirements.txt +1 -1
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/sskeys.py +5 -5
- owlplanner-2025.2.27/src/owlplanner/version.py +0 -1
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/.devcontainer/devcontainer.json +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/.flake8 +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/.gitattributes +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/.gitignore +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/LICENSE +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/USER_GUIDE.md +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docker/Dockerfile +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docker/README.md +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docker/docker-compose.yml +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docker/fastentrypoint.sh +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/AD-taxDef.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/AD-taxFree.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/AD-taxable.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/Hist_Bequest.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/Hist_Spending.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/MC-tutorial2a.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/MC-tutorial2b.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/OwlUI.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/allocations.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/owl.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/profile.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/ratesCorrelations.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/ratesPlot.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/savingsPlot.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/sourcesPlot.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/spendingPlot.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/taxIncomePlot.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/images/taxesPlot.png +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/owl.pdf +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/docs/owl.tex +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/case_jack+jill.toml +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/case_joe.toml +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/case_john+sally.toml +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/case_jon+jane.toml +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/case_kim+sam-bequest.toml +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/case_kim+sam-spending.toml +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/jack+jill.xlsx +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/joe.xlsx +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/john+sally.xlsx +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/jon+jane.xlsx +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/examples/template.xlsx +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/notebooks/john+sally.ipynb +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/notebooks/kim+sam.ipynb +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/notebooks/template.ipynb +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/notebooks/tutorial_1.ipynb +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/notebooks/tutorial_2.ipynb +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/notebooks/tutorial_3.ipynb +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/owlplanner.cmd +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/owlplanner.sh +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/requirements.txt +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/__init__.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/abcapi.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/config.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/data/__init__.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/data/rates.csv +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/logging.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/progress.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/rates.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/tax2025.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/timelists.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/src/owlplanner/utils.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/tests/test_logger.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/tests/test_regressions.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/tests/test_repro.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/tests/test_toml_cases.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/tests/test_units.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ttt.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/About_Owl.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Asset_Allocation.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Assets.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Fixed_Income.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Graphs.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Historical_Range.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Logs.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Monte_Carlo.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Optimization_Parameters.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/README.md +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Rates_Selection.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Settings.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Wages_And_Contributions.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/Worksheets.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/main+fonts.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/main.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/owlbridge.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/plots.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/progress.py +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/style.css +0 -0
- {owlplanner-2025.2.27 → owlplanner-2025.3.7}/ui/tomlexamples.py +0 -0
|
@@ -14,7 +14,7 @@ or, if one prefers to have everything on their own computer,
|
|
|
14
14
|
to install and run a Docker image as described in these [instructions](docker/README.md).
|
|
15
15
|
|
|
16
16
|
### Requirements
|
|
17
|
-
You will need Python and `pip` installed on your computer for
|
|
17
|
+
You will need Python and `pip` installed on your computer for completing the installation.
|
|
18
18
|
|
|
19
19
|
### Installation steps for developers
|
|
20
20
|
These instructions are command-line instructions.
|
|
@@ -29,7 +29,8 @@ From the top directory of the source code run:
|
|
|
29
29
|
python -m build
|
|
30
30
|
pip install -e .
|
|
31
31
|
```
|
|
32
|
-
The -e instructs
|
|
32
|
+
The -e instructs `pip` to install in *editable* mode and use the live version
|
|
33
|
+
in the current directory tree.
|
|
33
34
|
|
|
34
35
|
### Running the streamlit frontend
|
|
35
36
|
Running the Owl user interface locally from Windows:
|
|
@@ -42,7 +43,7 @@ Running the Owl user interface locally from Linux or MacOS:
|
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
### Publishing a version (for reference only)
|
|
45
|
-
Run checks before
|
|
46
|
+
Run checks before all commits:
|
|
46
47
|
```
|
|
47
48
|
flake8 ui src tests
|
|
48
49
|
pytest
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: owlplanner
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.3.7
|
|
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
|
|
@@ -711,7 +711,13 @@ Description-Content-Type: text/markdown
|
|
|
711
711
|
-------------------------------------------------------------------------------------
|
|
712
712
|
|
|
713
713
|
### TL;DR
|
|
714
|
-
Owl is a planning tool that uses a linear programming optimization algorithm
|
|
714
|
+
Owl is a retirement planning tool that uses a linear programming optimization algorithm
|
|
715
|
+
to provide guidance on retirement decisions, including Roth conversions.
|
|
716
|
+
Users can select varying return rates to perform historical back testing,
|
|
717
|
+
stochastic rates for performing Monte Carlo analyses,
|
|
718
|
+
or fixed rates either derived from historical averages, or set by the user.
|
|
719
|
+
|
|
720
|
+
There are a few ways to run Owl:
|
|
715
721
|
|
|
716
722
|
- Run Owl directly on the Streamlit Community Server at [owlplanner.streamlit.app](https://owlplanner.streamlit.app).
|
|
717
723
|
|
|
@@ -868,7 +874,7 @@ assets to support, even with no estate being left.
|
|
|
868
874
|
---------------------------------------------------------------
|
|
869
875
|
## Documentation
|
|
870
876
|
|
|
871
|
-
- Documentation for the app user interface is available from the interface itself.
|
|
877
|
+
- Documentation for the app user interface is available from the interface [itself](https://owlplanner.streamlit.app/Documentation).
|
|
872
878
|
- Installation guide and software requirements can be found [here](INSTALL.md).
|
|
873
879
|
- User guide for the underlying Python package as used in a Jupyter notebook can be found [here](USER_GUIDE.md).
|
|
874
880
|
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
-------------------------------------------------------------------------------------
|
|
9
9
|
|
|
10
10
|
### TL;DR
|
|
11
|
-
Owl is a planning tool that uses a linear programming optimization algorithm
|
|
11
|
+
Owl is a retirement planning tool that uses a linear programming optimization algorithm
|
|
12
|
+
to provide guidance on retirement decisions, including Roth conversions.
|
|
13
|
+
Users can select varying return rates to perform historical back testing,
|
|
14
|
+
stochastic rates for performing Monte Carlo analyses,
|
|
15
|
+
or fixed rates either derived from historical averages, or set by the user.
|
|
16
|
+
|
|
17
|
+
There are a few ways to run Owl:
|
|
12
18
|
|
|
13
19
|
- Run Owl directly on the Streamlit Community Server at [owlplanner.streamlit.app](https://owlplanner.streamlit.app).
|
|
14
20
|
|
|
@@ -165,7 +171,7 @@ assets to support, even with no estate being left.
|
|
|
165
171
|
---------------------------------------------------------------
|
|
166
172
|
## Documentation
|
|
167
173
|
|
|
168
|
-
- Documentation for the app user interface is available from the interface itself.
|
|
174
|
+
- Documentation for the app user interface is available from the interface [itself](https://owlplanner.streamlit.app/Documentation).
|
|
169
175
|
- Installation guide and software requirements can be found [here](INSTALL.md).
|
|
170
176
|
- User guide for the underlying Python package as used in a Jupyter notebook can be found [here](USER_GUIDE.md).
|
|
171
177
|
|
|
@@ -1968,8 +1968,8 @@ class Plan(object):
|
|
|
1968
1968
|
self.dist_in = self.w_ijn[:, 1, :] - self.rmd_in
|
|
1969
1969
|
self.dist_in[self.dist_in < 0] = 0
|
|
1970
1970
|
self.G_n = np.sum(self.F_tn, axis=0)
|
|
1971
|
-
T_tn = self.F_tn * self.theta_tn
|
|
1972
|
-
self.T_n = np.sum(T_tn, axis=0)
|
|
1971
|
+
self.T_tn = self.F_tn * self.theta_tn
|
|
1972
|
+
self.T_n = np.sum(self.T_tn, axis=0)
|
|
1973
1973
|
|
|
1974
1974
|
tau_0 = np.array(self.tau_kn[0, :])
|
|
1975
1975
|
tau_0[tau_0 < 0] = 0
|
|
@@ -2105,6 +2105,12 @@ class Plan(object):
|
|
|
2105
2105
|
taxPaidNow = np.sum(self.T_n / self.gamma_n[:-1], axis=0)
|
|
2106
2106
|
dic["Total income tax paid on ordinary income"] = f"{u.d(taxPaidNow)}"
|
|
2107
2107
|
dic["- Total income tax paid on ordinary income (nominal)"] = f"{u.d(taxPaid)}"
|
|
2108
|
+
for t in range(self.N_t):
|
|
2109
|
+
taxPaid = np.sum(self.T_tn[t], axis=0)
|
|
2110
|
+
taxPaidNow = np.sum(self.T_tn[t] / self.gamma_n[:-1], axis=0)
|
|
2111
|
+
tname = tx.taxBracketNames[t]
|
|
2112
|
+
dic[f"-- Subtotal in tax bracket {tname}"] = f"{u.d(taxPaidNow)}"
|
|
2113
|
+
dic[f"--- Subtotal in tax bracket {tname} (nominal)"] = f"{u.d(taxPaid)}"
|
|
2108
2114
|
|
|
2109
2115
|
taxPaid = np.sum(self.U_n, axis=0)
|
|
2110
2116
|
taxPaidNow = np.sum(self.U_n / self.gamma_n[:-1], axis=0)
|
|
@@ -2129,12 +2135,17 @@ class Plan(object):
|
|
|
2129
2135
|
iname_s = self.inames[self.i_s]
|
|
2130
2136
|
iname_d = self.inames[self.i_d]
|
|
2131
2137
|
dic[f"Sum of spousal transfer to {iname_s} in year {ynx}"] = (f"{u.d(totSpousalNow)}")
|
|
2132
|
-
dic[f"- Sum of spousal transfer to {iname_s} in year {ynx} (nominal)"] = (
|
|
2133
|
-
|
|
2134
|
-
dic[f"-- Spousal transfer to {iname_s} in year {ynx} -
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
+
dic[f"- Sum of spousal transfer to {iname_s} in year {ynx} (nominal)"] = (
|
|
2139
|
+
f"{u.d(totSpousal)}")
|
|
2140
|
+
dic[f"-- Spousal transfer to {iname_s} in year {ynx} - taxable (nominal)"] = (
|
|
2141
|
+
f"{u.d(q_j[0])}")
|
|
2142
|
+
dic[f"-- Spousal transfer to {iname_s} in year {ynx} - tax-def (nominal)"] = (
|
|
2143
|
+
f"{u.d(q_j[1])}")
|
|
2144
|
+
dic[f"-- Spousal transfer to {iname_s} in year {ynx} - tax-free (nominal)"] = (
|
|
2145
|
+
f"{u.d(q_j[2])}")
|
|
2146
|
+
|
|
2147
|
+
dic[f"Sum of post-tax non-spousal bequests from {iname_d} in year {ynx}"] = (
|
|
2148
|
+
f"{u.d(totOthersNow)}")
|
|
2138
2149
|
dic[f"- Sum of post-tax non-spousal bequests from {iname_d} in year {ynx} (nominal)"] = (
|
|
2139
2150
|
f"{u.d(totOthers)}")
|
|
2140
2151
|
dic[f"-- Post-tax non-spousal bequests from {iname_d} in year {ynx} - taxable (nominal)"] = (
|
|
@@ -2156,7 +2167,7 @@ class Plan(object):
|
|
|
2156
2167
|
dic[f"-- Post-tax account value at the end of {lastyear} - tax-free (nominal)"] = (f"{u.d(estate[2])}")
|
|
2157
2168
|
|
|
2158
2169
|
dic["Plan starting date"] = str(self.startDate)
|
|
2159
|
-
dic[f"Cumulative inflation factor from start date to end of {lastyear}"] = f"{self.gamma_n[-1]:.2f}"
|
|
2170
|
+
dic[f"Cumulative inflation factor from start date to end of {lastyear}"] = (f"{self.gamma_n[-1]:.2f}")
|
|
2160
2171
|
for i in range(self.N_i):
|
|
2161
2172
|
dic[f"{self.inames[i]:>12}'s {self.horizons[i]:02}-year life horizon"] = (
|
|
2162
2173
|
f"{now} -> {now + self.horizons[i] - 1}")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2025.03.07"
|
|
@@ -25,7 +25,7 @@ elif ret == kz.loadCaseFile:
|
|
|
25
25
|
st.info(
|
|
26
26
|
"#### Starting a case from a *case* parameter file.\n\n"
|
|
27
27
|
"Upload your own case or select one from multiple examples."
|
|
28
|
-
" Alternatively, you can select `New Case...` in the
|
|
28
|
+
" Alternatively, you can select `New Case...` in the top selector box to start a case from scratch.\n\n"
|
|
29
29
|
"Look at the :material/help: [Documentation](Documentation) for more details."
|
|
30
30
|
)
|
|
31
31
|
st.write("#### Upload your own case file")
|
|
@@ -121,7 +121,7 @@ else:
|
|
|
121
121
|
st.divider()
|
|
122
122
|
cantcreate = kz.isIncomplete() or diz1
|
|
123
123
|
if not cantcreate and kz.getKey("plan") is None:
|
|
124
|
-
st.info("Plan needs to be created once
|
|
124
|
+
st.info("Plan needs to be created once desired changes are completed.")
|
|
125
125
|
|
|
126
126
|
cantmodify = kz.currentCaseName() == kz.newCase or kz.currentCaseName() == kz.loadCaseFile
|
|
127
127
|
cantcopy = cantmodify or kz.caseHasNoPlan()
|
|
@@ -34,16 +34,28 @@ formulation of the optimization problem can be found
|
|
|
34
34
|
|
|
35
35
|
--------------------------------------------------------------------------------------
|
|
36
36
|
### Getting started with the user interface
|
|
37
|
-
Functions of each page are described below in the same order as they appear in the sidebar.
|
|
37
|
+
Functions of each page are described below in the same order as they appear in the left sidebar.
|
|
38
38
|
Typically, pages would be accessed in order, starting from the top.
|
|
39
|
+
|
|
39
40
|
The `Case selector` box at the top of the page allows to select an existing case
|
|
40
41
|
or create a new one from scratch, or from a *case* parameter file, which
|
|
41
42
|
would then populate all parameter values.
|
|
42
43
|
This box is present in all pages except those in the **Resources** section
|
|
43
|
-
and allows to compare different scenarios.
|
|
44
|
+
and allows to access and compare different scenarios.
|
|
45
|
+
|
|
46
|
+
A typical workflow for exploring different scenarios involves starting with a base
|
|
47
|
+
case and then duplicating/creating derived scenarios with slight changes in the parameters,
|
|
48
|
+
which are configured in the **Case Setup** section. The comparison between the
|
|
49
|
+
different resulting outcomes is shown on the [Output Files](#output-files) page.
|
|
50
|
+
|
|
51
|
+
Owl uses a year as the standard time unit. All values are therefore entered and
|
|
52
|
+
reported as yearly values. These include wages, income, rates, social security, etc.
|
|
53
|
+
Dollar values are typically entered in thousands, unless in tables, where they
|
|
54
|
+
are entered and reported in unit dollars.
|
|
44
55
|
|
|
45
56
|
There are four sections in the user interface:
|
|
46
57
|
**Case Setup**, **Single Scenario**, **Multiple Scenarios**, and **Resources**.
|
|
58
|
+
The sections below follow the same logical order.
|
|
47
59
|
|
|
48
60
|
-------------------------------------------------
|
|
49
61
|
### :orange[Case Setup]
|
|
@@ -307,24 +319,28 @@ The first line of the *Sources* worksheets are the most important
|
|
|
307
319
|
as these lines are the only ones that are actionable.
|
|
308
320
|
|
|
309
321
|
#### Output Files
|
|
310
|
-
This page
|
|
311
|
-
First it shows a synopsis of the computed scenario by
|
|
322
|
+
This page allows to compare cases and save files for future use.
|
|
323
|
+
First, it shows a synopsis of the computed scenario by
|
|
312
324
|
displaying sums of income, bequest, and spending values over the duration of the plan.
|
|
313
|
-
If
|
|
314
|
-
|
|
325
|
+
If multiple cases were configured and run (most likely through duplication and
|
|
326
|
+
modifying the configuration), they will be compared in that panel provided they were made
|
|
327
|
+
for the same individuals. Column on the left shows the values for the selected case
|
|
328
|
+
while those on the right will show the differences.
|
|
315
329
|
The contents of the synopsis can be downloaded as a plain text file by
|
|
316
330
|
clicking the button below it.
|
|
317
331
|
|
|
318
|
-
Similarly, parameters used to generate the case are collected in *toml* format and displayed.
|
|
319
|
-
The `Download case file...` button allows to save the parameters used to generate the
|
|
320
|
-
outcome of this case to a *case* file.
|
|
321
|
-
|
|
322
332
|
Another section called `Excel workbooks` allows
|
|
323
|
-
to save the contents of the tables on the corresponding page
|
|
333
|
+
to save the contents of the tables on the corresponding page as an Excel workbook.
|
|
334
|
+
These data are displayed on the *Worksheets* and the *Wages and Contributions* pages.
|
|
335
|
+
|
|
336
|
+
Similarly, all parameters used to generate the case are collected in *toml* format and displayed.
|
|
337
|
+
The `Download case file...` button allows to save the parameters of the selected scenario
|
|
338
|
+
to a *case* file.
|
|
324
339
|
|
|
325
|
-
With the case parameter and the wages and contributions
|
|
340
|
+
With the case parameter file and the wages and contributions worksheet,
|
|
326
341
|
the same case can be reproduced at a later time by uploading
|
|
327
|
-
them through the widgets on the `Create Case` and `Wages and Contributions` pages
|
|
342
|
+
them through the widgets on the `Create Case` and `Wages and Contributions` pages,
|
|
343
|
+
respectively.
|
|
328
344
|
|
|
329
345
|
--------------------------------------------------------------------------------------
|
|
330
346
|
### :orange[Multiple Scenarios]
|
|
@@ -18,9 +18,8 @@ else:
|
|
|
18
18
|
df = kz.compareSummaries()
|
|
19
19
|
if df is not None:
|
|
20
20
|
st.write("#### Synopsis")
|
|
21
|
-
# st.code(lines, language=None)
|
|
22
|
-
# st.markdown(df.to_markdown())
|
|
23
21
|
st.dataframe(df[1:], use_container_width=True)
|
|
22
|
+
st.caption("Values are in today's \\$ unless marked otherwise.")
|
|
24
23
|
st.download_button(
|
|
25
24
|
"Download synopsis", data=df[1:].to_string(), file_name=f"Synopsis_{caseName}.txt",
|
|
26
25
|
mime="text/plain;charset=UTF-8"
|
|
@@ -49,12 +49,11 @@ experiment with different parameters.
|
|
|
49
49
|
For creating your own cases, you can start
|
|
50
50
|
from scratch by selecting `New Case...` in the selection box while on the **Create Case** page,
|
|
51
51
|
and fill in the information needed on each page in the `Case Setup` section.
|
|
52
|
-
Once a case has been fully parameterized and successfully optimized,
|
|
53
|
-
its parameters can be saved by using the `Download case file...` button on the `Output Files` page.
|
|
54
|
-
|
|
55
52
|
Alternatively, you can duplicate any existing case by using
|
|
56
53
|
the `Duplicate case` button, and then edit its values to fit your situation.
|
|
57
54
|
|
|
55
|
+
Once a case has been fully parameterized and successfully optimized,
|
|
56
|
+
its parameters can be saved by using the `Download case file...` button on the `Output Files` page.
|
|
58
57
|
Multiple cases can coexist and can be called and compared using the `Case selector` box
|
|
59
58
|
at the top of the page.
|
|
60
59
|
|
|
@@ -260,7 +260,7 @@ def storepull(key):
|
|
|
260
260
|
def setKey(key, val):
|
|
261
261
|
ss.cases[ss.currentCase][key] = val
|
|
262
262
|
ss.cases[ss.currentCase]["caseStatus"] = "modified"
|
|
263
|
-
|
|
263
|
+
ss.cases[ss.currentCase]["summaryDf"] = None
|
|
264
264
|
return val
|
|
265
265
|
|
|
266
266
|
|
|
@@ -326,7 +326,7 @@ def compareSummaries():
|
|
|
326
326
|
df = pd.concat([df, odf])
|
|
327
327
|
|
|
328
328
|
if df.shape[0] > 1:
|
|
329
|
-
# Unroll to subtract
|
|
329
|
+
# Unroll to subtract $tring representation of numbers.
|
|
330
330
|
for col in range(1, df.shape[1] - 5):
|
|
331
331
|
strval = df.iloc[0, col]
|
|
332
332
|
if isinstance(strval, str) and strval[0] == "$":
|
|
@@ -334,9 +334,9 @@ def compareSummaries():
|
|
|
334
334
|
for row in range(1, df.shape[0]):
|
|
335
335
|
fnval = float(df.iloc[row, col][1:].replace(",", ""))
|
|
336
336
|
diff = fnval - f0val
|
|
337
|
-
sign = "
|
|
338
|
-
sign = "" if diff == 0 else sign
|
|
339
|
-
df.iloc[row, col] = f"{sign}${abs(diff):,.0f}"
|
|
337
|
+
sign = "\u2191" if diff >= 0 else "\u2193"
|
|
338
|
+
sign = "\u2192" if diff == 0 else sign
|
|
339
|
+
df.iloc[row, col] = f"{sign} ${abs(diff):,.0f}"
|
|
340
340
|
|
|
341
341
|
return df.transpose()
|
|
342
342
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2025.02.27"
|
|
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
|