你好,我是测试蔡坨坨。
在前面两篇文章中,我们探讨了「一年之余,财富何方?」以及「财富梳理:复式记账之道」,旨在回答两个核心问题:“为什么要记账?”和“如何科学记账?”。
实践是检验真理的唯一标准。同样,复式记账也需要通过实践来理解。在开始实践之前,学习很多晦涩难懂的会计学概念没有任何意义。正如上篇文章末尾所述,对于复式记账的理论部分,我们只需记住会计恒等式
和两句口诀
,便能游刃有余。
会计恒等式:资产+费用=负债+所有者权益+收入
两句口诀:
资产、费用类:借增贷减
负债、权益、收入类:借减贷增
要开始实践,就要有工具上手,复式记账是方法论,而Beancount则是支持复式记账的工具。
在众多选择中,我推荐使用Beancount。虽然第一次见到Beancount时,我的内心是拒绝的,纯文本环境,也没有市面上大多数记账软件方便快捷、界面简单的优势,似乎还需要一点学习成本。
但是,在犹豫片刻之后,我便鼓起勇气用一晚上时间完成了学习和初始化,两天后就决定全面搬迁到Beancount。从2024年初开始,到现在已有三个多月的使用体验,我对它十分满意,希望能将它推广给更多的用户,原因如下:
除了Beancount之外,还有许多其他开源的工具可供选择。可以参考Plain Text Accounting网站上列出的,类似的具有竞争力的还有Ledger和hledger。其中,Ledger是这类工具的开创者。无论是里面介绍的哪个工具,实现理念都是大同小异,即记录账户之间的资金流动
。
Beancount是一个基于文本的复式记账软件,与其说是记账软件,不如说它是复式算账软件,因为它没有提供任何对于记账相关的功能,它提供的是对于某种特定格式的账本的解析功能,实际上的记账人是你,甚至你的账本Beancount不会做任何操作,官方将其定义为“一种复式记账计算机语言
”。
复式记账软件不少,就算是开源世界,也有GnuCash,这些软件都有完整的GUI操作,用户在一堆文本框里输入各种数字和文字,软件接收输入后存储到自己的数据库里,又何苦选择文本记账的方式呢?
我给出的理由是:
上面提到,文本记账的话,其实还有Ledger和hledger可以选择。Beancount是一个Ledger-like软件,Ledger是这一类复式记账软件的开创者。相比于C++写的Ledger,用Python写的Beancount更轻便,方便增加插件和二次开发,同时也增加了许多功能,如灵活强大的“货币”支持(Beancount其实并不知道什么是货币,它记录的只是通货(commodity)
的变化,所有的通货皆由用户自定义,因此Beancount可以用来记录除货币在内的任何东西的变化,比如假期天数、信用卡积分、股票、基金、航空里程等,当然也可以用来数豆子,这也是Beancount名字的来源)。
在这三个软件中,Beancount的生态社区最为活跃。它简化了记账符号的使用,将正负号代替了传统的“借”和“贷”。
此外,Beancount官方提供了一个名为fava的图形化管理工具。通过fava,用户可以在web界面中展示文本账簿,使记账信息一目了然。fava还提供各种报表统计分析功能,让用户能够更加方便地进行财务分析。可以访问官方提供的Demo提前体验一波。
由于Beancount和Fava都是使用Python实现的,因此安装过程也非常简单(前提是需要有Python环境)。
安装Beancount
pip install beancount
安装Fava
pip install fava
安装完成后,您只需执行fava xxx.bean
即可查看任意账本文件(鉴于目前还没开始编写账本,可以先用fava提供的示例账本过把干瘾)
fava example.bean
打开浏览器,并访问 http://127.0.0.1:5000,即可开始使用
运行Fava后,你会看到一个华丽的 Web UI,其中有两张报表值得我们关注,损益表和资产负债表。
记账的目的是为了了解自己的财务状况,换成通俗易懂的话就是为了回答以下三个问题:
一本维护良好的账本能生成很多有用的财务报表,而其中最有用的是损益表
和资产负债表
,前者能回答第一个和第三个问题,后者能回答第二个问题。
损益表,也称为利润表,在这张报表中,我们可以一目了然地看到自己每月有哪些收入、收入来自于哪些地方、有多少支出、支出花在了什么地方。
在复式记账中,支出类借增贷减,上半部分代表支出(正数、流出),收入类借减贷增,下半部分代表收入(负数、流入)。
鼠标悬停在某个月份上,可以看到这个月份的净利润:
右上角可以切换 按年/按季/按月/按周/按日
展示:
还可以切换到收入
或支出
上,只看收入或支出的情况:
默认展示堆叠条形图,鼠标悬停在条形图上,可以看到此项在这个月的变化:
切换到Income或Expenses上,能看到收入或支出的旭日图:
页面右上角有时间、账户、筛选(标签,收款人等等)几个过滤框,日期除了支持具体的年月日,还支持 year/month/day
等关键字,例如 year-2 - year
表示只展示前年到今年的交易:
页面下半部分是具体每个账户的收支情况:
点击某个账户,可以看到这个账户的曲线图和具体的交易记录:
在资产负债表里,可以一目了然地看到自己有多少资产、资产分别在哪些账户里,有多少负债、是哪里的负债。
上半部分是净资产变化的折线图,下半部分是具体每个账户的情况。
切换到Assets、Liabilities或Equity上,可以看到资产、负债或净资产的饼图:
说了这么多,也许你已经安装完毕,磨拳搓掌准备行动。
Beancount的使用很简单,概括为两个步骤:
文本文件
(文件扩展名为.bean
)按一定格式记账fava xxx.bean
下面是个完整的示例:
账本文件中包含账本信息设置、账户设置、账户初始化、交易记录等步骤,我们将在下文做详细说明。
;【一、账本信息】
option "title" "我的账本" ;账本名称
option "operating_currency" "CNY" ;账本主货币
;【二、账户设置】
;1、开设账户
1990-01-01 open Assets:Card:1234 CNY, USD ;尾号1234的银行卡,支持CNY和USD
1990-01-01 open Expenses:Traffic:Taxi CNY ;打车消费,只支持CNY
1990-01-01 open Liabilities:CreditCard:5678 CNY, USD ;双币信用卡
1990-01-01 open Income:Salary CNY ;工资收入
1990-01-01 open Equity:OpenBalance ;用于账户初始化,支持任意货币
;2、账户初始化
2024-01-11 * "账户余额初始化" "初始化银行卡1234余额为10000元"
Assets:Card:1234 10000.00 CNY
Equity:OpenBalance -10000.00 CNY
;【三、交易记录】
2024-01-01 * "滴滴打车" "打车到公司,银行卡支付"
Expenses:Traffic:Taxi 200.00 CNY
Assets:Card:1234 -200.00 CNY
2024-01-01 * "" "餐饮"
Assets:Card:1234 -20.00 CNY
Liabilities:CreditCard:5678 20.00 CNY
2024-01-10 * "XX公司" "工资收入"
Assets:Card:1234 3000.00 CNY
Income:Salary -3000.00 CNY
执行命令:
fava demo.bean
浏览器访问http://127.0.0.1:5000:
到这里,我们已经完成了Beancount的快速入门。
Beancount的作者是Emacs的用户,因此自己写了Emacs的插件。Vim的用户可以使用第三方提供的nathangrigg/vim-beancount插件。Sublime的用户可以使用sublime-beancount。
而我使用的是Visual Studio Code,配合Beancount(by Lencerf)扩展插件,能够实现语法着色、账户自动补全、数字按小数点对齐、错误提示等功能。
选择编辑器和插件的目的在于提高效率,使记账变得更加轻松和愉快。
当然,如果你不嫌麻烦,直接使用最原始的记事本也完全没有问题。
在组织账本时,将其拆分成多个文件是一个很好的做法。这样可以更好地管理和维护账本,使其更具可读性和可维护性。通过使用Beancount的include
语法,可以将多个账本文件关联起来,形成一个完整的账户体系。
例如,我的账本结构目录如下:
最外层是main.bean
主账本文件,用于整合和管理所有其他账本文件,查账时只需执行命令fava main.bean
;开户和账户余额初始化相关的信息放在accounts
文件夹下,并使用assets、liabilities等关键字命名文件,以便对应相应类型的账户;交易记录按照年份进行分类,在每个年份文件夹中可以进一步细分,例如日常支出、转账、收入、旅游娱乐、投资收益等。
这样的结构设计使得账本信息更加有条理,便于查找和管理。同时,也方便了账本的维护和更新,能够更有效地记录和追踪财务情况。
在初始化时,需要配置账本名称、主货币等属性。
;【账本设置】
;功能:设置属性
;语法:option 属性名 值
option "title" "Joker's Ledger" ;设置账本名称
option "operating_currency" "CNY" ;账本主货币为人民币
1990-01-01 custom "fava-option" "language" "zh" ;可视化界面使用中文
在开始记账之前,必须开通好账户。
在Beancount中,账户是以树形结构组织的,支持多层级,以英文冒号:
分隔,如Assets:Bank:CMB:1234
,第一层必须是会计恒等式中的五个账户类型之一。
命名时可以采用银行的缩写、尾号、用途等信息,以便于识别和管理。
开户命令:
日期 open 账户名 货币类型
举栗:
2024-01-01 open Assets:Wechat:MiniFund CNY ;微信零钱通
yyyy-MM-dd
,开户日期需要在该账户第一笔交易之前,可以使用开始复式记账的前一天或者自己的生日。当然还有一些更有创意的选择::
分割成多个层级,合理利用层级可以让账户层次更清晰;第一层级只能使用Assets、Liabilities、Equity、Income、Expenses中的一个,因为Beancount需要根据这个字段区分账户的性质,以决定它们该出现在哪张报表中;第二层级必须以大写英文或数字开头,后面的层级就没有做限制了。,
分隔。;
作为注释符号。日常交易中涉及的账户,一定可以归于其中某一类。
合理开户的核心要素在于你想要追踪哪些东西
,比如你想看每个月吃了多少肯德基,你就可以专门开个费用账户叫做Expenses:KFC
,如果你完全不在意三餐的区别,开一个吃饭
(Expenses:Food)账户就足够了。
账户类型 | 说明 | 举栗 |
---|---|---|
资产(Assets) | 所有我的 | 流动资产:银行储蓄卡余额、微信零钱、零钱通、支付宝余额、余额宝等;固定资产:房子、车子等 |
费用(Expenses) | 花出去的 | 衣、食、住、行、娱乐、旅游等 |
负债(Liabilities) | 问别人借的 | 信用卡CreditCard、贷款Loan、花呗、京东白条、XX月付、房贷、车贷、借钱Payable等 |
所有者权益(Equity) | 老板投的钱 | 这个账户比较特殊,在账户初始化、误差处理等少数场合使用 |
收入(Income) | 赚的钱 | 工资Salary、投资收益Investments、副业收入Sideline、意外收入Gift、二手交易2ndTrade等 |
开户示例:
;资产账户
2024-01-01 open Assets:Bank:CMB:1234 CNY ;招商银行
2024-01-01 open Assets:Wechat:MiniFund CNY ;微信零钱通
;负债账户
2024-01-01 open Liabilities:Huabei CNY ;花呗
;费用账户
2024-01-01 open Expenses:Clothing CNY ;衣
2024-01-01 open Expenses:Food CNY ;食
2024-01-01 open Expenses:Housing CNY ;住
2024-01-01 open Expenses:Transportation CNY ;行
;收入账户
2024-01-01 open Income:Salary CNY ;工资
2024-01-01 open Income:Investments CNY ;投资收益
2024-01-01 open Income:Sideline CNY ;副业
; 所有者权益
2024-01-01 open Equity:OpenBalance CNY ;初始化账户余额
当我们开始记账时,一般资产和负债都不会是0,所以需要对资产和负债账户进行初始化。
初始化的命令格式和交易记录的命令一致,下文将会介绍交易记录。
举栗:
2024-01-02 * "账户余额初始化" "招商银行卡1234"
Assets:Bank:CMB:1234 300.00 CNY
Equity:OpenBalance -300.00 CNY
不要惧怕开户,对于一些短时间用的小账户,也可以开户,因为账户是可以关闭的,关闭后的账户不会出现在报表中,因此也不会触发你的强迫症。
销户命令:
日期 close 账户名
举栗:
1999-07-01 close Assets:Bank:CMB:1234
Beancount的交易记录主要包含日期和相关账户的资金流动(至少两个账户,可以涉及多个账户)。
命令格式:
日期 对账标志位 "交易方" "交易备注"
账户A 金额 货币
账户B 金额 货币
举栗:
;借方:费用增加,贷方:资产减少
2024-03-09 * "高德打车" "高德地图打车订单"
Expenses:Transport 84.68 CNY ;借方:交通费用增加
Assets:Bank:CMB:1234 -84.68 CNY ;贷方:资产减少
;借方:费用增加,贷方:资产减少,权益减少
2024-03-01 * "KFC" "10块钱买了一个吮指原味鸡"
Expenses:Food 10.00 CNY
Assets:Bank:CMB:1234 -7.00 CNY
Equity:Tickets:KFC -3.00 CNY ;假设有个3元的优惠券
;借方:资产增加,贷方:收入增加
2024-03-10 * "XXX公司" "2024年2月工资"
Assets:Bank:CMB:1234 3000.00 CNY
Income:Salary -3000.00 CNY
;借方:费用增加,贷方:负债增加
2024-02-04 * "铁路12306" "火车票"
Expenses:Transport 39.00 CNY
Liabilities:Huabei -39.00 CNY
其中:
*
号表示这笔交易是确定的,没有疑问,若是!
则表示存疑,但一般用不上
交易方和交易备注均可省略
货币必须与账本设置的主货币一致,若不一致会报错,如果是不同货币,可以使用@@
进行货币转换,比如:
2024-02-26 * "XXX" "转账备注:微信转账(兑换2500泰铢)"
Expenses:Travel 2500.00 THB @@ 511.00 CNY
Assets:Wechat:MiniFund -511.00 CNY
正号表示借方(正号可以省略),负号表示贷方
2024-03-09 * "高德打车" "高德地图打车订单"
Expenses:Transport 84.68 CNY ;借方:交通费用增加
Assets:Bank:CMB:1234 -84.68 CNY ;贷方:资产减少
支持单个账户的自动补全
2024-03-01 * "KFC" "10块钱买了一个吮指原味鸡"
Expenses:Food ;自动补全,会转化为 Food账户 +10.00 CNY
Assets:Bank:CMB:1234 -7.00 CNY
Equity:Tickets:KFC -3.00 CNY ;假设有个3元的优惠券
打标签
单个标签
,#
后面的内容是标签名称,在Fava上可以筛选标签,查看该标签下各个账户的收支
2024-03-01 * "XXX"
"XXX"
#Phuket
Expenses:Travel 300.00 CNY
Assets:Bank:CMB:1234 -300.00 CNY
标签堆栈
,堆栈中所有交易记录都会被自动打上标签,便于后期检索
;语法:pushtag #标签内容
; 交易记录1
; 交易记录2
; .........
; poptag #标签内容
pushtag #Phuket
...
2024-03-01 * ""
""
Expenses:Travel 300.00 CNY
Assets:Bank:CMB:1234 -300.00 CNY
...
poptag #Phuket
Beancount 可以使用多种通货,但好比不同货币有汇率,这些通货之间也有对应数量关系,即某个东西值多少钱,这就是单位通货和货币的汇率。
;功能:导入某个通货某日的价格
;语法:时间 price 通货 价格
2024-03-21 price GOLD 431.00 CNY
Fava的华丽 Web UI 已经能展现很多有用的财务报表,满足大部分用户的需求,如果用户需要进行一些更复杂的数据统计,比如「我 2023 年吃过的饭店按次数排列」,则可以使用 bean-query 工具用 SQL 语句进行查询,详见 Beancount 作者的文档:Beancount – Query Language。
这是一个用来统计光顾麦当劳次数的例子:
在生活中有些事件希望被记录,但这些事情可能与财务无直接关系,Beancount也支持记录,比如旅行、会议、生日、纪念日等。
命令:
日期 even "事件分类" "事件详情"
举栗:
2024-01-01 event "beancount" "开始使用beancount复式记账啦"
对于大额的转账类收入或支出,如果直接归到收入或支出,会导致统计图的比例被挤压。
这种情况也可以使用事件来解决,比如创建一个Equity:Exchange
账户负责转账记录,然后在事件中创建转账条目用以记录。
2024-02-12 * "XX转账5万元"
Assets:BankCard 50000.00 CNY
Equity:Exchange -50000.00 CNY
2024-02-12 event "转账" "XX转账5万元"
在使用一段时间后,发现Beancount在金额计算上因为浮点数非精确计算的性质,会出现0.01误差(在记录金额时建议保留两位小数,比如100.00,可以消除浮点误差)。如果已经有很多的金额没有保留两位小数,出现误差也不要慌,我的解决方案是创建一个Equity:Balance-Error
账户,定期对误差进行消除。
2024-03-21 * "消除账户浮点误差"
Equity:Balance-Error -0.01 CNY
Assets:BankCard 0.01 CNY
还有一些时间久了无法回溯的差额、四舍五入的误差,都可以使用Equity账户来处理。
解决方案是设置四个Equity账户用于处理不同场景的误差:
Equity:OpenBalance 用于初始化
Equity:HistoryIncome 开始复式记账前的部分收入
Equity:Round 四舍五入操作
Equity:UFO 无法追溯的差额
一本维护良好的账本应该定期做断言(assertion)
。
前面说到复式记账最大的优势是不仅仅记录收入和支出,同时还会记录资产负债,Beancount中可以通过balance
命令实现账户核对,标记某个日期某个账户(资产Assets账户或负债账户Liabilities)里还有多少豆子。
;资产
2024-02-01 balance Assets:Bank:CMB:1234 100.00 CNY
;负债
2024-02-01 balance Liabilities:Huabei -1000.00 CNY
断言语句告诉 Beancount,某个账户在某个日期凌晨 00:00:00 时间点(也就是前一天深夜 23:59:59 的下一秒),余额为某个数字。如果历史交易记录无误,计算出来的金额就会与预期一致,若不一致,则Beancount就会报错提示。
Beancount 的时间精度是日
,所以诸如 open, close, balance 等带日期的语句,均发生在当日的第一笔交易之前,你可以想像它们都是在凌晨 00:00:00 时间点发生的,而普通的交易都是发生在白天。因此,要断言一月份的余额,日期应写作 02-01 而不是 01-31。
理想情况下,进行断言的频率应该是每月或每半个月一次,这样可以及时发现并纠正可能存在的错误。
说到这里,我们已经介绍了Beancount的基本使用方法。如果你想了解更多关于Beancount的语法规则和更广泛的应用场景,建议参考官方文档:
虽然我们现在可以开始进行记账了。
但是,问题来了,每次都需要手动录入交易信息,对于我这种懒人来说,想想就很痛苦。
所以,本着“能坐着就不站着,能躺着就不坐着
”的原则,自动记账
这件事势在必行。
如何自动记账?
我的方案是:
快速随时
记账。通过这种方式,我们可以实现自动或半自动记账。关于账单的自动导入和解析,将在下一篇文章中进行介绍。
以上,完。
脚踏实地,仰望星空,和坨坨一起学习软件测试,升职加薪!