beancount 加密货币记账实践

beancount 加密货币记账实践

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 的判定法则非常简单粗暴但极其准确:

  1. 资金从“边界外”流入“边界内” = 追加投资本金(Capital Addition)
  2. 资金从“边界内”流出到“边界外” = 撤回资金/出金(Capital Withdrawal)
  3. 资金在“边界内”互转 = 内部调仓(无外部现金流,不影响本金,只计算盈亏)

C2C 入金(法币买 USDT)

  • 流向: Assets:Bank:CNY (边界外) -> Assets:Crypto:Binance:USDT (边界内)
  • Beangrow 判定: 外部资金注入。完美识别为本金增加。

空投收益(以公允价值入账)

  • 流向: Income:Crypto:Airdrop (边界外) -> Assets:Crypto:Binance:TokenUSDT (边界内)
  • 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 使用正则)
}