上下文中的命令行记账

Martin Blais,2014 年 7 月

http://furius.ca/beancount/doc/motivation

本文提供了使用复式记账命令行系统管理个人财务的背景与动机。

动机

什么是“记账”?

它能为我带来什么?

记账

生成报表

自定义脚本

归档文档

各部分如何协同工作

为什么不用电子表格?

为什么不用商业软件?

那 Mint.com 呢?

那 Quicken 呢?

那 QuickBooks 呢?

那 GnuCash 呢?

为什么要构建一门计算机语言?

命令行记账的优势

为什么不用 SQL 数据库?

但我只想做 X 怎么办?

我为什么如此兴奋?

动机

当我向人们谈起我的命令行记账开发活动时,会得到各种各样的反应。

有时我会听到他们对自己财务状况的绝望:许多人希望更好地掌控和理解自己的财务状况,他们叹息着希望自己能更有条理。另一些时候,在我描述了我的流程后,他们会露出难以置信的表情:"你为什么还要费这个劲?" 这些人往往觉得自己的财务生活如此简单,五分钟就能说清楚。但他们通常完全不清楚自己到底有多少个账户,对自身财务状况也只有模糊的认识。他们至少拥有 20 个账户;只有当我们逐项梳理时,他们才意识到自己的财务生态比想象中复杂得多。最后,还有一些人对使用强大记账系统的想法感到非常兴奋,但他们并不真正理解我所说的是什么。他们可能以为这是一种支持投资组合的系统,或者是我用来像苛刻的管家一样制定预算的工具。通常他们最终会觉得这太复杂了,根本无从下手。

本文试图用具体的方式解释命令行记账究竟是什么,你能从中获得什么,各种软件组件如何协同工作,以及你能期待什么样的成果。事实上,复式记账是一种每个人都应在高中时学习的基本技术。而将它应用于自身,是一种简单而强大的方法,足以驱动你的整个财务生活。

什么是“记账”?

当人们谈论“记账”时,通常隐含地指代以下几种不同的财务流程之一或多个:

  • 记账。 将过去的交易记录在单一位置——即“账簿”,也称为“账本”,如“这家公司的账本”。本质上,这意味着将外部账户对账单中的金额和类别复制到一个统一的系统中,该系统包含与某个实体相关的所有“账户”并将其相互关联。这通常被称为“记账”或“记账活动”。

  • 发票。 准备发票并跟踪付款。承包商经常提及这一点,因为这是他们活动中的主要关切:向客户发出服务报酬的付款请求,并检查相应的付款是否已实际到账(如未到账,则采取催收措施)。如果你在管理公司的财务,处理工资单是另一项繁重的记账工作。

  • 税务。 确定或计算应税收入,填写并向相关政府机构提交税务申报表。这一过程可能非常繁琐,尤其对于那些个人资产复杂性开始增加的人(如拥有多种类型的账户、新的报告要求),可能会带来相当大的压力。这往往是他们开始思考如何系统化管理财务的时刻。

  • 支出。 分析支出,本质上回答一个问题:“我的钱花到哪里去了?”收入较低但持有多个信用卡的人,可能希望精确追踪和计算每月的开支。这有助于提升财务意识。即使在资源充裕的情况下,审视日常支出的去向以及主要收入的流向,也常常会带来意想不到的发现。

  • 预算。 预测未来支出,为不同类别分配有限的资金,并跟踪实际支出与预算的接近程度。对个人而言,这通常是为了还清债务或寻找更多储蓄方式。对公司而言,这发生在规划各类项目时。

  • 投资。 汇总并计算投资回报和资本收益。如今,许多人通过折扣券商自行管理储蓄,投资于 ETF 和精选的共同基金。能够查看资产分布和风险敞口,并计算资本收益,是非常有用的。

  • 报告。 上市公司有监管要求,需向投资者提供透明度。因此,它们通常会发布年度损益表以及期初和期末的资产负债表。对个人而言,这些报表在向银行申请个人贷款或抵押贷款时同样有用,因为它们能反映一个人的财务健康状况。

在本文档中,我将介绍命令行会计如何为这些活动提供帮助和支持。

它能为我做什么?

