1
0
fin-depo/fin_depo/investbank_nordnet.py

106 lines
3.5 KiB
Python
Raw Normal View History

2024-06-20 21:43:45 +00:00
"""Nordnet Depository fetching for [Nordnet](https://nordnet.dk), the online scandinavian investment bank.
2024-06-04 19:30:42 +00:00
This fetcher uses the [Nordnet
API](https://www.nordnet.dk/externalapi/docs/api), which requires a Nordnet
account.
Some of the code here is based on [Morten Helmstedt's Nordnet
utilities](https://github.com/helmstedt/nordnet-utilities/blob/main/nordnet_login.py).
I am grateful for his pioneering work.
"""
import datetime
import logging
2024-07-20 18:21:50 +00:00
from collections.abc import Mapping
2024-06-04 19:30:42 +00:00
from decimal import Decimal
import fin_defs
2024-07-18 22:22:54 +00:00
import requests
2024-07-16 20:00:28 +00:00
from frozendict import frozendict
2024-07-27 01:14:12 +00:00
from nordnet_api_client import NordnetClient
2024-08-02 03:28:56 +00:00
from nordnet_api_client.data import Instrument
2024-06-04 19:30:42 +00:00
2024-07-18 22:22:54 +00:00
from .data import Depo, DepoFetcher, DepoGroup, DepoSingle
2024-06-04 19:30:42 +00:00
logger = logging.getLogger(__name__)
2024-08-02 03:28:56 +00:00
def asset_from_instrument(instrument: Instrument) -> fin_defs.Asset | None:
if instrument.instrument_group_type == 'FND':
return None
2024-08-02 03:28:56 +00:00
symbol = instrument.symbol
exchange_id = instrument.tradables[0].mic
return fin_defs.Stock(
symbol,
fin_defs.EXCHANGES_BY_IDS[exchange_id],
nordnet_id=instrument.instrument_id,
)
2024-07-18 22:22:54 +00:00
2024-07-20 18:21:50 +00:00
EMPTY_DICT: Mapping[str, str | int] = frozendict()
2024-07-18 22:22:54 +00:00
2024-06-04 20:15:21 +00:00
2024-07-18 22:22:29 +00:00
class NordnetDepoFetcher(DepoFetcher):
2024-06-20 21:43:45 +00:00
"""Depository fetcher for [Nordnet](https://nordnet.dk), the online investment bank.
Requirements for use:
- Account on [Nordnet](https://nordnet.dk). This requires a MitID.
- Password login enabled from [settings](https://www.nordnet.dk/indstillinger/min-profil)
**Warning**: This system uses an unofficial API which uses your normal
Nordnet username and password for login access, with full read/write
access! **This is dangerous**, and any potential leak would give an
attacker full access to your account.
Depository structure: Each account you have access to will be given its own
`Depo`, with all of them nested under a "Nordnet" nested depository.
"""
2024-07-18 22:22:29 +00:00
def __init__(self, session: requests.Session, username: str, password: str):
2024-07-27 01:13:50 +00:00
self.client = NordnetClient(session, username, password)
2024-06-04 19:30:42 +00:00
def get_depo(self) -> Depo:
2024-06-04 20:15:21 +00:00
now = datetime.datetime.now(
tz=datetime.UTC,
) # TODO: Use info from json requests
2024-07-27 01:13:50 +00:00
accounts = self.client.get_accounts()
2024-07-16 20:00:28 +00:00
nested: list[Depo] = []
2024-07-27 01:13:50 +00:00
for account in accounts:
account_id = account.accid
2024-06-04 20:15:21 +00:00
assets: dict[fin_defs.Asset, Decimal] = {}
# Determine amount of usable currency stored on Nordnet
2024-07-27 01:13:50 +00:00
for account_info in self.client.get_account_info(account_id):
2024-06-04 20:15:21 +00:00
asset = fin_defs.FiatCurrency(
2024-07-27 01:13:50 +00:00
account_info.account_sum.currency,
2024-06-04 20:15:21 +00:00
)
2024-07-27 01:13:50 +00:00
amount = Decimal(account_info.account_sum.value)
assets[asset] = amount
del asset, amount
# Determine positions on Nordnet
2024-07-27 01:13:50 +00:00
for pos in self.client.get_account_positions(account_id):
asset = asset_from_instrument(pos.instrument)
2024-06-04 20:15:21 +00:00
if asset is None:
continue
2024-07-27 01:13:50 +00:00
amount = Decimal(pos.qty)
assets[asset] = amount
del asset, amount
2024-06-04 20:15:21 +00:00
nested.append(
DepoSingle(
2024-07-27 01:13:50 +00:00
name=f'{account.type} {account.alias}',
2024-06-04 20:15:21 +00:00
_assets=assets,
updated_time=now,
),
)
return DepoGroup(
2024-07-16 20:00:28 +00:00
name='Nordnet',
2024-06-04 19:30:42 +00:00
updated_time=now,
nested=nested,
2024-06-04 19:30:42 +00:00
)