This is a post describing my experiences with the command line accounting tool ledger. My general preference for text based tools that “fit” into the UNIX ecosystem and which can work well with Emacs led me to this. The fact that it’s written by someone I admire a lot was an additional reason. The post that follows is a description of how I use it and what I’ve learnt over the past year. There will be gaps in my usage and outright mistakes due to my lack of understanding of accounting concepts and ledger features so be warned.

The tool is fairly simple. It requires that you maintain a list of your transactions in a double entry system. Double entry book keeping means that all transactions should have a debit account (one which receives money) and a credit account (from which money is deducted). At any point in time, the accounts should balance to zero. This took some getting used to for me but not too much and I’ve started thinking of my accounts in this way now.

Basics

A typical input file (which I’ll call the ledger file from now) will be a list of entries that look like this

2014/10/21  Acme groceries
    Expenses:Groceries     500 Rs
    Assets:Cash            -500 Rs

This records that on the 21 of October 2014, I spent 500 Rs cash to buy groceries. It moves 500 Rs from the Assets:Cash account to the Expenses:Groceries account. It’s also possible to have more than two accounts as long as the amounts balance. For example

2015/01/15 Acme restaurant
   Expenses:Eating out     1000 Rs
   Assets:Cash             -500 Rs
   Assets:Savings          -500 Rs

This says that I spent 1000 Rs on a meal at Acme Restaurant and paid 500 Rs in cash and the remaining 500 directly from my savings account (via. my debit card).

Accounts are hierarchical and the hierarchies are split using the :. So, you’d have things like Expenses:Groceries, Expenses:Internet which are two accounts all under the higher level Expenses account. I use Assets for accounts that hold my assets (like my bank accounts etc.), Expenses for expenses, Income to track where my money is coming in from, Liabilities to track money I owe and Loans to track money owed to me. I also have an Equity account to “withdraw” my initial assets from. More on this later. I use an Emacs mode that comes along with ledger to add entries to the file and use git to version control it. I have a few simple shell aliases that make certain queries available with a small number of keystrokes so that I can run things easily. More on this too, later.

Some notes on the non tech. aspects of the whole “system”. While there are many good applications out there on all possible platforms, people usually fail to keep their accounts due to a lack of discipline. They start off in full gusto, like I’ve done before with Gnucash and other tools, and then they run out of steam, falter and, also like I did with Gnucash and other tools, give up. Many try again but finally just let it go for good. The problem is, in summary, lack of discipline. There are two ways, as I see it, to fix this problem. The first is to construct tools that work even if one doesn’t have discipline. So there are apps that allow you, with a smart phone, to add an accounting entry to a database with just a few taps. Others which track SMSs from your bank to maintain a running balance of your financial situation. While not especially disciplined in my daily life, my approach is to try to develop it rather than adjust my lifestyle and tools to not need it. So, I make it a point to note down cash transactions during the day and then finally at the end of the day, as part of a daily ritual, update my ledger file with the expenses of the day. Once a week, as part of a weekly ritual, I cross check my balances against my actual accounts in my bank and wallet to make sure that everything is “in sync”. This took some trouble to get ready but after a month or so, the whole thing has become automatic. I’ve resisted the temptation to try and “remember” things to add into the file since I usually end up forgetting. Everything is either written down or in the file.

The first entry in my ledger is for Jul 1 2014 and I’m still going strong. That’s over a year of information and there are around 1800 transactions in there so it seems to be working.

I have a directory called ~/notes/accounts/ which has several ledger files. There’s one called accounts.dat which is the most heavily used. I also keep a separate one called lycaeum.dat which tracks expenses and income for my mentoring institute. This is version controlled using git and pushed to multiple locations as backup. I have a shell function called l defined like so

l () {
        ledger -w -f ${LEDGER_FILE} -V --date-format='%d-%b-%y' $*
}

