跳到主要内容

Beancount 和 Fava 账户管理完全指南

· 阅读需 14 分钟
Mike Thrift
Mike Thrift
Marketing Manager

会计科目表是 Beancount 账本的核心骨架。一个设计良好的账户层级结构能让每份报表更清晰、每次查询更快速,也能让每个报税季少些痛苦。在本指南中,我们将全面介绍在 Beancount 和 Fava 中创建、查看、更新和关闭账户的所有知识——从入门基础到高级模式。

五种账户类型

Beancount 使用标准的复式记账模型,包含五种根账户类型:

类型用途正常方向所属报表
Assets你拥有的资源(现金、投资、房产)正数(借方)资产负债表
Liabilities你欠的债务(信用卡、贷款、抵押贷款)负数(贷方)资产负债表
Equity所有者权益、留存收益、期初余额负数(贷方)资产负债表
Income收入来源(工资、利息、股息)负数(贷方)利润表
Expenses支出类别(餐饮、房租、水电费)正数(借方)利润表

基本会计恒等式始终成立:

Assets + Expenses + Equity + Income + Liabilities = 0

一个实用的判断方法:如果金额只在某个时间段内有意义(例如"这个月我花了多少钱买吃的?"),就用 Income 或 Expenses。如果它代表一个持续的余额(例如"我的活期账户里有多少钱?"),就用 Assets 或 Liabilities。

账户命名规范

