-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Portfolio fetch stock prices using alpha-vantage python module * alphavantage call respect the configurable polling period
- Loading branch information
1 parent
373c6e5
commit c7a37b8
Showing
7 changed files
with
144 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import os | ||
import sys | ||
import inspect | ||
import logging | ||
import traceback | ||
from enum import Enum | ||
import datetime as dt | ||
import time | ||
from alpha_vantage.timeseries import TimeSeries | ||
|
||
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) | ||
parentdir = os.path.dirname(currentdir) | ||
sys.path.insert(0, parentdir) | ||
|
||
from Utils.Utils import Markets | ||
|
||
|
||
class AVInterval(Enum): | ||
""" | ||
AlphaVantage interval types: '1min', '5min', '15min', '30min', '60min', 'daily', 'weekly and 'monthly' | ||
""" | ||
|
||
MIN_1 = "1min" | ||
MIN_5 = "5min" | ||
MIN_15 = "15min" | ||
MIN_30 = "30min" | ||
MIN_60 = "60min" | ||
DAILY = "daily" | ||
WEEKLY = "weekly" | ||
MONTHLY = "monthly" | ||
|
||
|
||
class AlphaVantageInterface: | ||
"""class providing interfaces to request data from AlphaVantage""" | ||
|
||
# Inner class to create a Singleton pattern | ||
class __AlphaVantageInterface: | ||
def __init__(self, config): | ||
self._config = config | ||
self._last_call_ts = dt.datetime.now() | ||
self._TS = TimeSeries( | ||
key=config.get_alpha_vantage_api_key(), | ||
output_format="json", | ||
treat_info_as_error=True, | ||
) | ||
|
||
def daily(self, market_id): | ||
""" | ||
Calls AlphaVantage API and return the Daily time series for the given market | ||
- **market_id**: string representing an AlphaVantage compatible market id | ||
- Returns **None** if an error occurs otherwise the pandas dataframe | ||
""" | ||
self._wait_before_call() | ||
try: | ||
market_id = self._format_market_id(market_id) | ||
data, meta_data = self._TS.get_daily( | ||
symbol=market_id, outputsize="compact" | ||
) | ||
return data | ||
except Exception as e: | ||
logging.error("AlphaVantage wrong api call for {}".format(market_id)) | ||
logging.debug(e) | ||
logging.debug(traceback.format_exc()) | ||
logging.debug(sys.exc_info()[0]) | ||
return None | ||
|
||
def _format_market_id(self, market_id): | ||
""" | ||
Convert a standard market id to be compatible with AlphaVantage API. | ||
Adds the market exchange prefix (i.e. London is LON:) | ||
""" | ||
# return "{}:{}".format("LON", market_id.split("-")[0]) | ||
if "LSE:" in market_id: | ||
subs = market_id.split(":") | ||
assert len(subs) == 2 | ||
return "{}:{}".format(Markets[subs[0]].value, subs[1]) | ||
return market_id | ||
|
||
def _wait_before_call(self): | ||
""" | ||
Wait between API calls to not overload the server | ||
""" | ||
while (dt.datetime.now() - self._last_call_ts) <= dt.timedelta( | ||
seconds=self._config.get_alpha_vantage_polling_period() | ||
): | ||
time.sleep(0.2) | ||
self._last_call_ts = dt.datetime.now() | ||
|
||
# Single instance of the inner class | ||
_instance = None | ||
|
||
def __init__(self, config): | ||
if not AlphaVantageInterface._instance: | ||
AlphaVantageInterface._instance = AlphaVantageInterface.__AlphaVantageInterface( | ||
config | ||
) | ||
logging.info("AlphaVantageInterface initialised") | ||
|
||
def get_prices(self, market_id, interval=AVInterval.DAILY): | ||
""" | ||
Return the price time series of the requested market with the interval | ||
granularity. Return None if the interval is invalid | ||
""" | ||
if interval == AVInterval.DAILY: | ||
return self._instance.daily(market_id) | ||
else: | ||
logging.warning( | ||
"AlphaVantageInterface supports only DAILY interval. Requested interval: {}".format( | ||
interval.value | ||
) | ||
) | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters