owlplanner 2025.2.5__tar.gz → 2025.2.6__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.5 → owlplanner-2025.2.6}/PKG-INFO +1 -1
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/pyproject.toml +1 -1
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/plan.py +1 -1
- owlplanner-2025.2.6/src/owlplanner/version.py +1 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/About_Owl.py +1 -1
- owlplanner-2025.2.5/ui/Basic_Info.py → owlplanner-2025.2.6/ui/Create_Case.py +1 -1
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Documentation.py +18 -15
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Graphs.py +1 -1
- owlplanner-2025.2.5/ui/Case_Summary.py → owlplanner-2025.2.6/ui/Output_Files.py +23 -12
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Quick_Start.py +7 -7
- owlplanner-2025.2.6/ui/Worksheets.py +18 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/main.py +3 -3
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/owlbridge.py +25 -7
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/requirements.txt +1 -1
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/sskeys.py +0 -8
- owlplanner-2025.2.5/src/owlplanner/version.py +0 -1
- owlplanner-2025.2.5/ui/Worksheets.py +0 -27
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.devcontainer/devcontainer.json +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.flake8 +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.github/workflows/github-actions-runtests.yml +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.gitignore +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/INSTALL.md +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/LICENSE +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/README.md +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/AD-taxDef.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/AD-taxFree.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/AD-taxable.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/Hist_Bequest.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/Hist_Spending.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/MC-tutorial2a.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/MC-tutorial2b.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/OwlUI.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/allocations.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/owl.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/profile.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/ratesCorrelations.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/ratesPlot.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/savingsPlot.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/sourcesPlot.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/spendingPlot.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/taxIncomePlot.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/taxesPlot.png +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/owl.pdf +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/owl.tex +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_jack+jill.toml +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_joe.toml +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_john+sally.toml +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_kim+sam-bequest.toml +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_kim+sam-spending.toml +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/jack+jill.xlsx +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/joe.xlsx +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/john+sally.xlsx +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/template.xlsx +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/john+sally.ipynb +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/kim+sam.ipynb +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/template.ipynb +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/tutorial_1.ipynb +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/tutorial_2.ipynb +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/tutorial_3.ipynb +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/owlplanner.cmd +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/requirements.txt +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/__init__.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/abcapi.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/config.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/data/__init__.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/data/rates.csv +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/logging.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/progress.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/rates.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/tax2025.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/timelists.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/utils.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_logger.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_regressions.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_repro.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_toml_cases.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_units.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Asset_Allocation.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Assets.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Fixed_Income.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Historical_Range.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Logs.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Monte_Carlo.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Optimization_Parameters.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/README.md +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Rates_Selection.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Settings.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Wages_And_Contributions.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/plots.py +0 -0
- {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/progress.py +0 -0
|
@@ -540,7 +540,7 @@ class Plan(object):
|
|
|
540
540
|
|
|
541
541
|
if self.N_i == 2:
|
|
542
542
|
# Approximate calculation for spousal benefit (only valid at FRA).
|
|
543
|
-
self.zeta_in[self.i_s, self.n_d:] = max(amounts[self.i_s], amounts[self.i_d]
|
|
543
|
+
self.zeta_in[self.i_s, self.n_d:] = max(amounts[self.i_s], amounts[self.i_d])
|
|
544
544
|
|
|
545
545
|
self.ssecAmounts = np.array(amounts)
|
|
546
546
|
self.ssecAges = np.array(ages, dtype=np.int32)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2025.02.06"
|
|
@@ -12,7 +12,7 @@ st.snow()
|
|
|
12
12
|
|
|
13
13
|
st.write('''
|
|
14
14
|
- Owl is released under GPL Licence through a publicly available
|
|
15
|
-
repository on [
|
|
15
|
+
repository on [GitHub](https://github.com/mdlacasse/owl).
|
|
16
16
|
|
|
17
17
|
- Mathematical formulation of the linear optimization problem can be
|
|
18
18
|
found [here](https://raw.github.com/mdlacasse/Owl/main/docs/owl.pdf).
|
|
@@ -46,7 +46,7 @@ There are four sections in the user interface:
|
|
|
46
46
|
### :orange[Case Setup]
|
|
47
47
|
This section contains the steps for creating and configuring case scenarios.
|
|
48
48
|
|
|
49
|
-
####
|
|
49
|
+
#### Create Case
|
|
50
50
|
This page is where every new scenario begins.
|
|
51
51
|
It controls the creation of scenarios as the `Select case` drop-down menu contains
|
|
52
52
|
two additional items when this page is open:
|
|
@@ -72,7 +72,7 @@ An example is provided
|
|
|
72
72
|
can be found in this [directory](https://github.com/mdlacasse/Owl/blob/main/examples/).
|
|
73
73
|
Using a *case* file
|
|
74
74
|
will populate all the fields required to run a scenario. A *case* file for the case being developed
|
|
75
|
-
can be saved under the [
|
|
75
|
+
can be saved under the [Output Files](#output-files) page and made available to reload at a later time.
|
|
76
76
|
Case parameter files can have any name but when saving from the interface, their name will start with *case_*
|
|
77
77
|
followed by the case name.
|
|
78
78
|
|
|
@@ -246,8 +246,10 @@ As one of the two choices (net spending or bequest) is selected as the value to
|
|
|
246
246
|
the other becomes a constraint to obey.
|
|
247
247
|
|
|
248
248
|
The maximum amount for Roth conversions and who can execute them is configurable.
|
|
249
|
-
|
|
250
|
-
|
|
249
|
+
Roth conversions are optimized for reducing taxes and maximizing the selected objective function,
|
|
250
|
+
unless the `Convert from contributions file`
|
|
251
|
+
button is toggled, in which case Roth conversions will not be optimized,
|
|
252
|
+
but will rather be performed according to
|
|
251
253
|
the `Roth conv` column on the
|
|
252
254
|
[Wages and Contributions](#wages-and-contributions) page.
|
|
253
255
|
|
|
@@ -285,8 +287,6 @@ This simulation uses a single instance of a series of rates, either fixed or var
|
|
|
285
287
|
as selected in the **Case Setup** section.
|
|
286
288
|
The outcome is optimized according to the chosen parameters: either maximize the
|
|
287
289
|
net spending, of maximize the bequest under the constraint of a net spending amount.
|
|
288
|
-
If `Convert from contributions file` is not toggled on,
|
|
289
|
-
Roth conversions are optimized for reducing taxes and maximizing the selected objective function.
|
|
290
290
|
Various plots show the results, which can be displayed in today's \\$ or
|
|
291
291
|
in nominal value.
|
|
292
292
|
|
|
@@ -298,26 +298,29 @@ these graphs, two additional buttons will appear.
|
|
|
298
298
|
This page shows the various worksheets containing annual transactions
|
|
299
299
|
and savings account balances in nominal \\$.
|
|
300
300
|
Each table can be downloaded separately in csv format, or all tables can be downloaded
|
|
301
|
-
together as an Excel workbook by clicking the button
|
|
302
|
-
|
|
301
|
+
together as an Excel workbook by clicking the associated button on the
|
|
302
|
+
[Output Files](#output-files) page.
|
|
303
303
|
Note that all values here (worksheets and workbook) are in \\$, not in thousands.
|
|
304
304
|
The first line of the *Sources* worksheets are the most important
|
|
305
305
|
as these lines are the only ones that are actionable.
|
|
306
306
|
|
|
307
|
-
####
|
|
308
|
-
This page
|
|
309
|
-
|
|
307
|
+
#### Output Files
|
|
308
|
+
This page allow to save many files for future use.
|
|
309
|
+
First it shows a synopsis of the computed scenario by
|
|
310
|
+
displaying sums of income, bequest, and spending values over the duration of the plan.
|
|
310
311
|
The contents of this page can be downloaded as a plain text file by
|
|
311
312
|
clicking the button at the bottom of the section.
|
|
312
313
|
|
|
313
|
-
|
|
314
|
+
Finally, parameters used to generate the case are collected in *toml* format and displayed.
|
|
314
315
|
The `Download case file...` button allows to save the parameters used to generate the
|
|
315
316
|
outcome of this case to a *case* file.
|
|
316
317
|
|
|
317
|
-
|
|
318
|
+
Another section called `Excel workbooks` allows
|
|
318
319
|
to save the contents of the tables on the corresponding page to an Excel workbook.
|
|
319
|
-
|
|
320
|
-
|
|
320
|
+
|
|
321
|
+
With the case parameter and the wages and contributions files,
|
|
322
|
+
the same case can be reproduced at a later time by uploading
|
|
323
|
+
them through the widgets on the `Create Case` and `Wages and Contributions` pages.
|
|
321
324
|
|
|
322
325
|
--------------------------------------------------------------------------------------
|
|
323
326
|
### :orange[Multiple Scenarios]
|
|
@@ -4,7 +4,7 @@ import sskeys as kz
|
|
|
4
4
|
import owlbridge as owb
|
|
5
5
|
|
|
6
6
|
ret = kz.titleBar('summary')
|
|
7
|
-
kz.caseHeader("
|
|
7
|
+
kz.caseHeader("Output Files")
|
|
8
8
|
|
|
9
9
|
if ret is None or kz.caseHasNoPlan():
|
|
10
10
|
st.info('Case(s) must be first created before running this page.')
|
|
@@ -12,7 +12,7 @@ else:
|
|
|
12
12
|
if kz.caseIsRunReady():
|
|
13
13
|
owb.runPlan()
|
|
14
14
|
|
|
15
|
-
if kz.
|
|
15
|
+
if kz.isCaseUnsolved():
|
|
16
16
|
st.info("Case status is currently '%s'." % kz.getKey('caseStatus'))
|
|
17
17
|
else:
|
|
18
18
|
lines = kz.getKey('summary')
|
|
@@ -24,6 +24,27 @@ else:
|
|
|
24
24
|
file_name='Synopsis_'+kz.getKey('name')+'.txt',
|
|
25
25
|
mime='text/plain;charset=UTF-8')
|
|
26
26
|
|
|
27
|
+
st.divider()
|
|
28
|
+
st.write("#### Excel workbooks")
|
|
29
|
+
col1, col2 = st.columns(2, gap='large')
|
|
30
|
+
with col1:
|
|
31
|
+
download2 = st.download_button(
|
|
32
|
+
label="Download wages and contributions file",
|
|
33
|
+
help='Download wages and contributions as an Excel workbook.',
|
|
34
|
+
data=owb.saveContributions(),
|
|
35
|
+
file_name=kz.getKey('name')+'.xlsx',
|
|
36
|
+
disabled=kz.isCaseUnsolved(),
|
|
37
|
+
mime='application/vnd.ms-excel')
|
|
38
|
+
|
|
39
|
+
with col2:
|
|
40
|
+
download2 = st.download_button(
|
|
41
|
+
label="Download worksheets",
|
|
42
|
+
help='Download worksheets as an Excel workbook.',
|
|
43
|
+
data=owb.saveWorkbook(),
|
|
44
|
+
file_name='Workbook_'+kz.getKey('name')+'.xlsx',
|
|
45
|
+
mime='application/vnd.ms-excel',
|
|
46
|
+
disabled=kz.isCaseUnsolved())
|
|
47
|
+
|
|
27
48
|
lines = kz.getKey('casetoml')
|
|
28
49
|
if lines != '':
|
|
29
50
|
st.divider()
|
|
@@ -34,13 +55,3 @@ else:
|
|
|
34
55
|
data=lines,
|
|
35
56
|
file_name='case_'+kz.getKey('name')+'.toml',
|
|
36
57
|
mime='application/toml')
|
|
37
|
-
|
|
38
|
-
st.divider()
|
|
39
|
-
st.write("#### Wages and contributions file")
|
|
40
|
-
download2 = st.download_button(
|
|
41
|
-
label="Download wages and contributions file",
|
|
42
|
-
help='Download Excel workbook.',
|
|
43
|
-
data=owb.saveContributions(),
|
|
44
|
-
file_name=kz.getKey('name')+'.xlsx',
|
|
45
|
-
disabled=kz.caseHasNotCompletedRun(),
|
|
46
|
-
mime='application/vnd.ms-excel')
|
|
@@ -13,7 +13,8 @@ with col1:
|
|
|
13
13
|
st.markdown('''
|
|
14
14
|
Owl does not store any information related to a case:
|
|
15
15
|
all is lost after a session is closed. For that reason,
|
|
16
|
-
two files can be used to store the specifications of a case so that it can be
|
|
16
|
+
two files can be used to store the specifications of a case so that it can be reproduced
|
|
17
|
+
at a later time:
|
|
17
18
|
- A *case* parameter file
|
|
18
19
|
specifying account balances, asset allocation, social security and pension, rates,
|
|
19
20
|
optimization parameters and related assumptions.
|
|
@@ -33,26 +34,25 @@ of Jack and Jill provided here as an example:
|
|
|
33
34
|
- Wages and contributions file named
|
|
34
35
|
[jack+jill.xlsx](https://raw.github.com/mdlacasse/Owl/main/examples/jack+jill.xlsx)
|
|
35
36
|
in Excel format.
|
|
36
|
-
1) Navigate to the **
|
|
37
|
+
1) Navigate to the **Create Case** page and drag and drop the case parameter file
|
|
37
38
|
you just downloaded (*case_jack+jill.toml*).
|
|
38
39
|
1) Navigate to the **Wages and Contributions** page and
|
|
39
40
|
drag and drop the wages and contributions file you downloaded (*jack+jill.xlsx*).
|
|
40
|
-
1) Move to the **Single Scenario** section to browse results.
|
|
41
|
+
1) Move to the **Single Scenario** section to browse the simulation results.
|
|
41
42
|
|
|
42
43
|
Congratulations! :balloon: You just ran your first case. You can now explore each page and
|
|
43
44
|
experiment with different parameters.
|
|
44
45
|
|
|
45
46
|
For creating your own cases, you can start
|
|
46
|
-
from scratch by selecting `New Case...` in the selection box while on the **
|
|
47
|
+
from scratch by selecting `New Case...` in the selection box while on the **Create Case** page,
|
|
47
48
|
and fill in the information needed on each page of the `Case Setup` section.
|
|
48
49
|
Once a case has been fully parameterized and successfully optimized,
|
|
49
|
-
|
|
50
|
-
by using the `Download case file...` button on the `Case Results` page.
|
|
50
|
+
its parameters can be saved by using the `Download case file...` button on the `Output Files` page.
|
|
51
51
|
|
|
52
52
|
Alternatively, you can duplicate any existing case by using
|
|
53
53
|
the `Duplicate case` button, and then edit its values to fit your situation.
|
|
54
54
|
|
|
55
|
-
Multiple cases can coexist and can be called using the `Select case` box
|
|
55
|
+
Multiple cases can coexist and can be called and compared using the `Select case` box
|
|
56
56
|
at the bottom of the margin.
|
|
57
57
|
|
|
58
58
|
More information can be found on the :material/help: **Documentation** page located in the **Resources** section.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
|
|
3
|
+
import sskeys as kz
|
|
4
|
+
import owlbridge as owb
|
|
5
|
+
|
|
6
|
+
ret = kz.titleBar('worksheets')
|
|
7
|
+
kz.caseHeader("Worksheets")
|
|
8
|
+
|
|
9
|
+
if ret is None or kz.caseHasNoPlan():
|
|
10
|
+
st.info('Case(s) must be first created before running this page.')
|
|
11
|
+
else:
|
|
12
|
+
if kz.caseIsRunReady():
|
|
13
|
+
owb.runPlan()
|
|
14
|
+
|
|
15
|
+
if kz.isCaseUnsolved():
|
|
16
|
+
st.info("Case status is currently '%s'." % kz.getKey('caseStatus'))
|
|
17
|
+
else:
|
|
18
|
+
owb.showWorkbook()
|
|
@@ -11,16 +11,16 @@ kz.init()
|
|
|
11
11
|
st.logo('https://raw.github.com/mdlacasse/Owl/main/docs/images/owl.png', size='large')
|
|
12
12
|
|
|
13
13
|
pages = {
|
|
14
|
-
'Case Setup': [st.Page('
|
|
14
|
+
'Case Setup': [st.Page('Create_Case.py', icon=':material/person_add:'),
|
|
15
15
|
st.Page('Assets.py', icon=':material/savings:'),
|
|
16
16
|
st.Page('Wages_And_Contributions.py', icon=':material/work_history:'),
|
|
17
17
|
st.Page('Fixed_Income.py', icon=':material/currency_exchange:'),
|
|
18
18
|
st.Page('Rates_Selection.py', icon=':material/monitoring:'),
|
|
19
19
|
st.Page('Asset_Allocation.py', icon=':material/percent:'),
|
|
20
20
|
st.Page('Optimization_Parameters.py', icon=':material/tune:')],
|
|
21
|
-
'Single Scenario': [st.Page('Graphs.py', icon=':material/
|
|
21
|
+
'Single Scenario': [st.Page('Graphs.py', icon=':material/stacked_line_chart:'),
|
|
22
22
|
st.Page('Worksheets.py', icon=':material/data_table:'),
|
|
23
|
-
st.Page('
|
|
23
|
+
st.Page('Output_Files.py', icon=':material/description:')],
|
|
24
24
|
'Multiple Scenarios': [st.Page('Historical_Range.py', icon=':material/history:'),
|
|
25
25
|
st.Page('Monte_Carlo.py', icon=':material/finance:')],
|
|
26
26
|
'Resources': [st.Page('Logs.py', icon=':material/error:'),
|
|
@@ -59,7 +59,6 @@ def _checkPlan(func):
|
|
|
59
59
|
return wrapper
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
# _checkPlan
|
|
63
62
|
def prepareRun(plan):
|
|
64
63
|
ni = 2 if kz.getKey('status') == 'married' else 1
|
|
65
64
|
|
|
@@ -103,10 +102,10 @@ def prepareRun(plan):
|
|
|
103
102
|
plan.setLongTermCapitalTaxRate(kz.getKey('gainTx'))
|
|
104
103
|
plan.setDividendRate(kz.getKey('divRate'))
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
_setInterpolationMethod(plan)
|
|
106
|
+
_setAllocationRatios(plan)
|
|
107
|
+
_setRates(plan)
|
|
108
|
+
_setContributions(plan, False)
|
|
110
109
|
|
|
111
110
|
|
|
112
111
|
@_checkPlan
|
|
@@ -173,6 +172,10 @@ def runMC(plan):
|
|
|
173
172
|
|
|
174
173
|
@_checkPlan
|
|
175
174
|
def setRates(plan):
|
|
175
|
+
_setRates(plan)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _setRates(plan):
|
|
176
179
|
yfrm = kz.getKey('yfrm')
|
|
177
180
|
yto = kz.getKey('yto')
|
|
178
181
|
|
|
@@ -277,11 +280,19 @@ def showSources(plan):
|
|
|
277
280
|
|
|
278
281
|
@_checkPlan
|
|
279
282
|
def setInterpolationMethod(plan):
|
|
283
|
+
_setInterpolationMethod(plan)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _setInterpolationMethod(plan):
|
|
280
287
|
plan.setInterpolationMethod(kz.getKey('interpMethod'), kz.getKey('interpCenter'), kz.getKey('interpWidth'))
|
|
281
288
|
|
|
282
289
|
|
|
283
290
|
@_checkPlan
|
|
284
|
-
def setContributions(plan):
|
|
291
|
+
def setContributions(plan, reset=True):
|
|
292
|
+
_setContributions(plan, reset)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def _setContributions(plan, reset):
|
|
285
296
|
"""
|
|
286
297
|
Set from UI -> Plan.
|
|
287
298
|
"""
|
|
@@ -294,7 +305,10 @@ def setContributions(plan):
|
|
|
294
305
|
|
|
295
306
|
try:
|
|
296
307
|
plan.readContributions(dicDf)
|
|
297
|
-
|
|
308
|
+
if reset:
|
|
309
|
+
kz.setKey('timeListsFileName', 'edited values')
|
|
310
|
+
else:
|
|
311
|
+
kz.storeKey('timeListsFileName', 'edited values')
|
|
298
312
|
plan.timeListsFileName = 'edited values'
|
|
299
313
|
except Exception as e:
|
|
300
314
|
st.error("Failed to parse contributions: %s" % (e))
|
|
@@ -332,6 +346,10 @@ def resetContributions(plan):
|
|
|
332
346
|
|
|
333
347
|
@_checkPlan
|
|
334
348
|
def setAllocationRatios(plan):
|
|
349
|
+
_setAllocationRatios(plan)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _setAllocationRatios(plan):
|
|
335
353
|
if kz.getKey('allocType') == 'individual':
|
|
336
354
|
try:
|
|
337
355
|
generic = kz.getIndividualAllocationRatios()
|
|
@@ -123,14 +123,6 @@ def caseHasPlan():
|
|
|
123
123
|
return getKey('plan') is not None
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
def caseHasNotCompletedRun():
|
|
127
|
-
return not caseHasCompletedRun()
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def caseHasCompletedRun():
|
|
131
|
-
return getKey('caseStatus') == 'solved'
|
|
132
|
-
|
|
133
|
-
|
|
134
126
|
def caseIsRunReady():
|
|
135
127
|
return not caseIsNotRunReady() and getKey('caseStatus') in ['modified', 'new']
|
|
136
128
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2025.02.05"
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import streamlit as st
|
|
2
|
-
|
|
3
|
-
import sskeys as kz
|
|
4
|
-
import owlbridge as owb
|
|
5
|
-
|
|
6
|
-
ret = kz.titleBar('worksheets')
|
|
7
|
-
kz.caseHeader("Worksheets")
|
|
8
|
-
|
|
9
|
-
if ret is None or kz.caseHasNoPlan():
|
|
10
|
-
st.info('Case(s) must be first created before running this page.')
|
|
11
|
-
else:
|
|
12
|
-
if kz.caseIsRunReady():
|
|
13
|
-
owb.runPlan()
|
|
14
|
-
|
|
15
|
-
if kz.caseHasNotCompletedRun():
|
|
16
|
-
st.info("Case status is currently '%s'." % kz.getKey('caseStatus'))
|
|
17
|
-
else:
|
|
18
|
-
owb.showWorkbook()
|
|
19
|
-
st.divider()
|
|
20
|
-
if kz.caseHasPlan():
|
|
21
|
-
download2 = st.download_button(
|
|
22
|
-
label="Download data as an Excel workbook...",
|
|
23
|
-
data=owb.saveWorkbook(),
|
|
24
|
-
file_name='Workbook_'+kz.getKey('name')+'.xlsx',
|
|
25
|
-
mime='application/vnd.ms-excel',
|
|
26
|
-
disabled=kz.isCaseUnsolved()
|
|
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
|