owlplanner 2025.11.3__tar.gz → 2025.11.9__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 (117) hide show
  1. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/INSTALL.md +1 -1
  2. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/PKG-INFO +14 -9
  3. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/README.md +8 -4
  4. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/RELEASE_NOTES.md +11 -1
  5. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/USER_GUIDE.md +1 -1
  6. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docker/README.md +1 -1
  7. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/pyproject.toml +9 -5
  8. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/plan.py +2 -2
  9. owlplanner-2025.11.9/src/owlplanner/version.py +1 -0
  10. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/About_Owl.py +1 -1
  11. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Documentation.py +5 -0
  12. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Monte_Carlo.py +1 -1
  13. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Quick_Start.py +1 -1
  14. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Settings.py +11 -5
  15. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/owlbridge.py +2 -1
  16. owlplanner-2025.11.3/src/owlplanner/version.py +0 -1
  17. owlplanner-2025.11.3/ui/.owlbridge.py.swo +0 -0
  18. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/.devcontainer/devcontainer.json +0 -0
  19. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/.flake8 +0 -0
  20. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/.gitattributes +0 -0
  21. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/.github/workflows/github-actions-runtests.yml +0 -0
  22. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/.gitignore +0 -0
  23. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/.streamlit/config.toml +0 -0
  24. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/.streamlit/fullconfig.toml +0 -0
  25. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/LICENSE +0 -0
  26. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docker/Dockerfile.bare +0 -0
  27. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docker/Dockerfile.static +0 -0
  28. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docker/buildentrypoint.sh +0 -0
  29. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docker/docker-compose.yml +0 -0
  30. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docker/runentrypoint.sh +0 -0
  31. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/AD-taxDef.png +0 -0
  32. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/AD-taxFree.png +0 -0
  33. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/AD-taxable.png +0 -0
  34. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/Hist_Bequest.png +0 -0
  35. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/Hist_Spending.png +0 -0
  36. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/MC-tutorial2a.png +0 -0
  37. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/MC-tutorial2b.png +0 -0
  38. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/OwlUI.png +0 -0
  39. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/allocations.png +0 -0
  40. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/owl.png +0 -0
  41. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/piecewiseConstant.png +0 -0
  42. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/profile.png +0 -0
  43. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/ratesCorrelations.png +0 -0
  44. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/ratesPlot.png +0 -0
  45. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/savingsPlot.png +0 -0
  46. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/sourcesPlot.png +0 -0
  47. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/spendingPlot.png +0 -0
  48. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/taxIncomePlot.png +0 -0
  49. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/images/taxesPlot.png +0 -0
  50. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/owl.pdf +0 -0
  51. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/docs/owl.tex +0 -0
  52. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/case_drawdowncalc-comparison-1.toml +0 -0
  53. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/case_jack+jill.toml +0 -0
  54. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/case_joe.toml +0 -0
  55. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/case_john+sally.toml +0 -0
  56. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/case_jon+jane.toml +0 -0
  57. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/case_kim+sam-bequest.toml +0 -0
  58. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/case_kim+sam-spending.toml +0 -0
  59. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/jack+jill.xlsx +0 -0
  60. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/joe.xlsx +0 -0
  61. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/john+sally.xlsx +0 -0
  62. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/jon+jane.xlsx +0 -0
  63. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/kim+sam.xlsx +0 -0
  64. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/examples/template.xlsx +0 -0
  65. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/notebooks/john+sally.ipynb +0 -0
  66. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/notebooks/kim+sam.ipynb +0 -0
  67. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/notebooks/template.ipynb +0 -0
  68. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/notebooks/tutorial_1.ipynb +0 -0
  69. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/notebooks/tutorial_2.ipynb +0 -0
  70. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/notebooks/tutorial_3.ipynb +0 -0
  71. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/owlplanner.cmd +0 -0
  72. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/owlplanner.sh +0 -0
  73. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/pytest.ini +0 -0
  74. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/requirements.txt +0 -0
  75. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/__init__.py +0 -0
  76. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/abcapi.py +0 -0
  77. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/config.py +0 -0
  78. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/data/__init__.py +0 -0
  79. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/data/rates.csv +0 -0
  80. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/mylogging.py +0 -0
  81. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/plotting/__init__.py +0 -0
  82. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/plotting/base.py +0 -0
  83. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/plotting/factory.py +0 -0
  84. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/plotting/matplotlib_backend.py +0 -0
  85. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/plotting/plotly_backend.py +0 -0
  86. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/progress.py +0 -0
  87. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/rates.py +0 -0
  88. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/tax2025.py +0 -0
  89. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/tax2026.py +0 -0
  90. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/timelists.py +0 -0
  91. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/src/owlplanner/utils.py +0 -0
  92. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_logger.py +0 -0
  93. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_regressions.py +0 -0
  94. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_repro.py +0 -0
  95. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_toml_cases.py +0 -0
  96. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_ui_asset_allocation.py +0 -0
  97. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_ui_compare_summaries.py +0 -0
  98. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_ui_sskeys.py +0 -0
  99. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/tests/test_units.py +0 -0
  100. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Asset_Allocation.py +0 -0
  101. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Create_Case.py +0 -0
  102. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Current_Assets.py +0 -0
  103. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Fixed_Income.py +0 -0
  104. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Graphs.py +0 -0
  105. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Historical_Range.py +0 -0
  106. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Logs.py +0 -0
  107. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Optimization_Parameters.py +0 -0
  108. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Output_Files.py +0 -0
  109. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/README.md +0 -0
  110. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Rates_Selection.py +0 -0
  111. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Wages_and_Contributions.py +0 -0
  112. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/Worksheets.py +0 -0
  113. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/__init__.py +0 -0
  114. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/main.py +0 -0
  115. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/progress.py +0 -0
  116. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/sskeys.py +0 -0
  117. {owlplanner-2025.11.3 → owlplanner-2025.11.9}/ui/tomlexamples.py +0 -0
