From 2787c212d23e73db2973843a6f367df057ebcc71 Mon Sep 17 00:00:00 2001 From: Chris Berkhout Date: Mon, 27 Dec 2021 11:25:55 +1100 Subject: [PATCH] Fix AlphaVantage to handle adjusted endpoint being premium. --- src/pricehist/exceptions.py | 4 +- src/pricehist/sources/alphavantage.py | 19 ++++- tests/live.sh | 12 +-- tests/pricehist/sources/test_alphavantage.py | 39 ++++++++- .../test_alphavantage/ibm-partial-adj.json | 81 +++++++++++++++++++ .../test_alphavantage/ibm-partial.json | 42 ++-------- 6 files changed, 149 insertions(+), 48 deletions(-) create mode 100644 tests/pricehist/sources/test_alphavantage/ibm-partial-adj.json diff --git a/src/pricehist/exceptions.py b/src/pricehist/exceptions.py index 5ac7aa7..e207537 100644 --- a/src/pricehist/exceptions.py +++ b/src/pricehist/exceptions.py @@ -52,7 +52,7 @@ class InvalidType(SourceError, ValueError): class CredentialsError(SourceError): """Access credentials are unavailable or invalid.""" - def __init__(self, keys, source): + def __init__(self, keys, source, msg=""): self.keys = keys self.source = source message = ( @@ -61,6 +61,8 @@ class CredentialsError(SourceError): f"correctly. Run 'pricehist source {source.id()}' for more " f"information about credentials." ) + if msg: + message += f" {msg}" super(CredentialsError, self).__init__(message) diff --git a/src/pricehist/sources/alphavantage.py b/src/pricehist/sources/alphavantage.py index 75cda5d..84df4d9 100644 --- a/src/pricehist/sources/alphavantage.py +++ b/src/pricehist/sources/alphavantage.py @@ -51,7 +51,8 @@ class AlphaVantage(BaseSource): "will list all digital and physical currency symbols.\n" "The PAIR for stocks is the stock symbol only. The quote currency " f"will be determined automatically. {self._stock_symbols_message()}\n" - "The price type 'adjclose' is only available for stocks.\n" + "The price type 'adjclose' is only available for stocks, and " + "requires an access key for which premium endpoints are unlocked.\n" "Beware that digital currencies quoted in non-USD currencies may " "be converted from USD data at one recent exchange rate rather " "than using historical rates.\n" @@ -186,8 +187,13 @@ class AlphaVantage(BaseSource): def _stock_data(self, series): output_quote = self._stock_currency(series.base) or "UNKNOWN" + if series.type == "adjclose": + function = "TIME_SERIES_DAILY_ADJUSTED" + else: + function = "TIME_SERIES_DAILY" + params = { - "function": "TIME_SERIES_DAILY_ADJUSTED", + "function": function, "symbol": series.base, "outputsize": self._outputsize(series.start), "apikey": self._apikey(), @@ -225,7 +231,8 @@ class AlphaVantage(BaseSource): "high": entries["2. high"], "low": entries["3. low"], "close": entries["4. close"], - "adjclose": entries["5. adjusted close"], + "adjclose": "5. adjusted close" in entries + and entries["5. adjusted close"], } for day, entries in reversed(data["Time Series (Daily)"].items()) } @@ -332,6 +339,12 @@ class AlphaVantage(BaseSource): if type(data) == dict: if "Note" in data and "call frequency" in data["Note"]: raise exceptions.RateLimit(data["Note"]) + if ( + "Information" in data + and "ways to unlock premium" in data["Information"] + ): + msg = "You were denied access to a premium endpoint." + raise exceptions.CredentialsError([self.API_KEY_NAME], self, msg) if "Error Message" in data and "apikey " in data["Error Message"]: raise exceptions.CredentialsError([self.API_KEY_NAME], self) diff --git a/tests/live.sh b/tests/live.sh index 543d634..33e66c3 100755 --- a/tests/live.sh +++ b/tests/live.sh @@ -47,11 +47,11 @@ name="Alpha Vantage stocks" cmd="pricehist fetch alphavantage TSLA -s 2021-01-04 -e 2021-01-08" read -r -d '' expected <