Beispiel #1
0
def convert_inventory(price_map, target_currency, inventory, date):
    """Convert and sum an inventory to a common currency.

    Returns:
      A Decimal, the sum of all positions that could be converted.
    """

    total = ZERO

    for pos in inventory:
        # Fetch the price in the cost currency if there is one.
        if pos.cost:
            base_quote = (pos.units.currency, pos.cost.currency)
            _, cost_number = prices.get_price(price_map, base_quote, date)
            if cost_number is None:
                cost_number = pos.cost.number
            currency = pos.cost.currency
        # Otherwise, price it in its own currency.
        else:
            cost_number = 1
            currency = pos.units.currency
        if currency == target_currency:
            total += pos.units.number * cost_number
        else:
            base_quote = (currency, target_currency)

            # Get the conversion rate.
            _, price = prices.get_price(price_map, base_quote, date)
            if price is not None:
                total += pos.units.number * cost_number * price
    return total
Beispiel #2
0
def convert_inventory(price_map, target_currency, inventory, date):
    """Convert and sum an inventory to a common currency.

    Returns:
      A Decimal, the sum of all positions that could be converted.
    """

    total = ZERO

    for pos in inventory:
        # Fetch the price in the cost currency if there is one.
        if pos.cost:
            base_quote = (pos.units.currency, pos.cost.currency)
            _, cost_number = prices.get_price(price_map, base_quote, date)
            if cost_number is None:
                cost_number = pos.cost.number
            currency = pos.cost.currency
        # Otherwise, price it in its own currency.
        else:
            cost_number = 1
            currency = pos.units.currency
        if currency == target_currency:
            total += pos.units.number * cost_number
        else:
            base_quote = (currency, target_currency)

            # Get the conversion rate.
            _, price = prices.get_price(price_map, base_quote, date)
            if price is not None:
                total += pos.units.number * cost_number * price
    return total
Beispiel #3
0
def get_final_holdings(entries,
                       included_account_types=None,
                       price_map=None,
                       date=None):
    """Get a list of holdings by account (as Postings)."""

    simple_entries = [
        entry for entry in entries if (not isinstance(entry, Transaction)
                                       or entry.flag != flags.FLAG_UNREALIZED)
    ]

    root_account = realization.realize(simple_entries)

    holdings = []

    for real_account in sorted(list(realization.iter_children(root_account)),
                               key=lambda ra: ra.account):
        account_type = account_types.get_account_type(real_account.account)
        if (included_account_types
                and account_type not in included_account_types):
            continue
        for pos in real_account.balance:
            price = None
            if pos.cost and price_map:
                base_quote = (pos.units.currency, pos.cost.currency)
                _, price = prices.get_price(price_map, base_quote, date)
            holdings.append(
                Posting(real_account.account, pos.units, pos.cost, price, None,
                        None))

    return holdings
Beispiel #4
0
def get_holding_from_position(lot,
                              number,
                              account=None,
                              price_map=None,
                              date=None):
    """Compute a Holding corresponding to the specified position 'pos'.

    :param lot: A Lot object.
    :param number: The number of units of 'lot' in the position.
    :param account: A str, the name of the account, or None if not needed.
    :param price_map: A dict of prices, as built by prices.build_price_map().
    :param date: A datetime.date instance, the date at which to price the
        holdings.  If left unspecified, we use the latest price information.

    :return: A Holding object.
    """
    if lot.cost is not None:
        # Get price information if we have a price_map.
        market_value = None
        if price_map is not None:
            base_quote = (lot.currency, lot.cost.currency)
            price_date, price_number = prices.get_price(
                price_map, base_quote, date)
            if price_number is not None:
                market_value = number * price_number
        else:
            price_date, price_number = None, None

        return Holding(account, number, lot.currency, lot.cost.number,
                       lot.cost.currency, number * lot.cost.number,
                       market_value, price_number, price_date)
    else:
        return Holding(account, number, lot.currency, None, lot.currency,
                       number, number, None, None)
