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 +19 -3
- owlplanner/utils.py +9 -2
- owlplanner/version.py +1 -1
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.15.dist-info}/METADATA +1 -1
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.15.dist-info}/RECORD +7 -7
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.15.dist-info}/WHEEL +0 -0
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.15.dist-info}/licenses/LICENSE +0 -0
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
|
-
|
|
1285
|
-
row.addElem(_q3(Cw, i,
|
|
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
|
|
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
|
-
#
|
|
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.
|
|
1
|
+
__version__ = "2025.03.15"
|
|
@@ -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=
|
|
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=
|
|
11
|
-
owlplanner/version.py,sha256=
|
|
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.
|
|
15
|
-
owlplanner-2025.3.
|
|
16
|
-
owlplanner-2025.3.
|
|
17
|
-
owlplanner-2025.3.
|
|
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,,
|
|
File without changes
|
|
File without changes
|