backtrader.feeds.quandl 源代码
#!/usr/bin/env python
"""Quandl Data Feed Module - Quandl data parsing.
This module provides data feeds for Quandl CSV data and
Quandl API connection.
Classes:
QuandlCSV: Parses pre-downloaded Quandl CSV files.
Quandl: Live Quandl data feed.
Example:
>>> data = bt.feeds.QuandlCSV(dataname='quandl.csv')
>>> cerebro.adddata(data)
"""
import collections
import io
import itertools
from datetime import date, datetime
from .. import feed
from ..utils import date2num
from ..utils.py3 import urlquote
__all__ = ["QuandlCSV", "Quandl"]
[文档]
class QuandlCSV(feed.CSVDataBase):
"""
Parses pre-downloaded Quandl CSV Data Feeds (or locally generated if they
comply to the Quandl format)
Specific parameters:
- ``dataname``: The filename to parse or a file-like object
- ``reverse`` (default: ``False``)
It is assumed that locally stored files have already been reversed
during the download process
- ``adjclose`` (default: ``True``)
Whether to use the dividend/split adjusted close and adjust all
values according to it.
- ``round`` (default: ``False``)
Whether to round the values to a specific number of decimals after
having adjusted the close
- ``decimals`` (default: ``2``)
Number of decimals to round to
"""
_online = False # flag to avoid double reversal
params = (
("reverse", False),
("adjclose", True),
("round", False),
("decimals", 2),
)
[文档]
def start(self):
"""Start the Quandl CSV data feed.
Reverses data if needed for correct chronological order.
"""
super().start()
if not self.params.reverse:
return
elif self._online:
return # revers is True but also online, managed with order = asc
# Quandl data can be in reverse order -> reverse
dq = collections.deque()
for line in self.f:
dq.appendleft(line)
f = io.StringIO(newline=None)
f.writelines(dq)
f.seek(0)
self.f.close()
self.f = f
def _loadline(self, linetokens):
i = itertools.count(0)
dttxt = linetokens[next(i)] # YYYY-MM-DD
dt = date(int(dttxt[0:4]), int(dttxt[5:7]), int(dttxt[8:10]))
dtnum = date2num(datetime.combine(dt, self.p.sessionend))
self.lines.datetime[0] = dtnum
if self.p.adjclose:
for _ in range(7):
next(i) # skip ohlcv, ex-dividend, split ratio
o = float(linetokens[next(i)])
h = float(linetokens[next(i)])
low = float(linetokens[next(i)])
c = float(linetokens[next(i)])
v = float(linetokens[next(i)])
self.lines.openinterest[0] = 0.0
if self.p.round:
decimals = self.p.decimals
o = round(o, decimals)
h = round(h, decimals)
low = round(low, decimals)
c = round(c, decimals)
v = round(v, decimals)
self.lines.open[0] = o
self.lines.high[0] = h
self.lines.low[0] = low
self.lines.close[0] = c
self.lines.volume[0] = v
return True
[文档]
class Quandl(QuandlCSV):
"""
Executes a direct download of data from Quandl servers for the given time
range.
Specific parameters (or specific meaning):
- ``dataname``
The ticker to download ('YHOO', for example)
- ``baseurl``
The server url. Someone might decide to open a Quandl compatible
service in the future.
- ``proxies``
A dict indicating which proxy to go through for the download as in
{'http': 'http://myproxy.com'} or {'http': 'http://127.0.0.1:8080'}
- ``buffered``
If True, the entire socket connection will be buffered locally before
parsing starts.
- ``reverse``
Quandl returns the value in descending order (newest first). If this is
``True`` (the default), the request will tell Quandl to return in
ascending (oldest to newest) format
- ``adjclose``
Whether to use the dividend/split adjusted close and adjust all values
according to it.
- ``apikey``
Apikey identification in case it may be needed
- ``dataset``
String identifying the dataset to query. Defaults to ``WIKI``
"""
_online = True # flag to avoid double reversal
params = (
("baseurl", "https://www.quandl.com/api/v3/datasets"),
("proxies", {}),
("buffered", True),
("reverse", True),
("apikey", None),
("dataset", "WIKI"),
)
def __init__(self):
"""Initialize the Quandl data feed.
Sets up error tracking for data downloads.
"""
self.error = None
[文档]
def start(self):
"""Start the Quandl data feed and download data.
Constructs URL with parameters and fetches data from Quandl API.
"""
self.error = None
url = f"{self.p.baseurl}/{self.p.dataset}/{urlquote(self.p.dataname)}.csv"
urlargs = []
if self.p.reverse:
urlargs.append("order=asc")
if self.p.apikey is not None:
urlargs.append(f"api_key={self.p.apikey}")
if self.p.fromdate:
dtxt = self.p.fromdate.strftime("%Y-%m-%d")
urlargs.append(f"start_date={dtxt}")
if self.p.todate:
dtxt = self.p.todate.strftime("%Y-%m-%d")
urlargs.append(f"end_date={dtxt}")
if urlargs:
url += "?" + "&".join(urlargs)
from ..utils.py3 import ProxyHandler, build_opener, install_opener, urlopen
if self.p.proxies:
proxy = ProxyHandler(self.p.proxies)
opener = build_opener(proxy)
install_opener(opener)
try:
datafile = urlopen(url)
except OSError as e:
self.error = str(e)
# leave us empty
return
if datafile.headers["Content-Type"] != "text/csv":
self.error = "Wrong content type: %s" % datafile.headers
return # HTML returned? wrong url?
if self.params.buffered:
# buffer everything from the socket into a local buffer
f = io.StringIO(datafile.read().decode("utf-8"), newline=None)
datafile.close()
else:
f = datafile
self.f = f
# Prepared a "path" file - CSV Parser can take over
super().start()