Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Add support for AlphaVantage API #490

Merged
merged 7 commits into from
Apr 13, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/source/readers/alphavantage.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
AlphaVantage
------------

.. py:module:: pandas_datareader.av.forex

.. autoclass:: AVForexReader
:members:
:inherited-members:


.. py:module:: pandas_datareader.av.time_series

.. autoclass:: AVTimeSeriesReader
:members:
:inherited-members:


.. py:module:: pandas_datareader.av.sector

.. autoclass:: AVSectorPerformanceReader
:members:
:inherited-members:


.. py:module:: pandas_datareader.av.quotes

.. autoclass:: AVQuotesReader
:members:
:inherited-members:
101 changes: 101 additions & 0 deletions docs/source/remote_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Currently the following sources are supported:
- :ref:`Morningstar<remote_data.morningstar>`
- :ref:`IEX<remote_data.iex>`
- :ref:`Robinhood<remote_data.robinhood>`
- :ref:`AlphaVantage<remote_data.alphavantage>`
- :ref:`Enigma<remote_data.enigma>`
- :ref:`Quandl<remote_data.quandl>`
- :ref:`St.Louis FED (FRED)<remote_data.fred>`
Expand Down Expand Up @@ -145,6 +146,106 @@ year relative to today.
f = web.DataReader('F', 'robinhood')
f.head()


.. _remote_data.alphavantage

AlphaVantage
============

`AlphaVantage <https://www.alphavantage.co/documentation>`__ provides realtime
equities and forex data. Free registration is required to get an API key.

Historical Time Series Data
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Through the
`AlphaVantage <https://www.alphavantage.co/documentation>`__ Time Series
endpoints, it is possible to obtain historical equities data for individual
symbols. The following endpoints are available:

* ``av-daily`` - Daily Time Series
* ``av-daily-adjusted`` - Daily Time Series (Adjusted)
* ``av-weekly`` - Weekly Time Series
* ``av-weekly-adjusted`` - Weekly Time Series (Adjusted)
* ``av-monthly`` - Monthly Time Series
* ``av-monthly-adjusted`` - Monthly Time Series (Adjusted)

.. ipython:: python

import os
from datetime import datetime
import pandas_datareader.data as web

f = web.DataReader("AAPL", "av-daily", start=datetime(2017, 2, 9),
end=datetime(2017, 5, 24),
access_key=os.getenv('ALPHAVANTAGE_API_KEY'))
f.loc["2017-02-09"]

The top-level function ``get_data_av`` is also provided. This function will
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like get_data_av -- how could a new user know what av is? Maybe just the long get_data_alphavantage? Autocomplete is pretty good.

return the ``TIME_SERIES_DAILY`` endpoint for the symbol and date range
provided.

Quotes
^^^^^^

`AlphaVantage <https://www.alphavantage.co/documentation>`__ Batch Stock Quotes
endpoint allows the retrieval of realtime stock quotes for up to 100 symbols at
once. These quotes are accessible through the top-level function
``get_quote_av``.

.. ipython:: python

import os
from datetime import datetime
import pandas_datareader.data as web

web.get_quote_av(["AAPL", "TSLA"])


.. note:: Most quotes are only available during market hours.

Forex
^^^^^

`AlphaVantage <https://www.alphavantage.co/documentation>`__ provides realtime
currency exchange rates (for physical and digital currencies).

To request the exchange rate of physical or digital currencies, simply format
as "FROM/TO" as in "USD/JPY".

.. ipython:: python

import os
import pandas_datareader.data as web

f = web.DataReader("USD/JPY", "av-forex",
access_key=os.getenv('ALPHAVANTAGE_API_KEY'))

Multiple pairs are are allowable:

.. ipython:: python

import os
import pandas_datareader.data as web

f = web.DataReader(["USD/JPY", "BTC/CNY"], "av-forex",
access_key=os.getenv('ALPHAVANTAGE_API_KEY'))


Sector Performance
^^^^^^^^^^^^^^^^^^

`AlphaVantage <https://www.alphavantage.co/documentation>`__ provides sector
performances through the top-level function ``get_sector_performance_av``.

.. ipython:: python

import os
import pandas_datareader.data as web

web.get_sector_performance_av().head()


.. _remote_data.enigma:

Enigma
Expand Down
24 changes: 23 additions & 1 deletion docs/source/whatsnew/v0.7.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,28 @@ Highlights include:
Enhancements
~~~~~~~~~~~~

- A new data connector for data provided by
`AlphaVantage <https://www.alphavantage.co/documentation>`__ was
introduced to obtain Foreign Exchange (FX) data.
(:issue:`389`)

- A new data connector for data provided by
`AlphaVantage <https://www.alphavantage.co/documentation>`__ was
introduced to obtain historical time series data.
(:issue:`389`)

- A new data connector for data provided by
`AlphaVantage <https://www.alphavantage.co/documentation>`__ was
introduced to obtain sector performance data, accessed through the
top-level function ``get_sector_performance_av``.
(:issue:`389`)

