将未来日期的交易放在一个独立的场景账簿中,以便在你的财务报告中预测现金、支出和债务。本教程使用普通的 Beancount 条目和固定的规划周期。你的实际账簿与你的假设保持分离。
兼容性检查(2026 年 9 月 7 日): 这些示例已在标准 Beancount 3.2.3、beanquery 0.2.0 和 Fava 1.30.16 上测试通过。该 Fava 版本未附带预测插件。Beancount.io 的自定义源码确实包含一个 fava.plugins.forecast 实现;但那是不同的运行时,且源码的可用性并不能确定部署到你的账户的版本。以下可移植的工作流程无需任何扩展。
第 1 步:启用预测插件
本工作流程跳过插件激活。 在测试的标准安装中添加 plugin "fava.plugins.forecast" 会导致导入错误。有关常规插件设置,请参阅插件指南;模块必须先实际安装,账簿才能加载它。
先决条件:本地 Python 环境已安装 beancount==3.2.3、beanquery==0.2.0 和 fava==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.beancount 或 scenario-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 中没有重复效果。较旧的 UNTIL、REPEAT 和 SKIP 指令属于自定义插件约定,而非核心语言。本工作流程明确表达了它们预期的日期。
该场景涵盖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 USD2. 限制发生次数并将贷款本金与利息分开
假设车贷还有 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记录实际结果。当一笔支付发生时,在那里记录其实际金额,并从下一个场景中移除相应的假设,以避免重复计算。 - 审查时间范围: 保存场景时,保留带日期的快照。延长其结束日期意味着添加具体发生,并再次检查贷款拆分、取消日期和舍入。