记账
记账这件事,本质上是在回答三个问题:
- 钱从哪来?
- 钱现在在哪?
- 钱最后去哪了?
听起来很简单,但只要你的金融活动稍微复杂一点,这三问立刻变成一道「多变量方程」:
- 多个账户:银行卡、支付宝、信用卡、交易所、链上钱包……
- 多种资产类型:储蓄、贷款、投资……
- 多种货币:CNY、USD、BTC、各种山寨币……
- 多个时间维度:分期、预支、借贷……
也正因为如此,我前后换过好几套方案。
2016–2021:网易有钱 - 当时需求很朴素:记人民币收入、储蓄、日常开销。它能自动同步银行流水、支付宝微信账单,对国内场景非常方便。
2021–2024:MoneyWiz - 出国后我需要多币种,并且主要使用英国的银行账户。MoneyWiz 在多币种、海外账户同步上很顺手。
2024:我开始记录加密资产,这时候情况开始非常复杂了,我不只想知道「总额涨了多少」,而是想要:每一笔买入/卖出的明细、不同资产的占比、每日的浮盈浮亏、更严谨的收益率计算。
MoneyWiz 对投资/加密资产支持很有限;我又试了有知有行,它能记录投资前后总额并算收益率,但无法记录到每笔明细,很多价格需要手动维护,浮盈浮亏也无法自动计算。
最后我接触到复式记账和 Beancount,彻底解决了我的问题。
我才意识到,很多时候我们觉得记账麻烦,并不是 UI 不够漂亮、交互不够顺滑,而是记账方法不够科学。当方法足够科学时,你甚至不需要 UI,一个 CLI + 几个纯文本文件 + 一套清晰语法,就能把财务世界描述得非常准确。
复式记账法
复式记账乍看很反直觉,但一旦掌握,会发现它非常强大和灵活,而且会迫使你用更清晰的方式理解金融活动。
五个桶(账户类型)
复式记账会把所有账户归到五类(可以理解成五个装豆子的桶):
- 资产 Assets:现金、银行存款、有价证券、链上资产……
- 负债 Liabilities:信用卡欠款、房贷、车贷……
- 收入 Income:工资、奖金、利息……
- 花费 Expenses:吃饭、购物、旅行、订阅……
- 权益 Equity:调节/归档用的「底座」,例如期初余额、误差修正等
所有金融活动都是「桶之间的转移」
- 收入 → 资产:发工资(收入桶减少,资产桶增加)
- 资产 → 花费:买东西(资产桶减少,花费桶增加)
- 负债 → 资产:借钱(负债桶增加,资产桶增加)
- 资产 → 负债:还款(资产桶减少,负债桶减少)
- 花费 → 资产:退货(花费桶减少,资产桶增加)
- 资产 → 收入:投资亏损(资产桶减少,收入桶减少)
你会发现:按这种符号约定,收入账户的余额经常是负数。这不是 bug,而是记账视角不同。
可以这样想象:把「收入」想成一个装着你一生(过去和未来)劳动成果的桶。每次你拿到工资,其实是在从这个桶里取出一部分,放进你的资产里。你能取的越多,收入桶里的数值就越往负的方向走。
所以收入为负数并不表示「你欠了收入」,只是因为你在从这个桶取出资产。这也涉及到复式记账法的一个核心规则:一笔交易里,所有数字相加必须等于 0。这也是它检验正确性的关键:你少写一笔、写错一位数,系统就会当场报警。
在 Beancount 常见的符号约定下,你会看到类似这样的「会计恒等式」写法:
(收入 + 负债) + (资产 + 花费) = 0
你也可以把它理解为更传统的表达:你赚到的、借来的,最终要么变成你拥有的资产,要么被花掉。
Beancount
Beancount 是目前我用过最舒服、也最适合复杂财务世界的纯文本复式记账工具。
它不是复式记账软件的开创者,更早的代表是 Ledger。但 Beancount 在 Ledger 的概念上做了不少改良,也经历了时间的考验(2007 年开始)。
学习 Beancount 最直接的方法是看官方文档:Getting Started with Beancount、Beancount Language Syntax,或者看这篇文章也很不错:Beancount —— 命令行复式簿记 | wzyboy’s blog
这篇博客我不会展开讲语法和使用细节,而是用几个例子让你快速感受 Beancount 的强大之处和为什么说它更适合 Crypto 和 AI 时代。
处理复杂交易
使用 Beancount 可以优雅处理复杂交易,以下例子涉及多对多,多账户 + 多人复杂交易,但是可以描述很清楚
2016-02-05 * "饭店" "和室友吃饭"
Assets:Cash:Wallet -300.00 CNY ; 我用现金支付
Assets:Receivables:Bob -200.00 CNY ; 室友帮我付的现金
Expenses:Food:DiningOut +250.00 CNY ; AA 我的一半
Assets:Receivables:Bob +250.00 CNY ; AA 室友的一半
这里同时发生了:
- 你付了部分现金
- 室友也付了部分现金
- AA 分摊
- 你对室友产生/抵消应收
最后只需要看 Assets:Receivables:Bob 余额就可以知道你欠室友多少钱,看 Expenses:Food:DiningOut 余额就可以知道每个月吃饭开销花了多少钱。
如果用「单式记账 + 备注」硬堆,后面基本一定算不清,而复式记账把结构直接写出来,之后统计就变得非常自然。
处理多币种交易
跨币种交易通常涉及汇率问题,Beancount 也能优雅处理
2016-02-10 * "商店" "买东西"
Assets:Cash -200.00 USD
Liabilities:CMB:CreditCards -650.00 CNY @@ 100.00 USD
Expenses:Clothing:Pants +150.00 USD
Expenses:Clothing:Shoes +150.00 USD
这类「刷卡以人民币记账、但实际消费以美元计价」的场景,在跨境生活里非常常见。Beancount 的表达方式很直接:用一条记录把两边币种的关系和当时汇率绑定住,之后查询/报表都能基于它继续推导。
更适合 Crypto 交易
Beancount 不限制货币单位:USD、CNY、BTC、USDT、甚至任何你自定义的 token 都可以。再配合类似 SQL 的查询工具 bean-query,拿来做加密资产投资分析非常顺手。
举一个看起来很复杂,但记录很简洁的例子:
2025-07-23 price BTC 1 USD
2025-07-24 * "OKX" "买BTC"
Assets:Crypto:USD -150 USD
Assets:Crypto:BTC 149 BTC {1 USD}
Expenses:TradingFee:Crypto 1 USD
2025-07-24 * "OKX" "买BTC"
Assets:Crypto:USD -60 USD
Assets:Crypto:BTC 19 BTC {3 USD}
Expenses:TradingFee:Crypto 3 USD
2025-07-24 * "OKX" "卖BTC"
Assets:Crypto:BTC -198 BTC {} @ 2 USD
Assets:Crypto:USD 298 USD
Income:Investment
2025-07-25 price BTC 4 USD
这个例子里包含了:
- 多次买入,成本不同
- 手续费
- 卖出时自动匹配成本(
{}让 Beancount 自己去找) - 市价(
price)随时间变化
仅基于这些记录,Beancount 可以自动算出:
- 总收益/已实现收益/未实现收益
- 各类收益率(例如资金加权收益率 Modified Dietz、时间加权收益率 TWRR、甚至你自定义的任意收益计算)
换句话说:你只负责把事实写清楚,任何复杂计算都可以交给 Beancount。
我的 Beancount 实践
把账本当代码管理。
编辑器
我用 VSCode,配合 Beancount、Beancount Formatter 和以下配置实现语法高亮、自动补全、错误检查、格式化等。
{
"beancount.mainBeanFile": "main.bean",
"beancount.runFavaOnActivate": false,
"beancount.completePayeeNarration": true,
"beancount.fixedCJKWidth": true,
"beancount.inputMethods": ["pinyin"],
"beancount.instantAlignment": false,
"editor.formatOnSave": true
}

