Beancount 和 Fava 账户管理完全指南
会计科目表是 Beancount 账本的核心骨架。一个设计良好的账户层级结构能让每份报表更清晰、每次查询更快速,也能让每个报税季少些痛苦。在本指南中,我们将全面介绍在 Beancount 和 Fava 中创建、查看、更新和关闭账户的所有知识——从入门基础到高级模式。
五种账户类型
Beancount 使用标准的复式记账模型,包含五种根账户类型:
| 类型 | 用途 | 正常方向 | 所属报表 |
|---|---|---|---|
| Assets | 你拥有的资源(现金、投资、房产) | 正数(借方) | 资产负债表 |
| Liabilities | 你欠的债务(信用卡、贷款、抵押贷款) | 负数(贷方) | 资产负债表 |
| Equity | 所有者权益、留存收益、期初余额 | 负数(贷方) | 资产负债表 |
| Income | 收入来源(工资、利息、股息) | 负数(贷方) | 利润表 |
| Expenses | 支出类别(餐饮、房租、水电费) | 正数(借方) | 利润表 |
基本会计恒等式始终成立:
Assets + Expenses + Equity + Income + Liabilities = 0
一个实用的判断方法:如果金额只在某个时间段内有意义(例如"这个月我花了多少钱买吃的?"),就用 Income 或 Expenses。如果它代表一个持续的余额(例如"我的活期账户里有多少钱?"),就用 Assets 或 Liabilities。
账户命名规范
Beancount 中的账户名称是用冒号分隔的层级标识符。规则如下:
- 必须以五种根类型之一开头:
Assets、Liabilities、Equity、Income、Expenses - 每个组成部分以大写字母或数字开头
- 组成部分可以包含字母、数字和连字符(不允许空格或下划线)
- 至少需要两个组成部分(例如
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:VTSAX 或 Liabilities: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:Food 和 Expenses: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 记账的基础。以下是关键要点:
- 始终使用显式的
open指令——它们能捕获拼写错误并强制规范 - 添加货币约束以防止跨币种错误
- 使用一致的命名规范——资产负债表按机构组织,收入/支出按类别组织
- 从简单开始逐步完善——随着报表需求的增长再拆分账户
- 定期进行余额断言——每月对账能及早发现错误
- 正确关闭账户——附带零余额断言
- 善用 Fava 的功能——更新状态指示器、折叠模式和文档集成
- 使用元数据进行自定义分类和报表
祝记账愉快!
- https://beancount.github.io/docs/beancount_language_syntax.html
- https://beancount.github.io/docs/command_line_accounting_cookbook.html
- https://beancount.github.io/docs/beancount_options_reference.html
- https://beancount.github.io/docs/beancount_query_language.html
- https://plaintextaccounting.org/Choosing-accounts
