beancount, fava学习使用的补充
这几日放假在家,看到了beancount复式记账的教程,总感觉好像找到了一直想要做,但是又因各种拖延症耽搁下来的记账模式。于是好好地看了网上的帖子,觉得处理起来还成,对于有初级会计基本知识的人来说,上手很快;对于没有的人来说,依样画葫芦,也是可以学得到的。
我使用过程中也遇见了各种问题和需求,我这里记下我已经解决的部分,希望在使用过程中,做到干中学。
什么是beancount?为什么要用?
请各位看这位博主写的文章,非常详细介绍了复式记账的概念。我的感觉是,用了会上瘾。
beancount是底层会计系统寄出,fava则是其对应的图形化界面。设置好fava后,基本记录就在里面进行就好了。
我的需求
希望可以用docker compose, 希望可以多账本切换。网上的教程都是使用python,pip来安装,挺好的。但是碰到迁移,就提现出docker的优势。我所有的微服务都是用docker来配置,不能使用的情况,就寻找alternative。
docker-compose 安装 fava dock
网上的dock已经有了基本的功能实现,但是没有账本切换功能。我找了一个实现功能较全的dock,然后对Dockerfile进行了修改。我只摘取了修改部分,使用时候还是需要全部都拷贝的。
ENV BEANCOUNT_INPUT_FILE ""
ENV PYTHONPATH "/myData/myTools"
ENV FAVA_OPTIONS "-H 0.0.0.0"
CMD cron && fava ${FAVA_OPTIONS} ${BEANCOUNT_INPUT_FILE}
------------------改为---------------------
ENV BEANCOUNT_INPUT_FILE ""
ENV BEANCOUNT_INPUT_FILE_1 ""
ENV BEANCOUNT_INPUT_FILE_2 ""
ENV PYTHONPATH "/myData/myTools"
ENV FAVA_OPTIONS "-H 0.0.0.0"
CMD cron && fava ${FAVA_OPTIONS} ${BEANCOUNT_INPUT_FILE} ${BEANCOUNT_INPUT_FILE_1} ${BEANCOUNT_INPUT_FILE_2}
##在你的服务器中进行设置,假设你已经按照好了docker-compose
mkdir docker
git clone https://github.com/grostim/fava-docker.git
cd fava-docker && vi Dockerfile #插入更换上面修改代码,这样可以实现多账簿切换
docker build -t fava-docker . #生成docker image name fava-docker
vi docker-compose.yml
docker-compose up -d #运行后,就可以在localhost:15003访问到beancount fava的界面了。
------docker-compose.yml--------
version: "3.7"
services:
fava:
image: fava-docker:latest
container_name: beancount
environment:
- BEANCOUNT_INPUT_FILE=/input.beancount
- BEANCOUNT_INPUT_FILE_1=/input.1.beancount
# - BEANCOUNT_FILE_2=/input.2.beancount ##我只切换两个账户,就只用两个
volumes:
- /mnt/nas/Dropbox/Apps/beancount/trade/main.beancount:/input.1.beancount #账簿和dropbox相连,可以进行版本控制
- /mnt/nas/Dropbox/Apps/beancount/expense/main.beancount:/input.beancount
ports:
- 15003:5000 #端口自设,docker内部是5000
restart: always
networks:
- traefik
networks:
traefik:
driver: bridge
-----------------以上为docker-compose.yml------------------
实际要远程访问的话,还需要其他的知识,比如用traefik,nginx,frp,根据个人实际情况来设置。
设置好后,就可以看见在网页左上角就有了可以变换账簿的选择。非docker安装的情况,这个很容易实现。但是docker下要实现,就只能自己build image。
其他使用的技巧,其实搜一搜都能找到。而且这个使用的特点是,一旦用了之后,就留下记录,很难忘记,如同学自行车一般。
ref link 推荐:https://awesome-beancount.com/
其他笔记和记录
https://zhuanlan.zhihu.com/p/87377967 这里文件分类整理的非常好
默认目录(0-default):日常支出,每月一个文件。
证券投资(1-securities):股票和基金买卖记录。
旅行出差(2-trip):旅行出差的账本
周期性账(3-cycle):包括每月还信用卡、交水电费放在这里。
项目目录(4-project):比如装修房子
最1层:main.bean作为主账本,include各个账户文件及每年账本文件。 第2层:每年有个目录,下设年份.bean的文件,include各个子目录下00.bean文件。 第3层:每个子目录下00.bean文件include该目录下所有正式的记账文件
;==main文件==
;【一、账本设置】
option "title" "我的账本"
option "operating_currency" "CNY"
1990-01-01 custom "fava-option" "language" "zh"
;【二、账户设置】
include "accounts/assets.bean" ;资产账户设置及初始化
include "accounts/liabilities.bean" ;负债账户设置及初始化
include "accounts/expenses.bean" ;支出账户设置
include "accounts/income.bean" ;收入账户设置
include "accounts/equity.bean" ;权益账户设置
;【三、交易记录】
include "2018/2018.bean" ;历史账本合集
include "2019/2019.bean" ;2019年账本合集
Equity:OpenBalance 用于初始化
Equity:HistoryIncome 开始复式记账(2019-07-01)前的部分收入
Equity:Round 四舍五入操作
Equity:UFO 无法追溯的差额
https://xwartz.xyz/blog/beancount-best-practice/
如何进行汇率换算
2019-05-01 * "Huobi" "Buy 1000 USDT"
Assets:DemandDeposit:YuEBao -7000.00 CNY
Assets:DigitalCy:USDT 1000.00 USDT {7 CNY} @@ 7000.00 CNY
如何在open中加入设定 usd hkd,但是不一定需要,因为有时候我需要把他们全部变成cny来看总资产
1900-01-01 open Assets:Cash:FSM USD,HKD
给出了目录结构
在 2019-05-01 开始使用 Beancount,目前有港币现金 23000,招商银行余额 50000
; 现金
2019-05-01 pad Assets:Cash:HKD Equity:Opening-Balances
2019-05-01 balance Assets:Cash:HKD 23000.00 HKD
2019-05-01 pad Assets:Cash:Bank:CMB Equity:Opening-Balances
2019-05-01 balance Assets:Cash:Bank:CMB 50000.00 CNY
这样,在 2019-05-01 之前的数据变化不会影响账户余额了,而 2019-05-01 之后发生的交易可以使用 Beancount 正常记录
https://wzyboy.im/post/1063.html
定期断言
一本维护良好的账本应当定期做断言(assertion),标记在某个日期某个账户(通常是 Assets 或 Liabilities 账户)里有多少豆子。
Beancount 便会检查那个账户的数字是否与断言的数字相等,如果不相等就会报错。
2016-02-01 balance Assets:Cash 100.00 USD
Beancount 另一个有趣的功能是填充(padding),填充是配合断言一起用的,当 Beancount 解析到填充语句时,会自动在这条语句和下一条断言语句之间插入一条填充交易,使得断言成功。在填充语句所在日期和断言语句所在日期之间不能再有其他交易。
2015-11-30 pad Assets:Cash Expenses:Food:Drinks
2015-12-01 balance Assets:Cash 200.00 CNY
小红 11 月底做账目核对的时候,发现钱包里的现金是 200 元,但是根据 10 月底的余额,以及 11 月的交易记录,钱包里应该剩 200 多元才对,她想了下,可能是有几次在路边买了饮料喝忘记记录了,因此她使用填充功能来解决这个问题,在 11 月最后一笔交易和 12-01 的断言之间插入一条 pad 语句,这样 Beancount 便会自动插入一条交易,使 Assets:Cash 里的余额调整为 200.00 CNY,而因此产生的货币变化,则记录到 Expenses:Food:Drinks 账户里。
用法是从 时间1 到 时间2 期间 账户1 的余额是 banlance 指明的值,差值算到 账户2 内。
时间1 pad 账户1 账户2
时间2 balance 账户1 金额1 货币
我们初始化账户可以把 时间1 设置为生日, 时间2 设置为当前,这样表示之前帐目的都用 Opening-Balances 先抹平,如果我们之前有记录的内容,直接补充进去就好了, pad 会自己更新
https://wzyboy.im/post/1317.html
2018-08-30 * "Sell 3 AMZN" 单价
Assets:Trade:Positions -3 AMZN {1000.00 USD} @ 2000.00 USD
Assets:Trade:Cash 6000.00 USD
Income:Trade:PnL -3000.00 USD
; 总价
2018-08-30 * "Sell 3 AMZN"
Assets:Trade:Positions -3 AMZN {1000.00 USD} @@ 6000.00 USD
Assets:Trade:Cash 6000.00 USD
Income:Trade:PnL -3000.00 USD
为什么要带上 {1000.00 USD}?为什么有个 PnL?为什么交易看起来不平(总和不是零)?下文详解。
你可以改用 FIFO 簿记方法:
1970-01-01 open Assets:Trade:Positions "FIFO"
2017-07-14 * "Buy 10 AMZN"
Assets:Trade:Cash
Assets:Trade:Positions 10 AMZN {1000.00 USD}
2018-08-30 * "Sell 3 AMZN"
Assets:Trade:Positions -3 AMZN {}
Assets:Trade:Cash 6000.00 USD
Income:Trade:PnL
Expenses:Trade:Commissions +10 USD
剩下会自动补齐
花钱,expense是正数
PnL为何在这里是负数
分红与赠股 income这里是负数吗
2018-03-09 * "DIVIDEND: MICROSOFT CORP"
Income:Trade:Dividend
Assets:Trade:Cash 3.36 USD
2017-06-05 * "Spin off: 1 WB for 10 SINA"
Income:Trade:Dividend
Assets:Trade:Positions 2 WB {71.94 USD}
在 Fava 中默认不显示 Unrealized PnL 产生的交易,可点击「X」按钮显示出来,也可通过选项来更改默认显示的交易类型。点击market value,也能显示PnL如:
1970-01-01 custom "fava-option" "journal-show-transaction" "pending cleared other"
Beancount 支持维护一个价格数据库。Beancount 的核心功能不会用到这些数据,但是有些插件会,比如计算浮动盈亏(Unrealized PnL)。我写了一个简单的脚本,可以从 Beancount 文件读取你所有的持仓,然后从 IEX 的 API 抓取这些股票的过去一年里每天的收盘价并输出到屏幕。我现在工作流是,有个专门的文件用来保存价格数据库,每月整理账本的时候做一次更新,然后在 Vim 里 :sort u 做一次去重。
average 库存:https://bitbucket.org/blais/beancount/src/c21adfcd90abf4b6b0aed8119530f143c9a5024d/beancount/parser/booking_method.py#lines-173:243
USD如何显示后两位小数点 option "render_commas" "true"
balance 语句后面只能是账户、数量、货币三个参数,不能再加 cost 信息的。如果有可能的话,建议还是找到这些持仓的购买信息(应该有结单吧?),然后把它们完整录入,这样有助于 Beancount 帮你计算正确的盈亏(在报税的时候需要)。如果找不到的话,可以这样:
2019-06-22 * "Opening Balances"
Equity:OpenBalance
Assets:Broker:Pingan:Positions 6700.00 CN_002739 {19.30 CNY, 2019-01-01}
其中 2019-01-01 就是你指定的购买日期,19.30 CNY 是那天的价格。
https://gitpress.io/c/beancount-tutorial/beancount-tutorial-3
一次普通的消费,在 Beancount 中一般记录成:
2019-04-05 * "支付宝" "上海喜士多便利连锁有限…, 零食"
Liabilities:SPDB -5.4 CNY ; SPDB 是浦发银行简称
Expenses:Food:Snack +5.4 CNY
可以看到,使用信用卡购买 ¥5.4 零食,是从 Liabilities (负债)中减去 5.4,然后加到了 Expenses:Food:Snack (零食) 中。
如果是还款,则这样记录:
2019-04-08 * "银行还款"
Assets:Cash -8289.89 CNY
Liabilities:SPDB +8289.89 CNY
使用现金还清了 8289.89 元欠款。
导入信用卡记录的方法在这里也介绍了
就是用python的方式对excel csv进行格式变换,有记录的直接变成beancount接受的方式
https://gitpress.io/c/beancount-tutorial/beancount-cheat-sheet
2015-05-30 ! "Cable Co" "Phone Bill" #tag ˆlink
id: "TW378743437" ; Meta-data
Expenses:Home:Phone 87.45 USD
Assets:Checking ; You may leave one amount out
省略了一个,加了一个id
... 123.45 USD Simple
... 10 GOOG {502.12 USD} With per-unit cost
... 10 GOOG {{5021.20 USD}} With total cost
... 10 GOOG {502.12 # 9.95 USD} With both costs
... 1000.00 USD @ 1.10 CAD With per-unit price
... 10 GOOG {502.12 USD} @ 1.10 CAD With cost & price
... 10 GOOG {502.12 USD, 2014-05-12} With date
! ... 123.45 USD ... With flag
https://www.byvoid.com/zht/blog/beancount-bookkeeping-2
2019-01-01 * "日本航空" "紐約-東京"
Expenses:Transport:Airline 1000 USD
Liabilities:CreditCard:US:Discover -1000 USD
這個例子表示我在日本航空購買了紐約-東京的機票,消費1000美元(貸記),付款的信用卡Discover扣款1000美元(借記)。
所有Expenses類別的賬戶都是正數,所有Income類別的賬戶都是負數。這是Beancount及類似工具使用正數來表示借記(Debit),負數表示貸記(Credit)的結果。同理,通常Assets類是正數,Liabilities類是負數。本質上每個賬戶的數值只有絕對值有意義,正負號並沒有實際含義。
外汇转换
方法1
2019-01-01 * "日本航空" "紐約-東京"
Expenses:Transport:Airline 1000 USD @ 110 JPY
Liabilities:CreditCard:JP:Rakuten -110000 JPY
方法2
2019-01-01 * "日本航空" "紐約-東京"
Expenses:Transport:Airline 1000 USD @@ 110000 JPY
Liabilities:CreditCard:JP:Rakuten -110000 JPY
方法3
2019-01-01 * "日本航空" "購買里程"
Assets:Points:Airline:JAL 10000 P_JAL @ 2.5 JPY
Liabilities:CreditCard:US:Discover -220.0 USD @@ 25000 JPY
AA管理
发生
2019-05-25 * "猿島" "渡輪"
Expenses:Transport:Ferry 1300 JPY ; 個人渡輪費用
Assets:Receivables:X 1300 JPY ; 對X應收賬款
Assets:Receivables:Y 1300 JPY ; 對Y應收賬款
Liabilities:CreditCard:JP:Rakuten -3900 JPY
2019-05-25 * "猿島" "登島費"
Expenses:Transport:Attraction 200 JPY ; 登島費
Liabilities:Payable:X -200 JPY ; 欠X的錢
结算
2019-05-26 * "猿島" "費用結算"
Assets:Receivables:X -1300 JPY ; X償還債務
Liabilities:Payable:X 200 JPY ; 償還對X的債務
Assets:Cash:JPY 1100 JPY ; X實際付給我的錢到賬
Assets:Receivables:Y -1300 JPY ; Y償還債務
Assets:Bank:JP:SMBC:JPY 1300 JPY ; Y實際付給我的錢到賬
記錄對他人的債權(應收賬款)和欠他人的債務(應付賬款),我分別使用了Assets:Receivables和Liabilities:Payable下面的賬戶。
https://www.byvoid.com/zht/blog/beancount-bookkeeping-3
结余调整
2015-01-01 * "賬戶初始"
Assets:US:BofA:Checking 3490.52 USD
Equity:Opening-Balances -3490.52 USD
另一种
2015-01-01 pad Assets:US:BofA:Checking Equity:Opening-Balances
2015-01-02 balance Assets:US:BofA:Checking 3490.52 USD
标签
2019-06-01 * "奧地利航空" "東京-維也納" #2019-07-Europe-Trip
Expenses:Transport:Airline 600 USD
Liabilities:US:CreditCard:Citi
另一种,两个tag之间直接标记tag 標籤堆棧和文件包含是不能組合使用的,也就是說標籤堆棧內的include的文件不會自動加上標籤。建议用上一种方式
pushtag #2019-07-Europe-Trip
2019-06-01 * "奧地利航空" "東京-維也納"
Expenses:Transport:Airline 600 USD
Liabilities:US:CreditCard:Citi
2019-06-01 * "奧地利航空" "維也納-莫斯科"
Expenses:Transport:Airline 100 USD
Liabilities:US:CreditCard:Citi
poptag #2019-07-Europe-Trip
账户使用原则
如果該收支屬於一個特別的事件,那麼就將其加入這個事件對應的單獨文件,例如#2019-07-Europe-Trip。
如果該收支是一個週期項目,但跟某個銀行賬戶無關,則加入按類別劃分的文件,例如水電費、房租、工資。
如果該收支跟某個銀行賬戶緊密相關,則加入該賬戶對應的文化,例如銀行手續費、信用卡還款、返現。
不屬於以上情況,則加入按日期劃分的文件
添加 外部plugin 到docker中
/mnt/nas/Dropbox/Apps/beancount/ref/plugin/amortize_over.py:/usr/local/lib/python3.8/site-packages/amortize_over.py
plugin "amortize_over"
用pad功能时候,前后日期要不一样