利用 GnuCash Python Bindings 將記帳資料寫入GnuCash 檔案

作者: Yong-Siang Shih / Sun 30 August 2020 / 分類: Projects

GnuCash

問題

一直以來都是使用 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 了。未來再看情形重新評估看看。

Cash
Yong-Siang Shih

作者

Yong-Siang Shih

軟體工程師,機器學習科學家,開放原始碼愛好者。曾在 Appier 從事機器學習系統開發,也曾在 Google, IBM, Microsoft 擔任軟體實習生。喜好探索學習新科技。* 在 GitHub 上追蹤我

載入 Disqus 評論