コード例 #1
0
ファイル: account.py プロジェクト: strager/moneycalc
 def deposit(self, timeline, date, amount, description):
     assert amount >= 0
     assert amount == money(amount)
     if date != self.__next_payment_due:
         raise NotImplementedError()
     current_period = Period(date, add_month(date))
     interest_rate = self.interest_rate.period_interest_rate(current_period)
     interest = money(interest_rate * self.balance)
     if amount < interest:
         raise NotImplementedError()
     # TODO(strager): Ensure minimum monthly payment is met.
     principal = money(amount - interest)
     if principal > self.balance:
         raise NotImplementedError()
     timeline.add_interest_deposit(
         date=date,
         account=self,
         amount=interest,
         description='{} (interest ({:.5}%))'.format(
             description,
             interest_rate * Decimal(12) * Decimal(100)))
     timeline.add_principal_deposit(
         date=date,
         account=self,
         amount=principal,
         description='{} (principal)'.format(description))
     self.balance = money(self.balance - principal)
     self.__next_payment_due = current_period.end_date
コード例 #2
0
ファイル: account.py プロジェクト: strager/moneycalc
    def __update_finance_charge(self, date):
        '''
        Accrue finance charges for all days before (but not including) the
        given date.

        Also, mark finance charges as due as necessary.
        '''
        if self.__last_update is None:
            assert self.__balance == money(0)
            return
        now = self.__last_update
        while now < date:
            if now.day == 1:
                # TODO(strager): Ensure __due_finance_charge is paid within the payment window.
                if self.__due_finance_charge != money(0):
                    raise NotImplementedError()
                self.__due_finance_charge = self.__period_finance_charge
                self.__period_finance_charge = money(0)
            tomorrow = now + datetime.timedelta(days=1)
            if self.__balance < money(0):
                if now in self.__draw_term:
                    interest_rate = self.__interest_rate.period_interest_rate(
                        Period(now, tomorrow))
                    finance_charge = money(interest_rate * -self.__balance)
                    self.__period_finance_charge += finance_charge
                elif now in self.__repayment_term:
                    raise NotImplementedError()
                else:
                    raise NotImplementedError()
            self.__last_update = tomorrow
            now = tomorrow
        assert self.__last_update == date
コード例 #3
0
ファイル: account.py プロジェクト: strager/moneycalc
 def __init__(self, name, interest_rate, draw_term, repayment_term):
     super(LineOfCreditAccount, self).__init__(name=name)
     self.__interest_rate = interest_rate
     self.__draw_term = draw_term
     self.__repayment_term = repayment_term
     self.__balance = money(0)
     self.__period_finance_charge = money(0)
     self.__due_finance_charge = money(0)
     self.__last_update = None
コード例 #4
0
ファイル: tax.py プロジェクト: strager/moneycalc
def tax_due(events, year):
    taxable_cash_income = sum(event.amount for event in events if event.tax_effect == TaxEffect.CASH_INCOME)
    withheld_cash = sum(-event.amount for event in events if event.tax_effect == TaxEffect.CASH_WITHHELD)
    deductible = sum(abs(event.amount) for event in events if event.tax_effect == TaxEffect.DEDUCTIBLE)
    tax_rate = us_tax_rate(year=year, amount=taxable_cash_income) + ca_tax_rate(year=year, amount=taxable_cash_income)
    taxable_income = max((taxable_cash_income - deductible, money(0)))
    total_due = money(taxable_income * tax_rate)
    net_due = total_due - withheld_cash
    return net_due
コード例 #5
0
ファイル: account.py プロジェクト: strager/moneycalc
 def deposit(self, timeline, date, amount, description):
     assert amount >= 0
     assert amount == money(amount)
     assert self.__last_update is None or date >= self.__last_update
     timeline.add_generic_deposit(date=date,
                                  account=self,
                                  amount=amount,
                                  description=description)
     self.__balance = money(self.__balance + amount)
     self.__last_update = date
