def balances(keyword):
    "Show balances across all accounts"

    buchfink_db = BuchfinkDB()
    balances_sum = {}
    usd_value_sum = {}

    for account in buchfink_db.get_all_accounts():
        if keyword is not None and keyword not in account['name']:
            continue

        if 'exchange' in account:
            exchange = buchfink_db.get_exchange(account['name'])

            api_key_is_valid, error = exchange.validate_api_key()

            if not api_key_is_valid:
                logger.critical(
                    'Skipping exchange %s because API key is not valid (%s)',
                    account['name'], error)
                continue

            balances, error = exchange.query_balances()

            if not error:
                logger.info('Fetched balances for %d assets from %s',
                            len(balances.keys()), account['name'])
                for asset, balance in balances.items():
                    amount = balance['amount']
                    balances_sum[asset] = balances_sum.get(asset,
                                                           FVal(0)) + amount
                    if 'usd_value' in balance:
                        usd_value_sum[asset] = usd_value_sum.get(
                            asset, FVal(0)) + balance['usd_value']

        elif 'ethereum' in account:
            manager = buchfink_db.get_chain_manager(account)
            manager.query_balances()

            for eth_balance in manager.balances.eth.values():
                for asset, balance in eth_balance.asset_balances.items():
                    amount = balance.amount
                    balances_sum[asset] = balances_sum.get(asset,
                                                           FVal(0)) + amount
                    usd_value_sum[asset] = usd_value_sum.get(
                        asset, FVal(0)) + balance.usd_value

        elif 'bitcoin' in account:
            manager = buchfink_db.get_chain_manager(account)
            manager.query_balances()
            asset = Asset('BTC')

            for balance in manager.balances.btc.values():
                amount = balance.amount
                balances_sum[asset] = balances_sum.get(asset, FVal(0)) + amount
                usd_value_sum[asset] = usd_value_sum.get(
                    asset, FVal(0)) + balance.usd_value

        elif 'file' in account:

            account = yaml.load(open(account['file'], 'r'),
                                Loader=yaml.SafeLoader)
            if 'balances' in account:
                for balance in account['balances']:
                    amount = FVal(balance['amount'])
                    asset = Asset(balance['asset'])
                    usd_value = amount * buchfink_db.inquirer.find_usd_price(
                        asset)
                    balances_sum[asset] = balances_sum.get(asset,
                                                           FVal(0)) + amount
                    usd_value_sum[asset] = usd_value_sum.get(
                        asset, FVal(0)) + usd_value

    currency = buchfink_db.get_main_currency()
    currency_in_usd = buchfink_db.inquirer.find_usd_price(currency)

    table = []
    assets = [
        obj[0] for obj in sorted(
            usd_value_sum.items(), key=itemgetter(1), reverse=True)
    ]
    balance_in_currency_sum = 0

    for asset in assets:
        balance = balances_sum[asset]
        balance_in_currency = usd_value_sum.get(asset,
                                                FVal(0)) / currency_in_usd
        balance_in_currency_sum += balance_in_currency
        table.append([
            asset, balance, asset.symbol,
            round(float(balance_in_currency), 2)
        ])
    table.append(
        ['Total', None, None,
         round(float(balance_in_currency_sum), 2)])
    print(
        tabulate(table,
                 headers=[
                     'Asset', 'Amount', 'Symbol',
                     'Fiat Value (%s)' % currency.symbol
                 ]))
Beispiel #2
0
def fetch_(keyword, account_type, fetch_actions, fetch_balances, fetch_trades, external):
    "Fetch trades for configured accounts"

    buchfink_db = BuchfinkDB()
    buchfink_db.perform_assets_updates()
    now = ts_now()
    fetch_limited = fetch_actions or fetch_balances or fetch_trades

    if external:
        accounts = [account_from_string(ext, buchfink_db) for ext in external]
    else:
        accounts = buchfink_db.get_all_accounts()

    # TODO: This should move to BuchfinkDB.get_accounts()
    if keyword is not None:
        if keyword.startswith('/') and keyword.endswith('/'):
            keyword_re = re.compile(keyword[1:-1])
            accounts = [acc for acc in accounts if keyword_re.search(acc.name)]
        else:
            accounts = [acc for acc in accounts if keyword in acc.name]

    logger.info(
            'Collected %d account(s): %s',
            len(accounts),
            ', '.join([acc.name for acc in accounts])
        )

    for account in accounts:
        if account_type is not None and account_type not in account.account_type:
            continue

        name = account.name
        trades = []
        actions = []

        if account.account_type == "ethereum":

            if not fetch_limited or fetch_actions:
                logger.info('Analyzing ethereum transactions for %s', name)
                manager = buchfink_db.get_chain_manager(account)

                txs = manager.ethereum.transactions.single_address_query_transactions(
                        account.address,
                        start_ts=0,
                        end_ts=now,
                        with_limit=False,
                        only_cache=False
                )

                for txn in txs:
                    tx_hash = '0x' + txn.tx_hash.hex()
                    receipt = buchfink_db.get_ethereum_transaction_receipt(tx_hash, manager)

                    acc_actions = classify_tx(account, tx_hash, txn, receipt)
                    if actions:
                        for act in actions:
                            logger.debug('Found action: %s', act)
                    actions.extend(acc_actions)

            if not fetch_limited or fetch_trades:
                logger.info('Fetching uniswap trades for %s', name)

                manager = buchfink_db.get_chain_manager(account)

                trades = manager.eth_modules['uniswap'].get_trades(
                        addresses=manager.accounts.eth,
                        from_timestamp=int(epoch_start_ts),
                        to_timestamp=int(epoch_end_ts),
                        only_cache=False
                    )

        elif account.account_type == "exchange":

            if not fetch_limited or fetch_trades:
                logger.info('Fetching exhange trades for %s', name)

                exchange = buchfink_db.get_exchange(name)

                api_key_is_valid, error = exchange.validate_api_key()

                if not api_key_is_valid:
                    logger.critical(
                            'Skipping exchange %s because API key is not valid (%s)',
                            account.name,
                            error
                    )

                else:
                    trades = exchange.query_online_trade_history(
                        start_ts=epoch_start_ts,
                        end_ts=epoch_end_ts
                    )

        else:
            logger.debug('No way to retrieve trades for %s, yet', name)

        annotations_path = "annotations/" + name + ".yaml"

        if not fetch_limited or fetch_actions:

            if os.path.exists(annotations_path):
                annotated = buchfink_db.get_actions_from_file(annotations_path)
            else:
                annotated = []

            logger.info('Fetched %d action(s) (%d annotated) from %s',
                    len(actions) + len(annotated), len(annotated), name)
            actions.extend(annotated)

            if actions:
                with open("actions/" + name + ".yaml", "w") as yaml_file:
                    yaml.dump({
                        "actions": serialize_ledger_actions(actions)
                    }, stream=yaml_file, sort_keys=True)

        if not fetch_limited or fetch_trades:
            if os.path.exists(annotations_path):
                annotated = buchfink_db.get_trades_from_file(annotations_path)
            else:
                annotated = []

            logger.info('Fetched %d trades(s) (%d annotated) from %s',
                    len(trades) + len(annotated), len(annotated), name)

            trades.extend(annotated)

            with open("trades/" + name + ".yaml", "w") as yaml_file:
                yaml.dump({
                    "trades": serialize_trades(trades)
                }, stream=yaml_file, sort_keys=True)

        if not fetch_limited or fetch_balances:
            buchfink_db.fetch_balances(account)

            logger.info('Fetched balances from %s', name)