From: Scott Gasch <scott@gasch.org>
Date: Mon, 20 Jan 2020 01:07:28 +0000 (-0800)
Subject: Fix a couple of bugs.  Make the simulation run 100x and halt if
X-Git-Url: https://wannabe.guru.org/gitweb/?a=commitdiff_plain;h=cf4f9fcc05eddcaf6d275c61ee8f6ecc1097a416;p=retire.git

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.
---

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."""