你可能会合理地问:当然,但为什么要费这个劲?我们可以从会计能为你解答的问题角度来理解其用途:

  • 我的钱去哪儿了,勒布 owski? 如果你不记录收支、大量使用现金、持有过多信用卡,或者你只是一个头脑飘在云端、不拘小节却才华横溢的艺术家,你可能会疑惑:为什么月底剩下的钱总不如预期那么多。损益表将回答这个问题。

  • 我想成为沃伦·巴菲特。我每个月需要存多少钱? 我个人不做预算,但我知道很多人会做。如果你为某个项目或未来的储蓄设定了明确的财务目标,首先需要做的是制定预算并限制支出。追踪资金流向是实现这一目标的第一步。你甚至可以以一种可与市场比较的方式计算你的回报率。

  • 我有一些现金可以投资。根据我的投资组合,我该把钱投到哪里? 通过全面报告你的所有资产,你可以清楚了解自己的资产类别和货币敞口,从而帮助你决定如何配置新资金,以匹配目标投资组合的配置比例。

  • 我净资产有多少? 你拥有 401(k)、IRA 和应税账户,可能还有一笔未还清的学生贷款,或者名下有房产并背负两笔抵押贷款。不管怎样,你的总资产是多少?能获得一个明确的数字,告诉你距离退休目标还有多远,这非常有用。Beancount 可以轻松计算出你的净资产(精确到分)。

  • 2008 年的创伤仍令我心有余悸。我的投资安全吗? 例如,我用自己的资金通过多家折扣券商进行管理,很多人也是如此。我实际上是在用 ETF 运作一个微型对冲基金,目标是尽可能在资产类别、行业敞口、货币敞口等方面实现多元化。此外,由于存在税收递延账户,我无法在一个地方完成全部操作。使用 Beancount,你可以生成持仓清单,并按类别进行汇总。

  • 缴税真让人头疼。 说多了都是泪。为什么这么烦?主要是因为不确定性和疑虑。不知道自己该交多少税,实在让人焦虑。如果你能随时掌握所有数据,情况就不会这么糟了。你需要申报哪些内容?对一些人来说,只有一项收入来源,但对很多人来说,情况会变得复杂(你可能正处在这种状况中却浑然不觉):合格股息与普通股息、长期与短期资本利得、其他收入来源、洗售交易等等。每到报税季,我会调出当年的损益表,就能清晰列出所有需要申报的项目和可抵扣的费用。

  • 我想买房。我能攒下多少首付款? 如果突然需要一大笔现金,你能拿出多少?如果你能列出自己的全部资产,就可以按“流动性”进行汇总,从而了解在紧急情况下可用的现金总额。

  • 银行先生,请借我一些钱。 让银行职员眼前一亮:直接拿出你的资产负债表即可,最好是当天早上刚生成的最新版本。你应该随时都能拥有完整的资产负债表。

  • 为你的身后事做准备。 立遗嘱需要列出你的全部资产。通过提供一份完整的资产清单,包括所有待继承或待收取的“账目”,能大大减轻子女的负担。金额只是故事的一部分:能列出所有账户和机构,才能让他人更轻松地清理你的资产。

  • 我记不清他们有没有付钱了。 如果你发出过发票并有应收账款,能追踪谁已付款、谁只是口头承诺付款,会非常方便。

我相信你还能想到更多用途。欢迎告诉我。

记账

好吧,现在我来分享这种方法的核心洞见。支撑所有其他功能的最核心、最基本的操作是记账。一个至关重要的基本认识是:将所有财务交易统一记录到一个整合系统中的这一简单行为,足以让你生成解决上述所有问题的报表。你正在构建一个数据集合——一份按日期排列的交易对象列表,每笔交易都代表你名下账户之间的资金流动。这套数据完整记录了你的财务活动时间线。

你所需要做的就是输入每一笔交易,同时遵守一个简单的约束,即复式记账法,其规则如下:

Each time an amount is posted to an account, it must have a corresponding inverse amount posted to some other account(s), and the sum of these amounts must be zero.

就是这样。这就是该方法的核心,符合这一约束的一系列交易会具备一些优良特性,这些特性在我的其他文档中有详细讨论。为了生成合理的报表,所有账户还会进一步标记为以下四类之一:资产负债收入支出。第五类权益仅用于汇总所有以往收入和支出交易的历史记录。

命令行记账系统只是用于便捷地输入、读取和处理此类交易数据的简单计算机语言,它们确保复式记账法的约束得到遵守。这些系统本质上是计数器,可以在专用的“账户”中对任何类型的“项目”进行加总。它们基本上是带有多个储物箱的计算器。BeancountLedger 在语法和部分语义上可能略有不同,但总体原理相同,简化假设也非常相似。

下面是一个具体的交易示例,以便你对此有所感受。在文本文件中——这是命令行记账系统的输入——会写入类似以下内容来表示一笔信用卡交易:

2014-05-23 * "CAFE MOGADOR  NEW YO" "Dinner with Caroline"
  Liabilities:US:BofA:CreditCard    -98.32 USD
  Expenses:Restaurant

这是一个包含两个“分录”或“条目”的交易示例。“Expenses:Restaurant”是一条账户,而非类别,尽管账户通常表现得像类别(这两者之间没有区别)。支出条目的金额未明确指定,这是输入语言允许的一种便利。软件会自动根据余额的剩余部分计算出该金额,在本例中为 98.32 美元,因此 -98.32 美元 + 98.32 美元 = 0(请记住,所有分录的总和必须为零——这一点由语言强制保证)。

