Beancount 中的库存管理
Beancount 的库存系统是一个强大的功能,用于跟踪随时间推移买卖的资产,例如股票、共同基金或外币。 它允许精确跟踪成本基础,这对于计算资本利得和了解投资组合表现至关重要。 本教程涵盖了在您的账本中管理库存的核心机制。
核心概念
库存管理的核心是跟踪头寸。“头寸”简单来说就是账户中持有的某种商品的数量。 Beancount 区分两种基本类型的头寸。
头寸类型
-
简单头寸 (无成本):这是一个标准的余额过账。 它表示商品的数量,没有任何相关的购置成本。 它适用于现金或简单的 余额断言。
Assets:Bank:Checking 100.00 USD -
具有成本基础的头寸:这种类型的头寸不仅包括单位数量和商品,还包括获得该商品的成本。 这是库存跟踪的基础。 成本在花括号
{}中指定。Assets:Invest:VTSAX 10 VTSAX {100.00 USD, "lot-1"}在这个例子中,我们持有 10 单位的
VTSAX。 每个单位的购置成本为 100.00 美元。 这批特定的股票被标识为一个“批次”。
库存操作
您可以对库存执行两种主要操作:
-
增加(添加到库存):当您购买商品时,您会增加您的库存。 您创建一个新的批次,其中包含特定数量的单位和成本基础。
2024-01-15 * "购买股票"
Assets:Invest:STOCK 50 STOCK {25.00 USD, "lot-1"}
Assets:Bank:Checking -1250.00 USD在这里,我们以每单位 25.00 美元的价格购买 50 单位的
STOCK。 这会在Assets:Invest:STOCK账户中创建一个批次。 -
减少(从库存中移除):当您出售商品时,您会减少您的库存。 您必须指定您要出售的批次。 这是通过在花括号中提供匹配信息来完成的。
2024-01-20 * "出售股票"
Assets:Invest:STOCK -25 STOCK {25.00 USD}
Assets:Bank:Checking 625.00 USD在此交易中,我们从以每单位 25.00 美元的价格购买的批次中出售 25 单位的
STOCK。
记账方法
当您减少库存时,如果多个批次匹配或匹配不明确,Beancount 需要一个规则来决定从哪个特定批次中提取。 这个规则被称为“记账方法”。 您可以为整个文件设置默认方法,也可以为每个帐户指定一个方法。
1. STRICT (默认)
STRICT 方法是默认且最安全的记账方法。 它强制执行显式且明确的匹配。
2024-01-01 open Assets:Invest:STOCK "STRICT"
- 需要精确的批次匹配:您必须在减少过账 (
{...}) 中提供足够的信息,以唯一标识要出售的批次。 - 不明确匹配时出错:如果提供的信息与多个批次匹配,Beancount 将引发错误,迫使您更加具体。
- 例外:如果减少过账完全移除账户中持有的总单位数,则允许使用空的成本说明符 (
{})。
2. FIFO (先进先出)
FIFO 方法自动将减少量记入最早的可用批次。
2024-01-01 open Assets:Invest:STOCK "FIFO"
- 自动解析:它通过选择最旧的匹配批次来解决歧义。
- 按时间顺序匹配:这是一种常见的会计方法,您假设您正在出售您持有时间最长的资产。 这是许多国家/地区出于税务目的而必需的方法。
3. LIFO (后进先出)
LIFO 方法与 FIFO 相反。 它将减少量记入最新的可用批次。
2024-01-01 open Assets:Invest:STOCK "LIFO"
- 反向时间顺序:它选择与减少标准匹配的最近购置的批次。
- 税务优化:在某些司法管辖区,此方法可用于税务优化,例如,通过首先出售成本基础最高的股票以最大限度地减少资本利得。
4. NONE
NONE 方法完全禁用批次匹配。
2024-01-01 open Assets:Invest:STOCK "NONE"
- 无批次匹配:Beancount 不会尝试将减少量与增加量匹配。
- 允许混合符号:这允许一个帐户同时持有同一商品的正余额和负余额。 此行为类似于 Ledger CLI 工具处理商品的方式。
批次说明
“批次”是在特定时间和价格购买的特定商品块。 当您创建或减少头寸时,您可以详细指定其批次属性。
完整说明
当增加库存(购买)时,您可以为批 次指定最多三个属性:
Assets:Invest:STOCK 10 STOCK {
100.00 USD, # 成本基础 (每单位成本)
2024-01-15, # 购置日期
"lot-identifier" # 唯一的字符串标签
}
虽然这三个都是可选的,但提供至少成本基础是标准做法。
匹配方法
当减少库存(出售)时,您使用相同的语法来指定要从哪个批次出售。
-
按成本匹配:这是最常用的方法。
Assets:Invest:STOCK -5 STOCK {100.00 USD} -
按日期匹配:如果成本相同,您可以使用购置日期消除歧义。
Assets:Invest:STOCK -5 STOCK {2024-01-15} -
按标签匹配:标签提供了一种万无一失的方法来识别批次。
Assets:Invest:STOCK -5 STOCK {"lot-identifier"} -
匹配任何批次:一组空的花括号
{}将匹配任何可用的批次。 这通常与FIFO或LIFO记账一起使用,其中特定批次是自动选择的。Assets:Invest:STOCK -5 STOCK {}
价格处理
理解成本基础 ({}) 和价格 (@) 之间的区别至关重要。 它们服务于不同的目的,不能互换。
价格 vs 成本
{cost}:定义资产的购置成本。 它是库存批次本身的一部分,用于记账减少量和计算资本利得。@ price:在交易时记录市场价格的注释。 它用于货币转换或记录特定日期的市场价值。
以下是三种情况:
-
价格注释(转换):使用
@从一种货币转换为另一种货币。Assets:Forex 1000 USD @ 0.85 EUR -
成本基础(购置):购买资产时使用
{}建立其成本。Assets:Invest 10 STOCK {100.00 USD} -
两者(记录价格的销售):出售资产时,使用
{}标识要出售的批次,并使用@记录销售价格。 这允许自动计算资本利得。Assets:Invest -10 STOCK {100.00 USD} @ 105.00 USD此条目以每股 105.00 美元的价格出售了 10 股
STOCK,这些股票的成本为每股 100.00 美元。
价格使用规则
- 价格注释 (
@) 不影响记账哪个批次。 批次匹配完全由成本基础 ({}) 和帐户的记账方法处理。 @符号仅用于:
- 货币转换。
- 记录交易时资产的市场价值。
- 提供资本利得计算的销售价格。
配置
您可以全局或按帐户配置记账方法。
全局记账方法
您可以使用 option 指令为整个 Beancount 文件设置默认记账方法。
option "booking_method" "STRICT"
可用选项为 "STRICT"、"FIFO"、"LIFO" 和 "NONE"。
按帐户覆盖
对于不同的帐户使用不同的方法通常很有用。 例如,您可能希望退休帐户使用 FIFO,但应税经纪帐户使用 STRICT,以确保您出售特定的税务批次。 您可以在打开帐户时设置记账方法。
2024-01-01 open Assets:Retirement:401K "FIFO"
2024-01-01 open Assets:Taxable:Stock "STRICT"
最佳实践
-
库存组织:为了保持您的账本清晰简洁,强烈建议您为持有的每种独特商品使用单独的帐户。
# 良好:按商品分离帐户
Assets:Invest:VTSAX ; 此处仅 VTSAX 头寸
Assets:Invest:VFIAX ; 此处仅 VFIAX 头寸避免在同一帐户中混合不同的股票或基金,因为它会使库存管理变得复杂。
-
批次管理:
-
为批次使用有意义的标签,特别是对于特定的交易,如税务损失收割或员工股票授予。
Assets:Invest:STOCK 10 STOCK {100.00 USD, "tax-loss-harvest-2024"} -
使用注释记录您的交易。 这使您的账本以后更容易阅读和理解。
Assets:Invest:STOCK -10 STOCK {100.00 USD} @ 110.00 USD ; 收益:10%
- 调试:如果您遇到错误或意外行为,Beancount 提供了用于检查库存状态的工具。
-
检查库存状态:
bean-doctor工具可以向您显示文件中任何时间点所有库存的准确状态。将
<LINENO>替换为交易之后的行号,以查看其效果。 -
验证批次匹配:
bean-check工具验证您的整个文件。 它将捕获任何记账错误,例如STRICT模式下的不明确批次匹配。