Repository navigation
fix(degiro): recognize newer German export formats and fix dividend/withholding reconciliation - #434
Merged
vroonhof merged 2 commits intoSep 20, 2026
Conversation
DEGIRO's German-language export now uses different wording for several
row types than what the importer expected, causing real accounts to
either lose all trades silently or abort entirely:
- Buy/sell rows dropped the inline product name and "@" price marker in
favor of "zu je" ("at each"), e.g. "Kauf 3 zu je 64,91 EUR (ISIN)"
instead of "Kauf 60 iShares@20.08 EUR (ISIN)". This affected every
buy/sell row in a real 2026 export, none of which matched _TRADE_RE,
so no trades were imported at all (only a warning was logged).
- A new connection-fee wording, "Einrichtung von Handelsmodalitäten
YYYY (Exchange)", was unclassified and aborted the import with
NotImplementedError.
- A new FX wording, "Währungswechsel (Einbuchung/Ausbuchung)", was
likewise unclassified and aborted the import.
- A new money-market-fund compensation row, "Geldmarktfonds
Kompensation", was also unclassified and aborted the import.
Extend _TRADE_RE to accept the "zu je" variant and add the three new
descriptions to the classification tables, mirroring the existing
English/Italian/French/German entries. Covered by new parametrized
test cases in test_degiro_account_parser.py and test_degiro_importer.py.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
_process_dividend() built a single SecurityPayment and then applied
apply_withholding_tax_fields() to that same object whenever a matching
Dividend Tax row existed, merging the dividend amount and the
withholding fields onto one payment.
PaymentReconciliationCalculator._accumulate_broker() assumes dividend
and withholding tax live on two separate payments -- the convention
the IBKR and Fidelity importers already follow, since their broker
exports report dividend and tax as separate cash events. It returns
early as soon as it sees withholding fields set, before accounting for
the payment's dividend amount:
if withholding_claim is not None and withholding_claim != 0:
agg.withholding += withholding_claim
...
return
amount = payment.amount or Decimal("0")
agg.dividend += amount # never reached for a merged DEGIRO payment
Effect: for every DEGIRO dividend with a matching withholding-tax row,
payment reconciliation reported "Broker div: None" and a false
mismatch, e.g.:
MISMATCH DE ALLIANZ SE 2026-05-12: KL div 31.354 CHF / KL wht
4.7031 CHF vs Broker div None None / Broker wht 9.02 EUR; ...
Split _process_dividend() into two SecurityPayment objects (plain
dividend, and a separate is_withholding=True payment) to match the
IBKR/Fidelity convention. Covered by a new regression test.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
vroonhof
approved these changes
Sep 20, 2026
vroonhof
left a comment
Owner
There was a problem hiding this comment.
Thank you. It is bit sad DEGIRO cannot produce something more robust.
📄 Sample PDF and XML PreviewA sample Steuerauszug has been generated from (Artifact expires in 14 days. Requires GitHub login to download. View workflow run) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
While processing a real 2026 DEGIRO German-language export, two independent bugs
surfaced:
New German export row formats not recognized (first commit): buy/sell rows
switched from
Kauf 60 iShares@20.08 EUR (ISIN)toKauf 3 zu je 64,91 EUR (ISIN), which affected every trade row in a current German export — allsilently skipped, no trades imported at all. Three other row types
(
Einrichtung von Handelsmodalitäten ...,Währungswechsel (Einbuchung/Ausbuchung),Geldmarktfonds Kompensation) were alsounclassified and caused a hard
NotImplementedErrorabort.Dividend + withholding tax merged into one payment breaks reconciliation
(second commit):
_process_dividend()merged the dividend amount andwithholding tax onto a single
SecurityPayment, butPaymentReconciliationCalculator._accumulate_broker()expects them as twoseparate payments (the convention the IBKR/Fidelity importers already
follow) — causing every DEGIRO dividend with withholding tax to show a false
"Broker div: None" mismatch in the reconciliation report.
Both are fixed with minimal, targeted changes; see the individual commit
messages for full detail. Each is covered by new/extended unit tests.
Test plan
pytest tests/importers/degiro/— 109 passedpytest tests/— same result asmain(2 pre-existing, unrelatedWindows-only failures in fidelity/build_web_app tests)
without warnings/aborts, and payment reconciliation correctly matches
dividends that were previously flagged as false mismatches
black/flake8cleanAI used: Claude Sonnet 5