owlplanner 2025.3.13__py3-none-any.whl → 2025.3.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 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)
@@ -1289,6 +1292,11 @@ class Plan(object):
1289
1292
  for t in range(Nt):
1290
1293
  row.addElem(_q2(CF, t, n, Nt, Nn), self.theta_tn[t, n])
1291
1294
 
1295
+ # Minus 10% penalty on early withdrawals.
1296
+ if n < self.n59[i]:
1297
+ row.addElem(_q3(Cw, i, 1, n, Ni, Nj, Nn), 0.1)
1298
+ row.addElem(_q3(Cw, i, 2, n, Ni, Nj, Nn), 0.1)
1299
+
1292
1300
  A.addRow(row, rhs, rhs)
1293
1301
 
1294
1302
  # Impose income profile.
@@ -1970,6 +1978,12 @@ class Plan(object):
1970
1978
  self.G_n = np.sum(self.F_tn, axis=0)
1971
1979
  self.T_tn = self.F_tn * self.theta_tn
1972
1980
  self.T_n = np.sum(self.T_tn, axis=0)
1981
+ self.penalty_n = np.zeros(Nn)
1982
+ # Add early withdrawal penalties if any.
1983
+ for i in range(Ni):
1984
+ self.penalty_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]])
1985
+
1986
+ self.T_n += self.penalty_n
1973
1987
 
1974
1988
  tau_0 = np.array(self.tau_kn[0, :])
1975
1989
  tau_0[tau_0 < 0] = 0
@@ -2112,6 +2126,11 @@ class Plan(object):
2112
2126
  dic[f"-- Subtotal in tax bracket {tname}"] = f"{u.d(taxPaidNow)}"
2113
2127
  dic[f"-- [Subtotal in tax bracket {tname}]"] = f"{u.d(taxPaid)}"
2114
2128
 
2129
+ penaltyPaid = np.sum(self.penalty_n, axis=0)
2130
+ penaltyPaidNow = np.sum(self.penalty_n / self.gamma_n[:-1], axis=0)
2131
+ dic["-- Subtotal in early withdrawal penalty"] = f"{u.d(penaltyPaidNow)}"
2132
+ dic["-- [Subtotal in early withdrawal penalty]"] = f"{u.d(penaltyPaid)}"
2133
+
2115
2134
  taxPaid = np.sum(self.U_n, axis=0)
2116
2135
  taxPaidNow = np.sum(self.U_n / self.gamma_n[:-1], axis=0)
2117
2136
  dic["Total tax paid on gains and dividends"] = f"{u.d(taxPaidNow)}"
@@ -2507,6 +2526,7 @@ class Plan(object):
2507
2526
 
2508
2527
  title = self._name + "\nRaw Income Sources"
2509
2528
  stypes = self.sources_in.keys()
2529
+ # stypes = [item for item in stypes if "RothX" not in item]
2510
2530
 
2511
2531
  if tag != "":
2512
2532
  title += " - " + tag
@@ -2517,7 +2537,7 @@ class Plan(object):
2517
2537
  else:
2518
2538
  yformat = "\\$k (" + str(self.year_n[0]) + "\\$)"
2519
2539
  sources_in = {}
2520
- for key in self.sources_in:
2540
+ for key in stypes:
2521
2541
  sources_in[key] = self.sources_in[key] / self.gamma_n[:-1]
2522
2542
 
2523
2543
  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.14"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.3.13
3
+ Version: 2025.3.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
@@ -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=2uS_N121p-fPhCboVSAthdt_uVw109ltLTvCLeGouuo,116263
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=gPOv802nGWM84uQsfLVWHJKlgbpuozzBAjyW-OgDkzE,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.14.dist-info/METADATA,sha256=C5BlpAPu2CwtVQmuBUPDTYi7mXg86T3b0dYR5anPUak,53801
15
+ owlplanner-2025.3.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ owlplanner-2025.3.14.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
+ owlplanner-2025.3.14.dist-info/RECORD,,