← Back to HQ

Calculate Bitcoin Taxes Yourself: FiFo, Holding Period & the Open-Source Tool for Your Tax Return

by Alien Investor

You hold Bitcoin in self-custody. Good. You buy through multiple brokers. Even better. And now the tax authority asks which coins you bought when, which of them are tax-free and exactly how high your taxable gain is.

For exactly this problem there is the BTC Tax Tool β€” an open-source tool I developed myself for my own tax return (CLI, web version and app). It reads your CSV exports from BitBox, Sparrow, Electrum, Trezor Suite, Ledger Wallet, 21bitcoin, Bison, Swissquote, Strike, Pocket and Bisq (other exchanges via a CoinTracking or Blockpit export) and automatically calculates what has to go to the tax office and what remains tax-free.

"Don't Trust, Verify β€” including your accountant. If you understand how the calculation works, you're not at anyone's mercy."

πŸ›Έ The Web Version β€” drop your CSVs, get your report. Free.

No Python, no terminal: the tax tool also runs as a web app β€” free, no access link, no account. Drag your CSV exports into the browser, the app detects every broker automatically and computes all tax years at once. Your files never leave your machine β€” the entire calculation runs locally in your browser via WebAssembly. No upload, no account, no tracking. Same open-source calculation engine as the CLI tool.

Note: the web app interface switches between German and English (language button in the app). The reports themselves are made for the German tax system, Β§ 23 EStG.

β†’ Open the web version (fictional sample data included to try it out)
β†’ The guide β€” step by step with screenshots
β†’ As an app for Android and Linux desktop
β†’ Web version, app or CLI β€” which fits you?

1. The Foundation: What German Tax Law Says

Bitcoin is classified in Germany as a private disposal transaction (Β§ 23 EStG). The rules:

Situation Tax treatment
BTC held for one year or less, then sold Profit is a taxable event β€” tax is due once the exemption threshold is reached
BTC held for more than one year, then sold Profit tax-free
Transfer between your own wallets/accounts The transferred holdings: not a taxable event
Network/withdrawal fee paid in bitcoin Disposal of the fee portion at the daily rate (BMF circular of 6 March 2025, paras. 54, 60) β€” usually cents, the tool includes them
Bitcoin given away or donated Not a disposal, but the coins leave your holdings β€” acquisition date and cost carry over to the recipient (Sec. 23 (1) sentence 3 EStG)
Profit under 600 EUR/year (until 2023) Exemption threshold β€” not a single cent in tax
Profit under 1,000 EUR/year (from 2024) Exemption threshold β€” not a single cent in tax

The method is called FiFo β€” First In, First Out. That means: what you buy first, you also sell first. Sounds simple, but gets complicated quickly when you buy from five brokers and your BTC moves between multiple wallets. On top of that, the German Federal Ministry of Finance circular of 6 March 2025 requires in para. 62 a wallet-based view β€” FiFo applies per wallet, not across everything at once. Since October 2026 the tool calculates exactly that way and also treats every exchange account as a wallet of its own.

The Exemption Threshold Is a Trap

Many people think: "I'm under 1,000 EUR, so it's irrelevant." Wrong. The exemption threshold is not a tax allowance. If your gain reaches or exceeds it, the entire taxable profit becomes taxable β€” not just the part above it. A profit of 1,001 EUR is therefore fully taxable β€” not just that one euro.

2. The Problem with Self-Custody

Tax apps like CoinTracking or Blockpit work well for exchanges that record everything. For genuine self-custody holders with hardware wallets, problems arise:

The BTC Tax Tool runs locally on your machine. No cloud, no registration, no third-party servers. Your data stays with you.

From here on: the path for technical users (free CLI tool)

Sections 3–5 below describe the free CLI tool from GitHub β€” for everyone who likes working in a terminal.

Using the web version or the app? Then you need none of this. No Python, no terminal β€” drop or pick your CSVs, done. Skip straight to section 6: What you submit to the tax office.

3. Installing the CLI tool (one-time β€” GitHub version only)

You need Python 3.10 or newer. Many Linux systems ship it; check the version with python3 --version (Windows: python --version). On macOS and Windows you may need to install it first (python.org).

Mac / Linux:

git clone https://github.com/Alien-Investor/btc-steuertool.git
cd btc-steuertool
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

Windows:

git clone https://github.com/Alien-Investor/btc-steuertool.git
cd btc-steuertool
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt

