コード例 #1
0
def get_market_value(pos, price_map, date=None):
    """Get the market value of a Position.

    This differs from the convert.get_value function in Beancount by returning
    the cost value if no price can be found.

    Args:
        pos: A Position.
        price_map: A dict of prices, as built by prices.build_price_map().
        date: A datetime.date instance to evaluate the value at, or None.

    Returns:
        An Amount, with value converted or if the conversion failed just the
        cost value (or the units if the position has no cost).
    """
    units_ = pos.units
    cost_ = pos.cost
    value_currency = cost_.currency if cost_ else None

    if value_currency:
        base_quote = (units_.currency, value_currency)
        _, price_number = get_price(price_map, base_quote, date)
        if price_number is not None:
            return Amount(units_.number * price_number, value_currency)
        return Amount(units_.number * cost_.number, value_currency)
    return units_
コード例 #2
0
 def __call__(self, context):
     warnings.warn("PRICE() is deprecated; use GETPRICE() instead")
     args = self.eval_args(context)
     base, quote, date = args
     pair = (base.upper(), quote.upper())
     _, price = prices.get_price(context.price_map, pair, date)
     return price
コード例 #3
0
ファイル: template_filters.py プロジェクト: adamgibbins/fava
def get_market_value(pos, price_map, date=None):
    """Get the market value of a Position.

    This differs from the convert.get_value function in Beancount by returning
    the cost value if no price can be found.

    Args:
        pos: A Position.
        price_map: A dict of prices, as built by prices.build_price_map().
        date: A datetime.date instance to evaluate the value at, or None.

    Returns:
        An Amount, with value converted or if the conversion failed just the
        cost value (or the units if the position has no cost).
    """
    units_ = pos.units
    cost_ = pos.cost
    value_currency = cost_.currency if cost_ else None

    if value_currency:
        base_quote = (units_.currency, value_currency)
        _, price_number = prices.get_price(price_map, base_quote, date)
        if price_number is not None:
            return Amount(units_.number * price_number, value_currency)
        return Amount(units_.number * cost_.number, value_currency)
    return units_
コード例 #4
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)
コード例 #5
0
def convert_amount(amt, target_currency, price_map, date=None, via=None):
    """Return the market value of an Amount in a particular currency.

    In addition, if a conversion rate isn't available, you can provide a list of
    currencies to attempt to synthesize a rate for via implieds rates.

    Args:
      amt: An instance of Amount.
      target_currency: The target currency to convert to.
      price_map: A dict of prices, as built by prices.build_price_map().
      date: A datetime.date instance to evaluate the value at, or None.
      via: A list of currencies to attempt to synthesize an implied rate if the
        direct conversion fails.
    Returns:
      An Amount, either with a succesful value currency conversion, or if we
      could not convert the value, the amount itself, unmodified.

    """
    # First, attempt to convert directly. This should be the most
    # straightforward conversion.
    base_quote = (amt.currency, target_currency)
    _, rate = prices.get_price(price_map, base_quote, date)
    if rate is not None:
        # On success, just make the conversion directly.
        return Amount(amt.number * rate, target_currency)
    elif via:
        assert isinstance(via, (tuple, list))

        # A price is unavailable, attempt to convert via cost/price currency
        # hop, if the value currency isn't the target currency.
        for implied_currency in via:
            if implied_currency == target_currency:
                continue
            base_quote1 = (amt.currency, implied_currency)
            _, rate1 = prices.get_price(price_map, base_quote1, date)
            if rate1 is not None:
                base_quote2 = (implied_currency, target_currency)
                _, rate2 = prices.get_price(price_map, base_quote2, date)
                if rate2 is not None:
                    return Amount(amt.number * rate1 * rate2, target_currency)

    # We failed to infer a conversion rate; return the amt.
    return amt
