Master post - Eoddata.com web service blog series

Sat 25 March 2017 by Adrian Torrie

This post is part 1 of the "Using Python with Eoddata.com web service" series:

  1. Master post - Eoddata.com web service blog series
  2. Login() - Eoddata.com web service blog series
  3. ExchangeList() - Eoddata.com web service blog series
  4. CountryList() - Eoddata.com web service blog series
  5. SymbolList() - Eoddata.com web service blog series
  6. FundamentalList() - Eoddata.com web service blog series

Summary

  • Master post for the blog series that holds all the links related to making web service calls to Eoddata.com. Overview of the web service can be found here
  • Download the class definition file for an easy to use client, which is demonstrated below
  • This post shows you how to create a secure credentials file to hold the username and password so you don't have to keep entering it, and will allow for automation later.
  • A quick overview is given below of establishing a session using the requests module, and parsing the xml response using xml.etree.cElementTree. Then a quick inspection of the objects created follows.

The following links were used to help get these things working.

Version Control

In [2]:
%run ../../code/version_check.py
Python: 3.5.3 |Continuum Analytics, Inc.| (default, Feb 22 2017, 21:13:27) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]

matplotlib:	2.0.0
numpy:		1.12.0
pandas:		0.19.2
quandl:		3.0.1
requests:	2.12.4
sklearn:	0.18.1
scipy:		0.18.1
statsmodels:	0.8.0
tensorflow:	1.0.1

Change Log

Date Created: 2017-03-25

Date of Change    Change Notes
--------------    ----------------------------------------------------------------
2017-03-25        Initial draft
2017-04-02        Added "file saved: " output

Setup

In [3]:
%run ../../code/eoddata.py

from getpass import getpass
import json
import os
import os.path
import requests as r
import stat
import xml.etree.cElementTree as etree

ws = 'http://ws.eoddata.com/data.asmx'
ns='http://ws.eoddata.com/Data'
session = r.Session()
In [4]:
username = getpass()
········
In [5]:
password = getpass()
········

Secure Credentials File

Create credentials file for later usage. The file will have permissions created so only the current user can access the file. The following SO post was followed.

The following directory will be created if it doesn't exist:

  • Windows: %USERPROFILE%/.eoddata
  • Linux: ~/.eoddata
In [6]:
# gather credentials
credentials = {'username': username, 'password': password}

# set filename variables
credentials_dir = os.path.join(os.path.expanduser("~"), '.eoddata')
credentials_file_name = 'credentials'
credentials_path = os.path.join(credentials_dir, credentials_file_name)

# set security variables
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL  # Refer to "man 2 open".
mode = stat.S_IRUSR | stat.S_IWUSR  # This is 0o600 in octal and 384 in decimal.

# create directory for file if not exists
if not os.path.exists(credentials_dir):
    os.makedirs(credentials_dir)

# for security, remove file with potentially elevated mode
try:
    os.remove(credentials_path)
except OSError:
    pass

# open file descriptor
umask_original = os.umask(0)
try:
    fdesc = os.open(credentials_path, flags, mode)
finally:
    os.umask(umask_original)

# save credentials in secure file
with os.fdopen(fdesc, 'w') as f:
    json.dump(credentials, f)
    f.write("\n")
    
print("file saved: {}".format(credentials_path))
file saved: /home/adrian/.eoddata/credentials

Inspect the XML returned

In [7]:
call = 'Login'
url = '/'.join((ws, call))

payload = {'Username': username, 'Password': password}

response = session.get(url, params=payload, stream=True)

if response.status_code == 200:
    root = etree.parse(response.raw).getroot()

Data inspection (root)

In [8]:
dir(root)
Out[8]:
['__class__',
 '__copy__',
 '__deepcopy__',
 '__delattr__',
 '__delitem__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getstate__',
 '__gt__',
 '__hash__',
 '__init__',
 '__le__',
 '__len__',
 '__lt__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__setitem__',
 '__setstate__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'append',
 'clear',
 'extend',
 'find',
 'findall',
 'findtext',
 'get',
 'getchildren',
 'getiterator',
 'insert',
 'items',
 'iter',
 'iterfind',
 'itertext',
 'keys',
 'makeelement',
 'remove',
 'set']
In [9]:
for child in root.getchildren():
    print (child.tag, child.attribute)
In [10]:
for item in root.items():
    print (item)
('Header', 'false')
('Token', '018558T9FMQ5')
('Suffix', 'true')
('Message', 'Login Successful')
('DataFormat', 'MSAI')
In [11]:
for key in root.keys():
    print (key)
Header
Token
Suffix
Message
DataFormat
In [11]:
print (root.get('Message'))
print (root.get('Token'))
print (root.get('DataFormat'))
print (root.get('Header'))
print (root.get('Suffix'))
Login Successful
018558U111MR
MSAI
false
true

Get data (token)

In [12]:
token = root.get('Token')

Client

In [13]:
# client can be opened using a with statement
with (Client()) as eoddata:
    print('token: {}'.format(eoddata.get_token()))
token: 018558FGCX8Q
In [14]:
# initialise using secure credentials file
eoddata = Client()

# client field accessors
ws = eoddata.get_web_service()
ns = eoddata.get_namespace()
token = eoddata.get_token()
session = eoddata.get_session()

print('ws: {}'.format(ws))
print('ns: {}'.format(ns))
print('token: {}'.format(token))
print(session)
ws: http://ws.eoddata.com/data.asmx
ns: http://ws.eoddata.com/Data
token: 018558ET482U

In [15]:
# the client has a list of exchange codes avaiable once intialised
eoddata.get_exchange_codes()
Out[15]:
['AMEX',
 'ASX',
 'BSE',
 'CBOT',
 'CFE',
 'CME',
 'EUREX',
 'AMS',
 'BRU',
 'LIS',
 'PAR',
 'FOREX',
 'INDEX',
 'HKEX',
 'KCBT',
 'LIFFE',
 'LSE',
 'MLSE',
 'MGEX',
 'USMF',
 'NASDAQ',
 'NSE',
 'NYBOT',
 'COMEX',
 'NYMEX',
 'NYSE',
 'NZX',
 'OTCBB',
 'SGX',
 'TSX',
 'TSXV',
 'WCE']
In [16]:
# client must be closed if opened outside a with block
session.close()
eoddata.close_session()

Comments

Fork me on GitHub