ibkr-report-parser
Interactive Brokers (IBKR) Report Parser for MyTax (vero.fi) - not affiliated with either service
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
TITLEThe title of the website. DefaultIBKR Report ParserCURRENCYThe currency used in the report output. DefaultEURUSE_DEEMED_ACQUISITION_COSTWhether to use the deemed acquisition cost, if it benefits you. DefaultTRUESTORAGE_TYPEThe storage to save the fetched daily Euro exchange rates, if set to anything other thanDISABLED. Currently supported types areLOCAL,AWS, andGCP. DefaultDISABLEDSTORAGE_DIRThe directory used whenSTORAGE_TYPEis set toLOCAL. Default.ibkr_storageBUCKET_IDThe storage bucket used whenSTORAGE_TYPEis set toAWSorGCP. Default""
Testing and debugging
DEBUGFlask debug. DefaultFALSELOGGING_LEVELPython logging level. DefaultINFOEXCHANGE_RATES_URLURL for the Euro exchange rates from European Central Bank. Defaulthttps://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:
- Merges all trades so option premiums from earlier years can adjust stock lots sold later.
- 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bfc45e7cfd62b1836b854e52796cf8f9b59b5facc5a8f2e24755648c35973a61
|
|
| MD5 |
88fcf40e23c0dd77bdb199e82dd2e161
|
|
| BLAKE2b-256 |
d1e7c22687d1cc0391ec668b5f05167bf33cf5e0df70d123c06ef695f67b3b79
|
File details
Details for the file ibkr_report_parser-2026.7.20-py3-none-any.whl.
File metadata
- Download URL: ibkr_report_parser-2026.7.20-py3-none-any.whl
- Upload date:
- Size: 208.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
566e0bd61863645c7b63182bafde2c35bb783b763a1e751c7f8ce5bfbd5671eb
|
|
| MD5 |
2527179042499de7e09cea6f9cfb3e9a
|
|
| BLAKE2b-256 |
71c443c9f8be10791418ec6f63d9e1de62a45bd745396c0244453644286c76f2
|