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 +21 -1
- owlplanner/utils.py +9 -2
- owlplanner/version.py +1 -1
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.14.dist-info}/METADATA +1 -1
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.14.dist-info}/RECORD +7 -7
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.14.dist-info}/WHEEL +0 -0
- {owlplanner-2025.3.13.dist-info → owlplanner-2025.3.14.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)
|
|
@@ -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
|
|
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
|
-
#
|
|
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.14"
|
|
@@ -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=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=
|
|
11
|
-
owlplanner/version.py,sha256=
|
|
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.
|
|
15
|
-
owlplanner-2025.3.
|
|
16
|
-
owlplanner-2025.3.
|
|
17
|
-
owlplanner-2025.3.
|
|
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,,
|
|
File without changes
|
|
File without changes
|