大多数金融机构都提供某种方式,让你以某种格式下载账户活动摘要。通过你编写的自定义脚本,可以从此类下载文件中自动提取交易的大部分细节,并将其转换为上述语法:

  • 可下载文件中始终包含交易日期。

  • CAFE MOGADOR NEW YO”这部分是“备注”,同样由下载文件提供,这些名称通常足以让你判断消费的商家是谁。这些备注正是你在信用卡对账单上看到的那些难看的名称,并作为交易的“收款方”属性附加在交易上。

  • 我手动添加了“Dinner with Caroline”作为注释。我并非必须这么做(这是可选的),但我在对账新交易时喜欢这样做,只需一分钟,就能帮助我在日后查找时回忆起过去的事件。

  • 导入器自动带入了Liabilities:US:BofA:CreditCard分录及其金额,但我必须手动插入Expenses:Restaurant账户:我亲自输入了它。我的文本编辑器中设置了快捷方式,可通过账户名称自动补全快速完成,只需一秒钟,极其简单。此外,也可以通过在同一个输入文件的先前历史记录上运行一个简单的学习算法,自动预选该账户(我们通常总是去相同的地方)。

语法会变得稍微复杂一些,例如它允许你记录股票的买卖、追踪资产的成本基础,还有许多其他便利功能,比如能够定义和统计账户中的任何类型“项目”(例如“累积的年假时数”)。但这个例子捕捉了我所做工作的精髓。我基本上以这种方式自动化地复制我所有账户的全部交易记录。我每几周花费大约一到两个小时来更新这个输入文件,主要针对使用最频繁的账户(信用卡和支票账户)。其他账户我则每隔几个月更新一次,或在需要生成报告时才更新。由于我对自己的财务状况有清晰的了解,这已不再是一种负担……反而变得有趣了。

你最终获得的是一个完整的记录,一个涵盖所有账户、跨越时间的完整财务交易时间线,这些记录常常相互关联,构成了你的整个财务生活,全部保存在一个文本文件中

生成报告

那么,精心维护这个文件的意义何在?我编写了代码来读取并解析它,可以在本地运行的网页服务器上提供多种视图和聚合分析,或从这一系列数据中生成自定义报告。最有用的视图无疑是资产负债表利润表,但还有其他类型:

  • 资产负债表。资产负债表将你所有资产和负债账户的最终余额汇总在一页纸上。这是你在某一特定时间点上所有账户的快照,是对财务状况的清晰概览。它能精确显示你的净资产(如果你更新了所有账户,结果会非常准确),也是你在申请贷款时银行家所关心的内容。Beancount 可以在任意时间点生成我的资产负债表,但我最常关注的是“当前”或“最新”的资产负债表。

  • 利润表。利润表是对两个时间点之间所有收入和支出的汇总。它以任何会计师都熟悉的格式呈现这些账户的最终余额:收入账户在左侧,支出账户在右侧。这能揭示某一时间段内发生的变化,即变化的差值。它详细告诉你赚了多少钱、钱花在了哪里。两者之间的差额就是你的储蓄额。Beancount 可以为任意时间段生成此类报表,例如今年,或逐月呈现。

  • 日记账。对于每个账户(或者如果你愿意,也可以视为每个类别),我可以生成所有影响该账户的交易列表。我称之为日记账(Ledger 称之为“register”)。例如,如果你查看信用卡账户的日记账,它应该与银行对账单完全一致。另一方面,如果你查看“餐饮支出”账户,它应显示你所有餐饮消费记录,无论使用何种支付方式(包括现金,如果你选择录入的话)。你可以轻松查询财务历史中的任何细节,比如:“三年前三月我和亚瑟吃饭的那家店是哪家?”或“我想卖掉那张沙发……我当初买它花了多少钱?”

  • 应付与应收款项。如果你有已知将收到的款项,例如你已报税或已开具发票、正等待付款,或已寄出支票、期待其在未来兑现,你可以使用专门的账户来追踪这些事项。交易语法允许你将多个交易相互关联,从而判断哪些款项已支付或已收到。

  • 计算税费。 如果您输入工资入账时附上工资单的详细信息,就可以精确计算出您已缴纳的税款金额,这些金额应与雇主提供的年度收入申报表(例如美国的 W2 表、加拿大的 T4 表、英国的 P60 表,或其他国家的相应表格)所报告的金额完全一致。这一点在您需要分期缴纳税款时尤其方便。如果您是自由职业者,则需要跟踪许多此类事项,包括公司可报销的开支。此外,统计您需要申报为应税收入的股息也很有用。

  • 投资。 我不算特别富有,但我使用折扣券商和主要通过 ETF 来管理自己的资产。此外,我还利用各种免税账户,尽管这些账户的资产选择有限。如今这已相当普遍。您甚至可以说我管理着一个微型对冲基金,这种说法并不夸张。借助 Beancount,我可以生成所有持仓的详细清单,并提供每日市值变动、资本利得、股息、资产类别分布(如股票与固定收益)、货币敞口等报告,还能准确计算出我的资产中有多少是流动资产——例如,我可用于购房首付的资金有多少。无论何时,都能精确掌握。这非常棒。我还能按账户、工具类型或货币对持仓进行各种汇总统计。

  • 预测。 我所在的公司有员工股票计划,并设有归属时间表。在合理假设的前提下,我可以预测自己预期的总收入,包括归属的股票部分。我可以回答这样的问题:“以目前的速度,我将在哪一天达到 X 的净资产?”比如,X 是您退休所需的资金数额。

  • 分摊开支。 如果您与他人共同承担开支,例如与朋友旅行或合租室友,复式记账法能自然且简便地解决费用对账问题。您还可以生成各类支出的报告以便清晰了解。毫无歧义。

  • 预算规划。 我的收入足够高,因此我自己并不设定具体的预算目标,但我计划支持相关功能来实现这一点。

