[HOME] | [ABOUT ME] | [BLOG] | [CONTACT]


Ledger CLI

Previously I used Mint to track my finances across all my accounts. When it shut down, my dad moved to Monarch, which inspired me to find a replacement as well.

My main priorities were privacy and control. Though it takes more effort to ledger manually, I’m no longer relying on some corporation that could disappear and take their service with them. Since my finances are congregated in my hands, my financial habits are much more private (well, as private as they can be without going the Monero and cash only route). Also being text based, I get much more control granted by the ability to write scripts that automatically add entries and integrate with my environment.

Biggest downside, which I’m mostly over now that I’m used to it, is that there isn’t any pretty eyecandy visualizations, like pie charts or line graphs to generate reports with. There is gnuplot functionality, but I’ve found it to be limited (more likely I didn’t spend enough time figuring it out).

hledger might have more features, but I find it difficult to justify installing dozens of Haskell dependencies for a single program.

Directory layout

~/ledger
    accounts
    commodities
    prices
    transactions.ledger

My accounts file is used to keep a list of “categories” for my assets, income, expenses, etc. I have my configuration file set up such that any account that isn’t explicitly listed in this file will cause an error when generating ledger reports.

commodities is similar to accounts, rather it keeps track of which symbols are legal in my ledger, to prevent typos like VLVXV when I meant VLXVX. Also whitelists USD, JPY, and other currencies.

prices exists to track the value of various symbols. Manually updating this is a pita so I set up a nightly cron job in tandem with a python script which queries AlphaVantage’s API for a list of symbols, and appends them to this file in a Ledger friendly way.

Get my script

If you choose to use it, dont forget to set the LEDGER_PRICE_DB environment variable to the path of your price file. Oh, and the API key is unwisely stored in a variable. My cron job defines it in the same line:

0 0 * * * LEDGER_PRICE_DB=$HOME/ledger/prices python $HOME/.scripts/update_ledger_prices.py

Lastly, transactions.ledger is the ledger. I have set up a few cron jobs to automatically add uncleared transactions for various recurring bills. Which once I verify/acknowledge them, I’ll change their status to cleared.

printf "\n<date>   <payee>\n\t<account>\t x.xx USD\n\t<account> " >> ~/ledger/transactions.ledger

Favorite reports:

To simply show net worth:

$ ledger b Assets Liabilities

Shows a high level overview of Expenses and Income on a month-by-month basis.

$ ledger r Exp Inc --monthly --market --depth 1 

Sometimes I’ll append the --effective flag to get a better idea of how less frequent paid-up-front bills are distributed over following months. Like insurance or my mobile plan.

On most reports I’ll use the --market (-V) flag to translate the current value of my holdings to USD. For accuracy it’s important to keep an up to date list of symbol prices and currency exchange rates.

WM/Workflow integration

I set up a script in my path named transact, which opens and sets my cursor to the bottom of the transactions.ledger file. After exiting my editor, a signal is sent to dwmblocks and/or waybar to refresh the related custom ledger status module(s). (Right now I only have one to sum the overall balance between my all my liability accounts)

#!/bin/sh
nvim + ~/ledger/transactions.ledger
pkill -RTMIN+3 dwmblocks #waybar

A nice discovery I made is that Neovim’s treesitter plugin has support for ledger syntax highlighting.

Read more about ledger here

I reference the manual when I get bored, try to pick up new reporting and organization abilities.