-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* boilerplate for av provider * adding stock eod for av * ruff n black * changing available functions for better ux * docstring * move debug_mode out of system settings (#5366) * move debug_mode out of system settings * Update router.py * update readme with debug mode * dev_mode hub service + openbb_ namespace to Env * update readme * copy env to avoid problems w global state * Linting * rebuild python interface + fix py38 * Add @classproperty to fetcher for nested return types (#5371) * add classproperty to fetcher and cpi.py * type var bound * validate model in registry map * better exception msg * fix fred mypy and add data_type * typo * specific model validation * specific model validation * reformat error msg * better * msg * add black & ruff to core deps * supress linter errors if not debug mode * pylint + regen fixedincome * py38 compat * fix bug getting provider for placeholder cmds + ruff * Revert "fix bug getting provider for placeholder cmds + ruff" This reverts commit 1328c0b. * ruff * avoid bug for placeholder and no provider * expose available providers in provider interface * poetry toml to match ci ruff version * first we ruff and then we black * add back noqa: E501 to docstrings inside package * use singleton for provider interface: same functionality (#5372) * use singleton for provider interface: same functionality * ruff * docstring typo * update readme with tuna reference * move to correct readme * Merge * Some error handling (#5357) * Removed prints (#5367) * Removed prints * FIxed typing * FIxed typing * Fixed typing * Fixed typing * Fixed typing * Fixed typing * Fixed typing * Fix * Reverted stuff * Feature/move package (#5374) * move package to openbb_sdk * avoid test writing files * black * revert toml changes, will do it in another PR * run build in a separate process * change error msg * rename func * change msg * rename func + msg * change param name * update readme * lazy load some deps * Update README.md * modules is better * doc * ruff * pylint * fix autocomplete (#5383) * Core tests (#5375) * makeing the function easier - @montezdesousa pls review this commit * improve update_provider_choices readbility * unncessary classmethod * command runner tests * fixing wrong attribution * some tests for the charting manager * changing fetcher and models to have a shorter name * @the-prax suggestions * fixing references to av * making function a private fild so the user don't access it * unbreaking changes * Improve snake_case generation * adding av to pyproject.toml * stating the function as a private field while keeping validation for function specific fields --------- Co-authored-by: montezdesousa <[email protected]> Co-authored-by: Diogo Sousa <[email protected]> Co-authored-by: Igor Radovanovic <[email protected]> Co-authored-by: Colin Delahunty <[email protected]>
- Loading branch information
1 parent
172a923
commit 080ecff
Showing
9 changed files
with
305 additions
and
2 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# OpenBB Alpha Vantage Provider | ||
|
||
This extension integrates the Alpha Vantage data provider into the OpenBB SDK. | ||
|
||
## Installation | ||
|
||
To install the extension, run the following command in this folder: | ||
|
||
```bash | ||
pip install . | ||
``` |
20 changes: 20 additions & 0 deletions
20
openbb_sdk/providers/alpha_vantage/openbb_alpha_vantage/__init__.py
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,20 @@ | ||
"""Alpha Vantage Provider module.""" | ||
from openbb_provider.abstract.provider import Provider | ||
|
||
from openbb_alpha_vantage.models.stock_eod import AVStockEODFetcher | ||
|
||
alpha_vantage_provider = Provider( | ||
name="alpha_vantage", | ||
website="https://www.alphavantage.co/documentation/", | ||
description="""Alpha Vantage provides realtime and historical | ||
financial market data through a set of powerful and developer-friendly data APIs | ||
and spreadsheets. From traditional asset classes (e.g., stocks, ETFs, mutual funds) | ||
to economic indicators, from foreign exchange rates to commodities, | ||
from fundamental data to technical indicators, Alpha Vantage | ||
is your one-stop-shop for enterprise-grade global market data delivered through | ||
cloud-based APIs, Excel, and Google Sheets. """, | ||
required_credentials=["api_key"], | ||
fetcher_dict={ | ||
"StockEOD": AVStockEODFetcher, | ||
}, | ||
) |
Empty file.
244 changes: 244 additions & 0 deletions
244
openbb_sdk/providers/alpha_vantage/openbb_alpha_vantage/models/stock_eod.py
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,244 @@ | ||
"""Alpha Vantage Stock End of Day fetcher.""" | ||
|
||
|
||
from datetime import datetime | ||
from typing import Any, Dict, List, Literal, Optional, get_args | ||
|
||
import pandas as pd | ||
from dateutil.relativedelta import relativedelta | ||
from openbb_provider.abstract.fetcher import Fetcher | ||
from openbb_provider.standard_models.stock_eod import StockEODData, StockEODQueryParams | ||
from openbb_provider.utils.descriptions import DATA_DESCRIPTIONS, QUERY_DESCRIPTIONS | ||
from openbb_provider.utils.helpers import get_querystring | ||
from pydantic import Field, NonNegativeFloat, PositiveFloat, root_validator, validator | ||
|
||
|
||
class AVStockEODQueryParams(StockEODQueryParams): | ||
"""Alpha Vantage Stock End of Day Query. | ||
Source: https://www.alphavantage.co/documentation/ | ||
""" | ||
|
||
_function: Literal[ | ||
"TIME_SERIES_INTRADAY", | ||
"TIME_SERIES_DAILY", | ||
"TIME_SERIES_WEEKLY", | ||
"TIME_SERIES_MONTHLY", | ||
"TIME_SERIES_DAILY_ADJUSTED", | ||
"TIME_SERIES_WEEKLY_ADJUSTED", | ||
"TIME_SERIES_MONTHLY_ADJUSTED", | ||
] = Field( | ||
description="The time series of your choice. ", | ||
default="TIME_SERIES_DAILY", | ||
) | ||
period: Literal["intraday", "daily", "weekly", "monthly"] = Field( | ||
default="daily", description=QUERY_DESCRIPTIONS.get("period", "") | ||
) | ||
interval: Optional[Literal["1min", "5min", "15min", "30min", "60min"]] = Field( | ||
description="The interval between two consecutive data points in the time series.", | ||
default="60min", | ||
available_on_functions=["TIME_SERIES_INTRADAY"], | ||
required_on_functions=["TIME_SERIES_INTRADAY"], | ||
) | ||
adjusted: Optional[bool] = Field( | ||
description="Output time series is adjusted by historical split and dividend events.", | ||
default=True, | ||
available_on_functions=["TIME_SERIES_INTRADAY"], | ||
) | ||
extended_hours: Optional[bool] = Field( | ||
description="Extended trading hours during pre-market and after-hours.", | ||
default=False, | ||
available_on_functions=["TIME_SERIES_INTRADAY"], | ||
) | ||
month: Optional[str] = Field( | ||
description="Query a specific month in history (in YYYY-MM format).", | ||
default=None, | ||
available_on_functions=["TIME_SERIES_INTRADAY"], | ||
) | ||
outputsize: Optional[Literal["compact", "full"]] = Field( | ||
description="Compact returns only the latest 100 data points in the intraday " | ||
"time series; full returns trailing 30 days of the most recent intraday data " | ||
"if the month parameter (see above) is not specified, or the full intraday " | ||
"data for a specific month in history if the month parameter is specified.", | ||
default="full", | ||
available_on_functions=[ | ||
"TIME_SERIES_INTRADAY", | ||
"TIME_SERIES_DAILY", | ||
"TIME_SERIES_DAILY_ADJUSTED", | ||
], | ||
) | ||
|
||
@root_validator | ||
def setup_function(cls, values): # pylint: disable=E0213 | ||
"""Set the function based on the period.""" | ||
|
||
functions_based_on_period = { | ||
"intraday": "TIME_SERIES_INTRADAY", | ||
"daily": "TIME_SERIES_DAILY", | ||
"weekly": "TIME_SERIES_WEEKLY", | ||
"monthly": "TIME_SERIES_MONTHLY", | ||
} | ||
values["_function"] = functions_based_on_period[values["period"]] | ||
return values | ||
|
||
@root_validator | ||
def adjusted_function_validate(cls, values): # pylint: disable=E0213 | ||
""" | ||
Validate that the function is adjusted if the `adjusted` parameter is set to True. | ||
""" | ||
|
||
function = values["_function"] | ||
adjusted = values.get("adjusted", None) | ||
|
||
if function != "TIME_SERIES_INTRADAY": | ||
values["_function"] = function if not adjusted else f"{function}_ADJUSTED" | ||
|
||
return values | ||
|
||
@root_validator | ||
def on_functions_validate(cls, values): # pylint: disable=E0213 | ||
""" | ||
Validate that the functions used on custom extra Field attributes | ||
`available_on_functions` and `required_on_functions` are valid functions. | ||
""" | ||
custom_attributes = ["available_on_functions", "required_on_functions"] | ||
|
||
fields = cls.__fields__ | ||
available_functions = get_args(cls.__annotations__["_function"]) | ||
|
||
if values["_function"] not in available_functions: | ||
raise ValueError( | ||
f"Function {values['_function']} must be on of the following: {available_functions}" | ||
) | ||
|
||
def validate_functions(functions: List[str]): | ||
for f in functions: | ||
if f not in available_functions: | ||
raise ValueError( | ||
f"Function {f} must be on of the following: {available_functions}" | ||
) | ||
|
||
for field in fields: | ||
for attr in custom_attributes: | ||
if functions := fields[field].field_info.extra.get(attr, None): | ||
validate_functions(functions) | ||
|
||
return values | ||
|
||
@root_validator | ||
def on_functions_criteria_validate(cls, values): # pylint: disable=E0213 | ||
""" | ||
Validate that the fields are set to None if the function is not available | ||
and that the required fields are not None if the function is required. | ||
""" | ||
|
||
fields = cls.__fields__ | ||
function = values["_function"] | ||
|
||
for field in fields: | ||
if ( | ||
available_on_functions := fields[field].field_info.extra.get( | ||
"available_on_functions", None | ||
) | ||
) and function not in available_on_functions: | ||
values[field] = None | ||
if ( | ||
( | ||
required_on_functions := fields[field].field_info.extra.get( | ||
"required_on_functions", None | ||
) | ||
) | ||
and function in required_on_functions | ||
and values[field] is None | ||
): | ||
raise ValueError(f"Field {field} is required on function {function}") | ||
|
||
return values | ||
|
||
@validator("month") | ||
def month_validate(cls, v): # pylint: disable=E0213 | ||
"""Validate month, check if the month is in YYYY-MM format.""" | ||
if v is not None: | ||
try: | ||
datetime.strptime(v, "%Y-%m") | ||
except ValueError as e: | ||
raise e | ||
return v | ||
|
||
|
||
class AVStockEODData(StockEODData): | ||
"""Alpha Vantage Stock End of Day Data.""" | ||
|
||
class Config: | ||
"""Pydantic alias config using fields dict.""" | ||
|
||
fields = {"date": "timestamp", "adj_close": "adjusted_close"} | ||
|
||
adjusted_close: PositiveFloat = Field( | ||
description=DATA_DESCRIPTIONS.get("adj_close", "") | ||
) | ||
dividend_amount: NonNegativeFloat = Field( | ||
description="Dividend amount paid for the corresponding date.", | ||
) | ||
split_coefficient: NonNegativeFloat = Field( | ||
description="Split coefficient for the corresponding date.", | ||
) | ||
|
||
|
||
class AVStockEODFetcher( | ||
Fetcher[ | ||
AVStockEODQueryParams, | ||
List[AVStockEODData], | ||
] | ||
): | ||
"""Transform the query, extract and transform the data from the Alpha Vantage endpoints.""" | ||
|
||
@staticmethod | ||
def transform_query(params: Dict[str, Any]) -> AVStockEODQueryParams: | ||
"""Transform the query.""" | ||
|
||
transformed_params = params | ||
|
||
now = datetime.now().date() | ||
if params.get("start_date") is None: | ||
transformed_params["start_date"] = now - relativedelta(years=1) | ||
|
||
if params.get("end_date") is None: | ||
transformed_params["end_date"] = now | ||
|
||
return AVStockEODQueryParams(**transformed_params) | ||
|
||
@staticmethod | ||
def extract_data( | ||
query: AVStockEODQueryParams, | ||
credentials: Optional[Dict[str, str]], | ||
**kwargs: Any, | ||
) -> dict: | ||
"""Return the raw data from the Alpha Vantage endpoint.""" | ||
|
||
api_key = credentials.get("alpha_vantage_api_key") if credentials else "" | ||
|
||
query_dict = query.dict() | ||
query_dict["function"] = query_dict.pop("_function") | ||
|
||
query_str = get_querystring(query_dict, ["start_date", "end_date"]) | ||
|
||
url = f"https://www.alphavantage.co/query?{query_str}&datatype=csv&apikey={api_key}" | ||
|
||
data = pd.read_csv(url) | ||
data["timestamp"] = pd.to_datetime(data["timestamp"]) | ||
|
||
data = data[ | ||
(data["timestamp"] >= pd.to_datetime(query.start_date)) | ||
& (data["timestamp"] <= pd.to_datetime(query.end_date)) | ||
] | ||
|
||
return data.to_dict("records") | ||
|
||
@staticmethod | ||
def transform_data( | ||
data: dict, | ||
) -> List[AVStockEODData]: | ||
"""Transform the data to the standard format.""" | ||
|
||
return [AVStockEODData.parse_obj(d) for d in data] |
Empty file.
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,18 @@ | ||
[tool.poetry] | ||
name = "openbb-alpha-vantage" | ||
version = "0.1.0" | ||
description = "" | ||
authors = ["OpenBB Team <[email protected]>"] | ||
readme = "README.md" | ||
packages = [{ include = "openbb_alpha_vantage" }] | ||
|
||
[tool.poetry.dependencies] | ||
python = "^3.8" | ||
openbb-provider = { path = "../../sdk/provider" } | ||
|
||
[build-system] | ||
requires = ["poetry-core"] | ||
build-backend = "poetry.core.masonry.api" | ||
|
||
[tool.poetry.plugins."openbb_provider_extension"] | ||
alpha_vantage = "openbb_alpha_vantage:alpha_vantage_provider" |
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