您最终会像管理一家公司那样管理个人财务……但这个过程非常简单,因为您使用了一种简洁而巧妙设计的计算机语言,它做了大量简化(例如摒弃了“借方和贷方”的概念),将整个流程简化为最核心的最小单元。

自定义脚本

应用场景无穷无尽。我对为自定义项目生成报告有着各种天马行空的想法。这些既是实用的,也是有趣的实验,我称之为“挑战”。一些例子:

  • 我曾拥有一套公寓,在持有期间直至出售,我一直使用复式记账法记录所有相关账目。所有相关账户名称中都包含Loft4530。这意味着我可以精确计算与该房产相关的所有现金流的内部收益率,甚至包括更换灯泡这类琐碎开销。纯粹为了乐趣,将其视为一项纯粹投资。

  • 我可以生成我年度支出和资产的树状图。这是一种很好的可视化方式,能清晰呈现各类别的相对重要性。

  • 我可以考虑货币时间价值后计算平均支出。这会很有趣,能告诉我我的生活成本随时间发生了怎样的变化。

它的美妙之处在于,一旦你拥有了数据语料库——如果你能逐步维护它,创建起来相对容易——你就可以通过编写少量 Python 代码实现各种有趣的功能。我开发 Beancount 的目的就是为了以两种方式实现这一点:

  1. 通过提供一个“插件”系统,让你能够筛选已解析的交易列表。这使你能够自定义 Beancount 的语法,并快速原型化新的数据录入便利功能。默认提供的插件仅通过过滤和转换已解析的交易列表,即可提供扩展功能。实现起来非常简单:你只需实现一个具有特定签名的回调函数,并在输入文件中添加一行代码即可。

  2. 通过编写脚本。 你只需极少的代码即可解析并获取账本内容。在 Python 中,这看起来不过如此:

    import beancount.loader

    entries, errors, options = beancount.loader.load_file('myfile.ledger')

  for entry in entries:
    …

搞定。你现在就可以开始生成你想要的任何输出了。你可以使用 Python 世界中的所有库,而我的代码主要采用函数式风格,文档详尽,并经过全面的单元测试,你应该能轻松上手。此外,如果你对使用这套系统尚有疑虑,也可以先用它来开始录入数据,之后再编写脚本将其转换为其他格式。

归档文档

如果你为每个现实中的账户都定义了对应的账户,那么你也就自然地建立了一种组织对账单和其他纸质文件的方法。随着我们与会计师和机构越来越多地通过电子邮件沟通,将信件扫描为 PDF 并保存为计算机文件正变得越来越普遍。如今所有银行都已无纸化,只要你愿意,就可以下载这些对账单(我通常在年底做一次,用于存档,以防万一)。能够整齐地组织这些文件并轻松检索,非常方便。

我的做法是维护一个与我定义的账户名称相对应的目录层级,结构如下:

.../documents/
              Assets/
                     US/
                        TDBank/
                               Checking/
                                        2014-04-08.statement.march.pdf
                                        2014-05-07.statement.april.pdf
                                        … 
              Liabilities/
                          US/
                             Amex/
                                  Platinum/
                                           2014-04-17.March.pdf
                                           2014-04-19.download.ofx
                                           …
              Expenses/
                       Health/
                              Medical/
                                      2014-04-02.anthem.eob-physiotherapy.pdf
                                      …

这些示例文件分别对应账户名 Assets:US:TDBank:CheckingLiabilities:US:Amex:PlatinumExpenses:Health:Medical。我将这个目录纳入版本控制。只要文件名以日期开头(例如 “2014-04-02”),Beancount 就能自动找到这些文件,并在网页界面中将其作为账户日记的一部分插入,点击即可查看文档本身。这让我能将所有对账单集中存放,若需要查找某份文件,我也知道它有明确的存放位置。

此外,我编写的导入工具能够识别已下载的文件,并自动将它们移动到相应账户的目录下。

各组件如何协同工作

我已经介绍了我是如何组织财务的。接下来,我将说明所用的各种软件组件及其协作方式:

  • Beancount 是系统的核心。它读取我更新的文本文件,解析我定义的计算机语言,并从生成的数据结构中生成报表。该软件读取输入文件,刻意不与任何其他程序通信。它独立运行。

  • Beancount 的 ingest 包和工具通过从银行和其他机构的文件下载中提取交易记录,帮助自动化账户数据的更新。这些工具协调运行您自行实现的导入器(所有繁琐的导入代码都集中在这里,即您需要编写的代码,以便更轻松地保持文本文件的更新,例如解析 OFX 和 CSV 文件)。请参阅 bean-extract 和 bean-identify 工具。

  • ingest 包还帮助管理文档(参见 bean-file 工具)。由于它能够识别每个文档属于哪个账户,因此可以自动将下载的文件移动到我的文档归档中。这为我节省了大量时间。

  • 最后,为了提供市场价值,Beancount 输入文件应包含适当的价格指令。Beancount 还包含用于获取账本文件中各种商品最新或历史价格的代码(参见 bean-price 工具)。与从 OFX 下载中提取交易类似,它也会输出用于定义价格的 Beancount 输入语法。

