I recently came across an article about a service provided by the Yahoo! finance website, which return details about stock quotes in
comma separated values (CSVs). Many folks have used this service in their programs to display (almost) real time stock data. Of course, I had to make my phone do the same :) As we will see, Python makes it look easy - no, Python makes it look GOOD!
BackgroundThe Yahoo! finance service
http://quote.yahoo.com/d/quotes.csv is a very simple yet powerful service. The user can control the fields in the stock quote data through a format string. The return data contains stock data fields in CSV format. The fields and their order is based on the format string.
This is another example of the usage of this service.
Cache ManagementThe application on the phone should minimize the network traffic. However, care should be taken that the data is updated as frequently as possible to keep the real-time nature of the data. To achieve this, there is a very rudimentary cache management technique implemented in the module. The cache management checks how old the stock data is and if it is older than a certain expiry. The network traffic is generated only if the data is expired.
ChartThis module also allows downloading the chart for a given symbol. The chart is downloaded from yet another Yahoo! finance service
http://ichart.finance.yahoo.com/t The response of this service is a intra-day chart for the latest day. If a chart exists, the response is of type
image/png. This can be used as a test.
ImplementationThe following code snippet is from the
quotes.py module. This piece works well on 3rd edition phones:
# These times should be set to minimize the network traffic
QUOTEEXPIRY = 60 # 1 Minute
CHARTEXPIRY = 300 # 5 Minutes
CACHEDIR = 'c:\\cache\\'
# If the file does not exist or if the creation time of the
# existing file is older than expiry, then return True
def is_expired(filename, expiry):
expired = False
if not os.path.exists(filename):
expired = True
else:
lastmod = os.stat(filename)[ST_MTIME]
currtime = int(time.time())
if currtime > lastmod + expiry:
expired = True
return expired
# This function downloads the chart for a given symbol
# If the symbol does not have a chart, the function returns
# False, else returns True
def get_chart(symbol):
retval = True
filename = CACHEDIR+symbol.upper()+'chart.png'
if is_expired(filename, CHARTEXPIRY):
name, status = urllib.urlretrieve('http://ichart.finance.yahoo.com/t?s='+symbol.upper(), filename)
if status.type != 'image/png':
retval = False
os.remove(filename)
return retval
# Get the CSV from yahoo server and return parsed values
# Format is known and hence the cryptic retval parsing
def get_quote(symbol):
filename = CACHEDIR+symbol.upper()+'quote.txt'
if is_expired(filename, QUOTEEXPIRY):
urllib.urlretrieve('http://quote.yahoo.com/d/quotes.csv?s='+symbol.upper()+'&d=t&f=sl1d1t1c1ohgvj1pp2xwenr', filename)
f = file(filename)
data = f.read()
f.close()
names = ['sym', 'last', 'date', 'curtime', 'change', 'open', 'high',
'low', 'vol', 'mcap', 'close', 'pctchg', 'exchange', 'annrange',
'earnings', 'name', 'peratio']
values = map(lambda s: s.strip('"'), data.split('\n')[0].split(','))
return dict(zip(names, values))
The meaning of the format string can be found from the correspondance between the string and the
names array.
The complete implementation is located
hereSummaryThis log is yet another example of power and elegance of Python. The way
zip() function simplifies creation of a very usable dictionary out of an array.