Beispiel #5
0
def get_final_holdings(entries, included_account_types=None, price_map=None,
                       date=None):
    """Get a list of holdings by account (as Postings)."""

    simple_entries = [entry for entry in entries
                      if (not isinstance(entry, Transaction) or
                          entry.flag != flags.FLAG_UNREALIZED)]

    root_account = realization.realize(simple_entries)

    holdings = []

    for real_account in sorted(list(realization.iter_children(root_account)),
                               key=lambda ra: ra.account):
        account_type = account_types.get_account_type(real_account.account)
        if (included_account_types and
                account_type not in included_account_types):
            continue
        for pos in real_account.balance:
            price = None
            if pos.cost and price_map:
                base_quote = (pos.units.currency, pos.cost.currency)
                _, price = prices.get_price(price_map, base_quote, date)
            holdings.append(Posting(real_account.account,
                                    pos.units,
                                    pos.cost,
                                    price, None, None))

    return holdings
Beispiel #6
0
    def test_get_price(self, entries, _, __):
        """
        2013-06-01 price  USD  1.00 CAD
        2013-06-10 price  USD  1.50 CAD
        2013-07-01 price  USD  2.00 CAD
        """
        price_map = prices.build_price_map(entries)

        date, price = prices.get_price(price_map, 'USD/CAD',
                                       datetime.date(2013, 5, 15))
        self.assertEqual(None, price)
        self.assertEqual(None, date)

        date, price = prices.get_price(price_map, 'USD/CAD',
                                       datetime.date(2013, 6, 1))
        self.assertEqual(D('1.00'), price)
        self.assertEqual(datetime.date(2013, 6, 1), date)

        date, price = prices.get_price(price_map, 'USD/CAD',
                                       datetime.date(2013, 6, 5))
        self.assertEqual(D('1.00'), price)
        self.assertEqual(datetime.date(2013, 6, 1), date)

        date, price = prices.get_price(price_map, 'USD/CAD',
                                       datetime.date(2013, 6, 10))
        self.assertEqual(D('1.50'), price)
        self.assertEqual(datetime.date(2013, 6, 10), date)

        date, price = prices.get_price(price_map, 'USD/CAD',
                                       datetime.date(2013, 6, 20))
        self.assertEqual(D('1.50'), price)
        self.assertEqual(datetime.date(2013, 6, 10), date)

        date, price = prices.get_price(price_map, 'USD/CAD',
                                       datetime.date(2013, 7, 1))
        self.assertEqual(D('2.00'), price)
        self.assertEqual(datetime.date(2013, 7, 1), date)

        date, price = prices.get_price(price_map, 'USD/CAD',
                                       datetime.date(2013, 7, 15))
        self.assertEqual(D('2.00'), price)
        self.assertEqual(datetime.date(2013, 7, 1), date)

        # With no date, should devolved to get_latest_price().
        date, price = prices.get_price(price_map, 'USD/CAD', None)
        self.assertEqual(D('2.00'), price)
        self.assertEqual(datetime.date(2013, 7, 1), date)

        # Test not found.
        result = prices.get_price(price_map, ('EWJ', 'JPY'))
        self.assertEqual((None, None), result)
Beispiel #7
0
def get_holding_from_position(lot, number, account=None, price_map=None, date=None):
    """Compute a Holding corresponding to the specified position 'pos'.

    :param lot: A Lot object.
    :param number: The number of units of 'lot' in the position.
    :param account: A str, the name of the account, or None if not needed.
    :param price_map: A dict of prices, as built by prices.build_price_map().
    :param date: A datetime.date instance, the date at which to price the
        holdings.  If left unspecified, we use the latest price information.

    :return: A Holding object.
    """
    if lot.cost is not None:
        # Get price information if we have a price_map.
        market_value = None
        if price_map is not None:
            base_quote = (lot.currency, lot.cost.currency)
            price_date, price_number = prices.get_price(price_map,
                                                        base_quote, date)
            if price_number is not None:
                market_value = number * price_number
        else:
            price_date, price_number = None, None

        return Holding(account,
                       number,
                       lot.currency,
                       lot.cost.number,
                       lot.cost.currency,
                       number * lot.cost.number,
                       market_value,
                       price_number,
                       price_date)
    else:
        return Holding(account,
                       number,
                       lot.currency,
                       None,
                       lot.currency,
                       number,
                       number,
                       None,
                       None)