请参见下图,该图生动地展示了这些工具如何协同工作。

为什么不用电子表格呢?

这确实是个好问题,电子表格无疑非常有用。如果我能用电子表格追踪我的财务状况,我肯定不会自己开发软件。

问题是,复式记账交易数据的内在结构并不适合表格化表示。每笔交易具有多个属性(日期、说明、标签)和两个或更多分录,每个分录都关联一个金额,可能还有一个成本。如果您将日期放在一个轴上、账户放在另一个轴上,最终会得到一个非常稀疏且庞大的表格;这不仅没什么用,而且极难编辑。反之,如果您为每一行都设置一列专门用于账户名称,那么所有的计算都必须将账户单元纳入计算逻辑中,这将变得极其难以处理,甚至不可能实现。所有数据聚合操作都是相对于账户名称进行的。

此外,处理带有成本基础的单位累积需要复杂的操作,我甚至不知道如何在电子表格中实现这一点。命令行记账系统的核心部分是库存逻辑,它允许您跟踪每个账户中持有的每单位的成本基础,并仅针对现有批次进行仓位减少记账。这使系统能够自动计算资本收益。这也与强制要求每笔交易的分录总和为零的代码相关。

我相信,"交易 <-> 分录"的数据表示方式,结合合理的库存更新方法,正是本系统的核心。正是这种需求,才促使我们创建一种专门的计算机语言来构建此类数据。此外,拥有我们自己的语法,还能提供其他有用的指令,例如余额验证、账户开立/关闭日期,以及对交易子集的高级过滤。这些功能在电子表格中是完全无法实现的。

为什么不用商业软件呢?

那 Mint.com 呢?

人们经常告诉我,他们使用Mint.com来追踪财务状况,通常紧接着会有一大堆具体的抱怨。像 Mint 这样的在线服务提供了复式记账功能的一部分。这些服务的主要焦点是按类别报告支出和维护预算。因此,它们在自动下载你的信用卡和银行交易记录方面表现得非常出色。我认为,如果你希望找到一种低维护成本的财务管理方式,并且不介意明显的隐私风险,那么这是一个绝佳的选择:它提供网页界面、移动应用,更新账户可能只需要点击几个按钮、输入一些密码,每几周进行少量手动修正即可。

然而,我自己使用它时仍有一些顾虑:

  • 密码问题。 我完全无法放心将我所有银行、信用卡和投资账户的密码交给任何一家商业公司。这在我看来简直是疯狂的、令人恐惧的,我绝不愿意把如此多的信任寄托在任何一家公司的手上。我不在乎他们怎么说:我曾在多家软件公司工作过,深知销售人员的承诺、网站宣传与工程现实之间的巨大鸿沟。我也深知坚定的黑客所具有的强大破坏力。

  • 报告功能不足。 报告界面可能美观且色彩丰富——网站上看起来确实漂亮——但绝对无法满足我对自己数据的所有报告需求。我常听到人们抱怨这些系统无法实现他们想要的报告功能。而使用我的系统,我随时可以编写脚本,生成未来可能需要的任何类型的报告。例如,我可以输出一张我支出的树状图,而不是毫无用处的饼图。我可以以各种独特的方式切分和分析我的交易记录。我可以为项目或旅行标记特定交易并单独报告。它的功能远超通用报告系统。

  • 持久性问题。 如果五年后这家公司不复存在,我的数据会去哪里?如果我花时间精心整理我的财务数据,我希望确保它能永远以开放格式供我访问。虽然这些网站中有些可能提供下载功能,但谁会用它?它真的好用吗?是否能包含所有下载的交易记录?我不知道。

  • 不支持国际使用。 它很可能无法很好地处理跨国、多币种的情况。这些服务主要面向大多数用户,而这些用户通常所有财务事务都集中在一个国家。我居住在美国,过去曾在加拿大生活,那里仍有免税投资账户;偶尔前往加拿大时的开销也让我有必要保留一张当地的信用卡;未来我可能还会在其他国家(如香港或澳大利亚)生活数年。Mint 能支持这种情况吗?可能不行。即使它支持加拿大,它能否同时管理两地的账户?如果我未来搬到其他国家呢?我需要一个能永久整合所有国家、所有货币账户的单一视图,别无他求。我的系统能很好地支持这一点。(我尚未发现任何其他复式记账系统能像 Beancount 那样以货币无关的方式妥善处理国际问题。)

  • 无法处理特定情况。 如果我拥有房地产,我能否合理评估我的房屋价值,从而生成准确的资产负债表?通过热心的房地产经纪人定期获取我房产的“可比交易数据”,远比使用Zillow这类服务更能精确地告诉我房屋的实际价值。我需要能够将这些数据输入我的资产负债表。那么,我以前工作的那家澳大利亚私营公司的股票期权又该如何定价?其他无形资产呢,比如我借给朋友的个人贷款应收款项?我怀疑在线服务根本无法让你输入这些项目。如果你希望全面、精确地掌握财务状况,就必须能够进行这些调整。

  • 自定义追踪。 通过使用“虚拟货币”,我可以追踪货币和股票之外的各类项目。例如,在 Beancount 中,我使用“IRAUSD”这一商品来追踪一年中任何时间点我已缴纳的 401k 金额。我也可以类似地计算传统 IRA 账户的税后基础金额。我甚至可以用一种虚拟的“VACHR”货币来追踪我的休假时数,并与工资单进行核对。

  • 资本利得报告。 我自己尚未尝试过,但听其他人抱怨过 Mint 在资本利得报告方面的功能有限。它会保留交易批次吗?能处理平均成本法记账吗?外汇收益的损益又如何?我通过 PayPal 销售书籍所获得的收入呢?我希望我的会计系统能直接作为报税的输入数据。

  • 现金交易。 输入现金交易有多困难?我是否必须登录,或启动一个缓慢而沉重、仅能在 Windows 上运行的程序?使用 Beancount,我只需在文本编辑器中打开一个文件,瞬间即可完成,简单便捷。在线服务甚至允许输入自定义现金交易吗?

