問題
一直以來都是使用 GnuCash 作為記帳工具,雖然有自動補完的功能,但各種紀錄還是得手動的輸入。消費的部份因為簡單所以每週偶爾記記還算可行,但券商、銀行裡的各種複雜交易如果都手動輸入感覺就相當花時間了。(其實一方面也是因為不會每週都記錄券商交易,而是累積起來一次輸入,所以心理上感覺比較繁雜。)所以最近研究了一下 GnuCash 的自動匯入功能,發現當中有許多不太彈性的地方,除此之外,匯入速度不知為何十分緩慢,讓人不禁覺得自己手動輸入搞不好還比較快。
為了解決這個問題,就來研究了一下 GnuCash 的 Python bindings 尋找能夠自動輸入大量交易的方法。最後在一番研究之後,參考了 GnuCash 裡頭的 example scripts,寫了一個簡單的 gnucash-importer。
GnuCash Importer
gnucash-importer 的功能是可以讀取 CSV 格式的記帳檔案,然後把裡頭的資料寫進 GnuCash 的檔案之中。使用這個工具作為輸入的手段的話,就能先將想插入的資料轉換成 CSV 格式,然後再透過 gnucash-importer 寫入 GnuCash 之中。
比如說如果先將股票帳戶的資料透過某種方法轉換成如下的格式:
date,description,commodity,memo,account,amount,value
09/24/2020,Purchase VTI,CURRENCY::USD,,Assets:Current Assets:Cash Account:TD Ameritrade,,-2500.00
,,,,Assets:Investments:Stock:VTI,10,2500.00
09/07/2020,BND Dividend,CURRENCY::USD,,Assets:Current Assets:Cash Account:TD Ameritrade,,70.00
,,,,Income:Dividend Income:Dividend Income USD:BND Dividend,,-100.00
,,,,Assets:Investments:Bond:BND,,
,,,W-8 Tax Withholding - BND,Expenses:Taxes:Federal:Taxes Withholding:Taxes Withholding USD:2020 Taxes Withholding USD,,30.00
然後再利用 gnucash-importer 來插入資料:
python -m gnucash_importer target.gnucash source.csv
就可以自動插入一筆購買 10 shares of VTI 的紀錄,和一筆得到 BND 的利息的紀錄。
所以說只要另外寫一些程式,把平常的帳戶資料先轉成這個格式的 CSV,就能簡單的匯入 GnuCash 之中了。
說穿了其實核心部份只是利用了簡單的 API:
import gnucash
DAY = 24
MONTH = 9
YEAR = 2020
DESCRIPTION = 'Purchase VTI'
ACCOUNT = 'Assets:Current Assets:Cash Account:TD Ameritrade'
VTI_ACCOUNT = 'Assets:Investments:Stock:VTI'
def lookup_account(root_account, account_path):
names = account_path.split(':')
account = root_account
for name in names:
account = account.lookup_by_name(name)
return account
with gnucash.Session(
gnucash_path,
gnucash.SessionOpenMode.SESSION_NORMAL_OPEN) as session:
book = session.book
comm_table = book.get_table()
commodity = comm_table.lookup('CURRENCY', 'USD')
# 指定幣種和基本敘述
trans = gnucash.Transaction(book)
trans.BeginEdit()
trans.SetDate(DAY, MONTH, YEAR)
trans.SetCurrency(commodity)
trans.SetDescription(DESCRIPTION)
# 紀錄從現金帳戶花去 -2500
split = gnucash.Split(book)
split.SetValue(gnucash.GncNumeric(-2500))
root_acct = book.get_root_account()
acct = lookup_account(root_acct, ACCOUNT)
split.SetAccount(acct)
split.SetParent(trans)
# 紀錄 VTI 持有增加 $2500 = 10 shares
vti_split = gnucash.Split(book)
vti_split.SetValue(gnucash.GncNumeric(2500))
vti_split.SetAmount(gnucash.GncNumeric(10))
vti_acct = lookup_account(root_acct, VTI_ACCOUNT)
vti_split.SetAccount(vti_acct)
vti_split.SetParent(trans)
trans.CommitEdit()
其他可能性
其實之所以突然想來寫個 importer ,還有一個原因是先前看過別人用 beancount 記帳的心得,對於像那樣直接用純文字記帳的方法感到有點興趣。由於是純文字,很有彈性,要寫各種 importer 當然也不成問題。實際上官方好像就有提供各種 importers 來使用的樣子。
但因為太習慣 GnuCash 有各種自動完成,以及各種方便顯示的圖表了,所以目前還在觀望之中。乍看之下如果使用 fava 的話,雖然可以顯示一些基本的圖表,但跟 GnuCash 比起來還是有點距離。雖然因為很有彈性,所以理論上可以寫各種擴充套件,甚至搞不好早就有人寫好了強大的圖表套件。但一直還沒時間研究,所以只好暫時繼續使用 GnuCash 了。未來再看情形重新評估看看。