Beispiel #1
0
 def test_commonprefix(self):
     self.assertEqual('Assets:US:TD',
                      account.commonprefix(['Assets:US:TD:Checking',
                                            'Assets:US:TD:Savings']))
     self.assertEqual('Assets:US',
                      account.commonprefix(['Assets:US:TD:Checking',
                                            'Assets:US:BofA:Checking']))
     self.assertEqual('Assets',
                      account.commonprefix(['Assets:US:TD:Checking',
                                            'Assets:CA:RBC:Savings']))
     self.assertEqual('',
                      account.commonprefix(['Assets:US:TD:Checking',
                                            'Liabilities:US:CreditCard']))
     self.assertEqual('',
                      account.commonprefix(['']))
Beispiel #2
0
def aggregate_holdings_list(holdings):
    if not holdings:
        return None

    units, total_book_value, total_market_value = ZERO, ZERO, ZERO
    accounts = set()
    currencies = set()
    cost_currencies = set()
    for pos in holdings:
        units += pos.units.number
        accounts.add(pos.account)
        currencies.add(pos.units.currency)
        cost_currencies.add(
            pos.cost.currency if pos.cost else pos.units.currency)

        if pos.cost:
            total_book_value += pos.units.number * pos.cost.number
        else:
            total_book_value += pos.units.number

        if pos.price is not None:
            total_market_value += pos.units.number * pos.price
        else:
            total_market_value += \
                pos.units.number * (pos.cost.number if pos.cost else 1)

    assert len(cost_currencies) == 1

    avg_cost = total_book_value / units if units else None
    avg_price = total_market_value / units if units else None

    currency = currencies.pop() if len(currencies) == 1 else '*'
    cost_currency = cost_currencies.pop()
    account_ = (accounts.pop() if len(accounts) == 1
                else account.commonprefix(accounts))
    show_cost = bool(avg_cost) and cost_currency != currency

    return Posting(
        account_,
        Amount(units, currency),
        Cost(avg_cost, cost_currency, None, None) if show_cost else None,
        avg_price if show_cost else None,
        None,
        None
    )
Beispiel #3
0
def aggregate_holdings_list(holdings):
    if not holdings:
        return None

    units, total_book_value, total_market_value = ZERO, ZERO, ZERO
    accounts = set()
    currencies = set()
    cost_currencies = set()
    for pos in holdings:
        units += pos.units.number
        accounts.add(pos.account)
        currencies.add(pos.units.currency)
        cost_currencies.add(
            pos.cost.currency if pos.cost else pos.units.currency)

        if pos.cost:
            total_book_value += pos.units.number * pos.cost.number
        else:
            total_book_value += pos.units.number

        if pos.price is not None:
            total_market_value += pos.units.number * pos.price
        else:
            total_market_value += \
                pos.units.number * (pos.cost.number if pos.cost else 1)

    assert len(cost_currencies) == 1

    avg_cost = total_book_value / units if units else None
    avg_price = total_market_value / units if units else None

    currency = currencies.pop() if len(currencies) == 1 else '*'
    cost_currency = cost_currencies.pop()
    account_ = (accounts.pop()
                if len(accounts) == 1 else account.commonprefix(accounts))
    show_cost = bool(avg_cost) and cost_currency != currency

    return Posting(
        account_, Amount(units, currency),
        Cost(avg_cost, cost_currency, None, None) if show_cost else None,
        avg_price if show_cost else None, None, None)
Beispiel #4
0
def aggregate_holdings_list(holdings):
    """Aggregate a list of holdings.

    If there are varying 'account', 'currency' or 'cost_currency' attributes,
    their values are replaced by '*'. Otherwise they are preserved. Note that
    all the cost-currency values must be equal in order for aggregations to
    succeed (without this constraint a sum of units in different currencies has
    no meaning).

    Args:
      holdings: A list of Holding instances.
    Returns:
      A single Holding instance, or None, if there are no holdings in the input
      list.
    Raises:
      ValueError: If multiple cost currencies encountered.
    """
    if not holdings:
        return None

    # Note: Holding is a bit overspecified with book and market values. We
    # recompute them from cost and price numbers here anyhow.
    units, total_book_value, total_market_value = ZERO, ZERO, ZERO
    accounts = set()
    currencies = set()
    cost_currencies = set()
    price_dates = set()
    book_value_seen = False
    market_value_seen = False
    for holding in holdings:
        units += holding.number
        accounts.add(holding.account)
        price_dates.add(holding.price_date)
        currencies.add(holding.currency)
        cost_currencies.add(holding.cost_currency)

        if holding.book_value is not None:
            total_book_value += holding.book_value
            book_value_seen = True
        elif holding.cost_number is not None:
            total_book_value += holding.number * holding.cost_number
            book_value_seen = True

        if holding.market_value is not None:
            total_market_value += holding.market_value
            market_value_seen = True
        elif holding.price_number is not None:
            total_market_value += holding.number * holding.price_number
            market_value_seen = True

    if book_value_seen:
        average_cost = total_book_value / units if units else None
    else:
        total_book_value = None
        average_cost = None

    if market_value_seen:
        average_price = total_market_value / units if units else None
    else:
        total_market_value = None
        average_price = None

    if len(cost_currencies) != 1:
        raise ValueError(
            "Cost currencies are not homogeneous for aggregation: {}".format(
                ','.join(map(str, cost_currencies))))

    units = units if len(currencies) == 1 else ZERO
    currency = currencies.pop() if len(currencies) == 1 else '*'
    cost_currency = cost_currencies.pop()
    account_ = (accounts.pop()
                if len(accounts) == 1 else account.commonprefix(accounts))
    price_date = price_dates.pop() if len(price_dates) == 1 else None
    return Holding(account_, units, currency, average_cost, cost_currency,
                   total_book_value, total_market_value, average_price,
                   price_date)