Beancount 中的结算日期与转账账户
Martin Blais,2014 年 7 月
http://furius.ca/beancount/doc/proposal-dates
动机
当在投资账户中执行交易时,通常会在交易执行日期(“交易日期”)与资金存入关联现金账户的日期(“结算日期”)之间存在延迟。这使得导入的余额断言有时需要人为调整日期,甚至有时根本无法处理。本文提出为交易或分录添加一个可选的“结算日期”,并定义相应的处理语义来解决此问题。
提案描述
结算日期
在 Beancount 的首个实现中,我曾为每笔交易附加两个日期,但从未实际使用过它们。备用日期虽被附加,但此后被忽略。其含义本应是将交易拆分为两笔,通过某种转账账户实现,这可能具有实用的语义,但我从未进一步开发。
输入示例如下:
2014-06-23=2014-06-28 * "Sale"
Assets:ScottTrade:GOOG -10 GOOG {589.00 USD}
S Assets:ScottTrade:Cash
其中“S”分录标记表示该笔分录需推迟至结算日期处理。
或者,你也可以将日期附加到分录上:
2014-06-23 * "Sale"
Assets:ScottTrade:GOOG -10 GOOG {589.00 USD}
2014-06-28 Assets:ScottTrade:Cash
上述两种语法提案均允许你指定哪些分录应推迟至结算日期。第二种方式更灵活,因为每个分录都可能具有不同的日期;但第一种更受限的语法会减少复杂性。
以上任一语法均可转换为多笔交易,并通过一个转账账户吸收待处理金额:
2014-06-23 * "Sale" ^settlement-3463873948
Assets:ScottTrade:GOOG -10 GOOG {589.00 USD}
Assets:ScottTrade:Transfer
2014-06-28 * "Sale" ^settlement-3463873948
Assets:ScottTrade:Transfer
Assets:ScottTrade:Cash 5890.00 USD
到目前为止,我通过在必要时人为调整余额断言的日期来规避此问题。由于我的交易中卖出操作较少,因此尚未构成重大问题。我尚不确定是否必须为此提供解决方案,也许最好的做法是仅在问题出现时记录应对方法。
也许有人能说服我改变看法。
转账账户
在前一节中,我们讨论了一种风格:一笔在两个账户间转移资金的条目包含两个日期,并最终生成两条独立条目。一个相关但解决方式不同的辅助问题是:如何执行相反操作,即如何合并两条分别记入同一转账账户(有时称为“暂记账户”)的独立条目。
例如,用户可能希望分别输入交易的两端,例如通过在不同输入文件上运行导入脚本。与其手动对账和合并这些条目,我们希望显式支持此功能:通过识别与这些转账账户匹配的交易,并在它们之间建立共同关联。
最重要的是,我们需要能够轻松识别哪一笔交易在另一端没有匹配,这表明数据缺失。
-
此功能的一个原型位于 beancount.plugins.tag_pending。
待解决问题
我们如何确定一个合适的转账账户名称?使用子账户是否是合理的方案?如果用户希望使用一个全局统一的暂存账户怎么办?
TODO
此属性能否解决交易与结算之间的余额断言问题?
TODO [Write out a detailed example]
有什么缺点吗?
TODO
这对资产负债表和损益表有何影响?用户能否清楚地理解这些暂存/转账账户中的金额含义?
TODO
解耦交易
一个更激进的想法是在交易-分录层次结构中增加一个额外层级,支持将多个部分交易分组,并将平衡规则上移至该层级。本质上,两个独立输入的交易(通过某种规则或简单地各自成组)可以形成一个新的平衡单元。
这将对数据结构和 Beancount 的设计提出更严格的要求,但能原生支持部分交易,同时保留其各自的日期、描述等信息。这是否是一个更好的模型?请考虑其优势。
先前的工作
Ledger 的有效日期与辅助日期
Ledger 具有“辅助日期”的概念。其工作方式很简单:任何交易都可以拥有第二个日期,用户可以在运行时(通过 --aux-date)选择使用主日期还是辅助日期。
在存在余额断言的情况下,我不清楚这一功能在实际中应如何使用。如果没有余额断言,我可以理解其作用:只需用结算日期渲染所有内容即可。但这可能仅适用于特定报表。
我更倾向于保持解析的交易集合具有单一语义;若交易的含义因调用条件而异,这将在 Beancount 中开创一个不良先例,我宁愿不破坏这一优良特性,因此默认情况下我更倾向于避免采用此方案。
辅助日期也称为“有效日期”,可与每个单独的分录关联。辅助日期相对于“主日期”或“实际日期”(即记录的分录日期)是次要的:
2008/10/16 * (2090) Bountiful Blessings Farm
Expenses:Food:Groceries $ 37.50 ; [=2008/10/01]
Expenses:Food:Groceries $ 37.50 ; [=2008/11/01]
Expenses:Food:Groceries $ 37.50 ; [=2008/12/01]
Expenses:Food:Groceries $ 37.50 ; [=2009/01/01]
Expenses:Food:Groceries $ 37.50 ; [=2009/02/01]
Expenses:Food:Groceries $ 37.50 ; [=2009/03/01]
Assets:Checking
最初提出此功能是为了预算编制,允许将支出的会计处理移至相邻的预算周期,以便将实际支付金额结转至这些周期。一个月的银行金额可根据需要对应前一个月或后一个月的预算。(注:John Wiegley)
这与我上面建议的某种语法类似——允许用户为每个分录指定一个日期——但其他分录并未拆分为独立交易。这些日期的使用同样由命令行选项(--effective)触发。我假设上述支票账户的分录在 2008/10/16 一次性发生,与报告日期无关。让我们验证这一点:
$ ledger -f settlement1.lgr reg checking --effective
08-Oct-16 Bountiful Blessings.. Assets:Checking $ -225.00 $ -225.00
我原本也是这么想的。这种方法可行,但其问题是:在 2008 年 10 月 1 日(最早生效日期)至 2009 年 3 月 1 日(最晚生效日期)之间编制的任何资产负债表都无法平衡。在这段时间内,部分金额处于“悬而未决”状态,在这些日期中的任意一天编制资产负债表都将无法平衡。
这会破坏 Beancount 的一个不变量:我们必须保证在任何时间点都能生成一份平衡的资产负债表,且任何交易子集都必须平衡。我更倾向于将此示例交易拆分为多个交易,如上文建议所示,将这些处于“悬而未决”状态的临时金额显式地转入一个明确的“悬置”或“转账”账户,使每笔交易都能自行平衡。此外,这一步骤可以作为一个转换阶段实现:用多个交易替换具有生效日期的原始交易,每个新交易对应一个生效日期与交易日期不同的分录(此功能可通过插件按需启用)。
GnuCash
TODO(blais) - GnuCash 和其他图形界面系统是如何处理这个问题的?是否存在标准的账户方法?
参考资料
美国国税局要求您使用交易日而非结算日进行税务申报;根据《国税局第 17 号出版物》:
在已建立市场交易的证券。 对于在已建立证券市场交易的证券,您的持有期从您购买证券的交易日次日开始,到您出售证券的交易日结束。
请勿将交易日与结算日混淆,结算日是指必须完成股票交付并支付款项的日期。
示例。
您是采用现金收付制、按日历年度报税的纳税人。您于 2013 年 12 月 30 日以盈利出售了股票。根据证券交易所的规则,该笔交易通过股票交付完成,时间为交易后第四个交易日,即 2014 年 1 月 6 日。您在同一天收到了售股款项。请在 2013 年的报税表中申报此收益,即使您在 2014 年才收到款项。该收益属于长期或短期,取决于您持有该股票是否超过一年。您的持有期于 12 月 30 日结束。若您以亏损出售股票,也应在 2013 年的报税表中申报。
请勿将交易日与结算日混淆,结算日是指必须完成股票交付并支付款项的日期。