コード例 #6
0
    def play(self):
        start_date = datetime.date(year=2017, month=1, day=1)
        end_date = datetime.date(year=2047, month=1, day=1)
        home_purchase_date = datetime.date(2017, 1, 1)
        home_purchase_amount = money('1200000.00')
        home_loan_amount = money('975000.00')
        home_appraisal_amount = home_purchase_amount

        self.timeline = moneycalc.timeline.Timeline()

        funcs = [
            self.__iter_year_summary_funcs(timeline=self.timeline,
                                           start_date=start_date),
            [(home_purchase_date,
              lambda date: self.purchase_home(date, home_loan_amount))],
            iter_tax_payment_funcs(timeline=self.timeline,
                                   start_date=start_date,
                                   account=self.primary_account),
            iter_salary_funcs(timeline=self.timeline,
                              start_date=start_date,
                              to_account=self.primary_account),
            iter_expenses_funcs(timeline=self.timeline,
                                start_date=start_date,
                                account=self.primary_account),
            iter_property_expense_funcs(timeline=self.timeline,
                                        start_date=start_date,
                                        account=self.primary_account,
                                        home_value=home_appraisal_amount),
            self.iter_activity_funcs(),
        ]
        for (date, func) in moneycalc.util.iter_merge_sort(funcs,
                                                           key=lambda
                                                           (date, func): date):
            if date > end_date:
                break
            try:
                func(date)
            except NotImplementedError:
                traceback.print_exc()
                break

        print_timeline = False
        if print_timeline:
            sys.stdout.write('Timeline:\n\n')
            for event in self.timeline:
                sys.stdout.write('{}\n'.format(event))

        self.timeline = None
コード例 #7
0
 def tax_func(date):
     amount = money(home_value * tax_rate / 2)
     account.withdraw(timeline=timeline,
                      date=date,
                      amount=amount,
                      description='Property tax',
                      tax_effect=TaxEffect.DEDUCTIBLE)
コード例 #8
0
ファイル: account.py プロジェクト: strager/moneycalc
 def __init__(self, name, amount, interest_rate, term):
     super(AmortizedMonthlyLoan, self).__init__(name=name)
     assert amount == money(amount)
     self.balance = amount
     self.interest_rate = interest_rate
     self.term = term
     self.__next_payment_due = term.start_date
     self.__maturity_date = sub_month(self.term.end_date)
コード例 #9
0
ファイル: account.py プロジェクト: strager/moneycalc
 def minimum_deposit(self, date):
     if date > self.__maturity_date:
         raise NotImplementedError()
     if date != self.__next_payment_due:
         raise NotImplementedError()
     current_period = Period(date, add_month(date))
     interest_rate = self.interest_rate.period_interest_rate(current_period)
     if date == self.__maturity_date:
         interest = money(interest_rate * self.balance)
         return money(interest + self.balance)
     else:
         months_remaining = moneycalc.time.diff_months(
             self.term.end_date, current_period.start_date)
         tmp = Decimal(
             math.pow(Decimal(1) + interest_rate, months_remaining))
         return money(self.balance * (interest_rate * tmp) /
                      (tmp - Decimal(1)))
コード例 #10
0
ファイル: account.py プロジェクト: strager/moneycalc
 def withdraw(self,
              timeline,
              date,
              amount,
              description,
              tax_effect=TaxEffect.NONE):
     assert amount >= 0
     assert amount == money(amount)
     assert self.__last_update is None or date >= self.__last_update
     if amount > self.__balance:
         raise OverdraftError()
     timeline.add_withdrawl(date=date,
                            account=self,
                            amount=amount,
                            description=description,
                            tax_effect=tax_effect)
     self.__balance = money(self.__balance - amount)
     self.__last_update = date
コード例 #11
0
 def iter_half_bonus_income_funcs():
     year = start_date.year
     while True:
         q1 = datetime.date(year=year, month=1, day=1)
         q3 = datetime.date(year=year, month=7, day=1)
         for now in [q1, q3]:
             if now >= start_date:
                 yield (
                     now,
                     lambda date: receive_income(date, money('14728.95')))
         year += 1
コード例 #12
0
ファイル: account.py プロジェクト: strager/moneycalc
 def withdraw(self,
              timeline,
              date,
              amount,
              description,
              tax_effect=TaxEffect.NONE):
     assert amount >= 0
     assert amount == money(amount)
     assert self.__last_update is None or date >= self.__last_update
     if date not in self.__draw_term:
         # TODO(strager)
         #raise OverdraftError()
         pass
     self.__update_finance_charge(date)
     timeline.add_withdrawl(date=date,
                            account=self,
                            amount=amount,
                            description=description,
                            tax_effect=tax_effect)
     self.__balance = money(self.__balance - amount)
     self.__last_update = date