That's it. No database, no server, no subscription.

4. Place Your CSV Files (CLI)

Export your CSV files from the respective apps and place them in the corresponding folders. The folders bitbox/ and Broker/ don't exist yet after cloning β€” they are listed in .gitignore so your financial data never accidentally ends up on GitHub. You need to create them once yourself:

Mac / Linux:

mkdir -p bitbox Broker

Windows:

mkdir bitbox
mkdir Broker
Source Folder Filename
BitBox (hardware wallet) bitbox/ any name, all *.csv files are loaded
Sparrow, Electrum, Trezor Suite, Ledger Wallet (since v1.4) wallets/ (noKYC: wallets/nokyc/) any name, the program is detected from the contents; the file name becomes the wallet's name (for Ledger the account names count, every account is a wallet of its own). Format derived from the programs' source code, not yet confirmed against real exports – the report warns
21bitcoin Broker/ must start with 21bitcoin
Bison Broker/ Bison-CSV-Gesamt.csv
Swissquote Broker/ Swissquote_CSV-Gesamt.csv
Strike Broker/ strike_2024.csv, strike_2025.csv etc.
Pocket Broker/ must start with Pocket
Bisq (noKYC) Broker/ must start with bisq: Bisq saves as tradeHistory.csv, rename it e.g. to bisq.csv. Export with Bisq set to German or English (since v1.3)
CoinTracking / Blockpit (aggregate import) Broker/ must start with cointracking, blockpit or sammelimport; with nokyc in the file name everything in it counts as noKYC. Every account in the file becomes a wallet of its own, and the account name appears as the source in the tax evidence – so name it neutrally. Format derived from the documentation, not yet confirmed against real exports – the report warns, please check amounts, fees and time zone
noKYC purchases without CSV (Robosats, P2P, cash) Project folder manual_buys.csv β€” optional, create yourself
Private sales (P2P without broker) Project folder manual_sales.csv β€” optional, create yourself

Your data stays local

The folders bitbox/ and Broker/ as well as the files manual_buys.csv and manual_sales.csv are listed in .gitignore β€” they will never accidentally be checked into Git or put online. Your financial data stays on your machine.

noKYC Purchases and Private Sales

Anyone who buys BTC without a KYC broker β€” via Robosats, HodlHodl, directly person-to-person or for cash β€” has no broker CSV (the tool reads Bisq exports directly, see the table above). For this there is manual_buys.csv: a simple text file in the project folder where you enter each purchase with date, BTC amount and EUR amount.

date,btc_amount,eur_amount,note,kyc
2024-07-22,0.00500000,280.00,Robosats trade,
2024-11-05,0.00250000,148.50,P2P cash,
2024-12-01,0.00200000,190.00,Coinbase purchase (broker without parser),ja

The kyc column is optional. Empty means noKYC (default). With ja you mark a purchase from a broker that has no import of its own yet: it then counts towards the KYC holdings and appears in the report for the tax office.

Same principle for private sales without a broker: manual_sales.csv with the same first four columns. The optional fifth column is called no_kyc there and works the other way round: ja = sale from the noKYC holdings, internal report only. Empty = normal sale, appears in the report for the tax office. The tool reads both files automatically and processes them like any other purchase or sale.

On the legal situation: A tax report with correct acquisition costs is usually enough. You do not have to hand over wallet addresses unprompted. In individual cases, however, the tax office can request addresses, transaction hashes and holdings (BMF letter of 06.03.2025, para. 101, 104). So keep your records, including for P2P purchases.

⚑ Update October 2026 (v1.5): maintenance release

⚑ Update October 2026 (v1.4): Sparrow, Electrum, Trezor, Ledger – and error messages that get through

⚑ Update October 2026 (v1.3): Hardened Parsers, Bisq in English, Aggregate Import

An audit of the CSV parsers found a silent failure: a renamed column or a byte-order mark at the start of the file (as Excel writes it when saving as "CSV UTF-8") turned a column into an unnoticed blank – whole Pocket, Bison or Swissquote files dropped out of the calculation without a word, Strike purchases showed up with 0 BTC. Since version 1.3 such a mark is skipped, and the tool checks every file for its required columns before reading: if one is missing, it stops with file, line and column instead of quietly carrying on.

Your broker is missing? Send the header line of the export plus one row of made-up values to kontakt@alien-investor.org – a real export is the release criterion for every new parser.

