跳转到主要内容

预测未来交易

构建一个独立的、经过验证的 Beancount 场景账簿,包含未来日期的收入、支出和贷款还款。

将未来日期的交易放在一个独立的场景账簿中,以便在你的财务报告中预测现金、支出和债务。本教程使用普通的 Beancount 条目和固定的规划周期。你的实际账簿与你的假设保持分离。

兼容性检查(2026 年 9 月 7 日): 这些示例已在标准 Beancount 3.2.3、beanquery 0.2.0Fava 1.30.16 上测试通过。该 Fava 版本未附带预测插件。Beancount.io 的自定义源码确实包含一个 fava.plugins.forecast 实现;但那是不同的运行时,且源码的可用性并不能确定部署到你的账户的版本。以下可移植的工作流程无需任何扩展。

第 1 步:启用预测插件

本工作流程跳过插件激活。 在测试的标准安装中添加 plugin "fava.plugins.forecast" 会导致导入错误。有关常规插件设置,请参阅插件指南;模块必须先实际安装,账簿才能加载它。

先决条件:本地 Python 环境已安装 beancount==3.2.3beanquery==0.2.0fava==1.30.16。按照固定的 Fava 设置创建该环境。将以下三个文件保存在同一目录中,并在该目录中运行命令。

创建 books.beancount,包含这个完整的示例快照。其截止日期为 2023 年 12 月 31 日,在期初交易之后。支票账户持有 10,000.00 美元,未偿还的车贷本金为 14,400.00 美元。权益平衡了这个简化的期初快照。

; books.beancount — realized balances as of 2023-12-31
option "operating_currency" "USD"
2023-12-31 open Assets:Checking USD
2023-12-31 open Liabilities:Auto-Loan USD
2023-12-31 open Equity:Opening-Balances USD
2023-12-31 open Income:Salary USD
2023-12-31 open Expenses:Housing:Rent USD
2023-12-31 open Expenses:Food:Groceries USD
2023-12-31 open Expenses:Health:Gym USD
2023-12-31 open Expenses:Insurance:Auto USD
2023-12-31 open Expenses:Transportation:Interest USD
 
2023-12-31 * "Opening snapshot"
  Assets:Checking                  10000.00 USD
  Liabilities:Auto-Loan            -14400.00 USD
  Equity:Opening-Balances           4400.00 USD

创建 scenario.beancount 作为规划的入口点。它的两个 include 加载你接下来要编写的实际快照和假设。Beancount 相对于此文件读取 include 路径。

; scenario.beancount — planning entry point
option "title" "January 2024 planning scenario"
option "operating_currency" "USD"
include "books.beancount"
include "scenario-2024-01.beancount"

切勿在 books.beancount 中 include scenario.beancountscenario-2024-01.beancount。实际入口点不得加载计划交易,即使它们的日期已过。

第 2 步:创建预测交易

创建 scenario-2024-01.beancount,包含以下第一个条目。将后面的四个场景块各一次追加到该文件。这些是上下文相关的交易块:它们的账户声明来自 books.beancount,并通过 scenario.beancount 进行验证。

2024-01-01 ! "Scenario: January rent" #forecast
  Expenses:Housing:Rent              2500.00 USD
  Assets:Checking                  -2500.00 USD

! 标志标记待审查的交易;#forecast 是一个普通的交易标签。两者都不会创建重复事件或将交易排除在报告之外。单独的入口点控制包含关系。仅在计划条目上使用此标签,以便你在审查时识别它们。

理解预测语法

每个带日期的条目代表一次发生。诸如 [MONTHLY] 的叙述文本在标准 Beancount 中没有重复效果。较旧的 UNTILREPEATSKIP 指令属于自定义插件约定,而非核心语言。本工作流程明确表达了它们预期的日期。

该场景涵盖2024 年 1 月 1 日至 31 日(含)。所有计划日期都在固定的截止日期之后、2 月 1 日之前。这些历史日期使示例可重现;不依赖今天的日期。在调整时,请选择新的截止日期和有限的时间范围,然后再添加条目。

频率

为规划期内每个到期日编写一笔交易。完整的 1 月示例使用以下规则:

项目安排2024 年 1 月包含的日期
租金每月 1 日1 月 1 日
杂货每 7 天一次,从 1 月 1 日开始1 月 1 日、8 日、15 日、22 日、29 日
工资每 14 天一次,从 1 月 5 日开始1 月 5 日、19 日
健身房每月 15 日1 月 15 日
贷款还款每月 25 日1 月 25 日
汽车保险每 3 个日历月一次,从 1 月 15 日开始1 月 15 日;下一次支付在 4 月 15 日,超出此范围

对于其他每日或每年的计划,以相同方式枚举实际到期日。在扩展日程之前,为 31 日或 2 月 29 日等日期设定政策。不要静默移动它们或假设每个月都有相同的天数。

条件(可选)

1. 明确设置结束日期

假设健身房会员资格于 2024 年 12 月 31 日结束。其 1 月的发生如下。1 月场景止于 1 月 31 日,因此不包含 2 月至 12 月的条目。如果你扩展时间范围,请编写到 12 月 15 日的每次后续支付,并在那里停止。

2024-01-15 ! "Scenario: gym membership" #forecast
  Expenses:Health:Gym                  80.00 USD
  Assets:Checking                    -80.00 USD

2. 限制发生次数并将贷款本金与利息分开