换句话说,我是一个非常复杂的用户,没错,还有一点儿控制狂。我并不否认这一点。我对使用商业服务并无意识形态上的抵触,只是它不适合我。如果它适合你,那当然没问题。尽管这些服务的网站看起来精美诱人,但我从未听说有人对它们完全满意。我听到的大多是抱怨,偶尔有些轻微的满意,却从未遇到过有人对此狂热推崇。

那 Quicken 呢?

Quicken 是单式记账系统,即它在本地复制远程账户的交易,并允许你为每笔交易添加标签以归类。我认为它也支持投资账户的同步。但这对我来说还不够,我想追踪各种项目,并希望使用复式记账法,因为它能内在地验证我输入的数据是否正确。一旦你理解了复式记账法,单式记账就完全不够用了。

那 QuickBooks 呢?

那么,我们来谈谈那些足够胜任企业需求的高级软件。为什么我不直接用它们呢?既然它们对小企业来说已经足够好,那对我也应该足够好,对吧?有 QuickBooks 和其他类似软件。我为什么不使用它们:

  • 需要付费。 商业软件是有价格的。好吧,我或许能负担得起每年几百美元(QuickBooks 2014 的完整功能版看起来大约是每年 300 美元),但我并不真的想花钱。

  • 平台。 这些软件通常运行在Microsoft Windows上,有时也运行在Mac OS X上。我是一名软件开发者,主要使用Linux,笔记本则用Macbook Air,在上面我只愿意运行tmux和一个网页浏览器,其他任何东西都让我烦躁。我不会为了录入一笔简单的现金交易就重启系统。

  • 启动缓慢。 我无法具体评价 Quickbooks 的实现,但几乎所有我用过的商业级软件套件都有启动画面,并且启动极其缓慢,需要初始化大量插件。它们假设你会花数小时在软件里,这对商业用户来说是合理的,但对我而言,如果只是想快速更新账本,这种体验就太糟糕了。

  • 界面不足。 我没用过它们的界面,但考虑到交易的性质,以及我希望精确输入、快速搜索和组织数据的需求,我希望能直接以文本形式编辑。我想象使用其他界面会很不方便。借助Emacsorg-mode,我可以在打开账本文件后的几秒内,通过i-search快速定位到任何一笔交易。

  • 缺乏灵活性。 我该如何重新组织所有账户名称?我仍在学习复式记账法,过去曾犯过错误,现在希望重新调整账户的层级结构。使用文本文件时,我曾多次安全地批量重命名账户,并逐步完善我的科目表,以反映我对财务追踪系统组织方式的不断深化理解。文本的力量是强大的!

那 GnuCash 呢?

我不喜欢图形界面;它们很不方便。作为程序员,没有什么比编辑文本文件更直接的了。此外,GnuCash 对多币种的支持很差。每次我出于好奇重新试用它时,总能在第一个小时内发现 bug,而这种情况每几年就会发生一次。其他程序,比如 Skrooge,也同样采用笨重的大型图形界面方案。

为什么要构建一种计算机语言?

记账系统为使用一种简单计算机语言提供了多种合理理由。

如果试图全面追踪所有财务活动,单式记账法基本是不够的。现有系统往往仅限于支出分类,检查机制也仅限于“对账”,有时甚至会冻结历史数据。如果你不是为企业做记账,有时直接修改过去、在错误发生处修正,反而更合理。更重要的是,单式记账法缺乏复式记账法中自然的错误检查机制。

使用电子表格也无法优雅地解决这个问题;复式记账法的基础数据结构意味着要么是一个极其稀疏的电子表格——一边是账户,另一边是交易。但在实际使用中,这并不实用。另一种改进方式是插入两列,一列是账户,一列是金额,但可变的列数和查找代码也让这种方式显得笨拙。此外,如何处理大量货币的问题也并不清晰。

