Skip to main content

ibkr-report-parser

Python versions supported PyPI status CI codecov Code style: black

Interactive Brokers (IBKR) Report Parser for MyTax (vero.fi) - not affiliated with either service

Example

Example

How to run locally

Option 1: pip

pip install ibkr-report-parser
ibkr-report-parser

Option 2: Docker

docker pull ghcr.io/oittaa/ibkr-report-parser
docker run --rm -d -p 8080:8080 --name ibkr-report-parser ghcr.io/oittaa/ibkr-report-parser

Use the app

Browse to http://127.0.0.1:8080/

Environment variables

  • TITLE The title of the website. Default IBKR Report Parser
  • CURRENCY The currency used in the report output. Default EUR
  • USE_DEEMED_ACQUISITION_COST Whether to use the deemed acquisition cost, if it benefits you. Default TRUE
  • STORAGE_TYPE The storage to save the fetched daily Euro exchange rates, if set to anything other than DISABLED. Currently supported types are LOCAL, AWS, and GCP. Default DISABLED
  • STORAGE_DIR The directory used when STORAGE_TYPE is set to LOCAL. Default .ibkr_storage
  • BUCKET_ID The storage bucket used when STORAGE_TYPE is set to AWS or GCP. Default ""

Testing and debugging

  • DEBUG Flask debug. Default FALSE
  • LOGGING_LEVEL Python logging level. Default INFO
  • EXCHANGE_RATES_URL URL for the Euro exchange rates from European Central Bank. Default https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip

How to build yourself

Python

git clone https://github.com/oittaa/ibkr-report-parser.git
cd ibkr-report-parser
pip install .
ibkr-report-parser

Docker

git clone https://github.com/oittaa/ibkr-report-parser.git
cd ibkr-report-parser
docker build -t ibkr-report-parser:latest .
docker run --rm -d -p 8080:8080 --name ibkr-report-parser ibkr-report-parser

Multiple years and options

You can upload several CSV files (or one multi-year custom statement). The app:

  1. Merges all trades so option premiums from earlier years can adjust stock lots sold later.
  2. Reports only disposals from the latest calendar year present in the data (for MyTax). The year of each row is the later of acquisition and disposal dates (for shorts that is the cover year).

This matters for short puts that get assigned: the premium is not taxed on the option; it reduces the acquisition cost of the shares. A later-year IBKR statement alone does not include that premium—you need the assignment year in the upload as well.

Option exercise/assignment (IBKR codes A / Ex) is folded into the stock leg:

Position Event Effect on stock
Short call Assigned Premium increases disposal price (luovutushinta)
Long call Exercised Premium increases acquisition cost (hankintahinta)
Short put Assigned Premium decreases acquisition cost (hankintahinta)
Long put Exercised Premium decreases disposal price (luovutushinta)

Expired options and cash closes are still reported as option disposals.

MyTax field names (form 9A)

UI labels and the Python API follow Verohallinto form 9A terminology (English / Finnish):

Report / API Form 9A (EN sense) Finnish
acquired_on Acquisition date Hankintapäivä
acquisition_cost Acquisition cost / price Hankintahinta
disposed_on Disposal date Luovutuspäivä
proceeds Disposal price Luovutushinta
realized Gain or loss Luovutusvoitto / -tappio
used_deemed_acquisition_cost Deemed acquisition cost used Hankintameno-olettama
Totals: proceeds / gains / losses Total disposal prices / gains / losses Luovutushinnat / -voitot / -tappiot yhteensä

Python API

from ibkr_report import Report

FILE_1 = "tests/test-data/data_single_account.csv"
FILE_2 = "tests/test-data/data_multi_account.csv"

with open(FILE_1, "rb") as file:
    report = Report(file=file, report_currency="EUR", use_deemed_acquisition_cost=True)

with open(FILE_2, "rb") as file:
    report.add_trades(file=file)

print(f"Report year: {report.report_year} ({report.file_count} file(s))")
# Totals → form 9A: Luovutushinnat / Luovutusvoitot / Luovutustappiot yhteensä
print(f"Total disposal prices (luovutushinnat): {report.proceeds}")
print(f"Total capital gains (luovutusvoitot): {report.gains}")
print(f"Total capital losses (luovutustappiot): {report.losses}")

for item in report.disposals:
    # Hankintapäivä / hankintahinta / luovutuspäivä / luovutushinta / voitto tai tappio
    print(
        f"{item.symbol=}, {item.quantity=}, "
        f"hankintapäivä={item.acquired_on}, hankintahinta={item.acquisition_cost}, "
        f"luovutuspäivä={item.disposed_on}, luovutushinta={item.proceeds}, "
        f"realized={item.realized}"
    )
from ibkr_report import ExchangeRates, StorageType

rates = ExchangeRates(storage_type=StorageType.LOCAL, storage_dir="/tmp/my_storage")
print(rates.get_rate("EUR", "USD", "2020-06-20"))
print(rates.get_rate("GBP", "SEK", "2015-12-31"))

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ibkr_report_parser-2026.7.20.tar.gz (204.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ibkr_report_parser-2026.7.20-py3-none-any.whl (208.7 kB view details)

Uploaded Python 3

File details

Details for the file ibkr_report_parser-2026.7.20.tar.gz.

File metadata

  • Download URL: ibkr_report_parser-2026.7.20.tar.gz
  • Upload date:
  • Size: 204.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for ibkr_report_parser-2026.7.20.tar.gz
Algorithm Hash digest
SHA256 bfc45e7cfd62b1836b854e52796cf8f9b59b5facc5a8f2e24755648c35973a61
MD5 88fcf40e23c0dd77bdb199e82dd2e161
BLAKE2b-256 d1e7c22687d1cc0391ec668b5f05167bf33cf5e0df70d123c06ef695f67b3b79

See more details on using hashes here.

File details

Details for the file ibkr_report_parser-2026.7.20-py3-none-any.whl.

File metadata

File hashes

Hashes for ibkr_report_parser-2026.7.20-py3-none-any.whl
Algorithm Hash digest
SHA256 566e0bd61863645c7b63182bafde2c35bb783b763a1e751c7f8ce5bfbd5671eb
MD5 2527179042499de7e09cea6f9cfb3e9a
BLAKE2b-256 71c443c9f8be10791418ec6f63d9e1de62a45bd745396c0244453644286c76f2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page