- A new data connector for data provided by
`AlphaVantage <https://www.alphavantage.co/documentation>`__ was
introduced to obtain real-time Batch Stock Quotes through the
top-level function ``get_quote_av``.
(:issue:`389`)

.. _whatsnew_070.api_breaking:

Backwards incompatible API changes
Expand All @@ -28,4 +50,4 @@ Bug Fixes

- Added support for passing the API KEY to QuandlReader either directly or by
setting the environmental variable QUANDL_API_KEY (:issue:`485`).
- Handle Morningstar index volume data properly (:issue:`486`).
- Handle Morningstar index volume data properly (:issue:`486`).
66 changes: 66 additions & 0 deletions pandas_datareader/av/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import os

from pandas_datareader.base import _BaseReader
from pandas_datareader._utils import RemoteDataError

import pandas as pd

AV_BASE_URL = 'https://www.alphavantage.co/query'


class AlphaVantage(_BaseReader):
"""
Base class for all AlphaVantage queries
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should be docstring here. Maybe we should use a doc string inheriter to simplify this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind - this is a base class.

"""
_format = 'json'

def __init__(self, symbols=None, start=None, end=None, retry_count=3,
pause=0.001, session=None, api_key=None):
super(AlphaVantage, self).__init__(symbols=symbols, start=start,
end=end, retry_count=retry_count,
pause=pause, session=session)
if api_key is None:
api_key = os.getenv('ALPHAVANTAGE_API_KEY')
if not api_key or not isinstance(api_key, str):
raise ValueError('The AlphaVantage API key must be provided '
'either through the api_key variable or '
'through the environment varaible '
'ALPHAVANTAGE_API_KEY')
self.api_key = api_key

@property
def url(self):
""" API URL """
return AV_BASE_URL

@property
def params(self):
return {
'function': self.function,
'apikey': self.api_key
}

@property
def function(self):
""" AlphaVantage endpoint function"""
raise NotImplementedError

@property
def data_key(self):
""" Key of data returned from AlphaVantage """
raise NotImplementedError

def _read_lines(self, out):
try:
df = pd.DataFrame.from_dict(out[self.data_key], orient='index')
except KeyError:
if "Error Message" in out:
raise ValueError("The requested symbol {} could not be "
"retrived. Check valid ticker"
".".format(self.symbols))
else:
raise RemoteDataError()
df = df[sorted(df.columns)]
# df.sort_index(ascending=True, inplace=True)
df.columns = [id[3:] for id in df.columns]
return df
93 changes: 93 additions & 0 deletions pandas_datareader/av/forex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from pandas_datareader.av import AlphaVantage

from pandas_datareader._utils import RemoteDataError

import pandas as pd


class AVForexReader(AlphaVantage):
"""
Returns DataFrame of the AlphaVantage Foreign Exchange (FX) Exchange Rates
data.

.. versionadded:: 0.7.0

Parameters
----------
pairs : string, array-like object (list, tuple, Series)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just keep the standard symbols?

Single currency pair (formatted 'FROM/TO') or list of the same.
retry_count : int, default 3
Number of times to retry query request.
pause : int, default 0.5
Time, in seconds, to pause between consecutive queries of chunks. If
single value given for symbol, represents the pause between retries.
session : Session, default None
requests.sessions.Session instance to be used
api_key : str, optional
AlphaVantage API key . If not provided the environmental variable
ALPHAVANTAGE_API_KEY is read. The API key is *required*.
"""
def __init__(self, pairs=None, retry_count=3, pause=0.5, session=None,
api_key=None):

super(AVForexReader, self).__init__(symbols=pairs,
start=None, end=None,
retry_count=retry_count,
pause=pause,
session=session,
api_key=api_key)
self.from_curr = {}
self.to_curr = {}
self.optional_params = {}
if isinstance(pairs, str):
self.pairs = [pairs]
else:
self.pairs = pairs
try:
for pair in self.pairs:
self.from_curr[pair] = pair.split('/')[0]
self.to_curr[pair] = pair.split('/')[1]
except Exception as e:
print(e)
raise ValueError("Please input a currency pair "
"formatted 'FROM/TO' or a list of "
"currency pairs")

@property
def function(self):
return 'CURRENCY_EXCHANGE_RATE'

@property
def data_key(self):
return 'Realtime Currency Exchange Rate'

@property
def params(self):
params = {
'apikey': self.api_key,
'function': self.function
}
params.update(self.optional_params)
return params

def read(self):
result = []
for pair in self.pairs:
self.optional_params = {
'from_currency': self.from_curr[pair],
'to_currency': self.to_curr[pair],
}
data = super(AVForexReader, self).read()
result.append(data)
df = pd.concat(result, axis=1)
df.columns = self.pairs
return df

def _read_lines(self, out):
try:
df = pd.DataFrame.from_dict(out[self.data_key], orient='index')
except KeyError:
raise RemoteDataError()
df.sort_index(ascending=True, inplace=True)
df.index = [id[3:] for id in df.index]
return df
Loading