This inovkes ledger with a few preset options like -w which prints output in a wide (132 column) format, -f to specify which ledger file to use. The LEDGER_FILE variable is set to ~/notes/accounts/accounts.dat. The -V displays market values for commodities (something which I’ll describe later) and finally, the --date-format to print dates in a way that I can read them quickly. Getting how much I have in my savings accounts would then be done like so

$ l balance Assets:Savings

The top like of the ledger file is ;-*-ledger-*- which means that Emacs opens it up in ledger-mode. This has a few useful keybindings that I use. e.g. C-c C-a to quickly add an entry and C-c C-q to fix alignment. It also has a lot more but I’m not really that heavy a user.

Using ledger

Let’s take a little scenario and describe how things might work. It’s artificial but still representative of how I use it.

I wake up in the morning and look at my TODO list. I have to pay electricity bills today. I pay them online using my credit card and then add an entry like so

2015/11/07 Acme power company
    Expenses:Electricity    1000 Rs
    Liabilities:CC

One of the accounts in an entry can be left blank and ledger will automatically fill it in. In this case, the entry is as if we entered -1000 Rs for the Liabilities:CC account.

I get some work done and receive a text message which says that one of my service providers has charged my credit card for a VPS that I have. So,

2015/11/07 Acme Cloud 
    Expenses:Hosting    1500 Rs
    Liabilities:CC

After a while, I have to run out to get some groceries and stuff. I first withdraw some cash from the bank and then spend some of it at a few stores. I come back with a few bills. I decide to update the journal right away.

2015/11/07 Withdrawal
    Assets:Cash     3000 Rs
    Assets:Savings

2015/11/07 Acme Groceries
    Expenses:Groceries    1500 Rs
    Assets:Cash

2015/11/07 Acme Fisheries
    Expenses:Groceries:Meat    500 Rs
    Assets:Cash

This says that I withdrew 3000 Rs. from the savings bank account and then spent 2000 from that on some groceries and some fish (which I usually track separately). Back at home, I continue with my day and have to go out again. I refuel my motorcycle and keep the amount noted down. I also stop for a quick bite to eat from a small bakery. The resulting ledger entries are like so

2015/11/07 Acme fuel
    Expenses:Petrol:Bike    500 Rs
    Assets:Cash

2015/11/07 Acme bakery
    Expenses:Food          50 Rs
    Assets:Cash

After entering this, just to see if things are in sync, I run

l b Assets:Cash

Commands to ledger can be abbreviated so b means balance. It says

     1,250.00 Rs  Assets:Cash

I check my wallet and see that there’s just 1,150 Rs in there. I spent 100 Rs somewhere during the day which I’m not sure of and I quickly make an entry to balance to discrepancy

2015/11/07 Acme fuel
    Assets:Cash    =1150 Rs
    Expenses:Unknown

The = in the amount here sets the amount in that account to the specified number and will add or deduct from the Expenses:Unknown account to make the Assets:Cash correct. This over time, accumulates accounting errors and ideally, it should be 0.

I get a text message indicating a bank transfer. A student from The Lycaeum has transferred a part of the fees for a mentoring course that I’m conducting. Okay

2015/11/07 Mentoring course Fees
    Assets:Business      5000 Rs
    Income:Lycaeum:Fees

I keep a separate bank account for business transactions so this amount goes there and it’s credited from the Income:Lycaeum:Fees account. Now, I need to book a few tickets for an upcoming training which I’m going to do. This means

 2015/11/07 Acme Bus service
     Expenses:Travel      1000 Rs
     Liabilities:CC

To make things more realistic, let’s add a section to the top of our file like so

2015/11/01 Initial balance
    Assets:Business    50000 Rs
    Assets:Savings    25000 Rs
    Assets:Cash        5000 Rs
    Equity

These are the initial amounts taken out of a special Equity account. This is how initial balances are handled.

I will also add similar entries for a few other days in the month so that the file is more interesting. I’ve annotated it with comments (the lines that start with ;) for clarity. The final file looks like this