提供精美图形或基于网页用户界面的程序不可避免地显得笨拙,这是因为问题的本质:每一笔交易都是通过某个账户的日记账视角来组织的,但其分录中涉及的任何账户都同样有效。理想情况下,你只想直接查看交易本身。为方便输入而组织它们,与它们呈现的顺序几乎没有关系。使用文本具有诸多优势:

  • 你可以轻松使用查找和替换功能或 sed 进行全局修改,例如重命名或重新组织你的账户;

  • 你可以按照最便于数据录入的顺序组织交易;

  • 有许多现成的工具可用于搜索文本;

  • 你可以轻松编写各种小工具来输出数据格式,例如从其他文件类型导入数据,或转换自其他系统。

  • 文本本质上是开放的,即文件格式是你能够读取并存储在任何地方的数据格式,而不是一种当软件公司停止支持时就变得无法使用的不可理解的数据块。

最后,试图自动化从各种来源(例如 mint.com)导入所有数据的系统,存在一个主要缺陷:通常很难甚至不可能为那些未自动化的账户添加信息。根据我的经验,实践中你总会有一些条目和账户无法获得规范的可下载文件格式,或根本没有现实对应的来源。为了完整呈现个人的资产负债表,必须能够在单一系统中录入所有账户。换句话说,自定义账户和手动录入的交易至关重要。

鉴于上述所有原因,我认为用一种计算机语言来表达这种数据结构,比使用带有定制界面的重型软件更为合适。能够轻松打开一个文本文件,快速键入几行文字来添加一笔交易,是非常棒的——它快速而简便。Ledger 文件提供了一种天然开放的方式来表达你的数据,并且可以进行版本控制或在人与人之间共享。多个文件可以合并,也可以通过脚本对源文件进行操作,以重新组织你的数据历史。此外,一个只读的网页界面,能够呈现你期望的各种报表,并允许用户探索数据集的不同视角,已足以满足查看数据的需求。

命令行记账的优势

总之,使用命令行记账系统相比提供用户界面的商业软件具有诸多优势:

  • 快速。 你无需启动一个带有启动画面的缓慢程序,等待其初始化才能添加一笔交易。从你最爱的编辑器(我使用 Emacs)的书签中快速打开一个文本文件,既简单又迅速。如果你像许多程序员一样整天都在使用文本编辑器,你甚至不会多想,文件就已经呈现在眼前了。它快速而简便。

  • 可移植。 它可在所有平台上运行。Beancount 使用 Python 3 编写,并包含一些 C 扩展,因此可在 Mac、Linux 和 Windows 平台上运行。我非常谨慎并致力于将对外部第三方包的依赖降至最低,以避免安装问题。它应易于安装和更新,并在所有平台上保持一致的行为。

  • 开放性。你的数据是开放的,并将永远保持开放。我计划在有生之年一直保留我的数据集。使用开放格式,你永远不会陷入交易数据被存储在未知格式的二进制块中、且软件不再受支持的困境。此外,你的数据可以轻松转换为其他语言。你可以轻松调用我提供的解析器,并编写脚本将其输出为其他程序的输入格式。你可以将其纳入版本控制,甚至可以通过 sed 命令重命名字符串来完全重新组织你的账户结构。文本具有强大的力量。

  • 可定制。你可以生成高度定制的报表,精准解决你所面临的特定问题。我常听人抱怨其他财务软件无法完全满足他们的需求。而使用命令行会计系统,你至少可以自己编写一个小型扩展,直接利用你的数据集来实现所需功能。

为什么不直接使用 SQL 数据库?

我不喜欢重复造轮子。如果这个问题可以通过填充一个 SQL 数据库并对其进行查询来解决,我一定会这么做。创建一门语言需要巨大的开销:它需要持续维护和演进,绝非易事,但事实证明,为解决这个问题,这是必要且合理的。

这个问题源于以下几个原因:

  • 过滤操作基于交易与其子分录的两级数据结构,而将这种数据表示为单一表格以便进行操作非常不便。你不能仅处理分录:为了确保报表平衡,你必须选择完整的交易。当你选择交易时,语义是“选择所有具有属性的分录”。其中一个属性是“所有包含账户X的分录的交易”。这些语义在数据库中实现起来并不直观,数据结构的本质使其难以处理。

  • 各种指令种类繁多,难以设计一个优雅的单一表格来容纳所有数据。理想情况下,我们希望为每种指令定义两个表:一个存储所有通用数据(日期、源文件名和行号、指令类型),另一个存储类型特定的数据。虽然这可行,但它偏离了单一数据表的简洁结构。

  • 对库存(记录账户内容逐步变化的数据结构)的操作需要特殊处理,这在数据库中难以实现。批次减少操作需受限于不断变化的批次库存,每个批次都有特定的成本基础。某些批次减少会触发批次合并(用于平均成本记账)。这需要对这些库存对象执行自定义操作。

  • 聚合(分解)本质上是分层的。账户的树状结构使我们能够对分录的子树执行操作。这一点用表格实现起来同样困难。

