Merge branch 'feature/openbb-sdk-v4' into feature/argparse_translator

This commit is contained in:
hjoaquim
2023-08-09 08:39:21 +01:00
427 changed files with 69364 additions and 14439 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

35
.github/workflows/sdkv4-core.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Test SDKV4
on:
pull_request:
branches:
- feature/openbb-sdk-v4
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
unit_tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python_version:
["3.8", "3.9", "3.10", "3.11"]
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
- name: Install Python ${{ matrix.python_version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python_version }}
allow-prereleases: true
cache: "pip"
- name: Run tests
run: |
pip install nox
nox -s tests --python ${{ matrix.python_version }}

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,8 @@ 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(".")?.[0]?.replace(/[^0-9]/g, "") ?? "";
const probablyDate =
only_numbers?.length >= 4 &&
(includesDateNames(column) ||
@@ -197,7 +198,11 @@ export default function Table({
indexValue.toLowerCase().includes("hour") ||
indexValue.toLowerCase().includes("minute"))));
if (probablyDate && isoYearRegex.test(value?.toString()))
if (
probablyDate &&
value?.length === 4 &&
isoYearRegex.test(value?.toString())
)
return value;
if (probablyDate) {
@@ -219,7 +224,8 @@ 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(".")?.[0]?.replace(/[^0-9]/g, "") ?? "";
const probablyDate =
only_numbers?.length >= 4 &&
(includesDateNames(column) ||
@@ -246,14 +252,15 @@ export default function Table({
</a>
);
}
if (probablyDate && isoYearRegex.test(value?.toString())) {
return <p>{value}</p>;
}
if (
probablyDate &&
!isNaN(new Date(value).getTime()) &&
!isoYearRegex.test(value?.toString())
value?.length === 4 &&
isoYearRegex.test(value?.toString())
) {
return <p>{value}</p>;
}
if (probablyDate && !isNaN(new Date(value).getTime())) {
if (typeof value === "string") {
const date = value.split("T")[0];
const time = value.split("T")[1]?.split(".")[0];

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

8
noxfile.py Normal file
View File

@@ -0,0 +1,8 @@
import nox
@nox.session(python=["3.8", "3.9", "3.10", "3.11"])
def tests(session):
session.install("./openbb_sdk")
session.install("pytest")
session.run("pytest", "openbb_sdk/sdk/core/tests")

View File

@@ -3,4 +3,4 @@ from openbb_charting.core.backend import (
create_backend,
get_backend,
)
from openbb_charting.core.to_plotly_json import to_plotly_json
from openbb_charting.core.to_chart import to_chart

View File

@@ -1,9 +1,12 @@
from inspect import getmembers, isfunction
from typing import List
from openbb_charting import charting_router
from openbb_core.app.router import RouterLoader
CHARTING_ROUTER = "./charting_router.py"
# refers to the root of the repo, not the root of the extension
# this script should be run from the root of the repo
CHARTING_ROUTER = "openbb_sdk/extensions/charting/openbb_charting/charting_router.py"
def get_routes() -> List[str]:
@@ -18,15 +21,13 @@ def create_charting_functions_w_routes(routes_to_add: List[str]):
f.write(
f"""
def {route}(**kwargs):
def {route}(**kwargs) -> Tuple[OpenBBFigure, Dict[str, Any]]:
raise NotImplementedError("Command `{original_route}` does not have a charting function")
"""
)
def get_charting_functions() -> List[str]:
from . import charting_router # pylint: disable=import-outside-toplevel
functions = getmembers(charting_router, isfunction)
if functions:
return [function[0] for function in functions]

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.
@@ -137,7 +137,7 @@ class ChartStyle:
for attr, ext in zip(
["plt_styles_available", "console_styles_available"],
[".pltstyle", ".richstyle.json"],
[".pltstyle.json", ".richstyle.json"],
):
for file in folder.rglob(f"*{ext}"):
getattr(self, attr)[file.name.replace(ext, "")] = file

View File

@@ -338,9 +338,7 @@ class OpenBBFigure(go.Figure):
for i, (x_i, name_i, color_i) in enumerate(zip(valid_x, name, colors)):
if not color_i:
color_i = ( # noqa: PLW2901
self._self._theme.up_color
if i % 2 == 0
else self._self._theme.down_color
self._theme.up_color if i % 2 == 0 else self._theme.down_color
)
res_mean, res_std = np.mean(x_i), np.std(x_i)
@@ -386,7 +384,7 @@ class OpenBBFigure(go.Figure):
name=name_i if len(name) < 2 else name[1],
mode="markers",
marker=dict(
color=self._self._theme.down_color,
color=self._theme.down_color,
symbol="line-ns-open",
size=8,
),
@@ -1381,7 +1379,7 @@ class OpenBBFigure(go.Figure):
height = kwargs.pop("height", len(data.index) * 28 + 25)
width = kwargs.pop("width", sum(columnwidth) * 8.7)
fig: OpenBBFigure = cls()
fig = OpenBBFigure(**kwargs)
fig.add_table(
header=dict(values=header_values),
cells=dict(

View File

@@ -0,0 +1,95 @@
from typing import List, Optional, Union
import pandas as pd
from openbb_sdk.extensions.charting.openbb_charting.core.openbb_figure import (
OpenBBFigure,
)
class OpenBBFigureTable(OpenBBFigure):
def __init__(
self,
tabular_data: pd.DataFrame,
columnwidth: Optional[List[Union[int, float]]] = None,
):
super().__init__()
self._tabular_data = tabular_data
self._columnwidth = columnwidth
def show(
self,
show_index: Optional[bool] = True,
index_name: Optional[str] = "",
headers: Optional[Union[List[str], pd.Index]] = None,
title: Optional[str] = "",
source: Optional[str] = "",
external: Optional[bool] = False,
) -> Optional["OpenBBFigureTable"]:
if external:
return self
if not self._backend.isatty:
tmp_fig = self.to_table()
tmp_fig.show()
else:
# Make a copy of the dataframe to avoid SettingWithCopyWarning
df = self._tabular_data.copy()
show_index = not isinstance(df.index, pd.RangeIndex) and show_index
# convert non-str that are not timestamp or int into str
# eg) praw.models.reddit.subreddit.Subreddit
for col in df.columns:
try:
if not any(
isinstance(df[col].iloc[x], pd.Timestamp)
for x in range(min(10, len(df)))
):
df[col] = pd.to_numeric(df[col], errors="ignore")
except (ValueError, TypeError):
df[col] = df[col].astype(str)
def _get_headers(_headers: Union[List[str], pd.Index]) -> List[str]:
"""Check if headers are valid and return them."""
output = _headers
if isinstance(_headers, pd.Index):
output = list(_headers)
if len(output) != len(df.columns):
raise (
ValueError(
"Length of headers does not match length of DataFrame"
)
)
return output
df_outgoing = df.copy()
# If headers are provided, use them
if headers is not None:
# We check if headers are valid
df_outgoing.columns = _get_headers(headers)
if show_index and index_name not in df_outgoing.columns:
# If index name is provided, we use it
df_outgoing.index.name = index_name or "Index"
df_outgoing = df_outgoing.reset_index()
for col in df_outgoing.columns:
if col == "":
df_outgoing = df_outgoing.rename(columns={col: " "})
self._backend.send_table(
df_table=df_outgoing,
title=title,
source=source, # type: ignore
theme=self._charting_settings.table_style,
)
def to_table(
self,
print_index: bool = True,
**kwargs,
) -> "OpenBBFigure":
data = self._tabular_data
columnwidth = self._columnwidth
return super().to_table(data, columnwidth, print_index, **kwargs)

View File

@@ -1,12 +1,13 @@
from typing import Any, Dict, Optional, Union
from typing import Any, Dict, Optional, Tuple, Union
import pandas as pd
from openbb_charting.core.openbb_figure import OpenBBFigure
from openbb_charting.core.plotly_ta.data_classes import ChartIndicators
from openbb_charting.core.plotly_ta.ta_class import PlotlyTA
from openbb_core.app.model.charts.charting_settings import ChartingSettings
def to_plotly_json(
def to_chart(
charting_settings: ChartingSettings,
data: Union[pd.DataFrame, pd.Series],
indicators: Optional[Union[ChartIndicators, Dict[str, Dict[str, Any]]]] = None,
@@ -15,7 +16,7 @@ def to_plotly_json(
volume: bool = True,
prepost: bool = False,
volume_ticks_x: int = 7,
) -> str:
) -> Tuple[OpenBBFigure, Dict[str, Any]]:
"""
Returns the plotly json representation of the chart.
This function is used so it can be called at the module level and used out of the box,
@@ -57,5 +58,6 @@ def to_plotly_json(
prepost=prepost,
volume_ticks_x=volume_ticks_x,
)
content = fig.show(external=True).to_plotly_json()
return fig.show(external=True).to_plotly_json()
return fig, content

View File

@@ -0,0 +1,102 @@
{
"data": {
"candlestick": [
{
"decreasing": {
"fillcolor": "#e4003a",
"line": {
"color": "#e4003a"
}
},
"increasing": {
"fillcolor": "#00ACFF",
"line": {
"color": "#00ACFF"
}
},
"type": "candlestick"
}
]
},
"layout": {
"annotationdefaults": {
"showarrow": false
},
"autotypenumbers": "strict",
"colorway": [
"#ffed00",
"#ef7d00",
"#e4003a",
"#c13246",
"#822661",
"#48277c",
"#005ca9",
"#00aaff",
"#9b30d9",
"#af005f",
"#5f00af",
"#af87ff"
],
"dragmode": "pan",
"font": {
"family": "Fira Code",
"size": 18
},
"hoverlabel": {
"align": "left"
},
"mapbox": {
"style": "light"
},
"hovermode": "x",
"legend": {
"bgcolor": "rgba(0, 0, 0, 0)",
"x": 0.01,
"xanchor": "left",
"y": 0.99,
"yanchor": "top",
"font": {
"size": 15
}
},
"paper_bgcolor": "white",
"plot_bgcolor": "white",
"xaxis": {
"automargin": true,
"autorange": true,
"rangeslider": {
"visible": false
},
"showgrid": true,
"showline": true,
"tickfont": {
"size": 14
},
"zeroline": false,
"tick0": 1,
"title": {
"standoff": 20
},
"linecolor": "#F5EFF3",
"mirror": true,
"ticks": "outside"
},
"yaxis": {
"anchor": "x",
"automargin": true,
"fixedrange": false,
"zeroline": false,
"showgrid": true,
"showline": true,
"side": "right",
"tick0": 0.5,
"title": {
"standoff": 20
},
"gridcolor": "#283442",
"linecolor": "#F5EFF3",
"mirror": true,
"ticks": "outside"
}
}
}

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

View File

View File

View File

View File

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

View File

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,108 +2,124 @@
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.standard_models.global_news import (
GlobalNewsData,
GlobalNewsQueryParams,
)
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(GlobalNewsData):
"""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(
Fetcher[
GlobalNewsQueryParams,
GlobalNewsData,
BenzingaGlobalNewsQueryParams,
BenzingaGlobalNewsData,
]
):
@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,110 +2,121 @@
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.standard_models.stock_news import (
StockNewsData,
StockNewsQueryParams,
)
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[
StockNewsQueryParams,
StockNewsData,
BenzingaStockNewsQueryParams,
BenzingaStockNewsData,
]
):
@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 +124,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

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,13 +1,10 @@
"""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 (
from openbb_provider.standard_models.analyst_estimates import (
AnalystEstimatesData,
AnalystEstimatesQueryParams,
)
@@ -16,76 +13,67 @@ 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(
Fetcher[
AnalystEstimatesQueryParams,
AnalystEstimatesData,
FMPAnalystEstimatesQueryParams,
FMPAnalystEstimatesData,
]
):
@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,65 +1,58 @@
"""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 (
from openbb_provider.standard_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(
Fetcher[
AvailableIndicesQueryParams,
AvailableIndicesData,
FMPAvailableIndicesQueryParams,
FMPAvailableIndicesData,
]
):
@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 (
from openbb_provider.standard_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,97 +28,92 @@ 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[
BalanceSheetQueryParams,
BalanceSheetData,
FMPBalanceSheetQueryParams,
FMPBalanceSheetData,
]
):
@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,106 @@
"""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.standard_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[
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,133 +1,106 @@
"""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 (
from openbb_provider.standard_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]
class FMPCashFlowStatementFetcher(
Fetcher[
CashFlowStatementQueryParams,
CashFlowStatementData,
FMPCashFlowStatementQueryParams,
FMPCashFlowStatementData,
]
):
@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,95 @@
"""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.standard_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[
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,76 @@
"""FMP Company Overview Fetcher."""
from typing import Any, Dict, List, Optional
from openbb_provider.abstract.fetcher import Fetcher
from openbb_provider.standard_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[
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,99 +1,90 @@
"""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.standard_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")
class FMPCryptoEODFetcher(
Fetcher[
CryptoEODQueryParams,
CryptoEODData,
FMPCryptoEODQueryParams,
FMPCryptoEODData,
]
):
@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,11 +1,10 @@
"""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 (
from openbb_provider.standard_models.dividend_calendar import (
DividendCalendarData,
DividendCalendarQueryParams,
)
@@ -15,77 +14,76 @@ 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
class FMPDividendCalendarFetcher(
Fetcher[
DividendCalendarQueryParams,
DividendCalendarData,
FMPDividendCalendarQueryParams,
FMPDividendCalendarData,
]
):
@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,73 +1,75 @@
"""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 (
from openbb_provider.standard_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(
Fetcher[
EarningsCalendarQueryParams,
EarningsCalendarData,
FMPEarningsCalendarQueryParams,
FMPEarningsCalendarData,
]
):
@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,63 +1,56 @@
"""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 (
from openbb_provider.standard_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(
Fetcher[
EarningsCallTranscriptQueryParams,
EarningsCallTranscriptData,
FMPEarningsCallTranscriptQueryParams,
FMPEarningsCallTranscriptData,
]
):
@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 +59,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,13 +2,11 @@
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,
from openbb_provider.standard_models.esg_risk_rating import (
ESGRiskRatingQueryParams,
)
from pydantic import Field
@@ -45,30 +43,27 @@ class FMPESGRiskRatingData(Data):
class FMPESGRiskRatingFetcher(
Fetcher[
ESGRiskRatingQueryParams,
ESGRiskRatingData,
FMPESGRiskRatingQueryParams,
FMPESGRiskRatingData,
]
):
@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,12 +2,11 @@
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 openbb_provider.standard_models.esg_score import ESGScoreQueryParams
from pydantic import Field
from openbb_fmp.utils.helpers import create_url, get_data_many
@@ -39,25 +38,22 @@ class FMPESGScoreData(Data):
url: str
class FMPESGScoreFetcher(
Fetcher[ESGScoreQueryParams, ESGScoreData, FMPESGScoreQueryParams, FMPESGScoreData]
):
class FMPESGScoreFetcher(Fetcher[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,12 +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.models.esg_sector import ESGSectorData, ESGSectorQueryParams
from openbb_provider.abstract.query_params import QueryParams
from pydantic import Field
from openbb_fmp.utils.helpers import create_url, get_data_many
@@ -38,29 +37,24 @@ class FMPESGSectorData(Data):
ESGScore: float = Field(alias="esg_score")
class FMPESGSectorFetcher(
Fetcher[
ESGSectorQueryParams, ESGSectorData, FMPESGSectorQueryParams, FMPESGSectorData
]
):
class FMPESGSectorFetcher(Fetcher[FMPESGSectorQueryParams, FMPESGSectorData]):
@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,16 +1,11 @@
"""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 (
from openbb_provider.standard_models.executive_compensation import (
ExecutiveCompensationData,
ExecutiveCompensationQueryParams,
)
@@ -18,72 +13,61 @@ 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
ExecutiveCompensationQueryParams,
ExecutiveCompensationData,
FMPExecutiveCompensationQueryParams,
FMPExecutiveCompensationData,
]
):
@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,80 +1,82 @@
"""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 openbb_provider.standard_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")
class FMPForexEODFetcher(
Fetcher[
ForexEODQueryParams,
ForexEODData,
FMPForexEODQueryParams,
FMPForexEODData,
]
):
@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,53 +1,63 @@
"""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 openbb_provider.standard_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(
Fetcher[
ForexPairsQueryParams,
ForexPairsData,
FMPForexPairsQueryParams,
FMPForexPairsData,
]
):
@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,65 +1,53 @@
"""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 openbb_provider.standard_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(
Fetcher[
GlobalNewsQueryParams,
GlobalNewsData,
FMPGlobalNewsQueryParams,
FMPGlobalNewsData,
]
):
@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,15 +1,10 @@
"""FMP Historical Dividends 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.historical_dividends import (
from openbb_provider.standard_models.historical_dividends import (
HistoricalDividendsData,
HistoricalDividendsQueryParams,
)
@@ -22,69 +17,58 @@ 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
class FMPHistoricalDividendsFetcher(
Fetcher[
HistoricalDividendsQueryParams,
HistoricalDividendsData,
FMPHistoricalDividendsQueryParams,
FMPHistoricalDividendsData,
]
):
@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 (
from openbb_provider.standard_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,68 +18,58 @@ 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")
class FMPHistoricalEmployeesFetcher(
Fetcher[
HistoricalEmployeesQueryParams,
HistoricalEmployeesData,
FMPHistoricalEmployeesQueryParams,
FMPHistoricalEmployeesData,
]
):
@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,63 +1,59 @@
"""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 (
from openbb_provider.standard_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(
Fetcher[
HistoricalStockSplitsQueryParams,
HistoricalStockSplitsData,
FMPHistoricalStockSplitsQueryParams,
FMPHistoricalStockSplitsData,
]
):
@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 (
from openbb_provider.standard_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,82 +34,73 @@ 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]
class FMPIncomeStatementFetcher(
Fetcher[
IncomeStatementQueryParams,
IncomeStatementData,
FMPIncomeStatementQueryParams,
FMPIncomeStatementData,
]
):
@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,91 @@
"""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.standard_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[
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,119 +1,94 @@
"""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 (
from openbb_provider.standard_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")
class FMPInstitutionalOwnershipFetcher(
Fetcher[
InstitutionalOwnershipQueryParams,
InstitutionalOwnershipData,
FMPInstitutionalOwnershipQueryParams,
FMPInstitutionalOwnershipData,
]
):
@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,67 @@
"""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.standard_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[
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
return data

View File

@@ -1,135 +1,118 @@
"""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 openbb_provider.standard_models.key_metrics import (
KeyMetricsData,
KeyMetricsQueryParams,
)
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(
Fetcher[
KeyMetricsQueryParams,
KeyMetricsData,
FMPKeyMetricsQueryParams,
FMPKeyMetricsData,
]
):
@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,11 +2,10 @@
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 (
from openbb_provider.standard_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
@@ -51,31 +52,31 @@ class FMPMajorIndicesConstituentsData(MajorIndicesConstituentsData):
class FMPMajorIndicesConstituentsFetcher(
Fetcher[
MajorIndicesConstituentsQueryParams,
MajorIndicesConstituentsData,
FMPMajorIndicesConstituentsQueryParams,
FMPMajorIndicesConstituentsData,
]
):
@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,100 +1,88 @@
"""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 (
from openbb_provider.standard_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")
class FMPMajorIndicesEODFetcher(
Fetcher[
MajorIndicesEODQueryParams,
MajorIndicesEODData,
FMPMajorIndicesEODQueryParams,
FMPMajorIndicesEODData,
]
):
@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,67 +2,69 @@
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 openbb_provider.standard_models.price_target import (
PriceTargetData,
PriceTargetQueryParams,
)
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(
Fetcher[
PriceTargetQueryParams,
PriceTargetData,
FMPPriceTargetQueryParams,
FMPPriceTargetData,
]
):
@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,13 +1,10 @@
"""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 (
from openbb_provider.standard_models.price_target_consensus import (
PriceTargetConsensusData,
PriceTargetConsensusQueryParams,
)
@@ -15,62 +12,48 @@ 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(
Fetcher[
PriceTargetConsensusQueryParams,
PriceTargetConsensusData,
FMPPriceTargetConsensusQueryParams,
FMPPriceTargetConsensusData,
]
):
@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,11 +2,10 @@
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 (
from openbb_provider.standard_models.revenue_business_line import (
RevenueBusinessLineData,
RevenueBusinessLineQueryParams,
)
@@ -14,64 +13,50 @@ 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")
class FMPRevenueBusinessLineFetcher(
Fetcher[ # type: ignore
RevenueBusinessLineQueryParams,
RevenueBusinessLineData,
FMPRevenueBusinessLineQueryParams,
FMPRevenueBusinessLineData,
]
):
@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 +65,5 @@ class FMPRevenueBusinessLineFetcher(
@staticmethod
def transform_data(
data: List[FMPRevenueBusinessLineData],
) -> List[RevenueBusinessLineData]:
return data_transformer(data, RevenueBusinessLineData)
) -> List[FMPRevenueBusinessLineData]:
return data

View File

@@ -2,11 +2,10 @@
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 (
from openbb_provider.standard_models.revenue_geographic import (
RevenueGeographicData,
RevenueGeographicQueryParams,
)
@@ -14,80 +13,63 @@ 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")
class FMPRevenueGeographicFetcher(
Fetcher[ # type: ignore
RevenueGeographicQueryParams,
RevenueGeographicData,
FMPRevenueGeographicQueryParams,
FMPRevenueGeographicData,
]
):
@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 +77,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,11 +1,13 @@
"""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_provider.standard_models.risk_premium import (
RiskPremiumData,
RiskPremiumQueryParams,
)
from openbb_fmp.utils.helpers import create_url, get_data_many
@@ -14,35 +16,41 @@ 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[
RiskPremiumQueryParams,
RiskPremiumData,
FMPRiskPremiumQueryParams,
FMPRiskPremiumData,
]
):
@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,81 +1,65 @@
"""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 openbb_provider.standard_models.sec_filings import (
SECFilingsData,
SECFilingsQueryParams,
)
from pydantic import validator
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(
Fetcher[
SECFilingsQueryParams,
SECFilingsData,
FMPSECFilingsQueryParams,
FMPSECFilingsData,
]
):
@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,17 +1,11 @@
"""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 (
from openbb_provider.standard_models.share_statistics import (
ShareStatisticsData,
ShareStatisticsQueryParams,
)
@@ -20,57 +14,52 @@ 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")
class FMPShareStatisticsFetcher(
Fetcher[
ShareStatisticsQueryParams,
ShareStatisticsData,
FMPShareStatisticsQueryParams,
FMPShareStatisticsData,
]
):
@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,91 +2,88 @@
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.standard_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")
class FMPStockEODFetcher(
Fetcher[
StockEODQueryParams,
StockEODData,
FMPStockEODQueryParams,
FMPStockEODData,
]
):
@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,98 +1,81 @@
"""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 (
from openbb_provider.standard_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(
Fetcher[
StockInsiderTradingQueryParams,
StockInsiderTradingData,
FMPStockInsiderTradingQueryParams,
FMPStockInsiderTradingData,
]
):
@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
return data

View File

@@ -1,157 +1,115 @@
"""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 (
from openbb_provider.standard_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(
Fetcher[
StockMultiplesQueryParams,
StockMultiplesData,
FMPStockMultiplesQueryParams,
FMPStockMultiplesData,
]
):
@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

@@ -1,76 +1,61 @@
"""FMP Stock News fetcher."""
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.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 openbb_provider.standard_models.stock_news import (
StockNewsData,
StockNewsQueryParams,
)
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):
symbol: str
publishedDate: datetime = Field(alias="date")
title: str
image: Optional[str]
text: str
url: str
site: str
class FMPStockNewsData(StockNewsData):
"""FMP Stock News data."""
class Config:
fields = {"date": "publishedDate"}
symbol: str = Field(description="Ticker of the fetched news.")
image: Optional[str] = Field(description="URL to the image of the news source.")
site: str = Field(description="Name of the news source.")
class FMPStockNewsFetcher(
Fetcher[
StockNewsQueryParams,
StockNewsData,
FMPStockNewsQueryParams,
FMPStockNewsData,
]
):
@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
return data

View File

@@ -1,11 +1,10 @@
"""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 (
from openbb_provider.standard_models.stock_ownership import (
StockOwnershipData,
StockOwnershipQueryParams,
)
@@ -17,42 +16,67 @@ 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(
Fetcher[
StockOwnershipQueryParams,
StockOwnershipData,
FMPStockOwnershipQueryParams,
FMPStockOwnershipData,
]
):
@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 +84,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,11 +1,13 @@
"""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_provider.standard_models.stock_peers import (
StockPeersData,
StockPeersQueryParams,
)
from openbb_fmp.utils.helpers import create_url, get_data_many
@@ -16,42 +18,39 @@ 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[
StockPeersQueryParams,
StockPeersData,
FMPStockPeersQueryParams,
FMPStockPeersData,
]
):
@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,11 +2,10 @@
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 (
from openbb_provider.standard_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."""
@@ -37,37 +26,36 @@ class FMPStockSplitCalendarData(StockSplitCalendarData):
class FMPStockSplitCalendarFetcher(
Fetcher[
StockSplitCalendarQueryParams,
StockSplitCalendarData,
FMPStockSplitCalendarQueryParams,
FMPStockSplitCalendarData,
]
):
@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,80 +1,81 @@
"""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 (
from openbb_provider.standard_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(
Fetcher[
TreasuryRatesQueryParams,
TreasuryRatesData,
FMPTreasuryRatesQueryParams,
FMPTreasuryRatesData,
]
):
@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

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,61 +1,34 @@
"""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.standard_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):
"""CPI data."""
class FREDCPIFetcher(Fetcher[CPIQueryParams, CPIData, FREDCPIQueryParams, FREDCPIData]):
class FREDCPIFetcher(Fetcher[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

Some files were not shown because too many files have changed in this diff Show More