owlplanner 2025.2.10__py3-none-any.whl → 2025.2.14__py3-none-any.whl
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/plan.py +7 -7
- owlplanner/version.py +1 -1
- {owlplanner-2025.2.10.dist-info → owlplanner-2025.2.14.dist-info}/METADATA +32 -226
- {owlplanner-2025.2.10.dist-info → owlplanner-2025.2.14.dist-info}/RECORD +6 -6
- {owlplanner-2025.2.10.dist-info → owlplanner-2025.2.14.dist-info}/WHEEL +0 -0
- {owlplanner-2025.2.10.dist-info → owlplanner-2025.2.14.dist-info}/licenses/LICENSE +0 -0
owlplanner/plan.py
CHANGED
|
@@ -463,7 +463,8 @@ class Plan(object):
|
|
|
463
463
|
assert 0 <= phi[j] <= 1, "Fractions must be between 0 and 1."
|
|
464
464
|
|
|
465
465
|
self.phi_j = np.array(phi, dtype=np.float32)
|
|
466
|
-
self.mylog.vprint(
|
|
466
|
+
self.mylog.vprint("Spousal beneficiary fractions set to",
|
|
467
|
+
["{:.2f}".format(self.phi_j[j]) for j in range(self.N_j)])
|
|
467
468
|
self.caseStatus = "modified"
|
|
468
469
|
|
|
469
470
|
if np.any(self.phi_j != 1):
|
|
@@ -493,7 +494,8 @@ class Plan(object):
|
|
|
493
494
|
fac = u.getUnits(units)
|
|
494
495
|
amounts = u.rescale(amounts, fac)
|
|
495
496
|
|
|
496
|
-
self.mylog.vprint("Setting pension of", [u.d(amounts[i]) for i in range(self.N_i)],
|
|
497
|
+
self.mylog.vprint("Setting pension of", [u.d(amounts[i]) for i in range(self.N_i)],
|
|
498
|
+
"at age(s)", [int(ages[i]) for i in range(self.N_i)])
|
|
497
499
|
|
|
498
500
|
thisyear = date.today().year
|
|
499
501
|
# Use zero array freshly initialized.
|
|
@@ -525,10 +527,8 @@ class Plan(object):
|
|
|
525
527
|
amounts = u.rescale(amounts, fac)
|
|
526
528
|
|
|
527
529
|
self.mylog.vprint(
|
|
528
|
-
"Setting social security benefits of",
|
|
529
|
-
[
|
|
530
|
-
"at age(s)",
|
|
531
|
-
ages,
|
|
530
|
+
"Setting social security benefits of", [u.d(amounts[i]) for i in range(self.N_i)],
|
|
531
|
+
"at age(s)", [int(ages[i]) for i in range(self.N_i)],
|
|
532
532
|
)
|
|
533
533
|
|
|
534
534
|
thisyear = date.today().year
|
|
@@ -2262,7 +2262,7 @@ class Plan(object):
|
|
|
2262
2262
|
# style = {'net': '-', 'target': ':'}
|
|
2263
2263
|
style = {"profile": "-"}
|
|
2264
2264
|
series = {"profile": self.xi_n}
|
|
2265
|
-
fig, ax = _lineIncomePlot(self.year_n, series, style, title, yformat="xi")
|
|
2265
|
+
fig, ax = _lineIncomePlot(self.year_n, series, style, title, yformat="$\\xi$")
|
|
2266
2266
|
|
|
2267
2267
|
if figure:
|
|
2268
2268
|
return fig
|
owlplanner/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2025.02.
|
|
1
|
+
__version__ = "2025.02.14"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: owlplanner
|
|
3
|
-
Version: 2025.2.
|
|
3
|
+
Version: 2025.2.14
|
|
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
|
|
@@ -710,10 +710,16 @@ Description-Content-Type: text/markdown
|
|
|
710
710
|
|
|
711
711
|
-----
|
|
712
712
|
|
|
713
|
-
###
|
|
714
|
-
Owl is a planning tool that uses a linear programming optimization algorithm to provide guidance on retirement decisions.
|
|
713
|
+
### TL;DR
|
|
714
|
+
Owl is a planning tool that uses a linear programming optimization algorithm to provide guidance on retirement decisions. There are a few ways to run Owl.
|
|
715
715
|
|
|
716
|
-
|
|
716
|
+
- Run Owl directly on the Streamlit Community Server at [owlplanner.streamlit.app](https://owlplanner.streamlit.app).
|
|
717
|
+
|
|
718
|
+
- Run locally on your computer using a Docker image.
|
|
719
|
+
Follow these [instructions](docker/README.md) for this option.
|
|
720
|
+
|
|
721
|
+
- Run locally on your computer using Python code and libraries.
|
|
722
|
+
Follow there [instructions](INSTALL.md) to install Owl from the source code and run it on your computer.
|
|
717
723
|
|
|
718
724
|
-----
|
|
719
725
|
|
|
@@ -750,21 +756,21 @@ The algorithms in Owl rely on the open-source HiGHS linear programming solver. T
|
|
|
750
756
|
detailed description of the underlying
|
|
751
757
|
mathematical model can be found [here](https://raw.github.com/mdlacasse/Owl/main/docs/owl.pdf).
|
|
752
758
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
759
|
+
It is anticipated that most end users will use Owl through the graphical interface
|
|
760
|
+
either at [owlplanner.streamlit.app](https://owlplanner.streamlit.app)
|
|
761
|
+
or [installed](INSTALL.md) on their own computer.
|
|
762
|
+
The underlying Python package can also be used directly through Python scripts or a Jupyter Notebook
|
|
763
|
+
as described [here](USER_GUIDE.md).
|
|
758
764
|
|
|
759
765
|
Not every retirement decision strategy can be framed as an easy-to-solve optimization problem.
|
|
760
766
|
In particular, if one is interested in comparing different withdrawal strategies,
|
|
761
|
-
[FI Calc](ficalc.app) is
|
|
767
|
+
[FI Calc](ficalc.app) is an elegant application that addresses this need.
|
|
762
768
|
If, however, you also want to optimize spending, bequest, and Roth conversions, with
|
|
763
769
|
an approach also considering Medicare and federal income tax over the next few years,
|
|
764
770
|
then Owl is definitely a tool that can help guide your decisions.
|
|
765
771
|
|
|
766
772
|
--------------------------------------------------------------------------------------
|
|
767
|
-
##
|
|
773
|
+
## Capabilities
|
|
768
774
|
Owl can optimize for either maximum net spending under the constraint of a given bequest (which can be zero),
|
|
769
775
|
or maximize the after-tax value of a bequest under the constraint of a desired net spending profile,
|
|
770
776
|
and under the assumption of a heirs marginal tax rate.
|
|
@@ -805,16 +811,19 @@ bequest under the constraint of a desired net spending amount. Unlike discrete-e
|
|
|
805
811
|
simulators, Owl uses an optimization algorithm for every new scenario, which results in more
|
|
806
812
|
calculations being performed. As a result, the number of cases to be considered should be kept
|
|
807
813
|
to a reasonable number. For a few hundred cases, a few minutes of calculations can provide very good estimates
|
|
808
|
-
and reliable probability distributions.
|
|
809
|
-
|
|
810
|
-
|
|
814
|
+
and reliable probability distributions.
|
|
815
|
+
Optimizing each solution is more representative in the sense that optimal solutions
|
|
816
|
+
will naturally adjust to the return scenarios being considered.
|
|
817
|
+
This is more realistic as retirees would certainly re-evaluate
|
|
818
|
+
their expectations under severe market drops or gains.
|
|
819
|
+
This optimal approach provides a net benefit over event-based simulations,
|
|
811
820
|
which maintain a distribution strategy either fixed, or within guardrails for capturing the
|
|
812
821
|
retirees' reactions to the market.
|
|
813
822
|
|
|
814
823
|
Basic input parameters are given through function calls while optional additional time series can be read from
|
|
815
824
|
an Excel spreadsheet that contains future wages, contributions
|
|
816
|
-
to savings accounts, and planned *big-ticket items* such as the purchase of a lake house,
|
|
817
|
-
large gifts, or inheritance.
|
|
825
|
+
to savings accounts, and planned *big-ticket items* such as the purchase of a lake house,
|
|
826
|
+
the sale of a boat, large gifts, or inheritance.
|
|
818
827
|
|
|
819
828
|
Three types of savings accounts are considered: taxable, tax-deferred, and tax-exempt,
|
|
820
829
|
which are all tracked separately for married individuals. Asset transition to the surviving spouse
|
|
@@ -824,13 +833,12 @@ Tax status covers married filing jointly and single, depending on the number of
|
|
|
824
833
|
Medicare and IRMAA calculations are performed through a self-consistent loop on cash flow constraints. Future
|
|
825
834
|
values are simple projections of current values with the assumed inflation rates.
|
|
826
835
|
|
|
827
|
-
See one of the notebooks for a tutorial and representative user cases.
|
|
828
|
-
|
|
829
836
|
### Limitations
|
|
830
837
|
Owl is work in progress. At the current time:
|
|
831
838
|
- Only the US federal income tax is considered (and minimized through the optimization algorithm).
|
|
832
839
|
Head of household filing status has not been added but can easily be.
|
|
833
|
-
- Required minimum distributions are calculated, but tables for spouses more than 10 years apart are not included.
|
|
840
|
+
- Required minimum distributions are calculated, but tables for spouses more than 10 years apart are not included.
|
|
841
|
+
An error message will be generated for these cases.
|
|
834
842
|
- Social security rule for surviving spouse assumes that benefits were taken at full retirement age.
|
|
835
843
|
- Current version has no optimization of asset allocations between individuals and/or types of savings accounts.
|
|
836
844
|
If there is interest, that could be added in the future.
|
|
@@ -854,215 +862,12 @@ estate value too large for the savings assets to support, even with zero net spe
|
|
|
854
862
|
or maximizing the bequest subject to a net spending basis that is already too large for the savings
|
|
855
863
|
assets to support, even with no estate being left.
|
|
856
864
|
|
|
857
|
-
-----------------------------------------------------------------------
|
|
858
|
-
## An example of Owl's functionality
|
|
859
|
-
With about 10 lines of Python code, one can generate a full case study.
|
|
860
|
-
Here is a typical plan with some comments.
|
|
861
|
-
A plan starts with the names of the individuals, their birth years and life expectancies, and a name for the plan.
|
|
862
|
-
Dollar amounts are in k\$ (i.e. thousands) and ratios in percentage.
|
|
863
|
-
```python
|
|
864
|
-
import owlplanner as owl
|
|
865
|
-
# Jack was born in 1962 and expects to live to age 89. Jill was born in 1965 and hopes to live to age 92.
|
|
866
|
-
# Plan starts on Jan 1st of this year.
|
|
867
|
-
plan = owl.Plan(['Jack', 'Jill'], [1962, 1965], [89, 92], 'jack & jill - tutorial', startDate='01-01')
|
|
868
|
-
# Jack has $90.5k in a taxable investment account, $600.5k in a tax-deferred account and $70k from 2 tax-exempt accounts.
|
|
869
|
-
# Jill has $60.2k in her taxable account, $150k in a 403b, and $40k in a Roth IRA.
|
|
870
|
-
plan.setAccountBalances(taxable=[90.5, 60.2], taxDeferred=[600.5, 150], taxFree=[50.6 + 20, 40.8])
|
|
871
|
-
# An Excel file contains 2 tabs (one for Jill, one for Jack) describing anticipated wages and contributions.
|
|
872
|
-
plan.readContributions('jack+jill.xlsx')
|
|
873
|
-
# Jack will glide an s-curve for asset allocations from a 60/40 -> 70/30 stocks/bonds portfolio.
|
|
874
|
-
# Jill will do the same thing but is a bit more conservative from 50/50 -> 70/30 stocks/bonds portfolio.
|
|
875
|
-
plan.setInterpolationMethod('s-curve')
|
|
876
|
-
plan.setAllocationRatios('individual', generic=[[[60, 40, 0, 0], [70, 30, 0, 0]], [[50, 50, 0, 0], [70, 30, 0, 0]]])
|
|
877
|
-
# Jack has no pension, but Jill will receive $10k per year at 65 yo.
|
|
878
|
-
plan.setPension([0, 10.5], [65, 65])
|
|
879
|
-
# Jack anticipates receiving social security of $28.4k at age 70, and Jill $19.7k at age 62. All values are in today's $.
|
|
880
|
-
plan.setSocialSecurity([28.4, 19.7], [70, 62])
|
|
881
|
-
# Instead of a 'flat' profile, we select a 'smile' spending profile, with 60% needs for the survivor.
|
|
882
|
-
plan.setSpendingProfile('smile', 60)
|
|
883
|
-
# We will reproduce the historical sequence of returns starting in year 1969.
|
|
884
|
-
plan.setRates('historical', 1969)
|
|
885
|
-
# Jack and Jill want to leave a bequest of $500k, and limit Roth conversions to $100k per year.
|
|
886
|
-
# Jill's 403b plan does not support in-plan Roth conversions.
|
|
887
|
-
# We solve for the maximum net spending profile under these constraints.
|
|
888
|
-
plan.solve('maxSpending', options={'maxRothConversion': 100, 'bequest': 500, 'noRothConversions': 'Jill'})
|
|
889
|
-
```
|
|
890
|
-
The output can be seen using the following commands that display various plots of the decision variables in time.
|
|
891
|
-
```python
|
|
892
|
-
plan.showNetSpending()
|
|
893
|
-
plan.showGrossIncome()
|
|
894
|
-
plan.showTaxes()
|
|
895
|
-
plan.showSources()
|
|
896
|
-
plan.showAccounts()
|
|
897
|
-
plan.showAssetDistribution()
|
|
898
|
-
...
|
|
899
|
-
```
|
|
900
|
-
By default, all these plots are in nominal dollars. To get values in today's $, a call to
|
|
901
|
-
```python
|
|
902
|
-
plan.setDefaultPlots('today')
|
|
903
|
-
```
|
|
904
|
-
would change all graphs to report in today's dollars. Each plot can also override the default by setting the `value`
|
|
905
|
-
parameters to either *nominal* or *today*, such as in the following example, which shows the taxable ordinary
|
|
906
|
-
income over the duration of the plan,
|
|
907
|
-
along with inflation-adjusted extrapolated tax brackets. Notice how the optimized income is surfing
|
|
908
|
-
the boundaries of tax brackets.
|
|
909
|
-
```python
|
|
910
|
-
plan.showGrossIncome(value='nominal')
|
|
911
|
-
```
|
|
912
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/taxIncomePlot.png" width="75%">
|
|
913
|
-
|
|
914
|
-
The optimal spending profile is shown in the next plot (in today's dollars). Notice the drop
|
|
915
|
-
(recall we selected 60% survivor needs) at the passing of the first spouse.
|
|
916
|
-
```python
|
|
917
|
-
plan.showProfile('today')
|
|
918
|
-
```
|
|
919
|
-
|
|
920
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/spendingPlot.png" width="75%">
|
|
921
|
-
|
|
922
|
-
The following plot shows the account balances in nominal value for all savings accounts owned by Jack and Jill.
|
|
923
|
-
It was generated using
|
|
924
|
-
```python
|
|
925
|
-
plan.showAccounts(value='nominal')
|
|
926
|
-
```
|
|
927
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/savingsPlot.png" width="75%">
|
|
928
|
-
|
|
929
|
-
while this plot shows the complex cash flow from all sources, which was generated with
|
|
930
|
-
```python
|
|
931
|
-
plan.showSources(value='nominal')
|
|
932
|
-
```
|
|
933
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/sourcesPlot.png" width="75%">
|
|
934
|
-
|
|
935
|
-
For taxes, the following call will display Medicare premiums (including Part B IRMAA fees) and federal income tax
|
|
936
|
-
```python
|
|
937
|
-
plan.showTaxes(value='nominal')
|
|
938
|
-
```
|
|
939
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/taxesPlot.png" width="75%">
|
|
940
|
-
|
|
941
|
-
For the case at hand, recall that asset allocations were selected above through
|
|
942
|
-
|
|
943
|
-
```python
|
|
944
|
-
plan.setAllocationRatios('individual', generic=[[[60, 40, 0, 0], [70, 30, 0, 0]], [[50, 50, 0, 0], [70, 30, 0, 0]]])
|
|
945
|
-
```
|
|
946
|
-
gliding from a 60%/40% stocks/bonds portfolio to 70%/30% for Jack, and 50%/50% -> 70%/30% for Jill.
|
|
947
|
-
Assets distribution in all accounts in today's $ over time can be displayed from
|
|
948
|
-
```python
|
|
949
|
-
plan.showAssetDistribution(value='today')
|
|
950
|
-
```
|
|
951
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/AD-taxable.png" width="75%">
|
|
952
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/AD-taxDef.png" width="75%">
|
|
953
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/AD-taxFree.png" width="75%">
|
|
954
|
-
|
|
955
|
-
These plots are irregular because we used historical rates from 1969. The volatility of
|
|
956
|
-
the rates offers Roth conversion benefits which are exploited by the optimizer.
|
|
957
|
-
The rates used can be displayed by:
|
|
958
|
-
```python
|
|
959
|
-
plan.showRates()
|
|
960
|
-
```
|
|
961
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/ratesPlot.png" width="75%">
|
|
962
|
-
|
|
963
|
-
Values between brackets <> are the average values and volatility over the selected period.
|
|
964
|
-
|
|
965
|
-
For the statisticians, rates distributions and correlations between them can be shown using:
|
|
966
|
-
```python
|
|
967
|
-
plan.showRatesCorrelations()
|
|
968
|
-
```
|
|
969
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/ratesCorrelations.png" width="75%">
|
|
970
|
-
|
|
971
|
-
A short text summary of the outcome of the optimization can be displayed through using:
|
|
972
|
-
```python
|
|
973
|
-
plan.summary()
|
|
974
|
-
```
|
|
975
|
-
The output of the last command reports that if future rates are exactly like those observed
|
|
976
|
-
starting from 1969 and the following years, Jack and Jill could afford an annual spending of
|
|
977
|
-
\\$97k starting this year
|
|
978
|
-
(with a basis of \\$88.8k - the basis multiplies the profile which can vary over the course of the plan).
|
|
979
|
-
The summary also contains some details:
|
|
980
|
-
```
|
|
981
|
-
SUMMARY ================================================================
|
|
982
|
-
Net yearly spending basis in 2025$: $91,812
|
|
983
|
-
Net yearly spending for year 2025: $100,448
|
|
984
|
-
Net spending remaining in year 2025: $100,448
|
|
985
|
-
Total net spending in 2025$: $2,809,453 ($7,757,092 nominal)
|
|
986
|
-
Total Roth conversions in 2025$: $320,639 ($456,454 nominal)
|
|
987
|
-
Total income tax paid on ordinary income in 2025$: $247,788 ($469,522 nominal)
|
|
988
|
-
Total tax paid on gains and dividends in 2025$: $3,313 ($3,768 nominal)
|
|
989
|
-
Total Medicare premiums paid in 2025$: $117,660 ($343,388 nominal)
|
|
990
|
-
Spousal wealth transfer from Jack to Jill in year 2051 (nominal): taxable: $0 tax-def: $57,224 tax-free: $2,102,173
|
|
991
|
-
Sum of spousal bequests to Jill in year 2051 in 2025$: $499,341 ($2,159,397 nominal)
|
|
992
|
-
Post-tax non-spousal bequests from Jack in year 2051 (nominal): taxable: $0 tax-def: $0 tax-free: $0
|
|
993
|
-
Sum of post-tax non-spousal bequests from Jack in year 2051 in 2025$: $0 ($0 nominal)
|
|
994
|
-
Post-tax account values at the end of final plan year 2057 (nominal): taxable: $0 tax-def: $0 tax-free: $2,488,808
|
|
995
|
-
Total estate value at the end of final plan year 2057 in 2025$: $500,000 ($2,488,808 nominal)
|
|
996
|
-
Plan starting date: 01-01
|
|
997
|
-
Cumulative inflation factor from start date to end of plan: 4.98
|
|
998
|
-
Jack's 27-year life horizon: 2025 -> 2051
|
|
999
|
-
Jill's 33-year life horizon: 2025 -> 2057
|
|
1000
|
-
Plan name: jack & jill - tutorial
|
|
1001
|
-
Number of decision variables: 996
|
|
1002
|
-
Number of constraints: 867
|
|
1003
|
-
Case executed on: 2025-02-04 at 22:55:03
|
|
1004
|
-
------------------------------------------------------------------------
|
|
1005
|
-
```
|
|
1006
|
-
And an Excel workbook can be saved with all the detailed amounts over the years by using the following command:
|
|
1007
|
-
```python
|
|
1008
|
-
plan.saveWorkbook(overwrite=True)
|
|
1009
|
-
```
|
|
1010
|
-
For Monte Carlo simulations, the mean return rates, their volatility and covariance are specified
|
|
1011
|
-
and used to generate random scenarios. A histogram of outcomes is generated such as this one for Jack and Jill, which was generated
|
|
1012
|
-
by selecting *stochastic* rates and using
|
|
1013
|
-
```
|
|
1014
|
-
plan.runMC('maxSpending', ...)
|
|
1015
|
-
```
|
|
1016
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/MC-tutorial2a.png" width="75%">
|
|
1017
|
-
|
|
1018
|
-
Similarly, the next one was generated using
|
|
1019
|
-
```
|
|
1020
|
-
plan.runMC('maxBequest', ...)
|
|
1021
|
-
```
|
|
1022
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/MC-tutorial2b.png" width="75%">
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
See tutorial notebooks [1](https://github.com/mdlacasse/Owl/blob/main/notebooks/tutorial_1.ipynb),
|
|
1026
|
-
[2](https://github.com/mdlacasse/Owl/blob/main/notebooks/tutorial_2.ipynb), and
|
|
1027
|
-
[3](https://github.com/mdlacasse/Owl/blob/main/notebooks/tutorial_3.ipynb) for more info.
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
865
|
---------------------------------------------------------------
|
|
1031
|
-
##
|
|
1032
|
-
|
|
1033
|
-
If you have Python already installed on your computer, Owl can be installed as a package using the following commands:
|
|
1034
|
-
```shell
|
|
1035
|
-
python -m build
|
|
1036
|
-
pip install .
|
|
1037
|
-
```
|
|
1038
|
-
These commands need to run from the Owl directory where you downloaded Owl from GitHub either through git or a zip file.
|
|
1039
|
-
Pip will install all the required dependencies.
|
|
1040
|
-
|
|
1041
|
-
Owl relies on common Python modules such as NumPy, Pandas, SciPy, matplotlib, and Seaborn.
|
|
1042
|
-
The user front-end was built on Streamlit.
|
|
1043
|
-
Package `odfpy` might be required if one read files created by LibreOffice. Again, these dependencies
|
|
1044
|
-
will be installed by pip.
|
|
1045
|
-
|
|
1046
|
-
The simplest way to get started with Owl is to use the `streamlit` browser-based user interface
|
|
1047
|
-
that is started by the `owlplanner.cmd` script, which will start a user interface on your own browser.
|
|
1048
|
-
Here is a screenshot of one of the multiple tabs of the interface:
|
|
1049
|
-
|
|
1050
|
-
<img src="https://raw.github.com/mdlacasse/Owl/main/docs/images/OwlUI.png" width="100%">
|
|
1051
|
-
|
|
1052
|
-
Alternatively, one can prefer using Owl from Jupyter notebooks. For that purpose, the `examples` directory
|
|
1053
|
-
contains many files as a tutorial. The Jupyter Notebook interface is a browser-based application for authoring documents that combines live-code with narrative text, equations and visualizations.
|
|
1054
|
-
Jupyter will run in your default web browser, from your computer to your browser, and therefore no data is ever transferred on the Internet
|
|
1055
|
-
(your computer, i.e., `localhost`, is the server).
|
|
1056
|
-
|
|
1057
|
-
For simulating your own realizations, use the files beginning with the word *template*.
|
|
1058
|
-
Make a copy and rename them with your own names while keeping the same extension.
|
|
1059
|
-
Then you'll be able to personalize a case with your own numbers and start experimenting with Owl.
|
|
1060
|
-
Notebooks with detailed explanations can be found in
|
|
1061
|
-
[tutorial_1](https://github.com/mdlacasse/Owl/blob/main/examples/tutorial_1.ipynb),
|
|
1062
|
-
[tutorial_2](https://github.com/mdlacasse/Owl/blob/main/examples/tutorial_1.ipynb), and
|
|
1063
|
-
[tutorial_3](https://github.com/mdlacasse/Owl/blob/main/examples/tutorial_2.ipynb).
|
|
866
|
+
## Documentation
|
|
1064
867
|
|
|
1065
|
-
|
|
868
|
+
- Documentation for the app user interface is available from the interface itself.
|
|
869
|
+
- Installation guide and software requirements can be found [here](INSTALL.md).
|
|
870
|
+
- User guide for the underlying library to be used in a Jupyter notebook can be found [here](USER_GUIDE.md).
|
|
1066
871
|
|
|
1067
872
|
---------------------------------------------------------------------
|
|
1068
873
|
|
|
@@ -1071,6 +876,7 @@ Finally, you will also need the capability to read and edit Excel files. One can
|
|
|
1071
876
|
- Image from [freepik](https://freepik.com)
|
|
1072
877
|
- Optimization solver from [HiGHS](https://highs.dev)
|
|
1073
878
|
- Streamlit Community Cloud [Streamlit](https://streamlit.io)
|
|
879
|
+
- Other contributors: Josh (noimjosh@gmail.com) for Docker image code
|
|
1074
880
|
|
|
1075
881
|
---------------------------------------------------------------------
|
|
1076
882
|
|
|
@@ -2,16 +2,16 @@ owlplanner/__init__.py,sha256=QqrdT0Qks20osBTg7h0vJHAxpP9lL7DA99xb0nYbtw4,254
|
|
|
2
2
|
owlplanner/abcapi.py,sha256=LbzW_KcNy0IeHp42MUHwGu_H67B2h_e1_vu-c2ACTkQ,6646
|
|
3
3
|
owlplanner/config.py,sha256=XFVcXFVpEuWXzybaijNGSTt72py3cYJ3oq0S1ujivl0,11702
|
|
4
4
|
owlplanner/logging.py,sha256=tYMw04O-XYSzjTj36fmKJGLcE1VkK6k6oJNeqtKXzuc,2530
|
|
5
|
-
owlplanner/plan.py,sha256=
|
|
5
|
+
owlplanner/plan.py,sha256=sgQi0TD24Rmk_96M9AnJ72zKKmol0AKoM6CybAAQG1w,113088
|
|
6
6
|
owlplanner/progress.py,sha256=8jlCvvtgDI89zXVNMBg1-lnEyhpPvKQS2X5oAIpoOVQ,384
|
|
7
7
|
owlplanner/rates.py,sha256=TN407qU4n-bac1oymkQ_n2QKEPwFQxy6JZVGwgIkLQU,15585
|
|
8
8
|
owlplanner/tax2025.py,sha256=PVteko6G9gjAT247GnTzAPUe_RaLnZUArFtdzf1dF3M,7014
|
|
9
9
|
owlplanner/timelists.py,sha256=tYieZU67FT6TCcQQis36JaXGI7dT6NqD7RvdEjgJL4M,4026
|
|
10
10
|
owlplanner/utils.py,sha256=HM70W60qB41zfnbl2LltNwAuLYHyy5XYbwnbNcaa6FE,2351
|
|
11
|
-
owlplanner/version.py,sha256=
|
|
11
|
+
owlplanner/version.py,sha256=_MJp2MbS5Atcm2yUx56j3cirNAIGlUxcU_Vuv3WHoV8,28
|
|
12
12
|
owlplanner/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
owlplanner/data/rates.csv,sha256=6fxg56BVVORrj9wJlUGFdGXKvOX5r7CSca8uhUbbuIU,3734
|
|
14
|
-
owlplanner-2025.2.
|
|
15
|
-
owlplanner-2025.2.
|
|
16
|
-
owlplanner-2025.2.
|
|
17
|
-
owlplanner-2025.2.
|
|
14
|
+
owlplanner-2025.2.14.dist-info/METADATA,sha256=fEYEzkqBdWcT_Lv_96Ig7uxF7LwzPH0YcJl9NLD8auU,53447
|
|
15
|
+
owlplanner-2025.2.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
16
|
+
owlplanner-2025.2.14.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
17
|
+
owlplanner-2025.2.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|