Skip to content

Commit

Permalink
ENH: Add support for AlphaVantage API (#490)
Browse files Browse the repository at this point in the history
* Added AlphaVantage readeres

* DOCS: Cleanup AlphaVantage docs

* Added AlphaVantage Quotes Reader

* Updated AV tests

* Updated AV docstrings, repaired names

* DOCS: Added Alphavantage to readers index
  • Loading branch information
addisonlynch authored and bashtage committed Apr 13, 2018
1 parent 8a9ca74 commit 1763dbd
Show file tree
Hide file tree
Showing 15 changed files with 855 additions and 0 deletions.
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:
1 change: 1 addition & 0 deletions docs/source/readers/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Data Readers
.. toctree::
:maxdepth: 2

alphavantage
fred
famafrench
bank-of-canada
Expand Down
102 changes: 102 additions & 0 deletions docs/source/remote_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,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 @@ -146,6 +147,107 @@ 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_alphavantage`` is also provided. This
function will
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
22 changes: 22 additions & 0 deletions 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 Down
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
"""
_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
----------
symbols : string, array-like object (list, tuple, Series)
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, symbols=None, retry_count=3, pause=0.5, session=None,
api_key=None):

super(AVForexReader, self).__init__(symbols=symbols,
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(symbols, str):
self.symbols = [symbols]
else:
self.symbols = symbols
try:
for pair in self.symbols:
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 symbols")

@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.symbols:
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.symbols
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

0 comments on commit 1763dbd

Please sign in to comment.