@@ -1,4 +1,4 @@
1
- # Owl
1
+ # Owl - Optimal Wealth Lab
2
2
 
3
3
  ## A retirement exploration tool based on linear programming
4
4
 
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.11.3
4
- Summary: Owl: Retirement planner with great wisdom
3
+ Version: 2025.11.9
4
+ Summary: Owl - Optimal Wealth Lab: 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
7
7
  Project-URL: Issues, https://github.com/mdlacasse/owl/issues
@@ -684,19 +684,20 @@ License: GNU GENERAL PUBLIC LICENSE
684
684
  Public License instead of this License. But first, please read
685
685
  <https://www.gnu.org/licenses/why-not-lgpl.html>.
686
686
  License-File: LICENSE
687
- Classifier: Development Status :: 4 - Beta
687
+ Classifier: Development Status :: 5 - Production/Stable
688
688
  Classifier: Intended Audience :: End Users/Desktop
689
689
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
690
690
  Classifier: Operating System :: OS Independent
691
691
  Classifier: Programming Language :: Python :: 3
692
692
  Classifier: Topic :: Office/Business :: Financial :: Investment
693
- Requires-Python: >=3.8
693
+ Requires-Python: >=3.10
694
+ Requires-Dist: highspy
694
695
  Requires-Dist: matplotlib
695
696
  Requires-Dist: numpy
696
697
  Requires-Dist: odfpy
697
698
  Requires-Dist: openpyxl
698
699
  Requires-Dist: pandas
699
- Requires-Dist: plotly
700
+ Requires-Dist: plotly>=6.3
700
701
  Requires-Dist: pulp
701
702
  Requires-Dist: scipy
702
703
  Requires-Dist: seaborn
@@ -705,7 +706,7 @@ Requires-Dist: toml
705
706
  Description-Content-Type: text/markdown
706
707
 
707
708
 
708
- # Owl
709
+ # Owl - Optimal Wealth Lab
709
710
 
710
711
  ## A retirement exploration tool based on linear programming
711
712
 
@@ -750,13 +751,17 @@ your strategy under different market assumptions, helping to better understand y
750
751
 
751
752
  -------------------------------------------------------------------------------------
752
753
  ## Purpose and vision
