owlplanner 2025.2.27__py3-none-any.whl → 2025.3.11__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/config.py CHANGED
@@ -55,7 +55,7 @@ def saveConfig(myplan, file, mylog):
55
55
  diconf["Fixed Income"] = {
56
56
  "Pension amounts": (myplan.pensionAmounts / 1000).tolist(),
57
57
  "Pension ages": myplan.pensionAges.tolist(),
58
- "Pension indexed": myplan.pensionIndexed,
58
+ "Pension indexed": myplan.pensionIsIndexed,
59
59
  "Social security amounts": (myplan.ssecAmounts / 1000).tolist(),
60
60
  "Social security ages": myplan.ssecAges.tolist(),
61
61
  }
@@ -222,8 +222,8 @@ def readConfig(file, *, verbose=True, logstreams=None, readContributions=True):
222
222
  p.setSocialSecurity(ssecAmounts, ssecAges)
223
223
  pensionAmounts = np.array(diconf["Fixed Income"]["Pension amounts"], dtype=np.float32)
224
224
  pensionAges = np.array(diconf["Fixed Income"]["Pension ages"], dtype=np.int32)
225
- pensionIndexed = diconf["Fixed Income"]["Pension indexed"]
226
- p.setPension(pensionAmounts, pensionAges, pensionIndexed)
225
+ pensionIsIndexed = diconf["Fixed Income"]["Pension indexed"]
226
+ p.setPension(pensionAmounts, pensionAges, pensionIsIndexed)
227
227
 
228
228
  # Rates Selection.
229
229
  p.setDividendRate(float(diconf["Rates Selection"]["Dividend tax rate"]))
owlplanner/plan.py CHANGED
@@ -291,7 +291,7 @@ class Plan(object):
291
291
  self.zeta_in = np.zeros((self.N_i, self.N_n))
292
292
  self.pensionAmounts = np.zeros(self.N_i)
293
293
  self.pensionAges = 65 * np.ones(self.N_i, dtype=np.int32)
294
- self.pensionIndexed = [False, False]
294
+ self.pensionIsIndexed = [False, False]
295
295
  self.ssecAmounts = np.zeros(self.N_i)
296
296
  self.ssecAges = 67 * np.ones(self.N_i, dtype=np.int32)
297
297
 
@@ -531,7 +531,7 @@ class Plan(object):
531
531
 
532
532
  self.pensionAmounts = np.array(amounts)
533
533
  self.pensionAges = np.array(ages, dtype=np.int32)
534
- self.pensionIndexed = indexed
534
+ self.pensionIsIndexed = indexed
535
535
  self.caseStatus = "modified"
536
536
  self._adjustedParameters = False
537
537
 
@@ -1008,7 +1008,7 @@ class Plan(object):
1008
1008
  self.xiBar_n = self.xi_n * self.gamma_n[:-1]
1009
1009
  self.piBar_in = np.array(self.pi_in)
1010
1010
  for i in range(self.N_i):
1011
- if self.pensionIndexed[i]:
1011
+ if self.pensionIsIndexed[i]:
1012
1012
  self.piBar_in[i] *= self.gamma_n[:-1]
1013
1013
 
1014
1014
  self._adjustedParameters = True
@@ -1968,8 +1968,8 @@ class Plan(object):
1968
1968
  self.dist_in = self.w_ijn[:, 1, :] - self.rmd_in
1969
1969
  self.dist_in[self.dist_in < 0] = 0
1970
1970
  self.G_n = np.sum(self.F_tn, axis=0)
1971
- T_tn = self.F_tn * self.theta_tn
1972
- self.T_n = np.sum(T_tn, axis=0)
1971
+ self.T_tn = self.F_tn * self.theta_tn
1972
+ self.T_n = np.sum(self.T_tn, axis=0)
1973
1973
 
1974
1974
  tau_0 = np.array(self.tau_kn[0, :])
1975
1975
  tau_0[tau_0 < 0] = 0
@@ -2105,6 +2105,12 @@ class Plan(object):
2105
2105
  taxPaidNow = np.sum(self.T_n / self.gamma_n[:-1], axis=0)
2106
2106
  dic["Total income tax paid on ordinary income"] = f"{u.d(taxPaidNow)}"
2107
2107
  dic["- Total income tax paid on ordinary income (nominal)"] = f"{u.d(taxPaid)}"
