# Using Beancount to Record your Bitcoin Holdings Blockchain Commons' `beancounter.py` is a Python program that interacts with a [SpotBit server](https://www.spotbit.info/spotbit/) to help you to log the purchase, sales, and other transfers of Bitcoin. ## Why Beancounting Your Bitcoin is Crucial (in the US) > **WARNING:** _Please do not consider this overview to be specific tax information; you should consultant with an accountant specialized in taxes and cryptocurrency if you are unsure of how to deal with your own Bitcoin holdings._ Bitcoin is treated as property, not a currency in the United States. Think of it like stock. That typically means that when you buy and then sell Bitcoin, it generates a taxable event, resulting in capital gains taxes (or else a capital loss that can be applied to other gains). That means that for purchase and sales of Bitcoin you need to carefully account for lots, knowing what was purchased, when it was sold, what the holding period was, and what the profit (or loss) was on that sales. Beancount can help you with accounting of this sort. But, Bitcoin is even more complex than that because it _is_ a currency, despite the United States' decision not to treat it as such for financial purposes. That means that you must not just report capital gains and losses when you sell Bitcoin, but also when you use it as currency, to buy other equities or even to pay someone for services! For this you need not just a beancount record of when Bitcoin was purchased, and then when it was used, but also knowledge of what the value of Bitcoin was when you made the later usage. That's where `beancounter.py` comes in: it looks up all the transactions for a descriptor-based wallet and then it uses a SpotBit server to determine the value of Bitcoin when it was used, providing vital information for your accountant (or when you do your own taxes). ## How to Setup Beancounter.py The `beancounter.py` program is currently a part of the [SpotBit repo](https://github.com/BlockchainCommons/spotbit). To access it requires cloning or otherwise downloading the repo. (The following setup instructions show the process for a MacOS computer. Setting up `beancounter.py` on a Linux machine would be very similar.) To start with, clone the repo: ``` $ git clone https://github.com/BlockchainCommons/spotbit.git ``` (If you prefer, you can download a ZIP file from [GitHub](https://github.com/BlockchainCommons/spotbit) and unzip it.) You must have Python 3.10 installed. If you do not already, it can be installed with Brew: ``` $ brew install python@3.10 ``` If you do not have HomeBrew for your Mac, you should [install it](https://brew.sh/), as it's a crucial package manager for acess programs like Python. If you have a previous version of Python, you will need to uninstall it to ensure you are accessing Python 3.10. When you're done, you can verify you are using the correct Python as follows: ``` $ python3 --version Python 3.10.6 ``` You're now ready to finalize your SpotBit (and thus `beancounter.py`) setup. First setup & use a virtual environment: ``` $ cd spotbit $ python3 -m venv env/ $ source env/bin/activate ``` Then, install dependencies: ``` (env)$ python -m pip install -r requirements.txt ``` Your `beancounter.py` (and for that matter, SpotBit server) is now ready to go. ## Running Beancounter The `beancounter.py` program requires two arguments: 1. A Spotbit server 2. A descriptor for the account you will be accounting It's run with those two arguments and with an optional `--network` argument. The following example shows its use with a wallet containing a few small transactions, run against Blockchain Commons' main Spotbit server: ```shell $ python3 beancounter.py https://spotbit.info "wpkh([8fa28d60/84h/0h/0h]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z5Cpeu3fjTikY7acRFXEoFaPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/<0;1>/*)#s8uj8lvl" --network bitcoin Generating beancount report for descriptor: wpkh([8fa28d60/84h/0h/0h]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z5Cpeu3fjTikY7acRFXEoF aPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/<0;1>/*)#s8uj8lvl currency = 'USD' [2022-09-29 15:05:07,389] INFO (thread 43028): beancounter.parse_keys: result=[[8fa28d60]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z 5Cpeu3fjTikY7acRFXEoFaPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/0/*, [8fa28d60]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z5Cpeu3f jTikY7acRFXEoFaPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/1/*] [2022-09-29 15:05:07,668] INFO (thread 43028): beancounter.make_beancount_file_for: Attempting to sync wallet. [2022-09-29 15:05:11,810] INFO (thread 43028): beancounter.make_beancount_file_for: Wallet sync completed. [2022-09-29 15:05:21,458] INFO (thread 43028): beancounter.make_beancount_file_for: Writing beancount report to: BqrJab7K-HDKey from HDKey from shyChamois2-Output-[8fa28d60_0_segwit_s8uj8lvl].bean ``` If the descriptor has an invalid checksum, `beancounter.py` will attempt to use the descriptor without the checksum. You will see this message: ```shell [2022-09-29 18:20:08,530] INFO (thread 38116): beancounter.new_wallet: This descriptor has an invalid checksum. We will try to create a wallet without using the checksum provided. ``` Afterward, look for a new `.bean` file, which will contain the Beancount information generated from your wallet. Each Beancount file will have a unique file name: ```shell $ ls -lagh *.txt -rw-r--r-- 1 staff 1.7K Aug 31 09:40 BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt -rw-r--r-- 1 staff 1.3K Aug 31 09:20 requirements.txt ``` If a file isn't generated yet no error is reported, try re-running the above `python beancounter.py` command with the `--verbose` flag which will generate detailed output that can be used when diagnosing/reporting the problem. ```shell $ python3 beancounter.py https://spotbit.info "wpkh([8fa28d60/84h/0h/0h]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z5Cpeu3fjTikY7acRFXEoFaPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/<0;1>/*)#s8uj8lvl" --network bitcoin --verbose ``` ### Running Your Own SpotBit Server If you prefer to keep your price lookups off of the internet, you can instead run your own Spotbit server, and then do lookups there: ```shell $ python3 app.py INFO: Started server process [25393] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:5000 (Press CTRL+C to quit) ``` You can then run `beancounter.py` using that local server. ```shell $ python3 beancounter.py http://localhost:5000 "wpkh([8fa28d60/84h/0h/0h]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z5Cpeu3fjTikY7acRFXEoFaPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/<0;1>/*)" --network bitcoin Generating beancount report for descriptor: wpkh([8fa28d60/84h/0h/0h]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z5Cpeu3fjTikY7acRFXEoFaPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/<0;1>/*) ``` ## Reviewing Your Beancount File After you have run `beancounter.py`, you should have a Beancount file that shows all your transactions related to the wallet: ``` $ cat BqrJab7K-HDKey\ from\ HDKey\ from\ ashamedTuna8-Output-\[8fa28d60_0_segwit_\]-Beancount.txt ``` ```bean # Transactions for wpkh([8fa28d60/84h/0h/0h]xpub6BqrJab7KQPReGRxvmdXf35JUhmszH6nEvGBUa2Z5Cpeu3fjTikY7acRFXEoFaPaYKuGFL6L1EwWKMWErPZupuN6kevnttCJBQ9AJQxnfnu/<0;1>/*)#s8uj8lvl # Balance: 0.00025222 BTC 2008-10-31 commodity BTC name: "Bitcoin" asset-class: "cryptocurrency" 2021-12-16 open Assets:BTC BTC 2021-12-16 open Liabilities:Cash:USD USD 2021-12-16 * "Transaction hash: d60308a1bf42ad5f69f4f5c6741f55fb7d24569c4a6a52b2a5c6be9b90768735" Assets:BTC 0.00033333 BTC @ 49004.50 USD Liabilities:Cash:USD -16.33 USD 2022-01-19 * "Transaction hash: b5a3e1c700b7dcc6da80dc3cc9851e17b2b12bb844c47ccf080e65ad8152d91f" Assets:BTC -0.00010400 BTC @ 42448.00 USD Liabilities:Cash:USD 4.41 USD 2022-01-19 * "Transaction hash: c489805cd7d56ac2d29ff3f61f63eb733f5c597f487e718e0f8490a874f899ae" Assets:BTC 0.00002353 BTC @ 42327.25 USD Liabilities:Cash:USD -1.00 USD 2022-01-26 * "Transaction hash: e50e991e93d36bf7d068eacd86a78e72464ff154ff14d6b2cd81901af0c3db70" Assets:BTC 0.00002000 BTC @ 37956.50 USD Liabilities:Cash:USD -0.76 USD 2022-03-24 * "Transaction hash: 82f8c92010fb9a1c6c923ad346b22f55063ad3a591d07ca27091d9c7d170cb28" Assets:BTC -0.00011564 BTC @ 43012.00 USD Liabilities:Cash:USD 4.97 USD 2022-03-24 * "Transaction hash: 12e6f1b40e9cc70864bd62f8ed1fad101cc79bce47581e5f7820a921a53c1571" Assets:BTC 0.00009500 BTC @ 43012.00 USD Liabilities:Cash:USD -4.09 USD ``` [[TODO: Doublecheck this file still looks the same after next revisions]] Critically, it shows not just Bitcoin transanctions, but also USD valuations, which will be crucial for tax purposes! ## Using Your Beancount File If you haven't already, you should at this point install `beancount`: ``` $ sudo -H python3 -m pip install beancount fava-investor ``` [TODO: bean-check currently shows an error] ``` $ bean-check BqrJab7K-HDKey\ from\ HDKey\ from\ ashamedTuna8-Output-\[8fa28d60_0_segwit_\]-Beancount.txt /Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt:22: No position matches "Posting(account='Assets:BTC', units=0.00002353 BTC, cost=CostSpec(number_per=Decimal('42369.99'), number_total=None, currency='USD', date=None, label=None, merge=False), price=None, flag=None, meta={'filename': '/Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt', 'lineno': 23})" against balance (-0.00032933 BTC, 0.00033333 BTC {48854.62 USD, 2021-12-15}) 2022-01-18 * "bc1qsxdenuhrct5spc6zek4l8kgs88r5geyfjpjl2d" "Transaction hash: c489805cd7d56ac2d29ff3f61f63eb733f5c597f487e718e0f8490a874f899ae" Assets:BTC 0.00002353 BTC {42369.99 USD} Liabilities:Cash:USD -1.00 USD /Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt:26: No position matches "Posting(account='Assets:BTC', units=0.00002000 BTC, cost=CostSpec(number_per=Decimal('38045.62'), number_total=None, currency='USD', date=None, label=None, merge=False), price=None, flag=None, meta={'filename': '/Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt', 'lineno': 27})" against balance (-0.00032933 BTC, 0.00033333 BTC {48854.62 USD, 2021-12-15}) 2022-01-26 * "bc1qjsxluh0trdql6u3cly32en7vjtdhvrmkrjj6u4" "Transaction hash: e50e991e93d36bf7d068eacd86a78e72464ff154ff14d6b2cd81901af0c3db70" Assets:BTC 0.00002000 BTC {38045.62 USD} Liabilities:Cash:USD -0.76 USD /Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt:30: No position matches "Posting(account='Assets:BTC', units=0.00009500 BTC, cost=CostSpec(number_per=Decimal('43006.50'), number_total=None, currency='USD', date=None, label=None, merge=False), price=None, flag=None, meta={'filename': '/Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt', 'lineno': 31})" against balance (-0.00032933 BTC, 0.00033333 BTC {48854.62 USD, 2021-12-15}) 2022-03-23 * "bc1q0mfr7z2yshk620pgnyrcd3u456kq7aars8z5ra" "Transaction hash: 12e6f1b40e9cc70864bd62f8ed1fad101cc79bce47581e5f7820a921a53c1571" Assets:BTC 0.00009500 BTC {43006.50 USD} ``` [[There are also discrepancies in the balance:]] ``` $ bean-report BqrJab7K-HDKey\ from\ HDKey\ from\ ashamedTuna8-Output-\[8fa28d60_0_segwit_\]-Beancount.txt balances /Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt:22: No position matches "Posting(account='Assets:BTC', units=0.00002353 BTC, cost=CostSpec(number_per=Decimal('42369.99'), number_total=None, currency='USD', date=None, label=None, merge=False), price=None, flag=None, meta={'filename': '/Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt', 'lineno': 23})" against balance (-0.00032933 BTC, 0.00033333 BTC {48854.62 USD, 2021-12-15}) 2022-01-18 * "bc1qsxdenuhrct5spc6zek4l8kgs88r5geyfjpjl2d" "Transaction hash: c489805cd7d56ac2d29ff3f61f63eb733f5c597f487e718e0f8490a874f899ae" Assets:BTC 0.00002353 BTC {42369.99 USD} Liabilities:Cash:USD -1.00 USD /Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt:26: No position matches "Posting(account='Assets:BTC', units=0.00002000 BTC, cost=CostSpec(number_per=Decimal('38045.62'), number_total=None, currency='USD', date=None, label=None, merge=False), price=None, flag=None, meta={'filename': '/Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt', 'lineno': 27})" against balance (-0.00032933 BTC, 0.00033333 BTC {48854.62 USD, 2021-12-15}) 2022-01-26 * "bc1qjsxluh0trdql6u3cly32en7vjtdhvrmkrjj6u4" "Transaction hash: e50e991e93d36bf7d068eacd86a78e72464ff154ff14d6b2cd81901af0c3db70" Assets:BTC 0.00002000 BTC {38045.62 USD} Liabilities:Cash:USD -0.76 USD /Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt:30: No position matches "Posting(account='Assets:BTC', units=0.00009500 BTC, cost=CostSpec(number_per=Decimal('43006.50'), number_total=None, currency='USD', date=None, label=None, merge=False), price=None, flag=None, meta={'filename': '/Users/shannona/Documents/GitHub/BlockchainCommons/spotbit/BqrJab7K-HDKey from HDKey from ashamedTuna8-Output-[8fa28d60_0_segwit_]-Beancount.txt', 'lineno': 31})" against balance (-0.00032933 BTC, 0.00033333 BTC {48854.62 USD, 2021-12-15}) 2022-03-23 * "bc1q0mfr7z2yshk620pgnyrcd3u456kq7aars8z5ra" "Transaction hash: 12e6f1b40e9cc70864bd62f8ed1fad101cc79bce47581e5f7820a921a53c1571" Assets:BTC 0.00009500 BTC {43006.50 USD} Liabilities:Cash:USD -4.09 USD Assets:BTC 0.00000400 BTC Equity Expenses Income Liabilities:Cash:USD -2.29 USD ``` [[SPARROW RESULTS A BALANCE OF 25,222 satoshis, worth $5.10 on this account]] [TODO: WRITE ABOUT HOW TO USE WHEN THESE ISSUES ARE RESOLVED.]