This thread got extracted out of Programmatic Tax Return.
It can be used for discussion and also support if needed.
If possible, issues should be reported at GitHub.
This thread got extracted out of Programmatic Tax Return.
It can be used for discussion and also support if needed.
If possible, issues should be reported at GitHub.
I hate to hijack a thread about another Made-in-Birmensdorf product but I already went down this rabbit hole
@j_from_b Wow, this sounds awesome. I have not tested it so far, but I really like the idea. No privacy concerns, fully open source. I would suggest that we extract this into an own thread for your solution. It also sounds pretty extendable for any other broker / bank.
What is the status of IBKR? Can you probably share a report based on dummy data?
Thanks for sharing! Iβm definitely going to try this! ![]()
Have you tried it yet? Curious!
This hits my nerd interests of both finance and technology. Iβm genuinely excited to do my tax return this year ![]()
Bit confused, doesnβt it need a signature / certificate from Kantons?
No certificate seems be required. In fact I cannot see any signatures in any of the payloads for statements I have from other banks.
I tried reaching out to the listed email adres for new implementers and got no response
There has been one real world use case and ZH Private Tax accepted it.
The fornat assumes yiu are a bank in some places so some fakery is required. For instance the 1D barcode on each page that is used by the document scanner if you use paper requires a Bankleitzahl.
But yes one reaction to this is a lockdownβ¦
I have some examples of stock splits etc. so I can send you some for testing.
To answer questions raised elsewhere
If somebody has paper trading on IBKR that they xan donate for test data that would be great
This is for tinkerers. datalevel.ch is the option if you want polish & matury
you also have a reference to the kursliste data management guide, but it is a dead link:
https://github.com/vroonhof/opensteuerauszug/blob/main/docs/data/kursliste/kursliste.md
does generated language need to be de, fr or it or is en also valid?
Btw another tricky thing is late withholding refund (eg BND US withholding thatβs refunded early on subsequent year).
OK. Great! After some tinkering, I managed to generate a PDF.
I need to double check to see how accurate it is.
I also added functionality for it to check for missing ISINs:
Updated data/security_identifiers.csv
Total entries: 178 securities
With ISINs: 169 (95%)
Without ISINs: 9 (e.g. futures/options that typically don't have ISINs)
The 9 securities without ISINs (all futures/options):
[list of securities]
This finding is pretty useful: while searching for this taxstatement-api file, I have found this page, which even mentions your post here. This goes pretty much into details, because they found a security issue in the library. They pretty much explain how to retrieve the file from public sources.
Based on this, I went down the rabbit hole, and looked into the .jar file using IntelliJ decompiler. In the end, I was able to generate a PDF (and even an official validation report) for the sample XML created by @j_from_b . There is way more config params available for styling and configuration the PDF, but for now I had to stop. The funny thing is, that the jar official jar file even contains some official logos and other content from banks - looks like they are also using this tool. ![]()
Letβs hope this helps @j_from_b a bit. I really like the idea of creating an open source generator for this, which also works for banks and brokers who do not offer digital CH tax statements. Also the validation tool seems to be quite helpful - it already reports some issues for the sample XML file.
I had to attach the script as text because I cannot upload text files here. Feel free to edit my post.
#!/bin/sh
# script to download official taxstatement.jar from public sources.
# the jar is mentioned in the official technical documentation:
# https://www.ech.ch/sites/default/files/dosvers/beilagen/BEIL2_d_DEF_2022-06-07_eCH-0196_V2.0.0_Barcode%20Generierung%20-%20Technische%20Wegleitung.pdf
# it also fetches a sample XML file from https://github.com/vroonhof/opensteuerauszug and creates a PDF and validation report
mkdir taxstatement
cd taxstatement
wget https://efisc.kttg.ch/update/eFisc/2025/efisc2025_1.0.2-70_amd64.deb
ar x efisc2025_1.0.2-70_amd64.deb data.tar.zst
tar --use-compress-program=zstd -xf data.tar.zst --transform 's,.*/,,g' ./usr/share/efisc2025/taxstatement-2.2.4.1.jar
rm data.tar.zst
# libs for creating PDF
wget https://repo1.maven.org/maven2/uk/org/okapibarcode/okapibarcode/0.5.2/okapibarcode-0.5.2.jar
wget https://repo1.maven.org/maven2/org/apache/pdfbox/fontbox/2.0.35/fontbox-2.0.35.jar
wget https://repo1.maven.org/maven2/org/apache/pdfbox/pdfbox/2.0.35/pdfbox-2.0.35.jar
wget https://repo1.maven.org/maven2/commons-logging/commons-logging/1.3.5/commons-logging-1.3.5.jar
# additional libs for validation report
wget https://repo1.maven.org/maven2/org/apache/poi/poi/5.5.1/poi-5.5.1.jar
wget https://repo1.maven.org/maven2/org/apache/poi/poi-ooxml/5.5.1/poi-ooxml-5.5.1.jar
wget https://repo1.maven.org/maven2/org/apache/poi/poi-ooxml-lite/5.5.1/poi-ooxml-lite-5.5.1.jar
wget https://repo1.maven.org/maven2/commons-io/commons-io/2.21.0/commons-io-2.21.0.jar
wget https://repo1.maven.org/maven2/org/apache/xmlbeans/xmlbeans/5.3.0/xmlbeans-5.3.0.jar
wget https://repo1.maven.org/maven2/org/apache/commons/commons-collections4/4.5.0/commons-collections4-4.5.0.jar
wget https://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.28.0/commons-compress-1.28.0.jar
wget https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.25.3/log4j-api-2.25.3.jar
wget https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.25.3/log4j-core-2.25.3.jar
# additional libs for PDF to XML extraction
wget https://repo1.maven.org/maven2/com/google/zxing/core/3.5.4/core-3.5.4.jar
wget https://repo1.maven.org/maven2/com/google/zxing/javase/3.5.4/javase-3.5.4.jar
# the following is only needed for demonstration purposes
wget https://raw.githubusercontent.com/vroonhof/opensteuerauszug/refs/heads/main/tests/samples/fake_statement.xml
# creates PDF
# force needed for fake_statement.xml because it seems to miss some needed declarations: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ech.ch/xmlns/eCH-0196/2.2/eCH-0196-2-2.xsd http://www.ech.ch/xmlns/eCH-0097/4/eCH-0097-4-0.xsd"
java -Dforce=true -Dssk=false -Dpdf=true -cp "./*" ch.ewv.taxstatement.examples.TaxStatementMain fake_statement.xml
# creates validation report
java -Dxlsx=true -cp "./*" ch.ewv.taxstatement.examples.TaxStatementMain fake_statement.xml
# extracts XML from a PDF
java -cp "./*" ch.ewv.taxstatement.examples.TaxStatementPDFToXML fake_statement.pdf extracted.xml
Iβve had to make some changes to the code, but it is getting there now, there are still some fixups to be made:
e.g. make BuySell.BUY to just βBUYβ
opening value is blank when 0 etc.
Then there is inconsistency in IBKR data, why do some rows have:
19.02.2025 SELL 5000 AWE @ 1.448 GBP-5β000
and others just:
01.04.2025 Sell-10β000
OK. Making progress and having more fun with this than is normal/healthy. ![]()
Still stuff that isnβt quite right yet.
Has anyone actually done that? I also have 1000+ of trades last year.
Thanks for sharing this. I see that Iβm still having a few failures against the validator. This is useful!
It is so nice having the all the data in one place. It makes it easier to do some checks e.g.
Top 20 Price Discrepancies
ββββββββ¬βββββββββββββββ¬ββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββ¬βββββββββββββββββ¬ββββββββββββββ¬ββββββββββββββββββ
β Rank β ISIN β Security β Broker Price β Kursliste β Discrepancy β Notes β
β β β β β Price β β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 1 β US82575P1075 β SIBANYE-STILLWATER β 4.55 USD (3.61 CHF) β 11.29 CHF β +212.91% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 2 β IE00B4LHWP62 β ISHARES PHYSICAL PLATINUM β 10.46 GBP (11.15 CHF) β 25.06 CHF β +124.85% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 3 β GB00BNDRMJ14 β ALPHAWAVE IP GROUP β 1.78 GBP (1.90 CHF) β 0 CHF β -100.00% β β Kursliste = β
β β β β β β β 0 β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 4 β CA0679011084 β BARRICK GOLD β 18.40 USD (14.57 CHF) β 0 CHF β -100.00% β β Kursliste = β
β β β β β β β 0 β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 5 β DE000ENER6Y0 β SIEMENS ENERGY β 60.66 EUR (56.44 CHF) β 112.03 CHF β +98.48% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 6 β US2566771059 β DOLLAR GENERAL β 71.76 USD (56.85 CHF) β 105.19 CHF β +85.02% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 7 β US36828A1016 β GE VERNOVA β 361 USD (286.00 CHF) β 517.79 CHF β +81.04% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 8 β US63253R2013 β NAC KAZATOMPROM β 33.4 USD (26.46 CHF) β 44.21 CHF β +67.07% β Qty: 1100 β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 9 β US4464131063 β HUNTINGTON INGALLS β 227.60 USD (180.31 β 269.42 CHF β +49.42% β β
β β β β CHF) β β β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 10 β US02079K1079 β ALPHABET (GOOG) β 212.13 USD (168.06 β 248.61 CHF β +47.93% β β
β β β β CHF) β β β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 11 β US81369Y1001 β MATERIALS SELECT SECTOR β 86.60 USD (68.61 CHF) β 35.93 CHF β -47.63% β β
β β β SPDR β β β β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 12 β US75513E1010 β RTX CORP β 124.55 USD (98.67 β 145.30 CHF β +47.25% β β
β β β β CHF) β β β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 13 β US5324571083 β ELI LILLY β 731.69 USD (579.68 β 851.42 CHF β +46.88% β β
β β β β CHF) β β β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 14 β IE0001827041 β CRH PLC β 86.05 USD (68.17 CHF) β 98.87 CHF β +45.03% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 15 β US46428Q1094 β ISHARES SILVER TRUST β 45.37 USD (35.94 CHF) β 51.04 CHF β +41.99% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 16 β US93627C1018 β WARRIOR MET COAL β 63.59 USD (50.38 CHF) β 69.85 CHF β +38.65% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 17 β CA85207Q1046 β SPROTT PHYSICAL PLATINUM β 12.15 USD (9.63 CHF) β 13.34 CHF β +38.60% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 18 β JE00BF50RG45 β YELLOW CAKE PLC β 4.29 GBP (4.57 CHF) β 6.31 CHF β +38.00% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 19 β US78462F1030 β SPDR S&P 500 ETF β 496 USD (392.96 CHF) β 540.25 CHF β +37.48% β β
ββββββββΌβββββββββββββββΌββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββββββΌββββββββββββββΌββββββββββββββββββ€
β 20 β (next row) β ... β ... β ... β ... β β
ββββββββ΄βββββββββββββββ΄ββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββ΄βββββββββββββββββ΄ββββββββββββββ΄ββββββββββββββββββ
Yes, several confirmed.
But it will depend on your canton how well itβs received. (Worked in ZH and BS, not sure about others)
Some cantons do not allow it as they do not use the actual market values but have their own specific tax values for securities that need to be applied.