owlplanner 2025.3.13__py3-none-any.whl → 2025.3.15__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 CHANGED
@@ -266,6 +266,9 @@ class Plan(object):
266
266
  # self.horizons = [yobs[i] + expectancy[i] - thisyear + 1 for i in range(self.N_i)]
267
267
  self.N_n = np.max(self.horizons)
268
268
  self.year_n = np.linspace(thisyear, thisyear + self.N_n - 1, self.N_n, dtype=np.int32)
269
+ # Year in the plan (if any) where individuals turn 59. For 10% withdrawal penalty.
270
+ self.n59 = 59 - thisyear + self.yobs
271
+ self.n59[self.n59 < 0] = 0
269
272
  # Handle passing of one spouse before the other.
270
273
  if self.N_i == 2 and np.min(self.horizons) != np.max(self.horizons):
271
274
  self.n_d = np.min(self.horizons)
@@ -1281,8 +1284,9 @@ class Plan(object):
1281
1284
  # Minus capital gains on taxable withdrawals using last year's rate if >=0.
1282
1285
  # Plus taxable account withdrawals, and all other withdrawals.
1283
1286
  row.addElem(_q3(Cw, i, 0, n, Ni, Nj, Nn), fac * (tau_0prev[n] - self.mu) - 1)
1284
- row.addElem(_q3(Cw, i, 1, n, Ni, Nj, Nn), -1)
1285
- row.addElem(_q3(Cw, i, 2, n, Ni, Nj, Nn), -1)
1287
+ penalty = 0.1 if n < self.n59[i] else 0
1288
+ row.addElem(_q3(Cw, i, 1, n, Ni, Nj, Nn), -1 + penalty)
1289
+ row.addElem(_q3(Cw, i, 2, n, Ni, Nj, Nn), -1 + penalty)
1286
1290
  row.addElem(_q2(Cd, i, n, Ni, Nn), fac * self.mu)
1287
1291
 
1288
1292
  # Minus tax on ordinary income, T_n.
@@ -1970,6 +1974,12 @@ class Plan(object):
1970
1974
  self.G_n = np.sum(self.F_tn, axis=0)
1971
1975
  self.T_tn = self.F_tn * self.theta_tn
1972
1976
  self.T_n = np.sum(self.T_tn, axis=0)
1977
+ self.P_n = np.zeros(Nn)
1978
+ # Add early withdrawal penalty if any.
1979
+ for i in range(Ni):
1980
+ self.P_n[0:self.n59[i]] += 0.1*(self.w_ijn[i, 1, 0:self.n59[i]] + self.w_ijn[i, 2, 0:self.n59[i]])
1981
+
1982
+ self.T_n += self.P_n
1973
1983
 
1974
1984
  tau_0 = np.array(self.tau_kn[0, :])
1975
1985
  tau_0[tau_0 < 0] = 0
@@ -2112,6 +2122,11 @@ class Plan(object):
2112
2122
  dic[f"-- Subtotal in tax bracket {tname}"] = f"{u.d(taxPaidNow)}"
2113
2123
  dic[f"-- [Subtotal in tax bracket {tname}]"] = f"{u.d(taxPaid)}"
2114
2124
 
2125
+ penaltyPaid = np.sum(self.P_n, axis=0)
2126
+ penaltyPaidNow = np.sum(self.P_n / self.gamma_n[:-1], axis=0)
2127
+ dic["-- Subtotal in early withdrawal penalty"] = f"{u.d(penaltyPaidNow)}"
2128
+ dic["-- [Subtotal in early withdrawal penalty]"] = f"{u.d(penaltyPaid)}"
2129
+
2115
2130
  taxPaid = np.sum(self.U_n, axis=0)
2116
2131
  taxPaidNow = np.sum(self.U_n / self.gamma_n[:-1], axis=0)
2117
2132
  dic["Total tax paid on gains and dividends"] = f"{u.d(taxPaidNow)}"
@@ -2507,6 +2522,7 @@ class Plan(object):
2507
2522
 
