Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import List
from .invest_fee_drag_types import FeeDrag, FeeDragYear
from .money_amount import Money, money ← from money.amount ^1.0.0 · built alongside by fune
from .money_apply_rate import apply_rate ← from money.apply-rate ^1.0.0 · built alongside by fune
def _is_int(value: object) -> bool:
return isinstance(value, int) and not isinstance(value, bool)
def fee_drag(
start_value: Money, annual_growth_basis_points: int, annual_fee_basis_points: int, years: int
) -> FeeDrag:
"""The same investment grown twice, with and without an annual charge
taken on the year-end value, rounding to minor units every year as a
statement would."""
if not _is_int(start_value.minor) or start_value.minor < 0:
raise ValueError("startValue must be whole minor units, 0 or more; received %s" % (start_value.minor,))
g = annual_growth_basis_points
if not _is_int(g) or g < -10000:
raise ValueError("annualGrowthBasisPoints must be a whole number, -10000 or more; received %s" % (g,))
f = annual_fee_basis_points
if not _is_int(f) or f < 0 or f > 10000:
raise ValueError("annualFeeBasisPoints must be a whole number from 0 to 10000; received %s" % (f,))
if not _is_int(years) or years < 0 or years > 100:
raise ValueError("years must be a whole number from 0 to 100; received %s" % (years,))
currency = start_value.currency
without = start_value.minor
with_fee = start_value.minor
fees = 0
schedule: List[FeeDragYear] = []
for year in range(1, years + 1):
without += apply_rate(money(without, currency), g, "half-up").minor
grown = with_fee + apply_rate(money(with_fee, currency), g, "half-up").minor
fee = apply_rate(money(grown, currency), f, "half-up").minor
with_fee = grown - fee
fees += fee
schedule.append(
FeeDragYear(
year=year,
value_without_fee=money(without, currency),
value_with_fee=money(with_fee, currency),
fee=money(fee, currency),
)
)
drag = without - with_fee
drag_bp = 0
if without > 0:
n = drag * 10000
q, r = divmod(abs(n), without)
if 2 * r >= without:
q += 1
drag_bp = -q if n < 0 else q
return FeeDrag(
value_without_fee=money(without, currency),
value_with_fee=money(with_fee, currency),
drag=money(drag, currency),
drag_basis_points=drag_bp,
fees_paid=money(fees, currency),
schedule=schedule,
)