Skip to main content

CLI envelope budget powered by Beancount

Project description

Beancount Budget

A command-line envelope budgeter.

  • No custom transaction types needed: your budget lives in CSV files, and balances are computed from Beancount data.
  • Set goals using quotas: budget for regular expenses, future large purchases, and more.

Getting started

Requirements

Executables:

  • Python 3.11+
  • column(1), from util-linux
  • fzf

Libraries:

  • beancount
  • click
  • python-dateutil

Installation

pip install beancount-budget

Configuration

budget needs to know some things:

  • regexes for classifying your Beancount accounts; and
  • the paths to your Beancount, budget, and quota files.

Running budget configure will write a configuration file to the current directory, or the directory you specify in budget -c /path/to/dir configure.

Untested use cases

If you

  • handle more than one currency in your daily finances,
  • have ever had to substantially refactor your Beancount accounts,
  • have a stance on investments other than "once the money's in the brokerage, it's left my budget", or
  • are anything other than a U.S. W-2 laborer,

you are encouraged to try this software and email your experiences to the author.

Example

First, I need some example Beancount data and a configuration for the budget:

$ bean-example --seed 0 --date-birth 2022-01-01 --date-end 2024-01-01 > main.beancount
$ budget configure
Example configuration written to `.bcbudget.toml`.
Use your preferred editor to finish configuration.
$ vi .bcbudget.toml

This is what the config file looks like after editing:

currencies = ["USD", "VACHR"]

[regexes]
cash = "^Assets:US:(BofA:Checking|Hoogle:Vacation)"
deductions = "^Expenses:(Taxes:|Health:.*:Insurance$)"
expenses = "^Expenses:"
income = "^Income:"
transfers = "^$"
liabilities = "^Liabilities:"
invest = "^(Assets|Income):US:ETrade:"
open = "^Equity:Opening-Balances$"

[paths]
beancount = "main.beancount"
budgets = "budgets"
quotas = "quotas"

And here is an empty budget.

$ budget show 2022-01
Category                   Budgeted  Expenses  Balances  Deviations
Expenses:Financial:Fees                  4.00     -4.00       -4.00
Expenses:Food:Groceries                219.35   -219.35     -219.35
Expenses:Food:Restaurant               329.62   -329.62     -329.62
Expenses:Home:Electricity               65.00    -65.00     -130.00
Expenses:Home:Internet                  80.14    -80.14     -160.14
Expenses:Home:Phone                     68.36    -68.36      -68.36
Expenses:Home:Rent                    2400.00  -2400.00    -2400.00
Expenses:Transport:Tram                120.00   -120.00     -240.00
Total                                 3286.47  -3286.47    -3551.47
Available                                       6649.63
Net income                                      6649.63

In this example, all budget commands that require a month will use 2022-01. In daily usage you will likely use commands like budget show unqualified.

Figuring income

The example data's first month contains an opening balance for a checking account ($3948.43), and two paychecks whose net balances are almost evenly split between the checking account and a 401k account ($1350.60 and $1200.00 respectively).

The budgeter's focus is on everyday spending, so 401k postings aren't counted as income. That leaves 3948.43 + (1350.60 * 2) = 6649.63.

Filling the budget

budget fill allocates money to categories until each has enough balance for the month's expenses and quotas. It tries to eliminate negative deviations.

$ budget fill 2022-01 > /dev/null
$ xsv select 'category,"2022-01"' budgets/USD.csv
category,2022-01
Expenses:Financial:Fees,4.00
Expenses:Food:Groceries,219.35
Expenses:Food:Restaurant,329.62
Expenses:Home:Electricity,65.00
Expenses:Home:Internet,80.14
Expenses:Home:Phone,68.36
Expenses:Home:Rent,2400.00
Expenses:Transport:Tram,120.00
$ budget show 2022-01
Category                   Budgeted  Expenses  Balances  Deviations
Expenses:Financial:Fees        4.00      4.00
Expenses:Food:Groceries      219.35    219.35
Expenses:Food:Restaurant     329.62    329.62
Expenses:Home:Electricity     65.00     65.00
Expenses:Home:Internet        80.14     80.14
Expenses:Home:Phone           68.36     68.36
Expenses:Home:Rent          2400.00   2400.00
Expenses:Transport:Tram      120.00    120.00
Total                       3286.47   3286.47
Available                                       3363.16
Net income                                      6649.63

budget trim does the opposite: it removes money from overbudgeted categories, in order to eliminate positive deviations.

$ budget add Expenses:Transport:Tram 100 2022-01
Expenses:Transport:Tram  (Balance now)    100.00
                         (Balance added)  100.00
                         [Available]      100.00
$ budget trim 2022-01
[Available]  (Balance now)            3363.16
             (Balance added)           100.00
             Expenses:Transport:Tram   100.00

Adding quotas

For more on the concept, see "Quotas" below.

Some of these categories cost a fixed amount per month, so it makes sense to start planning for them. To start, create quotas/$YOUR_CURRENCY.toml. (Unlike budgets, quotas are entirely manually set up.)

["Expenses:Home:Electricity".this]
type = "monthly"
amount = 65

["Expenses:Home:Internet".self]
type = "monthly"
amount = 80

["Expenses:Transport:Tram".wow]
type = "monthly"
amount = 120

The names were chosen to reflect their arbitrary nature. I use this in whole-category quotas.

