summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanglewood <85772166+deeleeramone@users.noreply.github.com>2024-03-03 14:51:47 -0800
committerGitHub <noreply@github.com>2024-03-03 22:51:47 +0000
commiteb07111477c8477b39f419c5d88cade9f0aaf8ab (patch)
tree3dc06a9b0b40f917ebb7b0afaea3811e255f04ae
parent5f5fad05e75eae92e419f7b9661c2b010ad91d59 (diff)
adds AlphaVantage to historical_eps (#6155)
-rw-r--r--openbb_platform/extensions/equity/integration/test_equity_api.py8
-rw-r--r--openbb_platform/extensions/equity/integration/test_equity_python.py8
-rw-r--r--openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/__init__.py2
-rw-r--r--openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/historical_eps.py158
-rw-r--r--openbb_platform/providers/alpha_vantage/tests/record/http/test_alpha_vantage_fetchers/test_av_historical_eps_fetcher.yaml193
-rw-r--r--openbb_platform/providers/alpha_vantage/tests/test_alpha_vantage_fetchers.py10
6 files changed, 379 insertions, 0 deletions
diff --git a/openbb_platform/extensions/equity/integration/test_equity_api.py b/openbb_platform/extensions/equity/integration/test_equity_api.py
index 7b407ce038e..66b8d5acb04 100644
--- a/openbb_platform/extensions/equity/integration/test_equity_api.py
+++ b/openbb_platform/extensions/equity/integration/test_equity_api.py
@@ -1693,6 +1693,14 @@ def test_equity_market_snapshots(params, headers):
"params",
[
({"symbol": "AAPL", "limit": 5, "provider": "fmp"}),
+ (
+ {
+ "symbol": "AAPL",
+ "period": "quarter",
+ "limit": 5,
+ "provider": "alpha_vantage",
+ }
+ ),
],
)
@pytest.mark.integration
diff --git a/openbb_platform/extensions/equity/integration/test_equity_python.py b/openbb_platform/extensions/equity/integration/test_equity_python.py
index 13536bc1216..46b11b30f3a 100644
--- a/openbb_platform/extensions/equity/integration/test_equity_python.py
+++ b/openbb_platform/extensions/equity/integration/test_equity_python.py
@@ -1587,6 +1587,14 @@ def test_equity_market_snapshots(params, obb):
"params",
[
({"symbol": "AAPL", "limit": 5, "provider": "fmp"}),
+ (
+ {
+ "symbol": "AAPL",
+ "period": "quarter",
+ "limit": 5,
+ "provider": "alpha_vantage",
+ }
+ ),
],
)
@pytest.mark.integration
diff --git a/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/__init__.py b/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/__init__.py
index 85fd1b59985..b8591af6750 100644
--- a/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/__init__.py
+++ b/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/__init__.py
@@ -1,6 +1,7 @@
"""Alpha Vantage Provider module."""
from openbb_alpha_vantage.models.equity_historical import AVEquityHistoricalFetcher
+from openbb_alpha_vantage.models.historical_eps import AVHistoricalEpsFetcher
from openbb_core.provider.abstract.provider import Provider
alpha_vantage_provider = Provider(
@@ -16,5 +17,6 @@ alpha_vantage_provider = Provider(
credentials=["api_key"],
fetcher_dict={
"EquityHistorical": AVEquityHistoricalFetcher,
+ "HistoricalEps": AVHistoricalEpsFetcher,
},
)
diff --git a/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/historical_eps.py b/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/historical_eps.py
new file mode 100644
index 00000000000..ccb38ec5f6f
--- /dev/null
+++ b/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/historical_eps.py
@@ -0,0 +1,158 @@
+"""AlphaVantage Historical EPS Model."""
+
+# pylint: disable=unused-argument
+
+import warnings
+from datetime import date as dateType
+from typing import Any, Dict, List, Literal, Optional, Union
+
+from openbb_core.provider.abstract.fetcher import Fetcher
+from openbb_core.provider.standard_models.historical_eps import (
+ HistoricalEpsData,
+ HistoricalEpsQueryParams,
+)
+from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS
+from openbb_core.provider.utils.errors import EmptyDataError
+from openbb_core.provider.utils.helpers import (
+ ClientResponse,
+ ClientSession,
+ amake_requests,
+)
+from pydantic import Field, field_validator
+
+_warn = warnings.warn
+
+
+class AlphaVantageHistoricalEpsQueryParams(HistoricalEpsQueryParams):
+ """
+ AlphaVantage Historical EPS Query Params.
+
+ Source: https://www.alphavantage.co/documentation/#earnings
+ """
+
+ __json_schema_extra__ = {"symbol": ["multiple_items_allowed"]}
+
+ period: Literal["annual", "quarter"] = Field(
+ default="quarter", description=QUERY_DESCRIPTIONS.get("period", "")
+ )
+ limit: Optional[int] = Field(
+ default=None, description=QUERY_DESCRIPTIONS.get("limit", "")
+ )
+
+
+class AlphaVantageHistoricalEpsData(HistoricalEpsData):
+ """AlphaVantage Historical EPS Data."""
+
+ __alias_dict__ = {
+ "date": "fiscalDateEnding",
+ "eps_actual": "reportedEPS",
+ "eps_estimated": "estimatedEPS",
+ "surprise_percent": "surprisePercentage",
+ "reported_date": "reportedDate",
+ }
+
+ surprise: Optional[float] = Field(
+ default=None,
+ description="Surprise in EPS (Actual - Estimated).",
+ )
+ surprise_percent: Optional[Union[float, str]] = Field(
+ default=None,
+ description="EPS surprise as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ reported_date: Optional[dateType] = Field(
+ default=None,
+ description="Date of the earnings report.",
+ )
+
+ @field_validator(
+ "eps_estimated",
+ "eps_actual",
+ "surprise",
+ mode="before",
+ check_fields=False,
+ )
+ @classmethod
+ def validate_null(cls, v):
+ """Clean None returned as a string."""
+ return None if str(v).strip() == "None" or str(v) == "0" else v
+
+ @field_validator("surprise_percent", mode="before", check_fields=False)
+ @classmethod
+ def normalize_percent(cls, v):
+ """Normalize percent values."""
+ if isinstance(v, str) and v == "None" or str(v) == "0":
+ return None
+ return float(v) / 100
+
+
+class AVHistoricalEpsFetcher(
+ Fetcher[AlphaVantageHistoricalEpsQueryParams, List[AlphaVantageHistoricalEpsData]]
+):
+ """AlphaVantage Historical EPS Fetcher."""
+
+ @staticmethod
+ def transform_query(params: Dict[str, Any]) -> AlphaVantageHistoricalEpsQueryParams:
+ """Transform the query params."""
+ return AlphaVantageHistoricalEpsQueryParams(**params)
+
+ @staticmethod
+ async def aextract_data(
+ query: AlphaVantageHistoricalEpsQueryParams,
+ credentials: Optional[Dict[str, str]],
+ **kwargs: Any,
+ ) -> List[Dict]:
+ """Return the raw data from the AlphaVantage endpoint."""
+
+ api_key = credentials.get("alpha_vantage_api_key") if credentials else ""
+
+ BASE_URL = "https://www.alphavantage.co/query?function=EARNINGS&"
+
+ # We are allowing multiple symbols to be passed in the query, so we need to handle that.
+ symbols = query.symbol.split(",")
+
+ urls = [f"{BASE_URL}symbol={symbol}&apikey={api_key}" for symbol in symbols]
+
+ results = []
+
+ # We need to make a custom callback function for this async request.
+ async def response_callback(response: ClientResponse, _: ClientSession):
+ """Response callback function."""
+ symbol = response.url.query.get("symbol", None)
+ data = await response.json()
+ target = (
+ "annualEarnings" if query.period == "annual" else "quarterlyEarnings"
+ )
+ result = []
+ # If data is returned, append it to the results list.
+ if data:
+ result = [
+ {
+ "symbol": symbol,
+ **d,
+ }
+ for d in data.get(target, []) # type: ignore
+ ]
+ if query.limit is not None:
+ results.extend(result[: query.limit])
+ else:
+ results.extend(result)
+
+ # If no data is returned, raise a warning and move on to the next symbol.
+ if not data:
+ _warn(f"Symbol Error: No data found for {symbol}")
+
+ await amake_requests(urls, response_callback, **kwargs) # type: ignore
+
+ return results
+
+ @staticmethod
+ def transform_data(
+ query: AlphaVantageHistoricalEpsQueryParams,
+ data: List[Dict],
+ **kwargs: Any,
+ ) -> List[AlphaVantageHistoricalEpsData]:
+ """Transform the raw data into the standard model."""
+ if not data:
+ raise EmptyDataError("No data found.")
+ return [AlphaVantageHistoricalEpsData.model_validate(d) for d in data]
diff --git a/openbb_platform/providers/alpha_vantage/tests/record/http/test_alpha_vantage_fetchers/test_av_historical_eps_fetcher.yaml b/openbb_platform/providers/alpha_vantage/tests/record/http/test_alpha_vantage_fetchers/test_av_historical_eps_fetcher.yaml
new file mode 100644
index 00000000000..d0b62cfc85a
--- /dev/null
+++ b/openbb_platform/providers/alpha_vantage/tests/record/http/test_alpha_vantage_fetchers/test_av_historical_eps_fetcher.yaml
@@ -0,0 +1,193 @@
+interactions:
+- request:
+ body: null
+ headers:
+ Accept:
+ - application/json
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ method: GET
+ uri: https://www.alphavantage.co/query?apikey=MOCK_API_KEY&function=EARNINGS&symbol=AAPL
+ response:
+ body:
+ string: !!binary |
+ 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
+ headers:
+ Allow:
+ - GET, HEAD, OPTIONS
+ CF-Cache-Status:
+ - DYNAMIC
+ CF-RAY:
+ - 85d74473ed9d137e-YVR
+ Connection:
+ - keep-alive
+ Content-Encoding:
+ - gzip
+ Content-Type:
+ - application/json
+ Cross-Origin-Opener-Policy:
+ - same-origin
+ Date:
+ - Fri, 01 Mar 2024 06:59:58 GMT
+ Nel:
+ - '{"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}'
+ Referrer-Policy:
+ - same-origin
+ Report-To:
+ - '{"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1709276398&sid=1b10b0ff-8a76-4548-befa-353fc6c6c045&s=HYLkepa3xuJf8ZP93wYuVeE7fHXoMnoAaRfYOuePI1s%3D"}]}'
+ Reporting-Endpoints:
+ - heroku-nel=https://nel.heroku.com/reports?ts=1709276398&sid=1b10b0ff-8a76-4548-befa-353fc6c6c045&s=HYLkepa3xuJf8ZP93wYuVeE7fHXoMnoAaRfYOuePI1s%3D
+ Server:
+ - cloudflare
+ Transfer-Encoding:
+ - chunked
+ Vary:
+ - Cookie, Origin
+ Via:
+ - 1.1 vegur
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - DENY
+ status:
+ code: 200
+ message: OK
+- request:
+ body: null
+ headers:
+ Accept:
+ - application/json
+ Accept-Encoding:
+ - gzip, deflate
+ Connection:
+ - keep-alive
+ method: GET
+ uri: https://www.alphavantage.co/query?apikey=MOCK_API_KEY&function=EARNINGS&symbol=MSFT
+ response:
+ body:
+ string: !!binary |
+ H4sIAAAAAAAAA9ydS28dNxKF9/MrBK1ziXrwmfU4uwABMrvBLDSJYghwlIxkL4Jg/vug+xqGO9aY
+ n1O8NhSvBLmhwmnWIasOD9m//+3q6urq+vG3n//9y6vrr6+uv/3+m39cf3X+7c39/ZubVy9uHu7v
+ 7l8+Xn999c/999u/39/9tD/5093jDzev/n7z+vbF/Y939y+3v2RiflI7ub79e++efrj99ZeH17c/
+ vvju++3BkoZdv3viv199chCpJ5dJkJG6BoIYDBIBoihGS6MFgggKUlIrfz6IDhQkx4J0FMRT74Eg
+ DQbxQHJpRUEstRoIUmCQyJBkGKN6IIjTIAGaqNEhiSBRimQEgggMEkhgYXzXFBgR6TBGhO7SYJAc
+ GBGpMIhFXleBQQL5K5kCCcxb4jCIBCYuYXSXNCKvS2mQCBUFBul/Orl0jAGDNA0E6TBIroEgDQZx
+ DwSpMIjp+zm8//Svt6X4f97cPLy+fXj12+Wq8e35t0/mkyhZM4b/8ZHbx9d3P98cVsj+x2ce3zz8
+ +nD3eHsGreX//f93tw8/3N6/vnl5ey5JfZQW6xPGR0C9B99PKifLc/hjDr+Wj8P3zOCrpe5ywT7p
+ gF/ayQqpS6b4ywS/Zjr8eUThO8t+P0km8HOZwzf/OHwzBn+kXksJNbCU/L6RH2S/G4A/Pg5fHGZ/
+ qMHaundIfdupPx97B2M/GXqBE58lbT4up10c0G/Er1P05tGhP0mSyvCfLFWT4PBD6ttOffACQO7r
+ utyvY4R0JUp926kPZr4Osl8nE39j8FvyEim7N1kNkl938oPRb3P40iYTP533a9V+OVHxgH4jf5sL
+ BVP0ugm6H0cP5z71JCZB/JD7unO/TRvNUeb4p0Vvo8NfitSQ3Eu5rzv358kvPodf86ToHXDp89R6
+ pLHf5G5IftnJPx/+bnP8ZYLfOkz/nrSH6C+Y/rLT3+bSV53j9wl+hbNfT6MUi8GH7Jed/WMOf47e
+ 6pqWRzWpqob2YSj7ZWf/HH5RMPqTyV8h+zUnH5HKd9uHYuzf3pScPixrP5RLOxj/WctLCz9J+XKb
+ cAfw0k7a5+DBym+zsq/ild/MY8kPub89mecdrz5B3A/wL2J+Du2LQtJvuJVI64DzMmt2lCHf1O8W
+ Q08p35HKR0Zd0phN+XzBv+Se+AH9xvn5hK+g3JO+RunIqdqoMfiQ8h01+gKKfUl9Nt/j5b7V3EJm
+ Bcr8vjNf5/ArgF9Xwa/WRsyrAanfUKMvqQPqN1tT62pNtdZ2Oa/KAf9W64OdyA7wT9Y8g62u9yTW
+ LYYfsr+hVl82d8cc/xqVLyfrke0trZj8DXX6MPvHmqm/JrcR9FBB8ted/GDzGsx9dbby9c8191dM
+ /opWfgG7e5LKTOdSXPeM0P7WhgqSv+7kn6991cD459kmB5z9T57USsjeR+lfd/r3ef4vmPwF65y9
+ REzAm7sR0r/s9Lf58DeQ/mMR/T2V0CbHzN15wL+t/SD9AfxJ5SeZbvFothFDD8lfdvL7HL0C+Lqm
+ 8B2pSush2y3lfoFLfysLuI+dHdU9Bp9yPyOVT57Q7z+EnxdVPirJJOvlXNcH/ETjlydMO08sfbOV
+ D+I/9eTuHsMP2Z+R0PdUWfcE/kX2jpaG1xLyw1P277Y+kP5k5Z9Vvoo1/iZlxI4DQPYzWx8r/GY7
+ fHjlz6lr7pc7DnHAT2R+SRUs/a3M6A83eU5qMfCQ+rupD4BvtqDrwytf75ZDp1Qo9ZmpjzW9razR
+ +jU68WNbn+62PjD6xaNV74lLPqeSvDS93CmlwwuATT/oeqqtWfl6kppLDD5k/+7rI/DB8C8S/Eqy
+ 6hY6PUbJv9v6AHrU8c96PqOu1upaY4fnIPkVCn41XvbATc7LnRk8wIaN/rPS+bCfT89+vr6m1a+r
+ prxhvYZOc1LSn/18YI+jLSh4Bjd1ePHYaVbI+rOfr6+p9ssamVMtNWt+udO8B/yw1wfpn+syraPX
+ Ect/Sv+zoW+OPwOtI9uaNT8qdAo29KlQlT/HZW56hM9KyuYtdtCc0V8GlPoA/Jmfkfb6kf0dwW4+
+ 2d18ALmDYtfrly13BJv4ZEBl30G54+MLw8YePtk9fGSaa1FJ+1N2M3OSHqnuBdv4pFOig+o+tzXK
+ hiW1dsHLLg7wt8Z+XublGoV/4vhPK14A5H2Hmj4iQF6zztfUNWJlEuzkkw6FvbKgysu0yamhk/qC
+ jXzS0HFdVuT5bEOPOtdL8p7r5W6hOeBnst6zWPSwf08adO/msSDrMeeLaQtdC0Q539AxXXniINKH
+ 8GcXFOBTyp4ke4ldiwRZX6F91wnrF7kY1NKQiJ4r2MEnFdp3HbT2vqbi8eBejmD/nlRo3nUg7Liv
+ qng8iYuHLuyi9K/QxOMefQGfYdLHxj0p6IDu88p6bNsTattDWa+r4JuVHoMPSV+gmI/g2xfOeezX
+ kwJFfLTS+Zqdu5qkRu4kEOzXk7NfT/9SlMduPaFuPQPKxvw2Hr7Q5dyDLwCSPkMJ33P0BXzCFkZL
+ liPncwX79SRDbY/g90Vlbjj/sV9PHCp7vmD0MfuDyY/deuJQ2DMCP69if04aOqQo2LEnZ8ce6HJb
+ 9AV8Qpcbuh9bsF9Pdr+e1jXgV3G/JR/qsWt2IffPhr22Zu1bdEjJw3Mf9uuJQa+uaRj/5etd7NMT
+ gy5dA/Xu5BqWy8PGBj05G/TaGtirBK2RJEe+OCDYoScK7bkGujtb0+WoXO6m7wNyJuAj5Iva+pxa
+ 1RGDD/mu0Jf7rOBjj57sHj2S93nBKo/he46cRhRs0ROhtPcFo48v3Czm/XIX8B/gwzX+eSU/5f7Z
+ oCd/jUl//ygCpb2spL0u6mxiF5CcPwpBeH9+U0JmfQXbt9oWDX3sBo75RzEO+OGiD+D3ZfAjd02e
+ QRHin59ExEfDv2j3PnTx2v6xEkT+M3p0GEdBZ6tlDXqT2HdaIO87PIhDbtzTVVN+7Nqt+XdqDvg3
+ 3s9FHfUF+JWatSKaxhkU5H2Hcv6zgt8w8c9OvflmlgJJZ1G1F6p3GuZ9g7wXMOHLF3Wpzb8YdYDN
+ FPzweH8W0JDkuzVvDWhZVNtYCX27i/K7QRHvPbn5fwAAAP//wu11MyplcIprNzOic7kZkZP1BmYU
+ +5/2Cd6M6FxuRuQsvQERY7cGpgPvbSLzuRmRI/VExTaVDpRAacZCrs/jqgUAAAD//wMAqcpME+J6
+ AAA=
+ headers:
+ Allow:
+ - GET, HEAD, OPTIONS
+ CF-Cache-Status:
+ - DYNAMIC
+ CF-RAY:
+ - 85d74473e8ad8453-YVR
+ Connection:
+ - keep-alive
+ Content-Encoding:
+ - gzip
+ Content-Type:
+ - application/json
+ Cross-Origin-Opener-Policy:
+ - same-origin
+ Date:
+ - Fri, 01 Mar 2024 06:59:58 GMT
+ Nel:
+ - '{"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}'
+ Referrer-Policy:
+ - same-origin
+ Report-To:
+ - '{"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1709276398&sid=1b10b0ff-8a76-4548-befa-353fc6c6c045&s=HYLkepa3xuJf8ZP93wYuVeE7fHXoMnoAaRfYOuePI1s%3D"}]}'
+ Reporting-Endpoints:
+ - heroku-nel=https://nel.heroku.com/reports?ts=1709276398&sid=1b10b0ff-8a76-4548-befa-353fc6c6c045&s=HYLkepa3xuJf8ZP93wYuVeE7fHXoMnoAaRfYOuePI1s%3D
+ Server:
+ - cloudflare
+ Transfer-Encoding:
+ - chunked
+ Vary:
+ - Cookie, Origin
+ Via:
+ - 1.1 vegur
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - DENY
+ status:
+ code: 200
+ message: OK
+version: 1
diff --git a/openbb_platform/providers/alpha_vantage/tests/test_alpha_vantage_fetchers.py b/openbb_platform/providers/alpha_vantage/tests/test_alpha_vantage_fetchers.py
index 9c9c23d97cc..f3d7061c1ed 100644
--- a/openbb_platform/providers/alpha_vantage/tests/test_alpha_vantage_fetchers.py
+++ b/openbb_platform/providers/alpha_vantage/tests/test_alpha_vantage_fetchers.py
@@ -2,6 +2,7 @@ from datetime import date
import pytest
from openbb_alpha_vantage.models.equity_historical import AVEquityHistoricalFetcher
+from openbb_alpha_vantage.models.historical_eps import AVHistoricalEpsFetcher
from openbb_core.app.service.user_service import UserService
test_credentials = UserService().default_user_settings.credentials.model_dump(
@@ -32,3 +33,12 @@ def test_av_equity_historical_fetcher(credentials=test_credentials):
fetcher = AVEquityHistoricalFetcher()
result = fetcher.test(params, credentials)
assert result is None
+
+
+@pytest.mark.record_http
+def test_av_historical_eps_fetcher(credentials=test_credentials):
+ params = {"symbol": "AAPL,MSFT", "period": "quarter", "limit": 4}
+
+ fetcher = AVHistoricalEpsFetcher()
+ result = fetcher.test(params, credentials)
+ assert result is None