命令行记账食谱
Martin Blais,2014 年 7 月
http://furius.ca/beancount/doc/cookbook
引言
学习复式记账法的最佳方式是参考实际案例。这种方法优雅而高效,但初学者往往难以理解如何正确记录各种财务事件的交易。因此,我编写了这份食谱。它并非全面介绍 Beancount 所有功能的文档,而是一组实用指南,帮助您解决实际问题。我认为这将是 Beancount 文档集中最有用的文档!
此处所有示例均适用于任何复式记账系统:Ledger、GnuCash,甚至商业系统。部分细节可能仅有细微差异。本食谱使用 Beancount 软件的语法和计算方法编写。本文档还假设您已熟悉复式记账法的基本平衡概念,以及 Beancount 的部分语法,相关内容可参阅其用户手册或速查表。如果您尚未开始编写您的第一个文件,请先阅读开始使用 Beancount。
命令行记账系统对可记录的内容类型持中立态度,允许您创造性地定义各种单位来追踪不同事物。例如,您可以记录“IRA 供款美元”,虽然这不是真实货币,但对应于“实际可投入的美元金额”,并为其建立资产、收入和支出账户——这是完全可行的。请注意,某些巧妙的技巧在传统记账系统中可能无法实现。此外,这些系统中通常需要手动完成的操作(例如“结账年度”)可由软件自动完成,余额断言机制也允许我们在几乎无风险的情况下修改历史交易细节,因此无需通过冻结历史数据来“对账”。更多的灵活性触手可及。
最后,如果您遇到本文未涵盖的交易问题,请在页边留下评论,或向Ledger 邮件列表提交您的问题。我希望本文档能尽可能覆盖更多真实场景。
注意事项
在阅读本文时,请注意作者并非专业人士:我是一名计算机科学家,而非会计师。事实上,除了大学期间修过一门通识课程并完成 CFA 项目第一年学习外,我并无真正的会计培训背景。尽管如此,我确实有使用本软件维护三套账簿的实际经验:我的个人账本(包含八年完整的全部账户财务数据)、与配偶共用的联合账本,以及我曾拥有的承包与咨询公司的账目。多年来,我也用复式记账系统与我的会计师沟通,他提供了不少建议。然而……我仍可能在某些地方犯下根本性错误,若您发现任何可疑之处,欢迎在页边留下评论。
账户命名规范
您可以自由定义任何账户名称,只要其以以下五类之一开头即可:资产、负债、收入、支出或权益(请注意,您可通过选项自定义这些名称——详情请参阅语言语法文档)。账户名称通常由多个名称组成部分构成,各部分之间用冒号(:)分隔,以表示账户的层级结构,即“科目表”:
Assets:Component1:Component2:Component3:...
随着时间推移,我尝试过多种账户命名方式,最终形成了以下针对资产、负债和收入账户的命名规范:
Type : Country : Institution : Account : SubAccount
我喜欢这种方式,因为当您生成资产负债表时,树状结构会首先按国家、再按机构清晰地展示账户。
一些账户名称示例:
Assets:US:BofA:Savings ; Bank of America “Savings” account
Assets:CA:RBC:Checking ; Royal Bank of Canada “Checking” account
Liabilities:US:Amex:Platinum ; American Express Platinum credit card
Liabilities:CA:RBC:Mortgage ; Mortgage loan account at RBC
Income:US:ETrade:Interest ; Interest payments in E*Trade account
Income:US:Acme:Salary ; Salary income from ACME corp.
有时,当有必要时,我会再添加一两个子账户。例如,Vanguard 内部会根据资金来源是雇员缴款还是雇主匹配金额,分别设立不同账户:
Assets:US:Vanguard:Contrib401k:RGAGX ; My contributions to this fund
Assets:US:Vanguard:Match401k:RGAGX ; Employer contributions
对于投资账户,我通常将每种股票单独存放在其对应的子账户中:
Assets:US:ETrade:Cash ; The cash contents of the account
Assets:US:ETrade:FB ; Shares of Facebook
Assets:US:ETrade:AAPL ; Shares of Apple
Assets:US:ETrade:MSFT ; Shares of Microsoft
…
这样可以自动按股票类型对资产负债表进行分类,我觉得非常方便。
我另一个喜欢的规范是:当拥有相关联的不同账户类型时,使用相同的机构名称。例如,上述 E*Trade 资产账户对应的收入流,会记入名称相似的账户下:
Income:US:ETrade:Interest ; Interest income from cash deposits
Income:US:ETrade:Dividends ; Dividends received in this account
Income:US:ETrade:PnL ; Capital gains or losses from trades
…
对于“支出”账户,通常不存在相关的机构。因此,更适合将它们视为类别,并建立与支出类型直接对应的简单层级结构,例如:
Expenses:Sports:Scuba ; All matters of diving expenses
Expenses:Transport:Train ; Train (mostly Amtrak, but not always)
Expenses:Transport:Bus ; Various “chinese bus” companies
Expenses:Transport:Flights ; Flights (various airlines)
…
我有大量此类账户,超过 250 个。究竟定义多少、如何细分或“分类”您的支出,完全取决于您自己的需求。但请记住,只需在需要时才定义新账户;不必提前列出一大串。随时都可以轻松添加新账户。
值得注意的是,机构名称不必是真实存在的机构。例如,我曾拥有一套公寓楼中的单元房,我将 Loft4530 作为该房产所有相关账户的“机构”名称:
Assets:CA:Loft4530:Property
Assets:CA:Loft4530:Association
Income:CA:Loft4530:Rental
Expenses:Loft4530:Acquisition:Legal
Expenses:Loft4530:Acquisition:SaleAgent
Expenses:Loft4530:Loan-Interest
Expenses:Loft4530:Electricity
Expenses:Loft4530:Insurance
Expenses:Loft4530:Taxes:Municipal
Expenses:Loft4530:Taxes:School
如果您所有业务均在一个国家内开展,且无迁往其他国家的计划,为简洁起见,可以省略国家组件。
最后,对于‘权益’账户,嗯……通常你不需要定义太多,因为这些账户主要用于在资产负债表中报告以前年度或当前会计期间的净利润和货币兑换。通常你至少需要一个,具体命名并不重要:
Equity:Opening-Balances ; Balances used to open accounts
你可以自定义资产负债表中自动生成的其他权益账户的名称。
选择账户类型
学习如何为交易选择合适的账户,部分艺术在于为账户命名,并通过记录一些示例交易来设计资金在这些账户间流动的方案。这个过程可以相当有创意。当你在思考如何‘记录’生活中所有财务事件时,常常会纠结于某些账户该选择哪种类型:这应该是一个‘资产’账户?还是一个‘收入’账户?毕竟,除了生成报表之外,Beancount 并不会对这些账户类型做任何区别对待……
但这并不意味着你可以随意乱用类型。账户是否出现在资产负债表或利润表中确实很重要——通常都有一个正确的选择。当你不确定时,以下是一些选择账户类型的指导原则:
首先,如果计入该账户的金额仅在某个时间段内需要报告,则应属于利润表账户:收入或支出。另一方面,如果金额始终需要计入账户的总余额,则应为资产负债表账户:资产或负债。
其次,如果金额通常1为正数,或‘对你有利’,则该账户应为资产账户或支出账户;如果金额通常为负数,或‘对你不利’,则该账户应为负债账户或收入账户。
根据这两个指标,你应该能够判断任何情况。让我们通过一些例子来说明:
-
一顿餐厅用餐代表你用某些资产(现金)或负债(刷信用卡)换取了某种东西。没有人会在意‘自你出生以来所有食物消费的总和’是多少。只有过渡性的价值才重要:‘我这个月在餐厅花了多少钱?’或者,今年年初以来?或者,这次旅行期间?这显然指向一个支出账户。但你可能会疑惑:这是个正数,可这明明是我花掉的钱?没错,你用于支付的账户被减去了(借方),以换取你所获得的支出。把支出账户中的数字想象成你获得后立即消失的东西。这些餐食被消费了……然后就消失了。好吧,这个类比我们就停在这里。
-
你持有一些债券,并收到了利息支付。这笔利息作为现金存入了一个资产账户,例如交易账户。那么,另一方应记入哪个账户?
选择期初日期
你需定义的一些账户并不对应现实中的账户。Expenses:Groceries 账户表示自你开始记账以来所有杂货支出的总和。我个人喜欢在这些账户上使用我的出生日期。这有其道理:它汇总了你自出生以来所有在杂货上的花费,而这些花费正是从你来到这个世界才开始的。
你可以将此理由应用于其他账户。例如,与雇主相关的所有收入账户都应在你入职之日开设,并在离职之日关闭。这很合理。
如何处理现金
我们先从现金开始。我通常在出生日期时定义两个账户:
1973-04-27 open Assets:Cash
1973-04-27 open Assets:ForeignCash
第一个账户用于日常使用,代表我的钱包,通常只包含我的运营货币单位,即我通常视为“现金”的商品。对我而言,它们是美元(USD)和加元(CAD)商品。
第二个账户用于存放我在全球旅行时随身携带的纸币,这样它们就不会干扰我的现金余额。当我前往这些地方旅行时,我会将这些纸币转入主账户。例如,如果我返回日本,我会在出发前将日元(JPY)从 Assets:ForeignCash 转入 Assets:Cash,并在旅行期间使用它们。
现金取款
从支票账户取现到现金的交易通常如下所示:
2014-06-28 * "DDA WITHDRAW 0609C"
Assets:CA:BofA:Checking -700.00 USD
Assets:Cash
你将在支票账户的交易下载记录中看到这笔交易。
追踪现金支出
当你告诉别人你在追踪所有财务账户时,他们常误以为你必须将每一笔微不足道的现金交易都记入账本。其实不然!是否记录这些现金交易,以及记录多少,完全由你决定。
我个人尽量减少更新 Ledger 所需的手动操作。我处理现金的规则如下:
如果是用于餐饮或酒精,我就不记录。
如果是其他用途,我会保留收据,稍后再录入。
这对我很有效,因为我的大部分现金支出都是餐饮(或许是我通过信用卡支付其他所有开销,才让现金支出主要集中在餐饮上)。只有少数几张收据会堆在桌上几个月,我才抽空录入。
不过,你需要定期调整现金账户,以反映这些未记录的支出。我其实并不经常做这件事……可能每三个月一次,当我有空时才做。我的方法是手动清点钱包里的钞票,然后输入一个对应的余额确认:
2014-05-12 balance Assets:Cash 234.13 USD
每次这样做时,我还会添加一笔现金分配调整,以平衡账户:
2014-06-19 * "Cash distribution"
Expenses:Food:Restaurant 402.30 USD
Expenses:Food:Alcohol 100.00 USD
Assets:Cash ; -502.30 USD
2014-06-20 balance Assets:Cash 194.34 USD
如果你疑惑为什么现金账户的金额加总不一致(234.13 - 502.30 ≠ 194.34),那是因为在这两次余额确认之间,我通过从支票账户取现增加了现金账户余额,而这些取现记录会出现在别处(支票账户部分)。如果我导出 Assets:Cash 的日记账,就能看到这些取现记录。
如果我把所有支出都归入餐饮类别,本可以用 Pad 指令简化流程——Pad 条目不仅适用于账户历史的开头,也适用于同一账户的任意两次余额确认之间——但我希望将 80% 的支出记为餐饮,20% 记为酒精,以更准确地反映我真实的现金使用情况2。
最后,如果你在执行此操作的时间间隔较长,你可能希望通过手动添加多个现金分配3来分摊支出,这样在生成月度报告时,大额现金支出就不会以单笔整额的形式出现在该月内或月外。
工资收入
记录你的工资收入非常有益:你将能够获得全年收入的汇总,以及各项扣款的具体去向,并且当你收到雇主提供的 W-2 表格(或加拿大的 T4 表格)时,能欣喜地看到 Beancount 报表中的数字与之完全匹配。
我会将与雇主相关的所有条目放在一个独立的章节中。我首先设置一个事件,标记我开始在那里工作的日期,例如,使用假设公司“Hooli”(来自《硅谷》剧集):
2012-12-13 event "employer" "Hooli Inc."
这使我能够自动计算我在该公司工作的天数。当我离职时,我会将其更新为新公司,或在没有立即入职新公司时设为空字符串:
2019-03-02 event "employer" ""
本节将做出若干假设。其目标是向你展示可用于正确记录收入的各种方法。你几乎肯定需要根据自身情况调整这些方法。
雇员收入账户
然后,你需要为工资单定义相应的账户。必须确保为工资单上的每一项都设置一个对应的账户。例如,以下是我在 Hooli 公司为工资收入定义的部分收入账户:
2012-12-13 open Income:US:Hooli:Salary USD ; "Regular Pay"
2012-12-13 open Income:US:Hooli:ReferralBonus USD ; "Referral bonuses"
2012-12-13 open Income:US:Hooli:AnnualBonus USD ; "Annual bonus"
2012-12-13 open Income:US:Hooli:Match401k USD ; "Employer 401k match"
2012-12-13 open Income:US:Hooli:GroupTermLife USD ; "Group Term Life"
这些账户分别对应常规工资、员工推荐奖金、年度奖金、401k 缴款(本例中 Hooli 公司会按一定比例匹配你对退休账户的缴款)、人寿保险收入(此项同时体现为收入和支出),以及健身房会员费补贴。还有更多项目,但以上已是一个很好的示例。(本例中我将工资单上的名称作为注释写入,但如果你更喜欢,也可以将其作为元数据插入。)
你还需要将预扣税款记入相应年份的税务账户(详见税务章节):
2014-01-01 open Expenses:Taxes:TY2014:US:Medicare USD
2014-01-01 open Expenses:Taxes:TY2014:US:Federal USD
2014-01-01 open Expenses:Taxes:TY2014:US:StateNY USD
2014-01-01 open Expenses:Taxes:TY2014:US:CityNYC USD
2014-01-01 open Expenses:Taxes:TY2014:US:SDI USD
2014-01-01 open Expenses:Taxes:TY2014:US:SocSec USD
这些账户用于记录医疗保险税、联邦税、纽约州税和纽约市税(是的,纽约市居民需在州税之外额外缴纳市税)、州残疾保险(SDI)缴费,以及社会保障税。
你还需要在其他地方定义一些账户,用于记录从工资中自动扣除的各种支出:
2012-12-13 open Expenses:Health:Life:GroupTermLife USD ; "Life Ins."
2012-12-13 open Expenses:Health:Dental:Insurance USD ; "Dental"
2012-12-13 open Expenses:Health:Medical:Insurance USD ; "Medical"
2012-12-13 open Expenses:Health:Vision:Insurance USD ; "Vision"
2012-12-13 open Expenses:Internet:Reimbursement USD ; "Internet Reim"
2012-12-13 open Expenses:Transportation:PreTax USD ; "Transit PreTax"
这些账户对应公司团体人寿保险缴费、牙科、医疗和视力保险保费、家庭网络费用报销,以及税前支付的公共交通费用(纽约市允许你通过雇主用税前收入支付地铁卡费用)。
记录工资入账
当我通过直接存款导入到支票账户的付款明细时,记录将如下所示:
2014-02-28 * "HOOLI INC PAYROLL"
Assets:US:BofA:Checking 3364.67 USD
如果我尚未收到工资单,可以暂时先记入工资账户,待收到后再调整:
2014-02-28 * "HOOLI INC PAYROLL"
Assets:US:BofA:Checking 3364.67 USD
! Income:US:Hooli:Salary
当我收到或获取工资单后,我会移除临时记录并完成其余分录。一笔税前工资为 140,000 美元的合理分录大致如下:
2014-02-28 * "HOOLI INC PAYROLL"
Assets:US:BofA:Checking 3364.67 USD
Income:US:Hooli:GroupTermLife -25.38 USD
Income:US:Hooli:Salary -5384.62 USD
Expenses:Health:Dental:Insurance 2.88 USD
Expenses:Health:Life:GroupTermLife 25.38 USD
Expenses:Internet:Reimbursement -34.65 USD
Expenses:Health:Medical:Insurance 36.33 USD
Expenses:Transportation:PreTax 56.00 USD
Expenses:Health:Vision:Insurance 0.69 USD
Expenses:Taxes:TY2014:US:Medicare 78.08 USD
Expenses:Taxes:TY2014:US:Federal 1135.91 USD
Expenses:Taxes:TY2014:US:CityNYC 75.03 USD
Expenses:Taxes:TY2014:US:SDI 1.20 USD
Expenses:Taxes:TY2014:US:StateNY 340.06 USD
Expenses:Taxes:TY2014:US:SocSec 328.42 USD
工资支付完全与上一期相同的情况非常罕见: payroll 处理商的四舍五入通常会导致几分钱的差异,社会保险支付会达到上限,且会不定期发生各种扣除,例如对所获应税福利的扣除。此外,401k 供款会影响源扣税金额。因此,您必须逐张核对工资单以正确录入信息。但其实这并没有听起来那么耗时!这里有个技巧:如果您按照工资单上的顺序列出您的记账条目,更新交易会容易得多。您只需复制粘贴上一条记录,从上到下阅读工资单,然后相应调整数字即可。每条只需一分钟。
值得注意的是,上一条记录中有一些特殊之处。"团体定期寿险"条目同时包含一笔 25.38 美元的收入项和一笔支出项。这是因为 Hooli 公司支付了保费(工资单上明确如此显示)。Hooli 还报销部分家庭网络费用,因为我用它处理生产问题。这笔报销以负数条目形式出现,用于减少我的支出账户"Expenses:Internet"的金额。
休假时数
我们的工资单还包含累计休假时数和总休假余额(以休假小时计)。您也可以在同一条交易中追踪这些金额。您需要声明相应的账户:
2012-12-13 open Income:US:Hooli:Vacation VACHR
2012-12-13 open Assets:US:Hooli:Vacation VACHR
2012-12-13 open Expenses:Vacation:Hooli VACHR
累计的休假属于您应得的收益,因此应作为收入,以"VACHR"为单位,并累积在资产账户中,该账户记录您当前可使用的休假小时数。更新上一条工资收入交易记录:
2014-02-28 * "HOOLI INC PAYROLL"
Assets:US:BofA:Checking 3364.67 USD
…
Assets:US:Hooli:Vacation 4.62 VACHR
Income:US:Hooli:Vacation -4.62 VACHR
每两周工资单上累计 4.62 VACHR,一年发放 26 次,总计约为 26 × 4.62 = 120 小时。按每天 8 小时计算,相当于 15 个工作日,即 3 周,这正是本例中美国新员工的标准休假福利。
当您实际休假时,需将休假时间作为支出记账:
2014-06-17 * "Going to the beach today"
Assets:US:Hooli:Vacation -8 VACHR
Expenses:Vacation:Hooli
支出账户记录您已使用的休假时长。您可以定期核对工资单上报告的余额——即雇主认为您剩余的休假时间——是否与您记录的金额一致:
2014-02-29 balance Assets:US:Hooli:Vacation 112.3400 VACHR
您可以将休假小时单位按您的时薪定价,这样您的休假资产账户就能显示,如果您决定离职,公司需向您支付的金额。假设年薪为 14 万美元,每周工作 40 小时,每年工作 50 周,即每年 2000 小时,我们得出时薪为 70 美元,您可按如下方式录入:
2012-12-13 price VACHR 70.00 USD
同样,如果您的休假时数到期或达到上限,您可以计算因工作过度而放弃休假所损失的等值金额。您需要将部分 VACHR 从资产账户转出至一个收入账户(代表损失)。
401k 供款
401k 计划允许您使用税前收入向免税退休账户供款。该供款通过工资扣款完成。为记录这些供款,您只需在交易中添加一条对应于您退休账户的供款条目:
2014-02-28 * "HOOLI INC PAYROLL"
Assets:US:BofA:Checking 3364.67 USD
…
Assets:US:Vanguard:Cash 1000.00 USD
…
如果您正在追踪可使用的供款额度(参见本文档的税务部分),则需同时减少您的"401k 供款"资产账户。您需要为此交易添加两条额外条目:
2014-02-28 * "HOOLI INC PAYROLL"
Assets:US:BofA:Checking 3364.67 USD
…
Assets:US:Vanguard:Cash 1000.00 USD
Assets:US:Federal:PreTax401k -1000.00 US401K
Expenses:Taxes:TY2014:US:Federal:PreTax401k 1000.00 US401K
…
如果您的雇主匹配您的供款,这些金额可能不会显示在您的工资单上。由于这些供款无需纳税——它们直接存入免税递延账户——您的雇主无需将其包含在扣缴声明中。您会直接在投资账户中看到这些款项作为存款入账。您可以按如下方式记入退休账户的税务余额:
2013-03-16 * "BUYMF - MATCH"
Income:US:Hooli:Match401k -1173.08 USD
Assets:US:Vanguard:Cash 1173.08 USD
然后,当您投资这笔款项时,或如果您已指定资产配置且经纪商已自动执行,可直接用供款购买资产时,插入第二笔交易:
2013-03-16 * "BUYMF - MATCH"
Income:US:Hooli:Match401k -1173.08 USD
Assets:US:Vanguard:VMBPX 106.741 VMBPX {10.99 USD}
请注意,管理您 401(k)账户的基金可能会将您的供款和雇主的供款分别记录在不同的账户中。您需要为此创建子账户并进行相应调整:
2012-12-13 open Assets:US:Vanguard:PreTax401k:VMBPX VMBPX
2012-12-13 open Assets:US:Vanguard:Match401k:VMBPX VMBPX
他们通常这样做是为了分别追踪每笔供款的来源,因为涉及向其他账户进行滚转时存在若干限制,这些限制依赖于供款来源的区分。
归属股票授予
有关此主题的更多详情,请参阅专用文档。
其他福利
如果您愿意,可以对福利进行极其详细的追踪。以下是一些大胆的建议。
积分
如果您的雇主提供现场赞助的按摩疗法服务,您 presumably 可以从工资中扣除按摩费用,或通过公司内部网站(如果公司较现代化)进行支付,并使用某种内部积分系统(例如“Hooli 积分”)支付。您可以使用虚构的货币(例如“MASSA”)来追踪这些积分,其定价为 0.50 美元,即您购买按摩服务的价格:
2012-12-13 open Assets:US:Hooli:Massage MASSA
2012-12-13 price MASSA 0.50 USD
当我购买新的按摩积分时,我
2013-03-15 * "Buying points for future massages"
Liabilities:US:BofA:CreditCard -45.00 USD
Assets:US:Hooli:Massage 90 MASSA {0.50 USD}
如果您偶尔获得一些此类积分,可以在“收入”账户中进行追踪。
餐饮福利
与许多大型科技公司一样,Hooli 假设为其员工提供免费餐饮。这节省了时间并鼓励员工健康饮食。这目前在科技界是一种趋势。这项福利不会在任何地方明确显示,但如果您希望将其计入薪酬包并定价,可以通过一个收入账户进行追踪:
2012-12-13 open Income:US:Hooli:Food
根据您在公司用餐的频率,您可以估算每月的餐补金额:
2013-06-30 * "Distribution for food eaten at Hooli"
Income:US:Hooli:Food -350 USD
Expenses:Food:Restaurant
货币兑换与转换
如果您进行货币兑换(例如在银行间进行国际转账),您需要向 Beancount 提供汇率。其格式如下:
2014-03-03 * "Transfer from Swiss account"
Assets:CH:UBS:Checking -9000.00 CHF
Assets:US:BofA:Checking 10000.00 USD @ 0.90 CHF
第二笔分录的余额金额计算为:10,000.00 美元 × 0.90 瑞士法郎/美元 = 9,000 瑞士法郎,交易保持平衡。根据您的偏好,您也可以将汇率放在另一笔分录上,如下所示:
2014-03-03 * "Transfer from Swiss account"
Assets:CH:UBS:Checking -9000.00 CHF @ 1.11111 USD
Assets:US:BofA:Checking 10000.00 USD
第一笔分录的余额金额计算为:-9,000.00 瑞士法郎 × 1.11111 美元/瑞士法郎 = 10,000.00 美元4。通常我会选择我收到的汇率,并将其放在对应的那一侧。您也可以考虑外汇市场交易汇率的方向,例如瑞士法郎的交易汇率为 USD/CHF,因此我更倾向于第一种交易方式。价格数据库会双向转换汇率,因此这并不太重要5。
如果您使用电汇(这是此类资金转账的常见方式),可能会产生费用:
2014-03-03 * "Transfer from Swiss account"
Assets:CH:UBS:Checking -9025.00 CHF
Assets:US:BofA:Checking 10000.00 USD @ 0.90 CHF
Expenses:Fees:Wires 25.00 CHF
如果您在旅游景点常见的那些看起来可疑的货币兑换点兑换现金,情况可能如下所示:
2014-03-03 * "Changed some cash at the airport in Lausanne"
Assets:Cash -400.00 USD @ 0.90 CHF
Assets:Cash 355.00 CHF
Expenses:Fees:Services 5.00 CHF
无论如何,您都绝不应使用成本基础语法来兑换货币单位,因为在存入货币单位后,原始兑换汇率应被遗忘,而不应与普通货币绑定保留。例如,以下用法是错误的:
2014-03-03 * "Transfer from Swiss account"
Assets:CH:UBS:Checking -9000.00 CHF
Assets:US:BofA:Checking 10000.00 USD {0.90 CHF} ; <-bad!
如果您不小心这样做了,当您尝试使用新存入的美元时,就会出现错误:Beancount 将要求您指定这些“美元”的成本(以瑞士法郎计),例如:“借记我以 0.90 美元/瑞士法郎兑换的美元”。在现实世界中没有人这样做,您在记录交易时也不应如此:一旦货币完成兑换,它就只是另一种货币的资金,不再附带任何成本。
最后,一个较为微妙的问题是:随着时间推移反复以不同汇率进行价格换算,会在一定程度上破坏会计恒等式:汇率变动可能凭空产生少量资金,导致所有余额无法总和为零。然而,这并不是一个问题,因为 Beancount 实现了一种优雅的解决方案,可自动修正此问题,因此您可以自由使用这些换算而无需担心:它会在资产负债表中插入一个特殊的换算条目,以抵消换算的累积效应,从而获得一个干净的零余额。(换算问题的讨论超出了本食谱的范围;如需了解更多,请参阅 解决换算问题。)
投资与交易
跟踪交易及其相关收益是一个相当复杂的话题。您可以在专门讨论此主题的 使用 Beancount 进行交易 文档中找到关于利润与亏损的更完整介绍,以及各种场景的详细讨论。此处我们将讨论如何设置您的账户,并提供一些简单的示例交易以帮助您入门。
账户设置
您应创建一个账户前缀,用于归类与您的投资账户相关的各种子账户。假设您在 ETrade 开设了账户,可以命名为“Assets:US:ETrade”。请选择一个合适的机构名称。
您的投资账户将包含一个现金部分。您应创建一个专用的子账户,用于表示未投资的现金存款:
2013-02-01 open Assets:US:ETrade:Cash USD
我建议您为每种您将投资的资产类型进一步定义一个子账户。虽然这并非严格必要——Beancount 账户可以包含任意数量的资产——但这是一种很好的方式,便于按资产类型汇总所有持仓以供报告。例如,如果您将购买 LQD 和 BND 这两种流行的债券 ETF:
2013-02-01 open Assets:US:ETrade:LQD LQD
2013-02-01 open Assets:US:ETrade:BND BND
这也有助于生成更美观的报表:余额通常按成本显示,按资产类型汇总总成本对多种原因很有帮助(例如,每种资产都提供不同的市场敞口)。为机构内持有的每种资产设立专用子账户,是一种很好的做法。除非您有特殊理由不这样做,否则我强烈建议默认采用这种方式(您以后可以通过重命名账户随时更改)。
为您的账户指定资产约束,将有助于发现录入错误。股票交易通常比常规交易更复杂,这无疑会非常有帮助。
随后,您可能会以两种形式从该账户获得收入:资本利得(或称“损益”)和股息。我倾向于按机构来记录这些项目,因为这是报税时所需的方式。您也可能收到利息收入。请定义这些项目:
2013-02-01 open Income:US:ETrade:PnL USD
2013-02-01 open Income:US:ETrade:Dividends USD
2013-02-01 open Income:US:ETrade:Interest USD
最后,为了记录交易费用和佣金,您需要设置一些通用账户来接收这些费用:
1973-04-27 open Expenses:Financial:Fees
1973-04-27 open Expenses:Financial:Commissions
资金转账
您通常会通过从外部账户(例如支票账户)转账的方式,向该账户注入初始资金:
2014-02-04 * "Transferring money for investing"
Assets:US:BofA:Checking -2000.00 USD
Assets:US:ETrade:Cash 2000.00 USD
进行交易
购买股票时,应做如下记账:将新购入的证券存入该证券的子账户,同时借记现金账户,金额为对应证券的总成本加上佣金:
2014-02-16 * "Buying some LQD"
Assets:US:ETrade:LQD 10 LQD {119.24 USD}
Assets:US:ETrade:Cash -1199.35 USD
Expenses:Financial:Commissions 6.95 USD
请注意,当您购买某种证券时,实际上是在账户库存中建立了一个新的交易批次,因此必须提供每单位的成本(例如,本例中每单位 LQD 股票的成本为 119.24 美元)。这有助于我们正确计算资本利得。
卖出部分相同股票的操作类似,但需额外增加一条分录以确认资本利得或损失:
2014-02-16 * "Selling some LQD"
Assets:US:ETrade:LQD -5 LQD {119.24 USD} @ 123.40 USD
Assets:US:ETrade:Cash 610.05 USD
Expenses:Financial:Commissions 6.95 USD
Income:US:Etrade:PnL
请注意,从Assets:US:ETrade:LQD账户中减少的股票数量属于批次的减少,您必须提供信息以明确所减少的是哪个批次,在本例中需提供每股票 119.24 美元的成本基础。
我通常让 Beancount 自动计算资本利得或损失,因此我在最后一笔分录中未明确指定。Beancount 会自动平衡这笔交易,将该分录金额设为-20.80 美元,即获得 20.80 美元的收益(请注意,收入账户的符号是反向的)。指定卖出价格 123.40 美元是可选的,且在平衡交易时该价格会被忽略,实际利润由现金入账和佣金两条分录决定。
收到股息
收到股息有两种形式。首先,您可以收到现金股息,这些资金将存入现金账户:
2014-02-16 * "Dividends from LQD"
Income:US:ETrade:Dividends -87.45 USD
Assets:US:ETrade:Cash 87.45 USD
请注意,此处未指明股息的来源。您也可以在收入账户下设立子账户,以便单独统计。
或者,您可以选择以股票形式再投资股息:
2014-06-27 * "Dividends reinvested"
Assets:US:Vanguard:VBMPX 1.77400 VBMPX {10.83 USD}
Income:US:Vanguard:Dividends -19.21 USD
这种记账方式与购买股票类似,您也必须提供所收到股票单位的成本基础。这通常发生在非应税退休账户中。
有关更详尽的讨论和更多复杂示例,请参阅使用 Beancount 进行交易文档。
选择日期
买卖单一批次的股票通常涉及多个时间点的事件:下达交易指令、交易成交(通常在同一天)、交易结算。结算通常在成交后 2 至 3 个工作日完成。
为简化处理,我建议使用交易日作为记账日期。在美国,这是税务认可的日期,而结算日对您的账户并无实质影响(经纪商通常不允许您在没有相应现金或保证金的情况下进行交易)。因此,我通常不会为结算单独创建分录,这并无太大实际意义。
当然,也可以设计更复杂的方案,例如将结算日期作为元数据字段存储,以便后续在脚本中使用,但这已超出本文档的范围。
结论
本文件尚未完成。我还有许多示例用例计划在完成后添加到这里。当这些内容陆续完成时,我将在邮件列表中发布通知。特别是,以下主题将进行讨论:
-
医疗保健支出,例如保险费和退款
-
税收
-
个人退休账户(IRAs)、401k 及其他税收递延账户
-
房地产
-
选项
-
这并非绝对成立:在企业会计中,某些账户类型出于特定原因(通常是为了抵消同类型其他账户的价值)会以相反的数值记录,这些被称为“反向”账户。但作为个人,你几乎不可能拥有此类账户。如果你正在为公司设置会计科目表,Beancount 并不关心余额的正负符号。你只需像设置普通账户一样声明反向账户即可。 ↩
-
我正在考虑支持一种扩展版的 Pad 指令,使其能够接受百分比值,从而仅对总额的指定百分比进行填充,以实现自动化。 ↩
-
Beancount 的另一项扩展涉及支持在两个余额断言之间使用多个 Pad 指令,并自动实现这些填充指令的分布。 ↩
-
请注意,如果价格数据库需要对日期进行倒置计算,其结果可能产生具有大量小数位的价格。Beancount 使用 IEEE 十进制对象,而 Python 实现的默认上下文为 28 位数字,因此将 0.9 倒置将得到 1.111111…111(共 28 位)。 ↩