2508
2523
  title = self._name + "\nRaw Income Sources"
2509
2524
  stypes = self.sources_in.keys()
2525
+ # stypes = [item for item in stypes if "RothX" not in item]
2510
2526
 
2511
2527
  if tag != "":
2512
2528
  title += " - " + tag
@@ -2517,7 +2533,7 @@ class Plan(object):
2517
2533
  else:
2518
2534
  yformat = "\\$k (" + str(self.year_n[0]) + "\\$)"
2519
2535
  sources_in = {}
2520
- for key in self.sources_in:
2536
+ for key in stypes:
2521
2537
  sources_in[key] = self.sources_in[key] / self.gamma_n[:-1]
2522
2538
 
2523
2539
  fig, ax = _stackPlot(
owlplanner/utils.py CHANGED
@@ -70,8 +70,8 @@ def getUnits(units) -> int:
70
70
  return fac
71
71
 
72
72
 
73
- # Could be a one-line lambda function:
74
- # krond = lambda a, b: 1 if a == b else 0
73
+ # Next two functins could be a one-line lambda functions.
74
+ # e.g., krond = lambda a, b: 1 if a == b else 0
75
75
  def krond(a, b) -> int:
76
76
  """
77
77
  Kronecker integer delta function.
@@ -79,6 +79,13 @@ def krond(a, b) -> int:
79
79
  return 1 if a == b else 0
80
80
 
81
81
 
82
+ def heavyside(x) -> int:
83
+ """
84
+ Heavyside step function.
85
+ """
86
+ return 1 if x >= 0 else 0
87
+
88
+
82
89
  def roundCents(values, decimals=2):
83
90
  """
84
91
  Round values in NumPy array down to second decimal.
owlplanner/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2025.03.13"
1
+ __version__ = "2025.03.15"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.3.13
3
+ Version: 2025.3.15
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
@@ -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=uJ6jZ9Rx2CB2P5cFRscsUCXOW6uml7I4pta2ozjW0uo,12263
4
4
  owlplanner/logging.py,sha256=tYMw04O-XYSzjTj36fmKJGLcE1VkK6k6oJNeqtKXzuc,2530
5
- owlplanner/plan.py,sha256=BjNzeV9inGGmirMTQ8VVfOaxR8-WGLZAgSATyJk0dAI,115239
5
+ owlplanner/plan.py,sha256=SWTqNMC0Mk2BUO3CBeeyBaz_cCbLddlSgPJaIj2Cc-I,116090
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
- owlplanner/utils.py,sha256=HM70W60qB41zfnbl2LltNwAuLYHyy5XYbwnbNcaa6FE,2351
11
- owlplanner/version.py,sha256=GR2k_WJJsQtJYtt5VJ64fZchrCUdIeleskErLMVRk8s,28
10
+ owlplanner/utils.py,sha256=WpJgn79YZfH8UCkcmhd-AZlxlGuz1i1-UDBRXImsY6I,2485
11
+ owlplanner/version.py,sha256=bgb6jaI7G-g19wcFJKSKnZXFRyBbqhxpo45gREhwu-U,28
12
12
  owlplanner/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  owlplanner/data/rates.csv,sha256=6fxg56BVVORrj9wJlUGFdGXKvOX5r7CSca8uhUbbuIU,3734
14
- owlplanner-2025.3.13.dist-info/METADATA,sha256=k1I0OLgv8oQG7oxVARAVWXz7tWNNeynGPcB3uYndEUA,53801
15
- owlplanner-2025.3.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- owlplanner-2025.3.13.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
- owlplanner-2025.3.13.dist-info/RECORD,,
14
+ owlplanner-2025.3.15.dist-info/METADATA,sha256=aM0PuxyPW8mmVvJ-jmq_qBnpAAzd1mFM5OZ_JYx8v1o,53801
15
+ owlplanner-2025.3.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ owlplanner-2025.3.15.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
+ owlplanner-2025.3.15.dist-info/RECORD,,