假设车贷还有 36 次还款。在此 1 月时间范围内仅包含第一笔还款。对于此假设的分期付款,假设其 450.00 美元现金支付由 400.00 美元本金50.00 美元利息组成。这些是场景假设;不会生成后续分期付款。

2024-01-25 ! "Scenario: car loan payment 1 of 36" #forecast
  Liabilities:Auto-Loan               400.00 USD
  Expenses:Transportation:Interest     50.00 USD
  Assets:Checking                   -450.00 USD

正数负债过账将债务余额从 −14,400.00 美元减少到 −14,000.00 美元。现金减少 450.00 美元,只有 50.00 美元是支出。过账平衡,因为 400.00 + 50.00 - 450.00 = 0。负数负债过账会增加债务。

在没有支持日程的情况下,不要对全部 36 次还款重复相同的本金/利息拆分。未来的利息和最终还款可能不同。扩展此示例时,请使用贷方的还款日程;有关费用确认与债务偿还之间的区别,请参阅摊销

3. 将不规则间隔写为实际日期

对于从 1 月 5 日开始的双周工资,1 月的日期是 1 月 5 日和 1 月 19 日。下一次发生是 2 月 2 日,在此场景之外。双周意味着每 14 天一次,而非每个日历月两次。

2024-01-05 ! "Scenario: salary" #forecast
  Assets:Checking                   3000.00 USD
  Income:Salary                    -3000.00 USD
 
2024-01-19 ! "Scenario: salary" #forecast
  Assets:Checking                   3000.00 USD
  Income:Salary                    -3000.00 USD

实际示例:月度预算

通过将下面的杂货和汽车保险条目追加到 scenario-2024-01.beancount,完成你的月度预算。连同上面的租金、健身房、贷款还款和两笔工资条目,这产生了 11 笔计划交易

2024-01-01 ! "Scenario: groceries" #forecast
  Expenses:Food:Groceries             150.00 USD
  Assets:Checking                   -150.00 USD
 
2024-01-08 ! "Scenario: groceries" #forecast
  Expenses:Food:Groceries             150.00 USD
  Assets:Checking                   -150.00 USD
 
2024-01-15 ! "Scenario: groceries" #forecast
  Expenses:Food:Groceries             150.00 USD
  Assets:Checking                   -150.00 USD
 
2024-01-22 ! "Scenario: groceries" #forecast
  Expenses:Food:Groceries             150.00 USD
  Assets:Checking                   -150.00 USD
 
2024-01-29 ! "Scenario: groceries" #forecast
  Expenses:Food:Groceries             150.00 USD
  Assets:Checking                   -150.00 USD
 
2024-01-15 ! "Scenario: quarterly car insurance" #forecast
  Expenses:Insurance:Auto             450.00 USD
  Assets:Checking                   -450.00 USD

验证两个入口点,然后查询它们的期末余额。date < 2024-02-01 包含所有 1 月的过账。账簿查询使用固定的截止边界 date < 2024-01-01

bea --file books.beancount check
bea --file scenario.beancount check
bea --file books.beancount query "SELECT account, sum(position) WHERE date < 2024-01-01 GROUP BY account ORDER BY account"
bea --file scenario.beancount query "SELECT account, sum(position) WHERE date < 2024-02-01 GROUP BY account ORDER BY account"

两个 bea check 命令都应成功退出。将查询结果与这些独立的计算核对:

结果实际账簿,12 月 31 日1 月场景,1 月 31 日
支票账户10,000.00 美元10,000 + 6,000 − 2,500 − 750 − 80 − 450 − 450 = 11,770.00 美元
贷款余额−14,400.00 美元−14,400 + 400 = −14,000.00 美元
工资收入过账0.00 美元−6,000.00 美元
总支出过账0.00 美元2,500 + 750 + 80 + 450 + 50 = 3,830.00 美元

1 月的预计利润为 2,170.00 美元:6,000 收入减去 3,830 支出。支票账户增加 1,770.00 美元,因为额外的 400 本金还款减少了债务而非利润。

在标准 Fava 中打开场景:

fava scenario.beancount

将 Fava 的时间过滤器设置为 2024-01。其时间过滤会将期初资产和负债余额带入该期间,并移除后续条目。检查资产负债表中的 11,770.00 美元现金和 14,000.00 美元未偿债务。损益表应显示 2,170.00 美元的预计利润。打开 books.beancount 则显示实际快照。

故障排除与最佳实践

  • 旧插件导入错误: 使用此可移植工作流程时,移除激活行。标准 Fava 安装不提供 Beancount.io 的自定义模块。
  • 未知账户或缺少 include 文件: 将三个文件保存在同一目录中,复制 opens,并验证 scenario.beancount 而非单独的场景片段。
  • Fava 中缺少预测: 加载 scenario.beancount 并将时间过滤器设置为 2024-01。标签或叙述不会生成条目。
  • 意外余额: 将 11 个计划日期和金额与表格进行比较。即使每笔交易都平衡,加载两次发生会将财务影响加倍。
  • 保持预测独立: 普通的标志、标签和未来日期不会阻止条目影响未过滤的报告。使用 books.beancount 记录实际结果。当一笔支付发生时,在那里记录其实际金额,并从下一个场景中移除相应的假设,以避免重复计算。
  • 审查时间范围: 保存场景时,保留带日期的快照。延长其结束日期意味着添加具体发生,并再次检查贷款拆分、取消日期和舍入。

来源:https://beancount.io/zh/docs/Tips/forecast-plugin