最后,输入也会很困难。通过定义一门语言,我们避开了必须构建自定义用户界面以创建数据的难题。

尽管如此,我真的很喜欢使用数据库的想法。系统提供了一个脚本(bean-sql),用于将 Beancount 文件的内容转换为 SQL 数据库;虽然在这些表上进行计算并不十分优雅,但该功能依然被保留了下来。即使操作有些困难,你仍然可以尝试使用它。我甚至可能预先计算部分操作的结果,以便更轻松地运行 SQL 查询。

但……我只想做X吗?

有些人可能会认为,既然他们只想用这种系统来完成单一目的,那它一定极其复杂。但事实是,你决定追踪多少账户完全是个人选择。你可以选择追踪尽可能少的账户,且详细程度也仅需满足你的需求即可。例如,如果你只对投资感兴趣,那么你只需记录投资账户即可。如果你希望替代 Mint.comQuicken 的使用,你只需复制信用卡的交易记录,就能查看相应的支出情况。

只需复制你所有账户的交易记录,而无需每年痛苦地从零开始重新评估所有资产和支出以了解财务状况——这种简单性将让你信服。使用电子表格查看财务状况时,你至少需要从投资组合中复制数值;每次生成报告时,你都必须更新这些数值……而用我的方法,你只需更新每个账户的完整活动记录,即可顺带获得完整的持仓清单。如果你有系统化的方法,让所有数据保持最新会非常容易。

我想对这些人说:试试看吧,只为你感兴趣的那部分做记账。一旦你体验了复式记账法的运作方式,并对它的语法有了一些了解,你就会想要获得更完整的画面。你会被深深吸引。

我为何如此兴奋?

好吧,我确实成了一个会计迷。这并非我主动追求的,只是在我不经意间悄然发生(不过我依然不穿棕色袜子)。为什么我停不下来谈论这些事呢?

我曾经拥有一家公司,它是承接外包工作的平台(是的,我最初对它抱有更大的期望,但最终它只是个空壳。唉。)作为加拿大的公司所有者,我必须定期向联邦和省级政府提交五种不同类型的税款预缴申报,有些每月一次,有些每季度一次,且情况各不相同。会计师会提供给我一些“魔法数字”填入表格,而我只是像猴子一样照抄这些数字,却完全不了解它们后续如何被使用。我必须单独统计与工作相关的支出(用于抵扣)和个人支出——我没有明智地使用独立的信用卡,而是试图从同一账户中区分个人与公司开销。我还需追踪公司账户与个人账户之间的转账,这些转账后来会被申报为股息或工资收入。我经常同时有多个来自不同客户的待收发票,付款周期往往超过两个月。那简直是一场半地狱般的经历。你懂我的意思。我曾试图手动追踪所有这些事务,使用由文本文件和电子表格组成的系统,并小心翼翼地以特定方式处理一切。

问题是,虽然我天性非常有条理,但有时——只是偶尔——我会忘记更新其中一个文件,导致各种数据不同步。一旦发生这种情况,我就特别沮丧,不得不花时间翻查各种语句,找出哪里出了错。这既耗时又令人不快。当然,当你不得不做的事情令人不快时,你往往做不好它。我在这一年中对公司的财务状况始终没有清晰的了解,只是埋头工作、赚钱。我的会计师每年七月份报完税后才会做一次资产负债表,每次结果都让我有点意外。每次处理“钱的事”时,我都感到长期处于某种困惑和烦躁之中。这算不上噩梦,但确实让我疲惫不堪。我感觉,当我只是有一份工作的时候,生活要简单得多。

但有一天……有一天……我豁然开朗:我发现了复式记账法。我不太记得具体是怎么发现的了,好像是在一个网站上……对,就是这个网站:dwmbeancounter.com(这是一个很棒的网站)。我意识到,通过使用一个统一的系统,我能够一次性解决所有这些问题,并且这种方式本身就内置了错误检查机制。我震惊了!当时我甚至把整个内容都打印了出来,逐个完成每一个教程。这个简单的记账技巧,正是我迫切需要的。

但我试过的所有软件,要么令人失望,要么存在缺陷,要么过于复杂。于是我开始研究 Ledger,并联系了它的作者。不久之后,我便开始着手开发 Beancount1。我承认,为了处理自己的记账问题而专门设计一套系统,确实有点小题大做,但我一向对某些事情格外较真,而解决这个问题的过程让我非常享受。当“学习”与“实践”保持良好平衡时,我的人生才感到充实,而这件事恰恰属于“实践”范畴。

从那以后,我对任何与个人财务相关的事情都充满热情。或许是因为,当我能如此清晰地掌握自己的财务状况时,我感到无比快乐。我甚至有时会因为知道将来必须记录这笔开销,而开始享受花钱的新方式。我因能解决这些财务谜题而感到无比兴奋,以至于曾连续整个周末投入精力开发这款软件。这些挑战虽小,却具有切实的应用价值和可感知的后果——即时的满足感。我感受到一种掌控感,我也希望你能拥有同样的感受。


  1. 有关完整差异列表,请参阅此文档