예제 #1
0
 def test_calculate_simple_interest(self):
     print("test_calculate_simple_interest")
     apr = Decimal("48.74")
     capital = Decimal("500.00")
     et_capital = EntryType.objects.get(code=E_CAPITAL)
     entries = [
         AccountEntry(type=et_capital,
                      amount=capital,
                      timestamp=make_datetime(2017, 1, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 3, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 5, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 7, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 9, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 11, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal("-437.50"),
                      timestamp=make_datetime(2018, 1, 1)),
     ]
     timestamp = make_datetime(2018, 1, 1)
     interest = calculate_simple_interest(entries, apr, timestamp.date())
     print("interest =", dec2(interest))
     self.assertEqual(interest.quantize(Decimal("1.00")), Decimal("182.41"))
예제 #2
0
 def test_account(self):
     print("test_account")
     settlements = create_account_by_type(ACCOUNT_SETTLEMENTS)
     assert isinstance(settlements, Account)
     amounts = [12, "13.12", "-1.23", "20.00"]
     balances = [
         Decimal("12.00"),
         Decimal("25.12"),
         Decimal("23.89"),
         Decimal("43.89")
     ]
     t = parse_datetime("2016-06-13T01:00:00")
     dt = timedelta(minutes=5)
     times = [t + dt * i for i in range(len(amounts))]
     for i in range(len(times)):
         amount = amounts[i]
         t = times[i]
         e = AccountEntry(account=settlements,
                          amount=Decimal(amount),
                          type=EntryType.objects.get(code=E_SETTLEMENT),
                          timestamp=t)
         e.full_clean()
         e.save()
         self.assertEqual(settlements.balance, balances[i])
         self.assertEqual(settlements.balance, e.balance)
     for i in range(len(times)):
         t = times[i]
         self.assertEqual(settlements.get_balance(t + timedelta(seconds=1)),
                          balances[i])
예제 #3
0
 def test_calculate_simple_interest2(self):
     print('test_calculate_simple_interest2')
     apr = Decimal('48.74')
     capital = Decimal('500.00')
     et_capital = EntryType.objects.get(code=E_CAPITAL)
     entries = [
         AccountEntry(type=et_capital,
                      amount=capital,
                      timestamp=make_datetime(2017, 1, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 3, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 5, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 7, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 9, 1)),
         AccountEntry(type=et_capital,
                      amount=Decimal(-50),
                      timestamp=make_datetime(2017, 11, 1)),
     ]
     timestamp = make_datetime(2020, 1, 1)
     interest = calculate_simple_interest(entries, apr, timestamp.date())
     print('interest =', dec2(interest))
     self.assertEqual(interest.quantize(Decimal('1.00')), Decimal('426.11'))
예제 #4
0
 def test_calculate_simple_interest3(self):
     print("test_calculate_simple_interest3")
     apr = Decimal("3.00")
     capital = Decimal("500.00")
     et_capital = EntryType.objects.get(code=E_CAPITAL)
     entries = [
         AccountEntry(type=et_capital,
                      amount=capital,
                      timestamp=make_datetime(2018, 1, 10)),
     ]
     interest = calculate_simple_interest(entries,
                                          apr,
                                          date(2018, 3, 1),
                                          begin=date(2018, 2, 10))
     print("interest =", dec2(interest))
     self.assertEqual(interest.quantize(Decimal("1.00")), Decimal("0.78"))
예제 #5
0
def calculate_simple_interest(  # pylint: disable=too-many-locals
    entries,
    rate_pct: Decimal,
    interest_date: Optional[date] = None,
    begin: Optional[date] = None,
) -> Decimal:
    """
    Calculates simple interest of specified entries over time.
    Does not accumulate interest to interest.
    :param entries: AccountEntry iterable (e.g. list/QuerySet) ordered by timestamp (ascending)
    :param rate_pct: Interest rate %, e.g. 8.00 for 8%
    :param interest_date: Interest end date. Default is current date.
    :param begin: Optional begin date for the interest. Default is whole range from the timestamp of account entries.
    :return: Decimal accumulated interest
    """
    if interest_date is None:
        interest_date = now().date()

    bal = None
    cur_date = None
    daily_rate = rate_pct / Decimal(36500)
    accum_interest = Decimal("0.00")
    done = False

    entries_list = list(entries)
    nentries = len(entries_list)
    if nentries > 0:
        # make sure we calculate interest over whole range until interest_date
        last = entries_list[nentries - 1]
        assert isinstance(last, AccountEntry)
        if last.timestamp.date() < interest_date:
            timestamp = pytz.utc.localize(
                datetime.combine(interest_date, time(0, 0)))
            e = AccountEntry(timestamp=timestamp,
                             amount=Decimal("0.00"),
                             type=last.type)
            entries_list.append(e)

        # initial values from the first account entry
        e = entries_list[0]
        bal = e.amount or Decimal("0.00")
        cur_date = e.timestamp.date()
        if begin and begin > cur_date:
            cur_date = begin

    for e in entries_list[1:]:
        assert isinstance(e, AccountEntry)
        next_date = e.timestamp.date()
        if begin and begin > next_date:
            next_date = begin
        if next_date > interest_date:
            next_date = interest_date
            done = True
        assert cur_date
        assert bal is not None
        time_days = (next_date - cur_date).days
        if time_days > 0:
            day_interest = bal * daily_rate
            interval_interest = day_interest * Decimal(time_days)
            accum_interest += interval_interest
            cur_date = next_date
        if e.amount is not None:
            bal += e.amount
        if done:
            break

    return accum_interest