Skip to content

Instantly share code, notes, and snippets.

@egh
Created February 19, 2014 18:24
Show Gist options
  • Save egh/9098247 to your computer and use it in GitHub Desktop.
Save egh/9098247 to your computer and use it in GitHub Desktop.
Weaving a budget with org-mode & ledger

Weaving a budget with org-mode & ledger

ledger comes with a built in budget system, but I wanted to get an “envelope”, or “YNAB” style budget working. While this was easy to do in theory, in practice it proved more difficult. The theory is pretty simple; enevelope budgeting merely requires you to create some new accounts to keep track of each “envelope” of money. But in practice, it requires a huge amount of duplicate data-entry, because even when using ledger’s automatic transactions, because each month’s budget is mostly the same but not necessarily exactly the same.The following document describes how I managed to get something working, with nice reporting, using org-mode.

The theory

In theory, the automatic transaction feature of ledger can easily be used to manage an envelope budget. The basic idea is that you will place all your money in different Budgeted: accounts. For instance, if you earn $1000/mo and want to place half of that money in your food budget and the other half in your bar budget, you would use:

2014/01/01 Income
  Assets:Checking         $1000
  Income                 -$1000
  Budgeted:Expenses:Food   $500
  Budgeted:Expenses:Bar    $500
  Budget                 -$1000

The Budget account is to ensure things balance; it should be equal to your income.

Now, we will use automated transactions to deplete your budget as you move money from various accounts to your Expenses accounts. Here is an automated transaction that will work for all your expenses in 2014 and afterwards:

= expr (date>=[2014] and account =~ /^Expenses:/)
  Budgeted:$account        -1
  Budget                    1

Now, given expense transactions that look like:

2014/01/02 Foo
  Assets:Checking      -$100
  Expenses:Food         $100

this will add, for every posting that starts with Expenses:, a posting to Budgeted:Expenses and to Budget. This will result in the equivalent of having entered:

2014/01/02 Foo
  Assets:Checking          -$100
  Expenses:Foo              $100
  Budgeted:Expenses:Foo    -$100
  Budget                    $100

The automated transaction saves us a great deal of repetetive work.

Now, this solution will work. But the trickiest part, I found, was in adjusting your budget as needed. For instance, I found that I needed a base budget for things like food and gas, but that other items might suddenly stop. For instance, you might cancel your cable, or take up a new hobby. You can copy and paste your base budget, but then when you go back to retroactively change your food budget (as you will probably need to, to adjust to the fact that you are spending more or less than anticipated), you need to go back and change all those budget entries.

The practice

This is where org-mode, and particularly babel’s noweb features come in. But first, let’s look at how we can use org-mode to generate some useful reports. Here is how I generate last month’s expenses:

**** Last month's expenses
#+begin_src ledger :cmdline bal -p "last month" ^Expenses: :results output :exports results
!include /path/to/ledger.lgr
#+end_src

(You may need to ensure that ob-ledger is loaded into your org-mode; check the org-mode manual for details.) Now, if you type C-c C-c on this entry, it will generate a report of your expenses last month.

By using babel, you can generate a lot of useful reports and keep them up-to-date, exporing them to HTML or PDF for printing, etc.

But some of the really useful features come when you keep your ledger in ledger files, and use org-mode’s noweb to weave a budget together. noweb allows, among other things, you to include source blocks in other blocks. First, we’ll set up our base budget, which will be included in every budget. Say we know that every month we will spend $500 on food. We create ledger source block with a name, base-budget:

#+name: base-budget
#+begin_src ledger
  ; :BUDGET:
  Budgeted:Expenses:Food  $500
  Budgeted:Savings
#+end_src

This means that we want $500 to go to food, and the balance to savings. The first line is a tag to let identify this as a budget; this helps with some reports. Now, we can set up our budget block:

#+name: budget
#+begin_src ledger :noweb yes
= expr (date>=[2014] and account =~ /^Expenses:/)
  Budgeted:$account        -1
  Budget  1

:

2014/01/01 * Budget
 <<base-budget>>
 Budget  -$1000
#+end_src

What we have done here is set up our automated transaction, as above, and set up our first month’s budget. We have assumed that our first month’s income is $1000, and we have included our base budget. When this is woven by noweb, <<base-budget>> will be replaced with the base-budget source block, and org-mode will pass the following on to ledger:

2014/01/01 * Budget
  Budgeted:Expenses:Food  $500
  Budgeted:Savings
  Budget                -$1000

This will set up $500 in our food budget, and the balance ($500) for savings.

Now, to generate a report, we can use the following:

#+begin_src ledger :cmdline bal -p "this year" ^Budgeted:Expenses -E :results output :exports results :noweb yes
<<budget>>
!include /path/to/ledger.lgr
#+end_src

Running this report (C-c C-c) will tell you your budget balance for each expense. If you budgeted $500 for food and spent $600, your balance will be -$100. If you spend $300, your balance will be $200.

For each month, you will create a new budget entry in your budget source block, with monetary value of the:

Budget  -$1000

line equaling your income that month.

Now, say that in June we take up cycling. We want to budget $100 per month for this, but we want to start in June, not January. We will add the following entry to our budget source block:

2014/01/01 * Budget
 <<base-budget>>
 Budgeted:Expenses:Cycling  $100
 Budget                   -$1000

This means that going forward our budget will be $500 for food, $100 for cycling, and $400 for savings.

Now, you will need to keep adding the Cycling budget line every time from now on, so you might want, at some point, to get complicated. You could define a new source block with the name base-budget-new, include your old base-budget, using <<base-budget>=, and then include that in your budget entries going forward, to avoid duplicate typing. noweb should allow you to structure your budget entries however you like.

@sexptherapy
Copy link

sexptherapy commented Apr 5, 2017

Any updates on your workflow over the past few years? Thanks for sharing this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment