Functional Weave
Code in Rust

finance.fx-revaluation@1.0.0

impl/python.py

1,916 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 List, Sequence

from .finance_fx_revaluation_types import ForeignBalance, FxRevaluation, RevaluedBalance
from .money_add import add_money, subtract_money  ← from money.add ^1.0.0 · built alongside by fune
from .money_amount import money  ← from money.amount ^1.0.0 · built alongside by fune
from .money_convert import convert_money  ← from money.convert ^1.0.0 · built alongside by fune
from .money_convert_types import ExchangeRate


def fx_revaluation(
    balances: Sequence[ForeignBalance], rates: Sequence[ExchangeRate], functional_currency: str
) -> FxRevaluation:
    """Revalue foreign-currency balances at the closing rates and report the
    unrealised gain (positive) or loss (negative) on each and in total.
    """
    net = money(0, functional_currency)
    lines: List[RevaluedBalance] = []
    for item in balances:
        foreign = item.balance.currency
        if foreign == functional_currency:
            raise ValueError("account %s is already in %s" % (item.account, functional_currency))
        if item.booked_value.currency != functional_currency:
            raise ValueError("booked value of account %s must be in %s" % (item.account, functional_currency))
        matching = [r for r in rates if r.base == foreign and r.quote == functional_currency]
        if len(matching) == 0:
            raise ValueError("no period-end rate from %s to %s" % (foreign, functional_currency))
        if len(matching) > 1:
            raise ValueError("more than one period-end rate from %s to %s" % (foreign, functional_currency))
        revalued = convert_money(item.balance, matching[0], "half-up")
        gain_loss = subtract_money(revalued, item.booked_value)
        lines.append(
            RevaluedBalance(
                account=item.account,
                balance=item.balance,
                booked_value=item.booked_value,
                revalued_value=revalued,
                gain_loss=gain_loss,
            )
        )
        net = add_money(net, gain_loss)
    return FxRevaluation(lines=lines, net_gain_loss=net)