Investeringshistorik
  • Python 49.5%
  • Vue 36.5%
  • CSS 8.5%
  • TypeScript 5.2%
  • HTML 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-24 12:36:54 +02:00
backend Initial 2026-09-24 12:22:53 +02:00
frontend Added coin sea 2026-09-24 12:36:54 +02:00
reports Initial 2026-09-24 12:22:53 +02:00
tests Initial 2026-09-24 12:22:53 +02:00
.gitattributes Initial 2026-09-24 12:22:53 +02:00
.gitignore Initial 2026-09-24 12:22:53 +02:00
CLAUDE.md Initial 2026-09-24 12:22:53 +02:00
README.md Updated README.md 2026-09-24 12:24:54 +02:00
requirements.txt Initial 2026-09-24 12:22:53 +02:00

SEB investment tracker

A local tool that turns SEB Periodisk rapport PDFs into valuation snapshots, then fills daily values between them using public fund NAVs.

  • Backend: Python / FastAPI (backend/), SQLite at data/portfolio.sqlite3
  • Frontend: Vue 3 + Vite + Chart.js (frontend/)
  • Chart: daily valuations from first snapshot to today, with selectable ranges (All time, 4Y, 3Y, 2Y, 1Y, YTD, 6M, 3M, 1M)
  • No bank login. Everything runs on localhost.

Running it

python -m venv .venv && .venv/bin/pip install -r requirements.txt
(cd frontend && npm install && npm run build)

.venv/bin/uvicorn backend.app:app --host 127.0.0.1 --port 8000
# open http://127.0.0.1:8000

For frontend development, run npm run dev in frontend/ (port 5173, proxies /api to 8000).

Bulk-import every PDF in the working directory, then fetch prices:

.venv/bin/python -m backend.bootstrap
.venv/bin/python -m backend.prices

Tests: .venv/bin/python -m pytest

How valuation works

  1. Import (parser.py, store.py): a report gives holdings (name, units, SEB value), cash, and trades with ISINs. SEB lists holdings by name only, so names are matched to ISINs through earlier trades. Names that can't be matched are entered once in the import dialog and saved as aliases. Every import is checked: holdings must add up to SEB's securities total, and cash plus securities must equal the account total.

  2. Snapshots: each report's end date is a valuation snapshot. Holdings and cash are locked in on that date. Snapshots serve as anchors for estimating all other dates.

  3. Daily estimates (valuation.py): for any date, the system finds the latest snapshot on or before that date, then:

    • Adjusts holdings by trades recorded between snapshot and target date
    • Prices holdings with the latest public NAVs available
    • Converts foreign currencies using ECB rates
    • Carries forward cash from snapshot + trade proceeds
    • If any holding lacks a recent NAV and less than 5 days have passed since the snapshot, uses the snapshot's own unit price to bridge the gap
    • Marks the day incomplete if any required price is still missing
  4. Prices (prices.py): fetches daily NAVs from FT (first), then Avanza's public API, then Investing.com's fund pages. All three match exact ISIN and share-class currency. FX comes from ECB reference rates. Refresh is incremental: once a fund's history reaches the chart start, subsequent refreshes only fetch recent days. Manual NAV entry is available for funds no source covers.

The Price sources tab compares units × public NAV with SEB's month-end values, which catches a wrong ISIN or share class. Price fetches and failures are logged per fund and shown in the UI.

Known limits

  • Cash drift: Deposits, withdrawals, fees and distributions don't appear in the reports. Estimated cash can go negative between snapshots if a deposit occurred; those days show as incomplete. A value change is not a return.
  • Price source gaps: most funds use FT (fund history) or Avanza (live API), but a few depend on web scraping (Investing.com), which can break without notice. Failures are shown per fund in the Price sources tab and never hidden.
  • Share-class specificity: system requires exact ISIN + currency match. Polar Emerging Market Stars X SEK (IE00BJ205F06) is only found on Investing.com because it's not on FT or Avanza.
  • SEB .xlsx exports: holdings lists from the SEB app are not imported yet. Only Periodisk rapport PDFs work.
  • History depth: daily values start from your first imported snapshot. To see 2019 valuations, import monthly reports back to January 2019.