⚑ Update October 2026: FiFo per Wallet β€” as the BMF Circular Requires

The German Federal Ministry of Finance circular of 6 March 2025 states in para. 62: a wallet-based view applies. So FiFo does not run across all holdings together, but per wallet. Until now the tool calculated one pooled holding across all sources. Since version 1.2 every BitBox wallet is a FiFo holding of its own, and the tool treats every broker account as a wallet of its own as well (paras. 20 and 90 name the trading platform as a separate unit) β€” the only method used in the official documents, no toggle.

How acquisition data travels on a transfer is not spelled out in the BMF circular. The tool chooses the obvious reading β€” the sending wallet gives up units by FiFo, purchase date and cost are preserved β€” and discloses it in the evidence document. No tax advice.

⚑ Update August 2026: Fees Paid in Bitcoin and Gifts Are Now Included

Until now the tool treated transfers between your own wallets as tax-neutral, full stop. That is true for the transferred holdings β€” but not for the network fee you pay in bitcoin along the way. You hand it over in exchange for a service, and under the logic of the German Federal Ministry of Finance circular of 6 March 2025 (paras. 33, 54, 60) that is a small disposal of the fee portion. The tool now books it β€” which also means the reported holdings finally match your wallet.

Why no tax-advisor opinion on this? Because there is no explicit administrative statement and no court ruling β€” only the logic of the BMF circular and the practice of the major crypto tax tools, which do the same. The tool picks the traceable, documented method and lays it open. This is not tax advice.

⚑ Update June 2026: Bisq Direct Import + Strict noKYC Separation

The tool now supports direct import of the Bisq trade history CSV. Simply place the export from Bisq Classic ("Portfolio β†’ History β†’ Export to CSV"; since v1.3 with Bisq set to German or English) as bisq.csv in the Broker/ folder β€” the tool automatically recognises all completed purchases.

Also: the holding period is now calculated calendar-exact (anniversary date instead of a rigid 365-day count) β€” correct across leap years too.

For Robosats, HodlHodl and other P2P purchases without a CSV export, manual_buys.csv remains the right approach β€” also with noKYC separation.

Bisq is currently the only noKYC platform with a dedicated parser. The tool is MIT-licensed β€” anyone wanting to contribute an importer for Robosats, HodlHodl or other platforms is very welcome.

5. Your First Report (CLI)

Output a report for a specific year:

.venv/bin/python src/main.py --year 2024

All years at once:

.venv/bin/python src/main.py --all

With formal documentation for your accountant or tax office:

.venv/bin/python src/main.py --year 2024 --csv --nachweis

The result lands in reports/: a readable tax report, a print-ready formal proof of calculation and optionally CSV tables for Excel.

6. What You Submit to the Tax Office (Web, App & CLI)

The proof alone is not enough. The tax office wants to know that the purchase data is genuine. So always submit two parts:

The tool shows in the proof under "Source" exactly which broker provided which lot β€” so you can trace every single sale without gaps.

7. What This Tool Is Not

Not a replacement for a tax advisor. If you have taxable gains, have the results reviewed β€” especially in the first year. The tool calculates correctly according to FiFo, but you are responsible for the accuracy of your inputs.

What it is: a tool that informs and prepares you β€” instead of leaving you blindly trusting a cloud app you don't control.

As an app: Android and Linux desktop

Since version 1.0 (2 October 2026) the tax tool is also available as an app for Android (GrapheneOS) and as a Flatpak for the Linux desktop β€” free and open source like everything else. Interface and calculation core are the same as in the web version, with one difference: after installation the app downloads nothing. Pyodide, the calculation core, the ECB exchange rates and the BTC daily closing prices are built in. The reports are byte-identical to those of the CLI tool.

Android: how to get it

Deliberately not on the Google Play Store, but as signed releases from our own download address api.alien-investor.org/downloads/steuertool/. Easiest via Obtainium, which reports every update automatically (setup in the sheet below), or from the Zapstore, the app store on Nostr. Without either: download the APK from the download page and install it. Every release is mirrored on GitHub.

Set up Obtainium (values to copy)

On a phone with Obtainium installed it takes one tap; all settings are prefilled and Obtainium asks before adding:
Open in Obtainium

