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"))

Metadata

Release files for ibkr-report-parser 2026.7.20

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ibkr-report-parser 2026.7.20
File Size Uploaded
ibkr_report_parser-2026.7.20.tar.gz 204.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ibkr-report-parser 2026.7.20
File Interpreter ABI Platform
ibkr_report_parser-2026.7.20-py3-none-any.whl Python 3 none any Details

Total release size: 413.1 kB

Release files / ibkr_report_parser-2026.7.20.tar.gz

Download URL ibkr_report_parser-2026.7.20.tar.gz
Size 204.3 kB
Tags Source
SHA-256 checksum
How to use checksums
bfc45e7cfd62b1836b854e52796cf8f9b59b5facc5a8f2e24755648c35973a61
BLAKE2b-256 checksum
How to use checksums
d1e7c22687d1cc0391ec668b5f05167bf33cf5e0df70d123c06ef695f67b3b79
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.13

Release files / ibkr_report_parser-2026.7.20-py3-none-any.whl

Download URL ibkr_report_parser-2026.7.20-py3-none-any.whl
Size 208.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
566e0bd61863645c7b63182bafde2c35bb783b763a1e751c7f8ce5bfbd5671eb
BLAKE2b-256 checksum
How to use checksums
71c443c9f8be10791418ec6f63d9e1de62a45bd745396c0244453644286c76f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.13
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page