Merge, fix errors, and conflicts

This commit is contained in:
Igor Radovanovic
2023-08-07 21:33:26 +02:00
267 changed files with 62176 additions and 12057 deletions

View File

@@ -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: |

View File

@@ -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
View File

@@ -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

View File

@@ -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
View File

@@ -0,0 +1,3 @@
tests/
openbb_terminal/miscellaneous/gpt_index/index_0.4.json
.devcontainer/devcontainer.json

View File

@@ -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.

View File

@@ -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,

View File

@@ -17,7 +17,7 @@ router = Router(prefix="/ca")
@router.command(model="StockPeers")
def get(
def peers(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,

View File

@@ -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())

View File

@@ -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)

View File

@@ -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,
},
)

View File

@@ -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

View File

@@ -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

View File

@@ -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],
)

View File

@@ -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")

View File

@@ -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"

View File

@@ -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"

View File

@@ -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,
},
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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,
],
)

View File

@@ -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")

View File

@@ -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"

View File

@@ -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},
)

View File

@@ -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

View File

@@ -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],
)

View File

@@ -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"]

View File

@@ -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
View File

@@ -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"

View File

@@ -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"

View File

@@ -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,
},
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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")

View File

@@ -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)

View File

@@ -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,
],
)

View File

@@ -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")

View File

@@ -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)

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"])

View File

@@ -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")

View File

@@ -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"])

View File

@@ -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