import utils class tax_collector(object): def __init__(self): # These four accumulate and then clear every year (i.e. every call # to record_taxes_paid_and_reset_for_next_year) self.ordinary_income = 0 self.short_term_gains = 0 self.dividends_and_long_term_gains = 0 self.roth_income = 0 # The rest of these aggregate and are used as part of the final stats. self.total_tax_bill = 0 self.total_ordinary_income = 0 self.total_short_term_gains = 0 self.total_dividends_and_long_term_gains = 0 self.total_roth_income = 0 self.total_aggregate_income = 0 def record_taxes_paid_and_reset_for_next_year(self, taxes_paid): assert taxes_paid >= 0, "You can't pay negative taxes" self.total_tax_bill += taxes_paid self.total_aggregate_income += self.get_total_income() assert self.total_aggregate_income >= 0, "Accumulator should be >= 0" self.ordinary_income = 0 self.short_term_gains = 0 self.dividends_and_long_term_gains = 0 self.roth_income = 0 def record_ordinary_income(self, amount): assert amount >= 0, "Income should be non-negative" self.ordinary_income += amount self.total_ordinary_income += amount def record_short_term_gain(self, amount): assert amount >= 0, "Income should be non-negative" self.short_term_gains += amount self.total_short_term_gains += amount def record_dividend_or_long_term_gain(self, amount): assert amount >= 0, "Income should be non-negative" self.dividends_and_long_term_gains += amount self.total_dividends_and_long_term_gains += amount def record_roth_income(self, amount): assert amount >= 0, "Income should be non-negative" self.roth_income += amount self.total_roth_income += amount def approximate_taxes(self, standard_deduction, ordinary_income_tax_brackets, dividends_and_long_term_gains_brackets): assert standard_deduction >= 0, "Standard deduction should be non-negative" taxes_due = 0 # Handle ordinary income: ordinary_income = (self.ordinary_income + self.short_term_gains - standard_deduction) if ordinary_income < 0: ordinary_income = 0 taxes_due += ordinary_income_tax_brackets.compute_taxes_for_income( ordinary_income) # Handle dividends and long term gains: taxes_due += dividends_and_long_term_gains_brackets.compute_taxes_for_income( self.dividends_and_long_term_gains) # Assume Roth money is still available tax free in the future. assert taxes_due >= 0, "Computed negative taxes?!" return taxes_due def how_many_more_dollars_can_we_earn_without_changing_tax_rate( self, federal_ordinary_income_tax_brackets): """Return number of ordinary income dollars we can make without changing this year's tax rate. Note: this may return None which actually indicates something more like 'infinite since you're already at the top tax bracket.'""" income = self.ordinary_income if income <= 1: income = 2 b = federal_ordinary_income_tax_brackets.get_bracket_above_income( income) if b[0] is not None: delta = b[0] - income return delta return 0 def get_total_income(self): return (self.ordinary_income + self.short_term_gains + self.dividends_and_long_term_gains + self.roth_income) def dump_final_report(self): print " Taxes and income:" print " {:<50}: {:>14}".format("Total aggregate income", utils.format_money(self.total_aggregate_income)) print " ...{:<47}: {:>14}".format("Ordinary income", utils.format_money(self.total_ordinary_income)) print " ...{:<47}: {:>14}".format("Income from short term gains", utils.format_money(self.total_short_term_gains)) print " ...{:<47}: {:>14}".format("Income from dividends and long term gains", utils.format_money(self.total_dividends_and_long_term_gains)) print " ...{:<47}: {:>14}".format("Roth income", utils.format_money(self.total_roth_income)) print " {:<50}: {:>14}".format("Total taxes paid", utils.format_money(self.total_tax_bill)) overall_tax_rate = float(self.total_tax_bill) / float(self.total_aggregate_income) print " {:<50}: {:>14}".format("Effective tax rate", utils.format_rate(overall_tax_rate))