--- /dev/null
+Importing Stock Transactions Into Gnucash With Python
+#####################################################
+
+:date: 2020-06-21
+:tags: hint, python, gnucash
+:category: hints
+:author: Jude N
+
+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.
+
+.. code-block:: python
+
+ #!/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.
+
+.. _this post: https://www.edureka.co/community/18845/how-to-create-transaction-in-gnucash-in-response-to-an-email
+.. _SetSharePriceAndAmount: https://github.com/Gnucash/gnucash/blob/2.6.19/src/engine/Split.c#L980
+
+