Or by hand, in Obtainium β€œAdd app”:

  1. β€œApp source URL” https://api.alien-investor.org/downloads/steuertool/
  2. Under β€œAdditional options for HTML”: β€œVersion string extraction RegEx” btc-steuertool-([0-9]+(\.[0-9]+)+)\.apk$
  3. β€œMatch group to use for version string extraction RegEx” $1
  4. β€œExpected signing certificate hashes” 26:C5:E0:94:A8:B7:65:0C:A6:65:01:4D:0C:3A:8B:A6:82:B1:7C:05:F5:3C:6C:DE:F0:55:D0:7C:E9:84:BF:0B
  5. Tap the β€œ+” to add, then install. Obtainium reports updates automatically.

Why the RegEx? On a download page Obtainium reads the version number from the file name only with it. Without it, Obtainium only has a substitute identifier and cannot compare against the installed version. The certificate hash is a hard lock: Obtainium will not install an APK signed with a different key.

Signing fingerprint (SHA-256) to verify authenticity with AppVerifier, identical for every version:

26:C5:E0:94:A8:B7:65:0C:A6:65:01:4D:0C:3A:8B:A6:82:B1:7C:05:F5:3C:6C:DE:F0:55:D0:7C:E9:84:BF:0B apksigner: 26c5e094a8b7650ca665014d0c3a8ba682b17c05f53c6cdef055d07ce984bf0b

For the Linux desktop

The same interface, packaged with Electron as a Flatpak (x86_64). The file is in the GitHub release, together with SHA256SUMS and the signature SHA256SUMS.asc. The same three files are on our own download address. Not on Flathub, no automatic update. Step by step: Flatpak guide (for all desktop apps).

Requirement: Flatpak with the Flathub remote (for the runtime org.freedesktop.Platform 25.08, which Flatpak fetches during installation):

flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo

1. Download three files: btc-steuertool-1.5-linux-x86_64.flatpak, SHA256SUMS, SHA256SUMS.asc.

2. Check the signature. The checksum file is signed with the Alien Investor GPG release key β€” the same key as for Alien Pass, Sachwert-Tresor and Alien Notes: alien-investor-release-key.asc. Compare the fingerprint through a second channel:

100F 9E25 BFAE A807 DBC3 57D7 50C0 D785 83BF CB81

gpg --import alien-investor-release-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS      # "Good signature from "Alien Investor (Release-Signatur) …""
sha256sum -c SHA256SUMS                     # "…flatpak: OK"

3. Install and start:

flatpak install --user btc-steuertool-1.5-linux-x86_64.flatpak
flatpak run org.alieninvestor.steuertool

Update: a new bundle cannot be installed over the existing one (Flatpak 1.14). Download and check the new version, then flatpak uninstall --user org.alieninvestor.steuertool and install again. The app stores no tax data, only language and theme.

Check for yourself that the app has no network:

flatpak info --user --show-permissions org.alieninvestor.steuertool

Expected, exactly:

[Context]
shared=ipc;
sockets=wayland;fallback-x11;
devices=dri;

No network, no filesystem.

Limits, stated honestly

Web version, app or CLI β€” which fits you?

The web version is free: no access link, no account, no paywall. Open api.alien-investor.org/steuertool/, drop your CSV exports, done. Fictional sample data is included to try it out. Since 2 October 2026 there is no paid access any more β€” the tool is free in every form.

Frankly: the web version fetches its code from my server on every visit. So you have to trust that exactly the published code is sitting there β€” you can verify it, but it is not convenient. If you want maximum control, use the CLI from the repo: once cloned it runs fully offline, with bundled exchange-rate tables and not a single network connection. In between sit the apps for Android and the Linux desktop: installed and verified once (signing fingerprint or GPG-signed checksum), then offline. All three run the same code.

⚑ Open the web version πŸ“– Guide

What the server sees when you open the app β€” and what it does not: privacy notice for the app.

Open Source on GitHub

The complete code is public, free and open-source. You can verify how every line of the calculation works. Fictional sample data for all supported brokers is included as well β€” so you can test the tool before loading your real data.

github.com/Alien-Investor/btc-steuertool

Tools for Real Owners

Tools I use myself – for Bitcoin self-custody and digital sovereignty:

Note: Some links are affiliate links. If you use them, I receive a commission. Thanks!


Recharge Energy (Donate)

Send fuel to the mothership

Thanks for your support – for free content, financial sovereignty and the extraterrestrial resistance!