Budget
Zhang’s budgets follow the envelope model of YNAB (You Need A Budget): you create a budget for a spending category, assign money to it each month, and link expense accounts to it. Spending on those accounts is the budget’s activity, and what is left carries over to the next month. Budgets are separate from your accounts: they never change an account’s balance.
Syntax
Section titled “Syntax”YYYY-MM-DD budget <Name> <Commodity>YYYY-MM-DD budget-add <Name> <Number> <Commodity>YYYY-MM-DD budget-transfer <FromName> <ToName> <Number> <Commodity>YYYY-MM-DD budget-close <Name>| Directive | Effect |
|---|---|
budget |
Creates the budget <Name>, counted in <Commodity>. |
budget-add |
Assigns an amount to the budget in the month of its date. A negative amount takes money away. |
budget-transfer |
Moves an assigned amount from one budget to another in the month of its date. |
budget-close |
Closes the budget at the end of its date, or at its time if it has one. |
A budget name is a single word without spaces, quotes, colons, parentheses or commas, such as Food or
Daily-Groceries. Each directive takes a date, optionally with a time of day, and metadata lines below.
A budget directive reads two metadata keys:
| Key | Effect |
|---|---|
alias |
A display name for the budget in the web UI. |
category |
The group the budget page lists the budget under. |
Linking accounts
Section titled “Linking accounts”An account counts toward a budget through the budget metadata of its open directive. Repeat the key to link the
account to several budgets. A posting counts toward the budgets of the account’s open in effect at its date and time,
so an account closed and opened again with other budget metadata counts toward the new budgets from its reopening on,
also when it reopens later on the same day.
YYYY-MM-DD open <Account> budget: <Name>Examples
Section titled “Examples”2024-01-01 budget Food CNY alias: "Food and groceries" category: "Daily"2024-01-01 budget Fun CNY category: "Discretionary"
2024-01-01 open Assets:Bank:Checking CNY2024-01-01 open Expenses:Groceries CNY budget: Food2024-01-01 open Expenses:Restaurants CNY budget: Food2024-01-01 open Expenses:Movies CNY budget: Fun
2024-01-01 budget-add Food 2000 CNY2024-01-01 budget-add Fun 300 CNY
2024-01-12 * "Supermarket" "weekly shopping" Assets:Bank:Checking -420.00 CNY Expenses:Groceries
2024-01-20 budget-transfer Fun Food 100 CNYIn January, Food has 2100 CNY assigned, 420 CNY of activity and 1680 CNY available; Fun has 200 CNY available.
Behavior
Section titled “Behavior”Budgets work month by month. For each budget and month, Zhang keeps:
- assigned: what
budget-addandbudget-transferput into the budget, plus what was available at the end of the previous month; - activity: the postings to the linked accounts in that month. Spending on an expense account increases it, a refund decreases it;
- available: assigned minus activity. At the start of the next month, it becomes that month’s assigned amount, so money left over, or overspent, carries over.
Some details:
- A budget exists from the date of its
budgetdirective. A posting to a linked account before that date is not counted, and is reported once asBudgetDoesNotExist. - The amounts of
budget-addandbudget-transfer, and the postings, are converted to the budget’s commodity at their date, with the prices of the ledger, the latest on or before that date. An amount is never added as a number of another commodity: one that no price converts is left out, and reported asBudgetCommodityMismatch. budget-closecloses the budget. Abudget-closewith only a date leaves the budget open through that whole day, and one with a time, such as2024-03-01 18:00:00 budget-close Food, closes it at that time. A closed budget takes no activity: postings to its accounts after the close do not count toward it, and the first one of each account is reported asBudgetClosed. Itsbudget-addandbudget-transferdirectives still count, so you can move what is left to another budget with abudget-transferafter the close.- The budget page shows a budget as closed from the month of its
budget-closeon, and open in the months before; the budget card of the home page leaves it out from that month. A laterbudget-closechanges nothing. - The budget page of the web UI shows the assigned, activity and available amounts of each budget for a month, and
the events of a budget in a month. In queries,
#budgetsand#budget_eventshold the same figures; see Zhang-specific tables.
Errors
Section titled “Errors”| Error | When |
|---|---|
DefineDuplicatedBudget |
A budget directive names a budget that already exists. The second directive is ignored. |
BudgetDoesNotExist |
A budget-add, budget-transfer or budget-close names a budget that is not defined at its date; the directive is ignored. Or a posting’s account is linked to a budget that is not defined at the posting’s date; this is reported once per account and budget, and the transaction is still booked. |
BudgetCommodityMismatch |
The amount of a budget-add or budget-transfer, or a posting to a linked account, is in another commodity than the budget’s and no price on or before its date converts it. The amount does not count toward the budget, and the transaction is still booked. |
BudgetClosed |
A posting to a linked account comes after the budget’s budget-close. It does not count toward the budget; this is reported once per account and budget, and the transaction is still booked. |
Beancount compatibility
Section titled “Beancount compatibility”Beancount has no budget directives. In a Beancount file, write them as custom directives in the form Beancount
itself accepts: a quoted type, quoted budget names, a quoted commodity for budget, and a plain amount for
budget-add and budget-transfer:
| Zhang | Beancount file |
|---|---|
2024-01-01 budget Food CNY |
2024-01-01 custom "budget" "Food" "CNY" |
2024-01-01 budget-add Food 2000 CNY |
2024-01-01 custom "budget-add" "Food" 2000 CNY |
2024-01-20 budget-transfer Fun Food 100 CNY |
2024-01-20 custom "budget-transfer" "Fun" "Food" 100 CNY |
2024-12-31 budget-close Food |
2024-12-31 custom "budget-close" "Food" |
Metadata lines follow as usual. bean-check and Fava accept these lines as ordinary custom entries; Zhang reads
them as budgets and writes budgets this way into Beancount files. The unquoted form earlier versions of Zhang wrote,
custom budget Food CNY, is still read, so existing ledgers keep working, but Beancount rejects it (Invalid token):
switch to the quoted form when you also check the ledger with bean-check. A custom "budget" with other values,
such as Fava’s own budget entries (custom "budget" Expenses:Coffee "daily" 4.00 EUR), stays an ordinary
custom directive.
