复式借贷记账法 Beancount (1) - 基础知识
本文介绍一些基本概念,推荐仔细阅读References. 然后就是 bean-example > example.beancoun 其实也非常具有参考价值。
基本概念
商品单位 Commodities
与其说是我们狭义理解的商品,应该说理解为广义的商品,即具有交换价值的东西。 这里定义的通常是账户的单位。它可以是货币单位,也可以是某一种资产的单位,比如汽车,房子等。
账户 Accounts
账户 | 详情 |
---|---|
Asset 资产 | 有形或者无形的资产,比如 现金, 银行账户, 有价证券, 车子,房子 等等 |
Liabilities 负债 | 各种形式的负债,房贷,车贷,信用卡债,花呗 |
Income 收入 | 工资,奖金,彩票中奖,出租屋收入,股息,存款利息,借贷利息 等等 |
Expenses 支出 | 各种花费,手续费,购物,旅行,支付的贷款利息等等 |
Equity 权益 | 记录账本初始化之前的净收入(income - expenses) |
前面四种账户的类型应该很好理解,可能就是权益类型的账户比较难以理解一些。
The account type “equity” is used for accounts that hold a summary of the net income implied by all the past activity.
所以权益账户的目的就是帮助 zero-out 你所有的账户,使得以下恒等式成立
$$ income + liabilities + assets + expenses + equity = 0 $$
权益账户的用处有
- 初始化账本时已有的数据
其他情况下, 应该可以等价转换为Assets/Libabilities
基本语法
YYYY-MM-DD <操作> <参数...>
创建商品单位
1998-07-22 commodity AAPL
name: "Apple Computer Inc."
对商品定价
2015-04-30 price AAPL 125.15 USD
2015-05-30 price AAPL 130.28 USD
创建和关闭账户
账户需要显式的创建, 这里的关键字是open
, 当现实中账户关闭的时候,也可以关闭 close
。账户命名是 colon-separated tags,一系列的标签,通过冒号连接起来。虽然没有特定的规范,但是在GUI上会以这样的树形结构来聚合账户上的余额,所以一般会利用标签来逐渐缩小范围。
比如
2002-01-17 open Assets:Cash USD
2002-01-17 open Equity:Open-Balances
2002-01-17 open Liabilities:CreditCard:US:Chase:Freedom
2020-01-17 close Liabilities:CreditCard:US:Chase:Freedom
交易
2014-05-05 txn "Cafe Mogador" "Lamb tagine with wine"
Liabilities:CreditCard:CapitalOne -37.45 USD
Expenses:Restaurant
2014-03-19 * "Acme Corp" "Bi-monthly salary payment"
Assets:MyBank:Checking 3062.68 USD ; Direct deposit
Income:AcmeCorp:Salary -4615.38 USD ; Gross salary
Expenses:Taxes:TY2014:Federal 920.53 USD ; Federal taxes
Expenses:Taxes:TY2014:SocSec 286.15 USD ; Social security
Expenses:Taxes:TY2014:Medicare 66.92 USD ; Medicare
Expenses:Taxes:TY2014:StateNY 277.90 USD ; New York taxes
Expenses:Taxes:TY2014:SDI 1.20 USD ; Disability insurance
通用格式
YYYY-MM-DD [txn|Flag] [[Payee] Narration]
[Key: Value] ; meta datas
...
...
[Flag] Account Amount [{Cost}] [@ Price] ; posting
...
...
...
通常交易的directives是txn
但是因为这个是beancount里最常见的记录,因此允许用户省略
通常 *
表示交易数据无误,而!
表示交易数据可能有错。
*
后的两个string,第一个是payee,就是收款方, 可选的,也可以省略 第二个是narration 就是描述,
从第二行起,可以加入metadata meta data完了之后是 交易的数据(postings) 可以是很多条,这也是复式记账的好处,可以完整的描述钱的去向,比如上面的例子中,工资的发放就涉及到了很多账户。
在Posting中可以记录价格,和货币转换
2012-11-03 * "Transfer to account in Canada"
Assets:MyBank:Checking -400.00 USD @ 1.09 CAD
Assets:FR:SocGen:Checking 436.01 CAD
这里一个 @
表示的是单价,如果用 @@
则表示的是总成本
2012-11-03 * "Transfer to account in Canada"
Assets:MyBank:Checking -400.00 USD @@ 436.01 CAD
Assets:FR:SocGen:Checking 436.01 CAD
断言 Balance Assertion
编程的同学应该很容易理解. 这个概念和测试中的断言是一个意思。
当你对某一个账户在某个时间点上做断言的时候,
2015-06-01 balance Liabilities:CreditCard -634.30 USD
Beancount会根据这个来验证其账目的正确性,如果不匹配,则会报错。这个时候就需要对账找出并且修复错误。显然,时不时的对账户做断言是保持账户正确性的必要条件。而且如果出错,你只需要对比上一次正确断言和当前出错断言之间的记录即可。
填充 Padding
填充是和断言一起使用的,当balance assertion出现在pad之后(二者时间之内不能有其他交易),beancount会自动根据pad的参数,将余额调整至断言中的数据。
2019-12-31 pad Liabilities:CreditCard:US:Chase:SapphirePreferred Equity:Opening-Balances
2020-01-01 balance Liabilities:CreditCard:US:Chase:SapphirePreferred -95.0 USD
这个在初始化账本的时候,需要设定账户初始值的时候会频繁使用。
项目结构
Beancount的项目其实就是一堆beancount文件。
由于有include
关键字的存在,其项目结构是可以很松散的。
我的建议是合理的利用文件夹和include来管理beancount项目。
以我个人的经验,首先有一个main.beancount
作为入口文件。
里面并没有任何交易记录,只做一些全局变量的定义,比如Assets,Equity,货币单位。
然后利用 include 去索引其他文件夹
include "income/_index.beancount"
include "expense/_index.beancount"
include "property/_index.beancount"
include "vehicle/_index.beancount"
include "investment/_index.beancount"
这里我利用_index.beancount
来做文件的索引,每一个文件夹相当于一个scope 就会有一个index文件。这个index位于每一个文件夹下,确保每一个数据文件都被include进来,同时我也在index文件中定义在这个scope里需要的账户。
至于如何分文件夹,则是一个千人千面的问题了。
由于我大部分的账目都是信用卡,然后银行卡多数是付信用卡账单。这些都可以自动化导入,所以我利用年份命名的文件来记录这些流水。
这里面的大部分去想都是expense。但是因为比较杂所以不好归纳到单个文件。
至于expense
文件夹下,我只放置一些周期性的支出,比如手机账单,水电气账单,车险房险等。
车贷房贷都是单独track,所以各放入了一个文件夹。
收入里面则按照公司,每一个公司一个beancount文件。
参考文献
- Beancount Syntax Cheat Sheet (on Google Doc)
- https://wzyboy.im/post/1063.html
- https://beancount.github.io/
- https://byvoid.com/zht/blog/beancount-bookkeeping-2/
系列介绍
准备用一个系列的文章来介绍这个工具和一些技巧。 这些技巧有一些是我从已有的模版中找出来,也有一些是在Google Group里看到大家的推荐,自己又尝试出来的方法。