From cf4f9fcc05eddcaf6d275c61ee8f6ecc1097a416 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Sun, 19 Jan 2020 17:07:28 -0800 Subject: [PATCH] Fix a couple of bugs. Make the simulation run 100x and halt if it ever finds a scenario that causes it to run out of money. Also keep track of max net worth and display it in the final report. --- accounts.py | 2 +- retire.py | 38 +++++++++++++++++++++++++++++++++----- secrets.py | 4 +++- tax_brackets.py | 3 ++- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/accounts.py b/accounts.py index 0e53e04..2ff804d 100644 --- a/accounts.py +++ b/accounts.py @@ -120,7 +120,7 @@ class age_restricted_tax_deferred_account(account): taxes.record_ordinary_income(pretax_part) def deposit(self, amount): - self.pretax_part += amount + self.pretax += amount def appreciate(self, multiplier): old_pretax = self.pretax diff --git a/retire.py b/retire.py index 578869b..fc68655 100755 --- a/retire.py +++ b/retire.py @@ -1,6 +1,7 @@ #!/usr/local/bin/python import sys +import traceback from accounts import * import constants @@ -20,6 +21,7 @@ class simulation(object): self.scott_age = 0 self.alex_age = 0 self.year = 0 + self.max_net_worth = 0 def do_rmd_withdrawals(self, taxes): """Determine if any account that has RMDs will require someone to @@ -129,12 +131,20 @@ class simulation(object): total += x.get_balance() print "{:<50}: {:>14}".format(x.get_name(), x.get_balance()) print "{:<50}: {:>14}\n".format("TOTAL", total) + if self.max_net_worth < total: + self.max_net_worth = total def dump_final_report(self, taxes): print "\nAGGREGATE STATS FINAL REPORT:" + total = money(0) for x in self.accounts: x.dump_final_report() + total += x.get_balance() taxes.dump_final_report() + print " {:<50}: {:>14}".format("Max net worth achieved", + self.max_net_worth) + print "==> {:<50}: {:>14}".format("Final net worth of simulation", + total) def run(self): """Run the simulation!""" @@ -147,6 +157,7 @@ class simulation(object): adjusted_lynn_annual_social_security_dollars = ( self.params.get_initial_social_security_benefit(constants.LYNN)) + try: for self.year in xrange(2020, 2080): self.scott_age = self.year - 1974 @@ -201,7 +212,9 @@ class simulation(object): self.params.get_federal_ordinary_income_tax_brackets(), self.params.get_federal_dividends_and_long_term_gains_income_tax_brackets()) total_income = taxes.get_total_income() - tax_rate = float(taxes_due) / float(total_income) + tax_rate = 0.0 + if total_income > 0: + tax_rate = float(taxes_due) / float(total_income) if (look_for_conversions and tax_rate <= 0.14 and @@ -244,16 +257,31 @@ class simulation(object): adjusted_lynn_annual_social_security_dollars *= ss_multiplier self.params.get_federal_ordinary_income_tax_brackets().adjust_with_multiplier(inflation_multiplier) self.params.get_federal_dividends_and_long_term_gains_income_tax_brackets().adjust_with_multiplier(inflation_multiplier) + succeeded = True except Exception as e: print "Exception: %s" % e + print traceback.print_exc(e) print "Ran out of money!?!" + succeeded = False finally: self.dump_final_report(taxes) + return succeeded # main #params = mutable_default_parameters() -params = mutable_dynamic_historical_parameters() -accounts = secrets.accounts -s = simulation(params, accounts) -s.run() + +params = None +accounts = None +s = None +for x in xrange(1, 100): + del params + del accounts + del s + params = mutable_dynamic_historical_parameters() + accounts = secrets.get_starting_account_list() + s = simulation(params, accounts) + print "====================== Simulation %d ======================" % x + if s.run() == False: + print "This simulation failed!" + sys.exit(0) diff --git a/secrets.py b/secrets.py index dba2524..cedeec5 100644 --- a/secrets.py +++ b/secrets.py @@ -1,2 +1,4 @@ +import accounts -accounts = [ <<< your accounts >>> ] +def get_starting_account_list: + return [ <<< your accounts >>> ] diff --git a/tax_brackets.py b/tax_brackets.py index e0a4660..b2bd4a7 100644 --- a/tax_brackets.py +++ b/tax_brackets.py @@ -1,3 +1,4 @@ +import copy import utils from money import money @@ -5,7 +6,7 @@ class tax_brackets: """A class to represent tax brackets and some operations on them.""" def __init__(self, brackets): - self.brackets = brackets + self.brackets = copy.deepcopy(brackets) def compute_taxes_for_income(self, income): """Compute the tax bill for income given our brackets.""" -- 2.47.1