$ budget fill 2022-01
Expenses:Home:Electricity  (Balance now)     65.00
                           (Balance added)   65.00
                           [Available]       65.00

Expenses:Home:Internet     (Balance now)     80.00
                           (Balance added)   80.00
                           [Available]       80.00

Expenses:Transport:Tram    (Balance now)    120.00
                           (Balance added)  120.00
                           [Available]      120.00
$ budget show 2022-01
Category                   Budgeted  Expenses  Balances  Deviations
Expenses:Financial:Fees        4.00      4.00
Expenses:Food:Groceries      219.35    219.35
Expenses:Food:Restaurant     329.62    329.62
Expenses:Home:Electricity    130.00     65.00     65.00
Expenses:Home:Internet       160.14     80.14     80.00
Expenses:Home:Phone           68.36     68.36
Expenses:Home:Rent          2400.00   2400.00
Expenses:Transport:Tram      240.00    120.00    120.00
Total                       3551.47   3286.47    265.00
Available                                       3098.16
Net income                                      6649.63

Quotas

Quotas are amounts you intend to budget each month. For example, in United States dollars:

  • A goal quota: "I want to save $1200 for a vacation six months from now."
  • Another goal quota: "I've already saved $10000 for a car, but I'm still looking for the right one."
  • A monthly quota: "My groceries cost $200 per month, give or take."
  • Another monthly quota: "I started going to a gym last week, and it'll cost $70 per month."
  • A group of monthly quotas: "I give to several NPOs monthly, in these amounts: $20, $10, another $10."
  • A fixed quota: "I will budget at least $3600 per month for candles, regardless of spending."
  • A yearly quota: "My PO box costs $24 per month; I pay $288 each June."

The numbers are strictly illustrative and I will brook no complaints about them.

Each of these quotas are assigned to a Beancount account, such as Expenses:Gifts:NPO. Multiple quotas may be assigned to the same account. If none are assigned to an account, that account has a default quota of zero (which conceptually reduces to "no overspending").

A goal or yearly quota expects the balance to be fulfilled during the month before the stated end date. For example:

  • If on January you begin a $1200 goal with July as the target month, the $200 you budget in June will fulfill the quota.
  • If you have a $288 yearly quota payable each June, the $24 you budget in May will fulfill the quota.

Schema

Each quota is assigned a category and a name (both strings), and consists of the following fields, with TOML types in parentheses:

  • type (string): One of monthly, yearly, goal, or fixed.
  • amount (float): The amount to save.
  • start (string, optional): The month to begin saving, in YYYY-MM format.
  • by (string, goal quotas only): The month by which to save the required balance, in YYYY-MM format.
  • month (integer, yearly quotas only): The month by which to save the required balance.
  • hold (boolean, goal quotas only): Whether to protect the saved balance from budget trim.

Examples

This is how the aforementioned quotas would look in quotas/USD.toml:

["Expenses:Vacation"."Los Angeles"]
type = "goal"
start = "2019-01"
by = "2019-07"
amount = 1200  # from January to June, you'll budget $200/m

["Expenses:Basics:Groceries".this]  # "this" is arbitrarily chosen
type = "monthly"                    # to represent whole-account quotas
amount = 200

["Expenses:Basics:Candles".this]
type = "fixed"
amount = 3600

["Expenses:Basics:Health".gym]
type = "monthly"
amount = 70
start = "2019-01"

["Expenses:Gifts:NPO"."Department of Redundancy Department"]
type = "monthly"
amount = 20

["Expenses:Gifts:NPO"."Benevolent and Proactive Order of Llamas"]
type = "monthly"
amount = 10

["Expenses:Gifts:NPO"."Feed the Childrens"]
type = "monthly"
amount = 10

["Expenses:Goals:Car".this]
type = "goal"
start = "2018-01"
by = "2019-01"
amount = 10000
hold = true

["Expenses:Subs:USPS".this]
type = "yearly"
month = 6
amount = 288  # = $24/m

Further reading

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

beancount_budget-0.20.0.tar.gz (93.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

beancount_budget-0.20.0-py3-none-any.whl (29.9 kB view details)

Uploaded Python 3

File details

Details for the file beancount_budget-0.20.0.tar.gz.

File metadata

  • Download URL: beancount_budget-0.20.0.tar.gz
  • Upload date:
  • Size: 93.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.2

File hashes

Hashes for beancount_budget-0.20.0.tar.gz
Algorithm Hash digest
SHA256 a455513985f9f6da9465bf6908901aed9e2d52d9b6d564ce9417b246c0b1ace6
MD5 29858a8f2ff8e576d6bb979aae21e53c
BLAKE2b-256 81c56410adcd6e096f43687836a8385542484a75662a60eea0b98756826273eb

See more details on using hashes here.

File details

Details for the file beancount_budget-0.20.0-py3-none-any.whl.

File metadata

File hashes

Hashes for beancount_budget-0.20.0-py3-none-any.whl
Algorithm Hash digest
SHA256 652e68822a732081ed91c762fd67b9e866a2a4ff7f23453d8c64cd1aec0b557a
MD5 6dd1f5f8b9b49836cff23e9a0af6bd9e
BLAKE2b-256 b27447e1efd17e6033d85d3ceab261ea21bdb3bef748330a2456c69dfc4019cb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page