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"))
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])
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'))
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"))
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