Occassional (well very rare really) update
[pwan.org.git] / content / hints / gnucash-stock-import.rst
1 Importing Stock Transactions Into Gnucash With Python
2 #####################################################
3
4 :date: 2020-06-21
5 :tags: hint, python, gnucash
6 :category: hints
7 :author: Jude N
8
9 I use GnuCash, but keeping my 401(k) accounts up to date has always been a tedious, manual process.
10
11 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.
12
13 The `SetSharePriceAndAmount`_ method ended up being key, and I only found that by searching through the gnucash source.
14
15 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.
16
17 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.
18
19 .. code-block:: python
20
21 #!/usr/bin/python2.7
22
23 import csv
24 from datetime import datetime
25
26 import gnucash
27
28 session = gnucash.Session("xml://yourfile.gnucash")
29 book = session.book
30 root_account = book.get_root_account()
31
32 usd = book.get_table().lookup('ISO4217','USD')
33
34 # There's probably a better way to use 'Your:Retirement:Contributions' instead ....
35 contrib_acct = root_account.lookup_by_name("Your").lookup_by_name("Retirement").lookup_by_name("Contributions")
36
37 parent_acct = root_account.lookup_by_name("401k")
38
39 with open('your_transactions.csv', 'rb') as trans_csv:
40 trans_reader = csv.reader(trans_csv, delimiter=',')
41
42 # Skip over the first row since it's headers
43 header = next(trans_reader)
44
45 for description, date, fund_name, share_price_str, share_amount_str, amount_str in trans_reader:
46 child_account = parent_acct.lookup_by_name(fund_name)
47
48 posting_date = datetime.strptime(date,"%m/%d/%y")
49
50 tx = gnucash.Transaction(book)
51 tx.BeginEdit()
52
53 tx.SetCurrency(usd)
54
55 tx.SetDatePostedTS(posting_date)
56 tx.SetDescription(description)
57
58 sp1 = gnucash.Split(book)
59 sp1.SetParent(tx)
60 sp1.SetAccount(child_account)
61
62 # GncNumeric(n,d) represents numbers as fractions of the form n/d, so GncNumeric(1234567/1000000) = 1.234567
63 # There's probably a better way to do this...
64 share_price = gnucash.GncNumeric(float(share_price_str)*(10**6), 10**6)
65 share_amount = gnucash.GncNumeric(float(share_amount_str)*(10**6), 10**6)
66
67 # share_price * share_amount == amount, so I could have used that instead using the value from the csv
68 amount = gnucash.GncNumeric(float(amount_str)*(10**6), 10**6)
69
70 # ( ˘▽˘)っ♨ This is the secret sauce for setting the number of shares and the price.
71 sp1.SetSharePriceAndAmount(share_price, share_amount)
72
73 sp2 = gnucash.Split(book)
74 sp2.SetParent(tx)
75 sp2.SetAccount(contrib_acct)
76 sp2.SetValue(amount.neg())
77
78 tx.CommitEdit()
79 session.save()
80 session.end()
81
82
83 Special thanks to `this post`_ for providing most of the code above.
84
85 .. _this post: https://www.edureka.co/community/18845/how-to-create-transaction-in-gnucash-in-response-to-an-email
86 .. _SetSharePriceAndAmount: https://github.com/Gnucash/gnucash/blob/2.6.19/src/engine/Split.c#L980
87
88