From 1870de8109b31087ea9ee14e1b9f87d4c57c1ed8 Mon Sep 17 00:00:00 2001 From: Jon Michael Aanes Date: Tue, 4 Jun 2024 22:14:11 +0200 Subject: [PATCH] Nordnet supports basic stocks now. (Works for me!) Index funds are still WIP --- fin_depo/investbank_nordnet.py | 59 +++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/fin_depo/investbank_nordnet.py b/fin_depo/investbank_nordnet.py index d73eec9..a36be06 100644 --- a/fin_depo/investbank_nordnet.py +++ b/fin_depo/investbank_nordnet.py @@ -15,7 +15,7 @@ from decimal import Decimal import fin_defs -from .data import Depo, DepoSingle +from .data import Depo, DepoSingle, DepoGroup logger = logging.getLogger(__name__) @@ -31,6 +31,13 @@ API_ACCOUNT_LEDGERS = API_ROOT + '/accounts/{accid}/ledgers' API_ACCOUNT_POSITIONS = API_ROOT + '/accounts/{accid}/positions' +def asset_from_instrument_json(json) -> fin_defs.Asset | None: + if json['instrument_group_type'] == 'FND': + return None + symbol = json['symbol'] + exchange_id = json['tradables'][0]['mic'] + return fin_defs.Stock(symbol, fin_defs.EXCHANGES_BY_IDS[exchange_id]) + class NordnetDepoFetcher: def __init__(self, session, username: str, password: str): assert session is not None, 'missing session' @@ -39,7 +46,7 @@ class NordnetDepoFetcher: self.password = password self.is_logged_in = False - def get_json(self, url: str, params: dict[str, str | int] = {}) -> object: + def get_json(self, url: str, params: dict[str, str | int] = {}) -> dict: if not url.startswith(API_ROOT): msg = f'Given url must be located below API ROOT: {url}' raise ValueError(msg) @@ -77,26 +84,42 @@ class NordnetDepoFetcher: def get_depo(self) -> Depo: self.login() + now = datetime.datetime.now(tz=datetime.UTC) # TODO: Use info from json requests - accounts = self.get_json(API_ACCOUNTS) - print(accounts) + json_accounts = self.get_json(API_ACCOUNTS) + nested = [] + for json_account in json_accounts: + account_id = json_account['accid'] + assets: dict[fin_defs.Asset, Decimal] = { + } - # Old - now = datetime.datetime.now(tz=datetime.UTC) - result = self.session.query_private('Balance') - assets: dict[fin_defs.Asset, Decimal] = {} - for account, balance_str in result['result'].items(): - account = account.removesuffix('.HOLD') - asset = fin_defs.WELL_KNOWN_SYMBOLS[account] - balance = Decimal(balance_str) - if balance != 0: - assets[asset] = assets.get(asset, Decimal(0)) + balance - del account, balance_str, asset, balance + # Determine amount of usable currency stored on Nordnet + if True: + json_account_info = self.get_json(API_ACCOUNT_INFO.format(accid = account_id)) + asset = fin_defs.FiatCurrency(json_account_info[0]['account_sum']['currency']) + amount = Decimal(json_account_info[0]['account_sum']['value']) + assets[asset] = amount + del asset, amount - return DepoSingle( - name='nordnet', - _assets=assets, + # Determine positions on Nordnet + json_account_positions = self.get_json(API_ACCOUNT_POSITIONS.format(accid = account_id)) + for pos in json_account_positions: + asset = asset_from_instrument_json(pos['instrument']) + if asset is None: continue + amount = Decimal(pos['qty']) + assets[asset] = amount + del asset, amount + + nested.append(DepoSingle( + name='{} {}'.format(json_account['type'], json_account['alias']), + _assets=assets, + updated_time=now, + )) + + return DepoGroup( + name=f'Nordnet', updated_time=now, + nested=nested, )