A capital gain tax calculator for crypto traders or investors with configurable locale support. While originally designed for Australian tax returns, it supports any fiat currency through configuration.
- Locale-aware calculations: Configure your local fiat currency (AUD, USD, etc.) for cost basis and reporting
- Flexible accounting: Supports both FILO (Last-In-First-Out) and FIFO (First-In-First-Out) position matching
- Exchange log transformation: Built-in transformer for Bitstamp, IndependentReserve, Nexo, Exdos Wallet, etherscan and solscan transaction logs, extensible for other types of logs
- Comprehensive fee handling: Crypto fees trigger disposal events; fiat fees treated as incidental losses
- Australian tax compliance: CGT discount for assets held >12 months, configurable fiscal year
- Limited types of transformers support (Extending work or manual transformation required for unsupported logs)
- No automated market data fetching for missing exchange rates
- Limited to assets defined in config.toml:
- Supported cryptos: BTC, ETH, LTC, NMC, BCH, LINK, USDT, NEXO, SOL, TRX, TON
- Supported fiats: USD, AUD
- Supported pairs: btcusd, btcaud, ltcusd, ltcbtc, nmcusd, ethusd, ethbtc, bchusd, linkusd, linkaud, audusd, and Kraken-style pairs (xethxxbt, xethzusd, etc.)
 
All settings are in config.toml:
[locale]
fiat = "aud"           # Local fiat currency (aud, usd, etc.)
fy_start_month = 7     # Fiscal year start month (7 = July for Australian tax)
[options]
position_accounting = "filo"     # "filo" or "fifo"
sort_by_datetime_asc = true
precision_threshold = 0.00000001
[data]
cryptos = ["btc", "ltc", "nmc", "eth", "bch", "link", "usdt", "nexo", "sol", "trx", "ton"]
fiats = ["usd", "aud"]
operations = ["buy", "sell", "deposit", "withdrawal", "gain", "loss"]
# ... see config.toml for full configurationImportant: The locale.fiat setting determines which currency is used for all cost basis calculations and tax reporting.
pycgt expects CSV files with specific columns.
Some predefined columns are [data.fields] in config.toml:
Required columns:
- Datetime: When the trade happened (multiple formats supported)
- Operation: 'Buy', 'Sell', 'Deposit', 'Withdrawal', or 'Loss'
Optional columns:
- Type: Transaction type description
- Exchange: The exchange where the trade was made
- Pair: Trading pair (e.g., btcusd, btcaud, ethusd)
- Crypto amounts: BTC, LTC, NMC, ETH, BCH, LINK
- Fiat amounts: USD, AUD
- Fee columns: Fee(BTC), Fee(LTC), Fee(NMC), Fee(ETH), Fee(BCH), Fee(LINK), Fee(USD), Fee(AUD)
- Exchange rates: BTCUSD, BTCAUD, LTCUSD, LTCBTC, NMCUSD, ETHUSD, ETHBTC, BCHUSD, LINKUSD, LINKAUD, AUDUSD
- Comments: Any notes about the transaction
Other columns would be built according to CRYPTOS and FIATS configuration
CSV example (see example.csv):
Type,Exchange,Datetime,Operation,Pair,BTC,LTC,NMC,ETH,BCH,LINK,USD,AUD,Fee(BTC),Fee(LTC),Fee(NMC),Fee(ETH),Fee(BCH),Fee(LINK),Fee(USD),Fee(AUD),BTCAUD,BTCUSD,LTCUSD,LTCBTC,NMCUSD,ETHUSD,ETHBTC,BCHUSD,LINKUSD,LINKAUD,AUDUSD,Comments
Market,Coinbase,"2024-03-14T09:11:00.711Z",Buy,BTCAUD,1,,,,,,,,108524.67,,,,,,,108.52467,108633.19467,,,,,,,,,,,
Market,Coinbase,"2025-06-30T13:40:11.735Z",Sell,BTCAUD,0.998,,,,,,,162387.8306,,,,,,,,162.87646,162713.15,,,,,,,,,,,,
Python 3 is required. Using virtualenv is recommended.
python3 -m venv .virtualenv       # Create virtualenv
source .virtualenv/bin/activate   # Activate virtualenv
pip install --upgrade pip         # Upgrade pip
pip install -r requirements.txt   # Install dependenciesProcess pycgt-formatted CSV files:
python main.py [csv_files...]Example:
python main.py example.csv
python main.py file1.csv file2.csv  # Multiple files supportedConvert exchange exports to pycgt format:
python main.py -t -x EXCHANGE [-o OUTPUT] INPUT_FILES...Example:
# Transform Bitstamp export
python main.py -t -x bitstamp Bitstamp-Export.csv
# Custom output filename
python main.py -t -x bitstamp -o converted.csv Bitstamp-Export.csvSupported exchanges: bitstamp
When processing example.csv with fiat = "aud" in config.toml:
gain_or_loss,datetime,aud,discountable,description,buy_transaction.aud,buy_transaction.volume,...
loss,2024-09-07 09:11:00.711000+00:00,-27.46,N/A,,108524.67,1.0,2024-03-14 09:11:00.711000+00:00,...
gain,2025-03-15 09:11:00.711000+00:00,24.65,Yes,,108524.67,1.0,2024-03-14 09:11:00.711000+00:00,...
gain,2025-06-30 13:40:11.735000+00:00,54080.54,Yes,,108524.67,1.0,2024-03-14 09:11:00.711000+00:00,...
========================================================
Tax return report for year: 2024
Gross gains of the year: $0.00 AUD
Taxable gains of the year: $0.00 AUD
Net gains of the year:  $0.00 AUD
Portfolio of the year:
  btc: 1.0
  ltc: 0
  nmc: 0
  eth: 0
  bch: 0
  link: 0
========================================================
========================================================
Tax return report for year: 2025
Gross gains of the year: $54159.43 AUD
Discountable gains of the year: $54159.43 AUD
Taxable gains of the year: $27079.72 AUD
Net gains of the year:  $26753.82 AUD
Portfolio of the year:
  btc: 8.67e-19
  ltc: 0
  ...
========================================================
Note: The currency label (AUD) in the output adapts based on the locale.fiat setting in config.toml. If you set fiat = "usd", all outputs will show USD instead.
To add support for a new cryptocurrency:
- 
Update config.toml:[data] cryptos = ["btc", "ltc", "nmc", "eth", "bch", "link", "your_coin"] 
- 
Add trading pairs: [data.pair_split_map] your_coinusd = ["your_coin", "usd"] your_coinaud = ["your_coin", "aud"] 
To add support for a new exchange:
- Create transformer/your_exchange_transformer.pyinheriting fromBaseTransformer
- Implement the transform()method to convert the exchange's CSV format
- Register it in transformer/__init__.py:elif exchange_type == 'your_exchange': return YourExchangeTransformer(input_files, output_file) 
See transformer/bitstamp_transformer.py for reference implementation.
Distributed under the GNU General Public License v3.0. See LICENSE for more information.
Rob Lao - viewpl(at)gmail(dot)com