-import constants
-import utils
-from tax_brackets import tax_brackets
-from money import money
-from numpy import random
-
-class parameters(object):
- def get_initial_annual_expenses(self):
- pass
-
- def get_average_inflation_multiplier(self):
- pass
-
- def get_average_social_security_multiplier(self):
- pass
-
- def get_average_investment_return_multiplier(self):
- pass
-
- def get_initial_social_security_age(self, person):
- pass
-
- def get_initial_social_security_benefit(self, person):
- pass
-
- def get_federal_standard_deduction(self):
- pass
-
- def get_federal_ordinary_income_tax_brackets(self):
- pass
-
- def get_federal_dividends_and_long_term_gains_income_tax_brackets(self):
- pass
-
- def dump(self):
- pass
-
- def report_year(self, year):
- pass
-
-class mutable_default_parameters(parameters):
- """A container to hold the initial states of several simulation
- parameters. Play with them as you see fit and see what happens."""
-
- def __init__(self):
- self.with_default_values()
-
- def with_default_values(self):
- # Annual expenses in USD at the start of the simulation. This
- # will be adjusted upwards with inflation_multiplier every year.
- self.initial_annual_expenses = money(144300)
-
- # The average US inflation rate during the simulation. The
- # Fed's target rate is 2.0% as of 2020. The long term observed
- # average historical inflation rate in the US is 2.1%.
- #
- # Note this is a multiplier... so 1.0 would be no inflation,
- # 1.21 is 2.1% inflation, 0.9 is deflation, etc...
- self.inflation_multiplier = 1.03
-
- # We want to be able to model social security payments not
- # keeping pace with inflation. Like the inflation_multiplier
- # above, this is a multiplier. It affect the magnitide of
- # social security payments year over year.
- self.social_security_multiplier = 1.02
-
- # This is the average investment return rate. Asset allocation has
- # a large effect on this as does the overall economy. That said,
- # the US stock market has returned 10%/year over a large enough
- # time window. Our investments at Fidelity have returned 6.91%
- # in the lifetime they have been there. The expected return of a
- # 50/50 stock/bond investment mix based on historical data is 8.3%.
- self.investment_multiplier = 1.04
-
- # The age at which each person will take social security
- # benefits in this simulation and how much she will get the
- # first year. Note, this benefit size increases year over
- # year at social_security_multiplier. This is what the social
- # security website estimates if we both earn $0 from 2020 on:
- #
- # Lynn's benefits: Scott's benefits:
- # age 62 - $21,120 age 62 - $21,420
- # age 67 - $30,000 age 67 - $30,420
- # age 70 - $37,200 age 70 - $37,728
- #
- # X SCOTT LYNN
- self.social_security_age = [0, 62, 62 ]
- self.initial_social_security_dollars = [0, money(21000), money(21000) ]
-
- # Tax details... the standard deduction amount and tax
- # brackets for ordinary income and long term capital gains.
- self.federal_standard_deduction_dollars = 24800
- self.federal_ordinary_income_tax_brackets = tax_brackets(
- constants.PESSIMISTIC_FEDERAL_INCOME_TAX_BRACKETS)
- self.federal_dividends_and_long_term_gains_brackets = tax_brackets(
- constants.CURRENT_LONG_TERM_GAIN_FEDERAL_TAX_BRACKETS)
- return self
-
- def set_initial_annual_expenses(self, expenses):
- assert expenses >= 0, "You can't have negative expenses"
- self.initial_annual_expenses = expenses
- return self
-
- def get_initial_annual_expenses(self):
- return self.initial_annual_expenses
-
- def set_average_inflation_multiplier(self, multiplier):
- self.inflation_multiplier = multiplier
- return self
-
- def get_average_inflation_multiplier(self):
- return self.inflation_multiplier
-
- def set_average_social_security_multiplier(self, multiplier):
- self.social_security_multiplier = multiplier
- return self
-
- def get_average_social_security_multiplier(self):
- return self.social_security_multiplier
-
- def set_average_investment_return_multiplier(self, multiplier):
- self.investment_multiplier = multiplier
- return self
-
- def get_average_investment_return_multiplier(self):
- return self.investment_multiplier
-
- def set_initial_social_security_age_and_benefits(self,
- person,
- age,
- amount):
- assert age >= 60 and age <= 70, "age should be between 60 and 70"
- self.social_security_age[person] = age
- assert amount >= 0, "Social security won't pay negative dollars"
- self.initial_social_security_dollars[person] = amount
- return self
-
- def get_initial_social_security_age(self, person):
- return self.social_security_age[person]
-
- def get_initial_social_security_benefit(self, person):
- return self.initial_social_security_dollars[person]
-
- def set_federal_standard_deduction(self, deduction):
- assert deduction >= 0, "Standard deduction should be non-negative"
- self.federal_standard_deduction_dollars = deduction
- return self
-
- def get_federal_standard_deduction(self):
- return self.federal_standard_deduction_dollars
-
- def set_federal_ordinary_income_tax_brackets(self, brackets):
- self.federal_ordinary_income_tax_brackets = brackets
- return self
-
- def get_federal_ordinary_income_tax_brackets(self):
- return self.federal_ordinary_income_tax_brackets
-
- def set_federal_dividends_and_long_term_gains_income_tax_brackets(self,
- brackets):
- self.federal_dividends_and_long_term_gains_brackets = brackets;
- return self
-
- def get_federal_dividends_and_long_term_gains_income_tax_brackets(self):
- return self.federal_dividends_and_long_term_gains_brackets
-
- def dump(self):
- print "SIMULATION PARAMETERS"
- print " {:<50}: {:>14}".format("Initial year annual expenses",
- self.initial_annual_expenses)
- print " {:<50}: {:>14}".format("Annual inflation rate",
- utils.format_rate(self.inflation_multiplier))
- print " {:<50}: {:>14}".format("Average annual investment return rate",
- utils.format_rate(self.investment_multiplier))
- print " {:<50}: {:>14}".format("Annual social security benefit increase rate",
- utils.format_rate(self.social_security_multiplier))
- print " {:<50}: {:>14}".format("Age at which Lynn takes social security",
- self.social_security_age[constants.LYNN])
- print " {:<50}: {:>14}".format("Lynn's first year social security benefit",
- self.initial_social_security_dollars[constants.LYNN])
- print " {:<50}: {:>14}".format("Age at which Scott takes social security",
- self.social_security_age[constants.SCOTT])
- print " {:<50}: {:>14}".format("Scott's first year social security benefit",
- self.initial_social_security_dollars[constants.SCOTT])
- print " Federal tax brackets ["
- self.federal_ordinary_income_tax_brackets.dump()
- print " ]"
-
- print " Federal dividend and long term gain brackets ["
- self.federal_dividends_and_long_term_gains_brackets.dump()
- print " ]"
- print " We assume Roth money continues to be available tax-free."
-
-class mutable_dynamic_historical_parameters(mutable_default_parameters):
- def __init__(self):
- self.selection_index = None
- self.selection_duration = 0
- self.historical_tuples = [
- # year stock infl bond
- (2020, 3.14, 1.90, 1.54),
- (2019, 31.49, 1.70, 2.15),
- (2018, -4.38, 2.40, 2.33),
- (2017, 21.83, 2.10, 1.19),
- (2016, 11.96, 1.30, 0.61),
- (2015, 1.38, 0.10, 0.32),
- (2014, 13.69, 1.60, 0.12),
- (2013, 32.39, 1.50, 0.13),
- (2012, 16.00, 2.10, 0.17),
- (2011, 2.11, 3.20, 0.18),
- (2010, 15.06, 1.60, 0.32),
- (2009, 26.46, -0.40, 0.47),
- (2008,-37.00, 3.80, 1.83),
- (2007, 5.49, 2.80, 4.53),
- (2006, 15.79, 3.20, 4.94),
- (2005, 4.91, 3.40, 3.62),
- (2004, 10.88, 2.70, 1.89),
- (2003, 28.68, 2.30, 1.24),
- (2002,-22.10, 1.60, 2.00),
- (2001,-11.89, 2.80, 3.49),
- (2000, -9.10, 3.40, 6.11),
- (1999, 21.04, 2.20, 5.08),
- (1998, 28.58, 1.50, 5.05),
- (1997, 33.36, 2.30, 5.63),
- (1996, 22.96, 3.00, 5.52),
- (1995, 37.58, 2.80, 5.94),
- (1994, 1.32, 2.60, 5.32),
- (1993, 10.08, 3.00, 3.43),
- (1992, 7.62, 3.00, 3.89),
- (1991, 30.47, 4.20, 5.86),
- (1990, -3.10, 5.40, 7.89),
- (1989, 31.69, 4.82, 8.54),
- (1988, 16.61, 4.14, 7.65),
- (1987, 15.25, 3.65, 6.77),
- (1986, 18.67, 0.86, 6.45),
- (1985, 31.73, 3.56, 8.42),
- (1984, 6.27, 4.32, 10.91),
- (1983, 22.56, 3.21, 9.58),
- (1982, 21.55, 6.16, 12.27),
- (1981, -4.91, 10.32, 14.80),
- (1980, 32.42, 13.50, 12.00),
- (1979, 18.44, 11.35, 10.65),
- (1978, 6.65, 7.59, 7.00),
- (1977, -7.18, 6.50, 6.08),
- (1976, 23.84, 5.76, 5.88),
- (1975, 37.20, 9.13, 6.78),
- (1974,-26.47, 11.04, 8.20),
- (1973,-14.66, 6.22, 7.32),
- (1972, 18.90, 3.21, 4.95),
- (1971, 14.31, 4.38, 4.89),
- (1970, 14.01, 5.72, 6.90),
- (1969, -8.50, 5.46, 7.12),
- (1968, 11.06, 4.19, 5.69),
- (1967, 23.98, 3.09, 4.88),
- (1966,-10.06, 2.86, 5.20),
- (1965, 12.45, 1.61, 4.15),
- (1964, 16.48, 1.31, 3.85),
- (1963, 22.80, 1.32, 3.36),
- (1962, -8.73, 1.00, 2.90),
- (1961, 26.89, 1.01, 2.60),
- (1960, 0.47, 1.72, 3.24),
- (1959, 11.96, 0.69, 3.83),
- (1958, 43.36, 2.85, 3.5),
- (1957,-10.78, 3.31, 3.6),
- (1956, 6.56, 1.49, 2.9),
- (1955, 31.56, -0.37, 2.5),
- (1954, 52.62, 0.75, 2.37),
- (1953, -0.99, 0.75, 2.71),
- (1952, 18.37, 1.92, 2.19),
- (1951, 24.02, 7.88, 2.00),
- (1950, 31.71, 1.26, 1.98),
- (1949, 18.79, -1.24, 2.21),
- (1948, 5.50, 8.07, 2.40),
- (1947, 5.71, 14.36, 2.01),
- (1946, -8.07, 8.33, 1.64),
- (1945, 36.44, 2.27, 1.67),
- (1944, 19.75, 1.73, 1.86),
- (1943, 25.90, 6.13, 2.05),
- (1942, 20.34, 10.88, 2.36),
- (1941,-11.59, 5.00, 2.10),
- (1940, -9.78, 0.72, 2.76),
- (1939, -0.41, -1.42, 2.76),
- (1938, 31.12, -2.08, 2.94),
- (1937,-35.03, 3.60, 2.76),
- (1936, 33.92, 1.46, 3.39),
- (1935, 47.67, 2.24, 2.76),
- (1934, -1.44, 3.08, 2.76),
- (1933, 53.99, -5.11, 4.71),
- (1932, -8.19, -9.87, 4.71),
- (1931,-43.34, -8.90, 3.99),
- (1930,-24.90, -2.34, 4.71),
- (1929, -8.42, 0.00, 4.27) ]
- mutable_default_parameters.__init__(self)
-
- def report_year(self, year):
- if self.selection_index is None:
- self.selection_index = random.randint(0,
- len(self.historical_tuples) - 1)
- self.selection_duration = 1
-
- t = self.historical_tuples[self.selection_index]
- sim_year = t[0]
- stock_return = t[1]
- inflation = t[2]
- bond_return = t[3]
- print
- print "## REPLAY YEAR %d" % sim_year
- inflation_multiplier = utils.convert_rate_to_multiplier(inflation)
- self.set_average_inflation_multiplier(inflation_multiplier)
- print "## INFLATION is %s (%f)" % (
- utils.format_rate(inflation_multiplier),
- inflation_multiplier)
- ss_multiplier = inflation_multiplier
- if ss_multiplier >= 1.0:
- ss_multiplier -= 1.0
- ss_multiplier *= 0.6666
- ss_multiplier += 1.0
- self.set_average_social_security_multiplier(ss_multiplier)
- print "## SS is %s (%f)" % (
- utils.format_rate(self.get_average_social_security_multiplier()),
- ss_multiplier)
-
- # Assumes 50/50 Stocks/Bonds portfolio
- our_return = (stock_return * 0.5 +
- bond_return * 0.5)
- self.set_average_investment_return_multiplier(utils.convert_rate_to_multiplier(our_return))
- print "## 50/50 INVESTMENTS RETURN is %s" % utils.format_rate(self.get_average_investment_return_multiplier())
- self.selection_duration += 1
- self.selection_index -= 1
- if self.selection_index < 0 or random.randint(1, 100) < 20:
- self.selection_index = None
- self.selection_duration = None
-