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.