owlplanner 2025.1.29__py3-none-any.whl → 2025.2.1__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
@@ -397,16 +397,6 @@ class Plan(object):
397
397
 
398
398
  return None
399
399
 
400
- def setPreviousMAGI(self, magi, units='k'):
401
- """
402
- Set MAGI for two previous years to the plan. Values are in nominal $k.
403
- """
404
- assert len(magi) == 2, "MAGI must have two values."
405
- fac = u.getUnits(units)
406
- u.rescale(magi, fac)
407
- self.mylog.vprint('Setting previous years MAGI to:', [u.d(magi[i]) for i in range(2)])
408
- self.prevMAGI = np.array(magi)
409
-
410
400
  def rename(self, newname):
411
401
  """
412
402
  Override name of the plan. Plan name is used
@@ -869,12 +859,12 @@ class Plan(object):
869
859
 
870
860
  'year',
871
861
  'anticipated wages',
872
- 'ctrb taxable',
873
- 'ctrb 401k',
874
- 'ctrb Roth 401k',
875
- 'ctrb IRA',
876
- 'ctrb Roth IRA',
877
- 'Roth X',
862
+ 'taxable ctrb',
863
+ '401k ctrb',
864
+ 'Roth 401k ctrb',
865
+ 'IRA ctrb',
866
+ 'Roth IRA ctrb',
867
+ 'Roth conv',
878
868
  'big-ticket items'
879
869
 
880
870
  in any order. A template is provided as an example.
@@ -900,12 +890,12 @@ class Plan(object):
900
890
  for i, iname in enumerate(self.inames):
901
891
  h = self.horizons[i]
902
892
  self.omega_in[i, :h] = self.timeLists[iname]['anticipated wages'].iloc[:h]
903
- self.kappa_ijn[i, 0, :h] = self.timeLists[iname]['ctrb taxable'].iloc[:h]
904
- self.kappa_ijn[i, 1, :h] = self.timeLists[iname]['ctrb 401k'].iloc[:h]
905
- self.kappa_ijn[i, 2, :h] = self.timeLists[iname]['ctrb Roth 401k'].iloc[:h]
906
- self.kappa_ijn[i, 1, :h] += self.timeLists[iname]['ctrb IRA'].iloc[:h]
907
- self.kappa_ijn[i, 2, :h] += self.timeLists[iname]['ctrb Roth IRA'].iloc[:h]
908
- self.myRothX_in[i, :h] = self.timeLists[iname]['Roth X'].iloc[:h]
893
+ self.kappa_ijn[i, 0, :h] = self.timeLists[iname]['taxable ctrb'].iloc[:h]
894
+ self.kappa_ijn[i, 1, :h] = self.timeLists[iname]['401k ctrb'].iloc[:h]
895
+ self.kappa_ijn[i, 2, :h] = self.timeLists[iname]['Roth 401k ctrb'].iloc[:h]
896
+ self.kappa_ijn[i, 1, :h] += self.timeLists[iname]['IRA ctrb'].iloc[:h]
897
+ self.kappa_ijn[i, 2, :h] += self.timeLists[iname]['Roth IRA ctrb'].iloc[:h]
898
+ self.myRothX_in[i, :h] = self.timeLists[iname]['Roth conv'].iloc[:h]
909
899
  self.Lambda_in[i, :h] = self.timeLists[iname]['big-ticket items'].iloc[:h]
910
900
 
911
901
  # In 1st year, reduce wages and contribution depending on starting date.
@@ -957,8 +947,8 @@ class Plan(object):
957
947
  self.myRothX_in[:, :] = 0.
958
948
  self.kappa_ijn[:, :, :] = 0.
959
949
 
960
- cols = ['year', 'anticipated wages', 'ctrb taxable', 'ctrb 401k',
961
- 'ctrb Roth 401k', 'ctrb IRA', 'ctrb Roth IRA', 'Roth X', 'big-ticket items']
950
+ cols = ['year', 'anticipated wages', 'taxable ctrb', '401k ctrb',
951
+ 'Roth 401k ctrb', 'IRA ctrb', 'Roth IRA ctrb', 'Roth conv', 'big-ticket items']
962
952
  for i, iname in enumerate(self.inames):
963
953
  h = self.horizons[i]
964
954
  df = pd.DataFrame(0, index=np.arange(h), columns=cols)
@@ -1619,6 +1609,7 @@ class Plan(object):
1619
1609
  'noRothConversions',
1620
1610
  'withMedicare',
1621
1611
  'solver',
1612
+ 'previousMAGIs',
1622
1613
  ]
1623
1614
  # We will modify options if required.
1624
1615
  if options is None:
@@ -1647,6 +1638,17 @@ class Plan(object):
1647
1638
  if objective == 'maxSpending' and 'bequest' not in myoptions:
1648
1639
  self.mylog.vprint('Using bequest of $1.')
1649
1640
 
1641
+ if 'previousMAGIs' in myoptions:
1642
+ magi = myoptions['previousMAGIs']
1643
+ if len(magi) != 2:
1644
+ raise ValueError("previousMAGIs must have two values.")
1645
+
1646
+ if 'units' in options:
1647
+ units = u.getUnits(options['units'])
1648
+ else:
1649
+ units = 1000
1650
+ self.prevMAGI = units * np.array(magi)
1651
+
1650
1652
  self._adjustParameters()
1651
1653
 
1652
1654
  if 'solver' in options:
@@ -1991,8 +1993,8 @@ class Plan(object):
1991
1993
  'wages',
1992
1994
  'ssec',
1993
1995
  'pension',
1994
- 'dist',
1995
- 'rmd',
1996
+ '+dist',
1997
+ 'RMD',
1996
1998
  'RothX',
1997
1999
  'wdrwl taxable',
1998
2000
  'wdrwl tax-free',
@@ -2002,12 +2004,12 @@ class Plan(object):
2002
2004
  sources['wages'] = self.omega_in
2003
2005
  sources['ssec'] = self.zetaBar_in
2004
2006
  sources['pension'] = self.pi_in
2005
- sources['wdrwl taxable'] = self.w_ijn[:, 0, :]
2006
- sources['rmd'] = self.rmd_in
2007
- sources['dist'] = self.dist_in
2007
+ sources['taxable wdrwl'] = self.w_ijn[:, 0, :]
2008
+ sources['RMD'] = self.rmd_in
2009
+ sources['+dist'] = self.dist_in
2008
2010
  sources['RothX'] = self.x_in
2009
- sources['wdrwl tax-free'] = self.w_ijn[:, 2, :]
2010
- sources['bti'] = self.Lambda_in
2011
+ sources['tax-free wdrwl'] = self.w_ijn[:, 2, :]
2012
+ sources['BTI'] = self.Lambda_in
2011
2013
 
2012
2014
  savings = {}
2013
2015
  savings['taxable'] = self.b_ijn[:, 0, :]
@@ -2717,7 +2719,7 @@ class Plan(object):
2717
2719
  'all wages': np.sum(self.omega_in, axis=0),
2718
2720
  'all pensions': np.sum(self.pi_in, axis=0),
2719
2721
  'all soc sec': np.sum(self.zetaBar_in, axis=0),
2720
- "all bti's": np.sum(self.Lambda_in, axis=0),
2722
+ "all BTI's": np.sum(self.Lambda_in, axis=0),
2721
2723
  'all wdrwls': np.sum(self.w_ijn, axis=(0, 1)),
2722
2724
  'all deposits': -np.sum(self.d_in, axis=0),
2723
2725
  'ord taxes': -self.T_n,
@@ -2733,12 +2735,12 @@ class Plan(object):
2733
2735
  'wages': self.sources_in['wages'],
2734
2736
  'social sec': self.sources_in['ssec'],
2735
2737
  'pension': self.sources_in['pension'],
2736
- 'txbl acc wdrwl': self.sources_in['wdrwl taxable'],
2737
- 'RMDs': self.sources_in['rmd'],
2738
- '+distributions': self.sources_in['dist'],
2739
- 'Roth conversion': self.sources_in['RothX'],
2740
- 'tax-free wdrwl': self.sources_in['wdrwl tax-free'],
2741
- 'big-ticket items': self.sources_in['bti'],
2738
+ 'txbl acc wdrwl': self.sources_in['txbl acc wdrwl'],
2739
+ 'RMDs': self.sources_in['RMD'],
2740
+ '+distributions': self.sources_in['+dist'],
2741
+ 'Roth conv': self.sources_in['RothX'],
2742
+ 'tax-free wdrwl': self.sources_in['tax-free wdrwl'],
2743
+ 'big-ticket items': self.sources_in['BTI'],
2742
2744
  }
2743
2745
 
2744
2746
  for i in range(self.N_i):
@@ -2749,13 +2751,14 @@ class Plan(object):
2749
2751
  # Account balances except final year.
2750
2752
  accDic = {
2751
2753
  'taxable bal': self.b_ijn[:, 0, :-1],
2754
+ 'taxable ctrb': self.kappa_ijn[:, 0, :],
2752
2755
  'taxable dep': self.d_in,
2753
2756
  'taxable wdrwl': self.w_ijn[:, 0, :],
2754
2757
  'tax-deferred bal': self.b_ijn[:, 1, :-1],
2755
2758
  'tax-deferred ctrb': self.kappa_ijn[:, 1, :],
2756
2759
  'tax-deferred wdrwl': self.w_ijn[:, 1, :],
2757
2760
  '(included RMDs)': self.rmd_in[:, :],
2758
- 'Roth conversion': self.x_in,
2761
+ 'Roth conv': self.x_in,
2759
2762
  'tax-free bal': self.b_ijn[:, 2, :-1],
2760
2763
  'tax-free ctrb': self.kappa_ijn[:, 2, :],
2761
2764
  'tax-free wdrwl': self.w_ijn[:, 2, :],
@@ -2854,7 +2857,7 @@ class Plan(object):
2854
2857
  planData[self.inames[i] + ' tx-def ctrb'] = self.kappa_ijn[i, 1, :]
2855
2858
  planData[self.inames[i] + ' tx-def wdrl'] = self.w_ijn[i, 1, :]
2856
2859
  planData[self.inames[i] + ' (RMD)'] = self.rmd_in[i, :]
2857
- planData[self.inames[i] + ' Roth conversion'] = self.x_in[i, :]
2860
+ planData[self.inames[i] + ' Roth conv'] = self.x_in[i, :]
2858
2861
  planData[self.inames[i] + ' tx-free bal'] = self.b_ijn[i, 2, :-1]
2859
2862
  planData[self.inames[i] + ' tx-free ctrb'] = self.kappa_ijn[i, 2, :]
2860
2863
  planData[self.inames[i] + ' tax-free wdrwl'] = self.w_ijn[i, 2, :]
owlplanner/timelists.py CHANGED
@@ -23,12 +23,12 @@ import pandas as pd
23
23
  timeHorizonItems = [
24
24
  'year',
25
25
  'anticipated wages',
26
- 'ctrb taxable',
27
- 'ctrb 401k',
28
- 'ctrb Roth 401k',
29
- 'ctrb IRA',
30
- 'ctrb Roth IRA',
31
- 'Roth X',
26
+ 'taxable ctrb',
27
+ '401k ctrb',
28
+ 'Roth 401k ctrb',
29
+ 'IRA ctrb',
30
+ 'Roth IRA ctrb',
31
+ 'Roth conv',
32
32
  'big-ticket items',
33
33
  ]
34
34
 
@@ -38,8 +38,8 @@ def read(finput, inames, horizons, mylog):
38
38
  Read listed parameters from an excel spreadsheet or through
39
39
  a dictionary of dataframes through Pandas.
40
40
  Use one sheet for each individual with the following 9 columns:
41
- year, anticipated wages, ctrb taxable, ctrb 401k, ctrb Roth 401k,
42
- ctrb IRA, ctrb Roth IRA, Roth X, and big-ticket items.
41
+ year, anticipated wages, taxable ctrb, 401k ctrb, Roth 401k ctrb,
42
+ IRA ctrb, Roth IRA ctrb, Roth conv, and big-ticket items.
43
43
  Supports xls, xlsx, xlsm, xlsb, odf, ods, and odt file extensions.
44
44
  Returs a dictionary of dataframes by individual's names.
45
45
  """
