Petter Reinholdtsen: Plain text accounting file from your bitcoin transactions
A while back I wrote a small script to extract the Bitcoin
transactions in a wallet in the
ledger plain text accounting
format. The last few days I spent some time to get it working
better with more special cases. In case it can be useful for others,
here is a copy:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Copyright (c) 2023-2024 Petter Reinholdtsen
from decimal import Decimal
import json
import subprocess
import time
import numpy
def format_float(num):
return numpy.format_float_positional(num, trim='-')
accounts =
u'amount' : 'Assets:BTC:main',
addresses =
'' : 'Assets:bankkonto',
'' : 'Assets:bankkonto',
def exec_json(cmd):
proc = subprocess.Popen(cmd,stdout=subprocess.PIPE)
j = json.loads(proc.communicate()[0], parse_float=Decimal)
return j
def list_txs():
# get all transactions for all accounts / addresses
c = 0
txs = []
txidfee =
limit=100000
cmd = ['bitcoin-cli', 'listtransactions', '*', str(limit)]
if True:
txs.extend(exec_json(cmd))
else:
# Useful for debugging
with open('transactions.json') as f:
txs.extend(json.load(f, parse_float=Decimal))
#print txs
for tx in sorted(txs, key=lambda a: a['time']):
# print tx['category']
if 'abandoned' in tx and tx['abandoned']:
continue
if 'confirmations' in tx and 0 >= tx['confirmations']:
continue
when = time.strftime('%Y-%m-%d %H:%M', time.localtime(tx['time']))
if 'message' in tx:
desc = tx['message']
elif 'comment' in tx:
desc = tx['comment']
elif 'label' in tx:
desc = tx['label']
else:
desc = 'n/a'
print("%s %s" % (when, desc))
if 'address' in tx:
print(" ; to bitcoin address %s" % tx['address'])
else:
print(" ; missing address in transaction, txid=%s" % tx['txid'])
print(f" ; amount= tx['amount'] ")
if 'fee'in tx:
print(f" ; fee= tx['fee'] ")
for f in accounts.keys():
if f in tx and Decimal(0) != tx[f]:
amount = tx[f]
print(" %-20s %s BTC" % (accounts[f], format_float(amount)))
if 'fee' in tx and Decimal(0) != tx['fee']:
# Make sure to list fee used in several transactions only once.
if 'fee' in tx and tx['txid'] in txidfee \
and tx['fee'] == txidfee[tx['txid']]:
True
else:
fee = tx['fee']
print(" %-20s %s BTC" % (accounts['amount'], format_float(fee)))
print(" %-20s %s BTC" % ('Expences:BTC-fee', format_float(-fee)))
txidfee[tx['txid']] = tx['fee']
if 'address' in tx and tx['address'] in addresses:
print(" %s" % addresses[tx['address']])
else:
if 'generate' == tx['category']:
print(" Income:BTC-mining")
else:
if amount < Decimal(0):
print(f" Assets:unknown:sent:update-script-addr- tx['address'] ")
else:
print(f" Assets:unknown:received:update-script-addr- tx['address'] ")
print()
c = c + 1
print("# Found %d transactions" % c)
if limit == c:
print(f"# Warning: Limit limit reached, consider increasing limit.")
def main():
list_txs()
main()
It is more of a proof of concept, and I do not expect it to handle
all edge cases, but it worked for me, and perhaps you can find it
useful too.
To get a more interesting result, it is useful to map accounts sent
to or received from to accounting accounts, using the
addresses hash. As these will be very context dependent, I
leave out my list to allow each user to fill out their own list of
accounts. Out of the box, 'ledger reg BTC:main' should be able to
show the amount of BTCs present in the wallet at any given time in the
past. For other and more valuable analysis, a account plan need to be
set up in the addresses hash. Here is an example
transaction:
2024-03-07 17:00 Donated to good cause
Assets:BTC:main -0.1 BTC
Assets:BTC:main -0.00001 BTC
Expences:BTC-fee 0.00001 BTC
Expences:donations 0.1 BTC
It need a running Bitcoin Core daemon running, as it connect to it
using bitcoin-cli listtransactions * 100000 to extract the
transactions listed in the Wallet.
As usual, if you use Bitcoin and want to show your support of my
activities, please send Bitcoin donations to my address
15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b.
Tightening the feedback loop Link to heading One thing we notice ever so often is that although Phosh s source code is publicly available and upcoming changes are open for review the feedback loop between changes being made to the development branch and users noticing the change can still be quiet long.
This can be problematic as we ideally want to catch a regression or broken use case triggered by a change on the development branch (aka main) before the general availability of a new version.
I was working on what looked like a good pattern for a pair of
jeans-shaped trousers, and I knew I wasn t happy with 200-ish g/m
cotton-linen for general use outside of deep summer, but I didn t have a
source for proper denim either (I had been low-key looking for it for a
long time).
Then one day I looked at an article I had saved about fabric shops that
sell technical fabric and while window-shopping on one I found that they
had a decent selection of denim in a decent weight.
I decided it was a sign, and decided to buy the two heaviest denim they
had: a
The shop sent everything very quickly, the courier took their time (oh,
well) but eventually delivered my fabric on a sunny enough day that I
could wash it and start as soon as possible on the first pair.
The pattern I did in linen was a bit too fitting, but I was afraid I had
widened it a bit too much, so I did the first pair in the 100% cotton
denim. Sewing them took me about a week of early mornings and late
afternoons, excluding the weekend, and my worries proved false: they
were mostly just fine.
The only bit that could have been a bit better is the waistband, which
is a tiny bit too wide on the back: it s designed to be so for comfort,
but the next time I should pull the elastic a bit more, so that it stays
closer to the body.
I wore those jeans daily for the rest of the week, and confirmed that
they were indeed comfortable and the pattern was ok, so on the next
Monday I started to cut the elastic denim.
I decided to cut and sew two pairs, assembly-line style, using the
shaped waistband for one of them and the straight one for the other one.
I started working on them on a Monday, and on that week I had a couple
of days when I just couldn t, plus I completely skipped sewing on the
weekend, but on Tuesday the next week one pair was ready and could be
worn, and the other one only needed small finishes.
And I have to say, I m really, really happy with the ones with a shaped
waistband in elastic denim, as they fit even better than the ones with a
straight waistband gathered with elastic. Cutting it requires more
fabric, but I think it s definitely worth it.
But it will be a problem for a later time: right now three pairs of
jeans are a good number to keep in rotation, and I hope I won t have to
sew jeans for myself for quite some time.
I think that the leftovers of plain denim will be used for a skirt or
something else, and as for the leftovers of elastic denim, well, there
aren t a lot left, but what else I did with them is the topic for
another post.
Thanks to the fact that they are all slightly different, I ve started to
keep track of the times when I wash each pair, and hopefully I will be
able to see whether the elastic denim is significantly less durable than
the regular, or the added weight compensates for it somewhat. I m not
sure I ll manage to remember about saving the data until they get worn,
but if I do it will be interesting to know.
Oh, and I say I ve finished working on jeans and everything, but I still
haven t sewn the belt loops to the third pair. And I m currently wearing
them. It s a sewist tradition, or something. :D
The talks held in the room were these below, and in each of them you can watch the recording video.
As there has been an increase in the number of proposals received, I believe that interest in the translations devroom is growing. So I intend to send the devroom proposal to FOSDEM 2025, and if it is accepted, wait for the future Debian Leader to approve helping me with the flight tickets again. We ll see.
A first maintenance of the still fairly new package
This version mostly just updates to the newest releases of
Two months into my
Mee Goreng, a dish made of noodles in Malaysia.
Me at Petronas Towers.
Photo with Malaysians.

While we couldn t go with 6 on our upcoming LTS release, I do recommend
APN settings screenshot. Notice the circled entries.
Update 28.02.2024 19:45 CET: There is now a blog entry at