beancount记账

发布于:2025-02-11 ⋅ 阅读:(50) ⋅ 点赞:(0)

之前在安卓用「那样记账」记账,换 iPhone 后发觉在 App Store 没有,想找一款跨平台的记账软件,期望功能:

  • 记账
  • (分类、分层的)统计图示
  • 同步

找到 beancount [1],想起是之前 BYVoid 推荐过 [4]。本篇做入门简介,更详细的介绍见 beancount 的文档 [2] 和 BYVoid 的系列网志 [4]。

Beancount

beancount 属于纯文本记账 [5] 的工具之一,即所有收支记录都记在文本文件里,扩展名 .bean 或 .beancount,配有几款主流编辑器的高亮支持 [6]

由于是文本文件,则可以用 git 同步。目前主要是在电脑用。手机端有个支持安卓和 iphone 的 beancount-mobile [7,8],还未认真研究过。

Single-entry vs. Double-entry Counting

beancount 的记账模式是复式记账(double-entry counting);相对地,多数普通记账软件(如那样记账)的记账模式应该是单式(single-entry counting)。

复式记账是专业的记账法,不过目前记的都是日常消费,单、复式于我只是形式不同,对复式的强大无甚体会。从形式上看:

  • 「那样记账」将帐分成三类:收入、支出、转帐。对前两类,只涉及一个账户,即钱从那个帐户出、或入哪个账户,再加个标记用于统计图示。转帐就涉及两个账户,同复式。
  • 复式记账将所有帐都记为转帐。每笔转帐至少涉及两个账户,也可以多个,分成两方:支出(debit)、收入(credit)方。这可能就是 double 的含义。

example

此处举一例对比「那样记账」和 beancount 的记法差异:

2025.1.5 在 Cotti Coffee 花 12.07 人民币买了一杯抹茶生椰拿铁,刷中国银行的卡。

若用「那样记账」记,这属于支出帐,所以在软件「支出」页面,点个「饮料」标签(预先创建的标签),输入时间、金额,帐户选中国银行卡(也是预先创建的账户),就完成记录。

若用 beancount 记,涉及两个账户:

  • 中国银行卡
  • 饮料

买奶茶就记为「中国银行」账户给「饮料」账户转了 12.07 元,在文件中写作:

2025-01-05 * "Cotti Coffee" "抹茶生椰拿鐵"
    Expenses:Drinks                    12.07 CNY
    Assets:Checking:BoC               -12.07 CNY

其中 Expenses:DrinksAssets:Checking:BoC 是在别处定义的账户,此处省去。账户名是分层的,方便之后分层统计。也有打标签的语法,详见 [2,4]。「饮料」账户是一种抽象:因为这笔钱肯定是转到 Cotti Coffee 店铺的账户上去,只不过我们并不关注具体是打到哪间铺的哪个账户,而是将所有的卖饮料的店舖账户都抽象成一个 Expenses:Drinks,这顺便也承担消费归类的功能。

第二、三行的金额可以省写其中一项,因为每笔转帐的数值和必须是零,理论基础是会计恒等式 [2,4]

Multi-file Accounting & Project Management

beancount 支持将帐分写在多个 .bean 文件内,于是可以当成一个项目用 git 管理。例如统一放到 my_accounting/ 文件夹中:

my_accounting/
|- main.bean
|- accounts.bean
`- books/
   |- 2024-12.bean
   `- 2025-01.bean

此例从 2024 年 12 月开始用 beancount 记账,每个文件记一个月的帐,另有:

  • main.bean:导入所有其它文件,方便后续统计图示;
  • accounts.bean:定义账户,即开户。

accounts.bean

接上文举的例,定义两个账户:

  • .bean 文件用 ; 注释一行
  • 开户时间可以早些,只要保证早于第一次转帐就行,不用纠结真实的开户时间。
; accounts.bean

; 指定使用的货币,任意多条
option "operating_currency" "CNY"
; option "operating_currency" "USD"

; 定义账户
2024-11-01 open Expenses:Drinks    CNY
2024-11-01 open Assets:Checking:BoC    CNY

main.bean

此文件就导入所有其余 .bean 文件:

; main.bean
option "title" "iTom's Ledger"

; 导入开户信息
include "accounts.bean"

; 导入帐簿
include "books/2024-12.bean"
include "books/2025-01.bean"

数簿多了之后,手写 main.bean 有些麻烦。可以用脚本自动生成 main.bean,如:

@echo off
setlocal enabledelayedexpansion

echo Create main.bean, importing books.

set mainf=main.bean

@REM 创建 main.bean
echo ; main.bean> %mainf%
echo option "title" "iTom's Ledger">> %mainf%
@REM 导入开户文件
echo include "accounts.bean">> %mainf%
@REM 递归导入 books/ 内数簿
echo ; books>> %mainf%
call :import_books books

goto :eof

:import_books
    for %%f in (%~1\*.*) do (
        set ext=%%~xf

        @REM convert path separator: \ to /
        set cvtf=%%f
        set cvtf=!cvtf:\=/!

        if "!ext!" == ".bean" (
            echo include "!cvtf!">> %mainf%
        ) else if "!ext!" == ".beancount" (
            echo include "!cvtf!">> %mainf%
        )
    )

    for /d %%d in (%~1\*) do (
        call :import_books %%d
    )
exit /b

Visualisation

可以用 fava [3] 生成网页版统计图示:

fava main.bean

然后浏览器打开提示的网址,一般是 http://127.0.0.1:5000

References

  1. beancount/beancount
  2. Getting Started with Beancount
  3. beancount/fava
  4. Beancount複式記賬(一):爲什麼
  5. Plain Text Accounting (PTA)
  6. editor-support
  7. Beancount.io
  8. beancount-mobile

网站公告

今日签到

点亮在社区的每一天
去签到