Over the years, I have made multiple attempts at using software for tracking household finances, each one abandoned after an initial period of excitement.
About 13 years ago, I was scrapping the Chase Bank mobile website to display a running total of monthly expenses and estimated available “discretionary cash” at the end of the month. I ran this periodically to display a status line on the lock screen of my jailbroken iPhone. I was aiming to get almost instant feedback on my budget, while spending, and to avoid that where did the money go?! feeling at the end of the month. This was quite handy for a little while, I’m not even sure what killed it, probably the brittle scrapping code, or I just gave up on jailbreaking.
I tried mint.com for a little while after this, and I remember being pleased with their automatic categorization of transactions, but giving away my personal financial data always made me uneasy. There’s the privacy but also that feeling of lack of control, of not owning the data. What happens if they go bust?
Next, perhaps predictable for a developer, came a home-grown finance webapp. The project is now in good company in my Bitbucket graveyard. All in all, a decent effort of about 3k lines of code written over the course of 10 months in 2020. It was scrapping my different banks and feeding a SQLite ORM, to show a simple ledger with filters in the front-end. Looking at it now, it was doomed by the lack of double-entry accounting. It did however have basic graphs & pies, and a rules engine to clean up the data. As always, the most interesting thing in the repo is the TODO file, which tells a story of chasing the same goal I had 10 years prior: using current spending and upcoming recurring expenses to show a running estimate of the extra cash left at the end of the month, to “close the loop”.
Fast-forward a few more years, in 2024 I decided it was time to tackle the home finance project again. Now a bit older, the family financial situation is a little more layered, so the goals changed as well. I wanted to replace a series of random spreadsheets with a dashboard that could keep me updated on “macro” level questions. Answering things like “was this mortgage a good idea?” or “how’s that ETF performing?”. The nice thing about the macro level is that there are way fewer transactions, which means manually tracking them with an update every few months or so is way more doable. This got me thinking I might “succeed” this time around.
I started with GnuCash, assuming that “something that has been around for so long will be around for a lot longer”. That might be true, but not a good criteria in retrospect. It did however introduce me to double-entry accounting, and some basics like the accounting equation. Double-entry accounting forces you to record every transaction as being attached to at least 2 accounts, one being credited and one being debited. This tracks your money as a flow from A to B, instead of transactions in a ledger floating in the ether and unconnected to each other. This goes a long way to make sure you are painting an accurate picture, as the credits and debits have to balance.
While tracking stock purchases, I also learned about the concept of lots. Lots are used to answer the following question: “if I bought the same stock at 2 different times at different prices, and I later sell some of it, which buy price am I taking into account to calculate profit?”. This requires tracking “bunches” of stock units by their buy date and buy price, so-called lots. This can be useful for tax math, but in the end not so important in the day-to-day, as your bank usually does the math for you.
Even though I enjoyed the “retro open-source” charm of GnuCash’s GUI, all my hopes and dreams came crashing down when I tried to make some custom reports, which was my original goal. I was initially delighted to see a Lisp used as the scripting language, thinking this would give me some practice with the lambda and let me wield it’s functional power to generate quick and succinct reports. Many hours and two hundred lines of code later, all I had to show for my efforts was a report with a basic list of transactions.
Beancount
I don’t remember exactly how I stumbled on Beancount. It’s very good at being financial software for software developers. The key selling point, which granted seemed odd at first, is that the database is just a text file. It looks like this:
2023-06-22 * "Wine-Tarner Cable" ""
Assets:US:BofA:Checking -80.09 USD
Expenses:Home:Internet 80.09 USD
2023-07-04 * "BANK FEES" "Monthly bank fees"
Assets:US:BofA:Checking -4.00 USD
Expenses:Financial:Fees 4.00 USD
2023-07-05 * "RiverBank Properties" "Paying the rent"
Assets:US:BofA:Checking -2400.00 USD
Expenses:Home:Rent 2400.00 USD
This “Text-File-As-a-DB” approach has some nice consequences, notably:
- Ownership: the syntax is clear and legible, inspiring confidence that the data will remain accessible after carefully constructing a financial model over many years. Hypothetically speaking, you could just whip up a script from scratch in the language of your choice and start doing basic reports fairly quickly. In practice, this would likely never happen since the existing tooling is plenty adequate (and maybe that barrier of entry is not so low?), but it serves to give that extra peace of mind. Text is in a sense the most self-documenting of data formats, so the most likely to survive a long time.
- All your existing developer tooling is valid. Working with text files in your favorite IDE is a well-known process. Source-control is great to track changes and revert mistakes. It’s just another repository.
A simple but fully working example of a ledger file might look like this:
option "title" "Example Beancount file" ; Name your ledger
option "operating_currency" "USD" ; The default currency
1980-05-12 open Equity:Opening-Balances ; Initial balance comes from here.
1980-05-12 open Expenses:Restaurant ; This account is used as
; ; category to track expenses.
2023-01-01 open Assets:Checking USD ; Your checking account.
; ; A first transaction:
2023-01-01 * "Opening Balance" ; [Date] [Flag] [Description]
Assets:Checking 4043.21 USD ; First "posting" or "leg"
Equity:Opening-Balances -4043.21 USD ; 2nd posting
2023-01-01 * "Eating out with Nick" ; "*" is default for transactions
Assets:Checking -104.21 USD ; Take 104 USD from checking...
Expenses:Restaurant 104.21 USD ; And credit the "restaurant"
; account.
Fava
Originally, this Beancount ledger (as your database text file is called) was meant to be processed using command line tools, optionally spitting out some HTML reports when required. My preferred form of interaction however is with the web front-end, called Fava. It’s also an easy way to get started, after installing python and the pip package manager, these commands will get you started:
python -m venv venv # optionally use a venv to keep it neat
source venv/bin/activate # only if you created a venv above
pip3 install fava # install fava and beancount
bean-example > sample.ledger # generate a sample ledger
fava sample.ledger # start fava
You can now navigate to http://localhost:5000 to try Fava, or go ahead and try the online demo.
That’s it for now for some Beancount & Fava basics. So far I’ve been sticking with it for a bit over a year, let’s see if this one can go the long run or if it goes the way of countless other personal projects: bust 🤷♂️.