And now, let’s run some queries on it.

How much do I have in my various accounts? My assets.

$ l b Assets
            27100 Rs  Assets
             7500 Rs    Business
             2400 Rs    Cash
            17200 Rs    Savings
--------------------
            27100 Rs

The ledger tool takes a query type as its first argument. There are several query types. The one we’ve used above is balance (abbreviated to b). You can then pass a query expression which will limit the entries that are displayed. In this case, I’ve asked for the balance query for the Assets accounts. It shows me a list and a total. That’s nice. Now, What were my expenses this month? (sorted)

$ l r -M --period-sort total Expenses
01-Nov-15 - 30-Nov-15                        Expenses:Food                                          50 Rs                50 Rs
                                             Expenses:Unknown                                      100 Rs               150 Rs
                                             Expenses:Maintenance                                  200 Rs               350 Rs
                                             Expenses:Medicine                                     250 Rs               600 Rs
                                             Expenses:Petrol:Bike                                  500 Rs              1100 Rs
                                             Expenses:Entertainment                                595 Rs              1695 Rs
                                             Expenses:Groceries:Meat                               700 Rs              2395 Rs
                                             Expenses:Fine                                         900 Rs              3295 Rs
                                             Expenses:Fitness                                     1000 Rs              4295 Rs
                                             Expenses:Travel                                      1000 Rs              5295 Rs
                                             Expenses:Entertainment:Restaurant                    1500 Rs              6795 Rs
                                             Expenses:Hosting                                     1500 Rs              8295 Rs
                                             Expenses:Calligraphy                                 2500 Rs             10795 Rs
                                             Expenses:Groceries                                   2700 Rs             13495 Rs
                                             Expenses:Domestic                                    3500 Rs             16995 Rs
                                             Expenses:Maintenance:Washing machine                 4000 Rs             20995 Rs
                                             Expenses:Charity                                     5000 Rs             25995 Rs
                                             Expenses:Rent                                        5000 Rs             30995 Rs

This time, we use the register (abbreviated to r) query. It’s probably the most heavily used one. Here, we pass -M to group transactions by month. By default, there’s no grouping and all transactions are displayed. Here, we want it to group so that we can further process it. We then provide the --period-sort option which will sort the entries in the group by the given parameter. We sort by “total” (which means total amount). After this, I use “Expenses” since that’s what I’m interested in and find out that I spent the most on charity and rent.

How much do I owe?

$ l b Liabilities
            -5595 Rs  Liabilities:CC

A simple balance query on Liabilities. How much do I withdraw on average per week?

$ l reg -A  -W Assets:Cash and @Withdraw
01-Nov-15 - 07-Nov-15                        Assets:Cash                                          5400 Rs              5400 Rs
08-Nov-15 - 14-Nov-15                        <Adjustment>                                        -3900 Rs                    0
                                             Assets:Cash                                          2400 Rs              3900 Rs
15-Nov-15 - 21-Nov-15                        <Adjustment>                                        -6967 Rs                    0
                                             Assets:Cash                                          8500 Rs              5433 Rs

This is another register query. The first column in a register query is the transaction amount. The second is usually a running total. The -A flag converts that to show a running average rather than a running total. The -W asks ledger to group things weekly (we used -M for montly earlier). The query expression is a little more complicated. It says “all transactions in touching the Assets:Cash account and which have Withdraw in the description”. The @ matches against descriptions rather than account names. The final 5344 Rs. tells us that we withdraw that much every week.

Automated transactions.

Ledger can also automatically perform transactions based on criteria. I have an entry like so

= /^Income/
    (Liabilities:Service tax)                 0.14

Which means, for all transactions that start with “Income”, put 14% into a Liabilities:Service tax amount. This means that if I have a transaction like so

2015/10/10
    Assets:Business   1000 Rs
    Income:Consulting

