Functional Weave
Code in Rust

invest.dividend-yield@1.0.0

impl/python.py

1,906 bytes · the Python implementation · view raw

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 Sequence

from .invest_dividend_yield_types import DividendYield
from .money_amount import Money, money  ← from money.amount ^1.0.0 · built alongside by fune


def _is_int(value: object) -> bool:
    return isinstance(value, int) and not isinstance(value, bool)


def _basis_points(amount: int, price: int) -> int:
    """amount x 10000 / price, half-up; both 0 or more, price > 0."""
    q, r = divmod(amount * 10000, price)
    return q + 1 if 2 * r >= price else q


def dividend_yield(
    price: Money, trailing_dividends: Sequence[Money], forward_dividend: Money, payments_per_year: int
) -> DividendYield:
    """Trailing yield from the dividends paid in the last twelve months, and
    forward yield from the latest regular dividend annualised, both over the
    current price."""
    currency = price.currency
    if not _is_int(price.minor) or price.minor <= 0:
        raise ValueError("price must be whole minor units greater than zero; received %s" % (price.minor,))
    if not _is_int(payments_per_year) or payments_per_year < 1 or payments_per_year > 52:
        raise ValueError("paymentsPerYear must be a whole number from 1 to 52; received %s" % (payments_per_year,))
    for dividend in list(trailing_dividends) + [forward_dividend]:
        if dividend.currency != currency:
            raise ValueError("currency mismatch: %s and %s" % (currency, dividend.currency))
        if not _is_int(dividend.minor) or dividend.minor < 0:
            raise ValueError("dividends must be whole minor units, 0 or more; received %s" % (dividend.minor,))
    trailing = sum(d.minor for d in trailing_dividends)
    forward = forward_dividend.minor * payments_per_year
    return DividendYield(
        trailing_annual=money(trailing, currency),
        forward_annual=money(forward, currency),
        trailing_basis_points=_basis_points(trailing, price.minor),
        forward_basis_points=_basis_points(forward, price.minor),
    )