owlplanner/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2025.1.29"
1
+ __version__ = "2025.02.01"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.1.29
3
+ Version: 2025.2.1
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=eemIsdbtzdWCIj5VuuswgphxXMcxJ_GZfUlDi6lttFM,6658
3
3
  owlplanner/config.py,sha256=ouADb6YES5Zgv0UwnEK9Axwvs8drp-ahboQjI4WTrr0,12069
4
4
  owlplanner/logging.py,sha256=pXg_mMgBll-kklqaDRLDNVUFo-5DAa-yqTKtiVrhNWw,2530
5
- owlplanner/plan.py,sha256=4Kuulsp3uUAt9w0sLKPPGPry2tPnY74SMNSOTcVIs40,115575
5
+ owlplanner/plan.py,sha256=kVuv7OfnLnoTxO6LZgRY56Np-yWifGNg_vtlB8R_jZQ,115626
6
6
  owlplanner/progress.py,sha256=YZjL5_m4MMgKPlWlhhKacPLt54tVhVGF1eXxxZapMYs,386
7
7
  owlplanner/rates.py,sha256=aKOmau8i3uqxZGi7HQJpzooT3X-yAZhga5MZJ56pBzk,15627
8
8
  owlplanner/tax2025.py,sha256=b2RgM6TBQa8ggo6ODyh0p_J7j79UUm8z5NiENqa1l_k,7016