where the amount against Income:Consulting is -1000 Rs, ledger would automatically credit 140 Rs from the Liabilities:Service tax account. I can then quickly see how much I owe as service tax.

Budgeting

This is a feature that I don’t use enough yet but which I’ve started with. The basic idea is to create a budget for each account up front and then check against that. Let’s try that with. A version of the accounts file with added budgets is shown below

The added section is

~ Monthly
    Expenses:Rent                               5000 Rs
    Expenses:Groceries                          3500 Rs
    Expenses:Domestic                           4000 Rs
    Expenses:Electricity                        1500 Rs
    Expenses:Entertainment                      2000 Rs
    Expenses:Food                               1000 Rs
    Expenses:Fitness                             500 Rs
    Expenses:Hosting                            2500 Rs
    Expenses:Medicines                          1000 Rs
    Expenses:Petrol                             5000 Rs
    Assets

This tells ledger that every month, it should allocate this much money for each of the accounts specified and all of it comes from the Assets account. We could (and usually also do) have a ~ Yearly budget.

A register query for the current month for expenses like so. The -p allows us to narrow the date range to the current month.

$ l r -p "this month" Expenses
01-Nov-15 Acme groceries                     Expenses:Groceries                                    500 Rs               500 Rs
02-Nov-15 Acme Electricals                   Expenses:Maintenance                                  200 Rs               700 Rs
02-Nov-15 Acme stationeries                  Expenses:Calligraphy                                 2500 Rs              3200 Rs
04-Nov-15 Acme fine dining                   Expenses:Entertainment:Restaurant                    1500 Rs              4700 Rs
06-Nov-15 Traffic fine                       Expenses:Fine                                         900 Rs              5600 Rs
07-Nov-15 Acme Cloud                         Expenses:Hosting                                     1500 Rs              7100 Rs
07-Nov-15 Acme Groceries                     Expenses:Groceries                                   1500 Rs              8600 Rs
07-Nov-15 Acme Fisheries                     Expenses:Groceries:Meat                               500 Rs              9100 Rs
07-Nov-15 Acme fuel                          Expenses:Petrol:Bike                                  500 Rs              9600 Rs
07-Nov-15 Acme bakery                        Expenses:Food                                          50 Rs              9650 Rs
07-Nov-15 Acme fuel                          Expenses:Unknown                                      100 Rs              9750 Rs
07-Nov-15 Acme Bus service                   Expenses:Travel                                      1000 Rs             10750 Rs
08-Nov-15 Acme Groceries                     Expenses:Groceries                                    700 Rs             11450 Rs
08-Nov-15 Acme meat products                 Expenses:Groceries:Meat                               200 Rs             11650 Rs
10-Nov-15 Acme save the whales fund          Expenses:Charity                                     5000 Rs             16650 Rs
12-Nov-15 Gog                                Expenses:Entertainment                                595 Rs             17245 Rs
15-Nov-15 Domestic help                      Expenses:Domestic                                    3500 Rs             20745 Rs
17-Nov-15 Acme medicals                      Expenses:Medicine                                     250 Rs             20995 Rs
18-Nov-15 Acme repair company                Expenses:Maintenance:Washing machine                 4000 Rs             24995 Rs
21-Nov-15 Acme Housing                       Expenses:Rent                                        5000 Rs             29995 Rs
25-Nov-15 Acme Gym                           Expenses:Fitness                                     1000 Rs             30995 Rs

Now, let’s see how this balances against our budgets. This is as simple as adding the --budget flag to the query

