mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 20:42:26 +00:00
Merge, fix errors, and conflicts
This commit is contained in:
5
.github/release-drafter.yml
vendored
5
.github/release-drafter.yml
vendored
@@ -3,21 +3,16 @@ tag-template: 'v$NEXT_MINOR_VERSION'
|
||||
exclude-contributors:
|
||||
- 'jmaslek'
|
||||
- 'DidierRLopes'
|
||||
- 'JerBouma'
|
||||
- 'deeleeramone'
|
||||
- 'hjoaquim'
|
||||
- 'jose-donato'
|
||||
- 'luqmanbello'
|
||||
- 'martinb-bb'
|
||||
- 'montezdesousa'
|
||||
- 'tehcoderer'
|
||||
- 'Chavithra'
|
||||
- 'colin99d'
|
||||
- 'northern-64bit'
|
||||
- 'piiq'
|
||||
- 'andrewkenreich'
|
||||
- 'IgorWounds'
|
||||
- 'jerryduluk'
|
||||
- 'minhhoang1023'
|
||||
|
||||
template: |
|
||||
|
||||
12
.github/workflows/linting.yml
vendored
12
.github/workflows/linting.yml
vendored
@@ -63,3 +63,15 @@ jobs:
|
||||
uses: docker://avtodev/markdown-lint:v1
|
||||
with:
|
||||
args: "./*.md ./changelogs/*.md ./openbb_terminal/**/*.md ./discordbot/**/*.md"
|
||||
|
||||
json-yaml-validate:
|
||||
name: JSON Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: json-yaml-validate
|
||||
id: json-yaml-validate
|
||||
uses: GrantBirki/json-yaml-validate@v2.0.0
|
||||
with:
|
||||
exclude_file: json_validate_exclude.txt
|
||||
3
CONTRIBUTING.md
vendored
3
CONTRIBUTING.md
vendored
@@ -1212,6 +1212,9 @@ In order to do that, you'll simply need to choose from one the following files:
|
||||
1. [local_credentials.json](openbb_terminal/miscellaneous/models/local_credentials.json) --> credentials that should only be stored locally and not pushed to the [OpenBB Hub](https://my.openbb.co/) like brokerage keys or other very sensitive or personal to the user.
|
||||
2. [hub_credentials.json](openbb_terminal/miscellaneous/models/hub_credentials.json) --> credentials that should be stored in the [OpenBB Hub](https://my.openbb.co/) like API keys to access your favorite providers.
|
||||
|
||||
Then just update [all_api_keys.json](openbb_terminal/miscellaneous/models/all_api_keys.json) with the instructions to get
|
||||
the api key from the data source website. Make sure that this file has the correct `.json` format, otherwise the API keys page in the Hub will break (e.g. in json the last element key-value pair shouldn't be followed by a comma, and the last object in a list of dictionaries should also not be followed by a comma).
|
||||
|
||||
> Note: By differentiating between local and hub credentials, we can ensure that the user's credentials are not pushed to the [OpenBB Hub](https://my.openbb.co/) and are only stored locally. This does not mean that the credentials are not secure in the OpenBB Hub, but rather that the user can choose to store them locally if they wish.
|
||||
|
||||
### Setting and checking API key
|
||||
|
||||
@@ -181,7 +181,7 @@ export default function Table({
|
||||
: columns[0];
|
||||
const indexValue = indexLabel ? row[indexLabel] : null;
|
||||
const value = row[column];
|
||||
const only_numbers = value?.toString().replace(/[^0-9]/g, "") ?? "";
|
||||
const only_numbers = value?.toString()?.split(".")?.pop()?.replace(/[^0-9]/g, "") ?? "";
|
||||
const probablyDate =
|
||||
only_numbers?.length >= 4 &&
|
||||
(includesDateNames(column) ||
|
||||
@@ -219,7 +219,7 @@ export default function Table({
|
||||
const indexValue = indexLabel ? row.original[indexLabel] : null;
|
||||
const value = row.original[column];
|
||||
const valueType = typeof value;
|
||||
const only_numbers = value?.toString().replace(/[^0-9]/g, "") ?? "";
|
||||
const only_numbers = value?.toString()?.split(".")?.pop()?.replace(/[^0-9]/g, "") ?? "";
|
||||
const probablyDate =
|
||||
only_numbers?.length >= 4 &&
|
||||
(includesDateNames(column) ||
|
||||
|
||||
3
json_validate_exclude.txt
vendored
Normal file
3
json_validate_exclude.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
tests/
|
||||
openbb_terminal/miscellaneous/gpt_index/index_0.4.json
|
||||
.devcontainer/devcontainer.json
|
||||
@@ -30,7 +30,7 @@ class ChartStyle:
|
||||
"""
|
||||
|
||||
STYLES_REPO = Path(__file__).parent.parent / "styles"
|
||||
user_styles_directory = STYLES_REPO
|
||||
user_styles_directory: Path = STYLES_REPO
|
||||
|
||||
plt_styles_available: Dict[str, Path] = {}
|
||||
plt_style: str = "dark"
|
||||
@@ -58,7 +58,7 @@ class ChartStyle:
|
||||
def __init__(
|
||||
self,
|
||||
plt_style: Optional[str] = "",
|
||||
user_styles_directory: Optional[Union[str, Path]] = None,
|
||||
user_styles_directory: Optional[Path] = None,
|
||||
):
|
||||
"""Initialize the class.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ from pydantic import BaseModel
|
||||
router = Router(prefix="")
|
||||
|
||||
|
||||
# Remove this once the placeholders are replaced with real commands
|
||||
# Remove this once the placeholders are replaced with real commands.
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
@@ -33,11 +33,10 @@ def const(
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> CommandOutput[BaseModel]:
|
||||
""""""
|
||||
"""Get the constituents of an index."""
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
@router.command(model="CPI")
|
||||
def cpi(
|
||||
cc: CommandContext,
|
||||
@@ -57,7 +56,7 @@ def cpi_options(
|
||||
return CommandOutput(results=Empty())
|
||||
|
||||
|
||||
@router.command(model="MajorIndicesPrice")
|
||||
@router.command(model="MajorIndicesEOD")
|
||||
def index(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
|
||||
@@ -17,7 +17,7 @@ router = Router(prefix="/ca")
|
||||
|
||||
|
||||
@router.command(model="StockPeers")
|
||||
def get(
|
||||
def peers(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
|
||||
@@ -33,6 +33,17 @@ def balance(
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="BalanceSheetGrowth")
|
||||
def balance_growth(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> CommandOutput[BaseModel]:
|
||||
"""Balance Sheet Statement Growth."""
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="DividendCalendar")
|
||||
def cal(
|
||||
cc: CommandContext,
|
||||
@@ -55,6 +66,17 @@ def cash(
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="CashFlowStatementGrowth")
|
||||
def cash_growth(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> CommandOutput[BaseModel]:
|
||||
"""Cash Flow Statement Growth."""
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="ExecutiveCompensation")
|
||||
def comp(
|
||||
cc: CommandContext,
|
||||
@@ -191,6 +213,17 @@ def income(
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="IncomeStatementGrowth")
|
||||
def income_growth(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> CommandOutput[BaseModel]:
|
||||
"""Income Statement Growth."""
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="StockInsiderTrading")
|
||||
def ins(
|
||||
cc: CommandContext,
|
||||
@@ -202,6 +235,17 @@ def ins(
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="InstitutionalOwnership")
|
||||
def ins_own(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> CommandOutput[BaseModel]:
|
||||
"""Institutional Ownership."""
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command
|
||||
def key() -> CommandOutput[Empty]: # type: ignore
|
||||
return CommandOutput(results=Empty())
|
||||
@@ -251,14 +295,14 @@ def overview(
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="InstitutionalOwnership")
|
||||
@router.command(model="StockOwnership")
|
||||
def own(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> CommandOutput[BaseModel]:
|
||||
"""Institutional Ownership."""
|
||||
"""Stock Ownership."""
|
||||
return CommandOutput(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# flake8: noqa
|
||||
from typing import List
|
||||
from openbb_core.app.static.app_factory import create_app as __create_app
|
||||
|
||||
sdk = __create_app()
|
||||
obb = sdk
|
||||
|
||||
|
||||
def _rebuild_python_interface() -> None:
|
||||
def _rebuild_python_interface(*args, lint=True) -> None:
|
||||
"""Rebuild the Python SDK."""
|
||||
from openbb_core.app.static.package_builder import ( # pylint: disable=import-outside-toplevel
|
||||
PackageBuilder,
|
||||
)
|
||||
|
||||
PackageBuilder.build()
|
||||
PackageBuilder.build(modules=list(args), lint=lint)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
"""Benzinga provider module."""
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_benzinga.models.global_news import BenzingaGlobalNewsFetcher
|
||||
from openbb_benzinga.models.stock_news import BenzingaStockNewsFetcher
|
||||
|
||||
benzinga_provider = Provider(
|
||||
name="benzinga",
|
||||
website="https://www.benzinga.com/",
|
||||
description="""Benzinga is a financial data provider that offers an API
|
||||
focused on information that moves the market.""",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_dict={
|
||||
"GlobalNews": BenzingaGlobalNewsFetcher,
|
||||
"StockNews": BenzingaStockNewsFetcher,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -2,79 +2,98 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.global_news import GlobalNewsData, GlobalNewsQueryParams
|
||||
from pydantic import Field
|
||||
from openbb_provider.models.stock_news import StockNewsData
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import Field, validator
|
||||
|
||||
from openbb_benzinga.utils.helpers import BenzingaBaseNewsData, get_data
|
||||
from openbb_benzinga.utils.helpers import BenzingaImage, get_data
|
||||
|
||||
|
||||
class BenzingaGlobalNewsQueryParams(QueryParams):
|
||||
class BenzingaGlobalNewsQueryParams(GlobalNewsQueryParams):
|
||||
"""Benzinga Global News query.
|
||||
|
||||
Source: https://docs.benzinga.io/benzinga/newsfeed-v2.html
|
||||
|
||||
Parameter
|
||||
---------
|
||||
page : int (default: 0)
|
||||
The page of the data to retrieve.
|
||||
pageSize : int (default: 15)
|
||||
The number of results to return per page.
|
||||
displayOutput : str (default: "headline")
|
||||
The type of data to return. Options are "headline", "summary", "full", "all".
|
||||
date : Optional[datetime]
|
||||
The date of the news to retrieve.
|
||||
dateFrom : Optional[datetime]
|
||||
The start date of the news to retrieve.
|
||||
dateTo : Optional[datetime]
|
||||
The end date of the news to retrieve.
|
||||
updatedSince : Optional[int]
|
||||
The number of seconds since the news was updated.
|
||||
publishedSince : Optional[int]
|
||||
The number of seconds since the news was published.
|
||||
sort : Optional[str]
|
||||
The order in which to sort the news. Options are:
|
||||
"published_at", "updated_at", "title", "author", "channel", "ticker", "topic", "content_type".
|
||||
isin : Optional[str]
|
||||
The ISIN of the news to retrieve.
|
||||
cusip : Optional[str]
|
||||
The CUSIP of the news to retrieve.
|
||||
tickers : Optional[str]
|
||||
The tickers of the news to retrieve.
|
||||
channels : Optional[str]
|
||||
The channels of the news to retrieve.
|
||||
topics : Optional[str]
|
||||
The topics of the news to retrieve.
|
||||
authors : Optional[str]
|
||||
The authors of the news to retrieve.
|
||||
content_types : Optional[str]
|
||||
The content types of the news to retrieve.
|
||||
"""
|
||||
|
||||
page: int = Field(default=0)
|
||||
pageSize: int = Field(default=15)
|
||||
displayOutput: str = Field(default="headline")
|
||||
date: Optional[datetime] = None
|
||||
dateFrom: Optional[datetime] = None
|
||||
dateTo: Optional[datetime] = None
|
||||
updatedSince: Optional[int] = None
|
||||
publishedSince: Optional[int] = None
|
||||
sort: Optional[str] = None
|
||||
isin: Optional[str] = None
|
||||
cusip: Optional[str] = None
|
||||
tickers: Optional[str] = None
|
||||
channels: Optional[str] = None
|
||||
topics: Optional[str] = None
|
||||
authors: Optional[str] = None
|
||||
content_types: Optional[str] = None
|
||||
pageSize: int = Field(
|
||||
default=15, description="The number of results to return per page."
|
||||
)
|
||||
displayOutput: Literal["headline", "summary", "full", "all"] = Field(
|
||||
default="headline", description="The type of data to return."
|
||||
)
|
||||
date: Optional[datetime] = Field(
|
||||
default=None, description="The date of the news to retrieve."
|
||||
)
|
||||
dateFrom: Optional[datetime] = Field(
|
||||
default=None, description="The start date of the news to retrieve."
|
||||
)
|
||||
dateTo: Optional[datetime] = Field(
|
||||
default=None, description="The end date of the news to retrieve."
|
||||
)
|
||||
updatedSince: Optional[int] = Field(
|
||||
default=None,
|
||||
description="The number of seconds since the news was updated.",
|
||||
)
|
||||
publishedSince: Optional[int] = Field(
|
||||
default=None,
|
||||
description="The number of seconds since the news was published.",
|
||||
)
|
||||
sort: Optional[
|
||||
Literal[
|
||||
"published_at",
|
||||
"updated_at",
|
||||
"title",
|
||||
"author",
|
||||
"channel",
|
||||
"ticker",
|
||||
"topic",
|
||||
"content_type",
|
||||
]
|
||||
] = Field(
|
||||
default=None,
|
||||
description="The order in which to sort the news. Options are: published_at,"
|
||||
" updated_at, title, author, channel, ticker, topic, content_type.",
|
||||
)
|
||||
isin: Optional[str] = Field(
|
||||
default=None, description="The ISIN of the news to retrieve."
|
||||
)
|
||||
cusip: Optional[str] = Field(
|
||||
default=None, description="The CUSIP of the news to retrieve."
|
||||
)
|
||||
tickers: Optional[str] = Field(
|
||||
default=None, description="The tickers of the news to retrieve."
|
||||
)
|
||||
channels: Optional[str] = Field(
|
||||
default=None, description="The channels of the news to retrieve."
|
||||
)
|
||||
topics: Optional[str] = Field(
|
||||
default=None, description="The topics of the news to retrieve."
|
||||
)
|
||||
authors: Optional[str] = Field(
|
||||
default=None, description="The authors of the news to retrieve."
|
||||
)
|
||||
content_types: Optional[str] = Field(
|
||||
default=None, description="The content types of the news to retrieve."
|
||||
)
|
||||
|
||||
|
||||
class BenzingaGlobalNewsData(BenzingaBaseNewsData):
|
||||
url: str
|
||||
class BenzingaGlobalNewsData(StockNewsData):
|
||||
"""Benzinga Global News data."""
|
||||
|
||||
class Config:
|
||||
fields = {"date": "created", "text": "body"}
|
||||
|
||||
image: List[BenzingaImage] = Field(
|
||||
description="The images associated with the news."
|
||||
)
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%a, %d %b %Y %H:%M:%S %z")
|
||||
|
||||
|
||||
class BenzingaGlobalNewsFetcher(
|
||||
@@ -86,24 +105,21 @@ class BenzingaGlobalNewsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: GlobalNewsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> BenzingaGlobalNewsQueryParams:
|
||||
return BenzingaGlobalNewsQueryParams(
|
||||
page=query.page, **extra_params if extra_params else {}
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> BenzingaGlobalNewsQueryParams:
|
||||
return BenzingaGlobalNewsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: BenzingaGlobalNewsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: BenzingaGlobalNewsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[BenzingaGlobalNewsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("benzinga_api_key")
|
||||
api_key = credentials.get("benzinga_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://api.benzinga.com/api/v2/news"
|
||||
querystring = get_querystring(query.dict(), [])
|
||||
querystring = get_querystring(query.dict(by_alias=True), [])
|
||||
request_url = f"{base_url}?{querystring}&token={api_key}"
|
||||
data = get_data(request_url)
|
||||
data = get_data(request_url, **kwargs)
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No news found")
|
||||
@@ -113,6 +129,5 @@ class BenzingaGlobalNewsFetcher(
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[BenzingaGlobalNewsData],
|
||||
) -> List[GlobalNewsData]:
|
||||
processors = {"image": lambda x: "" if x == [] else x[0].url}
|
||||
return data_transformer(data, GlobalNewsData, processors)
|
||||
) -> List[BenzingaGlobalNewsData]:
|
||||
return data
|
||||
|
||||
@@ -2,80 +2,95 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.stock_news import StockNewsData, StockNewsQueryParams
|
||||
from pydantic import Field
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import Field, validator
|
||||
|
||||
from openbb_benzinga.utils.helpers import BenzingaBaseNewsData, get_data
|
||||
from openbb_benzinga.utils.helpers import BenzingaImage, get_data
|
||||
|
||||
|
||||
class BenzingaStockNewsQueryParams(QueryParams):
|
||||
class BenzingaStockNewsQueryParams(StockNewsQueryParams):
|
||||
"""Benzinga Stock News query.
|
||||
|
||||
Source: https://docs.benzinga.io/benzinga/newsfeed-v2.html
|
||||
|
||||
Parameter
|
||||
---------
|
||||
page : int (default: 0)
|
||||
The page of the data to retrieve.
|
||||
symbols: str
|
||||
The symbols of the companies.
|
||||
pageSize : int (default: 15)
|
||||
The number of results to return per page.
|
||||
headline : str
|
||||
The type of data to return. Options are "headline", "summary", "full", "all".
|
||||
date : Optional[datetime]
|
||||
The date of the news to retrieve.
|
||||
dateFrom : Optional[datetime]
|
||||
The start date of the news to retrieve.
|
||||
dateTo : Optional[datetime]
|
||||
The end date of the news to retrieve.
|
||||
updatedSince : Optional[int]
|
||||
The number of seconds since the news was updated.
|
||||
publishedSince : Optional[int]
|
||||
The number of seconds since the news was published.
|
||||
sort : Optional[str]
|
||||
The order in which to sort the news. Options are:
|
||||
"published_at", "updated_at", "title", "author", "channel", "ticker", "topic", "content_type".
|
||||
isin : Optional[str]
|
||||
The ISIN of the news to retrieve.
|
||||
cusip : Optional[str]
|
||||
The CUSIP of the news to retrieve.
|
||||
channels : Optional[str]
|
||||
The channels of the news to retrieve.
|
||||
topics : Optional[str]
|
||||
The topics of the news to retrieve.
|
||||
authors : Optional[str]
|
||||
The authors of the news to retrieve.
|
||||
content_types : Optional[str]
|
||||
The content types of the news to retrieve.
|
||||
"""
|
||||
|
||||
tickers: str = Field(alias="symbols")
|
||||
page: int = Field(default=0)
|
||||
pageSize: int = Field(default=15)
|
||||
displayOutput: str = Field(default="headline")
|
||||
date: Optional[datetime] = None
|
||||
dateFrom: Optional[datetime] = None
|
||||
dateTo: Optional[datetime] = None
|
||||
updatedSince: Optional[int] = None
|
||||
publishedSince: Optional[int] = None
|
||||
sort: Optional[str] = None
|
||||
isin: Optional[str] = None
|
||||
cusip: Optional[str] = None
|
||||
channels: Optional[str] = None
|
||||
topics: Optional[str] = None
|
||||
authors: Optional[str] = None
|
||||
content_types: Optional[str] = None
|
||||
class Config:
|
||||
fields = {"symbols": "tickers", "limit": "pageSize"}
|
||||
|
||||
displayOutput: Literal["headline", "summary", "full", "all"] = Field(
|
||||
default="headline", description="The type of data to return."
|
||||
)
|
||||
date: Optional[datetime] = Field(
|
||||
default=None, description="The date of the news to retrieve."
|
||||
)
|
||||
dateFrom: Optional[datetime] = Field(
|
||||
default=None, description="The start date of the news to retrieve."
|
||||
)
|
||||
dateTo: Optional[datetime] = Field(
|
||||
default=None, description="The end date of the news to retrieve."
|
||||
)
|
||||
updatedSince: Optional[int] = Field(
|
||||
default=None,
|
||||
description="The number of seconds since the news was updated.",
|
||||
)
|
||||
publishedSince: Optional[int] = Field(
|
||||
default=None,
|
||||
description="The number of seconds since the news was published.",
|
||||
)
|
||||
sort: Optional[
|
||||
Literal[
|
||||
"published_at",
|
||||
"updated_at",
|
||||
"title",
|
||||
"author",
|
||||
"channel",
|
||||
"ticker",
|
||||
"topic",
|
||||
"content_type",
|
||||
]
|
||||
] = Field(
|
||||
default=None,
|
||||
description="The order in which to sort the news. Options are: published_at,"
|
||||
" updated_at, title, author, channel, ticker, topic, content_type.",
|
||||
)
|
||||
isin: Optional[str] = Field(
|
||||
default=None, description="The ISIN of the news to retrieve."
|
||||
)
|
||||
cusip: Optional[str] = Field(
|
||||
default=None, description="The CUSIP of the news to retrieve."
|
||||
)
|
||||
channels: Optional[str] = Field(
|
||||
default=None, description="The channels of the news to retrieve."
|
||||
)
|
||||
topics: Optional[str] = Field(
|
||||
default=None, description="The topics of the news to retrieve."
|
||||
)
|
||||
authors: Optional[str] = Field(
|
||||
default=None, description="The authors of the news to retrieve."
|
||||
)
|
||||
content_types: Optional[str] = Field(
|
||||
default=None, description="The content types of the news to retrieve."
|
||||
)
|
||||
|
||||
|
||||
class BenzingaStockNewsData(BenzingaBaseNewsData):
|
||||
class BenzingaStockNewsData(StockNewsData):
|
||||
"""Benzinga Stock News data."""
|
||||
|
||||
class Config:
|
||||
fields = {"date": "created", "text": "body"}
|
||||
|
||||
image: List[BenzingaImage] = Field(
|
||||
description="The images associated with the news."
|
||||
)
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%a, %d %b %Y %H:%M:%S %z")
|
||||
|
||||
|
||||
class BenzingaStockNewsFetcher(
|
||||
Fetcher[
|
||||
@@ -86,26 +101,21 @@ class BenzingaStockNewsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockNewsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> BenzingaStockNewsQueryParams:
|
||||
return BenzingaStockNewsQueryParams(
|
||||
page=query.page,
|
||||
symbols=query.symbols, # type: ignore
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> BenzingaStockNewsQueryParams:
|
||||
return BenzingaStockNewsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: BenzingaStockNewsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: BenzingaStockNewsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[BenzingaStockNewsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("benzinga_api_key")
|
||||
api_key = credentials.get("benzinga_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://api.benzinga.com/api/v2/news"
|
||||
querystring = get_querystring(query.dict(), [])
|
||||
querystring = get_querystring(query.dict(by_alias=True), [])
|
||||
request_url = f"{base_url}?{querystring}&token={api_key}"
|
||||
data = get_data(request_url)
|
||||
data = get_data(request_url, **kwargs)
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No news found")
|
||||
@@ -113,6 +123,8 @@ class BenzingaStockNewsFetcher(
|
||||
return [BenzingaStockNewsData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[BenzingaStockNewsData]) -> List[StockNewsData]:
|
||||
processors = {"image": lambda x: "" if x == [] else x[0].url}
|
||||
return data_transformer(data, StockNewsData, processors)
|
||||
def transform_data(
|
||||
data: List[BenzingaStockNewsData],
|
||||
) -> List[BenzingaStockNewsData]:
|
||||
# {"image": lambda x: "" if x == [] else x[0].url}
|
||||
return data
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
"""Benzinga provider module."""
|
||||
|
||||
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_benzinga.models.global_news import BenzingaGlobalNewsFetcher
|
||||
from openbb_benzinga.models.stock_news import BenzingaStockNewsFetcher
|
||||
|
||||
# mypy: disable-error-code="list-item"
|
||||
|
||||
|
||||
benzinga_provider = Provider(
|
||||
name="benzinga",
|
||||
description="Provider for Benzinga.",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_list=[BenzingaGlobalNewsFetcher, BenzingaStockNewsFetcher],
|
||||
)
|
||||
@@ -1,16 +1,16 @@
|
||||
"""Benzinga Helpers."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
from openbb_provider.abstract.data import Data
|
||||
from pydantic import BaseModel, Field, validator
|
||||
from openbb_provider import helpers
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
def get_data(url: str) -> dict:
|
||||
r = requests.get(url, timeout=10, headers={"accept": "application/json"})
|
||||
def get_data(url: str, **kwargs: Any) -> dict:
|
||||
r = helpers.make_request(
|
||||
url, timeout=10, headers={"accept": "application/json"}, **kwargs
|
||||
)
|
||||
if r.status_code != 200:
|
||||
data = r.json()
|
||||
if data == ['Access denied for user 0 "anonymous"']:
|
||||
@@ -26,15 +26,3 @@ def get_data(url: str) -> dict:
|
||||
class BenzingaImage(BaseModel):
|
||||
size: str
|
||||
url: str
|
||||
|
||||
|
||||
class BenzingaBaseNewsData(Data):
|
||||
created: datetime = Field(alias="date")
|
||||
title: str
|
||||
image: List[BenzingaImage]
|
||||
body: str = Field(alias="text")
|
||||
url: str
|
||||
|
||||
@validator("created", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%a, %d %b %Y %H:%M:%S %z")
|
||||
|
||||
245
openbb_sdk/providers/benzinga/poetry.lock
generated
vendored
245
openbb_sdk/providers/benzinga/poetry.lock
generated
vendored
@@ -1,245 +0,0 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2023.5.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"},
|
||||
{file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.2.0"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
|
||||
{file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openbb-provider"
|
||||
version = "0.2.0"
|
||||
description = ""
|
||||
optional = false
|
||||
python-versions = "^3.8"
|
||||
files = []
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = {version = "^1.10", extras = ["dotenv"]}
|
||||
requests = "^2.31.0"
|
||||
urllib3 = "<2.0.0"
|
||||
|
||||
[package.source]
|
||||
type = "directory"
|
||||
url = "../../sdk/provider"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "1.10.11"
|
||||
description = "Data validation and settings management using python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pydantic-1.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ff44c5e89315b15ff1f7fdaf9853770b810936d6b01a7bcecaa227d2f8fe444f"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6c098d4ab5e2d5b3984d3cb2527e2d6099d3de85630c8934efcfdc348a9760e"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16928fdc9cb273c6af00d9d5045434c39afba5f42325fb990add2c241402d151"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0588788a9a85f3e5e9ebca14211a496409cb3deca5b6971ff37c556d581854e7"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9baf78b31da2dc3d3f346ef18e58ec5f12f5aaa17ac517e2ffd026a92a87588"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:373c0840f5c2b5b1ccadd9286782852b901055998136287828731868027a724f"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:c3339a46bbe6013ef7bdd2844679bfe500347ac5742cd4019a88312aa58a9847"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:08a6c32e1c3809fbc49debb96bf833164f3438b3696abf0fbeceb417d123e6eb"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a451ccab49971af043ec4e0d207cbc8cbe53dbf148ef9f19599024076fe9c25b"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b02d24f7b2b365fed586ed73582c20f353a4c50e4be9ba2c57ab96f8091ddae"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f34739a89260dfa420aa3cbd069fbcc794b25bbe5c0a214f8fb29e363484b66"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e297897eb4bebde985f72a46a7552a7556a3dd11e7f76acda0c1093e3dbcf216"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d185819a7a059550ecb85d5134e7d40f2565f3dd94cfd870132c5f91a89cf58c"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:4400015f15c9b464c9db2d5d951b6a780102cfa5870f2c036d37c23b56f7fc1b"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2417de68290434461a266271fc57274a138510dca19982336639484c73a07af6"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:331c031ba1554b974c98679bd0780d89670d6fd6f53f5d70b10bdc9addee1713"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8268a735a14c308923e8958363e3a3404f6834bb98c11f5ab43251a4e410170c"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:44e51ba599c3ef227e168424e220cd3e544288c57829520dc90ea9cb190c3248"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d7781f1d13b19700b7949c5a639c764a077cbbdd4322ed505b449d3ca8edcb36"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-win_amd64.whl", hash = "sha256:7522a7666157aa22b812ce14c827574ddccc94f361237ca6ea8bb0d5c38f1629"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc64eab9b19cd794a380179ac0e6752335e9555d214cfcb755820333c0784cb3"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8dc77064471780262b6a68fe67e013298d130414d5aaf9b562c33987dbd2cf4f"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe429898f2c9dd209bd0632a606bddc06f8bce081bbd03d1c775a45886e2c1cb"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:192c608ad002a748e4a0bed2ddbcd98f9b56df50a7c24d9a931a8c5dd053bd3d"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ef55392ec4bb5721f4ded1096241e4b7151ba6d50a50a80a2526c854f42e6a2f"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:41e0bb6efe86281623abbeeb0be64eab740c865388ee934cd3e6a358784aca6e"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:265a60da42f9f27e0b1014eab8acd3e53bd0bad5c5b4884e98a55f8f596b2c19"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:469adf96c8e2c2bbfa655fc7735a2a82f4c543d9fee97bd113a7fb509bf5e622"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e6cbfbd010b14c8a905a7b10f9fe090068d1744d46f9e0c021db28daeb8b6de1"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abade85268cc92dff86d6effcd917893130f0ff516f3d637f50dadc22ae93999"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9738b0f2e6c70f44ee0de53f2089d6002b10c33264abee07bdb5c7f03038303"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:787cf23e5a0cde753f2eabac1b2e73ae3844eb873fd1f5bdbff3048d8dbb7604"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:174899023337b9fc685ac8adaa7b047050616136ccd30e9070627c1aaab53a13"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:1954f8778489a04b245a1e7b8b22a9d3ea8ef49337285693cf6959e4b757535e"},
|
||||
{file = "pydantic-1.10.11-py3-none-any.whl", hash = "sha256:008c5e266c8aada206d0627a011504e14268a62091450210eda7c07fabe6963e"},
|
||||
{file = "pydantic-1.10.11.tar.gz", hash = "sha256:f66d479cf7eb331372c470614be6511eae96f1f120344c25f3f9bb59fb1b5528"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""}
|
||||
typing-extensions = ">=4.2.0"
|
||||
|
||||
[package.extras]
|
||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||
email = ["email-validator (>=1.0.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.0"
|
||||
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
|
||||
{file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
description = "Python HTTP for Humans."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = ">=2,<4"
|
||||
idna = ">=2.5,<4"
|
||||
urllib3 = ">=1.21.1,<3"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.7.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
|
||||
{file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.16"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
files = [
|
||||
{file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"},
|
||||
{file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "26269b8a989dcc6ac67961b7a43d485d231c8ac878265ac90f310ced959fc532"
|
||||
2
openbb_sdk/providers/benzinga/pyproject.toml
vendored
2
openbb_sdk/providers/benzinga/pyproject.toml
vendored
@@ -15,4 +15,4 @@ requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."openbb_provider_extension"]
|
||||
benzinga = "openbb_benzinga.provider:benzinga_provider"
|
||||
benzinga = "openbb_benzinga:benzinga_provider"
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
"""FMP Provider module."""
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_fmp.models.analyst_estimates import FMPAnalystEstimatesFetcher
|
||||
from openbb_fmp.models.available_indices import FMPAvailableIndicesFetcher
|
||||
from openbb_fmp.models.balance_sheet import FMPBalanceSheetFetcher
|
||||
from openbb_fmp.models.balance_sheet_growth import FMPBalanceSheetGrowthFetcher
|
||||
from openbb_fmp.models.cash_flow import FMPCashFlowStatementFetcher
|
||||
from openbb_fmp.models.cash_flow_growth import FMPCashFlowStatementGrowthFetcher
|
||||
from openbb_fmp.models.company_overview import FMPCompanyOverviewFetcher
|
||||
from openbb_fmp.models.crypto_eod import FMPCryptoEODFetcher
|
||||
from openbb_fmp.models.dividend_calendar import FMPDividendCalendarFetcher
|
||||
from openbb_fmp.models.earnings_calendar import FMPEarningsCalendarFetcher
|
||||
from openbb_fmp.models.earnings_call_transcript import FMPEarningsCallTranscriptFetcher
|
||||
from openbb_fmp.models.esg_risk_rating import FMPESGRiskRatingFetcher
|
||||
from openbb_fmp.models.esg_score import FMPESGScoreFetcher
|
||||
from openbb_fmp.models.esg_sector import FMPESGSectorFetcher
|
||||
from openbb_fmp.models.executive_compensation import FMPExecutiveCompensationFetcher
|
||||
from openbb_fmp.models.forex_eod import FMPForexEODFetcher
|
||||
from openbb_fmp.models.forex_pairs import FMPForexPairsFetcher
|
||||
from openbb_fmp.models.global_news import FMPGlobalNewsFetcher
|
||||
from openbb_fmp.models.historical_dividends import FMPHistoricalDividendsFetcher
|
||||
from openbb_fmp.models.historical_employees import FMPHistoricalEmployeesFetcher
|
||||
from openbb_fmp.models.historical_stock_splits import FMPHistoricalStockSplitsFetcher
|
||||
from openbb_fmp.models.income_statement import FMPIncomeStatementFetcher
|
||||
from openbb_fmp.models.income_statement_growth import FMPIncomeStatementGrowthFetcher
|
||||
from openbb_fmp.models.institutional_ownership import FMPInstitutionalOwnershipFetcher
|
||||
from openbb_fmp.models.key_executives import FMPKeyExecutivesFetcher
|
||||
from openbb_fmp.models.key_metrics import FMPKeyMetricsFetcher
|
||||
from openbb_fmp.models.major_indices_constituents import (
|
||||
FMPMajorIndicesConstituentsFetcher,
|
||||
)
|
||||
from openbb_fmp.models.major_indices_eod import FMPMajorIndicesEODFetcher
|
||||
from openbb_fmp.models.price_target import FMPPriceTargetFetcher
|
||||
from openbb_fmp.models.price_target_consensus import FMPPriceTargetConsensusFetcher
|
||||
from openbb_fmp.models.revenue_business_line import FMPRevenueBusinessLineFetcher
|
||||
from openbb_fmp.models.revenue_geographic import FMPRevenueGeographicFetcher
|
||||
from openbb_fmp.models.risk_premium import FMPRiskPremiumFetcher
|
||||
from openbb_fmp.models.sec_filings import FMPSECFilingsFetcher
|
||||
from openbb_fmp.models.share_statistics import FMPShareStatisticsFetcher
|
||||
from openbb_fmp.models.stock_eod import FMPStockEODFetcher
|
||||
from openbb_fmp.models.stock_insider_trading import FMPStockInsiderTradingFetcher
|
||||
from openbb_fmp.models.stock_multiples import FMPStockMultiplesFetcher
|
||||
from openbb_fmp.models.stock_news import FMPStockNewsFetcher
|
||||
from openbb_fmp.models.stock_ownership import FMPStockOwnershipFetcher
|
||||
from openbb_fmp.models.stock_peers import FMPStockPeersFetcher
|
||||
from openbb_fmp.models.stock_splits import FMPStockSplitCalendarFetcher
|
||||
from openbb_fmp.models.treasury_rates import FMPTreasuryRatesFetcher
|
||||
|
||||
fmp_provider = Provider(
|
||||
name="fmp",
|
||||
website="https://financialmodelingprep.com/",
|
||||
description="""Financial Modeling Prep is a new concept that informs you about
|
||||
stock market information (news, currencies, and stock prices).""",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_dict={
|
||||
"KeyExecutives": FMPKeyExecutivesFetcher,
|
||||
"StockEOD": FMPStockEODFetcher,
|
||||
"GlobalNews": FMPGlobalNewsFetcher,
|
||||
"StockNews": FMPStockNewsFetcher,
|
||||
"IncomeStatement": FMPIncomeStatementFetcher,
|
||||
"IncomeStatementGrowth": FMPIncomeStatementGrowthFetcher,
|
||||
"BalanceSheet": FMPBalanceSheetFetcher,
|
||||
"BalanceSheetGrowth": FMPBalanceSheetGrowthFetcher,
|
||||
"CashFlowStatement": FMPCashFlowStatementFetcher,
|
||||
"CashFlowStatementGrowth": FMPCashFlowStatementGrowthFetcher,
|
||||
"ShareStatistics": FMPShareStatisticsFetcher,
|
||||
"MajorIndicesEOD": FMPMajorIndicesEODFetcher,
|
||||
"RevenueGeographic": FMPRevenueGeographicFetcher,
|
||||
"RevenueBusinessLine": FMPRevenueBusinessLineFetcher,
|
||||
"InstitutionalOwnership": FMPInstitutionalOwnershipFetcher,
|
||||
"CompanyOverview": FMPCompanyOverviewFetcher,
|
||||
"StockInsiderTrading": FMPStockInsiderTradingFetcher,
|
||||
"StockOwnership": FMPStockOwnershipFetcher,
|
||||
"ESGScore": FMPESGScoreFetcher,
|
||||
"ESGSector": FMPESGSectorFetcher,
|
||||
"ESGRiskRating": FMPESGRiskRatingFetcher,
|
||||
"PriceTargetConsensus": FMPPriceTargetConsensusFetcher,
|
||||
"PriceTarget": FMPPriceTargetFetcher,
|
||||
"AnalystEstimates": FMPAnalystEstimatesFetcher,
|
||||
"EarningsCalendar": FMPEarningsCalendarFetcher,
|
||||
"EarningsCallTranscript": FMPEarningsCallTranscriptFetcher,
|
||||
"HistoricalStockSplits": FMPHistoricalStockSplitsFetcher,
|
||||
"StockSplitCalendar": FMPStockSplitCalendarFetcher,
|
||||
"HistoricalDividends": FMPHistoricalDividendsFetcher,
|
||||
"KeyMetrics": FMPKeyMetricsFetcher,
|
||||
"SECFilings": FMPSECFilingsFetcher,
|
||||
"TreasuryRates": FMPTreasuryRatesFetcher,
|
||||
"ExecutiveCompensation": FMPExecutiveCompensationFetcher,
|
||||
"CryptoEOD": FMPCryptoEODFetcher,
|
||||
"ForexEOD": FMPForexEODFetcher,
|
||||
"ForexPairs": FMPForexPairsFetcher,
|
||||
"StockPeers": FMPStockPeersFetcher,
|
||||
"StockMultiples": FMPStockMultiplesFetcher,
|
||||
"HistoricalEmployees": FMPHistoricalEmployeesFetcher,
|
||||
"AvailableIndices": FMPAvailableIndicesFetcher,
|
||||
"RiskPremium": FMPRiskPremiumFetcher,
|
||||
"MajorIndicesConstituents": FMPMajorIndicesConstituentsFetcher,
|
||||
"DividendCalendar": FMPDividendCalendarFetcher,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
"""FMP Analyst Estimates fetcher."""
|
||||
|
||||
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.analyst_estimates import (
|
||||
AnalystEstimatesData,
|
||||
AnalystEstimatesQueryParams,
|
||||
@@ -16,44 +13,38 @@ from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPAnalystEstimatesQueryParams(AnalystEstimatesQueryParams):
|
||||
"""FMP Analysts Estimates query.
|
||||
"""FMP Analysts Estimates Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/analyst-estimates-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
period: Literal["quarter", "annual"]
|
||||
The period of the analyst estimates.
|
||||
limit : int
|
||||
The limit number of the amount of returned estimates.
|
||||
"""
|
||||
|
||||
|
||||
class FMPAnalystEstimatesData(Data):
|
||||
symbol: str
|
||||
date: dateType
|
||||
estimatedRevenueLow: int
|
||||
estimatedRevenueHigh: int
|
||||
estimatedRevenueAvg: int
|
||||
estimatedEbitdaLow: int
|
||||
estimatedEbitdaHigh: int
|
||||
estimatedEbitdaAvg: int
|
||||
estimatedEbitLow: int
|
||||
estimatedEbitHigh: int
|
||||
estimatedEbitAvg: int
|
||||
estimatedNetIncomeLow: int
|
||||
estimatedNetIncomeHigh: int
|
||||
estimatedNetIncomeAvg: int
|
||||
estimatedSgaExpenseLow: int
|
||||
estimatedSgaExpenseHigh: int
|
||||
estimatedSgaExpenseAvg: int
|
||||
estimatedEpsAvg: float
|
||||
estimatedEpsHigh: float
|
||||
estimatedEpsLow: float
|
||||
numberAnalystEstimatedRevenue: int
|
||||
numberAnalystsEstimatedEps: int
|
||||
class FMPAnalystEstimatesData(AnalystEstimatesData):
|
||||
"""FMP Analyst Estimates Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"estimated_revenue_low": "estimatedRevenueLow",
|
||||
"estimated_revenue_high": "estimatedRevenueHigh",
|
||||
"estimated_revenue_avg": "estimatedRevenueAvg",
|
||||
"estimated_ebitda_low": "estimatedEbitdaLow",
|
||||
"estimated_ebitda_high": "estimatedEbitdaHigh",
|
||||
"estimated_ebitda_avg": "estimatedEbitdaAvg",
|
||||
"estimated_ebit_low": "estimatedEbitLow",
|
||||
"estimated_ebit_high": "estimatedEbitHigh",
|
||||
"estimated_ebit_avg": "estimatedEbitAvg",
|
||||
"estimated_net_income_low": "estimatedNetIncomeLow",
|
||||
"estimated_net_income_high": "estimatedNetIncomeHigh",
|
||||
"estimated_net_income_avg": "estimatedNetIncomeAvg",
|
||||
"estimated_sga_expense_low": "estimatedSgaExpenseLow",
|
||||
"estimated_sga_expense_high": "estimatedSgaExpenseHigh",
|
||||
"estimated_sga_expense_avg": "estimatedSgaExpenseAvg",
|
||||
"estimated_eps_avg": "estimatedEpsAvg",
|
||||
"estimated_eps_high": "estimatedEpsHigh",
|
||||
"estimated_eps_low": "estimatedEpsLow",
|
||||
"number_analyst_estimated_revenue": "numberAnalystEstimatedRevenue",
|
||||
"number_analysts_estimated_eps": "numberAnalystsEstimatedEps",
|
||||
}
|
||||
|
||||
|
||||
class FMPAnalystEstimatesFetcher(
|
||||
@@ -65,27 +56,26 @@ class FMPAnalystEstimatesFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: AnalystEstimatesQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPAnalystEstimatesQueryParams:
|
||||
return FMPAnalystEstimatesQueryParams(
|
||||
symbol=query.symbol, period=query.period, limit=query.limit
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPAnalystEstimatesQueryParams:
|
||||
return FMPAnalystEstimatesQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPAnalystEstimatesQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPAnalystEstimatesQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPAnalystEstimatesData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query.period = "quarter" if query.period == "quarterly" else "annual"
|
||||
|
||||
url = create_url(
|
||||
3, f"analyst-estimates/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPAnalystEstimatesData)
|
||||
return get_data_many(url, FMPAnalystEstimatesData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPAnalystEstimatesData],
|
||||
) -> List[AnalystEstimatesData]:
|
||||
return data_transformer(data, AnalystEstimatesData)
|
||||
) -> List[FMPAnalystEstimatesData]:
|
||||
return data
|
||||
|
||||
@@ -1,36 +1,32 @@
|
||||
"""FMP Available Indices fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.available_indices import (
|
||||
AvailableIndicesData,
|
||||
AvailableIndicesQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
|
||||
|
||||
class FMPAvailableIndicesQueryParams(QueryParams):
|
||||
"""FMP Available Indices query.
|
||||
class FMPAvailableIndicesQueryParams(AvailableIndicesQueryParams):
|
||||
"""FMP Available Indices Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-stock-index-prices
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class FMPAvailableIndicesData(Data):
|
||||
"""FMP Available Indices data."""
|
||||
class FMPAvailableIndicesData(AvailableIndicesData):
|
||||
"""FMP Available Indices Data."""
|
||||
|
||||
symbol: str
|
||||
name: Optional[str]
|
||||
currency: Optional[str]
|
||||
stockExchange: str = Field(alias="stock_exchange")
|
||||
exchangeShortName: str = Field(alias="exchange_short_name")
|
||||
class Config:
|
||||
fields = {
|
||||
"stock_exchange": "stockExchange",
|
||||
"exchange_short_name": "exchangeShortName",
|
||||
}
|
||||
|
||||
|
||||
class FMPAvailableIndicesFetcher(
|
||||
@@ -42,24 +38,23 @@ class FMPAvailableIndicesFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: AvailableIndicesQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPAvailableIndicesQueryParams:
|
||||
return FMPAvailableIndicesQueryParams()
|
||||
def transform_query(params: Dict[str, Any]) -> FMPAvailableIndicesQueryParams:
|
||||
return FMPAvailableIndicesQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPAvailableIndicesQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPAvailableIndicesQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPAvailableIndicesData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
url = f"{base_url}/symbol/available-indexes?apikey={api_key}"
|
||||
return get_data_many(url, FMPAvailableIndicesData)
|
||||
return get_data_many(url, FMPAvailableIndicesData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPAvailableIndicesData],
|
||||
) -> List[AvailableIndicesData]:
|
||||
return data_transformer(data, AvailableIndicesData)
|
||||
) -> List[FMPAvailableIndicesData]:
|
||||
return data
|
||||
|
||||
@@ -1,45 +1,25 @@
|
||||
"""FMP Balance Sheet Fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.balance_sheet import (
|
||||
BalanceSheetData,
|
||||
BalanceSheetQueryParams,
|
||||
)
|
||||
from pydantic import Field, NonNegativeInt, root_validator
|
||||
from pydantic import root_validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPBalanceSheetQueryParams(QueryParams):
|
||||
class FMPBalanceSheetQueryParams(BalanceSheetQueryParams):
|
||||
"""FMP Balance Sheet QueryParams.
|
||||
|
||||
Source: https://financialmodelingprep.com/developer/docs/#Balance-Sheet
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : Optional[str]
|
||||
The symbol of the company if cik is not provided.
|
||||
cik : Optional[str]
|
||||
The CIK of the company if symbol is not provided.
|
||||
period : Literal["annual", "quarter"]
|
||||
The period of the balance sheet. Default is "annual".
|
||||
limit : Optional[NonNegativeInt]
|
||||
The limit of the balance sheet.
|
||||
"""
|
||||
|
||||
symbol: Optional[str]
|
||||
cik: Optional[str]
|
||||
period: Literal["annual", "quarter"] = Field(default="annual")
|
||||
limit: Optional[NonNegativeInt]
|
||||
|
||||
@root_validator()
|
||||
def check_symbol_or_cik(cls, values): # pylint: disable=no-self-argument
|
||||
@@ -48,65 +28,66 @@ class FMPBalanceSheetQueryParams(QueryParams):
|
||||
return values
|
||||
|
||||
|
||||
class FMPBalanceSheetData(Data):
|
||||
date: dateType
|
||||
symbol: str
|
||||
cik: Optional[int]
|
||||
reportedCurrency: Optional[str]
|
||||
fillingDate: Optional[dateType]
|
||||
acceptedDate: Optional[datetime]
|
||||
calendarYear: Optional[int]
|
||||
period: Optional[str]
|
||||
class FMPBalanceSheetData(BalanceSheetData):
|
||||
"""FMP Balance Sheet Data."""
|
||||
|
||||
cashAndCashEquivalents: Optional[int]
|
||||
shortTermInvestments: Optional[int]
|
||||
cashAndShortTermInvestments: Optional[int]
|
||||
netReceivables: Optional[int]
|
||||
inventory: Optional[int]
|
||||
otherCurrentAssets: Optional[int]
|
||||
totalCurrentAssets: Optional[int] = Field(alias="current_assets")
|
||||
|
||||
longTermInvestments: Optional[int]
|
||||
propertyPlantEquipmentNet: Optional[int]
|
||||
|
||||
goodwill: Optional[int]
|
||||
intangibleAssets: Optional[int]
|
||||
goodwillAndIntangibleAssets: Optional[int]
|
||||
taxAssets: Optional[int]
|
||||
otherNonCurrentAssets: Optional[int]
|
||||
|
||||
totalNonCurrentAssets: Optional[int] = Field(alias="noncurrent_assets")
|
||||
totalAssets: Optional[int] = Field(alias="assets")
|
||||
|
||||
accountPayables: Optional[int]
|
||||
otherCurrentLiabilities: Optional[int]
|
||||
deferredRevenue: Optional[int]
|
||||
shortTermDebt: Optional[int]
|
||||
taxPayables: Optional[int]
|
||||
totalCurrentLiabilities: Optional[int] = Field(alias="current_liabilities")
|
||||
|
||||
longTermDebt: Optional[int]
|
||||
deferredRevenueNonCurrent: Optional[int]
|
||||
deferredTaxLiabilitiesNonCurrent: Optional[int]
|
||||
otherNonCurrentLiabilities: Optional[int]
|
||||
totalNonCurrentLiabilities: Optional[int] = Field(alias="noncurrent_liabilities")
|
||||
totalLiabilities: Optional[int] = Field(alias="liabilities")
|
||||
|
||||
commonStock: Optional[int]
|
||||
retainedEarnings: Optional[int]
|
||||
accumulatedOtherComprehensiveIncomeLoss: Optional[int]
|
||||
othertotalStockholdersEquity: Optional[int]
|
||||
totalEquity: Optional[int]
|
||||
totalLiabilitiesAndStockholdersEquity: Optional[int]
|
||||
class Config:
|
||||
fields = {
|
||||
"currency": "reportedCurrency",
|
||||
"filing_date": "fillingDate",
|
||||
"accepted_date": "acceptedDate",
|
||||
"cash_and_cash_equivalents": "cashAndCashEquivalents",
|
||||
"short_term_investments": "shortTermInvestments",
|
||||
"net_receivables": "netReceivables",
|
||||
"other_current_assets": "otherCurrentAssets",
|
||||
"current_assets": "totalCurrentAssets",
|
||||
"long_term_investments": "longTermInvestments",
|
||||
"property_plant_equipment_net": "propertyPlantEquipmentNet",
|
||||
"intangible_assets": "intangibleAssets",
|
||||
"other_non_current_assets": "otherNonCurrentAssets",
|
||||
"tax_assets": "taxAssets",
|
||||
"other_assets": "otherAssets",
|
||||
"noncurrent_assets": "totalNonCurrentAssets",
|
||||
"assets": "totalAssets",
|
||||
"account_payables": "accountPayables",
|
||||
"other_current_liabilities": "otherCurrentLiabilities",
|
||||
"tax_payables": "taxPayables",
|
||||
"short_term_debt": "shortTermDebt",
|
||||
"deferred_revenue": "deferredRevenue",
|
||||
"current_liabilities": "totalCurrentLiabilities",
|
||||
"long_term_debt": "longTermDebt",
|
||||
"other_non_current_liabilities": "otherNonCurrentLiabilities",
|
||||
"other_liabilities": "otherLiabilities",
|
||||
"noncurrent_liabilities": "totalNonCurrentLiabilities",
|
||||
"liabilities": "totalLiabilities",
|
||||
"common_stock": "commonStock",
|
||||
"other_stockholder_equity": "othertotalStockholdersEquity",
|
||||
"accumulated_other_comprehensive_income_loss": "accumulatedOtherComprehensiveIncomeLoss",
|
||||
"preferred_stock": "preferredStock",
|
||||
"retained_earnings": "retainedEarnings",
|
||||
"minority_interest": "minorityInterest",
|
||||
"total_stockholders_equity": "totalStockholdersEquity",
|
||||
"total_equity": "totalEquity",
|
||||
"total_liabilities_and_stockholders_equity": "totalLiabilitiesAndStockholdersEquity",
|
||||
"total_liabilities_and_total_equity": "totalLiabilitiesAndTotalEquity",
|
||||
}
|
||||
|
||||
# Leftovers below
|
||||
totalStockholdersEquity: Optional[int]
|
||||
minorityInterest: Optional[int]
|
||||
totalLiabilitiesAndTotalEquity: Optional[int]
|
||||
totalInvestments: Optional[int]
|
||||
netDebt: Optional[int]
|
||||
calendarYear: Optional[int]
|
||||
link: Optional[str]
|
||||
finalLink: Optional[str]
|
||||
|
||||
cashAndShortTermInvestments: Optional[int]
|
||||
goodwillAndIntangibleAssets: Optional[int]
|
||||
deferredRevenueNonCurrent: Optional[int]
|
||||
totalInvestments: Optional[int]
|
||||
|
||||
capitalLeaseObligations: Optional[int]
|
||||
deferredTaxLiabilitiesNonCurrent: Optional[int]
|
||||
totalNonCurrentLiabilities: Optional[int]
|
||||
totalDebt: Optional[int]
|
||||
netDebt: Optional[int]
|
||||
|
||||
|
||||
class FMPBalanceSheetFetcher(
|
||||
Fetcher[
|
||||
@@ -117,28 +98,24 @@ class FMPBalanceSheetFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: BalanceSheetQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPBalanceSheetQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarter"
|
||||
return FMPBalanceSheetQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPBalanceSheetQueryParams:
|
||||
return FMPBalanceSheetQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPBalanceSheetQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPBalanceSheetQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPBalanceSheetData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"balance-sheet-statement/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPBalanceSheetData)
|
||||
return get_data_many(url, FMPBalanceSheetData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPBalanceSheetData],
|
||||
) -> List[BalanceSheetData]:
|
||||
return data_transformer(data, BalanceSheetData)
|
||||
) -> List[FMPBalanceSheetData]:
|
||||
return data
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
"""FMP Balance Sheet Growth Fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.models.balance_sheet_growth import (
|
||||
BalanceSheetGrowthData,
|
||||
BalanceSheetGrowthQueryParams,
|
||||
)
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPBalanceSheetGrowthQueryParams(BalanceSheetGrowthQueryParams):
|
||||
"""FMP Balance Sheet Growth QueryParams.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Financial-Statements-Growth
|
||||
"""
|
||||
|
||||
|
||||
class FMPBalanceSheetGrowthData(BalanceSheetGrowthData):
|
||||
"""FMP Balance Sheet Growth Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"growth_cash_and_cash_equivalents": "growthCashAndCashEquivalents",
|
||||
"growth_short_term_investments": "growthShortTermInvestments",
|
||||
"growth_cash_and_short_term_investments": "growthCashAndShortTermInvestments",
|
||||
"growth_net_receivables": "growthNetReceivables",
|
||||
"growth_inventory": "growthInventory",
|
||||
"growth_other_current_assets": "growthOtherCurrentAssets",
|
||||
"growth_total_current_assets": "growthTotalCurrentAssets",
|
||||
"growth_property_plant_equipment_net": "growthPropertyPlantEquipmentNet",
|
||||
"growth_goodwill": "growthGoodwill",
|
||||
"growth_intangible_assets": "growthIntangibleAssets",
|
||||
"growth_goodwill_and_intangible_assets": "growthGoodwillAndIntangibleAssets",
|
||||
"growth_long_term_investments": "growthLongTermInvestments",
|
||||
"growth_tax_assets": "growthTaxAssets",
|
||||
"growth_other_non_current_assets": "growthOtherNonCurrentAssets",
|
||||
"growth_total_non_current_assets": "growthTotalNonCurrentAssets",
|
||||
"growth_other_assets": "growthOtherAssets",
|
||||
"growth_total_assets": "growthTotalAssets",
|
||||
"growth_account_payables": "growthAccountPayables",
|
||||
"growth_short_term_debt": "growthShortTermDebt",
|
||||
"growth_tax_payables": "growthTaxPayables",
|
||||
"growth_deferred_revenue": "growthDeferredRevenue",
|
||||
"growth_other_current_liabilities": "growthOtherCurrentLiabilities",
|
||||
"growth_total_current_liabilities": "growthTotalCurrentLiabilities",
|
||||
"growth_long_term_debt": "growthLongTermDebt",
|
||||
"growth_deferred_revenue_non_current": "growthDeferredRevenueNonCurrent",
|
||||
"growth_deferrred_tax_liabilities_non_current": "growthDeferrredTaxLiabilitiesNonCurrent",
|
||||
"growth_other_non_current_liabilities": "growthOtherNonCurrentLiabilities",
|
||||
"growth_total_non_current_liabilities": "growthTotalNonCurrentLiabilities",
|
||||
"growth_other_liabilities": "growthOtherLiabilities",
|
||||
"growth_total_liabilities": "growthTotalLiabilities",
|
||||
"growth_common_stock": "growthCommonStock",
|
||||
"growth_retained_earnings": "growthRetainedEarnings",
|
||||
"growth_accumulated_other_comprehensive_income_loss": "growthAccumulatedOtherComprehensiveIncomeLoss",
|
||||
"growth_othertotal_stockholders_equity": "growthOthertotalStockholdersEquity",
|
||||
"growth_total_stockholders_equity": "growthTotalStockholdersEquity",
|
||||
"growth_total_liabilities_and_stockholders_equity": "growthTotalLiabilitiesAndStockholdersEquity",
|
||||
"growth_total_investments": "growthTotalInvestments",
|
||||
"growth_total_debt": "growthTotalDebt",
|
||||
"growth_net_debt": "growthNetDebt",
|
||||
}
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
class FMPBalanceSheetGrowthFetcher(
|
||||
Fetcher[
|
||||
BalanceSheetGrowthQueryParams,
|
||||
BalanceSheetGrowthData,
|
||||
FMPBalanceSheetGrowthQueryParams,
|
||||
FMPBalanceSheetGrowthData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> FMPBalanceSheetGrowthQueryParams:
|
||||
return FMPBalanceSheetGrowthQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPBalanceSheetGrowthQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPBalanceSheetGrowthData]:
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3,
|
||||
f"balance-sheet-statement-growth/{query.symbol}",
|
||||
api_key,
|
||||
query,
|
||||
["symbol"],
|
||||
)
|
||||
return get_data_many(url, FMPBalanceSheetGrowthData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPBalanceSheetGrowthData],
|
||||
) -> List[FMPBalanceSheetGrowthData]:
|
||||
return data
|
||||
@@ -1,98 +1,75 @@
|
||||
"""FMP Cash Flow Statement Fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.cash_flows import (
|
||||
CashFlowStatementData,
|
||||
CashFlowStatementQueryParams,
|
||||
)
|
||||
from pydantic import Field, NonNegativeInt, root_validator
|
||||
from pydantic import Field, root_validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPCashFlowStatementQueryParams(QueryParams):
|
||||
"""FMP Cash Flow Statement QueryParams.
|
||||
class FMPCashFlowStatementQueryParams(CashFlowStatementQueryParams):
|
||||
"""FMP Cash Flow Statement Query.
|
||||
|
||||
Source: https://financialmodelingprep.com/developer/docs/#Cash-Flow-Statement
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : Optional[str]
|
||||
The symbol of the company if cik is not provided.
|
||||
cik : Optional[str]
|
||||
The CIK of the company if symbol is not provided.
|
||||
period : Literal["annual", "quarter"]
|
||||
The period of the cash flow statement. Default is "annual".
|
||||
limit : Optional[NonNegativeInt]
|
||||
The limit of the cash flow statement.
|
||||
"""
|
||||
|
||||
symbol: Optional[str]
|
||||
cik: Optional[str]
|
||||
period: Literal["annual", "quarter"] = Field(default="annual")
|
||||
limit: Optional[NonNegativeInt]
|
||||
cik: Optional[str] = Field(description="Central Index Key (CIK) of the company.")
|
||||
|
||||
@root_validator()
|
||||
def check_symbol_or_cik(cls, values): # pylint: disable=E0213
|
||||
def check_symbol_or_cik(cls, values): # pylint: disable=no-self-argument
|
||||
if values.get("symbol") is None and values.get("cik") is None:
|
||||
raise ValueError("symbol or cik must be provided")
|
||||
return values
|
||||
|
||||
|
||||
class FMPCashFlowStatementData(Data):
|
||||
date: dateType
|
||||
symbol: str
|
||||
cik: Optional[int]
|
||||
reportedCurrency: str = Field(alias="currency")
|
||||
fillingDate: Optional[dateType]
|
||||
acceptedDate: Optional[datetime]
|
||||
class FMPCashFlowStatementData(CashFlowStatementData):
|
||||
"""FMP Cash Flow Statement Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"currency": "reportedCurrency",
|
||||
"filing_date": "fillingDate",
|
||||
"accepted_date": "acceptedDate",
|
||||
"net_income": "netIncome",
|
||||
"depreciation_and_amortization": "depreciationAndAmortization",
|
||||
"stock_based_compensation": "stockBasedCompensation",
|
||||
"other_non_cash_items": "otherNonCashItems",
|
||||
"deferred_income_tax": "deferredIncomeTax",
|
||||
"change_in_working_capital": "changeInWorkingCapital",
|
||||
"accounts_receivables": "accountsReceivables",
|
||||
"inventory": "inventory",
|
||||
"accounts_payables": "accountsPayables",
|
||||
"other_working_capital": "otherWorkingCapital",
|
||||
"net_cash_flow_from_operating_activities": "netCashProvidedByOperatingActivities",
|
||||
"investments_in_property_plant_and_equipment": "investmentsInPropertyPlantAndEquipment",
|
||||
"acquisitions_net": "acquisitionsNet",
|
||||
"purchases_of_investments": "purchasesOfInvestments",
|
||||
"sales_maturities_of_investments": "salesMaturitiesOfInvestments",
|
||||
"other_investing_activities": "otherInvestingActivites",
|
||||
"net_cash_flow_from_investing_activities": "netCashUsedForInvestingActivites",
|
||||
"debt_repayment": "debtRepayment",
|
||||
"common_stock_issued": "commonStockIssued",
|
||||
"common_stock_repurchased": "commonStockRepurchased",
|
||||
"dividends_paid": "dividendsPaid",
|
||||
"other_financing_activities": "otherFinancingActivites",
|
||||
"net_cash_flow_from_financing_activities": "netCashUsedProvidedByFinancingActivities",
|
||||
"effect_of_forex_changes_on_cash": "effectOfForexChangesOnCash",
|
||||
"net_change_in_cash": "netChangeInCash",
|
||||
"cash_at_end_of_period": "cashAtEndOfPeriod",
|
||||
"cash_at_beginning_of_period": "cashAtBeginningOfPeriod",
|
||||
"operating_cash_flow": "operatingCashFlow",
|
||||
"capital_expenditure": "capitalExpenditure",
|
||||
"net_cash_flow": "freeCashFlow",
|
||||
}
|
||||
|
||||
# Leftovers below
|
||||
calendarYear: Optional[int]
|
||||
period: Optional[str]
|
||||
netIncome: Optional[int]
|
||||
depreciationAndAmortization: Optional[int]
|
||||
deferredIncomeTax: Optional[int]
|
||||
stockBasedCompensation: Optional[int]
|
||||
changeInWorkingCapital: Optional[int]
|
||||
accountsReceivables: Optional[int]
|
||||
inventory: Optional[int]
|
||||
accountsPayables: Optional[int]
|
||||
otherWorkingCapital: Optional[int]
|
||||
otherNonCashItems: Optional[int]
|
||||
netCashProvidedByOperatingActivities: Optional[int] = Field(
|
||||
alias="net_cash_flow_from_operating_activities"
|
||||
)
|
||||
investmentsInPropertyPlantAndEquipment: Optional[int]
|
||||
acquisitionsNet: Optional[int]
|
||||
purchasesOfInvestments: Optional[int]
|
||||
salesMaturitiesOfInvestments: Optional[int]
|
||||
otherInvestingActivites: Optional[int] = Field(alias="other_investing_activities")
|
||||
netCashUsedForInvestingActivites: Optional[int] = Field(
|
||||
alias="net_cash_flow_from_investing_activities"
|
||||
)
|
||||
debtRepayment: Optional[int]
|
||||
commonStockIssued: Optional[int]
|
||||
commonStockRepurchased: Optional[int]
|
||||
dividendsPaid: Optional[int]
|
||||
otherFinancingActivites: Optional[int] = Field(alias="other_financing_activities")
|
||||
netCashUsedProvidedByFinancingActivities: Optional[int] = Field(
|
||||
alias="net_cash_flow_from_financing_activities"
|
||||
)
|
||||
effectOfForexChangesOnCash: Optional[int] = Field(alias="exchange_gain_losses")
|
||||
netChangeInCash: Optional[int] = Field(alias="net_cash_flow")
|
||||
cashAtEndOfPeriod: Optional[int]
|
||||
cashAtBeginningOfPeriod: Optional[int]
|
||||
operatingCashFlow: Optional[int]
|
||||
capitalExpenditure: Optional[int]
|
||||
freeCashFlow: Optional[int]
|
||||
link: Optional[str]
|
||||
finalLink: Optional[str]
|
||||
|
||||
@@ -106,28 +83,26 @@ class FMPCashFlowStatementFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CashFlowStatementQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPCashFlowStatementQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarter"
|
||||
return FMPCashFlowStatementQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPCashFlowStatementQueryParams:
|
||||
return FMPCashFlowStatementQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCashFlowStatementQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPCashFlowStatementQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPCashFlowStatementData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
url = create_url(
|
||||
3, f"cash-flow-statement/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPCashFlowStatementData)
|
||||
return get_data_many(url, FMPCashFlowStatementData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPCashFlowStatementData],
|
||||
) -> List[CashFlowStatementData]:
|
||||
return data_transformer(data, CashFlowStatementData)
|
||||
) -> List[FMPCashFlowStatementData]:
|
||||
return data
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
"""FMP Cash Flow Statement Growth Fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.models.cash_flow_growth import (
|
||||
CashFlowStatementGrowthData,
|
||||
CashFlowStatementGrowthQueryParams,
|
||||
)
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPCashFlowStatementGrowthQueryParams(CashFlowStatementGrowthQueryParams):
|
||||
"""FMP Cash Flow Statement Growth QueryParams.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/financial-statements-growth-api/
|
||||
"""
|
||||
|
||||
|
||||
class FMPCashFlowStatementGrowthData(CashFlowStatementGrowthData):
|
||||
"""FMP Cash Flow Statement Growth Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"growth_net_income": "growthNetIncome",
|
||||
"growth_depreciation_and_amortization": "growthDepreciationAndAmortization",
|
||||
"growth_deferred_income_tax": "growthDeferredIncomeTax",
|
||||
"growth_stock_based_compensation": "growthStockBasedCompensation",
|
||||
"growth_change_in_working_capital": "growthChangeInWorkingCapital",
|
||||
"growth_accounts_receivables": "growthAccountsReceivables",
|
||||
"growth_inventory": "growthInventory",
|
||||
"growth_accounts_payables": "growthAccountsPayables",
|
||||
"growth_other_working_capital": "growthOtherWorkingCapital",
|
||||
"growth_other_non_cash_items": "growthOtherNonCashItems",
|
||||
"growth_net_cash_provided_by_operating_activities": "growthNetCashProvidedByOperatingActivites",
|
||||
"growth_investments_in_property_plant_and_equipment": "growthInvestmentsInPropertyPlantAndEquipment",
|
||||
"growth_acquisitions_net": "growthAcquisitionsNet",
|
||||
"growth_purchases_of_investments": "growthPurchasesOfInvestments",
|
||||
"growth_sales_maturities_of_investments": "growthSalesMaturitiesOfInvestments",
|
||||
"growth_other_investing_activities": "growthOtherInvestingActivites",
|
||||
"growth_net_cash_used_for_investing_activities": "growthNetCashUsedForInvestingActivites",
|
||||
"growth_debt_repayment": "growthDebtRepayment",
|
||||
"growth_common_stock_issued": "growthCommonStockIssued",
|
||||
"growth_common_stock_repurchased": "growthCommonStockRepurchased",
|
||||
"growth_dividends_paid": "growthDividendsPaid",
|
||||
"growth_other_financing_activities": "growthOtherFinancingActivites",
|
||||
"growth_net_cash_used_provided_by_financing_activities": "growthNetCashUsedProvidedByFinancingActivities",
|
||||
"growth_effect_of_forex_changes_on_cash": "growthEffectOfForexChangesOnCash",
|
||||
"growth_net_change_in_cash": "growthNetChangeInCash",
|
||||
"growth_cash_at_end_of_period": "growthCashAtEndOfPeriod",
|
||||
"growth_cash_at_beginning_of_period": "growthCashAtBeginningOfPeriod",
|
||||
"growth_operating_cash_flow": "growthOperatingCashFlow",
|
||||
"growth_capital_expenditure": "growthCapitalExpenditure",
|
||||
"growth_free_cash_flow": "growthFreeCashFlow",
|
||||
}
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
class FMPCashFlowStatementGrowthFetcher(
|
||||
Fetcher[
|
||||
CashFlowStatementGrowthQueryParams,
|
||||
CashFlowStatementGrowthData,
|
||||
FMPCashFlowStatementGrowthQueryParams,
|
||||
FMPCashFlowStatementGrowthData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
params: Dict[str, Any]
|
||||
) -> FMPCashFlowStatementGrowthQueryParams:
|
||||
return FMPCashFlowStatementGrowthQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCashFlowStatementGrowthQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPCashFlowStatementGrowthData]:
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"cash-flow-statement-growth/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPCashFlowStatementGrowthData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPCashFlowStatementGrowthData],
|
||||
) -> List[FMPCashFlowStatementGrowthData]:
|
||||
return data
|
||||
@@ -0,0 +1,78 @@
|
||||
"""FMP Company Overview Fetcher."""
|
||||
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.models.company_overview import (
|
||||
CompanyOverviewData,
|
||||
CompanyOverviewQueryParams,
|
||||
)
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data
|
||||
|
||||
# This part is only provided by FMP and not by the other providers for now.
|
||||
|
||||
|
||||
class FMPCompanyOverviewQueryParams(CompanyOverviewQueryParams):
|
||||
"""FMP Company Overview Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/companies-key-stats-free-api/
|
||||
"""
|
||||
|
||||
|
||||
class FMPCompanyOverviewData(CompanyOverviewData):
|
||||
"""FMP Company Overview Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"vol_avg": "volAvg",
|
||||
"mkt_cap": "mktCap",
|
||||
"last_div": "lastDiv",
|
||||
"company_name": "companyName",
|
||||
"exchange_short_name": "exchangeShortName",
|
||||
"full_time_employees": "fullTimeEmployees",
|
||||
"dcf_diff": "dcfDiff",
|
||||
"ipo_date": "ipoDate",
|
||||
"default_image": "defaultImage",
|
||||
"is_etf": "isEtf",
|
||||
"is_actively_trading": "isActivelyTrading",
|
||||
"is_adr": "isAdr",
|
||||
"is_fund": "isFund",
|
||||
}
|
||||
|
||||
|
||||
class FMPCompanyOverviewFetcher(
|
||||
Fetcher[
|
||||
CompanyOverviewQueryParams,
|
||||
CompanyOverviewData,
|
||||
FMPCompanyOverviewQueryParams,
|
||||
FMPCompanyOverviewData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> FMPCompanyOverviewQueryParams:
|
||||
return FMPCompanyOverviewQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCompanyOverviewQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPCompanyOverviewData]:
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
request_url = f"{base_url}profile/{query.symbol}?apikey={api_key}"
|
||||
data = get_data(request_url, **kwargs)
|
||||
if isinstance(data, dict):
|
||||
raise ValueError("Expected list of dicts, got dict")
|
||||
|
||||
return [FMPCompanyOverviewData.parse_obj(data[0])]
|
||||
|
||||
@staticmethod
|
||||
def transform_data( # type: ignore
|
||||
data: List[FMPCompanyOverviewData],
|
||||
) -> List[FMPCompanyOverviewData]:
|
||||
# Need to update transform_data to return a non list version of list isn't used
|
||||
return data # type: ignore
|
||||
@@ -1,104 +0,0 @@
|
||||
"""FMP Company Overview Fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.company_overview import (
|
||||
CompanyOverviewData,
|
||||
CompanyOverviewQueryParams,
|
||||
)
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data
|
||||
|
||||
# This part is only provided by FMP and not by the other providers for now.
|
||||
|
||||
|
||||
class FMPCompanyOverviewQueryParams(CompanyOverviewQueryParams):
|
||||
"""FMP Company Overview query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/companies-key-stats-free-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPCompanyOverviewData(Data):
|
||||
symbol: str
|
||||
price: float
|
||||
beta: float
|
||||
volAvg: int
|
||||
mktCap: int
|
||||
lastDiv: float
|
||||
range: str
|
||||
changes: float
|
||||
companyName: str
|
||||
currency: str
|
||||
cik: Optional[str]
|
||||
isin: Optional[str]
|
||||
cusip: Optional[str]
|
||||
exchange: str
|
||||
exchangeShortName: str
|
||||
industry: str
|
||||
website: str
|
||||
description: str
|
||||
ceo: str
|
||||
sector: str
|
||||
country: str
|
||||
fullTimeEmployees: str
|
||||
phone: str
|
||||
address: str
|
||||
city: str
|
||||
state: str
|
||||
zip: str
|
||||
dcfDiff: float
|
||||
dcf: float
|
||||
image: str
|
||||
ipoDate: str
|
||||
defaultImage: bool
|
||||
isEtf: bool
|
||||
isActivelyTrading: bool
|
||||
isAdr: bool
|
||||
isFund: bool
|
||||
|
||||
|
||||
class FMPCompanyProfileFetcher(
|
||||
Fetcher[ # type: ignore
|
||||
CompanyOverviewQueryParams,
|
||||
CompanyOverviewData,
|
||||
FMPCompanyOverviewQueryParams,
|
||||
FMPCompanyOverviewData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CompanyOverviewQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPCompanyOverviewQueryParams:
|
||||
return FMPCompanyOverviewQueryParams(symbol=query.symbol)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCompanyOverviewQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> FMPCompanyOverviewData:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
request_url = f"{base_url}profile/{query.symbol}?apikey={api_key}"
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, dict):
|
||||
raise ValueError("Expected list of dicts, got dict")
|
||||
|
||||
return FMPCompanyOverviewData.parse_obj(data[0])
|
||||
|
||||
@staticmethod
|
||||
def transform_data( # type: ignore
|
||||
data: FMPCompanyOverviewData,
|
||||
) -> CompanyOverviewData:
|
||||
# Need to update transform_data to return a non list version of list isn't used
|
||||
return data_transformer(data, CompanyOverviewData) # type: ignore
|
||||
@@ -1,61 +1,52 @@
|
||||
"""FMP Cryptos end of day fetcher."""
|
||||
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.crypto_eod import CryptoEODData, CryptoEODQueryParams
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import Field, NonNegativeInt, validator
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
|
||||
|
||||
class FMPCryptoEODQueryParams(QueryParams):
|
||||
"""FMP Crypto end of day query.
|
||||
class FMPCryptoEODQueryParams(CryptoEODQueryParams):
|
||||
"""FMP Crypto end of day Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Cryptocurrencies
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
start_date : date
|
||||
The start date of the stock data from which to retrieve the data.
|
||||
end_date : date
|
||||
The end date of the stock data up to which to retrieve the data.
|
||||
timeseries : Optional[int]
|
||||
The number of days to look back.
|
||||
serietype : Optional[Literal["line"]]
|
||||
The type of the series. Only "line" is supported.
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/cryptocurrency-historical-data-api/#Historical-Daily-Prices
|
||||
"""
|
||||
|
||||
symbol: str = Field(min_length=1)
|
||||
serietype: Optional[Literal["line"]]
|
||||
start_date: date
|
||||
end_date: date
|
||||
timeseries: Optional[NonNegativeInt] # Number of days to looks back
|
||||
timeseries: Optional[NonNegativeInt] = Field(
|
||||
default=None, description="Number of days to look back."
|
||||
)
|
||||
|
||||
|
||||
class FMPCryptoEODData(Data):
|
||||
date: datetime
|
||||
open: float
|
||||
high: float
|
||||
low: float
|
||||
close: float
|
||||
adjClose: float = Field(alias="adj_close")
|
||||
volume: float
|
||||
unadjustedVolume: float
|
||||
change: float
|
||||
changePercent: float
|
||||
vwap: float
|
||||
label: str
|
||||
changeOverTime: float
|
||||
class FMPCryptoEODData(CryptoEODData):
|
||||
"""FMP Crypto end of day Data."""
|
||||
|
||||
adjClose: float = Field(
|
||||
description="Adjusted Close Price of the symbol.", alias="adj_close"
|
||||
)
|
||||
unadjustedVolume: float = Field(
|
||||
description="Unadjusted volume of the symbol.", alias="unadjusted_volume"
|
||||
)
|
||||
change: float = Field(
|
||||
description="Change in the price of the symbol from the previous day.",
|
||||
alias="change",
|
||||
)
|
||||
changePercent: float = Field(
|
||||
description=r"Change \% in the price of the symbol.", alias="change_percent"
|
||||
)
|
||||
label: str = Field(description="Human readable format of the date.")
|
||||
changeOverTime: float = Field(
|
||||
description=r"Change \% in the price of the symbol over a period of time.",
|
||||
alias="change_over_time",
|
||||
)
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
@@ -68,32 +59,31 @@ class FMPCryptoEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CryptoEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPCryptoEODQueryParams:
|
||||
now = datetime.now()
|
||||
start_date = query.start_date if query.start_date else now
|
||||
end_date = query.end_date if query.end_date else now
|
||||
return FMPCryptoEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPCryptoEODQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=7)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
return FMPCryptoEODQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCryptoEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPCryptoEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPCryptoEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
query_str = get_querystring(query.dict(), ["symbol"])
|
||||
query_str = get_querystring(query.dict(by_alias=True), ["symbol"])
|
||||
query_str = query_str.replace("start_date", "from").replace("end_date", "to")
|
||||
url = f"{base_url}historical-price-full/{query.symbol}?{query_str}&apikey={api_key}"
|
||||
return get_data_many(url, FMPCryptoEODData, "historical")
|
||||
url = f"{base_url}historical-price-full/crypto/{query.symbol}?{query_str}&apikey={api_key}"
|
||||
|
||||
return get_data_many(url, FMPCryptoEODData, "historical", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPCryptoEODData]) -> List[CryptoEODData]:
|
||||
return data_transformer(data, CryptoEODData)
|
||||
def transform_data(data: List[FMPCryptoEODData]) -> List[FMPCryptoEODData]:
|
||||
return data
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
"""FMP Crypto Price fetcher."""
|
||||
|
||||
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.crypto_price import CryptoPriceData, CryptoPriceQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
|
||||
class Interval(str, Enum):
|
||||
oneminute = "1min"
|
||||
fiveminute = "5min"
|
||||
fifteenminute = "15min"
|
||||
thirtyminute = "30min"
|
||||
onehour = "1hour"
|
||||
fourhour = "4hour"
|
||||
|
||||
|
||||
class FMPCryptoPriceQueryParams(QueryParams):
|
||||
"""FMP Crypto Price query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Cryptocurrencies
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
interval : Enum of ["1min", "5min", "15min", "30min", "1hour", "4hour"] (default: "1hour")
|
||||
The interval of the data.
|
||||
"""
|
||||
|
||||
symbol: str = Field(min_length=1)
|
||||
interval: Interval = Field(default=Interval.onehour)
|
||||
|
||||
|
||||
class FMPCryptoPriceData(BaseStockPriceData):
|
||||
"""FMP Crypto Price data."""
|
||||
|
||||
|
||||
class FMPCryptoPriceFetcher(
|
||||
Fetcher[
|
||||
CryptoPriceQueryParams,
|
||||
CryptoPriceData,
|
||||
FMPCryptoPriceQueryParams,
|
||||
FMPCryptoPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CryptoPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPCryptoPriceQueryParams:
|
||||
return FMPCryptoPriceQueryParams(
|
||||
symbol=query.symbol, **extra_params if extra_params else {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCryptoPriceQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[FMPCryptoPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
|
||||
url = create_url(
|
||||
3, f"historical-chart/{query.interval}/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPCryptoPriceData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPCryptoPriceData]) -> List[CryptoPriceData]:
|
||||
return data_transformer(data, CryptoPriceData)
|
||||
@@ -1,10 +1,9 @@
|
||||
"""FMP Dividend Calendar fetcher."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.dividend_calendar import (
|
||||
DividendCalendarData,
|
||||
DividendCalendarQueryParams,
|
||||
@@ -15,40 +14,39 @@ from openbb_fmp.utils.helpers import get_data_many, get_querystring
|
||||
|
||||
|
||||
class FMPDividendCalendarQueryParams(DividendCalendarQueryParams):
|
||||
"""FMP Dividend Calendar query.
|
||||
"""FMP Dividend Calendar Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/dividend-calendar-api/
|
||||
|
||||
The maximum time interval between the start and end date can be 3 months.
|
||||
Default value for time interval is 1 month.
|
||||
|
||||
Parameter
|
||||
---------
|
||||
start_date : date
|
||||
The starting date to fetch the dividend calendar from. Default value is the
|
||||
previous day from the last month.
|
||||
end_date : date
|
||||
The ending date to fetch the dividend calendar till. Default value is the
|
||||
previous day from the current month.
|
||||
"""
|
||||
|
||||
|
||||
class FMPDividendCalendarData(DividendCalendarData):
|
||||
"""FMP Dividend Calendar data."""
|
||||
"""FMP Dividend Calendar Data."""
|
||||
|
||||
@validator("date", pre=True)
|
||||
class Config:
|
||||
fields = {
|
||||
"adj_dividend": "adjDividend",
|
||||
"record_date": "recordDate",
|
||||
"payment_date": "paymentDate",
|
||||
"declaration_date": "declarationDate",
|
||||
}
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@validator("recordDate", pre=True)
|
||||
@validator("recordDate", pre=True, check_fields=False)
|
||||
def record_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@validator("paymentDate", pre=True)
|
||||
@validator("paymentDate", pre=True, check_fields=False)
|
||||
def payment_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@validator("declarationDate", pre=True)
|
||||
@validator("declarationDate", pre=True, check_fields=False)
|
||||
def declaration_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@@ -62,30 +60,32 @@ class FMPDividendCalendarFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: DividendCalendarQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPDividendCalendarQueryParams:
|
||||
return FMPDividendCalendarQueryParams(
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date,
|
||||
**extra_params or {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPDividendCalendarQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=31)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now - timedelta(days=1)
|
||||
return FMPDividendCalendarQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPDividendCalendarQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPDividendCalendarQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPDividendCalendarData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
query_str = get_querystring(query.dict(), [])
|
||||
query_str = get_querystring(query.dict(by_alias=True), [])
|
||||
query_str = query_str.replace("start_date", "from").replace("end_date", "to")
|
||||
url = f"{base_url}/stock_dividend_calendar?{query_str}&apikey={api_key}"
|
||||
return get_data_many(url, FMPDividendCalendarData)
|
||||
return get_data_many(url, FMPDividendCalendarData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPDividendCalendarData],
|
||||
) -> List[DividendCalendarData]:
|
||||
return data_transformer(data, DividendCalendarData)
|
||||
) -> List[FMPDividendCalendarData]:
|
||||
return data
|
||||
|
||||
@@ -1,43 +1,48 @@
|
||||
"""FMP Earnings Calendar fetcher."""
|
||||
|
||||
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.earnings_calendar import (
|
||||
EarningsCalendarData,
|
||||
EarningsCalendarQueryParams,
|
||||
)
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPEarningsCalendarQueryParams(EarningsCalendarQueryParams):
|
||||
"""FMP Earnings Calendar query.
|
||||
"""FMP Earnings Calendar Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/earnings-calendar-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
limit : int
|
||||
"""
|
||||
|
||||
|
||||
class FMPEarningsCalendarData(Data):
|
||||
date: dateType
|
||||
symbol: str
|
||||
eps: Optional[float]
|
||||
epsEstimated: Optional[float]
|
||||
time: str
|
||||
revenue: Optional[int]
|
||||
revenueEstimated: Optional[int]
|
||||
updatedFromDate: Optional[dateType]
|
||||
fiscalDateEnding: dateType
|
||||
class FMPEarningsCalendarData(EarningsCalendarData):
|
||||
"""FMP Earnings Calendar Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"eps_estimated": "epsEstimated",
|
||||
"revenue_estimated": "revenueEstimated",
|
||||
"updated_from_date": "updatedFromDate",
|
||||
"fiscal_date_ending": "fiscalDateEnding",
|
||||
}
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@validator("updatedFromDate", pre=True, check_fields=False)
|
||||
def updated_from_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@validator("fiscalDateEnding", pre=True, check_fields=False)
|
||||
def fiscal_date_ending_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
|
||||
class FMPEarningsCalendarFetcher(
|
||||
@@ -49,25 +54,24 @@ class FMPEarningsCalendarFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: EarningsCalendarQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPEarningsCalendarQueryParams:
|
||||
return FMPEarningsCalendarQueryParams(symbol=query.symbol, limit=query.limit)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPEarningsCalendarQueryParams:
|
||||
return FMPEarningsCalendarQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPEarningsCalendarQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPEarningsCalendarQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPEarningsCalendarData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"historical/earning_calendar/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPEarningsCalendarData)
|
||||
return get_data_many(url, FMPEarningsCalendarData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPEarningsCalendarData],
|
||||
) -> List[EarningsCalendarData]:
|
||||
return data_transformer(data, EarningsCalendarData)
|
||||
) -> List[FMPEarningsCalendarData]:
|
||||
return data
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
"""FMP Earnings Call Transcript fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.base import BaseSymbol
|
||||
from openbb_provider.models.earnings_call_transcript import (
|
||||
EarningsCallTranscriptData,
|
||||
EarningsCallTranscriptQueryParams,
|
||||
)
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPEarningsCallTranscriptQueryParams(QueryParams, BaseSymbol):
|
||||
"""FMP Earnings Calendar query.
|
||||
class FMPEarningsCallTranscriptQueryParams(EarningsCallTranscriptQueryParams):
|
||||
"""FMP Earnings Calendar Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/earnings-calendar-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
year: int
|
||||
The year of the transcript to get.
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/earning-call-transcript-api/
|
||||
"""
|
||||
|
||||
year: int
|
||||
@validator("year", pre=True, check_fields=False)
|
||||
def time_validate(cls, v: int): # pylint: disable=E0213
|
||||
current_year = datetime.now().year
|
||||
return current_year if v > current_year or v < 1950 else v
|
||||
|
||||
|
||||
class FMPEarningsCallTranscriptData(EarningsCallTranscriptData):
|
||||
"""FMP Earnings Call Transcript data."""
|
||||
"""FMP Earnings Call Transcript Data."""
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
class FMPEarningsCallTranscriptFetcher(
|
||||
@@ -44,20 +43,16 @@ class FMPEarningsCallTranscriptFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: EarningsCallTranscriptQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPEarningsCallTranscriptQueryParams:
|
||||
return FMPEarningsCallTranscriptQueryParams(
|
||||
symbol=query.symbol, year=query.year
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPEarningsCallTranscriptQueryParams:
|
||||
return FMPEarningsCallTranscriptQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPEarningsCallTranscriptQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPEarningsCallTranscriptData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
4,
|
||||
@@ -66,10 +61,10 @@ class FMPEarningsCallTranscriptFetcher(
|
||||
query,
|
||||
["symbol"],
|
||||
)
|
||||
return get_data_many(url, FMPEarningsCallTranscriptData)
|
||||
return get_data_many(url, FMPEarningsCallTranscriptData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPEarningsCallTranscriptData],
|
||||
) -> List[EarningsCallTranscriptData]:
|
||||
return data_transformer(data, EarningsCallTranscriptData)
|
||||
) -> List[FMPEarningsCallTranscriptData]:
|
||||
return data
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
|
||||
from datetime import date
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.esg_risk_rating import (
|
||||
ESGRiskRatingData,
|
||||
ESGRiskRatingQueryParams,
|
||||
@@ -52,23 +51,22 @@ class FMPESGRiskRatingFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ESGRiskRatingQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPESGRiskRatingQueryParams:
|
||||
return FMPESGRiskRatingQueryParams.parse_obj(query)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPESGRiskRatingQueryParams:
|
||||
return FMPESGRiskRatingQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPESGRiskRatingQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPESGRiskRatingQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPESGRiskRatingData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
4, "esg-environmental-social-governance-data-ratings", api_key, query
|
||||
)
|
||||
return get_data_many(url, FMPESGRiskRatingData)
|
||||
return get_data_many(url, FMPESGRiskRatingData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPESGRiskRatingData]) -> List[ESGRiskRatingData]:
|
||||
return data_transformer(data, ESGRiskRatingData)
|
||||
def transform_data(data: List[FMPESGRiskRatingData]) -> List[FMPESGRiskRatingData]:
|
||||
return data
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.esg_score import ESGScoreData, ESGScoreQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
@@ -43,21 +42,20 @@ class FMPESGScoreFetcher(
|
||||
Fetcher[ESGScoreQueryParams, ESGScoreData, FMPESGScoreQueryParams, FMPESGScoreData]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ESGScoreQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPESGScoreQueryParams:
|
||||
return FMPESGScoreQueryParams.parse_obj(query)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPESGScoreQueryParams:
|
||||
return FMPESGScoreQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPESGScoreQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPESGScoreQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPESGScoreData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "esg-environmental-social-governance-data", api_key, query)
|
||||
return get_data_many(url, FMPESGScoreData)
|
||||
return get_data_many(url, FMPESGScoreData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPESGScoreData]) -> List[ESGScoreData]:
|
||||
return data_transformer(data, ESGScoreData)
|
||||
def transform_data(data: List[FMPESGScoreData]) -> List[FMPESGScoreData]:
|
||||
return data
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
|
||||
from datetime import date
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.abstract.query_params import QueryParams
|
||||
from openbb_provider.models.esg_sector import ESGSectorData, ESGSectorQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
@@ -44,23 +44,22 @@ class FMPESGSectorFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ESGSectorQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPESGSectorQueryParams:
|
||||
return FMPESGSectorQueryParams(year=query.year)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPESGSectorQueryParams:
|
||||
return FMPESGSectorQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPESGSectorQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPESGSectorQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPESGSectorData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
4, "esg-environmental-social-governance-sector-benchmark", api_key, query
|
||||
)
|
||||
return get_data_many(url, FMPESGSectorData)
|
||||
return get_data_many(url, FMPESGSectorData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPESGSectorData]) -> List[ESGSectorData]:
|
||||
return data_transformer(data, ESGSectorData)
|
||||
def transform_data(data: List[FMPESGSectorData]) -> List[FMPESGSectorData]:
|
||||
return data
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
"""FMP Executive Compensation Fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.executive_compensation import (
|
||||
ExecutiveCompensationData,
|
||||
ExecutiveCompensationQueryParams,
|
||||
@@ -18,44 +13,37 @@ from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
# This part is only provided by FMP and not by the other providers for now.
|
||||
# This endpoint is only provided by FMP and not by the other providers for now.
|
||||
|
||||
|
||||
class FMPExecutiveCompensationQueryParams(ExecutiveCompensationQueryParams):
|
||||
"""FMP Executive Compensation query.
|
||||
"""FMP Executive Compensation Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/executive-compensation-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPExecutiveCompensationData(Data):
|
||||
cik: Optional[str]
|
||||
symbol: str
|
||||
filingDate: dateType
|
||||
acceptedDate: dateType
|
||||
nameAndPosition: str
|
||||
year: int
|
||||
salary: float
|
||||
bonus: float
|
||||
stock_award: float
|
||||
incentive_plan_compensation: float
|
||||
all_other_compensation: float
|
||||
total: float
|
||||
url: str
|
||||
class FMPExecutiveCompensationData(ExecutiveCompensationData):
|
||||
"""FMP Executive Compensation Data."""
|
||||
|
||||
@validator("acceptedDate", pre=True)
|
||||
def convert_accepted_date(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
class Config:
|
||||
fields = {
|
||||
"filing_date": "filingDate",
|
||||
"accepted_date": "acceptedDate",
|
||||
"name_and_position": "nameAndPosition",
|
||||
"stock_award": "stockAward",
|
||||
"incentive_plan_compensation": "incentivePlanCompensation",
|
||||
"all_other_compensation": "allOtherCompensation",
|
||||
}
|
||||
|
||||
@validator("filingDate", pre=True)
|
||||
def convert_filing_date(cls, v): # pylint: disable=E0213
|
||||
@validator("filingDate", pre=True, check_fields=False)
|
||||
def filing_date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
@validator("acceptedDate", pre=True, check_fields=False)
|
||||
def accepted_date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
class FMPExecutiveCompensationFetcher(
|
||||
Fetcher[ # type: ignore
|
||||
@@ -66,24 +54,22 @@ class FMPExecutiveCompensationFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ExecutiveCompensationQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPExecutiveCompensationQueryParams:
|
||||
return FMPExecutiveCompensationQueryParams(symbol=query.symbol)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPExecutiveCompensationQueryParams:
|
||||
return FMPExecutiveCompensationQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPExecutiveCompensationQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPExecutiveCompensationData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "governance/executive_compensation", api_key, query)
|
||||
return get_data_many(url, FMPExecutiveCompensationData)
|
||||
return get_data_many(url, FMPExecutiveCompensationData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPExecutiveCompensationData],
|
||||
) -> List[ExecutiveCompensationData]:
|
||||
return data_transformer(data, ExecutiveCompensationData)
|
||||
) -> List[FMPExecutiveCompensationData]:
|
||||
return data
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
"""FMP Key Executives Fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.base import BaseSymbol
|
||||
from openbb_provider.models.key_executives import (
|
||||
KeyExecutivesData,
|
||||
KeyExecutivesQueryParams,
|
||||
)
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data
|
||||
|
||||
|
||||
class FMPKeyExecutivesQueryParams(QueryParams, BaseSymbol):
|
||||
"""FMP Key Executives QueryParams.
|
||||
|
||||
Source: https://financialmodelingprep.com/developer/docs/#Key-Executives
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
key_executive_name : Optional[str]
|
||||
The name of the key executive.
|
||||
key_executive_title : Optional[str]
|
||||
The title of the key executive.
|
||||
key_executive_title_since : Optional[datetime]
|
||||
The title since of the key executive.
|
||||
key_executive_year_born : Optional[datetime]
|
||||
The year born of the key executive.
|
||||
key_executive_gender: Optional[str]
|
||||
The gender of the key executive.
|
||||
"""
|
||||
|
||||
key_executive_name: Optional[str]
|
||||
key_executive_title: Optional[str]
|
||||
key_executive_title_since: Optional[datetime]
|
||||
key_executive_year_born: Optional[datetime]
|
||||
key_executive_gender: Optional[str]
|
||||
|
||||
|
||||
class FMPKeyExecutivesData(Data):
|
||||
name: str
|
||||
title: str
|
||||
titleSince: Optional[datetime]
|
||||
yearBorn: Optional[datetime]
|
||||
gender: Optional[str]
|
||||
|
||||
|
||||
class FMPKeyExecutivesFetcher(
|
||||
Fetcher[
|
||||
KeyExecutivesQueryParams,
|
||||
KeyExecutivesData,
|
||||
FMPKeyExecutivesQueryParams,
|
||||
FMPKeyExecutivesData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: KeyExecutivesQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPKeyExecutivesQueryParams:
|
||||
return FMPKeyExecutivesQueryParams(
|
||||
symbol=query.symbol,
|
||||
key_executive_name=query.key_executive_name,
|
||||
key_executive_title=query.key_executive_title,
|
||||
key_executive_title_since=query.key_executive_title_since,
|
||||
key_executive_year_born=query.key_executive_year_born,
|
||||
key_executive_gender=query.key_executive_gender,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPKeyExecutivesQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[FMPKeyExecutivesData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
request_url = f"{base_url}key-executives/{query.symbol}?apikey={api_key}"
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, dict):
|
||||
raise ValueError("Expected list of dicts, got dict")
|
||||
|
||||
if query.key_executive_name:
|
||||
data = [x for x in data if x["name"] == query.key_executive_name]
|
||||
if query.key_executive_title:
|
||||
data = [x for x in data if x["title"] == query.key_executive_title]
|
||||
if query.key_executive_title_since:
|
||||
data = [
|
||||
x for x in data if x["titleSince"] == query.key_executive_title_since
|
||||
]
|
||||
if query.key_executive_year_born:
|
||||
data = [x for x in data if x["yearBorn"] == query.key_executive_year_born]
|
||||
if query.key_executive_gender:
|
||||
data = [x for x in data if x["gender"] == query.key_executive_gender]
|
||||
|
||||
return [FMPKeyExecutivesData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPKeyExecutivesData],
|
||||
) -> List[KeyExecutivesData]:
|
||||
return data_transformer(data, KeyExecutivesData)
|
||||
@@ -1,49 +1,47 @@
|
||||
"""FMP Forex end of day fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.forex_eod import ForexEODData, ForexEODQueryParams
|
||||
from pydantic import Field, validator
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
from openbb_fmp.utils.helpers import get_data_many, get_querystring
|
||||
|
||||
|
||||
class FMPForexEODQueryParams(QueryParams):
|
||||
"""FMP Forex end of day query.
|
||||
class FMPForexEODQueryParams(ForexEODQueryParams):
|
||||
"""FMP Forex end of day Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-Forex-Price
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
symbol: str = Field(min_length=1)
|
||||
|
||||
class FMPForexEODData(ForexEODData):
|
||||
"""FMP Forex end of day Data."""
|
||||
|
||||
class FMPForexEODData(Data):
|
||||
date: datetime
|
||||
open: float
|
||||
high: float
|
||||
low: float
|
||||
close: float
|
||||
adjClose: float = Field(alias="adj_close")
|
||||
volume: float
|
||||
unadjustedVolume: float
|
||||
change: float
|
||||
changePercent: float
|
||||
vwap: Optional[float]
|
||||
label: str
|
||||
changeOverTime: float
|
||||
adjClose: float = Field(
|
||||
description="Adjusted Close Price of the symbol.", alias="adj_close"
|
||||
)
|
||||
unadjustedVolume: float = Field(
|
||||
description="Unadjusted volume of the symbol.", alias="unadjusted_volume"
|
||||
)
|
||||
change: float = Field(
|
||||
description="Change in the price of the symbol from the previous day.",
|
||||
alias="change",
|
||||
)
|
||||
changePercent: float = Field(
|
||||
description=r"Change \% in the price of the symbol.", alias="change_percent"
|
||||
)
|
||||
label: str = Field(description="Human readable format of the date.")
|
||||
changeOverTime: float = Field(
|
||||
description=r"Change \% in the price of the symbol over a period of time.",
|
||||
alias="change_over_time",
|
||||
)
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
@@ -56,25 +54,31 @@ class FMPForexEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ForexEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPForexEODQueryParams:
|
||||
return FMPForexEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
**extra_params or {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPForexEODQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=7)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
return FMPForexEODQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPForexEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPForexEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPForexEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
url = f"{base_url}/historical-price-full/forex/{query.symbol}?&apikey={api_key}"
|
||||
return get_data_many(url, FMPForexEODData, "historical")
|
||||
query_str = get_querystring(query.dict(by_alias=True), ["symbol"])
|
||||
query_str = query_str.replace("start_date", "from").replace("end_date", "to")
|
||||
url = f"{base_url}/historical-price-full/forex/{query.symbol}?{query_str}&apikey={api_key}"
|
||||
|
||||
return get_data_many(url, FMPForexEODData, "historical", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPForexEODData]) -> List[ForexEODData]:
|
||||
return data_transformer(data, ForexEODData)
|
||||
def transform_data(data: List[FMPForexEODData]) -> List[FMPForexEODData]:
|
||||
return data
|
||||
|
||||
@@ -1,26 +1,35 @@
|
||||
"""FMP Forex available pairs fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.forex_pairs import ForexPairsData, ForexPairsQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
|
||||
|
||||
class FMPForexPairsQueryParams(QueryParams):
|
||||
"""FMP Forex available pairs query.
|
||||
class FMPForexPairsQueryParams(ForexPairsQueryParams):
|
||||
"""FMP Forex available pairs Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-Forex-Price
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class FMPForexPairsData(Data):
|
||||
"""FMP Forex available pairs data."""
|
||||
class FMPForexPairsData(ForexPairsData):
|
||||
"""FMP Forex available pairs Data."""
|
||||
|
||||
symbol: str = Field(description="The symbol of the currency pair.")
|
||||
currency: str = Field(description="The base currency of the currency pair.")
|
||||
stockExchange: Optional[str] = Field(
|
||||
description="The stock exchange of the currency pair.",
|
||||
alias="stock_exchange",
|
||||
)
|
||||
exchange_short_name: Optional[str] = Field(
|
||||
description="The short name of the stock exchange of the currency pair.",
|
||||
alias="exchange_short_name",
|
||||
)
|
||||
|
||||
|
||||
class FMPForexPairsFetcher(
|
||||
@@ -32,22 +41,22 @@ class FMPForexPairsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ForexPairsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPForexPairsQueryParams:
|
||||
return FMPForexPairsQueryParams()
|
||||
def transform_query(params: Dict[str, Any]) -> FMPForexPairsQueryParams:
|
||||
return FMPForexPairsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPForexPairsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPForexPairsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPForexPairsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
url = f"{base_url}/symbol/available-forex-currency-pairs?apikey={api_key}"
|
||||
return get_data_many(url, FMPForexPairsData)
|
||||
|
||||
return get_data_many(url, FMPForexPairsData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPForexPairsData]) -> List[ForexPairsData]:
|
||||
return data_transformer(data, ForexPairsData)
|
||||
def transform_data(data: List[FMPForexPairsData]) -> List[FMPForexPairsData]:
|
||||
return data
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
"""FMP Forex Price fetcher."""
|
||||
|
||||
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.forex_price import ForexPriceData, ForexPriceQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
|
||||
class Interval(str, Enum):
|
||||
oneminute = "1min"
|
||||
fiveminute = "5min"
|
||||
fifteenminute = "15min"
|
||||
thirtyminute = "30min"
|
||||
onehour = "1hour"
|
||||
fourhour = "4hour"
|
||||
|
||||
|
||||
class FMPForexPriceQueryParams(QueryParams):
|
||||
"""FMP Forex Price query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Forex-Historical-Price
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
interval : Enum of ["1min", "5min", "15min", "30min", "1hour", "4hour"] (default: "1hour")
|
||||
The interval of the data.
|
||||
"""
|
||||
|
||||
symbol: str = Field(min_length=1)
|
||||
interval: Literal["1min", "5min", "15min", "30min", "1hour", "4hour"] = "1hour"
|
||||
|
||||
|
||||
class FMPForexPriceData(BaseStockPriceData):
|
||||
"""FMP Forex Price data."""
|
||||
|
||||
|
||||
class FMPForexPriceFetcher(
|
||||
Fetcher[
|
||||
ForexPriceQueryParams,
|
||||
ForexPriceData,
|
||||
FMPForexPriceQueryParams,
|
||||
FMPForexPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ForexPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPForexPriceQueryParams:
|
||||
return FMPForexPriceQueryParams(
|
||||
symbol=query.symbol, **extra_params if extra_params else {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPForexPriceQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[FMPForexPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
|
||||
url = create_url(
|
||||
3, f"historical-chart/{query.interval}/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPForexPriceData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPForexPriceData]) -> List[ForexPriceData]:
|
||||
return data_transformer(data, ForexPriceData)
|
||||
@@ -1,39 +1,27 @@
|
||||
"""FMP Global News fetcher."""
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.global_news import GlobalNewsData, GlobalNewsQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPGlobalNewsQueryParams(QueryParams):
|
||||
class FMPGlobalNewsQueryParams(GlobalNewsQueryParams):
|
||||
"""FMP Global News query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/general-news-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
page : int (default: 0)
|
||||
The page of the data to retrieve.
|
||||
"""
|
||||
|
||||
page: int = Field(default=0)
|
||||
|
||||
class FMPGlobalNewsData(GlobalNewsData):
|
||||
# publishedDate: datetime = Field(alias="date")
|
||||
class Config:
|
||||
fields = {"date": "publishedDate"}
|
||||
|
||||
class FMPGlobalNewsData(Data):
|
||||
publishedDate: datetime = Field(alias="date")
|
||||
title: str
|
||||
image: str
|
||||
text: str
|
||||
url: str
|
||||
site: str
|
||||
site: str = Field(description="The site of the news.")
|
||||
|
||||
|
||||
class FMPGlobalNewsFetcher(
|
||||
@@ -45,21 +33,20 @@ class FMPGlobalNewsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: GlobalNewsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPGlobalNewsQueryParams:
|
||||
return FMPGlobalNewsQueryParams(page=query.page)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPGlobalNewsQueryParams:
|
||||
return FMPGlobalNewsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPGlobalNewsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPGlobalNewsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPGlobalNewsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "general_news", api_key, query)
|
||||
return get_data_many(url, FMPGlobalNewsData)
|
||||
return get_data_many(url, FMPGlobalNewsData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPGlobalNewsData]) -> List[GlobalNewsData]:
|
||||
return data_transformer(data, GlobalNewsData)
|
||||
def transform_data(data: List[FMPGlobalNewsData]) -> List[FMPGlobalNewsData]:
|
||||
return data
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
"""FMP Historical Dividends fetcher."""
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.historical_dividends import (
|
||||
HistoricalDividendsData,
|
||||
HistoricalDividendsQueryParams,
|
||||
@@ -22,34 +19,29 @@ class FMPHistoricalDividendsQueryParams(HistoricalDividendsQueryParams):
|
||||
"""FMP Historical Dividends query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-Dividends
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPHistoricalDividendsData(Data):
|
||||
class FMPHistoricalDividendsData(HistoricalDividendsData):
|
||||
"""FMP Historical Dividends data."""
|
||||
|
||||
date: dateType
|
||||
label: str
|
||||
adjDividend: float
|
||||
dividend: float
|
||||
recordDate: Optional[dateType]
|
||||
paymentDate: Optional[dateType]
|
||||
declarationDate: Optional[dateType]
|
||||
class Config:
|
||||
fields = {
|
||||
"adj_dividend": "adjDividend",
|
||||
"record_date": "recordDate",
|
||||
"payment_date": "paymentDate",
|
||||
"declaration_date": "declarationDate",
|
||||
}
|
||||
|
||||
@validator("declarationDate", pre=True)
|
||||
@validator("declarationDate", pre=True, check_fields=False)
|
||||
def declaration_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@validator("recordDate", pre=True)
|
||||
@validator("recordDate", pre=True, check_fields=False)
|
||||
def record_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@validator("paymentDate", pre=True)
|
||||
@validator("paymentDate", pre=True, check_fields=False)
|
||||
def payment_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
@@ -63,28 +55,24 @@ class FMPHistoricalDividendsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: HistoricalDividendsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPHistoricalDividendsQueryParams:
|
||||
return FMPHistoricalDividendsQueryParams(
|
||||
symbol=query.symbol,
|
||||
**extra_params or {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPHistoricalDividendsQueryParams:
|
||||
return FMPHistoricalDividendsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPHistoricalDividendsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPHistoricalDividendsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPHistoricalDividendsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"historical-price-full/stock_dividend/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPHistoricalDividendsData, "historical")
|
||||
return get_data_many(url, FMPHistoricalDividendsData, "historical", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPHistoricalDividendsData],
|
||||
) -> List[HistoricalDividendsData]:
|
||||
return data_transformer(data, HistoricalDividendsData)
|
||||
) -> List[FMPHistoricalDividendsData]:
|
||||
return data
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
"""FMP Historical Employees fetcher."""
|
||||
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.historical_employees import (
|
||||
HistoricalEmployeesData,
|
||||
HistoricalEmployeesQueryParams,
|
||||
)
|
||||
from pydantic import Field, validator
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
@@ -20,36 +18,31 @@ class FMPHistoricalEmployeesQueryParams(HistoricalEmployeesQueryParams):
|
||||
"""FMP Historical Employees query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/historical-numer-of-employees-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPHistoricalEmployeesData(Data):
|
||||
"""FMP Historical Employees data."""
|
||||
class FMPHistoricalEmployeesData(HistoricalEmployeesData):
|
||||
"""FMP Historical Employees Data."""
|
||||
|
||||
symbol: str = Field(min_length=1)
|
||||
cik: int
|
||||
acceptanceTime: datetime = Field(alias="acceptance_time")
|
||||
periodOfReport: date = Field(alias="period_of_report")
|
||||
companyName: str = Field(alias="company_name")
|
||||
formType: str = Field(alias="form_type")
|
||||
filingDate: date = Field(alias="filing_date")
|
||||
employeeCount: int = Field(alias="employee_count")
|
||||
source: str
|
||||
class Config:
|
||||
fields = {
|
||||
"acceptance_time": "acceptanceTime",
|
||||
"period_of_report": "periodOfReport",
|
||||
"company_name": "companyName",
|
||||
"form_type": "formType",
|
||||
"filing_date": "filingDate",
|
||||
"employee_count": "employeeCount",
|
||||
}
|
||||
|
||||
@validator("acceptanceTime", pre=True)
|
||||
@validator("acceptanceTime", pre=True, check_fields=False)
|
||||
def acceptance_time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
@validator("periodOfReport", pre=True)
|
||||
@validator("periodOfReport", pre=True, check_fields=False)
|
||||
def period_of_report_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
@validator("filingDate", pre=True)
|
||||
@validator("filingDate", pre=True, check_fields=False)
|
||||
def filing_date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
@@ -63,25 +56,22 @@ class FMPHistoricalEmployeesFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: HistoricalEmployeesQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPHistoricalEmployeesQueryParams:
|
||||
return FMPHistoricalEmployeesQueryParams(
|
||||
symbol=query.symbol, **extra_params or {}
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPHistoricalEmployeesQueryParams:
|
||||
return FMPHistoricalEmployeesQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPHistoricalEmployeesQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPHistoricalEmployeesQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPHistoricalEmployeesData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "historical/employee_count", api_key, query)
|
||||
return get_data_many(url, FMPHistoricalEmployeesData)
|
||||
return get_data_many(url, FMPHistoricalEmployeesData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPHistoricalEmployeesData],
|
||||
) -> List[HistoricalEmployeesData]:
|
||||
return data_transformer(data, HistoricalEmployeesData)
|
||||
) -> List[FMPHistoricalEmployeesData]:
|
||||
return data
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
"""FMP Historical Stock Splits fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.historical_stock_splits import (
|
||||
HistoricalStockSplitsData,
|
||||
HistoricalStockSplitsQueryParams,
|
||||
)
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPHistoricalStockSplitsQueryParams(HistoricalStockSplitsQueryParams):
|
||||
"""FMP Historical Stock Splits query.
|
||||
"""FMP Historical Stock Splits Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/historical-stock-splits-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPHistoricalStockSplitsData(HistoricalStockSplitsData):
|
||||
"""FMP Historical Stock Splits data."""
|
||||
"""FMP Historical Stock Splits Data."""
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
|
||||
class FMPHistoricalStockSplitsFetcher(
|
||||
@@ -38,26 +38,24 @@ class FMPHistoricalStockSplitsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: HistoricalStockSplitsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPHistoricalStockSplitsQueryParams:
|
||||
return FMPHistoricalStockSplitsQueryParams(symbol=query.symbol)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPHistoricalStockSplitsQueryParams:
|
||||
return FMPHistoricalStockSplitsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPHistoricalStockSplitsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPHistoricalStockSplitsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"historical-price-full/stock_split/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPHistoricalStockSplitsData, "historical")
|
||||
return get_data_many(url, FMPHistoricalStockSplitsData, "historical", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPHistoricalStockSplitsData],
|
||||
) -> List[HistoricalStockSplitsData]:
|
||||
return data_transformer(data, HistoricalStockSplitsData)
|
||||
) -> List[FMPHistoricalStockSplitsData]:
|
||||
return data
|
||||
|
||||
@@ -1,47 +1,31 @@
|
||||
"""FMP Income Statement Fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.income_statement import (
|
||||
IncomeStatementData,
|
||||
IncomeStatementQueryParams,
|
||||
)
|
||||
from pydantic import Field, NonNegativeInt, root_validator
|
||||
from pydantic import Field, root_validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
|
||||
PeriodType = Literal["annual", "quarter"]
|
||||
|
||||
|
||||
class FMPIncomeStatementQueryParams(QueryParams):
|
||||
class FMPIncomeStatementQueryParams(IncomeStatementQueryParams):
|
||||
"""FMP Income Statement QueryParams.
|
||||
|
||||
Source: https://financialmodelingprep.com/developer/docs/#Income-Statement
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : Optional[str]
|
||||
The symbol of the company if no CIK is provided.
|
||||
cik : Optional[str]
|
||||
The CIK of the company if no symbol is provided.
|
||||
period : Literal["annual", "quarter"]
|
||||
The period of the income statement. Default is "annual".
|
||||
limit : Optional[NonNegativeInt]
|
||||
The limit of the income statement.
|
||||
Either a Symbol or CIK is required. Symbol is preferred over CIK.
|
||||
"""
|
||||
|
||||
symbol: Optional[str]
|
||||
cik: Optional[str]
|
||||
period: PeriodType = Field(default="annual")
|
||||
limit: Optional[NonNegativeInt]
|
||||
cik: Optional[str] = Field(
|
||||
description="The CIK of the company if no symbol is provided."
|
||||
)
|
||||
|
||||
@root_validator()
|
||||
def check_symbol_or_cik(cls, values): # pylint: disable=no-self-argument
|
||||
@@ -50,47 +34,39 @@ class FMPIncomeStatementQueryParams(QueryParams):
|
||||
return values
|
||||
|
||||
|
||||
class FMPIncomeStatementData(Data):
|
||||
date: dateType
|
||||
symbol: str
|
||||
reportedCurrency: str = Field(alias="currency")
|
||||
cik: Optional[int]
|
||||
fillingDate: Optional[dateType] = Field(alias="filing_date")
|
||||
acceptedDate: Optional[datetime]
|
||||
class FMPIncomeStatementData(IncomeStatementData):
|
||||
class Config:
|
||||
fields = {
|
||||
"currency": "reportedCurrency",
|
||||
"filing_date": "fillingDate",
|
||||
"accepted_date": "acceptedDate",
|
||||
"cost_of_revenue": "costOfRevenue",
|
||||
"gross_profit": "grossProfit",
|
||||
"research_and_development_expenses": "researchAndDevelopmentExpenses",
|
||||
"general_and_administrative_expenses": "generalAndAdministrativeExpenses",
|
||||
"selling_and_marketing_expenses": "sellingAndMarketingExpenses",
|
||||
"selling_general_and_administrative_expenses": "sellingGeneralAndAdministrativeExpenses",
|
||||
"other_expenses": "otherExpenses",
|
||||
"operating_expenses": "operatingExpenses",
|
||||
"depreciation_and_amortization": "depreciationAndAmortization",
|
||||
"operating_income": "operatingIncome",
|
||||
"interest_income": "interestIncome",
|
||||
"interest_expense": "interestExpense",
|
||||
"total_other_income_expenses_net": "totalOtherIncomeExpensesNet",
|
||||
"income_before_tax": "incomeBeforeTax",
|
||||
"income_tax_expense": "incomeTaxExpense",
|
||||
"net_income": "netIncome",
|
||||
"eps_diluted": "epsdiluted",
|
||||
"weighted_average_shares_outstanding": "weightedAverageShsOut",
|
||||
"weighted_average_shares_outstanding_dil": "weightedAverageShsOutDil",
|
||||
}
|
||||
|
||||
calendarYear: Optional[int]
|
||||
period: Optional[str]
|
||||
revenue: Optional[int]
|
||||
costOfRevenue: Optional[int]
|
||||
grossProfit: Optional[int]
|
||||
grossProfitRatio: Optional[float]
|
||||
researchAndDevelopmentExpenses: Optional[int]
|
||||
generalAndAdministrativeExpenses: Optional[int]
|
||||
sellingAndMarketingExpenses: Optional[int]
|
||||
sellingGeneralAndAdministrativeExpenses: Optional[int]
|
||||
otherExpenses: Optional[int]
|
||||
operatingExpenses: Optional[int]
|
||||
costAndExpenses: Optional[int]
|
||||
interestIncome: Optional[int]
|
||||
interestExpense: Optional[int]
|
||||
depreciationAndAmortization: Optional[int]
|
||||
ebitda: Optional[int]
|
||||
ebitdaratio: Optional[float]
|
||||
operatingIncome: Optional[int]
|
||||
operatingIncomeRatio: Optional[float]
|
||||
totalOtherIncomeExpensesNet: Optional[int]
|
||||
incomeBeforeTax: Optional[int]
|
||||
incomeBeforeTaxRatio: Optional[float]
|
||||
incomeTaxExpense: Optional[int]
|
||||
netIncome: Optional[int]
|
||||
netIncomeRatio: Optional[float]
|
||||
eps: Optional[float]
|
||||
epsdiluted: Optional[float] = Field(alias="eps_diluted")
|
||||
weightedAverageShsOut: Optional[int] = Field(
|
||||
alias="weighted_average_shares_outstanding"
|
||||
)
|
||||
weightedAverageShsOutDil: Optional[int] = Field(
|
||||
alias="weighted_average_shares_outstanding_dil"
|
||||
)
|
||||
link: Optional[str]
|
||||
finalLink: Optional[str]
|
||||
|
||||
@@ -104,28 +80,29 @@ class FMPIncomeStatementFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: IncomeStatementQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPIncomeStatementQueryParams:
|
||||
period: PeriodType = "annual" if query.period == "annually" else "quarter"
|
||||
return FMPIncomeStatementQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {}
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPIncomeStatementQueryParams:
|
||||
return FMPIncomeStatementQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPIncomeStatementQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPIncomeStatementQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPIncomeStatementData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"income-statement/{query.symbol}", api_key, query, ["symbol"]
|
||||
symbol = query.symbol or query.cik
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
|
||||
url = (
|
||||
f"{base_url}/income-statement/{symbol}?"
|
||||
f"period={query.period}&limit={query.limit}&apikey={api_key}"
|
||||
)
|
||||
return get_data_many(url, FMPIncomeStatementData)
|
||||
|
||||
return get_data_many(url, FMPIncomeStatementData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPIncomeStatementData],
|
||||
) -> List[IncomeStatementData]:
|
||||
return data_transformer(data, IncomeStatementData)
|
||||
) -> List[FMPIncomeStatementData]:
|
||||
return data
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
"""FMP Income Statement Growth Fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.models.income_statement_growth import (
|
||||
IncomeStatementGrowthData,
|
||||
IncomeStatementGrowthQueryParams,
|
||||
)
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPIncomeStatementGrowthQueryParams(IncomeStatementGrowthQueryParams):
|
||||
"""FMP Income Statement Growth QueryParams.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/financial-statements-growth-api/
|
||||
"""
|
||||
|
||||
|
||||
class FMPIncomeStatementGrowthData(IncomeStatementGrowthData):
|
||||
"""FMP Income Statement Growth Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"growth_revenue": "growthRevenue",
|
||||
"growth_cost_of_revenue": "growthCostOfRevenue",
|
||||
"growth_gross_profit": "growthGrossProfit",
|
||||
"growth_gross_profit_ratio": "growthGrossProfitRatio",
|
||||
"growth_research_and_development_expenses": "growthResearchAndDevelopmentExpenses",
|
||||
"growth_general_and_administrative_expenses": "growthGeneralAndAdministrativeExpenses",
|
||||
"growth_selling_and_marketing_expenses": "growthSellingAndMarketingExpenses",
|
||||
"growth_other_expenses": "growthOtherExpenses",
|
||||
"growth_operating_expenses": "growthOperatingExpenses",
|
||||
"growth_cost_and_expenses": "growthCostAndExpenses",
|
||||
"growth_interest_expense": "growthInterestExpense",
|
||||
"growth_depreciation_and_amortization": "growthDepreciationAndAmortization",
|
||||
"growth_ebitda": "growthEBITDA",
|
||||
"growth_ebitda_ratio": "growthEBITDARatio",
|
||||
"growth_operating_income": "growthOperatingIncome",
|
||||
"growth_operating_income_ratio": "growthOperatingIncomeRatio",
|
||||
"growth_total_other_income_expenses_net": "growthTotalOtherIncomeExpensesNet",
|
||||
"growth_income_before_tax": "growthIncomeBeforeTax",
|
||||
"growth_income_before_tax_ratio": "growthIncomeBeforeTaxRatio",
|
||||
"growth_income_tax_expense": "growthIncomeTaxExpense",
|
||||
"growth_net_income": "growthNetIncome",
|
||||
"growth_net_income_ratio": "growthNetIncomeRatio",
|
||||
"growth_eps": "growthEPS",
|
||||
"growth_eps_diluted": "growthEPSDiluted",
|
||||
"growth_weighted_average_shs_out": "growthWeightedAverageShsOut",
|
||||
"growth_weighted_average_shs_out_dil": "growthWeightedAverageShsOutDil",
|
||||
}
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
class FMPIncomeStatementGrowthFetcher(
|
||||
Fetcher[
|
||||
IncomeStatementGrowthQueryParams,
|
||||
IncomeStatementGrowthData,
|
||||
FMPIncomeStatementGrowthQueryParams,
|
||||
FMPIncomeStatementGrowthData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> FMPIncomeStatementGrowthQueryParams:
|
||||
return FMPIncomeStatementGrowthQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPIncomeStatementGrowthQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPIncomeStatementGrowthData]:
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
url = create_url(
|
||||
3, f"income-statement-growth/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPIncomeStatementGrowthData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPIncomeStatementGrowthData],
|
||||
) -> List[FMPIncomeStatementGrowthData]:
|
||||
return data
|
||||
@@ -1,83 +1,67 @@
|
||||
"""FMP Institutional Ownership Fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.base import BaseSymbol
|
||||
from openbb_provider.models.institutional_ownership import (
|
||||
InstitutionalOwnershipData,
|
||||
InstitutionalOwnershipQueryParams,
|
||||
)
|
||||
from pydantic import Field, validator
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPInstitutionalOwnershipQueryParams(QueryParams, BaseSymbol):
|
||||
"""FMP Institutional Ownership QueryParams.
|
||||
class FMPInstitutionalOwnershipQueryParams(InstitutionalOwnershipQueryParams):
|
||||
"""FMP Institutional Ownership Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/institutional-stock-ownership-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company if cik is not provided.
|
||||
include_current_quarter : bool
|
||||
Whether to include the current quarter. Default is False.
|
||||
date : Optional[dateType]
|
||||
A specific date to get data for.
|
||||
"""
|
||||
|
||||
includeCurrentQuarter: bool = Field(default=False, alias="include_current_quarter")
|
||||
date: Optional[dateType]
|
||||
|
||||
class FMPInstitutionalOwnershipData(InstitutionalOwnershipData):
|
||||
"""FMP Institutional Ownership Data."""
|
||||
|
||||
class FMPInstitutionalOwnershipData(Data):
|
||||
symbol: str = Field(min_length=1)
|
||||
cik: str = Field(min_length=1)
|
||||
date: dateType
|
||||
investorsHolding: int
|
||||
lastInvestorsHolding: int
|
||||
investorsHoldingChange: int
|
||||
numberOf13Fshares: int
|
||||
lastNumberOf13Fshares: int
|
||||
numberOf13FsharesChange: int
|
||||
totalInvested: float
|
||||
lastTotalInvested: float
|
||||
totalInvestedChange: float
|
||||
ownershipPercent: float
|
||||
lastOwnershipPercent: float
|
||||
ownershipPercentChange: float
|
||||
newPositions: int
|
||||
lastNewPositions: int
|
||||
newPositionsChange: int
|
||||
increasedPositions: int
|
||||
lastIncreasedPositions: int
|
||||
increasedPositionsChange: int
|
||||
closedPositions: int
|
||||
lastClosedPositions: int
|
||||
closedPositionsChange: int
|
||||
reducedPositions: int
|
||||
lastReducedPositions: int
|
||||
reducedPositionsChange: int
|
||||
totalCalls: int
|
||||
lastTotalCalls: int
|
||||
totalCallsChange: int
|
||||
totalPuts: int
|
||||
lastTotalPuts: int
|
||||
totalPutsChange: int
|
||||
putCallRatio: float
|
||||
lastPutCallRatio: float
|
||||
putCallRatioChange: float
|
||||
class Config:
|
||||
fields = {
|
||||
"investors_holding": "investorsHolding",
|
||||
"last_investors_holding": "lastInvestorsHolding",
|
||||
"investors_holding_change": "investorsHoldingChange",
|
||||
"number_of_13f_shares": "numberOf13Fshares",
|
||||
"last_number_of_13f_shares": "lastNumberOf13Fshares",
|
||||
"number_of_13f_shares_change": "numberOf13FsharesChange",
|
||||
"total_invested": "totalInvested",
|
||||
"last_total_invested": "lastTotalInvested",
|
||||
"total_invested_change": "totalInvestedChange",
|
||||
"ownership_percent": "ownershipPercent",
|
||||
"last_ownership_percent": "lastOwnershipPercent",
|
||||
"ownership_percent_change": "ownershipPercentChange",
|
||||
"new_positions": "newPositions",
|
||||
"last_new_positions": "lastNewPositions",
|
||||
"new_positions_change": "newPositionsChange",
|
||||
"increased_positions": "increasedPositions",
|
||||
"last_increased_positions": "lastIncreasedPositions",
|
||||
"increased_positions_change": "increasedPositionsChange",
|
||||
"closed_positions": "closedPositions",
|
||||
"last_closed_positions": "lastClosedPositions",
|
||||
"closed_positions_change": "closedPositionsChange",
|
||||
"reduced_positions": "reducedPositions",
|
||||
"last_reduced_positions": "lastReducedPositions",
|
||||
"reduced_positions_change": "reducedPositionsChange",
|
||||
"total_calls": "totalCalls",
|
||||
"last_total_calls": "lastTotalCalls",
|
||||
"total_calls_change": "totalCallsChange",
|
||||
"total_puts": "totalPuts",
|
||||
"last_total_puts": "lastTotalPuts",
|
||||
"total_puts_change": "totalPutsChange",
|
||||
"put_call_ratio": "putCallRatio",
|
||||
"last_put_call_ratio": "lastPutCallRatio",
|
||||
"put_call_ratio_change": "putCallRatioChange",
|
||||
}
|
||||
|
||||
@validator("date", pre=True)
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def time_validate(cls, v): # pylint: disable=no-self-argument
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
@@ -91,29 +75,22 @@ class FMPInstitutionalOwnershipFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: InstitutionalOwnershipQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPInstitutionalOwnershipQueryParams:
|
||||
return FMPInstitutionalOwnershipQueryParams(
|
||||
symbol=query.symbol,
|
||||
date=query.date,
|
||||
include_current_quarter=query.include_current_quarter,
|
||||
**extra_params if extra_params else {}
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPInstitutionalOwnershipQueryParams:
|
||||
return FMPInstitutionalOwnershipQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPInstitutionalOwnershipQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPInstitutionalOwnershipData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "institutional-ownership/symbol-ownership", api_key, query)
|
||||
return get_data_many(url, FMPInstitutionalOwnershipData)
|
||||
return get_data_many(url, FMPInstitutionalOwnershipData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPInstitutionalOwnershipData],
|
||||
) -> List[InstitutionalOwnershipData]:
|
||||
return data_transformer(data, InstitutionalOwnershipData)
|
||||
) -> List[FMPInstitutionalOwnershipData]:
|
||||
return data
|
||||
|
||||
68
openbb_sdk/providers/fmp/openbb_fmp/models/key_executives.py
Normal file
68
openbb_sdk/providers/fmp/openbb_fmp/models/key_executives.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""FMP Key Executives Fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.models.key_executives import (
|
||||
KeyExecutivesData,
|
||||
KeyExecutivesQueryParams,
|
||||
)
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
|
||||
|
||||
class FMPKeyExecutivesQueryParams(KeyExecutivesQueryParams):
|
||||
"""FMP Key Executives QueryParams.
|
||||
|
||||
Source: https://financialmodelingprep.com/developer/docs/#Key-Executives
|
||||
"""
|
||||
|
||||
|
||||
class FMPKeyExecutivesData(KeyExecutivesData):
|
||||
"""FMP Key Executives Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"currency_pay": "currencyPay",
|
||||
"year_born": "yearBorn",
|
||||
"title_since": "titleSince",
|
||||
}
|
||||
|
||||
@validator("titleSince", pre=True, check_fields=False)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.fromtimestamp(v / 1000)
|
||||
|
||||
|
||||
class FMPKeyExecutivesFetcher(
|
||||
Fetcher[
|
||||
KeyExecutivesQueryParams,
|
||||
KeyExecutivesData,
|
||||
FMPKeyExecutivesQueryParams,
|
||||
FMPKeyExecutivesData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> FMPKeyExecutivesQueryParams:
|
||||
return FMPKeyExecutivesQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPKeyExecutivesQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPKeyExecutivesData]:
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
url = f"{base_url}/key-executives/{query.symbol}?apikey={api_key}"
|
||||
|
||||
return get_data_many(url, FMPKeyExecutivesData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPKeyExecutivesData],
|
||||
) -> List[FMPKeyExecutivesData]:
|
||||
return data
|
||||
@@ -1,103 +1,88 @@
|
||||
"""Key Metrics fetcher."""
|
||||
|
||||
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.key_metrics import KeyMetricsData, KeyMetricsQueryParams
|
||||
from pydantic import Field
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPKeyMetricsQueryParams(QueryParams):
|
||||
"""FMP Key Metrics QueryParams.
|
||||
class FMPKeyMetricsQueryParams(KeyMetricsQueryParams):
|
||||
"""FMP Key Metrics Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/company-key-metrics-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
period : Literal["quarter", "annual"]
|
||||
The period of the key metrics. Default is "annual".
|
||||
limit : Optional[int]
|
||||
The limit of the key metrics to be returned.
|
||||
"""
|
||||
|
||||
symbol: str
|
||||
period: Literal["quarter", "annual"] = "annual"
|
||||
limit: Optional[int] = None
|
||||
|
||||
class FMPKeyMetricsData(KeyMetricsData):
|
||||
"""FMP Key Metrics Data."""
|
||||
|
||||
class FMPKeyMetricsData(Data):
|
||||
symbol: str
|
||||
date: dateType
|
||||
period: str
|
||||
revenuePerShare: float
|
||||
netIncomePerShare: float
|
||||
operatingCashFlowPerShare: Optional[float]
|
||||
freeCashFlowPerShare: Optional[float]
|
||||
cashPerShare: Optional[float]
|
||||
bookValuePerShare: Optional[float]
|
||||
tangibleBookValuePerShare: Optional[float]
|
||||
shareholdersEquityPerShare: Optional[float]
|
||||
interestDebtPerShare: Optional[float]
|
||||
marketCap: Optional[float]
|
||||
enterpriseValue: Optional[float]
|
||||
peRatio: Optional[float]
|
||||
priceToSalesRatio: Optional[float]
|
||||
pocfratio: Optional[float] = Field(alias="pocf_ratio")
|
||||
pfcfRatio: Optional[float]
|
||||
pbRatio: Optional[float]
|
||||
ptbRatio: Optional[float]
|
||||
evToSales: Optional[float]
|
||||
enterpriseValueOverEBITDA: Optional[float] = Field(
|
||||
alias="enterprise_value_over_ebitda"
|
||||
)
|
||||
evToOperatingCashFlow: Optional[float]
|
||||
evToFreeCashFlow: Optional[float]
|
||||
earningsYield: Optional[float]
|
||||
freeCashFlowYield: Optional[Optional[float]]
|
||||
debtToEquity: Optional[float]
|
||||
debtToAssets: Optional[float]
|
||||
netDebtToEBITDA: Optional[float] = Field(alias="net_debt_to_ebitda")
|
||||
currentRatio: Optional[float]
|
||||
interestCoverage: Optional[float]
|
||||
incomeQuality: Optional[float]
|
||||
dividendYield: Optional[Optional[float]]
|
||||
payoutRatio: Optional[Optional[float]]
|
||||
salesGeneralAndAdministrativeToRevenue: Optional[float]
|
||||
researchAndDdevelopementToRevenue: Optional[float] = Field(
|
||||
alias="research_and_developement_to_revenue"
|
||||
)
|
||||
intangiblesToTotalAssets: Optional[float]
|
||||
capexToOperatingCashFlow: Optional[float]
|
||||
capexToRevenue: Optional[float]
|
||||
capexToDepreciation: Optional[float]
|
||||
stockBasedCompensationToRevenue: Optional[float]
|
||||
grahamNumber: Optional[float]
|
||||
roic: Optional[float]
|
||||
returnOnTangibleAssets: Optional[float]
|
||||
grahamNetNet: Optional[float]
|
||||
workingCapital: Optional[float]
|
||||
tangibleAssetValue: Optional[float]
|
||||
netCurrentAssetValue: Optional[float]
|
||||
investedCapital: Optional[float]
|
||||
averageReceivables: Optional[float]
|
||||
averagePayables: Optional[float]
|
||||
averageInventory: Optional[float]
|
||||
daysSalesOutstanding: Optional[float]
|
||||
daysPayablesOutstanding: Optional[float]
|
||||
daysOfInventoryOnHand: Optional[float]
|
||||
receivablesTurnover: Optional[float]
|
||||
payablesTurnover: Optional[float]
|
||||
inventoryTurnover: Optional[float]
|
||||
roe: Optional[float]
|
||||
capexPerShare: Optional[float]
|
||||
class Config:
|
||||
fields = {
|
||||
"revenue_per_share": "revenuePerShare",
|
||||
"net_income_per_share": "netIncomePerShare",
|
||||
"operating_cash_flow_per_share": "operatingCashFlowPerShare",
|
||||
"free_cash_flow_per_share": "freeCashFlowPerShare",
|
||||
"cash_per_share": "cashPerShare",
|
||||
"book_value_per_share": "bookValuePerShare",
|
||||
"tangible_book_value_per_share": "tangibleBookValuePerShare",
|
||||
"shareholders_equity_per_share": "shareholdersEquityPerShare",
|
||||
"interest_debt_per_share": "interestDebtPerShare",
|
||||
"market_cap": "marketCap",
|
||||
"enterprise_value": "enterpriseValue",
|
||||
"pe_ratio": "peRatio",
|
||||
"price_to_sales_ratio": "priceToSalesRatio",
|
||||
"pocf_ratio": "pocfratio",
|
||||
"pfcf_ratio": "pfcfRatio",
|
||||
"pb_ratio": "pbRatio",
|
||||
"ptb_ratio": "ptbRatio",
|
||||
"ev_to_sales": "evToSales",
|
||||
"enterprise_value_over_ebitda": "enterpriseValueOverEBITDA",
|
||||
"ev_to_operating_cash_flow": "evToOperatingCashFlow",
|
||||
"ev_to_free_cash_flow": "evToFreeCashFlow",
|
||||
"earnings_yield": "earningsYield",
|
||||
"free_cash_flow_yield": "freeCashFlowYield",
|
||||
"debt_to_equity": "debtToEquity",
|
||||
"debt_to_assets": "debtToAssets",
|
||||
"net_debt_to_ebitda": "netDebtToEBITDA",
|
||||
"current_ratio": "currentRatio",
|
||||
"interest_coverage": "interestCoverage",
|
||||
"income_quality": "incomeQuality",
|
||||
"dividend_yield": "dividendYield",
|
||||
"payout_ratio": "payoutRatio",
|
||||
"sales_general_and_administrative_to_revenue": "salesGeneralAndAdministrativeToRevenue",
|
||||
"research_and_development_to_revenue": "researchAndDdevelopementToRevenue",
|
||||
"intangibles_to_total_assets": "intangiblesToTotalAssets",
|
||||
"capex_to_operating_cash_flow": "capexToOperatingCashFlow",
|
||||
"capex_to_revenue": "capexToRevenue",
|
||||
"capex_to_depreciation": "capexToDepreciation",
|
||||
"stock_based_compensation_to_revenue": "stockBasedCompensationToRevenue",
|
||||
"graham_number": "grahamNumber",
|
||||
"return_on_tangible_assets": "returnOnTangibleAssets",
|
||||
"graham_net_net": "grahamNetNet",
|
||||
"working_capital": "workingCapital",
|
||||
"tangible_asset_value": "tangibleAssetValue",
|
||||
"net_current_asset_value": "netCurrentAssetValue",
|
||||
"invested_capital": "investedCapital",
|
||||
"average_receivables": "averageReceivables",
|
||||
"average_payables": "averagePayables",
|
||||
"average_inventory": "averageInventory",
|
||||
"days_sales_outstanding": "daysSalesOutstanding",
|
||||
"days_payables_outstanding": "daysPayablesOutstanding",
|
||||
"days_of_inventory_on_hand": "daysOfInventoryOnHand",
|
||||
"receivables_turnover": "receivablesTurnover",
|
||||
"payables_turnover": "payablesTurnover",
|
||||
"inventory_turnover": "inventoryTurnover",
|
||||
"capex_per_share": "capexPerShare",
|
||||
}
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v): # pylint: disable=no-self-argument
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
class FMPKeyMetricsFetcher(
|
||||
@@ -109,27 +94,24 @@ class FMPKeyMetricsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: KeyMetricsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPKeyMetricsQueryParams:
|
||||
return FMPKeyMetricsQueryParams(
|
||||
symbol=query.symbol,
|
||||
limit=query.limit,
|
||||
period="annual" if query.period == "annually" else "quarter",
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPKeyMetricsQueryParams:
|
||||
return FMPKeyMetricsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPKeyMetricsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPKeyMetricsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPKeyMetricsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
url = create_url(
|
||||
3, f"key-metrics/{query.symbol}", api_key, query, exclude=["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPKeyMetricsData)
|
||||
return get_data_many(url, FMPKeyMetricsData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPKeyMetricsData]) -> List[KeyMetricsData]:
|
||||
return data_transformer(data, KeyMetricsData)
|
||||
def transform_data(data: List[FMPKeyMetricsData]) -> List[FMPKeyMetricsData]:
|
||||
return data
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.major_indices_constituents import (
|
||||
MajorIndicesConstituentsData,
|
||||
MajorIndicesConstituentsQueryParams,
|
||||
@@ -21,18 +20,20 @@ class FMPMajorIndicesConstituentsQueryParams(MajorIndicesConstituentsQueryParams
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/list-of-dow-companies-api/
|
||||
https://site.financialmodelingprep.com/developer/docs/list-of-sp-500-companies-api/
|
||||
https://site.financialmodelingprep.com/developer/docs/list-of-nasdaq-companies-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
index : Literal['nasdaq', 'sp500', 'dowjones']
|
||||
The index for which we want to fetch the constituents. Default is 'dowjones'.
|
||||
"""
|
||||
|
||||
|
||||
class FMPMajorIndicesConstituentsData(MajorIndicesConstituentsData):
|
||||
"""FMP Major Indices Constituents data."""
|
||||
|
||||
@validator("dateFirstAdded", pre=True)
|
||||
class Config:
|
||||
fields = {
|
||||
"sub_sector": "subSector",
|
||||
"headquarter": "headQuarter",
|
||||
"date_first_added": "dateFirstAdded",
|
||||
}
|
||||
|
||||
@validator("dateFirstAdded", pre=True, check_fields=False)
|
||||
def date_first_added_validate(cls, v): # pylint: disable=E0213
|
||||
try:
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
@@ -40,7 +41,7 @@ class FMPMajorIndicesConstituentsData(MajorIndicesConstituentsData):
|
||||
# For returning string in case of mismatched dates
|
||||
return v
|
||||
|
||||
@validator("founded", pre=True)
|
||||
@validator("founded", pre=True, check_fields=False)
|
||||
def founded_validate(cls, v): # pylint: disable=E0213
|
||||
try:
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
@@ -59,23 +60,25 @@ class FMPMajorIndicesConstituentsFetcher(
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: MajorIndicesConstituentsQueryParams, extra_params: Optional[Dict] = None
|
||||
params: Dict[str, Any]
|
||||
) -> FMPMajorIndicesConstituentsQueryParams:
|
||||
return FMPMajorIndicesConstituentsQueryParams(
|
||||
index=query.index,
|
||||
**extra_params or {},
|
||||
)
|
||||
return FMPMajorIndicesConstituentsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPMajorIndicesConstituentsQueryParams, api_key: str
|
||||
query: FMPMajorIndicesConstituentsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPMajorIndicesConstituentsData]:
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
url = f"{base_url}/{query.index}_constituent/?apikey={api_key}"
|
||||
return get_data_many(url, FMPMajorIndicesConstituentsData)
|
||||
|
||||
return get_data_many(url, FMPMajorIndicesConstituentsData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPMajorIndicesConstituentsData],
|
||||
) -> List[MajorIndicesConstituentsData]:
|
||||
return data_transformer(data, MajorIndicesConstituentsData)
|
||||
) -> List[FMPMajorIndicesConstituentsData]:
|
||||
return data
|
||||
|
||||
@@ -1,64 +1,58 @@
|
||||
"""FMP Major Indices end of day fetcher."""
|
||||
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.major_indices_eod import (
|
||||
MajorIndicesEODData,
|
||||
MajorIndicesEODQueryParams,
|
||||
)
|
||||
from openbb_provider.utils.descriptions import DATA_DESCRIPTIONS
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import Field, NonNegativeInt, validator
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
|
||||
|
||||
class FMPMajorIndicesEODQueryParams(QueryParams):
|
||||
"""FMP Major Indices end of day query.
|
||||
class FMPMajorIndicesEODQueryParams(MajorIndicesEODQueryParams):
|
||||
"""FMP Major Indices end of day Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-stock-index-prices
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
start_date : date
|
||||
The start date of the stock data from which to retrieve the data.
|
||||
end_date : date
|
||||
The end date of the stock data up to which to retrieve the data.
|
||||
timeseries : Optional[int]
|
||||
The number of days to look back.
|
||||
serietype : Optional[Literal["line"]]
|
||||
The type of the series. Only "line" is supported.
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/historical-index-price-api/
|
||||
"""
|
||||
|
||||
symbol: str = Field(min_length=1)
|
||||
serietype: Optional[Literal["line"]]
|
||||
start_date: date
|
||||
end_date: date
|
||||
timeseries: Optional[NonNegativeInt] # Number of days to looks back
|
||||
timeseries: Optional[NonNegativeInt] = Field(
|
||||
default=None, description="Number of days to look back."
|
||||
)
|
||||
|
||||
|
||||
class FMPMajorIndicesEODData(Data):
|
||||
date: datetime
|
||||
open: float
|
||||
high: float
|
||||
low: float
|
||||
close: float
|
||||
adjClose: float = Field(alias="adj_close")
|
||||
volume: float
|
||||
unadjustedVolume: float
|
||||
change: float
|
||||
changePercent: float
|
||||
vwap: float
|
||||
label: str
|
||||
changeOverTime: float
|
||||
class FMPMajorIndicesEODData(MajorIndicesEODData):
|
||||
"""FMP Major Indices end of day Data."""
|
||||
|
||||
date: datetime = Field(description=DATA_DESCRIPTIONS.get("date", ""))
|
||||
adjClose: float = Field(
|
||||
description="Adjusted Close Price of the symbol.", alias="adj_close"
|
||||
)
|
||||
unadjustedVolume: float = Field(
|
||||
description="Unadjusted volume of the symbol.", alias="unadjusted_volume"
|
||||
)
|
||||
change: float = Field(
|
||||
description="Change in the price of the symbol from the previous day.",
|
||||
alias="change",
|
||||
)
|
||||
changePercent: float = Field(
|
||||
description=r"Change \% in the price of the symbol.", alias="change_percent"
|
||||
)
|
||||
vwap: float = Field(description="Volume Weighted Average Price of the symbol.")
|
||||
label: str = Field(description="Human readable format of the date.")
|
||||
changeOverTime: float = Field(
|
||||
description=r"Change \% in the price of the symbol over a period of time.",
|
||||
alias="change_over_time",
|
||||
)
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
@@ -71,30 +65,26 @@ class FMPMajorIndicesEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: MajorIndicesEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPMajorIndicesEODQueryParams:
|
||||
raw_end = query.end_date if query.end_date else datetime.now()
|
||||
return FMPMajorIndicesEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=raw_end,
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPMajorIndicesEODQueryParams:
|
||||
return FMPMajorIndicesEODQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPMajorIndicesEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPMajorIndicesEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPMajorIndicesEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
query_str = get_querystring(query.dict(), ["symbol"])
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
query_str = get_querystring(query.dict(by_alias=True), ["symbol"])
|
||||
query_str = query_str.replace("start_date", "from").replace("end_date", "to")
|
||||
url = f"{base_url}historical-price-full/{query.symbol}?{query_str}&apikey={api_key}"
|
||||
return get_data_many(url, FMPMajorIndicesEODData, "historical")
|
||||
url = f"{base_url}/historical-price-full/index/%5E{query.symbol}?{query_str}&apikey={api_key}"
|
||||
|
||||
return get_data_many(url, FMPMajorIndicesEODData, "historical", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPMajorIndicesEODData]) -> List[MajorIndicesEODData]:
|
||||
return data_transformer(data, MajorIndicesEODData)
|
||||
def transform_data(
|
||||
data: List[FMPMajorIndicesEODData],
|
||||
) -> List[FMPMajorIndicesEODData]:
|
||||
return data
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
"""FMP Major Indices Price fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.base import BaseSymbol
|
||||
from openbb_provider.models.major_indices_price import (
|
||||
MajorIndicesPriceData,
|
||||
MajorIndicesPriceQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
|
||||
class FMPMajorIndicesPriceQueryParams(QueryParams, BaseSymbol):
|
||||
"""FMP MajorIndices Price query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-stock-index-prices
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the index.
|
||||
interval : Literal['1min', '5min', '15min', '30min', '1hour', '4hour']
|
||||
The interval of the index data to fetch. Default is '1hour`.
|
||||
"""
|
||||
|
||||
interval: Literal["1min", "5min", "15min", "30min", "1hour", "4hour"] = Field(
|
||||
default="1hour"
|
||||
)
|
||||
|
||||
|
||||
class FMPMajorIndicesPriceData(BaseStockPriceData):
|
||||
"""FMP MajorIndices Price data."""
|
||||
|
||||
|
||||
class FMPMajorIndicesPriceFetcher(
|
||||
Fetcher[
|
||||
MajorIndicesPriceQueryParams,
|
||||
MajorIndicesPriceData,
|
||||
FMPMajorIndicesPriceQueryParams,
|
||||
FMPMajorIndicesPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: MajorIndicesPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPMajorIndicesPriceQueryParams:
|
||||
return FMPMajorIndicesPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
**extra_params or {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPMajorIndicesPriceQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[FMPMajorIndicesPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
|
||||
url = create_url(
|
||||
3, f"historical-chart/{query.interval}/%5E{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPMajorIndicesPriceData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPMajorIndicesPriceData],
|
||||
) -> List[MajorIndicesPriceData]:
|
||||
return data_transformer(data, MajorIndicesPriceData)
|
||||
@@ -2,41 +2,42 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.price_target import PriceTargetData, PriceTargetQueryParams
|
||||
from pydantic import Field
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPPriceTargetQueryParams(PriceTargetQueryParams):
|
||||
"""FMP Price Target query.
|
||||
"""FMP Price Target Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Price-Target
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPPriceTargetData(Data):
|
||||
symbol: str
|
||||
publishedDate: datetime
|
||||
newsURL: str = Field(alias="news_url")
|
||||
newsTitle: Optional[str]
|
||||
analystName: Optional[str]
|
||||
priceTarget: float
|
||||
adjPriceTarget: float
|
||||
priceWhenPosted: float
|
||||
newsPublisher: str
|
||||
newsBaseURL: str = Field(alias="news_base_url")
|
||||
analystCompany: str
|
||||
class FMPPriceTargetData(PriceTargetData):
|
||||
"""FMP Price Target Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"published_date": "publishedDate",
|
||||
"news_url": "newsURL",
|
||||
"news_title": "newsTitle",
|
||||
"analyst_name": "analystName",
|
||||
"price_target": "priceTarget",
|
||||
"adj_price_target": "adjPriceTarget",
|
||||
"price_when_posted": "priceWhenPosted",
|
||||
"news_publisher": "newsPublisher",
|
||||
"news_base_url": "newsBaseURL",
|
||||
"analyst_company": "analystCompany",
|
||||
}
|
||||
|
||||
@validator("publishedDate", pre=True, check_fields=False)
|
||||
def published_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d") if v else None
|
||||
|
||||
|
||||
class FMPPriceTargetFetcher(
|
||||
@@ -48,21 +49,21 @@ class FMPPriceTargetFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: PriceTargetQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPPriceTargetQueryParams:
|
||||
return FMPPriceTargetQueryParams.parse_obj(query)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPPriceTargetQueryParams:
|
||||
return FMPPriceTargetQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPPriceTargetQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPPriceTargetQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPPriceTargetData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "price-target", api_key, query)
|
||||
return get_data_many(url, FMPPriceTargetData)
|
||||
|
||||
return get_data_many(url, FMPPriceTargetData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPPriceTargetData]) -> List[PriceTargetData]:
|
||||
return data_transformer(data, PriceTargetData)
|
||||
def transform_data(data: List[FMPPriceTargetData]) -> List[FMPPriceTargetData]:
|
||||
return data
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
"""FMP Price Target Consensus fetcher."""
|
||||
|
||||
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.price_target_consensus import (
|
||||
PriceTargetConsensusData,
|
||||
PriceTargetConsensusQueryParams,
|
||||
@@ -15,34 +12,23 @@ from openbb_provider.models.price_target_consensus import (
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class Interval(str, Enum):
|
||||
oneminute = "1min"
|
||||
fiveminute = "5min"
|
||||
fifteenminute = "15min"
|
||||
thirtyminute = "30min"
|
||||
onehour = "1hour"
|
||||
fourhour = "4hour"
|
||||
day = "day"
|
||||
|
||||
|
||||
class FMPPriceTargetConsensusQueryParams(PriceTargetConsensusQueryParams):
|
||||
"""FMP Price Target Consensus query.
|
||||
"""FMP Price Target Consensus Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/price-target-consensus-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPPriceTargetConsensusData(Data):
|
||||
symbol: str
|
||||
targetHigh: float
|
||||
targetLow: float
|
||||
targetConsensus: float
|
||||
targetMedian: float
|
||||
class FMPPriceTargetConsensusData(PriceTargetConsensusData):
|
||||
"""FMP Price Target Consensus Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"target_high": "targetHigh",
|
||||
"target_low": "targetLow",
|
||||
"target_consensus": "targetConsensus",
|
||||
"target_median": "targetMedian",
|
||||
}
|
||||
|
||||
|
||||
class FMPPriceTargetConsensusFetcher(
|
||||
@@ -54,23 +40,22 @@ class FMPPriceTargetConsensusFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: PriceTargetConsensusQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPPriceTargetConsensusQueryParams:
|
||||
return FMPPriceTargetConsensusQueryParams(symbol=query.symbol)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPPriceTargetConsensusQueryParams:
|
||||
return FMPPriceTargetConsensusQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPPriceTargetConsensusQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPPriceTargetConsensusQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPPriceTargetConsensusData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "price-target-consensus", api_key, query)
|
||||
return get_data_many(url, FMPPriceTargetConsensusData)
|
||||
return get_data_many(url, FMPPriceTargetConsensusData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPPriceTargetConsensusData],
|
||||
) -> List[PriceTargetConsensusData]:
|
||||
return data_transformer(data, PriceTargetConsensusData)
|
||||
) -> List[FMPPriceTargetConsensusData]:
|
||||
return data
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.revenue_business_line import (
|
||||
RevenueBusinessLineData,
|
||||
RevenueBusinessLineQueryParams,
|
||||
@@ -14,28 +13,19 @@ from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data
|
||||
|
||||
# This part is only provided by FMP and not by the other providers for now.
|
||||
|
||||
|
||||
class FMPRevenueBusinessLineQueryParams(RevenueBusinessLineQueryParams):
|
||||
"""FMP Revenue Business Line QueryParams.
|
||||
"""FMP Revenue Business Line Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/sales-revenue-by-segments-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : Optional[str]
|
||||
The symbol of the company if no CIK is provided.
|
||||
period : Literal["annual", "quarterly"]
|
||||
The period of the income statement. Default is "annual".
|
||||
structure : Literal["hierarchical", "flat"]
|
||||
The structure of the revenue business line. Default is "flat".
|
||||
"""
|
||||
|
||||
|
||||
class FMPRevenueBusinessLineData(RevenueBusinessLineData):
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
"""FMP Revenue Business Line Data."""
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
@@ -48,30 +38,27 @@ class FMPRevenueBusinessLineFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: RevenueBusinessLineQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPRevenueBusinessLineQueryParams:
|
||||
return FMPRevenueBusinessLineQueryParams.parse_obj(query)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPRevenueBusinessLineQueryParams:
|
||||
return FMPRevenueBusinessLineQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPRevenueBusinessLineQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPRevenueBusinessLineQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPRevenueBusinessLineData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
# Type has to be ignored below because we are using something different than the literal type
|
||||
query.period = "quarter" if query.period == "quarterly" else "annual" # type: ignore
|
||||
url = create_url(4, "revenue-product-segmentation", api_key, query)
|
||||
data = get_data(url)
|
||||
data = get_data(url, **kwargs)
|
||||
|
||||
if isinstance(data, dict):
|
||||
raise ValueError("Expected list of dicts, got dict")
|
||||
|
||||
data = [
|
||||
{
|
||||
"date": list(d.keys())[0],
|
||||
"data_and_service": list(d.values())[0],
|
||||
}
|
||||
{"date": list(d.keys())[0], "business_line": list(d.values())[0]}
|
||||
for d in data
|
||||
]
|
||||
|
||||
@@ -80,5 +67,5 @@ class FMPRevenueBusinessLineFetcher(
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPRevenueBusinessLineData],
|
||||
) -> List[RevenueBusinessLineData]:
|
||||
return data_transformer(data, RevenueBusinessLineData)
|
||||
) -> List[FMPRevenueBusinessLineData]:
|
||||
return data
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.revenue_geographic import (
|
||||
RevenueGeographicData,
|
||||
RevenueGeographicQueryParams,
|
||||
@@ -14,28 +13,19 @@ from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data
|
||||
|
||||
# This part is only provided by FMP and not by the other providers for now.
|
||||
|
||||
|
||||
class FMPRevenueGeographicQueryParams(RevenueGeographicQueryParams):
|
||||
"""FMP Revenue Geographic QueryParams.
|
||||
|
||||
Source: https://financialmodelingprep.com/developer/docs/#Revenue-Geographic-Segmentation
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : Optional[str]
|
||||
The symbol of the company if no CIK is provided.
|
||||
period : Literal["annual", "quarterly"]
|
||||
The period of the income statement. Default is "annual".
|
||||
structure : Literal["hierarchical", "flat"]
|
||||
The structure of the revenue geographic. Default is "flat".
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/revenue-geographic-by-segments-api/
|
||||
"""
|
||||
|
||||
|
||||
class FMPRevenueGeographicData(RevenueGeographicData):
|
||||
"""FMP Revenue Geographic Data."""
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
@@ -48,46 +38,40 @@ class FMPRevenueGeographicFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: RevenueGeographicQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPRevenueGeographicQueryParams:
|
||||
return FMPRevenueGeographicQueryParams(
|
||||
symbol=query.symbol, period=query.period, structure=query.structure
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPRevenueGeographicQueryParams:
|
||||
return FMPRevenueGeographicQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPRevenueGeographicQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPRevenueGeographicQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPRevenueGeographicData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
query.period = "quarter" if query.period == "quarterly" else "annual" # type: ignore
|
||||
url = create_url(4, "revenue-geographic-segmentation", api_key, query)
|
||||
data = get_data(url)
|
||||
data = get_data(url, **kwargs)
|
||||
|
||||
if isinstance(data, dict):
|
||||
raise ValueError("Expected list of dicts, got dict")
|
||||
|
||||
data = [
|
||||
{**v, "date": k} for d in data for k, v in d.items() if isinstance(v, dict)
|
||||
]
|
||||
|
||||
data = [
|
||||
{
|
||||
"date": d.get("date"),
|
||||
"americas": d.get("Americas Segment")
|
||||
or d.get("North America Segment")
|
||||
or d.get("Americas")
|
||||
or d.get("North America"),
|
||||
"europe": d.get("Europe Segment") or d.get("Europe"),
|
||||
"greater_china": d.get("Greater China Segment")
|
||||
or d.get("Greater China"),
|
||||
"japan": d.get("Japan Segment") or d.get("Japan") or d.get("J P"),
|
||||
"rest_of_asia_pacific": d.get("Rest of Asia Pacific Segment")
|
||||
or d.get("Rest of Asia Pacific")
|
||||
or d.get("Asia-Pacific"),
|
||||
**v,
|
||||
"date": k,
|
||||
"americas": v.get("Americas Segment", v.get("North America")),
|
||||
"europe": v.get("Europe Segment", v.get("Europe")),
|
||||
"greater_china": v.get("Greater China Segment", v.get("Greater China")),
|
||||
"japan": v.get("Japan Segment", v.get("Japan", v.get("J P"))),
|
||||
"rest_of_asia_pacific": v.get(
|
||||
"Rest of Asia Pacific Segment", v.get("Asia-Pacific")
|
||||
),
|
||||
}
|
||||
for d in data
|
||||
for k, v in d.items()
|
||||
if isinstance(v, dict)
|
||||
]
|
||||
|
||||
return [FMPRevenueGeographicData(**d) for d in data]
|
||||
@@ -95,6 +79,5 @@ class FMPRevenueGeographicFetcher(
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPRevenueGeographicData],
|
||||
) -> List[RevenueGeographicData]:
|
||||
# Parse data to RevenueGeographicData
|
||||
return data_transformer(data, RevenueGeographicData)
|
||||
) -> List[FMPRevenueGeographicData]:
|
||||
return data
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""FMP Risk Premium fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.risk_premium import RiskPremiumData, RiskPremiumQueryParams
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
@@ -14,13 +13,18 @@ class FMPRiskPremiumQueryParams(RiskPremiumQueryParams):
|
||||
"""FMP Risk Premium query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/market-risk-premium-api/
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class FMPRiskPremiumData(RiskPremiumData):
|
||||
"""FMP Risk Premium data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"total_equity_risk_premium": "totalEquityRiskPremium",
|
||||
"country_risk_premium": "countryRiskPremium",
|
||||
}
|
||||
|
||||
|
||||
class FMPRiskPremiumFetcher(
|
||||
Fetcher[
|
||||
@@ -31,18 +35,21 @@ class FMPRiskPremiumFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: RiskPremiumQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPRiskPremiumQueryParams:
|
||||
return FMPRiskPremiumQueryParams()
|
||||
def transform_query(params: Dict[str, Any]) -> FMPRiskPremiumQueryParams:
|
||||
return FMPRiskPremiumQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPRiskPremiumQueryParams, api_key: str
|
||||
query: FMPRiskPremiumQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPRiskPremiumData]:
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "market_risk_premium", api_key)
|
||||
return get_data_many(url, FMPRiskPremiumData)
|
||||
|
||||
return get_data_many(url, FMPRiskPremiumData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPRiskPremiumData]) -> List[RiskPremiumData]:
|
||||
return data_transformer(data, RiskPremiumData)
|
||||
def transform_data(data: List[FMPRiskPremiumData]) -> List[FMPRiskPremiumData]:
|
||||
return data
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
"""SEC Filings fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.sec_filings import SECFilingsData, SECFilingsQueryParams
|
||||
from pydantic import validator
|
||||
|
||||
@@ -17,35 +12,25 @@ from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPSECFilingsQueryParams(SECFilingsQueryParams):
|
||||
"""FMP SEC Filings QueryParams.
|
||||
"""FMP SEC Filings Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/sec-filings-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
type : str
|
||||
The type of the SEC filing form. (full list: https://www.sec.gov/forms)
|
||||
page : int
|
||||
The page of the results.
|
||||
limit : int
|
||||
The limit of the results.
|
||||
"""
|
||||
|
||||
|
||||
class FMPSECFilingsData(Data):
|
||||
symbol: str
|
||||
fillingDate: dateType
|
||||
acceptedDate: dateType
|
||||
cik: str
|
||||
type: str
|
||||
link: str
|
||||
finalLink: str
|
||||
class FMPSECFilingsData(SECFilingsData):
|
||||
"""FMP SEC Filings Data."""
|
||||
|
||||
@validator("fillingDate", "acceptedDate", pre=True)
|
||||
class Config:
|
||||
fields = {
|
||||
"filling_date": "fillingDate",
|
||||
"accepted_date": "acceptedDate",
|
||||
"final_link": "finalLink",
|
||||
}
|
||||
|
||||
@validator("fillingDate", "acceptedDate", pre=True, check_fields=False)
|
||||
def convert_date(cls, v): # pylint: disable=no-self-argument
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S").date()
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
class FMPSECFilingsFetcher(
|
||||
@@ -57,25 +42,23 @@ class FMPSECFilingsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: SECFilingsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPSECFilingsQueryParams:
|
||||
return FMPSECFilingsQueryParams(
|
||||
symbol=query.symbol, page=query.page, limit=query.limit, type=query.type
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPSECFilingsQueryParams:
|
||||
return FMPSECFilingsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPSECFilingsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPSECFilingsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPSECFilingsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"sec_filings/{query.symbol}", api_key, query, exclude=["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPSECFilingsData)
|
||||
|
||||
return get_data_many(url, FMPSECFilingsData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPSECFilingsData]) -> List[SECFilingsData]:
|
||||
return data_transformer(data, SECFilingsData)
|
||||
def transform_data(data: List[FMPSECFilingsData]) -> List[FMPSECFilingsData]:
|
||||
return data
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
"""FMP Share Statistics Fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.base import BaseSymbol
|
||||
from openbb_provider.models.share_statistics import (
|
||||
ShareStatisticsData,
|
||||
ShareStatisticsQueryParams,
|
||||
@@ -20,28 +14,25 @@ from pydantic import validator
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPShareStatisticsQueryParams(QueryParams, BaseSymbol):
|
||||
class FMPShareStatisticsQueryParams(ShareStatisticsQueryParams):
|
||||
"""FMP Income Statement QueryParams.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/shares-float-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPShareStatisticsData(Data):
|
||||
symbol: str
|
||||
date: dateType
|
||||
freeFloat: float
|
||||
floatShares: float
|
||||
outstandingShares: float
|
||||
source: str
|
||||
class FMPShareStatisticsData(ShareStatisticsData):
|
||||
"""FMP Share Statistics Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"free_float": "freeFloat",
|
||||
"float_shares": "floatShares",
|
||||
"outstanding_shares": "outstandingShares",
|
||||
}
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
@@ -54,23 +45,23 @@ class FMPShareStatisticsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ShareStatisticsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPShareStatisticsQueryParams:
|
||||
return FMPShareStatisticsQueryParams(symbol=query.symbol)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPShareStatisticsQueryParams:
|
||||
return FMPShareStatisticsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPShareStatisticsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPShareStatisticsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPShareStatisticsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "shares_float", api_key, query)
|
||||
return get_data_many(url, FMPShareStatisticsData)
|
||||
|
||||
return get_data_many(url, FMPShareStatisticsData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPShareStatisticsData],
|
||||
) -> List[ShareStatisticsData]:
|
||||
return data_transformer(data, ShareStatisticsData)
|
||||
) -> List[FMPShareStatisticsData]:
|
||||
return data
|
||||
|
||||
@@ -2,53 +2,52 @@
|
||||
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.stock_eod import StockEODData, StockEODQueryParams
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import Field, NonNegativeInt, validator
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
|
||||
|
||||
class FMPStockEODQueryParams(StockEODQueryParams):
|
||||
"""FMP Stock end of day query.
|
||||
"""FMP Stock end of day Query.
|
||||
|
||||
Source: https://financialmodelingprep.com/developer/docs/#Stock-Historical-Price
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
start_date : date
|
||||
The start date of the stock data from which to retrieve the data.
|
||||
end_date : date
|
||||
The end date of the stock data up to which to retrieve the data.
|
||||
timeseries : Optional[int]
|
||||
The number of days to look back.
|
||||
series_type : Optional[Literal["line"]]
|
||||
The type of the series. Only "line" is supported.
|
||||
"""
|
||||
|
||||
# symbol: str = Field(min_length=1)
|
||||
series_type: Optional[Literal["line"]]
|
||||
# start_date: date
|
||||
# end_date: date
|
||||
timeseries: Optional[NonNegativeInt] # Number of days to looks back
|
||||
timeseries: Optional[NonNegativeInt] = Field(
|
||||
default=None, description="Number of days to look back."
|
||||
)
|
||||
|
||||
|
||||
class FMPStockEODData(StockEODData):
|
||||
adjClose: float = Field(alias="adj_close")
|
||||
unadjustedVolume: float
|
||||
change: float
|
||||
changePercent: float
|
||||
vwap: float
|
||||
label: str
|
||||
changeOverTime: float
|
||||
"""FMP Stock end of day Data."""
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
adjClose: float = Field(
|
||||
description="Adjusted Close Price of the symbol.", alias="adj_close"
|
||||
)
|
||||
unadjustedVolume: float = Field(
|
||||
description="Unadjusted volume of the symbol.", alias="unadjusted_volume"
|
||||
)
|
||||
change: float = Field(
|
||||
description="Change in the price of the symbol from the previous day.",
|
||||
alias="change",
|
||||
)
|
||||
changePercent: float = Field(
|
||||
description=r"Change \% in the price of the symbol.", alias="change_percent"
|
||||
)
|
||||
|
||||
label: str = Field(description="Human readable format of the date.")
|
||||
changeOverTime: float = Field(
|
||||
description=r"Change \% in the price of the symbol over a period of time.",
|
||||
alias="change_over_time",
|
||||
)
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
@@ -61,32 +60,32 @@ class FMPStockEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockEODQueryParams:
|
||||
now = datetime.now()
|
||||
start_date = query.start_date or (now - timedelta(days=5))
|
||||
end_date = query.end_date or now
|
||||
return FMPStockEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
**extra_params or {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPStockEODQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=7)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
|
||||
return FMPStockEODQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPStockEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPStockEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v3"
|
||||
query_str = get_querystring(query.dict(), ["symbol"])
|
||||
query_str = get_querystring(query.dict(by_alias=True), ["symbol"])
|
||||
query_str = query_str.replace("start_date", "from").replace("end_date", "to")
|
||||
url = f"{base_url}/historical-price-full/{query.symbol}?{query_str}&apikey={api_key}"
|
||||
return get_data_many(url, FMPStockEODData, "historical")
|
||||
|
||||
return get_data_many(url, FMPStockEODData, "historical", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockEODData]) -> List[StockEODData]:
|
||||
return data_transformer(data, StockEODData)
|
||||
def transform_data(data: List[FMPStockEODData]) -> List[FMPStockEODData]:
|
||||
return data
|
||||
|
||||
@@ -1,62 +1,52 @@
|
||||
"""FMP Stock Insider Trading fetcher."""
|
||||
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_insider_trading import (
|
||||
StockInsiderTradingData,
|
||||
StockInsiderTradingQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPStockInsiderTradingQueryParams(StockInsiderTradingQueryParams):
|
||||
"""FMP Stock Insider Trading query.
|
||||
"""FMP Stock Insider Trading Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Stock-Insider-Trading
|
||||
|
||||
Parameter
|
||||
---------
|
||||
transactionType : List[TransactionTypes]
|
||||
The type of the transaction. Possible values are:
|
||||
A-Award, C-Conversion, D-Return, E-ExpireShort, F-InKind, G-Gift, H-ExpireLong
|
||||
I-Discretionary, J-Other, L-Small, M-Exempt, O-OutOfTheMoneym P-Purchase
|
||||
S-Sale, U-Tender, W-Will, X-InTheMoney, Z-Trust
|
||||
symbol : str]
|
||||
The symbol of the company.
|
||||
reportingCik : str]
|
||||
The CIK of the reporting owner.
|
||||
companyCik: str]
|
||||
The CIK of the company owner.
|
||||
page: int
|
||||
The page number to get
|
||||
"""
|
||||
|
||||
|
||||
class FMPStockInsiderTradingData(Data):
|
||||
"""FMP Stock Insider Trading data."""
|
||||
class FMPStockInsiderTradingData(StockInsiderTradingData):
|
||||
"""FMP Stock Insider Trading Data."""
|
||||
|
||||
symbol: str
|
||||
filingDate: datetime = Field(alias="filing_date")
|
||||
transactionDate: date = Field(alias="transaction_date")
|
||||
reportingCik: int = Field(alias="reporting_cik")
|
||||
transactionType: str = Field(alias="transaction_type")
|
||||
securitiesOwned: int = Field(alias="securities_owned")
|
||||
companyCik: int = Field(alias="company_cik")
|
||||
reportingName: str = Field(alias="reporting_name")
|
||||
typeOfOwner: str = Field(alias="type_of_owner")
|
||||
acquistionOrDisposition: str = Field(alias="acquistion_or_disposition")
|
||||
formType: str = Field(alias="form_type")
|
||||
securitiesTransacted: float = Field(alias="securities_transacted")
|
||||
price: float
|
||||
securityName: str = Field(alias="security_name")
|
||||
link: str
|
||||
class Config:
|
||||
fields = {
|
||||
"filing_date": "filingDate",
|
||||
"transaction_date": "transactionDate",
|
||||
"reporting_cik": "reportingCik",
|
||||
"transaction_type": "transactionType",
|
||||
"securities_owned": "securitiesOwned",
|
||||
"company_cik": "companyCik",
|
||||
"reporting_name": "reportingName",
|
||||
"type_of_owner": "typeOfOwner",
|
||||
"acquistion_or_disposition": "acquistionOrDisposition",
|
||||
"form_type": "formType",
|
||||
"securities_transacted": "securitiesTransacted",
|
||||
"security_name": "securityName",
|
||||
}
|
||||
|
||||
@validator("filingDate", pre=True, check_fields=False)
|
||||
def filing_date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
@validator("transactionDate", pre=True, check_fields=False)
|
||||
def transaction_date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d").date()
|
||||
|
||||
|
||||
class FMPStockInsiderTradingFetcher(
|
||||
@@ -68,31 +58,25 @@ class FMPStockInsiderTradingFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockInsiderTradingQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockInsiderTradingQueryParams:
|
||||
return FMPStockInsiderTradingQueryParams(
|
||||
transactionType=query.transactionType,
|
||||
symbol=query.symbol,
|
||||
reportingCik=query.reportingCik,
|
||||
companyCik=query.companyCik,
|
||||
page=query.page,
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPStockInsiderTradingQueryParams:
|
||||
return FMPStockInsiderTradingQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockInsiderTradingQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPStockInsiderTradingQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPStockInsiderTradingData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
# This changes the actual type of a pydantic class, but its a quick and clean way to format properly
|
||||
query.transactionType = ",".join(query.transactionType) # type: ignore
|
||||
url = create_url(4, "insider-trading", api_key, query)
|
||||
return get_data_many(url, FMPStockInsiderTradingData)
|
||||
|
||||
return get_data_many(url, FMPStockInsiderTradingData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPStockInsiderTradingData],
|
||||
) -> List[StockInsiderTradingData]:
|
||||
return data_transformer(data, StockInsiderTradingData)
|
||||
) -> List[FMPStockInsiderTradingData]:
|
||||
return data
|
||||
|
||||
@@ -1,127 +1,87 @@
|
||||
"""FMP Stock Multiples Fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_multiples import (
|
||||
StockMultiplesData,
|
||||
StockMultiplesQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_one
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPStockMultiplesQueryParams(StockMultiplesQueryParams):
|
||||
"""FMP Stock Multiples QueryParams.
|
||||
"""FMP Stock Multiples Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Company-Key-Metrics
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
limit : Optional[int]
|
||||
The limit of the key metrics ttm to be returned.
|
||||
"""
|
||||
|
||||
|
||||
class FMPStockMultiplesData(StockMultiplesData):
|
||||
"""FMP Stock Multiples Data."""
|
||||
|
||||
revenuePerShareTTM: Optional[float] = Field(alias="revenue_per_share_ttm")
|
||||
netIncomePerShareTTM: Optional[float] = Field(alias="net_income_per_share_ttm")
|
||||
operatingCashFlowPerShareTTM: Optional[float] = Field(
|
||||
alias="operating_cash_flow_per_share_ttm"
|
||||
)
|
||||
freeCashFlowPerShareTTM: Optional[float] = Field(
|
||||
alias="free_cash_flow_per_share_ttm"
|
||||
)
|
||||
cashPerShareTTM: Optional[float] = Field(alias="cash_per_share_ttm")
|
||||
bookValuePerShareTTM: Optional[float] = Field(alias="book_value_per_share_ttm")
|
||||
tangibleBookValuePerShareTTM: Optional[float] = Field(
|
||||
alias="tangible_book_value_per_share_ttm"
|
||||
)
|
||||
shareholdersEquityPerShareTTM: Optional[float] = Field(
|
||||
alias="shareholders_equity_per_share_ttm"
|
||||
)
|
||||
interestDebtPerShareTTM: Optional[float] = Field(
|
||||
alias="interest_debt_per_share_ttm"
|
||||
)
|
||||
marketCapTTM: Optional[float] = Field(alias="market_cap_ttm")
|
||||
enterpriseValueTTM: Optional[float] = Field(alias="enterprise_value_ttm")
|
||||
peRatioTTM: Optional[float] = Field(alias="pe_ratio_ttm")
|
||||
priceToSalesRatioTTM: Optional[float] = Field(alias="price_to_sales_ratio_ttm")
|
||||
pocfratioTTM: Optional[float] = Field(alias="pocf_ratio_ttm")
|
||||
pfcfRatioTTM: Optional[float] = Field(alias="pfcf_ratio_ttm")
|
||||
pbRatioTTM: Optional[float] = Field(alias="pb_ratio_ttm")
|
||||
ptbRatioTTM: Optional[float] = Field(alias="ptb_ratio_ttm")
|
||||
evToSalesTTM: Optional[float] = Field(alias="ev_to_sales_ttm")
|
||||
enterpriseValueOverEBITDATTM: Optional[float] = Field(
|
||||
alias="enterprise_value_over_ebitda_ttm"
|
||||
)
|
||||
evToOperatingCashFlowTTM: Optional[float] = Field(
|
||||
alias="ev_to_operating_cash_flow_ttm"
|
||||
)
|
||||
evToFreeCashFlowTTM: Optional[float] = Field(alias="ev_to_free_cash_flow_ttm")
|
||||
earningsYieldTTM: Optional[float] = Field(alias="earnings_yield_ttm")
|
||||
freeCashFlowYieldTTM: Optional[Optional[float]] = Field(
|
||||
alias="free_cash_flow_yield_ttm"
|
||||
)
|
||||
debtToEquityTTM: Optional[float] = Field(alias="debt_to_equity_ttm")
|
||||
debtToAssetsTTM: Optional[float] = Field(alias="debt_to_assets_ttm")
|
||||
netDebtToEBITDATTM: Optional[float] = Field(alias="net_debt_to_ebitda_ttm")
|
||||
currentRatioTTM: Optional[float] = Field(alias="current_ratio_ttm")
|
||||
interestCoverageTTM: Optional[float] = Field(alias="interest_coverage_ttm")
|
||||
incomeQualityTTM: Optional[float] = Field(alias="income_quality_ttm")
|
||||
dividendYieldTTM: Optional[Optional[float]] = Field(alias="dividend_yield_ttm")
|
||||
payoutRatioTTM: Optional[Optional[float]] = Field(alias="payout_ratio_ttm")
|
||||
salesGeneralAndAdministrativeToRevenueTTM: Optional[float] = Field(
|
||||
alias="sales_general_and_administrative_to_revenue_ttm"
|
||||
)
|
||||
researchAndDevelopementToRevenueTTM: Optional[float] = Field(
|
||||
alias="research_and_development_to_revenue_ttm"
|
||||
)
|
||||
intangiblesToTotalAssetsTTM: Optional[float] = Field(
|
||||
alias="intangibles_to_total_assets_ttm"
|
||||
)
|
||||
capexToOperatingCashFlowTTM: Optional[float] = Field(
|
||||
alias="capex_to_operating_cash_flow_ttm"
|
||||
)
|
||||
capexToRevenueTTM: Optional[float] = Field(alias="capex_to_revenue_ttm")
|
||||
capexToDepreciationTTM: Optional[float] = Field(alias="capex_to_depreciation_ttm")
|
||||
stockBasedCompensationToRevenueTTM: Optional[float] = Field(
|
||||
alias="stock_based_compensation_to_revenue_ttm"
|
||||
)
|
||||
grahamNumberTTM: Optional[float] = Field(alias="graham_number_ttm")
|
||||
roicTTM: Optional[float] = Field(alias="roic_ttm")
|
||||
returnOnTangibleAssetsTTM: Optional[float] = Field(
|
||||
alias="return_on_tangible_assets_ttm"
|
||||
)
|
||||
grahamNetNetTTM: Optional[float] = Field(alias="graham_net_net_ttm")
|
||||
workingCapitalTTM: Optional[float] = Field(alias="working_capital_ttm")
|
||||
tangibleAssetValueTTM: Optional[float] = Field(alias="tangible_asset_value_ttm")
|
||||
netCurrentAssetValueTTM: Optional[float] = Field(
|
||||
alias="net_current_asset_value_ttm"
|
||||
)
|
||||
investedCapitalTTM: Optional[float] = Field(alias="invested_capital_ttm")
|
||||
averageReceivablesTTM: Optional[float] = Field(alias="average_receivables_ttm")
|
||||
averagePayablesTTM: Optional[float] = Field(alias="average_payables_ttm")
|
||||
averageInventoryTTM: Optional[float] = Field(alias="average_inventory_ttm")
|
||||
daysSalesOutstandingTTM: Optional[float] = Field(alias="days_sales_outstanding_ttm")
|
||||
daysPayablesOutstandingTTM: Optional[float] = Field(
|
||||
alias="days_payables_outstanding_ttm"
|
||||
)
|
||||
daysOfInventoryOnHandTTM: Optional[float] = Field(
|
||||
alias="days_of_inventory_on_hand_ttm"
|
||||
)
|
||||
receivablesTurnoverTTM: Optional[float] = Field(alias="receivables_turnover_ttm")
|
||||
payablesTurnoverTTM: Optional[float] = Field(alias="payables_turnover_ttm")
|
||||
inventoryTurnoverTTM: Optional[float] = Field(alias="inventory_turnover_ttm")
|
||||
roeTTM: Optional[float] = Field(alias="roe_ttm")
|
||||
capexPerShareTTM: Optional[float] = Field(alias="capex_per_share_ttm")
|
||||
class Config:
|
||||
fields = {
|
||||
"revenue_per_share_ttm": "revenuePerShareTTM",
|
||||
"net_income_per_share_ttm": "netIncomePerShareTTM",
|
||||
"operating_cash_flow_per_share_ttm": "operatingCashFlowPerShareTTM",
|
||||
"free_cash_flow_per_share_ttm": "freeCashFlowPerShareTTM",
|
||||
"cash_per_share_ttm": "cashPerShareTTM",
|
||||
"book_value_per_share_ttm": "bookValuePerShareTTM",
|
||||
"tangible_book_value_per_share_ttm": "tangibleBookValuePerShareTTM",
|
||||
"shareholders_equity_per_share_ttm": "shareholdersEquityPerShareTTM",
|
||||
"interest_debt_per_share_ttm": "interestDebtPerShareTTM",
|
||||
"market_cap_ttm": "marketCapTTM",
|
||||
"enterprise_value_ttm": "enterpriseValueTTM",
|
||||
"pe_ratio_ttm": "peRatioTTM",
|
||||
"price_to_sales_ratio_ttm": "priceToSalesRatioTTM",
|
||||
"pocf_ratio_ttm": "pocfratioTTM",
|
||||
"pfcf_ratio_ttm": "pfcfRatioTTM",
|
||||
"pb_ratio_ttm": "pbRatioTTM",
|
||||
"ptb_ratio_ttm": "ptbRatioTTM",
|
||||
"ev_to_sales_ttm": "evToSalesTTM",
|
||||
"enterprise_value_over_ebitda_ttm": "enterpriseValueOverEBITDATTM",
|
||||
"ev_to_operating_cash_flow_ttm": "evToOperatingCashFlowTTM",
|
||||
"ev_to_free_cash_flow_ttm": "evToFreeCashFlowTTM",
|
||||
"earnings_yield_ttm": "earningsYieldTTM",
|
||||
"free_cash_flow_yield_ttm": "freeCashFlowYieldTTM",
|
||||
"debt_to_equity_ttm": "debtToEquityTTM",
|
||||
"debt_to_assets_ttm": "debtToAssetsTTM",
|
||||
"net_debt_to_ebitda_ttm": "netDebtToEBITDATTM",
|
||||
"current_ratio_ttm": "currentRatioTTM",
|
||||
"interest_coverage_ttm": "interestCoverageTTM",
|
||||
"income_quality_ttm": "incomeQualityTTM",
|
||||
"dividend_yield_ttm": "dividendYieldTTM",
|
||||
"payout_ratio_ttm": "payoutRatioTTM",
|
||||
"sales_general_and_administrative_to_revenue_ttm": "salesGeneralAndAdministrativeToRevenueTTM",
|
||||
"research_and_development_to_revenue_ttm": "researchAndDevelopementToRevenueTTM",
|
||||
"intangibles_to_total_assets_ttm": "intangiblesToTotalAssetsTTM",
|
||||
"capex_to_operating_cash_flow_ttm": "capexToOperatingCashFlowTTM",
|
||||
"capex_to_revenue_ttm": "capexToRevenueTTM",
|
||||
"capex_to_depreciation_ttm": "capexToDepreciationTTM",
|
||||
"stock_based_compensation_to_revenue_ttm": "stockBasedCompensationToRevenueTTM",
|
||||
"graham_number_ttm": "grahamNumberTTM",
|
||||
"roic_ttm": "roicTTM",
|
||||
"return_on_tangible_assets_ttm": "returnOnTangibleAssetsTTM",
|
||||
"graham_net_net_ttm": "grahamNetNetTTM",
|
||||
"working_capital_ttm": "workingCapitalTTM",
|
||||
"tangible_asset_value_ttm": "tangibleAssetValueTTM",
|
||||
"net_current_asset_value_ttm": "netCurrentAssetValueTTM",
|
||||
"invested_capital_ttm": "investedCapitalTTM",
|
||||
"average_receivables_ttm": "averageReceivablesTTM",
|
||||
"average_payables_ttm": "averagePayablesTTM",
|
||||
"average_inventory_ttm": "averageInventoryTTM",
|
||||
"days_sales_outstanding_ttm": "daysSalesOutstandingTTM",
|
||||
"days_payables_outstanding_ttm": "daysPayablesOutstandingTTM",
|
||||
"days_of_inventory_on_hand_ttm": "daysOfInventoryOnHandTTM",
|
||||
"receivables_turnover_ttm": "receivablesTurnoverTTM",
|
||||
"payables_turnover_ttm": "payablesTurnoverTTM",
|
||||
"inventory_turnover_ttm": "inventoryTurnoverTTM",
|
||||
"roe_ttm": "roeTTM",
|
||||
"capex_per_share_ttm": "capexPerShareTTM",
|
||||
}
|
||||
|
||||
|
||||
class FMPStockMultiplesFetcher(
|
||||
@@ -133,25 +93,25 @@ class FMPStockMultiplesFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockMultiplesQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockMultiplesQueryParams:
|
||||
return FMPStockMultiplesQueryParams(
|
||||
symbol=query.symbol, limit=query.limit, **extra_params or {}
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPStockMultiplesQueryParams:
|
||||
return FMPStockMultiplesQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockMultiplesQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPStockMultiplesQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPStockMultiplesData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
3, f"key-metrics-ttm/{query.symbol}", api_key, query, exclude=["symbol"]
|
||||
)
|
||||
return get_data_one(url, FMPStockMultiplesData)
|
||||
|
||||
return get_data_many(url, FMPStockMultiplesData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockMultiplesData]) -> List[StockMultiplesData]:
|
||||
return data_transformer(data, StockMultiplesData)
|
||||
def transform_data(
|
||||
data: List[FMPStockMultiplesData],
|
||||
) -> List[FMPStockMultiplesData]:
|
||||
return data
|
||||
|
||||
@@ -2,35 +2,24 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_news import StockNewsData, StockNewsQueryParams
|
||||
from pydantic import Field, NonNegativeInt
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
|
||||
|
||||
class FMPStockNewsQueryParams(QueryParams):
|
||||
class FMPStockNewsQueryParams(StockNewsQueryParams):
|
||||
"""FMP Stock News query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/stock-news-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbols : str
|
||||
The symbols of the companies.
|
||||
page : int (default: 0)
|
||||
The page of the data to retrieve.
|
||||
limit : Optional[int]
|
||||
The limit of the data to retrieve.
|
||||
"""
|
||||
|
||||
tickers: str = Field(min_length=1, alias="symbols")
|
||||
page: int = Field(default=0)
|
||||
limit: Optional[NonNegativeInt]
|
||||
class Config:
|
||||
fields = {"symbols": "tickers"}
|
||||
|
||||
|
||||
class FMPStockNewsData(Data):
|
||||
@@ -52,25 +41,20 @@ class FMPStockNewsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockNewsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockNewsQueryParams:
|
||||
return FMPStockNewsQueryParams(
|
||||
symbols=query.symbols,
|
||||
page=query.page,
|
||||
**extra_params if extra_params else {}
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPStockNewsQueryParams:
|
||||
return FMPStockNewsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockNewsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPStockNewsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPStockNewsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(3, "stock_news", api_key, query)
|
||||
return get_data_many(url, FMPStockNewsData)
|
||||
return get_data_many(url, FMPStockNewsData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockNewsData]) -> List[StockNewsData]:
|
||||
return data_transformer(data, StockNewsData)
|
||||
def transform_data(data: List[FMPStockNewsData]) -> List[FMPStockNewsData]:
|
||||
return data
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""FMP Stock Ownership fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_ownership import (
|
||||
StockOwnershipData,
|
||||
StockOwnershipQueryParams,
|
||||
@@ -17,20 +16,48 @@ class FMPStockOwnershipQueryParams(StockOwnershipQueryParams):
|
||||
"""FMP Stock Ownership query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Stock-Ownership-by-Holders
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : string
|
||||
The symbol of the company.
|
||||
page : int
|
||||
The page number to get
|
||||
date : date
|
||||
The CIK of the company owner.
|
||||
"""
|
||||
|
||||
|
||||
class FMPStockOwnershipData(StockOwnershipData):
|
||||
"""FMP Stock Ownership data."""
|
||||
"""FMP Stock Ownership Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"filing_date": "filingDate",
|
||||
"investor_name": "investorName",
|
||||
"security_name": "securityName",
|
||||
"type_of_security": "typeOfSecurity",
|
||||
"security_cusip": "securityCusip",
|
||||
"shares_type": "sharesType",
|
||||
"put_call_share": "putCallShare",
|
||||
"investment_discretion": "investmentDiscretion",
|
||||
"industry_title": "industryTitle",
|
||||
"last_weight": "lastWeight",
|
||||
"change_in_weight": "changeInWeight",
|
||||
"change_in_weight_percentage": "changeInWeightPercentage",
|
||||
"market_value": "marketValue",
|
||||
"last_market_value": "lastMarketValue",
|
||||
"change_in_market_value": "changeInMarketValue",
|
||||
"change_in_market_value_percentage": "changeInMarketValuePercentage",
|
||||
"shares_number": "sharesNumber",
|
||||
"last_shares_number": "lastSharesNumber",
|
||||
"change_in_shares_number": "changeInSharesNumber",
|
||||
"change_in_shares_number_percentage": "changeInSharesNumberPercentage",
|
||||
"quarter_end_price": "quarterEndPrice",
|
||||
"avg_price_paid": "avgPricePaid",
|
||||
"is_new": "isNew",
|
||||
"is_sold_out": "isSoldOut",
|
||||
"last_ownership": "lastOwnership",
|
||||
"change_in_ownership": "changeInOwnership",
|
||||
"change_in_ownership_percentage": "changeInOwnershipPercentage",
|
||||
"holding_period": "holdingPeriod",
|
||||
"first_added": "firstAdded",
|
||||
"performance_percentage": "performancePercentage",
|
||||
"last_performance": "lastPerformance",
|
||||
"change_in_performance": "changeInPerformance",
|
||||
"is_counted_for_performance": "isCountedForPerformance",
|
||||
}
|
||||
|
||||
|
||||
class FMPStockOwnershipFetcher(
|
||||
@@ -42,17 +69,16 @@ class FMPStockOwnershipFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockOwnershipQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockOwnershipQueryParams:
|
||||
return FMPStockOwnershipQueryParams.parse_obj(query)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPStockOwnershipQueryParams:
|
||||
return FMPStockOwnershipQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockOwnershipQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPStockOwnershipQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPStockOwnershipData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(
|
||||
4,
|
||||
@@ -60,8 +86,11 @@ class FMPStockOwnershipFetcher(
|
||||
api_key,
|
||||
query,
|
||||
)
|
||||
return get_data_many(url, FMPStockOwnershipData)
|
||||
|
||||
return get_data_many(url, FMPStockOwnershipData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockOwnershipData]) -> List[StockOwnershipData]:
|
||||
return data_transformer(data, StockOwnershipData)
|
||||
def transform_data(
|
||||
data: List[FMPStockOwnershipData],
|
||||
) -> List[FMPStockOwnershipData]:
|
||||
return data
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""FMP Stock Peers fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_peers import StockPeersData, StockPeersQueryParams
|
||||
|
||||
from openbb_fmp.utils.helpers import create_url, get_data_many
|
||||
@@ -16,17 +15,17 @@ class FMPStockPeersQueryParams(StockPeersQueryParams):
|
||||
"""FMP Stock Peers query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Stock-Peers
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
|
||||
class FMPStockPeersData(StockPeersData):
|
||||
"""FMP Stock Peers data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"peers_list": "peersList",
|
||||
}
|
||||
|
||||
|
||||
class FMPStockPeersFetcher(
|
||||
Fetcher[
|
||||
@@ -37,21 +36,20 @@ class FMPStockPeersFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockPeersQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockPeersQueryParams:
|
||||
return FMPStockPeersQueryParams(symbol=query.symbol, **extra_params or {})
|
||||
def transform_query(params: Dict[str, Any]) -> FMPStockPeersQueryParams:
|
||||
return FMPStockPeersQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockPeersQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPStockPeersQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any
|
||||
) -> List[FMPStockPeersData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
url = create_url(4, "stock_peers", api_key, query)
|
||||
return get_data_many(url, FMPStockPeersData)
|
||||
return get_data_many(url, FMPStockPeersData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockPeersData]) -> List[StockPeersData]:
|
||||
return data_transformer(data, StockPeersData)
|
||||
def transform_data(data: List[FMPStockPeersData]) -> List[FMPStockPeersData]:
|
||||
return data
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
"""FMP Stock Price fetcher."""
|
||||
|
||||
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_price import StockPriceData, StockPriceQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_fmp.utils.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
|
||||
class Interval(str, Enum):
|
||||
oneminute = "1min"
|
||||
fiveminute = "5min"
|
||||
fifteenminute = "15min"
|
||||
thirtyminute = "30min"
|
||||
onehour = "1hour"
|
||||
fourhour = "4hour"
|
||||
|
||||
|
||||
class FMPStockPriceQueryParams(QueryParams):
|
||||
"""FMP Stock Price query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Stock-Historical-Price
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
interval : Enum of ["1min", "5min", "15min", "30min", "1hour", "4hour"] (default: "1hour")
|
||||
The interval of the data.
|
||||
"""
|
||||
|
||||
symbol: str = Field(min_length=1)
|
||||
interval: Literal["1min", "5min", "15min", "30min", "1hour", "4hour"] = "1hour"
|
||||
|
||||
|
||||
class FMPStockPriceData(BaseStockPriceData):
|
||||
"""FMP Stock Price data."""
|
||||
|
||||
|
||||
class FMPStockPriceFetcher(
|
||||
Fetcher[
|
||||
StockPriceQueryParams,
|
||||
StockPriceData,
|
||||
FMPStockPriceQueryParams,
|
||||
FMPStockPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockPriceQueryParams:
|
||||
return FMPStockPriceQueryParams(
|
||||
symbol=query.symbol, **extra_params if extra_params else {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockPriceQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[FMPStockPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
|
||||
url = create_url(
|
||||
3, f"historical-chart/{query.interval}/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPStockPriceData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockPriceData]) -> List[StockPriceData]:
|
||||
return data_transformer(data, StockPriceData)
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
|
||||
from datetime import date
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_splits import (
|
||||
StockSplitCalendarData,
|
||||
StockSplitCalendarQueryParams,
|
||||
@@ -18,18 +17,8 @@ class FMPStockSplitCalendarQueryParams(StockSplitCalendarQueryParams):
|
||||
"""FMP Stock Split Calendar query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/stock-split-calendar-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
start_date : date
|
||||
The start date of the stock splits from which to retrieve the data.
|
||||
end_date : date
|
||||
The end date of the stock splits up to which to retrieve the data.
|
||||
"""
|
||||
|
||||
start_date: date
|
||||
end_date: date
|
||||
|
||||
|
||||
class FMPStockSplitCalendarData(StockSplitCalendarData):
|
||||
"""FMP Stock Split Calendar data."""
|
||||
@@ -44,30 +33,31 @@ class FMPStockSplitCalendarFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockSplitCalendarQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockSplitCalendarQueryParams:
|
||||
now = date.today()
|
||||
start_date = query.start_date if query.start_date else now
|
||||
end_date = query.end_date if query.end_date else now
|
||||
return FMPStockSplitCalendarQueryParams(
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPStockSplitCalendarQueryParams:
|
||||
today = date.today()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = today
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = today
|
||||
|
||||
return FMPStockSplitCalendarQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockSplitCalendarQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPStockSplitCalendarQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPStockSplitCalendarData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query_str = f"from={query.start_date}&to={query.end_date}"
|
||||
url = create_url(3, f"stock_split_calendar?{query_str}", api_key)
|
||||
return get_data_many(url, FMPStockSplitCalendarData)
|
||||
return get_data_many(url, FMPStockSplitCalendarData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPStockSplitCalendarData],
|
||||
) -> List[StockSplitCalendarData]:
|
||||
return data_transformer(data, StockSplitCalendarData)
|
||||
) -> List[FMPStockSplitCalendarData]:
|
||||
return data
|
||||
|
||||
@@ -1,49 +1,50 @@
|
||||
"""FMP Treasury Rates fetcher."""
|
||||
|
||||
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.treasury_rates import (
|
||||
TreasuryRatesData,
|
||||
TreasuryRatesQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_fmp.utils.helpers import get_data_many
|
||||
from openbb_fmp.utils.helpers import get_data_many, get_querystring
|
||||
|
||||
|
||||
class FMPTreasuryRatesQueryParams(TreasuryRatesQueryParams):
|
||||
"""FMP Stock News query.
|
||||
"""FMP Stock News Query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/treasury-rates-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
start_date : str
|
||||
The start date of the data.
|
||||
end_date : str
|
||||
The end date of the data. Default is today.
|
||||
Maximum time interval can be 3 months.
|
||||
"""
|
||||
|
||||
|
||||
class FMPTreasuryRatesData(Data):
|
||||
date: dateType
|
||||
month1: float = Field(alias="month_1")
|
||||
month2: float = Field(alias="month_2")
|
||||
month3: float = Field(alias="month_3")
|
||||
month6: float = Field(alias="month_6")
|
||||
year1: float = Field(alias="year_1")
|
||||
year2: float = Field(alias="year_2")
|
||||
year3: float = Field(alias="year_3")
|
||||
year5: float = Field(alias="year_5")
|
||||
year7: float = Field(alias="year_7")
|
||||
year10: float = Field(alias="year_10")
|
||||
year20: float = Field(alias="year_20")
|
||||
year30: float = Field(alias="year_30")
|
||||
class FMPTreasuryRatesData(TreasuryRatesData):
|
||||
"""FMP Treasury Rates Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"month_1": "month1",
|
||||
"month_2": "month2",
|
||||
"month_3": "month3",
|
||||
"month_6": "month6",
|
||||
"year_1": "year1",
|
||||
"year_2": "year2",
|
||||
"year_3": "year3",
|
||||
"year_5": "year5",
|
||||
"year_7": "year7",
|
||||
"year_10": "year10",
|
||||
"year_20": "year20",
|
||||
"year_30": "year30",
|
||||
}
|
||||
|
||||
@validator("date", pre=True, check_fields=False)
|
||||
def date_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
class FMPTreasuryRatesFetcher(
|
||||
@@ -55,26 +56,28 @@ class FMPTreasuryRatesFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: TreasuryRatesQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPTreasuryRatesQueryParams:
|
||||
return FMPTreasuryRatesQueryParams(
|
||||
start_date=query.start_date, end_date=query.end_date
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FMPTreasuryRatesQueryParams:
|
||||
return FMPTreasuryRatesQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPTreasuryRatesQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: FMPTreasuryRatesQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[FMPTreasuryRatesData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("fmp_api_key")
|
||||
api_key = credentials.get("fmp_api_key") if credentials else ""
|
||||
|
||||
query.start_date = (datetime.now() - timedelta(91)).date()
|
||||
query.end_date = (datetime.now() - timedelta(1)).date()
|
||||
|
||||
base_url = "https://financialmodelingprep.com/api/v4/"
|
||||
# query_str = get_querystring(query.dict(by_alias=True), [])
|
||||
query_str = get_querystring(query.dict(), [])
|
||||
query_str = query_str.replace("start_date", "from").replace("end_date", "to")
|
||||
url = f"{base_url}treasury?{query_str}&apikey={api_key}"
|
||||
return get_data_many(url, FMPTreasuryRatesData)
|
||||
|
||||
return get_data_many(url, FMPTreasuryRatesData, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPTreasuryRatesData]) -> List[TreasuryRatesData]:
|
||||
return data_transformer(data, TreasuryRatesData)
|
||||
def transform_data(data: List[FMPTreasuryRatesData]) -> List[FMPTreasuryRatesData]:
|
||||
return data
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
"""FMP Provider module."""
|
||||
|
||||
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_fmp.models.analyst_estimates import FMPAnalystEstimatesFetcher
|
||||
from openbb_fmp.models.available_indices import FMPAvailableIndicesFetcher
|
||||
from openbb_fmp.models.balance_sheet import FMPBalanceSheetFetcher
|
||||
from openbb_fmp.models.cash_flow import FMPCashFlowStatementFetcher
|
||||
from openbb_fmp.models.company_profile import FMPCompanyProfileFetcher
|
||||
from openbb_fmp.models.crypto_eod import FMPCryptoEODFetcher
|
||||
from openbb_fmp.models.crypto_price import FMPCryptoPriceFetcher
|
||||
from openbb_fmp.models.dividend_calendar import FMPDividendCalendarFetcher
|
||||
from openbb_fmp.models.earnings_calendar import FMPEarningsCalendarFetcher
|
||||
from openbb_fmp.models.earnings_call_transcript import FMPEarningsCallTranscriptFetcher
|
||||
from openbb_fmp.models.esg_risk_rating import FMPESGRiskRatingFetcher
|
||||
from openbb_fmp.models.esg_score import FMPESGScoreFetcher
|
||||
from openbb_fmp.models.esg_sector import FMPESGSectorFetcher
|
||||
from openbb_fmp.models.executive_compensation import FMPExecutiveCompensationFetcher
|
||||
from openbb_fmp.models.executives import FMPKeyExecutivesFetcher
|
||||
from openbb_fmp.models.forex_eod import FMPForexEODFetcher
|
||||
from openbb_fmp.models.forex_pairs import FMPForexPairsFetcher
|
||||
from openbb_fmp.models.forex_price import FMPForexPriceFetcher
|
||||
from openbb_fmp.models.global_news import FMPGlobalNewsFetcher
|
||||
from openbb_fmp.models.historical_dividends import FMPHistoricalDividendsFetcher
|
||||
from openbb_fmp.models.historical_employees import FMPHistoricalEmployeesFetcher
|
||||
from openbb_fmp.models.historical_stock_splits import FMPHistoricalStockSplitsFetcher
|
||||
from openbb_fmp.models.income_statement import FMPIncomeStatementFetcher
|
||||
from openbb_fmp.models.institutional_ownership import FMPInstitutionalOwnershipFetcher
|
||||
from openbb_fmp.models.key_metrics import FMPKeyMetricsFetcher
|
||||
from openbb_fmp.models.major_indices_constituents import (
|
||||
FMPMajorIndicesConstituentsFetcher,
|
||||
)
|
||||
from openbb_fmp.models.major_indices_eod import FMPMajorIndicesEODFetcher
|
||||
from openbb_fmp.models.major_indices_price import FMPMajorIndicesPriceFetcher
|
||||
from openbb_fmp.models.price_target import FMPPriceTargetFetcher
|
||||
from openbb_fmp.models.price_target_consensus import FMPPriceTargetConsensusFetcher
|
||||
from openbb_fmp.models.revenue_business_line import FMPRevenueBusinessLineFetcher
|
||||
from openbb_fmp.models.revenue_geographic import FMPRevenueGeographicFetcher
|
||||
from openbb_fmp.models.risk_premium import FMPRiskPremiumFetcher
|
||||
from openbb_fmp.models.sec_filings import FMPSECFilingsFetcher
|
||||
from openbb_fmp.models.share_statistics import FMPShareStatisticsFetcher
|
||||
from openbb_fmp.models.stock_eod import FMPStockEODFetcher
|
||||
from openbb_fmp.models.stock_insider_trading import FMPStockInsiderTradingFetcher
|
||||
from openbb_fmp.models.stock_multiples import FMPStockMultiplesFetcher
|
||||
from openbb_fmp.models.stock_news import FMPStockNewsFetcher
|
||||
from openbb_fmp.models.stock_ownership import FMPStockOwnershipFetcher
|
||||
from openbb_fmp.models.stock_peers import FMPStockPeersFetcher
|
||||
from openbb_fmp.models.stock_price import FMPStockPriceFetcher
|
||||
from openbb_fmp.models.stock_splits import FMPStockSplitCalendarFetcher
|
||||
from openbb_fmp.models.treasury_rates import FMPTreasuryRatesFetcher
|
||||
|
||||
# mypy: disable-error-code="list-item"
|
||||
|
||||
fmp_provider = Provider(
|
||||
name="fmp",
|
||||
description="Provider for FMP.",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_list=[
|
||||
FMPKeyExecutivesFetcher,
|
||||
FMPStockEODFetcher,
|
||||
FMPGlobalNewsFetcher,
|
||||
FMPStockNewsFetcher,
|
||||
FMPIncomeStatementFetcher,
|
||||
FMPBalanceSheetFetcher,
|
||||
FMPCashFlowStatementFetcher,
|
||||
FMPShareStatisticsFetcher,
|
||||
FMPMajorIndicesEODFetcher,
|
||||
FMPRevenueGeographicFetcher,
|
||||
FMPRevenueBusinessLineFetcher,
|
||||
FMPInstitutionalOwnershipFetcher,
|
||||
FMPCompanyProfileFetcher,
|
||||
FMPStockInsiderTradingFetcher,
|
||||
FMPStockOwnershipFetcher,
|
||||
FMPESGScoreFetcher,
|
||||
FMPESGSectorFetcher,
|
||||
FMPESGRiskRatingFetcher,
|
||||
FMPStockPriceFetcher,
|
||||
FMPPriceTargetConsensusFetcher,
|
||||
FMPPriceTargetFetcher,
|
||||
FMPAnalystEstimatesFetcher,
|
||||
FMPEarningsCalendarFetcher,
|
||||
FMPEarningsCallTranscriptFetcher,
|
||||
FMPHistoricalStockSplitsFetcher,
|
||||
FMPStockSplitCalendarFetcher,
|
||||
FMPHistoricalDividendsFetcher,
|
||||
FMPKeyMetricsFetcher,
|
||||
FMPSECFilingsFetcher,
|
||||
FMPTreasuryRatesFetcher,
|
||||
FMPExecutiveCompensationFetcher,
|
||||
FMPCryptoPriceFetcher,
|
||||
FMPCryptoEODFetcher,
|
||||
FMPMajorIndicesPriceFetcher,
|
||||
FMPForexEODFetcher,
|
||||
FMPForexPriceFetcher,
|
||||
FMPForexPairsFetcher,
|
||||
FMPStockPeersFetcher,
|
||||
FMPStockMultiplesFetcher,
|
||||
FMPHistoricalEmployeesFetcher,
|
||||
FMPAvailableIndicesFetcher,
|
||||
FMPRiskPremiumFetcher,
|
||||
FMPMajorIndicesConstituentsFetcher,
|
||||
FMPDividendCalendarFetcher,
|
||||
],
|
||||
)
|
||||
@@ -1,16 +1,16 @@
|
||||
"""FMP Helpers Module."""
|
||||
|
||||
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import List, Optional, Type, TypeVar, Union
|
||||
from io import StringIO
|
||||
from typing import Any, List, Optional, Type, TypeVar, Union
|
||||
|
||||
import requests
|
||||
from openbb_provider import helpers
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import QueryParamsType
|
||||
from openbb_provider.helpers import (
|
||||
BasicResponse,
|
||||
from openbb_provider.utils.helpers import (
|
||||
get_querystring,
|
||||
request,
|
||||
)
|
||||
from pydantic import BaseModel, NonNegativeInt, PositiveFloat, validator
|
||||
from requests.exceptions import SSLError
|
||||
@@ -18,10 +18,41 @@ from requests.exceptions import SSLError
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
|
||||
|
||||
def get_data(url: str) -> Union[list, dict]:
|
||||
class BasicResponse:
|
||||
def __init__(self, response: StringIO):
|
||||
# Find a way to get the status code
|
||||
self.status_code = 200
|
||||
response.seek(0)
|
||||
self.text = response.read()
|
||||
|
||||
def json(self) -> dict:
|
||||
return json.loads(self.text)
|
||||
|
||||
|
||||
def request(url: str) -> BasicResponse:
|
||||
"""
|
||||
Request function for PyScript. Pass in Method and make sure to await!
|
||||
Parameters:
|
||||
-----------
|
||||
url: str
|
||||
URL to make request to
|
||||
|
||||
Return:
|
||||
-------
|
||||
response: BasicRequest
|
||||
BasicRequest object with status_code and text attributes
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from pyodide.http import open_url
|
||||
|
||||
response = open_url(url)
|
||||
return BasicResponse(response)
|
||||
|
||||
|
||||
def get_data(url: str, **kwargs: Any) -> Union[list, dict]:
|
||||
"""Get data from FMP endpoint."""
|
||||
try:
|
||||
r: Union[requests.Response, BasicResponse] = requests.get(url, timeout=10)
|
||||
r: Union[requests.Response, BasicResponse] = helpers.make_request(url, **kwargs)
|
||||
except SSLError:
|
||||
r = request(url)
|
||||
if r.status_code == 404:
|
||||
@@ -69,14 +100,14 @@ def create_url(
|
||||
The querystring.
|
||||
|
||||
"""
|
||||
the_dict = {} if not query else query.dict()
|
||||
the_dict = {} if not query else query.dict(by_alias=True)
|
||||
query_string = get_querystring(the_dict, exclude or [])
|
||||
base_url = f"https://financialmodelingprep.com/api/v{version}/"
|
||||
return f"{base_url}{endpoint}?{query_string}&apikey={api_key}"
|
||||
|
||||
|
||||
def get_data_many(
|
||||
url: str, to_schema: Type[T], sub_dict: Optional[str] = None
|
||||
url: str, to_schema: Type[T], sub_dict: Optional[str] = None, **kwargs: Any
|
||||
) -> List[T]:
|
||||
"""Get data from FMP endpoint and convert to list of schemas.
|
||||
|
||||
@@ -94,7 +125,7 @@ def get_data_many(
|
||||
List[T]
|
||||
The list of schemas.
|
||||
"""
|
||||
data = get_data(url)
|
||||
data = get_data(url, **kwargs)
|
||||
if sub_dict and isinstance(data, dict):
|
||||
data = data.get(sub_dict, [])
|
||||
if isinstance(data, dict):
|
||||
@@ -102,9 +133,9 @@ def get_data_many(
|
||||
return [to_schema(**d) for d in data]
|
||||
|
||||
|
||||
def get_data_one(url: str, to_schema: Type[T]) -> T:
|
||||
def get_data_one(url: str, to_schema: Type[T], **kwargs: Any) -> T:
|
||||
"""Get data from FMP endpoint and convert to schema."""
|
||||
data = get_data(url)
|
||||
data = get_data(url, **kwargs)
|
||||
if isinstance(data, list):
|
||||
if len(data) == 0:
|
||||
raise ValueError("Expected dict, got empty list")
|
||||
|
||||
2
openbb_sdk/providers/fmp/pyproject.toml
vendored
2
openbb_sdk/providers/fmp/pyproject.toml
vendored
@@ -15,4 +15,4 @@ requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."openbb_provider_extension"]
|
||||
fmp = "openbb_fmp.provider:fmp_provider"
|
||||
fmp = "openbb_fmp:fmp_provider"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
"""FRED provider module."""
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_fred.models.cpi import FREDCPIFetcher
|
||||
|
||||
fred_provider = Provider(
|
||||
name="fred",
|
||||
website="https://fred.stlouisfed.org/",
|
||||
description="""Federal Reserve Economic Data is a database maintained by the
|
||||
Research division of the Federal Reserve Bank of St. Louis that has more than
|
||||
816,000 economic time series from various sources.""",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_dict={"CPI": FREDCPIFetcher},
|
||||
)
|
||||
|
||||
@@ -1,34 +1,16 @@
|
||||
"""FRED CPI Fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_fred.utils.fred_base import Fred
|
||||
from openbb_fred.utils.fred_helpers import all_cpi_options
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.cpi import CPIData, CPIDataPoint, CPIQueryParams
|
||||
from openbb_provider.models.cpi import CPIData, CPIQueryParams
|
||||
|
||||
|
||||
class FREDCPIQueryParams(CPIQueryParams):
|
||||
"""CPI query.
|
||||
When other provders are added, this will probably need less strict types
|
||||
|
||||
Parameter
|
||||
---------
|
||||
countries: List[CPI_COUNTRIES]
|
||||
The country or countries you want to see.
|
||||
units: List[CPI_UNITS]
|
||||
The units you want to see, can be "growth_previous", "growth_same" or "index_2015".
|
||||
frequency: List[CPI_FREQUENCY]
|
||||
The frequency you want to see, either "annual", monthly" or "quarterly".
|
||||
harmonized: bool
|
||||
Whether you wish to obtain harmonized data.
|
||||
start_date: Optional[date]
|
||||
Start date, formatted YYYY-MM-DD
|
||||
end_date: Optional[date]
|
||||
End date, formatted YYYY-MM-DD
|
||||
"""
|
||||
"""CPI query."""
|
||||
|
||||
|
||||
class FREDCPIData(CPIData):
|
||||
@@ -36,26 +18,17 @@ class FREDCPIData(CPIData):
|
||||
|
||||
|
||||
class FREDCPIFetcher(Fetcher[CPIQueryParams, CPIData, FREDCPIQueryParams, FREDCPIData]):
|
||||
"""FRED CPI Fetcher."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CPIQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FREDCPIQueryParams:
|
||||
return FREDCPIQueryParams(
|
||||
countries=query.countries,
|
||||
units=query.units,
|
||||
frequency=query.frequency,
|
||||
harmonized=query.harmonized,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date,
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> FREDCPIQueryParams:
|
||||
return FREDCPIQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FREDCPIQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> FREDCPIData:
|
||||
if credentials:
|
||||
api_key = credentials.get("fred_api_key")
|
||||
query: FREDCPIQueryParams, credentials: Optional[Dict[str, str]], **kwargs: Any
|
||||
) -> List[Dict[str, List[FREDCPIData]]]:
|
||||
api_key = credentials.get("fred_api_key") if credentials else ""
|
||||
|
||||
all_options = all_cpi_options(query.harmonized)
|
||||
|
||||
@@ -63,20 +36,20 @@ class FREDCPIFetcher(Fetcher[CPIQueryParams, CPIData, FREDCPIQueryParams, FREDCP
|
||||
step_2 = [x for x in step_1 if x["units"] == query.units]
|
||||
step_3 = [x for x in step_2 if x["frequency"] == query.frequency]
|
||||
|
||||
if not step_3:
|
||||
FREDCPIData(data={})
|
||||
|
||||
series_dict = {}
|
||||
|
||||
fred = Fred(api_key)
|
||||
for item in step_3:
|
||||
loc = f"{item['country']}-{item['frequency']}-{item['units']}"
|
||||
temp = fred.get_series(item["series_id"], query.start_date, query.end_date)
|
||||
clean_temp = [CPIDataPoint(**x) for x in temp]
|
||||
temp = fred.get_series(
|
||||
item["series_id"], query.start_date, query.end_date, **kwargs
|
||||
)
|
||||
clean_temp = [FREDCPIData(**x) for x in temp]
|
||||
series_dict[loc] = clean_temp
|
||||
|
||||
return FREDCPIData(data=series_dict)
|
||||
return [series_dict]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FREDCPIData]) -> List[CPIData]:
|
||||
return data_transformer(data, CPIData)
|
||||
def transform_data(
|
||||
data: List[Dict[str, List[FREDCPIData]]]
|
||||
) -> List[Dict[str, List[FREDCPIData]]]:
|
||||
return data
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
"""FRED provider module."""
|
||||
|
||||
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_fred.models.cpi import FREDCPIFetcher
|
||||
|
||||
# mypy: disable-error-code="list-item"
|
||||
|
||||
fred_provider = Provider(
|
||||
name="fred",
|
||||
description="Provider for FRED.",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_list=[FREDCPIFetcher],
|
||||
)
|
||||
@@ -1,8 +1,8 @@
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import requests
|
||||
from openbb_provider import helpers
|
||||
|
||||
root_url = "https://api.stlouisfed.org/fred"
|
||||
|
||||
@@ -11,9 +11,9 @@ class Fred:
|
||||
def __init__(self, api_key: Optional[str]):
|
||||
self.api_key = api_key
|
||||
|
||||
def __fetch_data(self, url: str):
|
||||
def __fetch_data(self, url: str, **kwargs: Any):
|
||||
full_url = f"{url}&api_key={self.api_key}&file_type=json"
|
||||
response = requests.get(full_url, timeout=10)
|
||||
response = helpers.make_request(full_url, **kwargs)
|
||||
return response.json()
|
||||
|
||||
def get_series(
|
||||
@@ -50,8 +50,10 @@ class Fred:
|
||||
if end_date:
|
||||
url += "&observation_end=" + end_date.strftime("%Y-%m-%d")
|
||||
if kwargs.keys():
|
||||
url += "&" + urlencode(kwargs)
|
||||
root = self.__fetch_data(url)
|
||||
url += "&" + urlencode(
|
||||
{k: v for k, v in kwargs.items() if k != "preferences"}
|
||||
)
|
||||
root = self.__fetch_data(url, **kwargs)
|
||||
if root is None:
|
||||
raise ValueError("No data exists for series id: " + series_id)
|
||||
return root["observations"]
|
||||
|
||||
@@ -1,63 +1,7 @@
|
||||
import csv
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Literal
|
||||
|
||||
CPI_COUNTRIES = Literal[
|
||||
"australia",
|
||||
"austria",
|
||||
"belgium",
|
||||
"brazil",
|
||||
"bulgaria",
|
||||
"canada",
|
||||
"chile",
|
||||
"china",
|
||||
"croatia",
|
||||
"cyprus",
|
||||
"czech_republic",
|
||||
"denmark",
|
||||
"estonia",
|
||||
"euro_area",
|
||||
"finland",
|
||||
"france",
|
||||
"germany",
|
||||
"greece",
|
||||
"hungary",
|
||||
"iceland",
|
||||
"india",
|
||||
"indonesia",
|
||||
"ireland",
|
||||
"israel",
|
||||
"italy",
|
||||
"japan",
|
||||
"korea",
|
||||
"latvia",
|
||||
"lithuania",
|
||||
"luxembourg",
|
||||
"malta",
|
||||
"mexico",
|
||||
"netherlands",
|
||||
"new_zealand",
|
||||
"norway",
|
||||
"poland",
|
||||
"portugal",
|
||||
"romania",
|
||||
"russian_federation",
|
||||
"slovak_republic",
|
||||
"slovakia",
|
||||
"slovenia",
|
||||
"south_africa",
|
||||
"spain",
|
||||
"sweden",
|
||||
"switzerland",
|
||||
"turkey",
|
||||
"united_kingdom",
|
||||
"united_states",
|
||||
]
|
||||
|
||||
CPI_UNITS = Literal["growth_previous", "growth_same", "index_2015"]
|
||||
|
||||
CPI_FREQUENCY = Literal["monthly", "quarterly", "annual"]
|
||||
from typing import List
|
||||
|
||||
|
||||
def all_cpi_options(harmonized: bool = False) -> List[dict]:
|
||||
|
||||
245
openbb_sdk/providers/fred/poetry.lock
generated
vendored
245
openbb_sdk/providers/fred/poetry.lock
generated
vendored
@@ -1,245 +0,0 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2023.5.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"},
|
||||
{file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.2.0"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
|
||||
{file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
|
||||
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openbb-provider"
|
||||
version = "0.2.0"
|
||||
description = ""
|
||||
optional = false
|
||||
python-versions = "^3.8"
|
||||
files = []
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = {version = "^1.10", extras = ["dotenv"]}
|
||||
requests = "^2.31.0"
|
||||
urllib3 = "<2.0.0"
|
||||
|
||||
[package.source]
|
||||
type = "directory"
|
||||
url = "../../sdk/provider"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "1.10.11"
|
||||
description = "Data validation and settings management using python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pydantic-1.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ff44c5e89315b15ff1f7fdaf9853770b810936d6b01a7bcecaa227d2f8fe444f"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6c098d4ab5e2d5b3984d3cb2527e2d6099d3de85630c8934efcfdc348a9760e"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16928fdc9cb273c6af00d9d5045434c39afba5f42325fb990add2c241402d151"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0588788a9a85f3e5e9ebca14211a496409cb3deca5b6971ff37c556d581854e7"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9baf78b31da2dc3d3f346ef18e58ec5f12f5aaa17ac517e2ffd026a92a87588"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:373c0840f5c2b5b1ccadd9286782852b901055998136287828731868027a724f"},
|
||||
{file = "pydantic-1.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:c3339a46bbe6013ef7bdd2844679bfe500347ac5742cd4019a88312aa58a9847"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:08a6c32e1c3809fbc49debb96bf833164f3438b3696abf0fbeceb417d123e6eb"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a451ccab49971af043ec4e0d207cbc8cbe53dbf148ef9f19599024076fe9c25b"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b02d24f7b2b365fed586ed73582c20f353a4c50e4be9ba2c57ab96f8091ddae"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f34739a89260dfa420aa3cbd069fbcc794b25bbe5c0a214f8fb29e363484b66"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e297897eb4bebde985f72a46a7552a7556a3dd11e7f76acda0c1093e3dbcf216"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d185819a7a059550ecb85d5134e7d40f2565f3dd94cfd870132c5f91a89cf58c"},
|
||||
{file = "pydantic-1.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:4400015f15c9b464c9db2d5d951b6a780102cfa5870f2c036d37c23b56f7fc1b"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2417de68290434461a266271fc57274a138510dca19982336639484c73a07af6"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:331c031ba1554b974c98679bd0780d89670d6fd6f53f5d70b10bdc9addee1713"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8268a735a14c308923e8958363e3a3404f6834bb98c11f5ab43251a4e410170c"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:44e51ba599c3ef227e168424e220cd3e544288c57829520dc90ea9cb190c3248"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d7781f1d13b19700b7949c5a639c764a077cbbdd4322ed505b449d3ca8edcb36"},
|
||||
{file = "pydantic-1.10.11-cp37-cp37m-win_amd64.whl", hash = "sha256:7522a7666157aa22b812ce14c827574ddccc94f361237ca6ea8bb0d5c38f1629"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc64eab9b19cd794a380179ac0e6752335e9555d214cfcb755820333c0784cb3"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8dc77064471780262b6a68fe67e013298d130414d5aaf9b562c33987dbd2cf4f"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe429898f2c9dd209bd0632a606bddc06f8bce081bbd03d1c775a45886e2c1cb"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:192c608ad002a748e4a0bed2ddbcd98f9b56df50a7c24d9a931a8c5dd053bd3d"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ef55392ec4bb5721f4ded1096241e4b7151ba6d50a50a80a2526c854f42e6a2f"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:41e0bb6efe86281623abbeeb0be64eab740c865388ee934cd3e6a358784aca6e"},
|
||||
{file = "pydantic-1.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:265a60da42f9f27e0b1014eab8acd3e53bd0bad5c5b4884e98a55f8f596b2c19"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:469adf96c8e2c2bbfa655fc7735a2a82f4c543d9fee97bd113a7fb509bf5e622"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e6cbfbd010b14c8a905a7b10f9fe090068d1744d46f9e0c021db28daeb8b6de1"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abade85268cc92dff86d6effcd917893130f0ff516f3d637f50dadc22ae93999"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9738b0f2e6c70f44ee0de53f2089d6002b10c33264abee07bdb5c7f03038303"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:787cf23e5a0cde753f2eabac1b2e73ae3844eb873fd1f5bdbff3048d8dbb7604"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:174899023337b9fc685ac8adaa7b047050616136ccd30e9070627c1aaab53a13"},
|
||||
{file = "pydantic-1.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:1954f8778489a04b245a1e7b8b22a9d3ea8ef49337285693cf6959e4b757535e"},
|
||||
{file = "pydantic-1.10.11-py3-none-any.whl", hash = "sha256:008c5e266c8aada206d0627a011504e14268a62091450210eda7c07fabe6963e"},
|
||||
{file = "pydantic-1.10.11.tar.gz", hash = "sha256:f66d479cf7eb331372c470614be6511eae96f1f120344c25f3f9bb59fb1b5528"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""}
|
||||
typing-extensions = ">=4.2.0"
|
||||
|
||||
[package.extras]
|
||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||
email = ["email-validator (>=1.0.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.0"
|
||||
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
|
||||
{file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
description = "Python HTTP for Humans."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = ">=2,<4"
|
||||
idna = ">=2.5,<4"
|
||||
urllib3 = ">=1.21.1,<3"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.7.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
|
||||
{file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.16"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
files = [
|
||||
{file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"},
|
||||
{file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "26269b8a989dcc6ac67961b7a43d485d231c8ac878265ac90f310ced959fc532"
|
||||
2
openbb_sdk/providers/fred/pyproject.toml
vendored
2
openbb_sdk/providers/fred/pyproject.toml
vendored
@@ -15,4 +15,4 @@ requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."openbb_provider_extension"]
|
||||
fred = "openbb_fred.provider:fred_provider"
|
||||
fred = "openbb_fred:fred_provider"
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Polygon provider module."""
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_polygon.models.balance_sheet import PolygonBalanceSheetFetcher
|
||||
from openbb_polygon.models.cash_flow import PolygonCashFlowStatementFetcher
|
||||
from openbb_polygon.models.crypto_eod import PolygonCryptoEODFetcher
|
||||
from openbb_polygon.models.forex_eod import PolygonForexEODFetcher
|
||||
from openbb_polygon.models.forex_pairs import PolygonForexPairsFetcher
|
||||
from openbb_polygon.models.income_statement import PolygonIncomeStatementFetcher
|
||||
from openbb_polygon.models.major_indices_eod import PolygonMajorIndicesEODFetcher
|
||||
from openbb_polygon.models.stock_eod import PolygonStockEODFetcher
|
||||
from openbb_polygon.models.stock_news import PolygonStockNewsFetcher
|
||||
|
||||
polygon_provider = Provider(
|
||||
name="polygon",
|
||||
website="https://polygon.io/",
|
||||
description="""The Polygon.io Stocks API provides REST endpoints that let you query
|
||||
the latest market data from all US stock exchanges. You can also find data on
|
||||
company financials, stock market holidays, corporate actions, and more.""",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_dict={
|
||||
"StockEOD": PolygonStockEODFetcher,
|
||||
"StockNews": PolygonStockNewsFetcher,
|
||||
"BalanceSheet": PolygonBalanceSheetFetcher,
|
||||
"IncomeStatement": PolygonIncomeStatementFetcher,
|
||||
"CashFlowStatement": PolygonCashFlowStatementFetcher,
|
||||
"CryptoEOD": PolygonCryptoEODFetcher,
|
||||
"MajorIndicesEOD": PolygonMajorIndicesEODFetcher,
|
||||
"ForexEOD": PolygonForexEODFetcher,
|
||||
"ForexPairs": PolygonForexPairsFetcher,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,38 +1,40 @@
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.balance_sheet import (
|
||||
BalanceSheetData,
|
||||
BalanceSheetQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import PolygonFundamentalQueryParams
|
||||
|
||||
|
||||
class PolygonBalanceSheetQueryParams(PolygonFundamentalQueryParams):
|
||||
__doc__ = PolygonFundamentalQueryParams.__doc__
|
||||
"""Polygon Fundamental QueryParams.
|
||||
|
||||
Source: https://polygon.io/docs/stocks#!/get_vx_reference_financials
|
||||
"""
|
||||
|
||||
|
||||
class PolygonBalanceSheetData(Data):
|
||||
cik: Optional[str]
|
||||
start_date: dateType = Field(alias="date")
|
||||
assets: Optional[int]
|
||||
current_assets: Optional[int]
|
||||
current_liabilities: Optional[int]
|
||||
equity: Optional[int] = Field(alias="total_equity")
|
||||
equity_attributable_to_noncontrolling_interest: Optional[int]
|
||||
equity_attributable_to_parent: Optional[int]
|
||||
liabilities: Optional[int]
|
||||
liabilities_and_equity: Optional[int] = Field(
|
||||
alias="total_liabilities_and_stockholders_equity"
|
||||
)
|
||||
noncurrent_assets: Optional[int]
|
||||
noncurrent_liabilities: Optional[int]
|
||||
class PolygonBalanceSheetData(BalanceSheetData):
|
||||
"""Return Balance Sheet Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"date": "start_date",
|
||||
"equity": "total_equity",
|
||||
"total_liabilities_and_stockholders_equity": "liabilities_and_equity",
|
||||
"minority_interest": "equity_attributable_to_noncontrolling_interest",
|
||||
}
|
||||
|
||||
@validator("symbol", pre=True, check_fields=False)
|
||||
def symbol_from_tickers(cls, v):
|
||||
if isinstance(v, list):
|
||||
return ",".join(v)
|
||||
return v
|
||||
|
||||
|
||||
class PolygonBalanceSheetFetcher(
|
||||
@@ -44,50 +46,46 @@ class PolygonBalanceSheetFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: BalanceSheetQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonBalanceSheetQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarterly"
|
||||
return PolygonBalanceSheetQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonBalanceSheetQueryParams:
|
||||
return PolygonBalanceSheetQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonBalanceSheetQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: PolygonBalanceSheetQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonBalanceSheetData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
base_url = "https://api.polygon.io/vX/reference/financials"
|
||||
query_string = get_querystring(query.dict(), [])
|
||||
query_string = get_querystring(query.dict(by_alias=True), [])
|
||||
request_url = f"{base_url}?{query_string}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
data = get_data(request_url, **kwargs)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No balance sheet found")
|
||||
|
||||
FIELDS = [
|
||||
"assets",
|
||||
"current_assets",
|
||||
"current_liabilities",
|
||||
"equity",
|
||||
"equity_attributable_to_noncontrolling_interest",
|
||||
"equity_attributable_to_parent",
|
||||
"liabilities",
|
||||
"liabilities_and_equity",
|
||||
"noncurrent_assets",
|
||||
"noncurrent_liabilities",
|
||||
]
|
||||
|
||||
to_return = []
|
||||
for item in data:
|
||||
new = {"start_date": item["start_date"]}
|
||||
new["cik"] = item["cik"]
|
||||
bs = item["financials"]["balance_sheet"]
|
||||
# TODO: Unpack this dynamically to avoid hardcoding.
|
||||
new["assets"] = bs["assets"].get("value")
|
||||
new["current_assets"] = bs["current_assets"].get("value")
|
||||
new["current_liabilities"] = bs["current_liabilities"].get("value")
|
||||
new["equity"] = bs["equity"].get("value")
|
||||
new["equity_attributable_to_noncontrolling_interest"] = bs[
|
||||
"equity_attributable_to_noncontrolling_interest"
|
||||
].get("value")
|
||||
new["equity_attributable_to_parent"] = bs[
|
||||
"equity_attributable_to_parent"
|
||||
].get("value")
|
||||
new["equity"] = bs["equity"].get("value")
|
||||
new["liabilities"] = bs["liabilities"].get("value")
|
||||
new["liabilities_and_equity"] = bs["liabilities_and_equity"].get("value")
|
||||
new["noncurrent_assets"] = bs["noncurrent_assets"].get("value")
|
||||
new["noncurrent_liabilities"] = bs["noncurrent_liabilities"].get("value")
|
||||
new = {"start_date": item["start_date"], "cik": item["cik"]}
|
||||
if bs := item["financials"]["balance_sheet"]:
|
||||
for field in FIELDS:
|
||||
new[field] = bs[field].get("value", 0)
|
||||
|
||||
to_return.append(PolygonBalanceSheetData(**new))
|
||||
return to_return
|
||||
@@ -95,5 +93,5 @@ class PolygonBalanceSheetFetcher(
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonBalanceSheetData],
|
||||
) -> List[BalanceSheetData]:
|
||||
return data_transformer(data, BalanceSheetData)
|
||||
) -> List[PolygonBalanceSheetData]:
|
||||
return data
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.cash_flows import (
|
||||
CashFlowStatementData,
|
||||
CashFlowStatementQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import PolygonFundamentalQueryParams
|
||||
@@ -23,21 +18,17 @@ class PolygonCashFlowStatementQueryParams(PolygonFundamentalQueryParams):
|
||||
__doc__ = PolygonFundamentalQueryParams.__doc__
|
||||
|
||||
|
||||
class PolygonCashFlowStatementData(Data):
|
||||
start_date: dateType = Field(alias="date")
|
||||
tickers: Optional[List[str]] = Field(alias="symbol")
|
||||
cik: Optional[str]
|
||||
filing_date: Optional[dateType]
|
||||
acceptance_datetime: Optional[datetime]
|
||||
fiscal_period: Optional[str] = Field(alias="period")
|
||||
net_cash_flow: int
|
||||
net_cash_flow_from_financing_activities: int
|
||||
net_cash_flow_from_investing_activities: int
|
||||
net_cash_flow_from_operating_activities: int
|
||||
net_cash_flow_continuing: int
|
||||
net_cash_flow_from_financing_activities_continuing: int
|
||||
net_cash_flow_from_investing_activities_continuing: int
|
||||
net_cash_flow_from_operating_activities_continuing: int
|
||||
class PolygonCashFlowStatementData(CashFlowStatementData):
|
||||
"""Cash Flow Statement Data."""
|
||||
|
||||
class Config:
|
||||
fields = {"date": "start_date"}
|
||||
|
||||
@validator("symbol", pre=True, check_fields=False)
|
||||
def symbol_from_tickers(cls, v):
|
||||
if isinstance(v, list):
|
||||
return ",".join(v)
|
||||
return v
|
||||
|
||||
|
||||
class PolygonCashFlowStatementFetcher(
|
||||
@@ -49,61 +40,44 @@ class PolygonCashFlowStatementFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CashFlowStatementQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonCashFlowStatementQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarterly"
|
||||
return PolygonCashFlowStatementQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonCashFlowStatementQueryParams:
|
||||
return PolygonCashFlowStatementQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonCashFlowStatementQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonCashFlowStatementData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
base_url = "https://api.polygon.io/vX/reference/financials"
|
||||
query_string = get_querystring(query.dict(), [])
|
||||
query_string = get_querystring(query.dict(by_alias=True), [])
|
||||
request_url = f"{base_url}?{query_string}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
data = get_data(request_url, **kwargs)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No Cash Flow Statement found")
|
||||
|
||||
FIELDS = [
|
||||
"net_cash_flow_from_financing_activities",
|
||||
"net_cash_flow_from_investing_activities",
|
||||
"net_cash_flow_from_operating_activities",
|
||||
"net_cash_flow_continuing",
|
||||
"net_cash_flow_from_financing_activities_continuing",
|
||||
"net_cash_flow_from_investing_activities_continuing",
|
||||
"net_cash_flow_from_operating_activities_continuing",
|
||||
"net_cash_flow",
|
||||
]
|
||||
|
||||
to_return = []
|
||||
for item in data:
|
||||
new = {"acceptance_datetime": item.get("acceptance_datetime")}
|
||||
new["start_date"] = item["start_date"]
|
||||
new["filing_date"] = item.get("filing_date")
|
||||
new["cik"] = item["cik"]
|
||||
new["fiscal_period"] = item["fiscal_period"]
|
||||
new["tickers"] = item["tickers"]
|
||||
cf = item["financials"]["cash_flow_statement"]
|
||||
new["net_cash_flow_from_financing_activities"] = cf[
|
||||
"net_cash_flow_from_financing_activities"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_investing_activities"] = cf[
|
||||
"net_cash_flow_from_investing_activities"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_operating_activities"] = cf[
|
||||
"net_cash_flow_from_operating_activities"
|
||||
].get("value")
|
||||
new["net_cash_flow_continuing"] = cf["net_cash_flow_continuing"].get(
|
||||
"value"
|
||||
)
|
||||
new["net_cash_flow_from_financing_activities_continuing"] = cf[
|
||||
"net_cash_flow_from_financing_activities_continuing"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_investing_activities_continuing"] = cf[
|
||||
"net_cash_flow_from_investing_activities_continuing"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_operating_activities_continuing"] = cf[
|
||||
"net_cash_flow_from_operating_activities_continuing"
|
||||
].get("value")
|
||||
new["net_cash_flow"] = cf["net_cash_flow"].get("value")
|
||||
new = {"start_date": item["start_date"], "cik": item["cik"]}
|
||||
if cf := item["financials"]["cash_flow_statement"]:
|
||||
for field in FIELDS:
|
||||
new[field] = cf[field].get("value", 0)
|
||||
|
||||
to_return.append(PolygonCashFlowStatementData(**new))
|
||||
return to_return
|
||||
@@ -112,5 +86,4 @@ class PolygonCashFlowStatementFetcher(
|
||||
def transform_data(
|
||||
data: List[PolygonCashFlowStatementData],
|
||||
) -> List[CashFlowStatementData]:
|
||||
processors = {"tickers": lambda x: "" if not x else ",".join(x)}
|
||||
return data_transformer(data, CashFlowStatementData, processors)
|
||||
return data
|
||||
|
||||
@@ -2,47 +2,58 @@
|
||||
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.crypto_eod import CryptoEODData, CryptoEODQueryParams
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
from openbb_provider.utils.descriptions import QUERY_DESCRIPTIONS
|
||||
from pydantic import Field, PositiveInt, validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
|
||||
class PolygonCryptoEODQueryParams(BaseStockQueryParams):
|
||||
"""Polygon crypto end of day query.
|
||||
class PolygonCryptoEODQueryParams(CryptoEODQueryParams):
|
||||
"""Polygon crypto end of day Query.
|
||||
|
||||
Source: https://polygon.io/docs/crypto/get_v2_aggs_ticker__cryptoticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
timespan: Literal[
|
||||
"minute", "hour", "day", "week", "month", "quarter", "year"
|
||||
] = Field(default="day", description="The timespan of the data.")
|
||||
sort: Literal["asc", "desc"] = Field(
|
||||
default="desc", description="Sort order of the data."
|
||||
)
|
||||
limit: PositiveInt = Field(
|
||||
default=49999, description=QUERY_DESCRIPTIONS.get("limit", "")
|
||||
)
|
||||
adjusted: bool = Field(default=True, description="Whether the data is adjusted.")
|
||||
multiplier: PositiveInt = Field(
|
||||
default=1, description="The multiplier of the timespan."
|
||||
)
|
||||
|
||||
class PolygonCryptoEODData(BaseStockData):
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: PositiveFloat
|
||||
|
||||
class PolygonCryptoEODData(CryptoEODData):
|
||||
"""Polygon crypto end of day Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"date": "t",
|
||||
"open": "o",
|
||||
"high": "h",
|
||||
"low": "l",
|
||||
"close": "c",
|
||||
"volume": "v",
|
||||
"vwap": "vw",
|
||||
}
|
||||
|
||||
n: PositiveInt = Field(
|
||||
description="The number of transactions for the symbol in the time period."
|
||||
)
|
||||
|
||||
@validator("t", pre=True, check_fields=False)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.fromtimestamp(v / 1000)
|
||||
|
||||
|
||||
class PolygonCryptoEODFetcher(
|
||||
@@ -54,44 +65,43 @@ class PolygonCryptoEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CryptoEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonCryptoEODQueryParams:
|
||||
now = datetime.now()
|
||||
start_date = query.start_date if query.start_date else now - timedelta(days=7)
|
||||
end_date = query.end_date if query.end_date else now
|
||||
return PolygonCryptoEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonCryptoEODQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=7)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
|
||||
return PolygonCryptoEODQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonCryptoEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: PolygonCryptoEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonCryptoEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"X:{query.stocksTicker.upper()}/range/1/{str(query.timespan.value)}/"
|
||||
f"X:{query.symbol}/range/1/{str(query.timespan)}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
data = get_data(request_url, **kwargs)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
if "results" not in data or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonCryptoEODData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonCryptoEODData]) -> List[CryptoEODData]:
|
||||
return data_transformer(data, CryptoEODData)
|
||||
def transform_data(data: List[PolygonCryptoEODData]) -> List[PolygonCryptoEODData]:
|
||||
return data
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
"""Polygon Crypto Price fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.crypto_price import CryptoPriceData, CryptoPriceQueryParams
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
|
||||
class PolygonCryptoPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon crypto price query.
|
||||
|
||||
Source: https://polygon.io/docs/crypto/get_v2_aggs_ticker__cryptoticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stocksTicker : str
|
||||
The ticker symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
|
||||
class PolygonCryptoPriceData(BaseStockData):
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: PositiveFloat
|
||||
|
||||
|
||||
class PolygonCryptoPriceFetcher(
|
||||
Fetcher[
|
||||
CryptoPriceQueryParams,
|
||||
CryptoPriceData,
|
||||
PolygonCryptoPriceQueryParams,
|
||||
PolygonCryptoPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CryptoPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonCryptoPriceQueryParams:
|
||||
return PolygonCryptoPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonCryptoPriceQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[PolygonCryptoPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"X:{query.stocksTicker.upper()}/range/1/{str(query.timespan.value)}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonCryptoPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonCryptoPriceData]) -> List[CryptoPriceData]:
|
||||
return data_transformer(data, CryptoPriceData)
|
||||
@@ -1,58 +1,59 @@
|
||||
"""Polygon forex end of day fetcher."""
|
||||
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Dict, List, Literal, Optional, Union
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import QueryParams
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.forex_eod import ForexEODData, ForexEODQueryParams
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
from openbb_provider.utils.descriptions import QUERY_DESCRIPTIONS
|
||||
from pydantic import Field, PositiveInt, validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, Timespan
|
||||
|
||||
|
||||
class PolygonForexEODQueryParams(QueryParams):
|
||||
"""Polygon forex end of day query.
|
||||
class PolygonForexEODQueryParams(ForexEODQueryParams):
|
||||
"""Polygon forex end of day Query.
|
||||
|
||||
Source: https://polygon.io/docs/forex/get_v2_aggs_ticker__forexticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stocksTicker : str
|
||||
The ticker symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime], optional
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime], optional
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
stocksTicker: str = Field(alias="symbol")
|
||||
start_date: Optional[Union[date, datetime]]
|
||||
end_date: Optional[Union[date, datetime]]
|
||||
timespan: Optional[Timespan] = Field(default=Timespan.day)
|
||||
sort: Optional[Literal["asc", "desc"]] = Field(default="desc")
|
||||
limit: Optional[PositiveInt] = Field(default=49999)
|
||||
adjusted: Optional[bool] = Field(default=True)
|
||||
multiplier: Optional[PositiveInt] = Field(default=1)
|
||||
timespan: Literal[
|
||||
"minute", "hour", "day", "week", "month", "quarter", "year"
|
||||
] = Field(default="day", description="The timespan of the data.")
|
||||
sort: Literal["asc", "desc"] = Field(
|
||||
default="desc", description="Sort order of the data."
|
||||
)
|
||||
limit: PositiveInt = Field(
|
||||
default=49999, description=QUERY_DESCRIPTIONS.get("limit", "")
|
||||
)
|
||||
adjusted: bool = Field(default=True, description="Whether the data is adjusted.")
|
||||
multiplier: PositiveInt = Field(
|
||||
default=1, description="The multiplier of the timespan."
|
||||
)
|
||||
|
||||
|
||||
class PolygonForexEODData(BaseStockData):
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: Optional[PositiveFloat]
|
||||
class PolygonForexEODData(ForexEODData):
|
||||
"""Polygon forex end of day Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"date": "t",
|
||||
"open": "o",
|
||||
"high": "h",
|
||||
"low": "l",
|
||||
"close": "c",
|
||||
"volume": "v",
|
||||
"vwap": "vw",
|
||||
}
|
||||
|
||||
n: PositiveInt = Field(
|
||||
description="The number of transactions for the symbol in the time period."
|
||||
)
|
||||
|
||||
@validator("t", pre=True, check_fields=False)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.fromtimestamp(v / 1000)
|
||||
|
||||
|
||||
class PolygonForexEODFetcher(
|
||||
@@ -64,42 +65,42 @@ class PolygonForexEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ForexEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonForexEODQueryParams:
|
||||
return PolygonForexEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
**extra_params or {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonForexEODQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=7)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
return PolygonForexEODQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonForexEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: PolygonForexEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonForexEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
now = datetime.now()
|
||||
start_date = query.start_date or (now - timedelta(days=5)).date()
|
||||
end_date = query.end_date or now.date()
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"C:{query.stocksTicker.upper()}/range/1/{query.timespan._value_}/"
|
||||
f"{start_date}/{end_date}?adjusted={query.adjusted}"
|
||||
f"C:{query.symbol}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
data = get_data(request_url, **kwargs)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
if "results" not in data or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonForexEODData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonForexEODData]) -> List[ForexEODData]:
|
||||
return data_transformer(data, ForexEODData)
|
||||
def transform_data(data: List[PolygonForexEODData]) -> List[PolygonForexEODData]:
|
||||
return data
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
"""Polygon available pairs fetcher."""
|
||||
|
||||
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.models.forex_pairs import ForexPairsData, ForexPairsQueryParams
|
||||
from openbb_provider.utils.descriptions import QUERY_DESCRIPTIONS
|
||||
from pydantic import Field, PositiveInt, validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
|
||||
|
||||
class PolygonForexPairsQueryParams(ForexPairsQueryParams):
|
||||
"""Polygon available pairs Query.
|
||||
|
||||
Source: https://polygon.io/docs/forex/get_v3_reference_tickers
|
||||
"""
|
||||
|
||||
symbol: Optional[str] = Field(description="Symbol of the pair to search.")
|
||||
date: Optional[dateType] = Field(
|
||||
default=datetime.now().date(), description=QUERY_DESCRIPTIONS.get("date", "")
|
||||
)
|
||||
search: Optional[str] = Field(
|
||||
default="",
|
||||
description="Search for terms within the ticker and/or company name.",
|
||||
)
|
||||
active: Optional[Literal[True, False]] = Field(
|
||||
default=True,
|
||||
description="Specify if the tickers returned should be actively traded on the queried date.",
|
||||
)
|
||||
order: Optional[Literal["asc", "desc"]] = Field(
|
||||
default="asc", description="Order data by ascending or descending."
|
||||
)
|
||||
sort: Optional[
|
||||
Literal[
|
||||
"ticker",
|
||||
"name",
|
||||
"market",
|
||||
"locale",
|
||||
"currency_symbol",
|
||||
"currency_name",
|
||||
"base_currency_symbol",
|
||||
"base_currency_name",
|
||||
"last_updated_utc",
|
||||
"delisted_utc",
|
||||
]
|
||||
] = Field(default="", description="Sort field used for ordering.")
|
||||
limit: Optional[PositiveInt] = Field(
|
||||
default=1000, description=QUERY_DESCRIPTIONS.get("limit", "")
|
||||
)
|
||||
|
||||
|
||||
class PolygonForexPairsData(ForexPairsData):
|
||||
"""Polygon available pairs Data."""
|
||||
|
||||
market: str = Field(description="The name of the trading market. Always 'fx'.")
|
||||
locale: str = Field(description="The locale of the currency pair.")
|
||||
currency_symbol: str = Field(description="The symbol of the quote currency.")
|
||||
currency_name: str = Field(description="The name of the quote currency.")
|
||||
base_currency_symbol: str = Field(description="The symbol of the base currency.")
|
||||
base_currency_name: str = Field(description="The name of the base currency.")
|
||||
last_updated_utc: datetime = Field(description="The last updated timestamp in UTC.")
|
||||
delisted_utc: Optional[datetime] = Field(
|
||||
description="The delisted timestamp in UTC."
|
||||
)
|
||||
|
||||
@validator("last_updated_utc", pre=True, check_fields=False)
|
||||
def last_updated_utc_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
@validator("delisted_utc", pre=True, check_fields=False)
|
||||
def delisted_utc_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
class PolygonForexPairsFetcher(
|
||||
Fetcher[
|
||||
ForexPairsQueryParams,
|
||||
ForexPairsData,
|
||||
PolygonForexPairsQueryParams,
|
||||
PolygonForexPairsData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonForexPairsQueryParams:
|
||||
return PolygonForexPairsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonForexPairsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonForexPairsData]:
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
tickers = f"ticker=C:{query.symbol}" if query.symbol else ""
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v3/reference/"
|
||||
f"tickers?{tickers}&market=fx&date={query.date}&"
|
||||
f"search={query.search}&active={query.active}&order={query.order}&"
|
||||
f"limit={query.limit}&sort={query.sort}&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = {"next_url": request_url}
|
||||
all_data: List[Dict] = []
|
||||
|
||||
while "next_url" in data:
|
||||
data = get_data(request_url, **kwargs)
|
||||
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if len(data["results"]) == 0:
|
||||
raise RuntimeError(
|
||||
"No results found. Please change your query parameters."
|
||||
)
|
||||
|
||||
if data["status"] == "OK":
|
||||
all_data.extend(data["results"])
|
||||
elif data["status"] == "ERROR":
|
||||
raise UserWarning(data["error"])
|
||||
|
||||
if "next_url" in data:
|
||||
request_url = f"{data['next_url']}&apiKey={api_key}"
|
||||
|
||||
return all_data
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonForexPairsData],
|
||||
) -> List[PolygonForexPairsData]:
|
||||
return data
|
||||
@@ -1,94 +0,0 @@
|
||||
"""Polygon Forex Price fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.forex_price import ForexPriceData, ForexPriceQueryParams
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
|
||||
class PolygonForexPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon forex price query.
|
||||
|
||||
Source: https://polygon.io/docs/forex/get_v2_aggs_ticker__forexticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stocksTicker : str
|
||||
The ticker symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
|
||||
class PolygonForexPriceData(BaseStockData):
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: Optional[PositiveFloat]
|
||||
|
||||
|
||||
class PolygonForexPriceFetcher(
|
||||
Fetcher[
|
||||
ForexPriceQueryParams,
|
||||
ForexPriceData,
|
||||
PolygonForexPriceQueryParams,
|
||||
PolygonForexPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ForexPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonForexPriceQueryParams:
|
||||
return PolygonForexPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonForexPriceQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[PolygonForexPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"C:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonForexPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonForexPriceData]) -> List[ForexPriceData]:
|
||||
return data_transformer(data, ForexPriceData)
|
||||
@@ -1,56 +1,63 @@
|
||||
from datetime import (
|
||||
date as dateType,
|
||||
datetime,
|
||||
)
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.income_statement import (
|
||||
IncomeStatementData,
|
||||
IncomeStatementQueryParams,
|
||||
)
|
||||
from pydantic import Field
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from pydantic import validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import PolygonFundamentalQueryParams
|
||||
|
||||
|
||||
class PolygonIncomeStatementQueryParams(PolygonFundamentalQueryParams):
|
||||
__doc__ = PolygonFundamentalQueryParams.__doc__
|
||||
"""Polygon Income Statement Query Parameters"""
|
||||
|
||||
|
||||
class PolygonIncomeStatementData(Data):
|
||||
start_date: dateType = Field(alias="date")
|
||||
tickers: Optional[List[str]]
|
||||
class PolygonIncomeStatementData(IncomeStatementData):
|
||||
class Config:
|
||||
fields = {
|
||||
"date": "start_date",
|
||||
"accepted_date": "acceptance_datetime",
|
||||
"period": "fiscal_period",
|
||||
"revenue": "revenues",
|
||||
"operating_income": "operating_income_loss",
|
||||
"income_before_tax": "income_loss_from_continuing_operations_before_tax",
|
||||
"income_tax_expense": "income_tax_expense_benefit",
|
||||
"net_income": "net_income_loss",
|
||||
"eps": "basic_earnings_per_share",
|
||||
"eps_diluted": "diluted_earnings_per_share",
|
||||
"interest_expense": "interest_expense_operating",
|
||||
"symbol": "tickers",
|
||||
}
|
||||
|
||||
# tickers: Optional[List[str]]
|
||||
cik: Optional[str]
|
||||
filing_date: Optional[dateType]
|
||||
acceptance_datetime: Optional[datetime] = Field(alias="accepted_date")
|
||||
fiscal_period: Optional[str] = Field(alias="period")
|
||||
revenues: Optional[float] = Field(alias="revenue")
|
||||
cost_of_revenue: Optional[float]
|
||||
gross_profit: Optional[float]
|
||||
operating_expenses: Optional[float]
|
||||
income_loss_from_continuing_operations_before_tax: Optional[float] = Field(
|
||||
alias="income_before_tax"
|
||||
)
|
||||
income_loss_from_continuing_operations_after_tax: Optional[float]
|
||||
income_tax_expense_benefit: Optional[float] = Field(alias="income_tax_expense")
|
||||
net_income_loss: Optional[float] = Field(alias="net_income")
|
||||
basic_earnings_per_share: Optional[float] = Field(alias="eps")
|
||||
diluted_earnings_per_share: Optional[float] = Field(alias="eps_diluted")
|
||||
benefits_costs_expenses: Optional[float]
|
||||
interest_expense_operating: Optional[float] = Field(alias="interest_expense")
|
||||
net_income_loss_attributable_to_noncontrolling_interest: Optional[int]
|
||||
net_income_loss_attributable_to_parent: Optional[float]
|
||||
net_income_loss_available_to_common_stockholders_basic: Optional[float]
|
||||
operating_income_loss: Optional[float]
|
||||
participating_securities_distributed_and_undistributed_earnings_loss_basic: Optional[
|
||||
float
|
||||
]
|
||||
preferred_stock_dividends_and_other_adjustments: Optional[float]
|
||||
|
||||
@validator("symbol", pre=True, check_fields=False)
|
||||
def symbol_from_tickers(cls, v):
|
||||
if isinstance(v, list):
|
||||
return ",".join(v)
|
||||
return v
|
||||
|
||||
|
||||
class PolygonIncomeStatementFetcher(
|
||||
Fetcher[
|
||||
@@ -61,29 +68,47 @@ class PolygonIncomeStatementFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: IncomeStatementQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonIncomeStatementQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarterly"
|
||||
return PolygonIncomeStatementQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonIncomeStatementQueryParams:
|
||||
return PolygonIncomeStatementQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonIncomeStatementQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: PolygonIncomeStatementQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonIncomeStatementData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
query.period = "annual" if query.period == "annually" else "quarter"
|
||||
|
||||
base_url = "https://api.polygon.io/vX/reference/financials"
|
||||
query_string = get_querystring(query.dict(), [])
|
||||
query_string = get_querystring(query.dict(by_alias=True), [])
|
||||
request_url = f"{base_url}?{query_string}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
data = get_data(request_url, **kwargs)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No Income Statement found")
|
||||
|
||||
FIELDS = [
|
||||
"revenues",
|
||||
"cost_of_revenue",
|
||||
"gross_profit",
|
||||
"operating_expenses" "income_loss_from_continuing_operations_before_tax",
|
||||
"income_tax_expense_benefit",
|
||||
"net_income_loss",
|
||||
"basic_earnings_per_share",
|
||||
"diluted_earnings_per_share",
|
||||
"net_income_loss_attributable_to_noncontrolling_interest",
|
||||
"net_income_loss_attributable_to_parent",
|
||||
"net_income_loss_available_to_common_stockholders_basic",
|
||||
"operating_income_loss",
|
||||
"participating_securities_distributed_and_undistributed_earnings_loss_basic",
|
||||
"preferred_stock_dividends_and_other_adjustments",
|
||||
"income_loss_from_continuing_operations_after_tax",
|
||||
"benefits_costs_expenses",
|
||||
"interest_expense_operating",
|
||||
]
|
||||
|
||||
to_return = []
|
||||
for item in data:
|
||||
new = {"acceptance_datetime": item.get("acceptance_datetime")}
|
||||
@@ -92,53 +117,12 @@ class PolygonIncomeStatementFetcher(
|
||||
new["fiscal_period"] = item["fiscal_period"]
|
||||
new["tickers"] = item["tickers"]
|
||||
new["cik"] = item["cik"]
|
||||
incs = item["financials"]["income_statement"]
|
||||
new["revenues"] = incs["revenues"].get("value")
|
||||
new["cost_of_revenue"] = incs.get("cost_of_revenue", {}).get("value", 0)
|
||||
new["gross_profit"] = incs.get("gross_profit", {}).get("value", 0)
|
||||
new["operating_expenses"] = incs["operating_expenses"].get("value")
|
||||
new["income_loss_from_continuing_operations_before_tax"] = incs[
|
||||
"income_loss_from_continuing_operations_before_tax"
|
||||
].get("value")
|
||||
new["income_tax_expense_benefit"] = incs["income_tax_expense_benefit"].get(
|
||||
"value"
|
||||
)
|
||||
new["net_income_loss"] = incs["net_income_loss"].get("value")
|
||||
new["basic_earnings_per_share"] = incs.get(
|
||||
"basic_earnings_per_share", {}
|
||||
).get("value")
|
||||
new["diluted_earnings_per_share"] = incs.get(
|
||||
"diluted_earnings_per_share", {}
|
||||
).get("value")
|
||||
new["net_income_loss_attributable_to_noncontrolling_interest"] = incs[
|
||||
"net_income_loss_attributable_to_noncontrolling_interest"
|
||||
].get("value")
|
||||
new["net_income_loss_attributable_to_parent"] = incs[
|
||||
"net_income_loss_attributable_to_parent"
|
||||
].get("value")
|
||||
new["net_income_loss_available_to_common_stockholders_basic"] = incs[
|
||||
"net_income_loss_available_to_common_stockholders_basic"
|
||||
].get("value")
|
||||
new["operating_income_loss"] = incs["operating_income_loss"].get("value")
|
||||
new[
|
||||
"participating_securities_distributed_and_undistributed_earnings_loss_basic"
|
||||
] = incs[
|
||||
"participating_securities_distributed_and_undistributed_earnings_loss_basic"
|
||||
].get(
|
||||
"value"
|
||||
)
|
||||
new["preferred_stock_dividends_and_other_adjustments"] = incs[
|
||||
"preferred_stock_dividends_and_other_adjustments"
|
||||
].get("value")
|
||||
new["income_loss_from_continuing_operations_after_tax"] = incs[
|
||||
"income_loss_from_continuing_operations_after_tax"
|
||||
].get("value")
|
||||
new["benefits_costs_expenses"] = incs["benefits_costs_expenses"].get(
|
||||
"value"
|
||||
)
|
||||
new["interest_expense_operating"] = incs.get(
|
||||
"interest_expense_operating", {}
|
||||
).get("value", 0)
|
||||
incs = item["financials"].get("income_statement", {})
|
||||
|
||||
if incs:
|
||||
for field in FIELDS:
|
||||
new[field] = incs.get(field, {}).get("value", 0)
|
||||
|
||||
to_return.append(PolygonIncomeStatementData(**new))
|
||||
return to_return
|
||||
|
||||
@@ -146,5 +130,4 @@ class PolygonIncomeStatementFetcher(
|
||||
def transform_data(
|
||||
data: List[PolygonIncomeStatementData],
|
||||
) -> List[IncomeStatementData]:
|
||||
processors = {"tickers": lambda x: "" if not x else ",".join(x)}
|
||||
return data_transformer(data, IncomeStatementData, processors)
|
||||
return data
|
||||
|
||||
@@ -1,48 +1,64 @@
|
||||
"""Polygon major indices end of day fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.major_indices_eod import (
|
||||
MajorIndicesEODData,
|
||||
MajorIndicesEODQueryParams,
|
||||
)
|
||||
from openbb_provider.utils.descriptions import QUERY_DESCRIPTIONS
|
||||
from pydantic import Field, PositiveFloat, PositiveInt, validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
|
||||
class PolygonMajorIndicesEODQueryParams(BaseStockQueryParams):
|
||||
"""Polygon major indices end of day query.
|
||||
class PolygonMajorIndicesEODQueryParams(MajorIndicesEODQueryParams):
|
||||
"""Polygon major indices end of day Query.
|
||||
|
||||
Source: https://polygon.io/docs/indices/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
timespan: Literal[
|
||||
"minute", "hour", "day", "week", "month", "quarter", "year"
|
||||
] = Field(default="day", description="The timespan of the data.")
|
||||
sort: Literal["asc", "desc"] = Field(
|
||||
default="desc", description="Sort order of the data."
|
||||
)
|
||||
limit: PositiveInt = Field(
|
||||
default=49999, description=QUERY_DESCRIPTIONS.get("limit", "")
|
||||
)
|
||||
adjusted: bool = Field(default=True, description="Whether the data is adjusted.")
|
||||
multiplier: PositiveInt = Field(
|
||||
default=1, description="The multiplier of the timespan."
|
||||
)
|
||||
|
||||
class PolygonMajorIndicesEODData(BaseStockData):
|
||||
"""Polygon major indices end of day data."""
|
||||
|
||||
class PolygonMajorIndicesEODData(MajorIndicesEODData):
|
||||
"""Polygon major indices end of day Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"open": "o",
|
||||
"high": "h",
|
||||
"low": "l",
|
||||
"close": "c",
|
||||
"volume": "v",
|
||||
}
|
||||
|
||||
t: datetime = Field(description="The timestamp of the data.")
|
||||
n: PositiveInt = Field(
|
||||
description="The number of transactions for the symbol in the time period."
|
||||
)
|
||||
vw: PositiveFloat = Field(
|
||||
description="The volume weighted average price of the symbol."
|
||||
)
|
||||
|
||||
@validator("t", pre=True, check_fields=False)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.fromtimestamp(v / 1000)
|
||||
|
||||
|
||||
class PolygonMajorIndicesEODFetcher(
|
||||
@@ -54,36 +70,37 @@ class PolygonMajorIndicesEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: MajorIndicesEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonMajorIndicesEODQueryParams:
|
||||
return PolygonMajorIndicesEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonMajorIndicesEODQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=7)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
return PolygonMajorIndicesEODQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonMajorIndicesEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: PolygonMajorIndicesEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonMajorIndicesEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"I:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"I:{query.symbol}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
data = get_data(request_url, **kwargs)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
if "results" not in data or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
@@ -92,5 +109,5 @@ class PolygonMajorIndicesEODFetcher(
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonMajorIndicesEODData],
|
||||
) -> List[MajorIndicesEODData]:
|
||||
return data_transformer(data, MajorIndicesEODData)
|
||||
) -> List[PolygonMajorIndicesEODData]:
|
||||
return data
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
"""Polygon major indices price fetcher."""
|
||||
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.major_indices_price import (
|
||||
MajorIndicesPriceData,
|
||||
MajorIndicesPriceQueryParams,
|
||||
)
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
|
||||
class PolygonMajorIndicesPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon major indices price query.
|
||||
|
||||
Source: https://polygon.io/docs/indices/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the index.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
|
||||
class PolygonMajorIndicesPriceData(BaseStockData):
|
||||
"""Polygon major indices price data."""
|
||||
|
||||
|
||||
class PolygonMajorIndicesPriceFetcher(
|
||||
Fetcher[
|
||||
MajorIndicesPriceQueryParams,
|
||||
MajorIndicesPriceData,
|
||||
PolygonMajorIndicesPriceQueryParams,
|
||||
PolygonMajorIndicesPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: MajorIndicesPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonMajorIndicesPriceQueryParams:
|
||||
return PolygonMajorIndicesPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
**extra_params or {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonMajorIndicesPriceQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
) -> List[PolygonMajorIndicesPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"I:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonMajorIndicesPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonMajorIndicesPriceData],
|
||||
) -> List[MajorIndicesPriceData]:
|
||||
return data_transformer(data, MajorIndicesPriceData)
|
||||
@@ -2,47 +2,58 @@
|
||||
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_eod import StockEODData, StockEODQueryParams
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
from openbb_provider.utils.descriptions import QUERY_DESCRIPTIONS
|
||||
from pydantic import Field, PositiveInt, validator
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
|
||||
class PolygonStockEODQueryParams(BaseStockQueryParams):
|
||||
"""Polygon stocks end of day query.
|
||||
class PolygonStockEODQueryParams(StockEODQueryParams):
|
||||
"""Polygon stocks end of day Query.
|
||||
|
||||
Source: https://polygon.io/docs/stocks/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
timespan: Literal[
|
||||
"minute", "hour", "day", "week", "month", "quarter", "year"
|
||||
] = Field(default="day", description="The timespan of the data.")
|
||||
sort: Literal["asc", "desc"] = Field(
|
||||
default="desc", description="Sort order of the data."
|
||||
)
|
||||
limit: PositiveInt = Field(
|
||||
default=49999, description=QUERY_DESCRIPTIONS.get("limit", "")
|
||||
)
|
||||
adjusted: bool = Field(default=True, description="Whether the data is adjusted.")
|
||||
multiplier: PositiveInt = Field(
|
||||
default=1, description="The multiplier of the timespan."
|
||||
)
|
||||
|
||||
class PolygonStockEODData(BaseStockData):
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: Optional[PositiveFloat]
|
||||
|
||||
class PolygonStockEODData(StockEODData):
|
||||
"""Polygon stocks end of day Data."""
|
||||
|
||||
class Config:
|
||||
fields = {
|
||||
"date": "t",
|
||||
"open": "o",
|
||||
"high": "h",
|
||||
"low": "l",
|
||||
"close": "c",
|
||||
"volume": "v",
|
||||
"vwap": "vw",
|
||||
}
|
||||
|
||||
n: PositiveInt = Field(
|
||||
description="The number of transactions for the symbol in the time period."
|
||||
)
|
||||
|
||||
@validator("t", pre=True, check_fields=False)
|
||||
def t_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.fromtimestamp(v / 1000)
|
||||
|
||||
|
||||
class PolygonStockEODFetcher(
|
||||
@@ -54,44 +65,42 @@ class PolygonStockEODFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonStockEODQueryParams:
|
||||
now = datetime.now()
|
||||
start_date = query.start_date or (now - timedelta(days=5)).date()
|
||||
end_date = query.end_date or now.date()
|
||||
return PolygonStockEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
**extra_params or {},
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonStockEODQueryParams:
|
||||
now = datetime.now().date()
|
||||
transformed_params = params
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - timedelta(days=7)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
return PolygonStockEODQueryParams(**transformed_params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonStockEODQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: PolygonStockEODQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonStockEODData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"{query.stocksTicker.upper()}/range/1/{str(query.timespan.value)}/"
|
||||
f"{query.symbol}/range/1/{str(query.timespan)}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
data = get_data(request_url, **kwargs)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
if "results" not in data or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonStockEODData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonStockEODData]) -> List[StockEODData]:
|
||||
return data_transformer(data, StockEODData)
|
||||
def transform_data(data: List[PolygonStockEODData]) -> List[PolygonStockEODData]:
|
||||
return data
|
||||
|
||||
@@ -2,26 +2,22 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer, get_querystring
|
||||
from openbb_provider.models.stock_news import StockNewsData, StockNewsQueryParams
|
||||
from openbb_provider.utils.helpers import data_transformer, get_querystring
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
|
||||
|
||||
class PolygonStockNewsQueryParams(QueryParams):
|
||||
class PolygonStockNewsQueryParams(StockNewsQueryParams):
|
||||
"""Polygon stock news query.
|
||||
|
||||
Source: https://polygon.io/docs/stocks/get_v2_reference_news
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
ticker_lt : str, optional
|
||||
Less than, by default None
|
||||
ticker_lte : str, optional
|
||||
@@ -42,13 +38,13 @@ class PolygonStockNewsQueryParams(QueryParams):
|
||||
Greater than or equal, by default None
|
||||
order : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default None
|
||||
limit : int, optional
|
||||
The limit of the query, by default 100
|
||||
sort : str, optional
|
||||
The sort of the query, by default None
|
||||
"""
|
||||
|
||||
ticker: str = Field(alias="symbols")
|
||||
class Config:
|
||||
fields = {"symbols": "ticker"}
|
||||
|
||||
ticker_lt: Optional[str] = Field(alias="ticker.lt", default=None)
|
||||
ticker_lte: Optional[str] = Field(alias="ticker.lte", default=None)
|
||||
ticker_gt: Optional[str] = Field(alias="ticker.gt", default=None)
|
||||
@@ -59,7 +55,6 @@ class PolygonStockNewsQueryParams(QueryParams):
|
||||
published_utc_gt: Optional[str] = Field(alias="published_utc.gt", default=None)
|
||||
published_utc_gte: Optional[str] = Field(alias="published_utc.gte", default=None)
|
||||
order: Optional[Literal["asc", "desc"]] = None
|
||||
limit: Optional[int] = Field(default=100)
|
||||
sort: Optional[str] = None
|
||||
|
||||
|
||||
@@ -95,24 +90,21 @@ class PolygonStockNewsFetcher(
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockNewsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonStockNewsQueryParams:
|
||||
return PolygonStockNewsQueryParams(
|
||||
symbols=query.symbols, **extra_params if extra_params else {}
|
||||
)
|
||||
def transform_query(params: Dict[str, Any]) -> PolygonStockNewsQueryParams:
|
||||
return PolygonStockNewsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonStockNewsQueryParams, credentials: Optional[Dict[str, str]]
|
||||
query: PolygonStockNewsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[PolygonStockNewsData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
api_key = credentials.get("polygon_api_key") if credentials else ""
|
||||
|
||||
base_url = "https://api.polygon.io/v2/reference/news"
|
||||
querystring = get_querystring(query.dict(), [])
|
||||
querystring = get_querystring(query.dict(by_alias=True), [])
|
||||
request_url = f"{base_url}?{querystring}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
data = get_data(request_url, **kwargs)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No news found")
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
"""Polygon stocks price fetcher."""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.helpers import data_transformer
|
||||
from openbb_provider.models.stock_price import StockPriceData, StockPriceQueryParams
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from openbb_polygon.utils.helpers import get_data
|
||||
from openbb_polygon.utils.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
|
||||
class PolygonStockPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon stocks price query.
|
||||
|
||||
Source: https://polygon.io/docs/stocks/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
|
||||
class PolygonStockPriceData(BaseStockData):
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: PositiveFloat
|
||||
|
||||
|
||||
class PolygonStockPriceFetcher(
|
||||
Fetcher[
|
||||
StockPriceQueryParams,
|
||||
StockPriceData,
|
||||
PolygonStockPriceQueryParams,
|
||||
PolygonStockPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonStockPriceQueryParams:
|
||||
return PolygonStockPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonStockPriceQueryParams, credentials: Optional[Dict[str, str]]
|
||||
) -> List[PolygonStockPriceData]:
|
||||
if credentials:
|
||||
api_key = credentials.get("polygon_api_key")
|
||||
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonStockPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonStockPriceData]) -> List[StockPriceData]:
|
||||
return data_transformer(data, StockPriceData)
|
||||
@@ -1,38 +0,0 @@
|
||||
"""Polygon provider module."""
|
||||
|
||||
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
|
||||
from openbb_polygon.models.balance_sheet import PolygonBalanceSheetFetcher
|
||||
from openbb_polygon.models.cash_flow import PolygonCashFlowStatementFetcher
|
||||
from openbb_polygon.models.crypto_eod import PolygonCryptoEODFetcher
|
||||
from openbb_polygon.models.crypto_price import PolygonCryptoPriceFetcher
|
||||
from openbb_polygon.models.forex_eod import PolygonForexEODFetcher
|
||||
from openbb_polygon.models.forex_price import PolygonForexPriceFetcher
|
||||
from openbb_polygon.models.income_statement import PolygonIncomeStatementFetcher
|
||||
from openbb_polygon.models.major_indices_eod import PolygonMajorIndicesEODFetcher
|
||||
from openbb_polygon.models.major_indices_price import PolygonMajorIndicesPriceFetcher
|
||||
from openbb_polygon.models.stock_eod import PolygonStockEODFetcher
|
||||
from openbb_polygon.models.stock_news import PolygonStockNewsFetcher
|
||||
from openbb_polygon.models.stock_price import PolygonStockPriceFetcher
|
||||
|
||||
# mypy: disable-error-code="list-item"
|
||||
polygon_provider = Provider(
|
||||
name="polygon",
|
||||
description="Provider for Polygon.",
|
||||
required_credentials=["api_key"],
|
||||
fetcher_list=[
|
||||
PolygonStockEODFetcher,
|
||||
PolygonStockNewsFetcher,
|
||||
PolygonBalanceSheetFetcher,
|
||||
PolygonIncomeStatementFetcher,
|
||||
PolygonCashFlowStatementFetcher,
|
||||
PolygonStockPriceFetcher,
|
||||
PolygonCryptoPriceFetcher,
|
||||
PolygonCryptoEODFetcher,
|
||||
PolygonMajorIndicesEODFetcher,
|
||||
PolygonMajorIndicesPriceFetcher,
|
||||
PolygonForexEODFetcher,
|
||||
PolygonForexPriceFetcher,
|
||||
],
|
||||
)
|
||||
@@ -1,9 +1,9 @@
|
||||
# IMPORT THIRD PARTY
|
||||
import requests
|
||||
from openbb_provider import helpers
|
||||
|
||||
|
||||
def get_data(url: str) -> dict:
|
||||
r = requests.get(url, timeout=10)
|
||||
def get_data(url: str, **kwargs) -> dict:
|
||||
r = helpers.make_request(url, **kwargs)
|
||||
if r.status_code != 200:
|
||||
data = r.json()
|
||||
message = data.get("message")
|
||||
|
||||
@@ -1,117 +1,68 @@
|
||||
"""Polygon types helpers."""
|
||||
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
from enum import Enum
|
||||
from typing import Literal, Optional, Union
|
||||
from datetime import date
|
||||
from typing import Literal, Optional
|
||||
|
||||
from openbb_provider.abstract.data import Data, QueryParams
|
||||
from pydantic import Field, PositiveFloat, PositiveInt, validator
|
||||
from openbb_provider.models.income_statement import IncomeStatementQueryParams
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class Timespan(str, Enum):
|
||||
minute = "minute"
|
||||
hour = "hour"
|
||||
day = "day"
|
||||
week = "week"
|
||||
month = "month"
|
||||
quarter = "quarter"
|
||||
year = "year"
|
||||
|
||||
|
||||
class PolygonFundamentalQueryParams(QueryParams):
|
||||
class PolygonFundamentalQueryParams(IncomeStatementQueryParams):
|
||||
"""Polygon Fundamental QueryParams.
|
||||
|
||||
Source: https://polygon.io/docs/stocks#!/get_vx_reference_financials
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : Optional[str]
|
||||
The symbol of the company if no CIK is provided.
|
||||
cik : Optional[str]
|
||||
The CIK of the company if no symbol is provided.
|
||||
company_name : Optional[str]
|
||||
The name of the company.
|
||||
company_name_search : Optional[str]
|
||||
The name of the company to search.
|
||||
sic : Optional[str]
|
||||
The Standard Industrial Classification (SIC) of the company.
|
||||
filing_date : Optional[date]
|
||||
The filing date of the financial statement.
|
||||
filing_date_lt : Optional[date]
|
||||
The filing date less than the given date.
|
||||
filing_date_lte : Optional[date]
|
||||
The filing date less than or equal to the given date.
|
||||
filing_date_gt : Optional[date]
|
||||
The filing date greater than the given date.
|
||||
filing_date_gte : Optional[date]
|
||||
The filing date greater than or equal to the given date.
|
||||
period_of_report_date : Optional[date]
|
||||
The period of report date of the financial statement.
|
||||
period_of_report_date_lt : Optional[date]
|
||||
The period of report date less than the given date.
|
||||
period_of_report_date_lte : Optional[date]
|
||||
The period of report date less than or equal to the given date.
|
||||
period_of_report_date_gt : Optional[date]
|
||||
The period of report date greater than the given date.
|
||||
period_of_report_date_gte : Optional[date]
|
||||
The period of report date greater than or equal to the given date.
|
||||
timeframe : Optional[Literal["annual", "quarterly", "ttm"]]
|
||||
The timeframe of the financial statement.
|
||||
include_sources : Optional[bool]
|
||||
Whether to include the sources of the financial statement.
|
||||
order : Optional[Literal["asc", "desc"]]
|
||||
The order of the financial statement.
|
||||
limit : Optional[PositiveInt]
|
||||
The limit of the financial statement.
|
||||
sort : Optional[Literal["filing_date", "period_of_report_date"]]
|
||||
The sort of the financial statement.
|
||||
"""
|
||||
|
||||
ticker: Optional[str] = Field(alias="symbol")
|
||||
cik: Optional[str]
|
||||
company_name: Optional[str]
|
||||
company_name_search: Optional[str] = Field(alias="company_name.search")
|
||||
sic: Optional[str]
|
||||
filing_date: Optional[date]
|
||||
filing_date_lt: Optional[date] = Field(alias="filing_date.lt")
|
||||
filing_date_lte: Optional[date] = Field(alias="filing_date.lte")
|
||||
filing_date_gt: Optional[date] = Field(alias="filing_date.gt")
|
||||
filing_date_gte: Optional[date] = Field(alias="filing_date.gte")
|
||||
period_of_report_date: Optional[date]
|
||||
period_of_report_date_lt: Optional[date] = Field(alias="period_of_report_date.lt")
|
||||
period_of_report_date_lte: Optional[date] = Field(alias="period_of_report_date.lte")
|
||||
period_of_report_date_gt: Optional[date] = Field(alias="period_of_report_date.gt")
|
||||
period_of_report_date_gte: Optional[date] = Field(alias="period_of_report_date.gte")
|
||||
timeframe: Optional[Literal["annual", "quarterly", "ttm"]] = Field(alias="period")
|
||||
include_sources: Optional[bool]
|
||||
order: Optional[Literal["asc", "desc"]]
|
||||
limit: Optional[PositiveInt] = 100
|
||||
sort: Optional[Literal["filing_date", "period_of_report_date"]]
|
||||
class Config:
|
||||
fields = {
|
||||
"symbol": "ticker",
|
||||
"period": "timeframe",
|
||||
}
|
||||
|
||||
|
||||
class BaseStockQueryParams(QueryParams):
|
||||
stocksTicker: str = Field(alias="symbol")
|
||||
start_date: Union[date, datetime] = Field(
|
||||
default=datetime.now().date() - timedelta(days=8)
|
||||
company_name: Optional[str] = Field(description="The name of the company.")
|
||||
company_name_search: Optional[str] = Field(
|
||||
description="The name of the company to search."
|
||||
)
|
||||
end_date: Union[date, datetime] = Field(
|
||||
default=datetime.now().date() - timedelta(days=1)
|
||||
sic: Optional[str] = Field(
|
||||
description="The Standard Industrial Classification (SIC) of the company."
|
||||
)
|
||||
filing_date: Optional[date] = Field(
|
||||
description="The filing date of the financial statement."
|
||||
)
|
||||
filing_date_lt: Optional[date] = Field(
|
||||
description="The filing date less than the given date."
|
||||
)
|
||||
filing_date_lte: Optional[date] = Field(
|
||||
description="The filing date less than or equal to the given date.",
|
||||
)
|
||||
filing_date_gt: Optional[date] = Field(
|
||||
description="The filing date greater than the given date.",
|
||||
)
|
||||
filing_date_gte: Optional[date] = Field(
|
||||
description="The filing date greater than or equal to the given date.",
|
||||
)
|
||||
period_of_report_date: Optional[date] = Field(
|
||||
description="The period of report date of the financial statement."
|
||||
)
|
||||
period_of_report_date_lt: Optional[date] = Field(
|
||||
description="The period of report date less than the given date.",
|
||||
)
|
||||
period_of_report_date_lte: Optional[date] = Field(
|
||||
description="The period of report date less than or equal to the given date.",
|
||||
)
|
||||
period_of_report_date_gt: Optional[date] = Field(
|
||||
description="The period of report date greater than the given date.",
|
||||
)
|
||||
period_of_report_date_gte: Optional[date] = Field(
|
||||
description="The period of report date greater than or equal to the given date.",
|
||||
)
|
||||
include_sources: Optional[bool] = Field(
|
||||
description="Whether to include the sources of the financial statement."
|
||||
)
|
||||
order: Optional[Literal["asc", "desc"]] = Field(
|
||||
description="The order of the financial statement."
|
||||
)
|
||||
sort: Optional[Literal["filing_date", "period_of_report_date"]] = Field(
|
||||
description="The sort of the financial statement."
|
||||
)
|
||||
timespan: Timespan = Field(default=Timespan.day)
|
||||
sort: Literal["asc", "desc"] = Field(default="desc")
|
||||
limit: PositiveInt = Field(default=49999)
|
||||
adjusted: bool = Field(default=True)
|
||||
multiplier: PositiveInt = Field(default=1)
|
||||
|
||||
|
||||
class BaseStockData(Data):
|
||||
c: PositiveFloat = Field(alias="close")
|
||||
o: PositiveFloat = Field(alias="open")
|
||||
h: PositiveFloat = Field(alias="high")
|
||||
l: PositiveFloat = Field(alias="low") # noqa: E741
|
||||
t: datetime = Field(alias="date")
|
||||
|
||||
@validator("t", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.fromtimestamp(v / 1000)
|
||||
|
||||
2
openbb_sdk/providers/polygon/pyproject.toml
vendored
2
openbb_sdk/providers/polygon/pyproject.toml
vendored
@@ -15,4 +15,4 @@ requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."openbb_provider_extension"]
|
||||
polygon = "openbb_polygon.provider:polygon_provider"
|
||||
polygon = "openbb_polygon:polygon_provider"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""User dependency."""
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Annotated, Optional
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
@@ -12,6 +12,7 @@ from openbb_core.app.model.user_settings import UserSettings
|
||||
from openbb_core.app.service.user_service import UserService
|
||||
from passlib.context import CryptContext
|
||||
from pymongo import MongoClient
|
||||
from typing_extensions import Annotated
|
||||
|
||||
SECRET_KEY = "a0657288545d1d2e991195841782ae2a22574a22954081db0c2888c5f5ddbecc" # nosec # pragma: allowlist secret
|
||||
ALGORITHM = "HS256"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, Form, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
from openbb_core.api.dependency.user import (
|
||||
@@ -14,6 +12,7 @@ from openbb_core.api.dependency.user import (
|
||||
from openbb_core.api.model.token_response import TokenResponse
|
||||
from openbb_core.app.model.user_settings import UserSettings
|
||||
from openbb_core.app.service.hub_service import HubService
|
||||
from typing_extensions import Annotated
|
||||
|
||||
router = APIRouter(prefix="/account", tags=["Account"])
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from functools import partial, wraps
|
||||
from inspect import Parameter, Signature, signature
|
||||
from typing import Annotated, Any, Callable, Dict, Tuple, TypeVar
|
||||
from typing import Any, Callable, Dict, Tuple, TypeVar
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi.routing import APIRoute
|
||||
@@ -10,7 +10,7 @@ from openbb_core.app.model.command_context import CommandContext
|
||||
from openbb_core.app.model.user_settings import UserSettings
|
||||
from openbb_core.app.router import RouterLoader
|
||||
from openbb_core.app.service.system_service import SystemService
|
||||
from typing_extensions import ParamSpec
|
||||
from typing_extensions import Annotated, ParamSpec
|
||||
|
||||
T = TypeVar("T")
|
||||
P = ParamSpec("P")
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from openbb_core.api.dependency.user import UserService, get_user, get_user_service
|
||||
from openbb_core.app.model.credentials import Credentials
|
||||
from openbb_core.app.model.user_settings import UserSettings
|
||||
from typing_extensions import Annotated
|
||||
|
||||
router = APIRouter(prefix="/settings", tags=["Settings"])
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
"""System router."""
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from openbb_core.api.dependency.system import get_system_settings
|
||||
from openbb_core.app.model.system_settings import SystemSettings
|
||||
from typing_extensions import Annotated
|
||||
|
||||
router = APIRouter(prefix="/system", tags=["System"])
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user