Beancount 中的账户名称是用冒号分隔的层级标识符。规则如下:

  • 必须以五种根类型之一开头:AssetsLiabilitiesEquityIncomeExpenses
  • 每个组成部分以大写字母或数字开头
  • 组成部分可以包含字母、数字和连字符(不允许空格或下划线)
  • 至少需要两个组成部分(例如 Expenses:Food,不能只是 Expenses
  • 冒号(:)用于分隔层级
; 有效的账户名称
Assets:US:BofA:Checking
Liabilities:CA:RBC:CreditCard
Equity:Retained-Earnings
Income:US:Acme:Salary
Expenses:Food:Groceries
Assets:Crypto:BTC-Holdings

; 无效的账户名称
assets:checking ; 根类型首字母小写
Assets:my checking ; 不允许包含空格
Expenses ; 只有一个组成部分

资产负债表账户的推荐命名模式为:

类型 : 国家 : 机构 : 账户 : 子账户

例如:Assets:US:Vanguard:401k:VTSAXLiabilities:US:Chase:Sapphire

对于支出和收入账户,使用基于类别的命名方式:

Expenses:Food:Groceries
Expenses:Housing:Utilities:Electric
Income:US:Employer:Salary

自定义根名称

你可以为五种根类型重命名,用于本地化或个人偏好:

option "name_assets"       "Actifs"
option "name_liabilities" "Passifs"
option "name_equity" "Capital"
option "name_income" "Revenus"
option "name_expenses" "Depenses"

创建账户(Open 指令)

每个账户在记录交易之前都必须使用 open 指令进行声明。完整语法为:

YYYY-MM-DD open Account [ConstraintCurrency,...] ["BookingMethod"]

基本开户

2014-05-01 open Assets:US:BofA:Checking

指定货币约束

限制货币可以防止意外记录错误的货币:

2014-05-01 open Assets:US:BofA:Checking       USD
2014-05-01 open Assets:Cash USD,CAD,EUR
2012-03-01 open Assets:US:ETrade:Main:ITOT ITOT

指定记账方法

对于投资账户,可以指定卖出时如何匹配持仓批次:

2014-02-11 open Assets:US:ETrade:IVV   IVV   "FIFO"
2014-02-11 open Assets:US:Schwab:AAPL AAPL "LIFO"
2014-02-11 open Assets:US:Fidelity GOOG "STRICT"

可用的记账方法:

方法行为
"STRICT"默认值。要求精确指定持仓批次;遇到歧义时报错
"FIFO"先进先出——优先减少最早的持仓批次
"LIFO"后进先出——优先减少最新的持仓批次
"AVERAGE"合并所有持仓批次并重新计算平均成本
"NONE"不进行批次匹配;接受任何价格

添加元数据

2013-03-14 open Assets:US:BTrade:HOOLI
category: "taxable"
institution: "BTrade Corp"
account-number: "XX-1234-5678"

策略性选择开户日期

  • 对于通用账户如 Expenses:Groceries,使用你的出生日期(这样可以获得一生的累计数据)
  • 对于与工作相关的收入账户,使用入职日期
  • 对于特定机构的账户(银行账户、信用卡),使用实际开户日期

使用插件自动开户

如果你想在原型开发阶段跳过手动编写 open 指令:

plugin "beancount.plugins.auto_accounts"

这会自动为交易中引用的任何账户生成 open 指令。但这样做会降低错别字检测能力,因此不建议在正式使用中启用

查看和查询账户

使用 bean-query (BQL)

# 列出所有账户及余额
bean-query ledger.beancount "SELECT account, units(sum(position)) GROUP BY 1"

# 仅列出支出账户
bean-query ledger.beancount "SELECT account WHERE account ~ 'Expenses'"

# 带流水余额的账户明细
bean-query ledger.beancount \
"SELECT date, account, position, balance WHERE account ~ 'BofA:Checking'"

# 特定账户的日记账视图
bean-query ledger.beancount "JOURNAL 'Assets:US:BofA:Checking'"

使用 bean-report

# 试算平衡表(所有账户的最终余额)
bean-report ledger.beancount balances

# 资产负债表
bean-report ledger.beancount balsheet

# 利润表
bean-report ledger.beancount income

# 特定账户的日记账
bean-report ledger.beancount journal -a Assets:US:BofA:Checking

使用 Fava

Fava 提供了丰富的可视化界面来浏览账户:

  • 资产负债表页面:Assets、Liabilities 和 Equity 的交互式树形视图
  • 利润表页面:Income 和 Expenses 的交互式树形视图
  • 账户页面:点击任意账户名称可查看其日记账、变动和余额标签页
  • 筛选栏:使用正则表达式来筛选匹配的账户(例如 Assets:US

更新账户(重命名和重组)

Beancount 没有内置的重命名指令,但有几种方法可以实现。

1. 查找替换

简单的查找替换可以工作,但要小心——Assets:Bank 也会匹配 Assets:Bank:Cash。使用支持单词边界的匹配模式:

sed -i 's/Assets:US:OldBank:Checking/Assets:US:NewBank:Checking/g' *.beancount

2. rename_accounts 插件

beancount_reds_plugins 包提供了一个强大的重命名插件:

plugin "beancount_reds_plugins.rename_accounts.rename_accounts" "{
'Expenses:Taxes' : 'Income:Taxes',
'Assets:House:Capital-Improvements' : 'Expenses:House:Appliances',
}"

该插件:

  • 使用子字符串匹配(Expenses:Taxes:Federal 自动变为 Income:Taxes:Federal
  • 支持正则表达式和反向引用
  • 自动为重命名后的账户生成 Open 指令
  • 不会修改你的源文件——只改变内存中的表示
  • 可以通过注释插件行来开关

3. 关闭后重新开户模式

对于真实的账户迁移(例如更换银行):

; 旧账户
2010-01-01 open Assets:US:OldBank:Checking USD

; 关闭旧账户,开设新账户
2024-06-15 close Assets:US:OldBank:Checking
2024-06-15 open Assets:US:NewBank:Checking USD

; 转移剩余余额
2024-06-15 * "转账到新银行"
Assets:US:OldBank:Checking -5000.00 USD
Assets:US:NewBank:Checking 5000.00 USD

关闭账户

close 指令标记一个账户为不再活跃:

2016-11-28 close Liabilities:CreditCard:CapitalOne

关闭账户的作用

  • 如果在关闭日期之后有任何过账,会引发错误
  • 在其活跃期之外的报表中过滤掉该账户
  • 告诉 Fava 在树形视图中隐藏该账户(可配置)

何时关闭账户

  • 当你关闭了现实中的银行账户或信用卡时
  • 当你换了工作时
  • 当你整合或重组会计科目表时
  • 当你卖出房产或关闭投资仓位时

关闭前务必断言余额为零

Beancount 不会在关闭时自动验证余额为零。需要手动添加断言:

2023-12-31 balance Assets:US:OldBank:Savings  0.00 USD
2023-12-31 close Assets:US:OldBank:Savings

组织你的会计科目表

从简单开始,逐步完善

你不需要在第一天就设计出完美的会计科目表。先从大类开始,随着报表需求的增长再进行拆分。Beancount 的作者表示他有 250 多个支出账户,全部是随着时间推移自然创建的。

常见的组织模式

模式一:按机构组织(适用于资产负债表账户)

Assets:US:BofA:Checking
Assets:US:BofA:Savings
Assets:US:Vanguard:401k:VTSAX
Assets:US:Vanguard:401k:VBTLX
Liabilities:US:Amex:Platinum
Liabilities:US:Chase:Sapphire

模式二:按类别组织(适用于收入和支出账户)

Expenses:Food:Groceries
Expenses:Food:Restaurant
Expenses:Food:Coffee
Expenses:Housing:Rent
Expenses:Housing:Insurance
Expenses:Housing:Utilities:Electric
Expenses:Housing:Utilities:Water
Expenses:Transport:Subway
Expenses:Transport:Gas
Expenses:Health:Medical
Expenses:Health:Dental

模式三:按地区组织(适用于多国财务)

Assets:US:BofA:Checking
Assets:CA:RBC:Checking
Assets:UK:HSBC:Current
Income:US:Acme:Salary
Income:CA:Freelance:Consulting

模式四:按房产或项目组织(适用于房地产或商业)

Assets:US:Loft4530:Property
Income:US:Loft4530:Rental
Expenses:Loft4530:Electricity
Expenses:Loft4530:Insurance
Expenses:Loft4530:Maintenance

模式五:关联账户镜像(使用相同的机构组件)

Assets:US:ETrade:Cash
Assets:US:ETrade:AAPL
Income:US:ETrade:Dividends
Income:US:ETrade:PnL
Expenses:US:ETrade:Commissions

层级应该有多深?

  • 2-3 层对于支出类别是常见的(Expenses:Food:Restaurant
  • 3-4 层适用于结构化的资产负债表项目(Assets:US:Vanguard:401k:VTSAX
  • 避免超过 5 层,除非你有明确的报表需求
  • 当 Fava 在树形视图中折叠深层级时,深层级结构效果很好

一个实际的例子

以下是个人财务的实用会计科目表:

; ── 资产 ──
Assets:US:BofA:Checking USD
Assets:US:BofA:Savings USD
Assets:US:Vanguard:401k:VTSAX VTSAX
Assets:US:Vanguard:Roth:VTSAX VTSAX
Assets:US:ETrade:Cash USD
Assets:US:ETrade:AAPL AAPL
Assets:Cash:Wallet USD

; ── 负债 ──
Liabilities:US:Amex:Platinum USD
Liabilities:US:Chase:Freedom USD
Liabilities:US:BofA:Mortgage USD

; ── 收入 ──
Income:US:Employer:Salary
Income:US:Employer:Bonus
Income:US:Employer:Match401k
Income:US:ETrade:Dividends
Income:US:BofA:Interest

; ── 支出 ──
Expenses:Food:Groceries
Expenses:Food:Restaurant
Expenses:Food:Coffee
Expenses:Housing:Rent
Expenses:Housing:Insurance
Expenses:Housing:Utilities:Electric
Expenses:Housing:Utilities:Water
Expenses:Transport:Subway
Expenses:Transport:Taxi
Expenses:Transport:Gas
Expenses:Health:Medical
Expenses:Health:Dental
Expenses:Health:Pharmacy
Expenses:Shopping:Clothing
Expenses:Shopping:Electronics
Expenses:Entertainment:Streaming
Expenses:Entertainment:Books
Expenses:Travel:Flights
Expenses:Travel:Hotels
Expenses:Taxes:Federal
Expenses:Taxes:State
Expenses:Taxes:SocialSecurity
Expenses:Taxes:Medicare

; ── 权益 ──
Equity:Opening-Balances
Equity:Retained-Earnings

Fava 特有功能

更新状态指示器

这是 Fava 在账户管理方面最出色的功能之一。在任何账户上添加以下元数据:

2014-05-01 open Assets:US:BofA:Checking  USD
fava-uptodate-indication: TRUE

Fava 会在账户旁显示彩色圆点:

  • 绿色圆点:最近一条记录是通过的余额断言(账户已对账)
  • 红色圆点:最近一条记录是失败的余额断言(需要关注)
  • 黄色圆点:存在最近的记录但不是余额断言(尚未对账)
  • 灰色圆点:在回溯期内没有活动

配置灰色圆点的阈值:

2016-06-14 custom "fava-option" "uptodate-indicator-grey-lookback-days" "60"

树形视图控制

控制 Fava 如何显示账户:

; 在树中显示已关闭的账户
2016-06-14 custom "fava-option" "show-closed-accounts" "true"

; 显示零交易的账户
2016-06-14 custom "fava-option" "show-accounts-with-zero-transactions" "true"

; 显示零余额的账户
2016-06-14 custom "fava-option" "show-accounts-with-zero-balance" "true"

折叠模式

默认折叠深层嵌套的账户:

; 折叠所有 3 层及更深的账户
2016-06-14 custom "fava-option" "collapse-pattern" ".*:.*:.*"

; 折叠特定的子树
2016-06-14 custom "fava-option" "collapse-pattern" "Assets:US:Vanguard:.*"

在账户日记账中包含子账户

在 Fava 中查看账户日记账时,包含子账户的过账记录:

2016-06-14 custom "fava-option" "account-journal-include-children" "true"

反转符号以提高可读性

默认情况下,收入和负债显示为负数(它们的自然方向)。要将它们显示为正数:

2016-06-14 custom "fava-option" "invert-income-liabilities-equity" "true"

文档管理

Fava 将文档处理与你的账户层级集成在一起。设置文档根目录:

option "documents" "/path/to/documents"

然后按账户路径组织文件:

/path/to/documents/
Assets/
US/
BofA/
Checking/
2024-01-15.january-statement.pdf
2024-02-15.february-statement.pdf
Liabilities/
US/
Amex/
Platinum/
2024-03-15.march-bill.pdf

YYYY-MM-DD 开头的文件会被 Fava 自动发现,并显示在账户的日记账视图中。

常见错误及避免方法

1. 账户名称拼写错误

一个简单的拼写错误如 Expenses:Grocries 就会创建一个完全不存在的、非预期的新账户。

解决方法:不要在正式环境中使用 auto_accounts 插件。要求显式声明 open 指令。Beancount 会对任何未声明的账户立即报错:

ERROR: Invalid reference to unknown account 'Expenses:Grocries'

2. 忘记设置货币约束

没有货币约束时,你可能会不小心将 EUR 记入一个仅限 USD 的账户。

解决方法:始终在 open 指令中指定货币:

2014-01-01 open Assets:US:BofA:Checking  USD

3. 不定期进行余额断言

没有定期的余额断言,错误可能数月都不会被发现。

解决方法:为每个活跃账户添加每月余额断言:

2024-01-01 balance Assets:US:BofA:Checking   5,432.10 USD
2024-02-01 balance Assets:US:BofA:Checking 4,890.55 USD
2024-03-01 balance Assets:US:BofA:Checking 6,123.00 USD

4. 命名规范不一致

混用不同的命名模式(例如 Expenses:FoodExpenses:US:Food)会使查询和报表变得混乱。

解决方法:选定一种规范并坚持使用。资产负债表账户使用国家前缀,收入和支出账户使用基于类别的命名。

5. 关闭账户时不断言余额为零

close 指令不会验证余额。你可能会关闭一个仍有余额的账户。

解决方法:始终将 close 与余额断言配对使用:

2023-12-31 balance Assets:US:OldBank:Savings  0.00 USD
2023-12-31 close Assets:US:OldBank:Savings

高级模式

多币种技巧

声明你的操作货币以获得专用的报表列:

option "operating_currency" "USD"
option "operating_currency" "EUR"

对于多币种账户,列出所有允许的货币:

2014-01-01 open Assets:Cash  USD,CAD,EUR

多币种的余额断言必须逐个货币进行:

2024-01-01 balance Assets:Cash     562.00 USD
2024-01-01 balance Assets:Cash 210.00 CAD
2024-01-01 balance Assets:Cash 60.00 EUR

使用 Pad 和 Balance 进行初始设置

使用 pad 指令来建立期初余额,无需手动计算金额:

2000-05-28 open Assets:US:BofA:Checking  USD
2000-05-28 pad Assets:US:BofA:Checking Equity:Opening-Balances
2024-07-01 balance Assets:US:BofA:Checking 12,345.67 USD

Beancount 会自动生成调整交易。一个重要的注意事项:余额断言检查的是指定日期开始时的余额。因此,1 月 2 日的 pad 需要在 1 月 3 日或之后进行余额断言。

使用账户元数据进行分类

open 指令上使用元数据进行自定义报表分类:

2014-01-01 open Assets:US:BofA:Checking  USD
category: "liquid"
tax-status: "taxable"

2014-01-01 open Assets:US:Vanguard:401k USD
category: "retirement"
tax-status: "tax-deferred"

使用 BQL 查询元数据:

SELECT account, META("category") WHERE META("tax-status") = "taxable"

为账户历史添加备注

为任何账户的日记账附加带日期的备注:

2024-03-20 note Assets:US:BofA:Checking "致电咨询争议扣款,参考编号 #12345"
2024-06-01 note Liabilities:US:Chase:Sapphire "致电客户保留部门后免除了年费"

这些备注会出现在 Fava 中账户的日记账视图中,提供审计追踪。

追踪账户和资金标记

Beancount 没有 Ledger 的虚拟过账功能,但你可以使用子账户来进行资金标记:

; 在活期账户内追踪应急基金
Assets:US:BofA:Checking:EmergencyFund USD
Assets:US:BofA:Checking:Operating USD

; 追踪报销
Assets:Receivables:Employer:Travel USD
Assets:Receivables:Friend:SharedDinner USD

税务友好的支出类别

构建支出账户结构以简化报税准备:

Expenses:Health:Medical:Deductible
Expenses:Charity:Deductible
Expenses:Business:Office
Expenses:Business:Equipment
Expenses:Education:Professional

快速参考速查表

任务语法
开设账户2024-01-01 open Assets:US:BofA:Checking USD
关闭账户2024-12-31 close Assets:US:OldBank:Savings
断言余额2024-01-01 balance Assets:US:BofA:Checking 5,432.10 USD
填充至余额2024-01-01 pad Assets:Cash Equity:Opening-Balances
添加备注2024-01-15 note Assets:US:BofA:Checking "Monthly reconciliation done"
附加文档2024-01-15 document Assets:US:BofA:Checking "/path/to/statement.pdf"
添加元数据open 后的下一行缩进写入键值对
自动开户(开发用)plugin "beancount.plugins.auto_accounts"
限制货币2024-01-01 open Assets:Cash USD,EUR
设置记账方法2024-01-01 open Assets:US:ETrade:AAPL AAPL "FIFO"

总结

良好的账户管理是高效 Beancount 记账的基础。以下是关键要点:

  1. 始终使用显式的 open 指令——它们能捕获拼写错误并强制规范
  2. 添加货币约束以防止跨币种错误
  3. 使用一致的命名规范——资产负债表按机构组织,收入/支出按类别组织
  4. 从简单开始逐步完善——随着报表需求的增长再拆分账户
  5. 定期进行余额断言——每月对账能及早发现错误
  6. 正确关闭账户——附带零余额断言
  7. 善用 Fava 的功能——更新状态指示器、折叠模式和文档集成
  8. 使用元数据进行自定义分类和报表

祝记账愉快!

References: