9.投资交易与损益追踪
投资交易与损益追踪是个人财务中较为复杂的一环,但在 Beancount 这种纯文本会计系统中,它遵循着严谨而优雅的逻辑。本章将深入探讨如何在 Beancount 中记录投资活动,重点在于理解“交易批次(Lot)”的概念,以及如何准确计算已实现与未实现的损益。
投资交易的核心:交易批次(Lot)
在 Beancount 中,记录投资交易的核心在于追踪“成本基础(Cost Basis)”。当你购买一项资产(如股票、基金)时,你不仅获得了资产的数量,还锁定了其获取成本。这个特定数量、特定成本的资产集合,我们称之为一个“交易批次”或“批次”。
购买资产(建立批次)
购买资产时,我们需要在资产账户中记录数量,并在成本字段中明确指出每股的成本。同时,这笔交易会消耗现金。
2024-01-15 * "买入苹果股票"
Assets:Investments:Brokerage 10 AAPL {150.00 USD}
Assets:Investments:Cash -1500.00 USD
Expenses:Financial:Commissions 5.00 USD
代码讲解:
Assets:Investments:Brokerage 10 AAPL {150.00 USD}:这一行表示我们买入了 10 股 AAPL,每股的成本基础是 150.00 USD。{}语法是关键,它告诉 Beancount 这些股票是“持有成本”的,需要单独追踪。Assets:Investments:Cash:现金账户减少了 1500.00 USD。Expenses:Financial:Commissions:交易佣金作为费用记录。
假设几天后,你又进行了一次购买,但价格不同:
2024-01-20 * "再次买入苹果股票"
Assets:Investments:Brokerage 5 AAPL {160.00 USD}
Assets:Investments:Cash -800.00 USD
Expenses:Financial:Commissions 5.00 USD
此时,你的 Assets:Investments:Brokerage 账户中就持有了两个批次的 AAPL:
- 10 股,每股成本 150.00 USD。
- 5 股,每股成本 160.00 USD。
已实现损益(Realized P/L)
当你卖出资产时,就会产生已实现损益。关键问题在于:你卖出的是哪个批次的股票?这直接影响到你的资本利得计算,进而影响税务。Beancount 提供了严格的“批次匹配(Booking)”机制来确保数据的准确性。
明确指定批次卖出
最直接的方式是在卖出时,明确指定你要卖出的批次。
2024-02-10 * "卖出部分苹果股票"
Assets:Investments:Brokerage -5 AAPL {150.00 USD} @ 170.00 USD
Assets:Investments:Cash 845.00 USD
Expenses:Financial:Commissions 5.00 USD
Income:Investments:CapitalGains
代码讲解:
Assets:Investments:Brokerage -5 AAPL {150.00 USD}:我们明确指定卖出的是成本为 150.00 USD 的那一批次中的 5 股。@ 170.00 USD:这是卖出价格,用于记录交易时的市场价,但它不参与交易的平衡计算,主要用于记录和报告。Assets:Investments:Cash:收到了 5 * 170.00 = 850.00 USD 的现金,减去 5.00 USD 佣金,净增 845.00 USD。Income:Investments:CapitalGains:这个账户是自动平衡的关键。Beancount 会计算这笔交易的损益并填入此账户。我们来算一下:- 卖出成本:5 股 * 150.00 USD/股 = 750.00 USD
- 卖出收入(扣除佣金前):5 股 * 170.00 USD/股 = 850.00 USD
- 已实现利润:850.00 - 750.00 = 100.00 USD
- 交易后,
CapitalGains账户将记录 -100.00 USD(注意:在复式记账中,收入类账户通常为负值表示盈利)。
模糊匹配与默认策略
如果你不指定批次,只写 -5 AAPL {},Beancount 会根据账户的默认预订策略(Booking Method)来选择批次。默认策略通常是 STRICT,即如果存在多个可能的批次,它会报错,强制你做出明确选择。这可以有效防止数据录入错误。
你也可以配置账户使用 FIFO(先进先出)或 LIFO(后进先出)策略。例如,在 open 指令中添加元数据:
2024-01-01 open Assets:Investments:Brokerage AAPL booking:FIFO
这样,当发生模糊匹配时,系统会自动选择最早购入的批次进行销售。
未实现损益(Unrealized P/L)
未实现损益是指你持有的资产,其当前市场价值与你的成本基础之间的差额。只要你不卖出,这笔利润就只是“账面浮盈”。Beancount 不会自动为你生成未实现损益的交易,但可以通过插件或查询来追踪。
使用插件自动记录
unrealized 插件可以自动在每个报告期末(通常是年末)生成一笔交易,将未实现损益记录下来,以便在报表中反映资产的当前市场价值。
首先,在你的 Beancount 配置文件中启用插件:
plugin "beancount.plugins.unrealized" "Unrealized"
启用后,你需要提供资产的市场价格。这通过 price 指令完成:
2024-03-01 price AAPL 180.00 USD
当月末或年末运行报告时,插件会检查你持有的 AAPL。对于成本为 150.00 USD 的剩余 5 股,市场价为 180.00 USD,每股浮盈 30.00 USD,总浮盈 150.00 USD。插件会自动生成类似下面的交易:
2024-03-31 U "Unrealized gain for AAPL"
Assets:Investments:Brokerage:Unrealized 150.00 USD
Income:Investments:UnrealizedGains -150.00 USD
这笔交易将未实现的利润计入一个专门的收入账户,同时增加一个子资产账户(或直接增加原资产账户,取决于插件配置)来平衡。这样,你的资产负债表就能反映出资产的市值。
交易佣金的会计处理
交易佣金是投资成本的一部分。在税务上,买入时的佣金通常会计入资产的成本基础,而卖出时的佣金则从卖出收入中扣除。
将买入佣金计入成本基础
为了精确计算损益,最规范的做法是将买入佣金分摊到每股成本中。这在 Beancount 中可以通过 {} 语法的扩展功能实现。
2024-01-15 * "买入苹果股票 (含佣金)"
Assets:Investments:Brokerage 10 AAPL {150.50 USD} ; 1500 + 5 / 10
Assets:Investments:Cash -1505.00 USD
这里,我们将总成本 1505.00 USD (1500 股票 + 5 佣金) 分摊到 10 股上,每股成本变为 150.50 USD。这样,在未来卖出时,计算出的资本利得会更准确,因为它已经包含了买入成本。
另一种更高级的语法是同时指定每股成本和总成本,这在处理佣金时非常有用:
2024-01-15 * "买入苹果股票 (含佣金)"
Assets:Investments:Brokerage 10 AAPL {150.00 USD + 5.00 USD}
Assets:Investments:Cash -1505.00 USD
这种写法明确告诉 Beancount,每股成本是 150.00 USD,但总成本包含了 5.00 USD 的额外费用。系统会自动将这 5.00 USD 分摊到这 10 股上,每股成本变为 150.50 USD。
股息收入的记录
股息是投资产生的收入,处理起来相对简单。通常分为现金股息和股票股息。
现金股息
现金股息直接增加你的现金余额,并记录为收入。
2024-04-15 * "收到AAPL现金股息"
Assets:Investments:Cash 25.00 USD
Income:Investments:Dividends -25.00 USD
股票股息
股票股息是公司以增发股票的形式支付的股息。这相当于以零成本获得了一批新股票,但这批新股票的成本基础需要根据股息的市场价值来确定。
2024-05-20 * "收到股票股息"
Assets:Investments:Brokerage 1 AAPL {175.00 USD} ; 假设除息日股价为175
Income:Investments:Dividends -175.00 USD
这笔交易记录了你获得了一股新的 AAPL,其成本基础为 175.00 USD,同时产生了一笔 175.00 USD 的股息收入。
股票分割的处理
股票分割(如 2:1 拆分)会改变股票的数量和每股成本,但不改变总的投资价值。在 Beancount 中,你需要手动调整持仓批次来反映这一变化。
假设你持有 100 股 AAPL,每股成本 200.00 USD,现在发生了 2:1 的股票分割。
2024-06-01 * "2:1 股票分割"
Assets:Investments:Brokerage -100 AAPL {200.00 USD}
Assets:Investments:Brokerage 200 AAPL {100.00 USD}
代码讲解:
- 第一行:冲销掉分割前的 100 股,每股成本 200.00 USD。
- 第二行:记录分割后的新持仓,数量变为 200 股,每股成本相应调整为 200.00 / 2 = 100.00 USD。
重要提示:这种处理方式会丢失原始的购买日期信息,这对于计算长期/短期资本利得至关重要。为了解决这个问题,可以在成本中显式指定原始日期:
2024-06-01 * "2:1 股票分割 (保留日期)"
Assets:Investments:Brokerage -100 AAPL {200.00 USD, 2024-01-15}
Assets:Investments:Brokerage 200 AAPL {100.00 USD, 2024-01-15}
这样,分割后的新股票批次仍然保留了原始的购买日期。
平均成本法(Average Cost Basis)
在某些情况下,例如在非应税账户(如退休账户)中,或者根据某些国家的税法,你可能需要使用平均成本法来计算损益。这种方法将所有批次的股票合并,计算出一个加权平均成本。
Beancount 通过 * 符号来支持平均成本法的计算。
2024-01-15 * "买入"
Assets:Investments:Brokerage 10 AAPL {150.00 USD}
Assets:Investments:Cash -1500.00 USD
2024-01-20 * "再次买入"
Assets:Investments:Brokerage 5 AAPL {160.00 USD}
Assets:Investments:Cash -800.00 USD
2024-03-10 * "卖出 (使用平均成本法)"
Assets:Investments:Brokerage -8 AAPL {*}
Assets:Investments:Cash 1440.00 USD
Income:Investments:CapitalGains
代码讲解:
- 当 Beancount 处理这笔卖出交易时,遇到
*符号,它会:- 找到账户中所有 AAPL 的批次(10 股 @ 150.00 和 5 股 @ 160.00)。
- 计算加权平均成本:
(10 * 150 + 5 * 160) / 15 = 153.333... USD。 - 以这个平均成本减少 8 股。
- 自动计算并平衡
Income:Investments:CapitalGains账户。
这种方法极大地简化了在需要使用平均成本场景下的记账工作。
总结
掌握 Beancount 的投资记账,核心在于理解“批次”和“成本基础”的概念。通过 {} 语法,我们能精确追踪每一笔投资的成本来源。已实现损益通过明确的卖出交易和成本匹配来计算,而未实现损益则通过插件和价格数据来反映。佣金的处理、股息的记录、股票分割的调整,以及平均成本法的应用,都是在这些核心概念之上的具体实践。熟练运用这些工具,你就能在纯文本的世界里,建立起一个强大、精确且完全透明的投资追踪系统。