项目结构
Beancount 天然支持模块化:不同类型交易拆到不同文件,再 include 进主入口,维护成本非常低。
.
├── books
│ ├── 2025
│ │ ├── 2025.bean
│ │ ├── cn.bean
│ │ ├── crypto.bean
│ │ ├── daily.bean
│ │ ├── periodic.bean
│ │ ├── prices.bean
│ └── books.bean
├── scripts
│ ├── importer-dbs-credit.js
│ ├── importer-dbs-debit.js
│ ├── importer-okx.js
├── accounts.bean
├── commodity.bean
├── config.pbtxt
├── dashboards.yaml
├── main.bean
main.bean 是入口文件,集中放配置、插件和 include:
option "title" "DIYgod's Book"
option "operating_currency" "USD"
option "booking_method" "LIFO"
option "account_rounding" "Equity:Rounding-Error"
plugin "beancount_periodic.recur"
plugin "beancount_periodic.split"
2024-01-01 custom "fava-option" "auto-reload" "true"
2024-01-01 custom "fava-option" "default_page" "income_statement/?conversion=units&interval=day"
2024-01-01 custom "fava-extension" "fava_portfolio_returns" "{
'beangrow_config': 'config.pbtxt',
}"
2024-01-01 custom "fava-extension" "fava_dashboards" "{
'config': 'dashboards.yaml'
}"
include "accounts.bean"
include "books/books.bean"
include "commodity.bean"
accounts.bean 定义所有账户(略去部分):
; Expenses 费用 —— 外出就餐、购物、旅行等
1995-06-09 open Expenses:Food:Restaurant
; ... 省略若干行 ...
; Income 收入 —— 工资、奖金等
2020-04-01 open Income:Salary
; ... 省略若干行 ...
; Assets 资产 —— 现金、银行存款、有价证券等
2024-01-01 open Assets:Bank:DBS SGD
2024-01-01 open Assets:Crypto:OKX:BTC BTC
; ... 省略若干行 ...
; Liabilities 负债 —— 信用卡、房贷、车贷等
2024-01-01 open Liabilities:Bank:DBS SGD
; ... 省略若干行 ...
; Equity 权益 —— 用于「存放」某个时间段开始前已有的豆子
2024-01-01 open Equity:Opening-Balances
2024-01-01 open Equity:Rounding-Error
commodity.bean 定义货币/资产,并用 price 指定价格来源(后面会讲自动更新):
2025-01-01 commodity USDT
name: "Tether"
2025-01-01 commodity BTC
name: "Bitcoin"
price: "USD:coinbase/BTC-USD"
2025-01-01 commodity USD
name: "United States Dollar"
2025-01-01 commodity QQQ
name: "NASDAQ-100 Index"
price: "USD:alphavantage/price:QQQ:USD"
books/2025/prices.bean 用于记录每日价格(自动生成),让持仓浮盈浮亏可被计算:
2025-01-01 price BTC 93346.48 USD
2025-01-02 price BTC 94384.76 USD
; ... 省略若干行 ...
几种常见的 Crypto 交易
下面这些例子来自我的实际习惯:交易不是手填的,而是通过 scripts/importer-okx.js 从 OKX 交易记录自动生成。
稳定币现货交易
1)买入:用 USDT 买 BTC + 手续费
2025-11-14 * "OKX" "Buy BTC with USDT"
Assets:Crypto:OKX:USDT -3022.493 USDT
Assets:Crypto:OKX:BTC 0.0302113288 BTC {100000 USDT}
Expenses:TradingFee:Crypto:OKX
这里我把手续费留空,让 Beancount 自动补齐(利用「每笔交易加起来为 0」的规则)。
但如果你的 BTC 可能来自 USDT、USDC 等不同稳定币,之后统计收益会涉及汇率与币种转换。为了让分析更统一,我常用一个过渡账户把成本统一成 USD:
2025-11-14 * "OKX" "Buy BTC with USDT"
Assets:Crypto:OKX:USDT -3022.493 USDT
Equity:Exchange 3022.493 USDT
Equity:Exchange -3022.493 USDT @ 1 USD
Assets:Crypto:OKX:BTC 0.0302113288 BTC {100000 USD}
Expenses:TradingFee:Crypto:OKX
Equity:Exchange 的作用很像「统一换算层」:把不同稳定币交易都折算成 USD 口径,后续报表会非常舒服。
2)卖出:卖 BTC 得 USDC + 自动算收益
2025-09-18 * "OKX" "Sell BTC for USDC"
Assets:Crypto:OKX:BTC -0.100011 BTC {} @ 117600 USD
Equity:Exchange 11756.00101788 USD
Equity:Exchange -11756.00101788 USD @ 1 USDC
Assets:Crypto:OKX:USDC 11756.00101788 USDC
Expenses:TradingFee:Crypto:OKX -5.29258212 USD
Income:Investment
{} @ 117600 USD:成本价由 Beancount 自动从历史记录里匹配,卖出价是 117600 USD- 多出来的部分进
Income:Investment:收益就这样自然出来了
如果你不需要统一换算,也可以简化成:
2025-09-18 * "OKX" "Sell BTC for USDC"
Assets:Crypto:OKX:BTC -0.100011 BTC {} @ 117600 USDC
Assets:Crypto:OKX:USDC 11756.00101788 USDC
Expenses:TradingFee:Crypto:OKX -5.29258212 USDC
Income:Investment
币币现货交易
用 BTC 买 ETH
2025-08-22 * "OKX" "Buy ETH with BTC"
Assets:Crypto:OKX:BTC -0.025828016279999998 BTC {} @ 112480.295 USD
Equity:Exchange 2,905.1428904392 USD
Equity:Exchange -2,905.1428904392 USD
Assets:Crypto:OKX:ETH 0.6820274505 ETH {4224.16 USD}
Income:Investment
Expenses:TradingFee:Crypto:OKX 0.0001705495 ETH {4224.16 USD}
币币交易的成本/收益更容易乱,但把过程统一到 USD 口径后,就会变得非常清晰:用 BTC 换到的 ETH,有明确的 USD 成本;手续费和之后的收益也能被正确计入。
U 本位合约
U 本位合约在交易所内部不是真的卖出 BTC,但为了把盈亏落到资产变化上,我用一个「借币卖出/买回」近似模型来表达:
- 开仓做空:等价于「借 BTC 卖出,换成 USDT」
- 平仓:等价于「用 USDT 买回 BTC 归还」
- 盈亏会自然体现在最后多出来(或少了)的部分上
2025-12-01 * "OKX" "合约 BTC-USDT 做空开仓"
Assets:Crypto:OKX:Futures:BTC -10 BTC @ 100000 USD
Equity:Exchange 1000000 USD
Equity:Exchange -1000000 USD @ 1 USDT
Assets:Crypto:OKX:Futures:USDT 1000000 USDT
2025-12-10 * "OKX" "合约 BTC-USDT 做空平仓"
Assets:Crypto:OKX:Futures:USDT 1000000 USDT
Equity:Exchange 1000000 USDT
Equity:Exchange -1000000 USDT @ 1 USD
Assets:Crypto:OKX:Futures:BTC -10 BTC {80000 USD}
Income:Investment
真实合约还会涉及保证金、资金费、强平、结算币种差异等。更严谨的做法可以继续拆分账户模型,但这套写法已经能在大多数场景里把结果记清楚、算出来。
币本位合约
币本位合约更复杂:仓位通常是「USD 计价的 BTC 价格敞口」,而不是固定数量 BTC。想按每日价格计算浮盈浮亏会很复杂,需要「双账模型」(事实账 + 估值账)。
我目前选择先把它简化成:平仓时手动算出以 BTC 为单位的收益,只记录最终 BTC 变化,只是这样会牺牲当前持仓未实现盈利的数据:
2025-11-21 * "OKX" "合约 BTC-USD 1.0"
Income:Investment
Assets:Crypto:OKX:BTC 0.007433571994392 BTC {85400 USD}
自动化脚本 + AI 记账
通过自动化脚本和 AI,可以极大简化记账工作量,让「记账」变成「对账」。
自动生成交易记录
Beancount 是纯文本,这意味着它天生适合自动化生成记录和更新资产价格。
社区里有很多导入工具,比如:beangulp、smart_importer。
但我自己用得最多的还是自写脚本(例如 OKX 的 scripts/importer-okx.js、DBS 的 scripts/importer-dbs.js)。原理都类似:从接口或者网页获取交易数据 → 转成 Beancount 文本。
对于一些没有接口、甚至没有账单导出的账户(比如我现在用的 Trust),直接截图丢给 AI 识别也很省心:

自动更新价格
Beancount 本身是离线系统,不会自动从互联网拉价格,所以我每天会把最新的币价/股价写进 books/2025/prices.bean,让报表能计算当日估值与未实现盈利。
官方提供了开箱即用的 beanprice,支持 Coinbase、Coinmarketcap、Alphavantage 等来源,一个命令就能更新:
bean-price -i --update-rate daily --no-cache main.bean >> books/2025/prices.bean
AI 分析与可视化
很多人把记账停在「记下来」就结束了,但真正有价值又容易被遗忘的是记录之后如何分析。
Beancount 在分析和可视化能力上非常夸张:
- 可以装插件的 Web 界面:Fava
- 类 SQL 查询语言:BQL(Beancount Query Language)
先看一些我常用的效果:
投资品的价格走势图(Fava 自带):

不同投资品的收益曲线,以及各种加权收益率(插件 Fava Portfolio Returns):

特定资产的变化曲线、分布占比、列表(插件 Fava Dashboards + 自定义 BQL):

更爽的是:现在有了 vibe coding,时代变了。 现在甚至不需要先学会 BQL 怎么写——可以直接让 AI 写。
比如我会这样提需求:
利用 Fava Dashboards 插件,在 dashboards.yaml 编写 BQL 实现一个展示我所有加密货币持仓随时间变化的曲线图。
曾经要折腾好久的个性化财务分析,现在可能就是一句话。
结语
我用了 Beancount 一年,几乎全部需求都很好得到了满足,非常满意,也在公司内部做过分享。这篇博客就是把分享内容整理成文字,希望能把它推荐给更多人。
我也承认,Beancount 的门槛对大多数人来说不低——它更像「写账本的编程语言」,而不是一个点点点的 App。 但我同样相信:随着 AI 发展,这些门槛会越来越低。未来每个人都可以用更低成本驾驭这种强大的工具,实现对自己财务的全面掌控。
如果你也正在经历:
- 多币种生活
- 投资品越来越多
- 账越记越乱
- 分析越来越复杂
那我建议你至少花半天时间试试 Beancount。 它可能会让你第一次觉得:原来我终于能把钱讲清楚了。