Programmatic Tax Return

I assume your export does have some attributes which are not supported yet by opensteuerauszug.

Can you please post the relevant lines which contain those attributes here in the forum or even better as GitHub issue?

And as a workaround for now, just try to remove those attributes from your XML, and try converting it again. Most probably they are not even needed. Needless to say, but you really need to double check the created PDF in detail before using it for the tax return.

Edit: I couldnt set the custom date range to the whole year since I opened up the account in April

In that case, I would just try the first available date until end of year.

1 Like

It is this error here:

It requires some changes to code or patching XML.

Thanks, that worked. The Output seems okayish, made it still way easier than manually adding every single position.

I had to double check every position, especially some acc ETF that didnt had a “Ertrag” value. Im guessing these are a bit problematic since they were FOP transfers.

Good to hear that it worked for you :slight_smile:

Was it only the two XML attributes Trade.initialInvestment and EquitySummaryByReportDateInBase.liteSurchargeAccruals which causes issues?

I had to double check every position, especially some acc ETF that didnt had a “Ertrag” value. Im guessing these are a bit problematic since they were FOP transfers.

Does that mean you had to do manual adjustments? Were things in the generated PDF missing / off? In that case, exact reports would help in order to improve it.

1 Like

No, I created a slimmed down XML with just the critical fields and options.
This one gave me the ValueError: Failed to parse IBKR Flex XML file /Users/xxx/Downloads/opensteuerauszug2.xml with ibflex: Trade.initialInvestment - Can’t convert ‘Yes’ to <class ‘decimal.Decimal’> error.

Then I simply deleted every initialInvestment value to none or ““, re-run opensteuerauszug agains this xml with these parameters:
python -m opensteuerauszug.steuerauszug --importer ibkr /Users/xxx/Downloads/opensteuerauszug2.xml --period-from 2025-04-10 --period-to 2025-12-31 --tax-year 2025 -o ibkr-2025.pdf

I then successfully imported this pdf in ZHprivateTax.

Does that mean you had to do manual adjustments? Were things in the generated PDF missing / off? In that case, exact reports would help in order to improve it.

The positions that I transferred to IBKR this year did not have any Ertrag values after importing. Since I did not buy or sell anything, the amount stayed the same for the entire year. To double-check, I manually imported this position with the amount at the start of the year and again at the end. privateTax then correctly calculated the Ertrag values. I then simply corrected the empty value in the eSteuerauszug position of the corresponding ETF.

Edit: The one ETF that I started buying this year, was correct

4 Likes

ValueError: Failed to parse IBKR Flex XML with ibflex: Trade.initialInvestment - Can’t convert ‘Yes’ to <class ‘decimal.Decimal’>

Can you please post the line (anonymized) causing this error here (or as GitHub issue)? We should fix this.

The positions that I transferred to IBKR this year did not have any Ertrag values after importing.

This is probably a use-case not fully supported by opensteuerauszug yet. Can you also post one example (all relevant lines from XML file)?

Sure:

<Trade accountId=“accountId” acctAlias=“” model=“” currency=“USD” fxRateToBase=“0.81491” assetCategory=“STK” subCategory=“ETF” symbol=“VT” description=“VANGUARD TOT WORLD STK ETF” conid=“52197301” securityID=“US9220427424” securityIDType=“ISIN” cusip=“922042742” isin=“US9220427424” figi=“BBG000GM5FZ6” listingExchange=“ARCA” underlyingConid=“” underlyingSymbol=“VT” underlyingSecurityID=“” underlyingListingExchange=“” issuer=“” issuerCountryCode=“US” tradeID=“tradeID” multiplier=“1” relatedTradeID=“” strike=“” reportDate=“20250414” expiry=“” dateTime=“20250414;155107” putCall=“” tradeDate=“20250414” principalAdjustFactor=“” settleDateTarget=“20250415” transactionType=“ExchTrade” exchange=“IBRECINV” quantity=“1.0692” tradePrice=“112.24” tradeMoney=“119.998990069” proceeds=“-119.998990069” taxes=“0” ibCommission=“-0.350520273” ibCommissionCurrency=“USD” netCash=“-120.349510342” closePrice=“112.16” openCloseIndicator=“O” notes=“RI” cost=“120.349510342” fifoPnlRealized=“0” mtmPnl=“-0.0775” origTradePrice=“0” origTradeDate=“” origTradeID=“” origOrderID=“0” origTransactionID=“0” buySell=“BUY” clearingFirmID=“” ibOrderID=“ibOrderID” transactionID=“redacted” ibExecID=“ibExecID” relatedTransactionID=“” rtn=“” brokerageOrderID=“” orderReference=“” volatilityOrderLink=“” exchOrderId=“N/A” extExecID=“extExecID” orderTime=“20250414;092946” openDateTime=“” holdingPeriodDateTime=“” whenRealized=“” whenReopened=“” levelOfDetail=“EXECUTION” changeInPrice=“0” changeInQuantity=“0” orderType=“” traderID=“” isAPIOrder=“N” accruedInt=“0” initialInvestment=“Yes” positionActionID=“” serialNumber=“” deliveryType=“” commodityType=“” fineness=“0.0” weight=“0.0” />
<Trade accountId="accountId" acctAlias="" model="" currency="USD" fxRateToBase="0.82941" assetCategory="STK" subCategory="ETF" symbol="VT" description="VANGUARD TOT WORLD STK ETF" conid="52197301" securityID="US9220427424" securityIDType="ISIN" cusip="922042742" isin="US9220427424" figi="BBG000GM5FZ6" listingExchange="ARCA" underlyingConid="" underlyingSymbol="VT" underlyingSecurityID="" underlyingListingExchange="" issuer="" issuerCountryCode="US" tradeID="tradeID" multiplier="1" relatedTradeID="" strike="" reportDate="20250501" expiry="" dateTime="20250501;155425" putCall="" tradeDate="20250501" principalAdjustFactor="" settleDateTarget="20250502" transactionType="ExchTrade" exchange="IBRECINV" quantity="9.2333" tradePrice="117.51" tradeMoney="1084.99498177" proceeds="-1084.99498177" taxes="0" ibCommission="-0.352528642" ibCommissionCurrency="USD" netCash="-1085.347510412" closePrice="117.02" openCloseIndicator="O" notes="RI" cost="1085.347510412" fifoPnlRealized="0" mtmPnl="-4.5142" origTradePrice="0" origTradeDate="" origTradeID="" origOrderID="0" origTransactionID="0" buySell="BUY" clearingFirmID="" ibOrderID="ibOrderID" transactionID="redacted" ibExecID="ibExecID" relatedTransactionID="" rtn="" brokerageOrderID="" orderReference="" volatilityOrderLink="" exchOrderId="N/A" extExecID="extExecID" orderTime="20250501;092946" openDateTime="" holdingPeriodDateTime="" whenRealized="" whenReopened="" levelOfDetail="EXECUTION" changeInPrice="0" changeInQuantity="0" orderType="" traderID="" isAPIOrder="N" accruedInt="0" initialInvestment="Yes" positionActionID="" serialNumber="" deliveryType="" commodityType="" fineness="0.0" weight="0.0" />
1 Like
<OpenPosition accountId="accountId" acctAlias="" model="" currency="EUR" fxRateToBase="0.93109" assetCategory="STK" subCategory="ETF" symbol="IWDA" description="ISHARES CORE MSCI WORLD" conid="conid" securityID="IE00B4L5Y983" securityIDType="ISIN" cusip="" isin="IE00B4L5Y983" figi="BBG000P71QK5" listingExchange="AEB" underlyingConid="" underlyingSymbol="IWDA" underlyingSecurityID="" underlyingListingExchange="" issuer="" issuerCountryCode="IE" multiplier="1" strike="" expiry="" putCall="" principalAdjustFactor="" reportDate="2025" position="13" markPrice="111.53" positionValue="1449.89" openPrice="58.33" costBasisPrice="58.33" costBasisMoney="758.19" percentOfNAV="3.49" fifoPnlUnrealized="691.7" side="Long" levelOfDetail="SUMMARY" openDateTime="" holdingPeriodDateTime="" vestingDate="" code="" originatingOrderID="" originatingTransactionID="" accruedInt="" serialNumber="" deliveryType="" commodityType="" fineness="0.0" weight="0.0" />
<Transfer accountId="accountId" acctAlias="" model="" currency="EUR" fxRateToBase="0.944" assetCategory="STK" subCategory="ETF" symbol="IWDA" description="ISHARES CORE MSCI WORLD" conid="conid" securityID="IE00B4L5Y983" securityIDType="ISIN" cusip="" isin="IE00B4L5Y983" figi="BBG000P71QK5" listingExchange="AEB" underlyingConid="" underlyingSymbol="IWDA" underlyingSecurityID="" underlyingListingExchange="" issuer="" issuerCountryCode="IE" multiplier="1" strike="" expiry="" putCall="" principalAdjustFactor="" reportDate="2025" date="20250813" dateTime="20250813" settleDate="20250815" type="FOP" direction="IN" company="--" account="account" accountName="" deliveringBroker="Multiple" quantity="13" transferPrice="0" positionAmount="1354.02" positionAmountInBase="1278.19488" pnlAmount="0" pnlAmountInBase="0" cashTransfer="0" code="" clientReference="" transactionID="transactionID" levelOfDetail="TRANSFER" positionInstructionID="" positionInstructionSetID="" serialNumber="" deliveryType="" commodityType="" fineness="0.0" weight="0.0" />
1 Like