9
- owlplanner/timelists.py,sha256=ifxbyMlRW3IMwsiu8zsoodA1CKJQthgk3iPq50vQIds,4104
9
+ owlplanner/timelists.py,sha256=WwymsYAGWcrEzMtc-wrLbn1EVA2fhqXGN4NHLJsH3Fs,4110
10
10
  owlplanner/utils.py,sha256=adIwqGVQFfvekke0JCxYJD3PKHbptVCj3NrQT2TQIB4,2351
11
- owlplanner/version.py,sha256=31a542RcfLaOTSP2qZRfQPdngqGSa6FlROIHXM1qDdc,27
11
+ owlplanner/version.py,sha256=0gSeVv3M2dXUJh4tEDh_HPMJgzKSY9PHw3rX05-ggH8,28
12
12
  owlplanner/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  owlplanner/data/rates.csv,sha256=6fxg56BVVORrj9wJlUGFdGXKvOX5r7CSca8uhUbbuIU,3734
14
- owlplanner-2025.1.29.dist-info/METADATA,sha256=EreFCtwuHeBO7xbqqQrLBET1Gdy5e-o9VsOeMvLN_rQ,64515
15
- owlplanner-2025.1.29.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- owlplanner-2025.1.29.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
- owlplanner-2025.1.29.dist-info/RECORD,,
14
+ owlplanner-2025.2.1.dist-info/METADATA,sha256=FUY7f2ri_UxQlUMZDllEohMHAVge-wmCp5bhnpi-gkA,64514
15
+ owlplanner-2025.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ owlplanner-2025.2.1.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
+ owlplanner-2025.2.1.dist-info/RECORD,,