Importing Stock Transactions Into Gnucash With Python
Posted on Sun 21 June 2020 in hints
I use GnuCash, but keeping my 401(k) accounts up to date has always been a tedious, manual process.
I came up with the python snippet below to handle the import, but it was a pain to write since I couldn't find any examples for setting up stock or mutual fund transactions.
The SetSharePriceAndAmount method ended up being key, and I only found that by searching through the gnucash source.
The GncNumeric class also ended up being more of a pain to use than I expected. There's probably a better way to use it, but the 'multiple values by 1000000/100000' approach is working for me now.
I'm using the stock GnuCash and python-gnucash version 2.6.19 available in Ubuntu 18.04, so this stuck using python 2.7.
#!/usr/bin/python2.7
import csv
from datetime import datetime
import gnucash
session = gnucash.Session("xml://yourfile.gnucash")
book = session.book
root_account = book.get_root_account()
usd = book.get_table().lookup('ISO4217','USD')
# There's probably a better way to use 'Your:Retirement:Contributions' instead ....
contrib_acct = root_account.lookup_by_name("Your").lookup_by_name("Retirement").lookup_by_name("Contributions")
parent_acct = root_account.lookup_by_name("401k")
with open('your_transactions.csv', 'rb') as trans_csv:
trans_reader = csv.reader(trans_csv, delimiter=',')
# Skip over the first row since it's headers
header = next(trans_reader)
for description, date, fund_name, share_price_str, share_amount_str, amount_str in trans_reader:
child_account = parent_acct.lookup_by_name(fund_name)
posting_date = datetime.strptime(date,"%m/%d/%y")
tx = gnucash.Transaction(book)
tx.BeginEdit()
tx.SetCurrency(usd)
tx.SetDatePostedTS(posting_date)
tx.SetDescription(description)
sp1 = gnucash.Split(book)
sp1.SetParent(tx)
sp1.SetAccount(child_account)
# GncNumeric(n,d) represents numbers as fractions of the form n/d, so GncNumeric(1234567/1000000) = 1.234567
# There's probably a better way to do this...
share_price = gnucash.GncNumeric(float(share_price_str)*(10**6), 10**6)
share_amount = gnucash.GncNumeric(float(share_amount_str)*(10**6), 10**6)
# share_price * share_amount == amount, so I could have used that instead using the value from the csv
amount = gnucash.GncNumeric(float(amount_str)*(10**6), 10**6)
# ( ˘▽˘)っ♨ This is the secret sauce for setting the number of shares and the price.
sp1.SetSharePriceAndAmount(share_price, share_amount)
sp2 = gnucash.Split(book)
sp2.SetParent(tx)
sp2.SetAccount(contrib_acct)
sp2.SetValue(amount.neg())
tx.CommitEdit()
session.save()
session.end()
Special thanks to this post for providing most of the code above.