I added a link to datalevel and other solution (a chrome extension that can auto fill the ZRH tax form) to opensteuerauszug/README.md at main · vroonhof/opensteuerauszug · GitHub

3 Likes

Has anyone thought of trying opensternauszug with postfinance or swissquote? “unetical”?

3 Likes

That should work out pretty well I assume. The precject allows hooking in any importers as far as I have seen. Using extensive export sample data (best would be some machine readable format like CSV or XML) which privides all needed data (also PDF could work), optionally an ecport documentation, and the two existing importers (IBKR, Schwab), I would assume an agentic AI can create a very good vasis to build on. That would be an interesting experiment for any bank or broker which does not offer eSteuerauszug or charges for it extra.

I read that the java library is supposed to be open source, but is this documented anywhere? If so, then maybe it makes more sense to focus on the IBKR → XML conversion if we have a verified and usable XML → PDF converter.

1 Like

Die API wird als Open Source Software unter Apache Lizenz
V 2.0 über die nachfolgende URL zur Verfügung gestellt. Die Quellen, Java Doc und Beispiele
stehen ebenfalls über die nachfolgende URL in der Datei taxstatement-api-2.2.zip zur
Verfügung.

This is pretty clear. I wonder if we can just take the JAR file we have found in official tax software (see posts above), decompile it and make it available on GitHub under the described Apache licence. The decompiled code looks quite readable. I could do this with minimal efforts.

Does anybody see blockers or potential legal issues here?

The main issue is that you don’t really have proof of what the license is (I don’t think the jar carries licensing information). (You’d need access to the zip to confirm what the actual license is)

If you want to have fun, you could have a clean room setup with two Claude Code Setup :grinning_face_with_smiling_eyes:

One Claude Code writes description/documentation (without copying the code). And the other does not have access to the original and writes the code (potentially in another language).

If you combine that with a harness to test compatibility (have the second cc be able to run tests against the original lib for behavior testing), it would probably work and not have any copyright issue)

I’m also sceptical as to whether the whole thing was released and even if it was, it looks like they tried to walk it back and remove all links to it, so I wouldn’t try to poke the bear. Nonetheless, it could be worthwhile to decompile and analyze to understand how it works and learn from it even if we cannot integrate the jar directly into our own software.

I am getting to the point where I actually should be doing my tax return instead of hacking on this. Did anybody try the behavior on private tax for DA-1. Does it still have an option / warning to add supporting evidence for the withholding if you provide a steuerauszug?

Context: I am wondering how much we need to provide evidence that we actually saw a matching withholding in the broker export [seperate issue if the DA-1 folk will actually accept it]

I only just got the code for the tax return.

For WHT, I normally attach the 1043-S certificate for the US WHT. You can always attach additional documents.

A generated pdf should not be able to replace the da-1 evidence. (I don’t even know if it might be considered fraud, but it’s definitely playing with fire). Trying to trick the software to avoid filing out the fields manually is one thing, replacing the requested documented proof with ones you created yourself is entirely different.

I don’t even know if it might be considered fraud, but it’s definitely playing with fire

I do not really agree here. We are not trying to provide fake information, trick them or such. The only thing we are doing is improving the data quality of the imported data (automated is less error prone than manually typing), and simplify our and their life.

Did anybody try the behavior on private tax for DA-1. Does it still have an option / warning to add supporting evidence for the withholding if you provide a steuerauszug?

ZH: There is no option to attach an additional document to the e-taxstatement import as the is when you manually enter a position. If you really want to attach a “official” document, you can attach an activity report at the end before handing in the tax return (there is a dedicated section for attachments to the securities declaration).

But I will not attach it. As always, tax authorities can ask for an additional proof (they also did that in the past in my case for other deductions). Since all things we are handing in here are legit, it is not an issue for us to send the the officially expected activity report on request.

If this approach of non-officially generated e-taxstatement would not be accepted, it would basically void datalevel’ IBKR e-taxstatement, which the sell, as well. I would assume that they did some validation of their business model before building it.

At this point we don’t know the internal processes eniugh know what documents the DA-1 folk getvto see.

Alternatively we could add an option to concatenate 1043-S in tge PDF

Datalevel coukd add the warm fuzzy feeling of an audited path but that would require them to take on quite sone liability.

Anyway I think it is nect to impossible to hold us equities abd not get the withholding as reported on the kurskiste s