$ l r --budget Expenses
01-Nov-15 Budget transaction                 Expenses:Rent:House                                 -5000 Rs             -5000 Rs
01-Nov-15 Budget transaction                 Expenses:Groceries                                  -3500 Rs             -8500 Rs
01-Nov-15 Budget transaction                 Expenses:Domestic                                   -4000 Rs            -12500 Rs
01-Nov-15 Budget transaction                 Expenses:Electricity                                -1500 Rs            -14000 Rs
01-Nov-15 Budget transaction                 Expenses:Entertainment                              -2000 Rs            -16000 Rs
01-Nov-15 Budget transaction                 Expenses:Food                                       -1000 Rs            -17000 Rs
01-Nov-15 Budget transaction                 Expenses:Fitness                                     -500 Rs            -17500 Rs
01-Nov-15 Budget transaction                 Expenses:Hosting                                    -2500 Rs            -20000 Rs
01-Nov-15 Budget transaction                 Expenses:Medicines                                  -1000 Rs            -21000 Rs
01-Nov-15 Budget transaction                 Expenses:Petrol                                     -5000 Rs            -26000 Rs
01-Nov-15 Acme groceries                     Expenses:Groceries                                    500 Rs            -25500 Rs
04-Nov-15 Acme fine dining                   Expenses:Entertainment                               1500 Rs            -24000 Rs
07-Nov-15 Acme Cloud                         Expenses:Hosting                                     1500 Rs            -22500 Rs
07-Nov-15 Acme Groceries                     Expenses:Groceries                                   1500 Rs            -21000 Rs
07-Nov-15 Acme Fisheries                     Expenses:Groceries                                    500 Rs            -20500 Rs
07-Nov-15 Acme fuel                          Expenses:Petrol                                       500 Rs            -20000 Rs
07-Nov-15 Acme bakery                        Expenses:Food                                          50 Rs            -19950 Rs
08-Nov-15 Acme Groceries                     Expenses:Groceries                                    700 Rs            -19250 Rs
08-Nov-15 Acme meat products                 Expenses:Groceries                                    200 Rs            -19050 Rs
12-Nov-15 Gog                                Expenses:Entertainment                                595 Rs            -18455 Rs
15-Nov-15 Domestic help                      Expenses:Domestic                                    3500 Rs            -14955 Rs
25-Nov-15 Acme Gym                           Expenses:Fitness                                     1000 Rs            -13955 Rs

Now the numbers look different. What ledger does is that it deducts each budget item from the appropriate account thereby reducing it and then actual expenses increase it again. If the final total is negative, it means that you’re below budget. If it’s above, it means that you’ve crossed your budget. To clarify, let’s look at just one account

$ l r --budget Expenses:Rent
01-Nov-15 Budget transaction                 Expenses:Rent                                       -5000 Rs             -5000 Rs
21-Nov-15 Acme Housing                       Expenses:Rent                                        5000 Rs                    0

Tells us that we had 5000 Rs budgeted for the rent and it was fully spent. Not so for entertainment

$ l r --budget Expenses:Entertainment
01-Nov-15 Budget transaction                 Expenses:Entertainment                              -2000 Rs             -2000 Rs
04-Nov-15 Acme fine dining                   Expenses:Entertainment                               1500 Rs              -500 Rs
12-Nov-15 Gog                                Expenses:Entertainment                                595 Rs                95 Rs

where we overshot our budget by 95 Rs. However, for Domestic expenses, we are under budget

$ l r --budget Expenses:Domestic
01-Nov-15 Budget transaction                 Expenses:Domestic                                   -4000 Rs             -4000 Rs
15-Nov-15 Domestic help                      Expenses:Domestic                                    3500 Rs              -500 Rs

Viewing everything like we first did gives us the information that we’re within our budget which is good.

Concluding remarks

Like I said above, I’ve been using the tool for a year now. The whole thing has worked for me and as of today, I have around 30k in my Unknown account. That’s not very good but since this is the first time I’m keeping accounts and this is over a whole year, it’s not that bad either.

It’s an ideal tool for UNIX aficionados. It’s text based, command line driven, super fast, has a somewhat steep learning curve with great rewards at the end, extremely flexible, transparent about what it does and a few other things which characterise the kind of software I like but that’s for another post. The official site is ledger-cli.org. The manual is worth reading just for itself and is fairly complete.

blog comments powered by Disqus