ENH: Stream benchmark and treasury data when downloading

Instead of loading entire csv or xml into memory.
This commit is contained in:
Richard Frank
2013-04-19 12:22:06 -04:00
committed by Eddie Hebert
parent ca0bce1680
commit 4ba35d7d46
2 changed files with 61 additions and 21 deletions
+5 -6
View File
@@ -18,7 +18,6 @@ from datetime import datetime
import csv
from StringIO import StringIO
from functools import partial
import requests
@@ -75,7 +74,7 @@ def get_raw_benchmark_data(start_date, end_date, symbol):
))
res = requests.get('http://ichart.yahoo.com/table.csv',
params=params)
params=params, stream=True)
if not res.ok:
raise BenchmarkDataNotFoundError("""
@@ -85,7 +84,7 @@ start_date={start_date}, end_date={end_date}, url={url}""".strip().
end_date=end_date,
url=res.url))
return csv.DictReader(StringIO(res.content))
return csv.DictReader(res.iter_lines())
def get_benchmark_data(symbol, start_date=None, end_date=None):
@@ -98,12 +97,10 @@ def get_benchmark_data(symbol, start_date=None, end_date=None):
end_date = datetime.utcnow()
raw_benchmark_data = get_raw_benchmark_data(start_date, end_date, symbol)
# Reverse data so we can load it in reverse chron order.
benchmarks_source = reversed(list(raw_benchmark_data))
mappings = benchmark_mappings()
return source_to_records(mappings, benchmarks_source)
return source_to_records(mappings, raw_benchmark_data)
def get_benchmark_returns(symbol, start_date=None, end_date=None):
@@ -120,4 +117,6 @@ def get_benchmark_returns(symbol, start_date=None, end_date=None):
daily_return = DailyReturn(date=data_point['date'], returns=returns)
benchmark_returns.append(daily_return)
# Reverse data so we can load it in reverse chron order.
benchmark_returns.reverse()
return benchmark_returns
+56 -15
View File
@@ -16,8 +16,8 @@
import requests
from StringIO import StringIO
from xml.dom.minidom import parse
from collections import OrderedDict
import xml.etree.ElementTree as ET
from loader_utils import (
guarded_conversion,
@@ -62,26 +62,67 @@ def treasury_mappings():
in _CURVE_MAPPINGS.iteritems()}
class iter_to_stream(object):
"""
Exposes an iterable as an i/o stream
"""
def __init__(self, iterable):
self.buffered = ""
self.iter = iter(iterable)
def read(self, size):
result = ""
while size > 0:
data = self.buffered or next(self.iter, None)
self.buffered = ""
if data is None:
break
size -= len(data)
if size < 0:
data, self.buffered = data[:size], data[size:]
result += data
return result
def get_treasury_source():
url = """\
http://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData\
"""
res = requests.get(url)
res = requests.get(url, stream=True)
stream = iter_to_stream(res.iter_lines())
content = StringIO(res.content)
dom = parse(content)
elements = ET.iterparse(stream, ('end', 'start-ns', 'end-ns'))
entries = dom.getElementsByTagName("entry")
namespaces = OrderedDict()
properties_xpath = ['']
for entry in entries:
properties = entry.getElementsByTagName("m:properties")
datum = {node.nodeName.replace('d:', ''):
node.childNodes[0].nodeValue
if len(node.childNodes)
else None
for node in properties[0].childNodes
if node.nodeType == dom.ELEMENT_NODE}
yield datum
def updated_namespaces():
if '' in namespaces and 'm' in namespaces:
properties_xpath[0] = "{%s}content/{%s}properties" % (
namespaces[''], namespaces['m']
)
else:
properties_xpath[0] = ''
for event, element in elements:
if event == 'end':
tag = ET.QName(element.tag).localname
if tag == "entry":
properties = element.find(properties_xpath[0])
datum = {ET.QName(node.tag).localname: node.text
for node in properties.iterchildren()
if ET.iselement(node)}
# clear the element after we've dealt with it:
element.clear()
yield datum
elif event == 'start-ns':
namespaces[element[0]] = element[1]
updated_namespaces()
elif event == 'end-ns':
namespaces.popitem()
updated_namespaces()
def get_treasury_data():