753
- The goal of Owl is to create a free and open-source ecosystem that has cutting-edge optimization capabilities,
754
+ One goal of Owl is to provide a free and open-source ecosystem that has cutting-edge optimization capabilities,
754
755
  allowing for the next generation of Python-literate retirees to experiment with their own financial future
755
- while providing a codebase where they can learn and contribute. There are and were
756
+ while providing a codebase where they can learn and contribute. At the same time, an intuitive and easy-to-use
757
+ user interface based on Streamlit allows a broad set of users to benefit from the application as it only requires basic financial knowledge.
758
+
759
+ There are and were
756
760
  good retirement optimizers in the recent past, but the vast majority of them are either proprietary platforms
757
761
  collecting your data, or academic papers that share the results without really sharing the details of
758
762
  the underlying mathematical models.
759
- The algorithms in Owl rely on the open-source HiGHS linear programming solver. The complete formulation and
763
+ The algorithms in Owl rely on the open-source HiGHS linear programming solver and but they have also been ported to
764
+ other platforms such as Mosek and COIN-OR. The complete formulation and
760
765
  detailed description of the underlying
761
766
  mathematical model can be found [here](https://github.com/mdlacasse/Owl/blob/main/docs/owl.pdf).
762
767
 
@@ -1,5 +1,5 @@
1
1
 
2
- # Owl
2
+ # Owl - Optimal Wealth Lab
3
3
 
4
4
  ## A retirement exploration tool based on linear programming
5
5
 
@@ -44,13 +44,17 @@ your strategy under different market assumptions, helping to better understand y
44
44
 
45
45
  -------------------------------------------------------------------------------------
46
46
  ## Purpose and vision
47
- The goal of Owl is to create a free and open-source ecosystem that has cutting-edge optimization capabilities,
47
+ One goal of Owl is to provide a free and open-source ecosystem that has cutting-edge optimization capabilities,
48
48
  allowing for the next generation of Python-literate retirees to experiment with their own financial future
49
- while providing a codebase where they can learn and contribute. There are and were
49
+ while providing a codebase where they can learn and contribute. At the same time, an intuitive and easy-to-use
50
+ user interface based on Streamlit allows a broad set of users to benefit from the application as it only requires basic financial knowledge.
51
+
52
+ There are and were
50
53
  good retirement optimizers in the recent past, but the vast majority of them are either proprietary platforms
51
54
  collecting your data, or academic papers that share the results without really sharing the details of
52
55
  the underlying mathematical models.
53
- The algorithms in Owl rely on the open-source HiGHS linear programming solver. The complete formulation and
56
+ The algorithms in Owl rely on the open-source HiGHS linear programming solver and but they have also been ported to
57
+ other platforms such as Mosek and COIN-OR. The complete formulation and
54
58
  detailed description of the underlying
55
59
  mathematical model can be found [here](https://github.com/mdlacasse/Owl/blob/main/docs/owl.pdf).
56
60
 
@@ -1,5 +1,15 @@
1
- ### Version 2025.07.01
1
+ ### Version 2025.11.09
2
+ - Moved development status to production/stable in pyproject
3
+ - Made version propagate everywhere needed
4
+ - Added node limit on milp to avoid Streamlit server shutdown on memory consumption
5
+
6
+ ### Version 2025.11.05
7
+ - Mentioning Owl as Optimal Wealth Lab
8
+ - Port to Streamlit 1.50 which broke many widgets
9
+ - Rework backprojection of assets to beginning of the year
10
+ - Rework Docker to smaller Alpine image and fix docs
2
11
 
12
+ ### Version 2025.07.01
3
13
  Added:
4
14
  - Settings option for menu position thanks to Streamlit 1.46 top and sidebar capabilities. Default is top.
5
15
  - Net Investment Income Tax calculations in self-consistent loop.
@@ -1,4 +1,4 @@
1
- # Owl
1
+ # Owl - Optimal Wealth Lab
2
2
 
3
3
  ## A retirement exploration tool based on linear programming
4
4
 
@@ -1,4 +1,4 @@
1
- # Owl
1
+ # Owl - Optimal Wealth Lab
2
2
 
3
3
  ## A retirement exploration tool based on linear programming
4
4
 
@@ -2,20 +2,23 @@
2
2
  requires = ["hatchling"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
+ [tool.hatch.version]
6
+ path = "src/owlplanner/version.py"
7
+
5
8
  [project]
6
9
  name = "owlplanner"
7
- version = "2025.11.03"
10
+ dynamic = ["version"]
8
11
  authors = [
9
12
  { name="Martin-D. Lacasse", email="martin.d.lacasse@gmail.com" },
10
13
  ]
11
14
  maintainers = [
12
15
  { name="Martin-D. Lacasse", email="martin.d.lacasse@gmail.com" },
13
16
  ]
14
- description = "Owl: Retirement planner with great wisdom"
17
+ description = "Owl - Optimal Wealth Lab: Retirement planner with great wisdom"
15
18
  readme = "README.md"
16
- requires-python = ">=3.8"
19
+ requires-python = ">=3.10"
17
20
  classifiers = [
18
- "Development Status :: 4 - Beta",
21
+ "Development Status :: 5 - Production/Stable",
19
22
  "Programming Language :: Python :: 3",
20
23
  "Intended Audience :: End Users/Desktop",
21
24
  "Topic :: Office/Business :: Financial :: Investment",
@@ -24,12 +27,13 @@ classifiers = [
24
27
  "Programming Language :: Python :: 3",
25
28
  ]
26
29
  dependencies = [
30
+ "highspy",
27
31
  "matplotlib",
28
32
  "numpy",
29
33
  "odfpy",
30
34
  "openpyxl",
31
35
  "pandas",
32
- "plotly",
36
+ "plotly>=6.3",
33
37
  "pulp",
34
38
  "seaborn",
35
39
  "scipy",
@@ -1669,7 +1669,7 @@ class Plan(object):
1669
1669
  self.prevMAGI = np.zeros(2)
1670
1670
  if "previousMAGIs" in myoptions:
1671
1671
  magi = myoptions["previousMAGIs"]
1672
- if 3 < len(magi) < 2:
1672
+ if len(magi) != 2:
1673
1673
  raise ValueError("previousMAGIs must have 2 values.")
1674
1674
 
1675
1675
  self.prevMAGI = self.optionsUnits * np.array(magi)
@@ -1786,7 +1786,7 @@ class Plan(object):
1786
1786
  "disp": False,
1787
1787
  "mip_rel_gap": 1e-7,
1788
1788
  "presolve": True,
1789
- # "node_limit": 10000 # Limit search nodes for faster solutions
1789
+ "node_limit": 1000000 # Limit search nodes for faster solutions
1790
1790
  }
1791
1791
 
1792
1792
  self._buildConstraints(objective, options)
@@ -0,0 +1 @@
1
+ __version__ = "2025.11.09"
@@ -4,7 +4,7 @@ import sskeys as kz
4
4
  import owlbridge as owb
5
5
 
6
6
 
7
- st.write("# :material/info: About Owl 🦉")
7
+ st.write("# :material/info: About Owl - Optimal Wealth Lab🦉")
8
8
  kz.divider("orange")
9
9
 
10
10
  st.write(f"This is Owl version {owb.version()} running on Streamlit {st.__version__}.")
@@ -14,11 +14,16 @@ with col3:
14
14
  col1, col2 = st.columns([0.80, 0.20], gap="large")
15
15
  with col1:
16
16
  st.markdown("""
17
+ ### Owl - Optimal Wealth Lab
17
18
  #### A retirement financial exploration tool based on linear programming
18
19
 
19
20
  The goal of Owl is to provide a free and open-source ecosystem that has cutting-edge
20
21
  optimization capabilities, allowing for the new generation of computer-literate retirees
21
22
  to experiment with their own financial future while providing a codebase where they can learn and contribute.
23
+ At the same time, Streamlit provides an intuitive and easy-to-use
24
+ interface which allows a broad set of users to benefit from the application
25
+ as it only requires basic financial knowledge.
26
+
22
27
  Strictly speaking, Owl is not a planning tool, but more an environment for exploring *what if* scenarios.
23
28
  It provides different realizations of a financial strategy through the rigorous
24
29
  mathematical optimization of relevant decision variables. Using a linear programming approach,
@@ -17,7 +17,7 @@ else:
17
17
  st.write("Generate a histogram of results obtained from running mutliple scenarios with stochastic rates.")
18
18
  col1, col2, col3, col4 = st.columns(4, gap="large", vertical_alignment="bottom")
19
19
  with col1:
20
- kz.initKey("MC_cases", 100)
20
+ kz.initCaseKey("MC_cases", 100)
21
21
  kz.getIntNum("Number of random instances", "MC_cases", step=10, max_value=10000)
22
22
  with col4:
23
23
  st.button("Run Simulation", on_click=owb.runMC, disabled=kz.caseIsNotMCReady())
@@ -7,7 +7,7 @@ with col3:
7
7
  st.image("http://github.com/mdlacasse/Owl/blob/main/docs/images/owl.png?raw=true")
8
8
  st.caption("Retirement planner with great wisdom")
9
9
  with col1:
10
- st.write("# :orange[Owl Retirement Planner]\nA retirement financial exploration tool based on linear programming")
10
+ st.write("# :orange[Owl - Optimal Wealth Lab]\nA retirement financial exploration tool based on linear programming")
11
11
  kz.divider("orange")
12
12
  st.write("### :material/campaign: News")
13
13
  st.markdown("""
@@ -4,6 +4,12 @@ import sskeys as kz
4
4
  import owlbridge as owb
5
5
 
6
6
 
7
+ def setKey(key):
8
+ val = kz.getGlobalKey("_"+key)
9
+ if val is not None:
10
+ kz.storeGlobalKey(key, val)
11
+
12
+
7
13
  st.write("# :material/settings: Settings")
8
14
  kz.divider("orange")
9
15
 
@@ -17,7 +23,7 @@ with col1:
17
23
  helpmsg = "Select the plotting library to use."
18
24
  index = choices.index(kz.getGlobalKey(gkey))
19
25
  ret = st.radio("Plotting backend", options=choices, index=index, args=[gkey],
20
- key=gkey, on_change=owb.setGlobalPlotBackend, help=helpmsg, horizontal=True)
26
+ key="_"+gkey, on_change=owb.setGlobalPlotBackend, help=helpmsg, horizontal=True)
21
27
 
22
28
  with col2:
23
29
  choices = ("sidebar", "top")
@@ -26,8 +32,8 @@ with col2:
26
32
  st.write("#### :orange[Menu]")
27
33
  helpmsg = "Select menu appearance."
28
34
  index = choices.index(kz.getGlobalKey(mkey))
29
- ret = st.radio("Menu location", options=choices, index=index,
30
- key=mkey, help=helpmsg, horizontal=True)
35
+ ret = st.radio("Menu location", options=choices, index=index, args=[mkey],
36
+ key="_"+mkey, on_change=setKey, help=helpmsg, horizontal=True)
31
37
 
32
38
  with col3:
33
39
  choices = ("sticky", "static")
@@ -36,8 +42,8 @@ with col3:
36
42
  st.write("#### :orange[Header]")
37
43
  helpmsg = "Select header behavior."
38
44
  index = choices.index(kz.getGlobalKey(pkey))
39
- ret = st.radio("Header behavior", options=choices, index=index,
40
- key=pkey, help=helpmsg, horizontal=True)
45
+ ret = st.radio("Header behavior", options=choices, index=index, args=[pkey],
46
+ key="_"+pkey, on_change=setKey, help=helpmsg, horizontal=True)
41
47
 
42
48
  st.divider()
43
49
  st.write("""
@@ -511,7 +511,8 @@ def setDefaultPlots(plan, key):
511
511
 
512
512
 
513
513
  def setGlobalPlotBackend(key):
514
- val = kz.getGlobalKey(key)
514
+ val = kz.getGlobalKey("_"+key)
515
+ kz.storeGlobalKey(key, val)
515
516
  # Apply to all existing cases.
516
517
  for casename in kz.onlyCaseNames():
517
518
  plan = kz.getKeyInCase("plan", casename)
@@ -1 +0,0 @@
1
- __version__ = "2025.11.03"
Binary file
File without changes
File without changes