コード例 #13
0
 def iter_quarter_bonus_income_funcs():
     year = start_date.year
     while True:
         q1 = datetime.date(year=year, month=1, day=1)
         q2 = datetime.date(year=year, month=4, day=1)
         q3 = datetime.date(year=year, month=7, day=1)
         q4 = datetime.date(year=year, month=10, day=1)
         for now in [q1, q2, q3, q3]:
             if now >= start_date:
                 yield (
                     now,
                     lambda date: receive_income(date, money('18750.00')))
         year += 1
コード例 #14
0
ファイル: account.py プロジェクト: strager/moneycalc
 def deposit(self, timeline, date, amount, description):
     assert amount >= 0
     assert amount == money(amount)
     assert self.__last_update is None or date >= self.__last_update
     self.__update_finance_charge(date)
     principal_amount = amount
     if self.__due_finance_charge > money(0):
         # Pay the finance charge due before paying the principal.
         finance_charge_payment = min(self.__due_finance_charge, amount)
         if finance_charge_payment > money(0):
             timeline.add_interest_deposit(
                 date=date,
                 account=self,
                 amount=finance_charge_payment,
                 description='{} (interest)'.format(description))
             self.__due_finance_charge -= finance_charge_payment
             principal_amount -= finance_charge_payment
     timeline.add_generic_deposit(date=date,
                                  account=self,
                                  amount=principal_amount,
                                  description=description)
     self.__balance = money(self.__balance + principal_amount)
     self.__last_update = date
コード例 #15
0
    def receive_income(date, gross_income):
        withheld_401k = money(0)  # TODO(strager)
        taxable_income = gross_income - withheld_401k
        withheld_us_income_tax = money(taxable_income *
                                       Decimal(0.215))  # FIXME(strager)
        withheld_ca_income_tax = money(taxable_income *
                                       Decimal(0.080))  # FIXME(strager)
        other_tax = money(taxable_income * Decimal(0.15))  # FIXME(strager)
        net_income = gross_income - withheld_401k - withheld_us_income_tax - withheld_ca_income_tax - other_tax
        # TODO(strager): 401k.

        timeline.add_withheld_cash(date=date,
                                   amount=withheld_us_income_tax,
                                   description='Salary (withheld US tax)')
        timeline.add_withheld_cash(date=date,
                                   amount=withheld_ca_income_tax,
                                   description='Salary (withheld CA tax)')
        timeline.add_income(date=date,
                            amount=taxable_income,
                            description='Salary (taxable)')
        to_account.deposit(timeline=timeline,
                           date=date,
                           amount=net_income,
                           description='Salary (net)')
コード例 #16
0
    def iter_activity_funcs(self):
        yield (datetime.date(2017, 1, 1),
               lambda date: self.__checking.deposit(timeline=self.timeline,
                                                    date=date,
                                                    amount=money('5000.00'),
                                                    description='Tooth fairy'))

        def mortgage_payment_func(date):
            payment = self.__home_loan.minimum_deposit(date=date)
            moneycalc.account.transfer(timeline=self.timeline,
                                       date=date,
                                       from_account=self.__checking,
                                       to_account=self.__home_loan,
                                       amount=payment,
                                       description='{} payment'.format(
                                           self.__home_loan))

        now = datetime.date(2017, 1, 1)  # FIXME(strager)
        while now < datetime.date(2047, 1, 1):  # FIXME(strager)
            yield (now, mortgage_payment_func)
            now = moneycalc.time.add_month(now)
コード例 #17
0
 def expenses_func(date):
     account.withdraw(timeline=timeline,
                      date=date,
                      amount=money('1873.61'),
                      description='Expenses')
コード例 #18
0
 def iter_base_salary_income_funcs():
     now = start_date
     while True:
         yield (now, lambda date: receive_income(date, money('7553.31')))
         now += datetime.timedelta(days=2 * 7)
コード例 #19
0
ファイル: account.py プロジェクト: strager/moneycalc
 def __init__(self, name):
     super(CheckingAccount, self).__init__(name=name)
     self.__balance = money(0)
     self.__last_update = None
コード例 #20
0
 def insurance_func(date):
     account.withdraw(timeline=timeline,
                      date=date,
                      amount=money('1000.00'),
                      description='Home insurance')
コード例 #21
0
 def auto_func(date):
     account.withdraw(timeline=timeline,
                      date=date,
                      amount=money('2225.70'),
                      description='Auto')