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.
Files changed (90) hide show
  1. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/PKG-INFO +1 -1
  2. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/pyproject.toml +1 -1
  3. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/plan.py +1 -1
  4. owlplanner-2025.2.6/src/owlplanner/version.py +1 -0
  5. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/About_Owl.py +1 -1
  6. owlplanner-2025.2.5/ui/Basic_Info.py → owlplanner-2025.2.6/ui/Create_Case.py +1 -1
  7. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Documentation.py +18 -15
  8. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Graphs.py +1 -1
  9. owlplanner-2025.2.5/ui/Case_Summary.py → owlplanner-2025.2.6/ui/Output_Files.py +23 -12
  10. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Quick_Start.py +7 -7
  11. owlplanner-2025.2.6/ui/Worksheets.py +18 -0
  12. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/main.py +3 -3
  13. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/owlbridge.py +25 -7
  14. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/requirements.txt +1 -1
  15. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/sskeys.py +0 -8
  16. owlplanner-2025.2.5/src/owlplanner/version.py +0 -1
  17. owlplanner-2025.2.5/ui/Worksheets.py +0 -27
  18. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.devcontainer/devcontainer.json +0 -0
  19. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.flake8 +0 -0
  20. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.github/workflows/github-actions-runtests.yml +0 -0
  21. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/.gitignore +0 -0
  22. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/INSTALL.md +0 -0
  23. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/LICENSE +0 -0
  24. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/README.md +0 -0
  25. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/AD-taxDef.png +0 -0
  26. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/AD-taxFree.png +0 -0
  27. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/AD-taxable.png +0 -0
  28. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/Hist_Bequest.png +0 -0
  29. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/Hist_Spending.png +0 -0
  30. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/MC-tutorial2a.png +0 -0
  31. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/MC-tutorial2b.png +0 -0
  32. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/OwlUI.png +0 -0
  33. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/allocations.png +0 -0
  34. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/owl.png +0 -0
  35. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/profile.png +0 -0
  36. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/ratesCorrelations.png +0 -0
  37. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/ratesPlot.png +0 -0
  38. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/savingsPlot.png +0 -0
  39. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/sourcesPlot.png +0 -0
  40. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/spendingPlot.png +0 -0
  41. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/taxIncomePlot.png +0 -0
  42. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/images/taxesPlot.png +0 -0
  43. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/owl.pdf +0 -0
  44. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/docs/owl.tex +0 -0
  45. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_jack+jill.toml +0 -0
  46. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_joe.toml +0 -0
  47. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_john+sally.toml +0 -0
  48. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_kim+sam-bequest.toml +0 -0
  49. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/case_kim+sam-spending.toml +0 -0
  50. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/jack+jill.xlsx +0 -0
  51. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/joe.xlsx +0 -0
  52. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/john+sally.xlsx +0 -0
  53. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/examples/template.xlsx +0 -0
  54. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/john+sally.ipynb +0 -0
  55. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/kim+sam.ipynb +0 -0
  56. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/template.ipynb +0 -0
  57. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/tutorial_1.ipynb +0 -0
  58. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/tutorial_2.ipynb +0 -0
  59. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/notebooks/tutorial_3.ipynb +0 -0
  60. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/owlplanner.cmd +0 -0
  61. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/requirements.txt +0 -0
  62. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/__init__.py +0 -0
  63. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/abcapi.py +0 -0
  64. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/config.py +0 -0
  65. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/data/__init__.py +0 -0
  66. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/data/rates.csv +0 -0
  67. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/logging.py +0 -0
  68. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/progress.py +0 -0
  69. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/rates.py +0 -0
  70. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/tax2025.py +0 -0
  71. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/timelists.py +0 -0
  72. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/src/owlplanner/utils.py +0 -0
  73. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_logger.py +0 -0
  74. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_regressions.py +0 -0
  75. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_repro.py +0 -0
  76. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_toml_cases.py +0 -0
  77. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/tests/test_units.py +0 -0
  78. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Asset_Allocation.py +0 -0
  79. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Assets.py +0 -0
  80. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Fixed_Income.py +0 -0
  81. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Historical_Range.py +0 -0
  82. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Logs.py +0 -0
  83. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Monte_Carlo.py +0 -0
  84. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Optimization_Parameters.py +0 -0
  85. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/README.md +0 -0
  86. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Rates_Selection.py +0 -0
  87. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Settings.py +0 -0
  88. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/Wages_And_Contributions.py +0 -0
  89. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/plots.py +0 -0
  90. {owlplanner-2025.2.5 → owlplanner-2025.2.6}/ui/progress.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.2.5
3
+ Version: 2025.2.6
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "owlplanner"
7
- version = "2025.02.05"
7
+ version = "2025.02.06"
8
8
  authors = [
9
9
  { name="Martin-D. Lacasse", email="martin.d.lacasse@gmail.com" },
10
10
  ]
@@ -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] / 2)
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 [github](https://github.com/mdlacasse/owl).
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).
@@ -7,7 +7,7 @@ import owlbridge as owb
7
7
 
8
8
  caseChoices = kz.allCaseNames()
9
9
  ret = kz.titleBar('setup', caseChoices)
10
- kz.caseHeader("Basic Info")
10
+ kz.caseHeader("Create Case")
11
11
 
12
12
  if ret == kz.newCase:
13
13
  st.info('#### Starting a new case from scratch.\n\n'
@@ -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
- #### Basic Info
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 [Case Summary](#case-summary) page and made available to reload at a later time.
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
- If a *Wages and Contributions* file has been uploaded and the `Convert from contributions file`
250
- button is toggled, Roth conversions will not be optimized, but will rather be performed according to
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 at the bottom
302
- of the page.
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
- #### Case Summary
308
- This page shows a synopsis of the scenario which was computed.
309
- It displays informative sums of relevant income, bequest, and spending values.
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
- Parameters used to generate the case are collected in *toml* format and displayed.
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
- Finally, another button called `Download wages and contributions file...` allows
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
- With both these files, the same case can be reproduced at a later time by uploading
320
- them through the widgets on the `Basic Info` and `Wages and Contributions` pages.
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]
@@ -26,7 +26,7 @@ else:
26
26
  on_click=owb.runPlan, disabled=kz.caseIsNotRunReady())
27
27
 
28
28
  st.divider()
29
- if kz.caseHasNotCompletedRun():
29
+ if kz.isCaseUnsolved():
30
30
  st.info("Case status is currently '%s'." % kz.getKey('caseStatus'))
31
31
  else:
32
32
  owb.plotSingleResults()
@@ -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("Case Summary")
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.caseHasNotCompletedRun():
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 recalled at a later time.
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 **Basic Info** page and drag and drop the case parameter file
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 **Basic Info** page,
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
- it can then be saved as a parameter file
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('Basic_Info.py', icon=':material/person_add:'),
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/directions_run:'),
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('Case_Summary.py', icon=':material/description:')],
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
- setInterpolationMethod()
107
- setAllocationRatios()
108
- setRates()
109
- setContributions()
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
- kz.setKey('timeListsFileName', 'edited values')
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()
@@ -7,4 +7,4 @@ scipy
7
7
  streamlit
8
8
  toml
9
9
  # --extra-index-url https://test.pypi.org/simple
10
- owlplanner >= 2025.02.05
10
+ owlplanner >= 2025.02.06
@@ -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