复式记账工具:Beancount 入门

本文是对 复式记账系列文章 最后一篇的补充,具体介绍一下 Beancount 的功能和用法。

体验

Beancount 提供了一个 在线 demo,可以在线体验一下:

左侧包含了 之前文章 提到过的损益表、资产负债表等报表。

损益表

打开损益表,上半部分是净利润的条形图:

上半部分代表支出(正数、流出),下半部分代表收入(负数、流入)。把鼠标悬停在某个月份上,能看到这个月份的净收入。

右上角还可以切换按月或按年展示。

还可以切换到收入或支出上,只看收入或支出的情况:

默认展示的是堆叠条形图,把鼠标悬停在条形图上,可以高亮的看到这一项支出在每个月的变化。

切换到 Income 或 Expenses 上,可以看到收入或支出的饼图:

页面右上方有时间、账户、筛选几个过滤框。日期除了支持具体的年月日,还支持 year/month/day 等关键字,例如 year-1 - year 可以只展示去年到今年的交易。

页面下半部分是具体每个账户的收支情况:

点击某个账户,还可以看到这个账户的条形图和具体的交易记录:

资产负债表

打开资产负债表,上半部分是净资产变化的折线图:

切换到 Assets、Liabilities 或 Equity 上,可以看到资产、负债或所有者权益的饼图:

页面下半部分是具体每个账户的情况:

语法

体验了上面这些华丽的图表之后,这些这些账是怎么记出来的呢?可以点击左侧的“编辑器”看一下:

只需要这么简单纯文本就行。心动了吗?

开户

在开始记账之前,必须先开通好账户,开通账户的语法是:

1
2
3
4
5
2023-10-10 open Assets:US:BofA:Checking
2023-10-10 open Liabilities:CA:RBC:CreditCard
2023-10-10 open Equity:Retained-Earnings
2023-10-10 open Income:US:Acme:Salary
2023-10-10 open Expenses:Food:Groceries

前面的日期是开通账户的日期,所有的交易都必须在这个日期之后。你可以选择第一笔记账的日期,或者你出生的日期等。

账户可以用 : 分割成很多层级,合理利用层级,可以让账户层次更清晰。

第一级只能使用 AssetsLiabilitiesEquityIncomeExpenses 中的一个,因为 Beancount 需要根据这个区分账户的性质,以决定它们该出现在哪张报表中。

Beancount 还限制了第二级账户必须以大写字母或数字开头,后面的就没有要求了,可以使用中文。如果你想全部使用中文,可以让每个二级账户以数字开头。这样即满足 Beancount 的语法要求,又可以让账户按照你指定的顺序出现在报表中。下面的例子中,为了方便,忽略这个限制,全部使用中文。

交易

交易的语法是:

1
2
3
4
2023-10-10 * "超市购物"
Expenses:食物 1 + 2 * 3 CNY
Expenses:生活用品
Assets:现金 -1000 CNY

第一行分别是日期、标志和摘要。标志有两种 *!* 是最常用的,就是正常的记账。如果你对某一笔账不是很确定,可以标记为 !,方便以后找到它。

后面每一行的格式是缩进、账户、金额、币种。金额支持四则运算,正负表示了流入还是流出,支持千分位的逗号。可以有一行省略金额和币种,因为所有金额相加是 0,所以可以根据其他金额计算出来这个省略的金额是多少。

货币

多币种记账有两种语法,单价和总价:

1
2
3
4
5
6
7
8
9
2023-10-10 * "购汇"
Assets:钱包:美元 100 USD @ 7 CNY
Expense:手续费 70 CNY
Assets:钱包:人民币 -7070 CNY

2023-10-10 * "结汇"
Assets:钱包:人民币 7000 CNY @@ 100 USD
Expenses:手续费 1 USD
Assets:钱包:美元 -101 USD

第一种语法中,表示 1 USD = 7 CNY,Beancount 会按照这个价格,把 USD 转换成 CNY,然后校验这笔交易是否平衡。其实 Beancount 在实现上和之前 多币种记账 介绍的差不多,只不过不用你手动去写那么多账户了,Beancount 自动的创建了 Equity:Conversions:Current 账户,充当了之前提到的“银行”的账户。