2108
+ for t in range(self.N_t):
2109
+ taxPaid = np.sum(self.T_tn[t], axis=0)
2110
+ taxPaidNow = np.sum(self.T_tn[t] / self.gamma_n[:-1], axis=0)
2111
+ tname = tx.taxBracketNames[t]
2112
+ dic[f"-- Subtotal in tax bracket {tname}"] = f"{u.d(taxPaidNow)}"
2113
+ dic[f"--- Subtotal in tax bracket {tname} (nominal)"] = f"{u.d(taxPaid)}"
2108
2114
 
2109
2115
  taxPaid = np.sum(self.U_n, axis=0)
2110
2116
  taxPaidNow = np.sum(self.U_n / self.gamma_n[:-1], axis=0)
@@ -2129,12 +2135,17 @@ class Plan(object):
2129
2135
  iname_s = self.inames[self.i_s]
2130
2136
  iname_d = self.inames[self.i_d]
2131
2137
  dic[f"Sum of spousal transfer to {iname_s} in year {ynx}"] = (f"{u.d(totSpousalNow)}")
2132
- dic[f"- Sum of spousal transfer to {iname_s} in year {ynx} (nominal)"] = (f"{u.d(totSpousal)}")
2133
- dic[f"-- Spousal transfer to {iname_s} in year {ynx} - taxable (nominal)"] = (f"{u.d(q_j[0])}")
2134
- dic[f"-- Spousal transfer to {iname_s} in year {ynx} - tax-def (nominal)"] = (f"{u.d(q_j[1])}")
2135
- dic[f"-- Spousal transfer to {iname_s} in year {ynx} - tax-free (nominal)"] = (f"{u.d(q_j[2])}")
2136
-
2137
- dic[f"Sum of post-tax non-spousal bequests from {iname_d} in year {ynx}"] = (f"{u.d(totOthersNow)}")
2138
+ dic[f"- Sum of spousal transfer to {iname_s} in year {ynx} (nominal)"] = (
2139
+ f"{u.d(totSpousal)}")
2140
+ dic[f"-- Spousal transfer to {iname_s} in year {ynx} - taxable (nominal)"] = (
2141
+ f"{u.d(q_j[0])}")
2142
+ dic[f"-- Spousal transfer to {iname_s} in year {ynx} - tax-def (nominal)"] = (
2143
+ f"{u.d(q_j[1])}")
2144
+ dic[f"-- Spousal transfer to {iname_s} in year {ynx} - tax-free (nominal)"] = (
2145
+ f"{u.d(q_j[2])}")
2146
+
2147
+ dic[f"Sum of post-tax non-spousal bequests from {iname_d} in year {ynx}"] = (
2148
+ f"{u.d(totOthersNow)}")
2138
2149
  dic[f"- Sum of post-tax non-spousal bequests from {iname_d} in year {ynx} (nominal)"] = (
2139
2150
  f"{u.d(totOthers)}")