Beispiel #8
0
def get_holding_from_position(position, price_map=None, date=None):
    """Compute a Holding corresponding to the specified position 'pos'.

    :param position: A Position object.
    :param price_map: A dict of prices, as built by prices.build_price_map().
    :param date: A datetime.date instance, the date at which to price the
        holdings.  If left unspecified, we use the latest price information.

    :return: A Holding object.
    """
    if position.cost is not None:
        # Get price information if we have a price_map.
        market_value = None
        if price_map is not None:
            base_quote = (position.units.currency, position.cost.currency)
            price_date, price_number = prices.get_price(price_map,
                                                        base_quote, date)
            if price_number is not None:
                market_value = position.units.number * price_number
        else:
            price_date, price_number = None, None

        return Holding(None,
                       position.units.number,
                       position.units.currency,
                       position.cost.number,
                       position.cost.currency,
                       position.units.number * position.cost.number,
                       market_value,
                       price_number,
                       price_date)
    else:
        return Holding(None,
                       position.units.number,
                       position.units.currency,
                       None,
                       position.units.currency,
                       position.units.number,
                       position.units.number,
                       None,
                       None)
Beispiel #9
0
def get_final_holdings(entries,
                       included_account_types=None,
                       price_map=None,
                       date=None):
    """Get a dictionary of the latest holdings by account.

    This basically just flattens the balance sheet's final positions, including
    that of equity accounts. If a 'price_map' is provided, insert price
    information in the flattened holdings at the latest date, or at the given
    date, if one is provided.

    Only the accounts in 'included_account_types' will be included, and this is
    always called for Assets and Liabilities only. If left unspecified, holdings
    from all account types will be included, including Equity, Income and
    Expenses.

    Args:
      entries: A list of directives.
      included_account_types: A sequence of strings, the account types to
        include in the output. A reasonable example would be
        ('Assets', 'Liabilities'). If not specified, include all account types.
      price_map: A dict of prices, as built by prices.build_price_map().
      date: A datetime.date instance, the date at which to price the
        holdings. If left unspecified, we use the latest price information.
    Returns:
      A list of dicts, with the following fields:
    """
    # Remove the entries inserted by unrealized gains/losses. Those entries do
    # affect asset accounts, and we don't want them to appear in holdings.
    #
    # Note: Perhaps it would make sense to generalize this concept of "inserted
    # unrealized gains."
    simple_entries = [
        entry for entry in entries if (not isinstance(entry, data.Transaction)
                                       or entry.flag != flags.FLAG_UNREALIZED)
    ]

    # Realize the accounts into a tree (because we want the positions by-account).
    root_account = realization.realize(simple_entries)

    # For each account, look at the list of positions and build a list.
    holdings = []
    for real_account in sorted(list(realization.iter_children(root_account)),
                               key=lambda ra: ra.account):

        if included_account_types:
            # Skip accounts of invalid types, we only want to reflect the requested
            # account types, typically assets and liabilities.
            account_type = account_types.get_account_type(real_account.account)
            if account_type not in included_account_types:
                continue

        for pos in real_account.balance.get_positions():
            if pos.lot.cost is not None:
                # Get price information if we have a price_map.
                market_value = None
                if price_map is not None:
                    base_quote = (pos.lot.currency, pos.lot.cost.currency)
                    price_date, price_number = prices.get_price(
                        price_map, base_quote, date)
                    if price_number is not None:
                        market_value = pos.number * price_number
                else:
                    price_date, price_number = None, None

                holding = Holding(real_account.account, pos.number,
                                  pos.lot.currency, pos.lot.cost.number,
                                  pos.lot.cost.currency,
                                  pos.number * pos.lot.cost.number,
                                  market_value, price_number, price_date)
            else:
                holding = Holding(real_account.account, pos.number,
                                  pos.lot.currency, None, pos.lot.currency,
                                  pos.number, pos.number, None, None)
            holdings.append(holding)

    return holdings