コード例 #6
0
def get_value(pos, price_map, date=None, output_date_prices=None):
    """Return the market value of a Position or Posting.

    Note that if the position is not held at cost, this does not convert
    anything, even if a price is available in the 'price_map'. We don't specify
    a target currency here. If you're attempting to make such a conversion, see
    ``convert_*()`` functions below. However, is the object is a posting and it
    has a price, we will use that price to infer the target currency and those
    will be converted.

    Args:
      pos: An instance of Position or Posting, equivalently.
      price_map: A dict of prices, as built by prices.build_price_map().
      date: A datetime.date instance to evaluate the value at, or None.
      output_date_prices: An optional output list of (date, price). If this list
        is provided, it will be appended to (mutated) to output the prices
        pulled in making the conversions.
    Returns:
      An Amount, either with a successful value currency conversion, or if we
      could not convert the value, just the units, unmodified. This is designed
      so that you could reduce an inventory with this and not lose any
      information silently in case of failure to convert (possibly due to an
      empty price map). Compare the returned currency to that of the input
      position if you need to check for success.

    """
    assert isinstance(pos, Position) or type(pos).__name__ == 'Posting'
    units = pos.units
    cost = pos.cost

    # Try to infer what the cost/price currency should be.
    value_currency = ((isinstance(cost, Cost) and cost.currency)
                      or (hasattr(pos, 'price') and pos.price
                          and pos.price.currency) or None)

    if isinstance(value_currency, str):
        # We have a value currency; hit the price database.
        base_quote = (units.currency, value_currency)
        price_date, price_number = prices.get_price(price_map, base_quote,
                                                    date)
        if output_date_prices is not None:
            output_date_prices.append((price_date, price_number))
        if price_number is not None:
            return Amount(units.number * price_number, value_currency)

    # We failed to infer a conversion rate; return the units.
    return units
コード例 #7
0
def generate(entries, options_map, baseCcy):
    errors = []
    priceMap = prices.build_price_map(entries)

    additionalEntries = []
    for entry in entries:
        if isinstance(entry, data.Price) and entry.amount.currency != baseCcy:
            fxRate = prices.get_price(priceMap, tuple([entry.amount.currency, baseCcy]), entry.date)
            priceInBaseCcy = amount.Amount(entry.amount.number * fxRate[1], baseCcy)

            additionalEntries.append(data.Price(
                entry.meta,
                entry.date,
                entry.currency,
                priceInBaseCcy
            ))

    entries.extend(additionalEntries)

    return entries, errors
コード例 #8
0
def add_prices_to_postings(entries, postings):
    """Attach price directives to postings where missing.
    The prices are fetched from the database of entries.

    Args:
      entries: A list of directives containing price directives.
      postings: A list of Posting instances to be augmented.
    Yields:
      A new list of Posting instances with the 'price' attribute filled in.
    """
    # Compute a price map, to extract most current prices.
    price_map = prices.build_price_map(entries)
    for posting in postings:
        if posting.price is None and posting.cost is not None:
            cbase = posting.units.currency
            cquote = posting.cost.currency
            (price_date,
             price_number) = prices.get_price(price_map, (cbase, cquote), None)
            posting = posting._replace(price=amount.Amount(price_number, cquote))
        yield posting
コード例 #9
0
    def _conversion(self, posting):
        currency = (posting.units.currency
                    if posting.cost is None else
                    posting.cost.currency)

        if self.exports.get(currency, None) in 'IGNORE':
            return ZERO

        currency = self.CURRENCY_MAP.get(currency, currency)
        if currency == self.cash_currency:
            # If its already in USD, a noop conversion is x1.
            return str(ONE)
        elif re.match('[A-Z]{3}$', currency):
            # If the instrument is a currency instrument, fetch it live.
            return '=GOOGLEFINANCE("CURRENCY:{}{}")'.format(currency, self.cash_currency)
        else:
            # Otherwise, use the latest value in our file.
            (_, price_number) = prices.get_price(self.price_map,
                                                 (currency, self.cash_currency),
                                                 None)
            return str(price_number)
コード例 #10
0
ファイル: query_env.py プロジェクト: beancount/beanquery
def getprice(context, base, quote, date=None):
    """Fetch a price."""
    pair = (base.upper(), quote.upper())
    _, price = prices.get_price(context.price_map, pair, date)
    return price
コード例 #11
0
ファイル: priceLookup.py プロジェクト: przemator/przbeancount
 def fetchPriceAmount(self, instrument, date):
     price = prices.get_price(self.priceMap,
                              tuple([instrument, self.baseCcy]), date)
     return price[1]
コード例 #12
0
ファイル: holdings.py プロジェクト: edejong/beancount
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.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.units.currency, pos.cost.currency)
                    price_date, price_number = prices.get_price(
                        price_map, base_quote, date)
                    if price_number is not None:
                        market_value = pos.units.number * price_number
                else:
                    price_date, price_number = None, None

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

    return holdings