Beancount 复式记账

Beancount 是一款纯文本的复式记账工具。纯文本的优点就在于方便处理,可以使用喜欢的任何文本编辑器或者脚本语言进行处理。同时记账的格式也比较清晰,即便不使用 fava 等工具,直接查看文本记录也拥有很高的可读性。

Beancount 的安装:

1
2
pip install beancount fava
fava main.bean

上述命令同时安装了 beancount 本体和 fava,fava 为 beancount 提供了更加强大美观的 web 页面展示。可以在这里试试在线的 Demo

开始记账

(Income + Liabilities) + (Assets + Expenses) + Equity = 0

(收入+负债)+(资产+费用)+ 权益 = 0

上边这个式子就是 beancount 记账的基础,同时也是通过这个式子验证记账的正确性。

  • 收入(-):外部来源的收入,如工资或奖金
  • 负债(-):所负的债务,如信用卡或贷款
  • 资产(+):持有的资产,如现金、存款、理财等
  • 费用(+):各类花费,如外出就餐、旅行、购物等
  • 权益(-):记录权益,一般用于处理记账开始时已有的资产负债等,除此之外基本上都是自动生成的,不需要人工记录

开立账户

首先要开设自己的各类账户,比如储蓄账户、信用卡账户、现金等。

一级分类不支持中文,二级分类开始支持中文名称。分类层级可以按照自己的喜好进行设置,后续在 fava 界面上按照层级进行展示。

1
2
3
4
5
6
;开设日期 open 账户类型:一级分类:二级分类 [记账货币]
1970-01-01 open Assets:Cash ;现金
1970-01-01 open Assets:Bank:A银行储蓄卡 CNY
1970-01-01 open Liabilities:CreditCard:B银行信用卡 CNY
1970-01-01 open Liabilities:CreditCard:C银行信用卡 USD
1970-01-01 open Equity:OpenBalance

这边有个特殊的账户 Equity:OpenBalance,在开始记账时,一般不是处于资产负债均为 0 的理想状态。为了记账能够满足上面提到的等式,需要这个特殊账户来让记账处于平衡状态,下一小节初始化账户会进行介绍。

除了账户和负债之外,我们还需要定义收入和费用的类型,便于我们记账。可以将其理解为收入来源和花费去向的途径,也可以将其作为分类使用。

1
2
3
4
5
6
7
8
9
;收入
1970-01-01 open Income:Salary

;费用
1970-01-01 open Expenses:Food:午餐
1970-01-01 open Expenses:Food:早餐
1970-01-01 open Expenses:Food:晚餐
1970-01-01 open Expenses:Shopping:商超百货
1970-01-01 open Expenses:Shopping:衣物

初始化账户

开立账户之后,账户内一般会有已经存在资产或者负债的情况,这时我们需要将账户初始化到正确的状态。

1
2
3
4
5
6
7
8
9
10
;日期 记账类型 注释
;账户 金额

1970-01-01 * "现金,初始余额100.00元"
Assets:Cash 100.00 CNY
Equity:OpenBalance -100.00 CNY

1970-01-01 * "信用卡,初始余额-200元"
Liabilities:CreditCard:B银行信用卡 -200.00 CNY
Equity:OpenBalance 200.00 CNY

账户初始化的记录格式符合记账的格式,如目前拥有现金 100 元,可以记录拥有资产 Assets:Cash 100 元。这时整体等式结果不为零,需要从 OpenBalance 这个特殊账户中 -100 元资产,使等式平衡。负债也是同理,只不过符号为负。

可以简单理解为,在开始记账时,从某处获取了 100 元,存入了现金账户,使现金账户有了 100 元资产。同时信用卡账户截至开始记账时总共花费了 200 元到某处,账户目前有 200 元负债。而这里的某处,我们不再向前追溯资产负债最初的来源交易,统一用 OpenBalance 这个特殊账户替代这个“某处”,使账户处于平衡状态。

记录交易

账户设置好之后,就可以开始记账,记账的格式和初始化账户时的记录相同。

1
2
3
4
5
6
7
8
9
10
;日期 记账类型 注释
;账户 金额

2021-03-01 * "M公司" "工资收入"
Assets:Bank:A银行储蓄卡 1000.00 CNY
Income:Salary -1000.00 CNY

2021-03-01 * "N饭店" "晚餐支出"
Expenses:Food:晚餐 50.00 CNY
Assets:Bank:A银行储蓄卡 -50.00 CNY

记账的发生涉及至少两个账户,保持等式的平衡。比如晚餐花费了 50 元,用储蓄卡支付,所以记录为晚餐费用 50 元,同时储蓄卡资产减少 50 元。关于收入,工资收入使资产账户增加了 1000 元,同时收入账户减少了 1000 元。这边的收入账户 Income 可以理解为可以是无穷大负值的一个账户,只要产生了收入,就记录为从收入账户转移金额到资产账户。

一条记账记录可以分成这些要素:

  • 日期
  • 交易类型:可以使用 * 或者 !* 代表已经完成的交易,金额已经清楚,“看起来没啥问题了”。 ! 代表不完整的交易,需要再次确认或者更新,“看起来还不太对”
  • 交易对象:可选,记录交易对象
  • 描述:可选,记交易的相关信息,如类型或者原因等,便于判断
  • 账户:交易发生的账户
  • 金额:交易发生的金额
1
2
3
4
5
6
2021-03-01 * "A城市一天的旅行花费"
Expenses:Food:早餐 10.00 CNY
Expenses:Food:午餐 30.00 CNY
Expenses:Food:晚餐 50.00 CNY
Expenses:Trip:车费 20.00 CNY
Assets:Bank:A银行储蓄卡

可以将多条交易合并成一条记账进行记录,多个账户中可以留一个账户的发生金额为空白,beancount 会自动进行平衡记录。

上述是简单记账所需要的一些信息,当然,beancount 语法还支持更多高级语法,可以给交易添加 tag、link、meta-data 等信息,此处不做详细描述。

文件组织

默认情况下可以将所有内容都按顺序写在一个文件里,当然为了便于个人信息的管理,可以将各种信息拆分到各个层级以及文件中去,通过在主文件里 include 各个文件实现文件组织。

文件分类的方式可以按自己的喜好进行,比如按日期分文件、按交易类别分文件、按交易账户分文件,都是可以的。以日期为例:

1
2
3
4
5
6
7
8
9
¦--main.bean
¦--accounts.bean ;账户开立和初始化等
¦--expenses.bean ;费用类别
¦--income.bean ;收入类别
¦--2020
¦ ¦--01-2020.bean
¦ ┕--02-trip.bean
┕--2021
┕--01-2021.bean

然后可以在 main.bean 中包含各文件:

1
2
3
4
5
6
7
; main.bean
include "accounts.bean"
include "expenses.bean"
include "income.bean"
include "2020/01-2020.bean"
include "2020/02-trip.bean"
include "2021/01-2021.bean"

后续使用 fava 时只需要执行 fava main.bean 即可。使用 bean-reportbean-web 等 beancount 自带的命令也可以生成报告或简单的 web 页面,但从美观和易用上还是建议直接使用 fava 作为前端。