beancount 记录数字货币有很大的优势,天然支持多币种,且有完善的投资记账支持(cost/price/lots)。然而 beancount 设计之初没有考虑到加密货币,因此某些场景极不方便。下面列举常见的加密货币场景以及我使用 beancount 记账的实践,可能谈不上最佳,读者若有好的记账办法也不吝赐教。
稳定币 #
将 USDT 设置为本币,其他所有稳定币都当作以 USDT 计价的货币。在稳定币之间的兑换可以这样记录(其实就是当作价格为1.00 USDT的加密货币),因为价格差导致的损失/收益统一记录在 Expenses 账户中。
2025-01-01 * "" ""
Assets:Crypto:CEX:Binance:USDT -1000.00 USDT
Expenses:Crypto:Spot:USDC
Assets:Crypto:CEX:Binance:USDC 999.99 USDC {1.00 USDT}
转账 #
精确但繁琐 #
最精确的是写清楚每一笔 lots 的成本,但是比较繁琐(可以借助脚本来自动填充)。
2025-01-01 * "" ""
Assets:Crypto:CEX:Binance:USDC -999.99 USDC {1.00 USDT}
Expenses:Crypto:Transfer
Assets:Crypto:Wallet:XXXX:USDC 999.99 UDSC {1.00 USDT}
洗成本 #
每次转账当成一次卖出,优点是简单,账户中不会出发繁多的不同 cost 的 lots,缺点是会使未实现收益转变为实现收益,同时成本发生变化。
2025-01-01 * "" ""
Assets:Crypto:CEX:Binance:USDC -999.99 USDC {} @ 1.00 USDT
Expenses:Crypto:Transfer
Assets:Crypto:Wallet:XXXX:USDC 999.99 UDSC {1.00 USDT}
新建无成本的虚拟资产 #
这个是我早期的做法,方便,但是无法追踪投资收益变化,且会增加记账复杂度,这里介绍但不推荐了。例如对于 BTC 转账,如果只是短期行为,可以记录为 BTC_PH 转账
投资回报 #
主要使用 Beangrow 进行投资回报检视。其将Beancount账户分为两部分:“边界内(你的投资组合)”和“边界外(外部世界)”。在 .pbtxt 配置文件中定义的 asset_account(加密货币)和 cash_account(你的各类 USDT 钱包/交易所账户),共同构成了这个“边界内”的资金池。
Beangrow 的判定法则非常简单粗暴但极其准确:
- 资金从“边界外”流入“边界内” = 追加投资本金(Capital Addition)
- 资金从“边界内”流出到“边界外” = 撤回资金/出金(Capital Withdrawal)
- 资金在“边界内”互转 = 内部调仓(无外部现金流,不影响本金,只计算盈亏)
C2C 入金(法币买 USDT)
- 流向:
Assets:Bank:CNY(边界外) ->Assets:Crypto:Binance:USDT(边界内) - Beangrow 判定: 外部资金注入。完美识别为本金增加。
空投收益(以公允价值入账)
- 流向:
Income:Crypto:Airdrop(边界外) ->Assets:Crypto:Binance:Token或USDT(边界内) - Beangrow 判定: 外部资金注入。它把“白嫖”来的空投视作你从外部拿了一笔钱加仓,完美剥离了运气成分,后续只算持仓表现。
法币出金(USDT 卖成法币)
- 流向:
Assets:Crypto:Binance:USDT(边界内) ->Assets:Bank:CNY(边界外) - Beangrow 判定: 资金撤回。Beangrow 会按比例结算这部分资金的累计收益,本金基数随之减小。
USDT 直接消费
- 流向:
Assets:Crypto:Card:USDT(边界内) ->Expenses:Shopping(边界外) - Beangrow 判定: 资金撤回(出金)
只需要在配置文件中,把你所有的 USDT 账户都罗列为 cash_account 即可。如果账户命名很规范(比如都在 Assets:Crypto 树下),可以使用正则匹配(match_accounts)来批量归拢,或者手动罗列:
Protocol Buffers
# beangrow.pbtxt 示例
investment {
currency: "BTC"
match_accounts: "Assets:Crypto:.*:BTC"
# 将所有存放 USDT 的地方都定义为该组合的“现金池”
# 手动指定方式:
cash_account: "Assets:Crypto:Binance:USDT"
cash_account: "Assets:Crypto:OKX:USDT"
cash_account: "Assets:Crypto:Ledger:USDT"
cash_account: "Assets:Crypto:Card:USDT" # 甚至包括用来消费的加密货币卡
# 如果账户体系非常规整,也可以用正则:
# match_accounts: "Assets:Crypto:.*:USDT" (注意:需要确保使用的 Beangrow 版本支持对 cash_account 使用正则)
}