2140
2151
  dic[f"-- Post-tax non-spousal bequests from {iname_d} in year {ynx} - taxable (nominal)"] = (
@@ -2156,7 +2167,7 @@ class Plan(object):
2156
2167
  dic[f"-- Post-tax account value at the end of {lastyear} - tax-free (nominal)"] = (f"{u.d(estate[2])}")
2157
2168
 
2158
2169
  dic["Plan starting date"] = str(self.startDate)
2159
- dic[f"Cumulative inflation factor from start date to end of {lastyear}"] = f"{self.gamma_n[-1]:.2f}"
2170
+ dic[f"Cumulative inflation factor from start date to end of {lastyear}"] = (f"{self.gamma_n[-1]:.2f}")
2160
2171
  for i in range(self.N_i):
2161
2172
  dic[f"{self.inames[i]:>12}'s {self.horizons[i]:02}-year life horizon"] = (
2162
2173
  f"{now} -> {now + self.horizons[i] - 1}")
owlplanner/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2025.02.27"
1
+ __version__ = "2025.03.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.2.27
3
+ Version: 2025.3.11
4
4
  Summary: Owl: Retirement planner with great wisdom
5
5
  Project-URL: HomePage, https://github.com/mdlacasse/owl
6
6
  Project-URL: Repository, https://github.com/mdlacasse/owl
@@ -711,7 +711,13 @@ Description-Content-Type: text/markdown
711
711
  -------------------------------------------------------------------------------------
712
712
 
713
713
  ### TL;DR
714
- Owl is a planning tool that uses a linear programming optimization algorithm to provide guidance on retirement decisions. There are a few ways to run Owl.
714
+ Owl is a retirement planning tool that uses a linear programming optimization algorithm
715
+ to provide guidance on retirement decisions, including Roth conversions.
716
+ Users can select varying return rates to perform historical back testing,
717
+ stochastic rates for performing Monte Carlo analyses,
718
+ or fixed rates either derived from historical averages, or set by the user.
719
+
720
+ There are a few ways to run Owl:
715
721
 
716
722
  - Run Owl directly on the Streamlit Community Server at [owlplanner.streamlit.app](https://owlplanner.streamlit.app).
717
723
 
@@ -759,7 +765,7 @@ mathematical model can be found [here](https://raw.github.com/mdlacasse/Owl/main
759
765
  It is anticipated that most end users will use Owl through the graphical interface
760
766
  either at [owlplanner.streamlit.app](https://owlplanner.streamlit.app)
761
767
  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
768
+ The underlying Python package can also be used directly through Python scripts or Jupyter Notebooks
763
769
  as described [here](USER_GUIDE.md).
764
770
 
765
771
  Not every retirement decision strategy can be framed as an easy-to-solve optimization problem.
@@ -792,7 +798,7 @@ Asset allocations are selected for the duration of the plan, and these can glide
792
798
  or along a configurable s-curve over the lifespan of the individual.
793
799
 
794
800
  Spending profiles are adjusted for inflation, and so are all other indexable quantities. Proflies can be
795
- flat or follow a *smile* curve which is also adjustable through two simple parameters.
801
+ flat or follow a *smile* curve which is also adjustable through three simple parameters.
796
802
 
797
803
  Available rates are from 1928 to last year and can be used to test historical performance.
798
804
  Fixed rates can also be provided, as well as *histochastic* rates, which are generated using
@@ -868,7 +874,7 @@ assets to support, even with no estate being left.
868
874
  ---------------------------------------------------------------
869
875
  ## Documentation
870
876
 
871
- - Documentation for the app user interface is available from the interface itself.
877
+ - Documentation for the app user interface is available from the interface [itself](https://owlplanner.streamlit.app/Documentation).
872
878
  - Installation guide and software requirements can be found [here](INSTALL.md).
873
879
  - User guide for the underlying Python package as used in a Jupyter notebook can be found [here](USER_GUIDE.md).
874
880
 
@@ -1,17 +1,17 @@
1
1
  owlplanner/__init__.py,sha256=QqrdT0Qks20osBTg7h0vJHAxpP9lL7DA99xb0nYbtw4,254
2
2
  owlplanner/abcapi.py,sha256=LbzW_KcNy0IeHp42MUHwGu_H67B2h_e1_vu-c2ACTkQ,6646
3
- owlplanner/config.py,sha256=bvqoOWrdPrWYQF9-PS_n00MoyZkAsmMOSczhTUFRGVU,12257
3
+ owlplanner/config.py,sha256=uJ6jZ9Rx2CB2P5cFRscsUCXOW6uml7I4pta2ozjW0uo,12263
4
4
  owlplanner/logging.py,sha256=tYMw04O-XYSzjTj36fmKJGLcE1VkK6k6oJNeqtKXzuc,2530
5
- owlplanner/plan.py,sha256=Wadr5IlsXJbOvnw7dDIb4nVD7PuUCiUI_HXCvyF4sF0,114925
5
+ owlplanner/plan.py,sha256=mCcoocK9g1nCUpQDaMVUTiwugKPuDZaEYbrSPPi0sBY,115404
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=B-A5eU3wxdcAaxRCbT3qI-JEKoD_ZeNbg_86XhNdQEI,7745
9
9
  owlplanner/timelists.py,sha256=tYieZU67FT6TCcQQis36JaXGI7dT6NqD7RvdEjgJL4M,4026
10
10
  owlplanner/utils.py,sha256=HM70W60qB41zfnbl2LltNwAuLYHyy5XYbwnbNcaa6FE,2351
11
- owlplanner/version.py,sha256=2dWgos-zzkuXchJJ940RNcgSbRClj6bmX8bVv2KOl-A,28
11
+ owlplanner/version.py,sha256=HrtvlhxZp9gln32M2lagzUjBWC3oqV1rUecAVUAAJj8,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.27.dist-info/METADATA,sha256=WT4eGtSQ125dYyOb8PgZ175f_WHrKvGssaEJQ5qd5P0,53506
15
- owlplanner-2025.2.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- owlplanner-2025.2.27.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
- owlplanner-2025.2.27.dist-info/RECORD,,
14
+ owlplanner-2025.3.11.dist-info/METADATA,sha256=h06pbBAcJCEqWvY_zOybpnIk5xEaVhax8R2YESfn73o,53801
15
+ owlplanner-2025.3.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ owlplanner-2025.3.11.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
+ owlplanner-2025.3.11.dist-info/RECORD,,