...so don't bother downloading it.
A crypto currency tax calculator.
ctax aims to determine profits and losses made by trading crypto currencies. It will import trades from input files and / or exchange APIs and use currency exchange rates from various sources to calculate profits and losses in the respective tax year. The result is CSV data that can be handed in with the tax declaration.
It is entirely possible that there are bugs or incorrect assumptions in the code so YOU SHOULD ALWAYS VERIFY THE RESULTS VERY CAREFULLY. There are no guarantees of any kind here. Seriously. Verify the results.
TODO
TODO
There is no support. You are welcome to ask questions / report issues / fix errors / add features / file pull requests, but do not expect fast responses.
This section describes the rationale behind ctax' profit / loss algorithm. Input and corrections are welcome.
The algorithm that calculates profit and loss is a rather simple FIFO / LIFO algorithm, as this seems to be the mode stipulated by tax laws in the majority of countries. The handling of fees can be a bit more complex than it seems on first glance, which is why it's described in the following chapter.
- tax currency: the currency the tax will have to be paid in
- base currency: the source currency in a conversion
- quote currency: the target currency in a conversion
- cost of purchase: money paid when buying an asset (in tax currency)
- proceeds: money received when selling an asset (in tax currency)
- profit / loss (P/L): proceeds minus cost of purchase (in tax currency)
ctax assumes that fees are tax deductible (TODO introduce non-deductible mode).
Exchanges charge fees in varying ways. The main difference is the currency in which the fee is deducted. Here are some examples.
- initial account balance: 1100 EUR / 0.1 BTC
- trade: buy 1 BTC @ 1000 EUR
- fee: 10% (for simplicity)
EUR BTC
1100 0.1 -> deduct fee 100 EUR
1000 0.1 -> convert 1000 EUR to 1 BTC
0 1.1
cost of purchase: 1100 EUR for 1.0 BTC (1100 EUR/BTC)
EUR BTC
1100 0.1 -> deduct fee 0.1 BTC
1100 0.0 -> convert 1000 EUR to 1 BTC
100 1.0
cost of purchase: 1000 EUR for 0.9 BTC (1111.11 EUR/BTC)
Note that the fee deduction mode directly influences the cost of purchase. This took me a while to get my head around. Why should the currency matter, as long as the value is equivalent? I came to the conclusion that in case #2, a lesser amount of quote currency was effectively received, meaning less of the service purchased (but for the same fee), meaning higher cost of purchase.
Bitfinex has a special case called "settlement" where Bitfinex wants to deduct the fees and the actual amount from base currency, but there's not enough balance to cover both.
Bitfinex then deducts the fee from base currency and converts the entire amount in question from base currency to quote currency. After this, there is a negative balance on the base currency account. Bitfinex now converts some of the quote currency back to base currrency to "settle" the negative balance.
EUR BTC
1030 0.00 -> deduct fee 100 EUR
930 0.00 -> convert 1000 EUR to 1 BTC
-70 1.00 -> convert 0.07 BTC back to 70 EUR
0 0.93
cost of purchase: 1030 EUR for 0.930 BTC (1107.52 EUR/BTC)
Similarly, Kraken sometimes deducts as much of the fee as possible from base currency, then deducts the remainder from quote currency.
EUR BTC
1030 0.00 -> deduct part of fee 30 EUR
1000 0.00 -> convert 1000 EUR to 1 BTC
0 1.00 -> deduct remainder of fee 0.07 BTC
0 0.93
cost of purchase: 1030 EUR for 0.930 BTC (1107.52 EUR/BTC)
The problem with cases such as #3 and #4 is that exchanges may not list two separate fees here. Or rather, they might list them in one place (e.g. downloaded ledger CSV data) but not in the other (e.g. data received from API, downloaded trade CSV data). Since the cost of purchase directly depends on the fee deduction mode, the resulting P/L will vary slightly, depending on the input data.
The data received from exchanges may not accurately reflect what happened on the exchange. I observed several cases where the API and downloaded trade CSV data would say one thing, but the downloaded ledger CSV data would say something else.
In this case, the following issues may arise:
- fees imported by ctax differ from actual fees
- balances internally maintained by ctax are inconsistent with balances shown by exchanges
- ctax detects unaccounted items due to inaccurate balances
Thank you to the people over at ccxt for doing a great job.