第二种语法与第一种语法的区别,就是直接告诉 Beancount 7000 CNY 一共等于 100 USD 了。

无论哪种语法,价格只是用来帮助 Beancount 检查交易是否平衡的,Beancount 不会保留价格信息。例如第一笔交易,Beancount 只会记录钱包里有 100 美元,不会保留这 100 美元是用多少人民币换来的信息。

货币不用提前声明,可以直接使用。货币命名只允许包含字母、下划线、中划线、点和单引号,只能以大写字母开头。

成本

Beancount 不会保留货币转换的价格信息,但投资一般需要记录每次交易的成本信息,以便日后卖出时知道盈亏。对此,Beancount 有专门的语法:

1
2
3
4
5
6
7
8
9
10
11
12
2023-10-10 * "买股票"
Assets:某股票 100 SOME.STOCK { 1 CNY }
Assets:现金 -100 CNY

2023-10-11 * "买股票"
Assets:某股票 100 SOME.STOCK { 2 CNY }
Assets:现金 -200 CNY

2023-10-12 * "卖股票"
Assets:某股票 -100 SOME.STOCK { 1 CNY }
Assets:现金 300 CNY
Income:投资盈亏

与价格不同,Beancount 会记录这个成本信息。例如这个例子中,Beancount 记录的不只是你有 200 股股票,实际记录的是你有 100 股一块钱买来的股票和 100 股两块钱买来的股票。所以卖出时,就需要指定你要卖的是哪个成本的股票。也可以不指定,Beancount 会按照先入先出的规则计算:

1
2
3
4
2023-10-12 * "卖股票"
Assets:某股票 -100 SOME.STOCK {}
Assets:现金 300 CNY
Income:投资盈亏

最终 Beancount 会计算出来这笔交易中的投资盈亏是 -200 CNY。

价格

货币的汇率和股票的价格,都是有可能变动的。可以使用价格语法记录:

1
2
2023-01-01 price USD            6.91 CNY
2023-10-12 price SOME.STOCK 3 CNY

这个价格有什么用呢?刚才的报表页面中有个选项:

这个选项是和币种相关的:

  • 按成本:按照成本展示,例如刚才那个股票就会展示成 300 CNY;
  • 按市价:按照价格展示,例如刚才那个股票就会展示成 600 CNY;
  • 按单位数量:就是保持记账时原始的币种,不做任何转换,例如刚才那个股票就会展示成 200 SOME.STOCK;
  • 转换成 USD:就是把所有货币全部转换成这种货币,参考 多币种记账 的例子。

这些是最基本的记账的语法,更多的语法和关于 Beancount 的介绍,请参考 Beancount 官方文档

安装

Beancount 本身是一个命令行工具,可以在命令行使用,但一般人不会直接这么用。

Beancount 还提供了网页工具叫 Fava,就是刚才看到的那个在线 demo,一般都是通过这个来使用的。

Fava 不光可以看,还可直接用来记。点击左边的加号:

Beancount 和 Fava 都是 Python 写的工具,主要安装方法有两种:通过 pip 安装或通过 Docker 安装。

知道 Docker 是什么的人,应该不用多做介绍。不知道 Docker 是什么的人,不是本文三言两语能说清楚的。

所以这里主要介绍通过 Python 安装的方法:

  1. 通过搜索引擎,使用你的操作系统 + “安装 pip”作为关键字搜索,例如“Windows 安装 pip”,然后照着教程安装 pip;
  2. 在命令行中执行 pip3 install fava 安装 Fava;
  3. 安装完成后,在命令行中执行 fava 你的账本文件 启动 Fava,例如 fava ledger.bean
  4. 然后在浏览器中访问 http://localhost:5000,就能看到和刚才那个在线 demo 一样的网页了。

如果你的电脑可以通过公网访问,或者把 Fava 放在可以通过公网访问的服务器上执行,那么这个账本不光可以在你的电脑上看,还可以在任意电脑或手机上查看。前提是注意访问权限的控制。