mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-12 20:31:18 +00:00
Move built-in providers code
This commit is contained in:
0
openbb_providers/builtin_providers/__init__.py
Normal file
0
openbb_providers/builtin_providers/__init__.py
Normal file
120
openbb_providers/builtin_providers/benzinga/global_news.py
Normal file
120
openbb_providers/builtin_providers/benzinga/global_news.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""Benzinga Global News Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.benzinga.helpers import BenzingaBaseNewsData, get_data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import QueryParams
|
||||
from openbb_provider.model.data.global_news import GlobalNewsData, GlobalNewsQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class BenzingaGlobalNewsQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "BenzingaGlobalNewsQueryParams"
|
||||
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
|
||||
|
||||
|
||||
class BenzingaGlobalNewsData(BenzingaBaseNewsData):
|
||||
__name__ = "BenzingaGlobalNewsData"
|
||||
url: str
|
||||
|
||||
|
||||
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 {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: BenzingaGlobalNewsQueryParams, api_key: str
|
||||
) -> List[BenzingaGlobalNewsData]:
|
||||
base_url = "https://api.benzinga.com/api/v2/news"
|
||||
querystring = get_querystring(query.dict(), [])
|
||||
request_url = f"{base_url}?{querystring}&token={api_key}"
|
||||
data = get_data(request_url)
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No news found")
|
||||
|
||||
return [BenzingaGlobalNewsData(**d) for d in data]
|
||||
|
||||
@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)
|
||||
44
openbb_providers/builtin_providers/benzinga/helpers.py
Normal file
44
openbb_providers/builtin_providers/benzinga/helpers.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""Benzinga Helpers."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
import requests
|
||||
from pydantic import BaseModel, Field, validator
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
|
||||
def get_data(url: str) -> dict:
|
||||
r = requests.get(url, timeout=10, headers={"accept": "application/json"})
|
||||
if r.status_code != 200:
|
||||
data = r.json()
|
||||
if data == ['Access denied for user 0 "anonymous"']:
|
||||
raise RuntimeError("API Key is invalid")
|
||||
message = data.get("message")
|
||||
error = data.get("error")
|
||||
value = message or error
|
||||
raise RuntimeError(f"Error in Benzinga request: {value}")
|
||||
|
||||
return r.json()
|
||||
|
||||
|
||||
class BenzingaImage(BaseModel):
|
||||
size: str
|
||||
url: str
|
||||
|
||||
|
||||
class BenzingaBaseNewsData(Data):
|
||||
__name__ = "BenzingaGlobalNewsData"
|
||||
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")
|
||||
21
openbb_providers/builtin_providers/benzinga/provider.py
Normal file
21
openbb_providers/builtin_providers/benzinga/provider.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""Benzinga provider module."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
|
||||
from builtin_providers.benzinga.global_news import BenzingaGlobalNewsFetcher
|
||||
from builtin_providers.benzinga.stock_news import BenzingaStockNewsFetcher
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.provider.abstract.provider import Provider
|
||||
|
||||
# mypy: disable-error-code="list-item"
|
||||
|
||||
|
||||
# ignoring because I dont know how to type the string properly
|
||||
benzinga_provider = Provider(
|
||||
name="benzinga", # type: ignore
|
||||
description="Provider for Benzinga.",
|
||||
fetcher_list=[BenzingaGlobalNewsFetcher, BenzingaStockNewsFetcher],
|
||||
)
|
||||
119
openbb_providers/builtin_providers/benzinga/stock_news.py
Normal file
119
openbb_providers/builtin_providers/benzinga/stock_news.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""Benzinga Stock News Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.benzinga.helpers import BenzingaBaseNewsData, get_data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import QueryParams
|
||||
from openbb_provider.model.data.stock_news import StockNewsData, StockNewsQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class BenzingaStockNewsQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "BenzingaStockNewsQueryParams"
|
||||
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 BenzingaStockNewsData(BenzingaBaseNewsData):
|
||||
__name__ = "BenzingaStocklNewsData"
|
||||
|
||||
|
||||
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 {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: BenzingaStockNewsQueryParams, api_key: str
|
||||
) -> List[BenzingaStockNewsData]:
|
||||
base_url = "https://api.benzinga.com/api/v2/news"
|
||||
querystring = get_querystring(query.dict(), [])
|
||||
request_url = f"{base_url}?{querystring}&token={api_key}"
|
||||
data = get_data(request_url)
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No news found")
|
||||
|
||||
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)
|
||||
0
openbb_providers/builtin_providers/fmp/__init__.py
Normal file
0
openbb_providers/builtin_providers/fmp/__init__.py
Normal file
89
openbb_providers/builtin_providers/fmp/analyst_estimates.py
Normal file
89
openbb_providers/builtin_providers/fmp/analyst_estimates.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""FMP Analyst Estimates fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.analyst_estimates import (
|
||||
AnalystEstimatesData,
|
||||
AnalystEstimatesQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPAnalystEstimatesQueryParams(AnalystEstimatesQueryParams):
|
||||
"""FMP Analysts Estimates query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/analyst-estimates-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
limit : int
|
||||
"""
|
||||
|
||||
__name__ = "FMPAnalystEstimatesQueryParams"
|
||||
|
||||
|
||||
class FMPAnalystEstimatesData(Data):
|
||||
__name__ = "FMPAnalystEstimatesData"
|
||||
|
||||
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 FMPAnalystEstimatesFetcher(
|
||||
Fetcher[
|
||||
AnalystEstimatesQueryParams,
|
||||
AnalystEstimatesData,
|
||||
FMPAnalystEstimatesQueryParams,
|
||||
FMPAnalystEstimatesData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: AnalystEstimatesQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPAnalystEstimatesQueryParams:
|
||||
return FMPAnalystEstimatesQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPAnalystEstimatesQueryParams, api_key: str
|
||||
) -> List[FMPAnalystEstimatesData]:
|
||||
url = create_url(
|
||||
3, f"analyst-estimates/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPAnalystEstimatesData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPAnalystEstimatesData],
|
||||
) -> List[AnalystEstimatesData]:
|
||||
return data_transformer(data, AnalystEstimatesData)
|
||||
169
openbb_providers/builtin_providers/fmp/balance_sheet.py
Normal file
169
openbb_providers/builtin_providers/fmp/balance_sheet.py
Normal file
@@ -0,0 +1,169 @@
|
||||
"""FMP Balance Sheet Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt, root_validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.balance_sheet import (
|
||||
BalanceSheetData,
|
||||
BalanceSheetQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
|
||||
|
||||
class FMPBalanceSheetQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPBalanceSheetQueryParams"
|
||||
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
|
||||
if values.get("symbol") is None and values.get("cik") is None:
|
||||
raise ValueError("symbol or cik must be provided")
|
||||
return values
|
||||
|
||||
|
||||
class FMPBalanceSheetData(Data):
|
||||
__name__ = "FMPBalanceSheetData"
|
||||
date: dateType
|
||||
symbol: str
|
||||
cik: Optional[int]
|
||||
reportedCurrency: Optional[str]
|
||||
fillingDate: Optional[dateType]
|
||||
acceptedDate: Optional[datetime]
|
||||
calendarYear: Optional[int]
|
||||
period: Optional[str]
|
||||
cashAndCashEquivalents: Optional[int]
|
||||
shortTermInvestments: Optional[int]
|
||||
cashAndShortTermInvestments: Optional[int]
|
||||
netReceivables: Optional[int]
|
||||
inventory: Optional[int]
|
||||
otherCurrentAssets: Optional[int]
|
||||
totalCurrentAssets: Optional[int]
|
||||
propertyPlantEquipmentNet: Optional[int]
|
||||
goodwill: Optional[int]
|
||||
intangibleAssets: Optional[int]
|
||||
goodwillAndIntangibleAssets: Optional[int]
|
||||
longTermInvestments: Optional[int]
|
||||
taxAssets: Optional[int]
|
||||
otherNonCurrentAssets: Optional[int]
|
||||
totalNonCurrentAssets: Optional[int]
|
||||
otherAssets: Optional[int]
|
||||
totalAssets: Optional[int]
|
||||
accountPayables: Optional[int]
|
||||
shortTermDebt: Optional[int]
|
||||
taxPayables: Optional[int]
|
||||
deferredRevenue: Optional[int]
|
||||
otherCurrentLiabilities: Optional[int]
|
||||
totalCurrentLiabilities: Optional[int]
|
||||
longTermDebt: Optional[int]
|
||||
deferredRevenueNonCurrent: Optional[int]
|
||||
deferredTaxLiabilitiesNonCurrent: Optional[int]
|
||||
otherNonCurrentLiabilities: Optional[int]
|
||||
totalNonCurrentLiabilities: Optional[int]
|
||||
otherLiabilities: Optional[int]
|
||||
capitalLeaseObligations: Optional[int]
|
||||
totalLiabilities: Optional[int]
|
||||
preferredStock: Optional[int]
|
||||
commonStock: Optional[int]
|
||||
retainedEarnings: Optional[int]
|
||||
accumulatedOtherComprehensiveIncomeLoss: Optional[int]
|
||||
othertotalStockholdersEquity: Optional[int]
|
||||
totalStockholdersEquity: Optional[int]
|
||||
totalLiabilitiesAndStockholdersEquity: Optional[int]
|
||||
minorityInterest: Optional[int]
|
||||
totalEquity: Optional[int]
|
||||
totalLiabilitiesAndTotalEquity: Optional[int]
|
||||
totalInvestments: Optional[int]
|
||||
netDebt: Optional[int]
|
||||
finalLink: Optional[str]
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPBalanceSheetQueryParams, api_key: str
|
||||
) -> List[FMPBalanceSheetData]:
|
||||
url = create_url(
|
||||
3, f"balance-sheet-statement/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPBalanceSheetData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPBalanceSheetData],
|
||||
) -> List[BalanceSheetData]:
|
||||
final_items = []
|
||||
for item in data:
|
||||
tot_se = item.totalStockholdersEquity
|
||||
minority = item.minorityInterest
|
||||
parent: Optional[int] = None
|
||||
if tot_se:
|
||||
if tot_se is None:
|
||||
pass
|
||||
elif minority is None:
|
||||
parent = tot_se
|
||||
else:
|
||||
parent = tot_se - minority
|
||||
|
||||
final = BalanceSheetData(
|
||||
date=item.date,
|
||||
# symbol=item.symbol,
|
||||
# currency=item.reportedCurrency,
|
||||
cik=item.cik,
|
||||
# period=item.period,
|
||||
assets=item.totalAssets,
|
||||
current_assets=item.totalCurrentAssets,
|
||||
current_liabilities=item.totalCurrentLiabilities,
|
||||
equity=item.totalStockholdersEquity,
|
||||
equity_attributable_to_noncontrolling_interest=item.minorityInterest,
|
||||
equity_attributable_to_parent=parent,
|
||||
liabilities=item.totalLiabilities,
|
||||
liabilities_and_equity=item.totalLiabilitiesAndTotalEquity,
|
||||
noncurrent_assets=item.totalNonCurrentAssets,
|
||||
noncurrent_liabilities=item.totalNonCurrentLiabilities,
|
||||
)
|
||||
final_items.append(final)
|
||||
return final_items
|
||||
133
openbb_providers/builtin_providers/fmp/cash_flow.py
Normal file
133
openbb_providers/builtin_providers/fmp/cash_flow.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""FMP Cash Flow Statement Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt, root_validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.cash_flows import (
|
||||
CashFlowStatementData,
|
||||
CashFlowStatementQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPCashFlowStatementQueryParams(QueryParams):
|
||||
"""FMP Cash Flow Statement QueryParams.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPCashFlowStatementQueryParams"
|
||||
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=E0213
|
||||
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):
|
||||
__name__ = "FMPCashFlowStatementData"
|
||||
date: dateType
|
||||
symbol: str
|
||||
cik: Optional[int]
|
||||
reportedCurrency: str = Field(alias="currency")
|
||||
fillingDate: Optional[dateType]
|
||||
acceptedDate: Optional[datetime]
|
||||
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]
|
||||
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]
|
||||
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
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCashFlowStatementQueryParams, api_key: str
|
||||
) -> List[FMPCashFlowStatementData]:
|
||||
url = create_url(
|
||||
3, f"cash-flow-statement/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPCashFlowStatementData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPCashFlowStatementData],
|
||||
) -> List[CashFlowStatementData]:
|
||||
return data_transformer(data, CashFlowStatementData)
|
||||
108
openbb_providers/builtin_providers/fmp/company_profile.py
Normal file
108
openbb_providers/builtin_providers/fmp/company_profile.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""FMP Company Overview Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from typing import Dict, Optional
|
||||
|
||||
from builtin_providers.fmp.helpers import get_data
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.company_overview import (
|
||||
CompanyOverviewData,
|
||||
CompanyOverviewQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
|
||||
|
||||
# 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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPCompanyOverviewQueryParams"
|
||||
|
||||
|
||||
class FMPCompanyOverviewData(Data):
|
||||
__name__ = "FMPCompanyOverviewData"
|
||||
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.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCompanyOverviewQueryParams, api_key: str
|
||||
) -> FMPCompanyOverviewData:
|
||||
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
|
||||
99
openbb_providers/builtin_providers/fmp/crypto_eod.py
Normal file
99
openbb_providers/builtin_providers/fmp/crypto_eod.py
Normal file
@@ -0,0 +1,99 @@
|
||||
"""FMP Cryptos end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt, validator
|
||||
|
||||
from builtin_providers.fmp.helpers import get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.crypto_eod import CryptoEODData, CryptoEODQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class FMPCryptoEODQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPCryptoEODQueryParams"
|
||||
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
|
||||
|
||||
|
||||
class FMPCryptoEODData(Data):
|
||||
__name__ = "FMPCryptoEODData"
|
||||
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
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_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:
|
||||
raw_end = query.end_date if query.end_date else datetime.now()
|
||||
return FMPCryptoEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=raw_end,
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPCryptoEODQueryParams, api_key: str
|
||||
) -> List[FMPCryptoEODData]:
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
query_str = get_querystring(query.dict(), ["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")
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPCryptoEODData]) -> List[CryptoEODData]:
|
||||
return data_transformer(data, CryptoEODData)
|
||||
80
openbb_providers/builtin_providers/fmp/crypto_price.py
Normal file
80
openbb_providers/builtin_providers/fmp/crypto_price.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""FMP Crypto Price fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import QueryParams
|
||||
from openbb_provider.model.data.crypto_price import (
|
||||
CryptoPriceData,
|
||||
CryptoPriceQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPCryptoPriceQueryParams"
|
||||
symbol: str = Field(min_length=1)
|
||||
interval: Interval = Field(default=Interval.onehour)
|
||||
|
||||
|
||||
class FMPCryptoPriceData(BaseStockPriceData):
|
||||
__name__ = "FMPCryptoPriceData"
|
||||
|
||||
|
||||
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, api_key: str
|
||||
) -> List[FMPCryptoPriceData]:
|
||||
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)
|
||||
76
openbb_providers/builtin_providers/fmp/earnings_calendar.py
Normal file
76
openbb_providers/builtin_providers/fmp/earnings_calendar.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""FMP Earnings Calendar fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.earnings_calendar import (
|
||||
EarningsCalendarData,
|
||||
EarningsCalendarQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPEarningsCalendarQueryParams(EarningsCalendarQueryParams):
|
||||
"""FMP Earnings Calendar query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/earnings-calendar-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
limit : int
|
||||
"""
|
||||
|
||||
__name__ = "FMPEarningsCalendarQueryParams"
|
||||
|
||||
|
||||
class FMPEarningsCalendarData(Data):
|
||||
__name__ = "FMPEarningsCalendarData"
|
||||
|
||||
date: dateType
|
||||
symbol: str
|
||||
eps: Optional[float]
|
||||
epsEstimated: Optional[float]
|
||||
time: str
|
||||
revenue: Optional[int]
|
||||
revenueEstimated: Optional[int]
|
||||
updatedFromDate: Optional[dateType]
|
||||
fiscalDateEnding: dateType
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPEarningsCalendarQueryParams, api_key: str
|
||||
) -> List[FMPEarningsCalendarData]:
|
||||
url = create_url(
|
||||
3, f"historical/earning_calendar/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPEarningsCalendarData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPEarningsCalendarData],
|
||||
) -> List[EarningsCalendarData]:
|
||||
return data_transformer(data, EarningsCalendarData)
|
||||
@@ -0,0 +1,67 @@
|
||||
"""FMP Earnings Call Transcript fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.earnings_call_transcript import (
|
||||
EarningsCallTranscriptData,
|
||||
EarningsCallTranscriptQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPEarningsCallTranscriptQueryParams"
|
||||
|
||||
|
||||
class FMPEarningsCallTranscriptData(EarningsCallTranscriptData):
|
||||
__name__ = "FMPEarningsCallTranscriptData"
|
||||
|
||||
|
||||
class FMPEarningsCallTranscriptFetcher(
|
||||
Fetcher[
|
||||
EarningsCallTranscriptQueryParams,
|
||||
EarningsCallTranscriptData,
|
||||
FMPEarningsCallTranscriptQueryParams,
|
||||
FMPEarningsCallTranscriptData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: EarningsCallTranscriptQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPEarningsCallTranscriptQueryParams:
|
||||
return FMPEarningsCallTranscriptQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPEarningsCallTranscriptQueryParams, api_key: str
|
||||
) -> List[FMPEarningsCallTranscriptData]:
|
||||
url = create_url(
|
||||
4,
|
||||
f"batch_earning_call_transcript/{query.symbol}",
|
||||
api_key,
|
||||
query,
|
||||
["symbol"],
|
||||
)
|
||||
return get_data_many(url, FMPEarningsCallTranscriptData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPEarningsCallTranscriptData],
|
||||
) -> List[EarningsCallTranscriptData]:
|
||||
return data_transformer(data, EarningsCallTranscriptData)
|
||||
78
openbb_providers/builtin_providers/fmp/esg_risk_rating.py
Normal file
78
openbb_providers/builtin_providers/fmp/esg_risk_rating.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""FMP ESG Risk Rating fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
from openbb_provider.model.data.esg_risk_rating import (
|
||||
ESGRiskRatingData,
|
||||
ESGRiskRatingQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
current_year = date.today().year
|
||||
ratings = Literal[
|
||||
"A+", "A", "A-", "B+", "B", "B-", "C+", "C", "C-", "D+", "D", "D-", "F"
|
||||
]
|
||||
|
||||
|
||||
class FMPESGRiskRatingQueryParams(ESGRiskRatingQueryParams):
|
||||
"""FMP ESG Risk Rating query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Company-ESG-Risk-Ratings
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPESGRiskRatingQueryParams"
|
||||
|
||||
|
||||
class FMPESGRiskRatingData(Data):
|
||||
__name__ = "FMPESGRiskRatingData"
|
||||
|
||||
symbol: str
|
||||
cik: int
|
||||
companyName: str
|
||||
industry: str
|
||||
year: int
|
||||
ESGRiskRating: ratings = Field(alias="esg_risk_rating")
|
||||
industryRank: str
|
||||
|
||||
|
||||
class FMPESGRiskRatingFetcher(
|
||||
Fetcher[
|
||||
ESGRiskRatingQueryParams,
|
||||
ESGRiskRatingData,
|
||||
FMPESGRiskRatingQueryParams,
|
||||
FMPESGRiskRatingData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ESGRiskRatingQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPESGRiskRatingQueryParams:
|
||||
return FMPESGRiskRatingQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPESGRiskRatingQueryParams, api_key: str
|
||||
) -> List[FMPESGRiskRatingData]:
|
||||
url = create_url(
|
||||
4, "esg-environmental-social-governance-data-ratings", api_key, query
|
||||
)
|
||||
return get_data_many(url, FMPESGRiskRatingData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPESGRiskRatingData]) -> List[ESGRiskRatingData]:
|
||||
return data_transformer(data, ESGRiskRatingData)
|
||||
66
openbb_providers/builtin_providers/fmp/esg_score.py
Normal file
66
openbb_providers/builtin_providers/fmp/esg_score.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""FMP ESG Score fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
from openbb_provider.model.data.esg_score import ESGScoreData, ESGScoreQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPESGScoreQueryParams(ESGScoreQueryParams):
|
||||
"""FMP ESG Score query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#ESG-SCORE
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPESGScoreQueryParams"
|
||||
|
||||
|
||||
class FMPESGScoreData(Data):
|
||||
__name__ = "FMPESGScoreData"
|
||||
symbol: str
|
||||
cik: int
|
||||
companyName: str
|
||||
formType: str
|
||||
acceptedDate: datetime
|
||||
date: date
|
||||
environmentalScore: float
|
||||
socialScore: float
|
||||
governanceScore: float
|
||||
ESGScore: float = Field(alias="esg_score")
|
||||
url: str
|
||||
|
||||
|
||||
class FMPESGScoreFetcher(
|
||||
Fetcher[ESGScoreQueryParams, ESGScoreData, FMPESGScoreQueryParams, FMPESGScoreData]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ESGScoreQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPESGScoreQueryParams:
|
||||
return FMPESGScoreQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPESGScoreQueryParams, api_key: str
|
||||
) -> List[FMPESGScoreData]:
|
||||
url = create_url(4, "esg-environmental-social-governance-data", api_key, query)
|
||||
return get_data_many(url, FMPESGScoreData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPESGScoreData]) -> List[ESGScoreData]:
|
||||
return data_transformer(data, ESGScoreData)
|
||||
69
openbb_providers/builtin_providers/fmp/esg_sector.py
Normal file
69
openbb_providers/builtin_providers/fmp/esg_sector.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""FMP ESG Sector fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.esg_sector import ESGSectorData, ESGSectorQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
current_year = date.today().year
|
||||
|
||||
|
||||
class FMPESGSectorQueryParams(QueryParams):
|
||||
"""FMP ESG Sector query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#ESG-Benchmarking-By-Sector-and-Year
|
||||
|
||||
Parameter
|
||||
---------
|
||||
year : int
|
||||
The year of the data.
|
||||
"""
|
||||
|
||||
__name__ = "FMPESGSectorQueryParams"
|
||||
|
||||
year: int = Field(ge=2000, le=current_year)
|
||||
|
||||
|
||||
class FMPESGSectorData(Data):
|
||||
__name__ = "FMPESGSectorData"
|
||||
year: int
|
||||
sector: str
|
||||
environmentalScore: float
|
||||
socialScore: float
|
||||
governanceScore: float
|
||||
ESGScore: float = Field(alias="esg_score")
|
||||
|
||||
|
||||
class FMPESGSectorFetcher(
|
||||
Fetcher[
|
||||
ESGSectorQueryParams, ESGSectorData, FMPESGSectorQueryParams, FMPESGSectorData
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ESGSectorQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPESGSectorQueryParams:
|
||||
return FMPESGSectorQueryParams(year=query.year)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPESGSectorQueryParams, api_key: str
|
||||
) -> List[FMPESGSectorData]:
|
||||
url = create_url(
|
||||
4, "esg-environmental-social-governance-sector-benchmark", api_key, query
|
||||
)
|
||||
return get_data_many(url, FMPESGSectorData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPESGSectorData]) -> List[ESGSectorData]:
|
||||
return data_transformer(data, ESGSectorData)
|
||||
@@ -0,0 +1,90 @@
|
||||
"""FMP Executive Compensation Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.executive_compensation import (
|
||||
ExecutiveCompensationData,
|
||||
ExecutiveCompensationQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
# This part is only provided by FMP and not by the other providers for now.
|
||||
|
||||
|
||||
class FMPExecutiveCompensationQueryParams(ExecutiveCompensationQueryParams):
|
||||
"""FMP Executive Compensation query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/executive-compensation-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPExecutiveCompensationQueryParams"
|
||||
|
||||
|
||||
class FMPExecutiveCompensationData(Data):
|
||||
__name__ = "FMPExecutiveCompensationData"
|
||||
|
||||
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
|
||||
|
||||
@validator("acceptedDate", pre=True)
|
||||
def convert_accepted_date(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
@validator("filingDate", pre=True)
|
||||
def convert_filing_date(cls, v): # pylint: disable=E0213
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
|
||||
|
||||
class FMPExecutiveCompensationFetcher(
|
||||
Fetcher[ # type: ignore
|
||||
ExecutiveCompensationQueryParams,
|
||||
ExecutiveCompensationData,
|
||||
FMPExecutiveCompensationQueryParams,
|
||||
FMPExecutiveCompensationData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ExecutiveCompensationQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPExecutiveCompensationQueryParams:
|
||||
return FMPExecutiveCompensationQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPExecutiveCompensationQueryParams, api_key: str
|
||||
) -> List[FMPExecutiveCompensationData]:
|
||||
url = create_url(4, "governance/executive_compensation", api_key, query)
|
||||
return get_data_many(url, FMPExecutiveCompensationData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPExecutiveCompensationData],
|
||||
) -> List[ExecutiveCompensationData]:
|
||||
return data_transformer(data, ExecutiveCompensationData)
|
||||
109
openbb_providers/builtin_providers/fmp/executives.py
Normal file
109
openbb_providers/builtin_providers/fmp/executives.py
Normal file
@@ -0,0 +1,109 @@
|
||||
"""FMP Key Executives Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import get_data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.base import BaseSymbol
|
||||
from openbb_provider.model.data.key_executives import (
|
||||
KeyExecutivesData,
|
||||
KeyExecutivesQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPKeyExecutivesQueryParams"
|
||||
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__ = "FMPKeyExecutivesData"
|
||||
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, api_key: str
|
||||
) -> List[FMPKeyExecutivesData]:
|
||||
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)
|
||||
98
openbb_providers/builtin_providers/fmp/forex_eod.py
Normal file
98
openbb_providers/builtin_providers/fmp/forex_eod.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""FMP Forex end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt, validator
|
||||
|
||||
from builtin_providers.fmp.helpers import get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.forex_eod import ForexEODData, ForexEODQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class FMPForexEODQueryParams(QueryParams):
|
||||
"""FMP Forex end of day query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-Forex-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.
|
||||
serietype : Optional[Literal["line"]]
|
||||
The type of the series. Only "line" is supported.
|
||||
"""
|
||||
|
||||
__name__ = "FMPForexEODQueryParams"
|
||||
symbol: str = Field(min_length=1)
|
||||
serietype: Optional[Literal["line"]] = None
|
||||
start_date: date
|
||||
end_date: date
|
||||
timeseries: Optional[NonNegativeInt] = None # Number of days to looks back
|
||||
|
||||
|
||||
class FMPForexEODData(Data):
|
||||
__name__ = "FMPForexEODData"
|
||||
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
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_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:
|
||||
raw_end = query.end_date if query.end_date else datetime.now()
|
||||
return FMPForexEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=raw_end,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPForexEODQueryParams, api_key: str
|
||||
) -> List[FMPForexEODData]:
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
query_str = get_querystring(query.dict(), ["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, FMPForexEODData, "historical")
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPForexEODData]) -> List[ForexEODData]:
|
||||
return data_transformer(data, ForexEODData)
|
||||
77
openbb_providers/builtin_providers/fmp/forex_price.py
Normal file
77
openbb_providers/builtin_providers/fmp/forex_price.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""FMP Forex Price fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import QueryParams
|
||||
from openbb_provider.model.data.forex_price import ForexPriceData, ForexPriceQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPForexPriceQueryParams"
|
||||
symbol: str = Field(min_length=1)
|
||||
interval: Literal["1min", "5min", "15min", "30min", "1hour", "4hour"] = "1hour"
|
||||
|
||||
|
||||
class FMPForexPriceData(BaseStockPriceData):
|
||||
__name__ = "FMPForexPriceData"
|
||||
|
||||
|
||||
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, api_key: str
|
||||
) -> List[FMPForexPriceData]:
|
||||
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)
|
||||
67
openbb_providers/builtin_providers/fmp/global_news.py
Normal file
67
openbb_providers/builtin_providers/fmp/global_news.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""FMP Global News fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.global_news import GlobalNewsData, GlobalNewsQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPGlobalNewsQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPGlobalNewsQueryParams"
|
||||
page: int = Field(default=0)
|
||||
|
||||
|
||||
class FMPGlobalNewsData(Data):
|
||||
__name__ = "FMPGlobalNewsData"
|
||||
publishedDate: datetime = Field(alias="date")
|
||||
title: str
|
||||
image: str
|
||||
text: str
|
||||
url: str
|
||||
site: str
|
||||
|
||||
|
||||
class FMPGlobalNewsFetcher(
|
||||
Fetcher[
|
||||
GlobalNewsQueryParams,
|
||||
GlobalNewsData,
|
||||
FMPGlobalNewsQueryParams,
|
||||
FMPGlobalNewsData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: GlobalNewsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPGlobalNewsQueryParams:
|
||||
return FMPGlobalNewsQueryParams(page=query.page)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPGlobalNewsQueryParams, api_key: str
|
||||
) -> List[FMPGlobalNewsData]:
|
||||
url = create_url(4, "general_news", api_key, query)
|
||||
return get_data_many(url, FMPGlobalNewsData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPGlobalNewsData]) -> List[GlobalNewsData]:
|
||||
return data_transformer(data, GlobalNewsData)
|
||||
123
openbb_providers/builtin_providers/fmp/helpers.py
Normal file
123
openbb_providers/builtin_providers/fmp/helpers.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""FMP Helpers Module."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import List, Optional, Type, TypeVar, Union
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
import requests
|
||||
from pydantic import BaseModel, NonNegativeInt, PositiveFloat, validator
|
||||
from requests.exceptions import SSLError
|
||||
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.provider.abstract.fetcher import QueryParamsType
|
||||
from openbb_provider.provider.provider_helpers import (
|
||||
BasicResponse,
|
||||
get_querystring,
|
||||
request,
|
||||
)
|
||||
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
|
||||
|
||||
def get_data(url: str) -> Union[list, dict]:
|
||||
try:
|
||||
r: Union[requests.Response, BasicResponse] = requests.get(url, timeout=10)
|
||||
except SSLError:
|
||||
r = request(url)
|
||||
if r.status_code == 404:
|
||||
raise RuntimeError("FMP endpoint doesn't exist")
|
||||
|
||||
data = r.json()
|
||||
if r.status_code != 200:
|
||||
message = data.get("message", "unknown error")
|
||||
raise RuntimeError(f"Error in FMP request: {message}")
|
||||
|
||||
if "Error Message" in data:
|
||||
raise RuntimeError("FMP Error Message: " + data["Error Message"])
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No results found. Try adjusting the query parameters.")
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def create_url(
|
||||
version: int,
|
||||
endpoint: str,
|
||||
api_key: str,
|
||||
query: Optional[QueryParamsType] = None,
|
||||
exclude: Optional[List[str]] = None,
|
||||
) -> str:
|
||||
"""Creates a URL for the FMP API.
|
||||
|
||||
Parameters:
|
||||
-----------
|
||||
version: int
|
||||
The version of the API to use.
|
||||
endpoint: str
|
||||
The endpoint to use.
|
||||
api_key: str
|
||||
The API key to use.
|
||||
query: Optional[QueryParamsType]
|
||||
The dictionary to be turned into a querystring.
|
||||
exclude: List[str]
|
||||
The keys to be excluded from the querystring.
|
||||
|
||||
Returns:
|
||||
--------
|
||||
str
|
||||
The querystring.
|
||||
|
||||
"""
|
||||
the_dict = {} if not query else query.dict()
|
||||
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
|
||||
) -> List[T]:
|
||||
"""Get data from FMP endpoint and convert to list of schemas.
|
||||
|
||||
Parameters:
|
||||
-----------
|
||||
url: str
|
||||
The URL to get the data from.
|
||||
to_schema: T
|
||||
The schema to convert the data to.
|
||||
sub_dict: Optional[str]
|
||||
The sub-dictionary to use.
|
||||
"""
|
||||
data = get_data(url)
|
||||
if sub_dict and isinstance(data, dict):
|
||||
data = data.get(sub_dict, [])
|
||||
if isinstance(data, dict):
|
||||
raise ValueError("Expected list of dicts, got dict")
|
||||
return [to_schema(**d) for d in data]
|
||||
|
||||
|
||||
def get_data_one(url: str, to_schema: Type[T]) -> T:
|
||||
"""Get data from FMP endpoint and convert to schema."""
|
||||
data = get_data(url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected dict with lists, got list")
|
||||
return to_schema(**data)
|
||||
|
||||
|
||||
class BaseStockPriceData(Data):
|
||||
open: PositiveFloat
|
||||
high: PositiveFloat
|
||||
low: PositiveFloat
|
||||
close: PositiveFloat
|
||||
volume: NonNegativeInt
|
||||
date: datetime
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_validate(cls, v: str) -> datetime: # pylint: disable=E0213
|
||||
if len(v) < 12:
|
||||
return datetime.strptime(v, "%Y-%m-%d")
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S")
|
||||
@@ -0,0 +1,93 @@
|
||||
"""FMP Historical Dividends fetcher."""
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.historical_dividends import (
|
||||
HistoricalDividendsData,
|
||||
HistoricalDividendsQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPHistoricalDividendsQueryParams(HistoricalDividendsQueryParams):
|
||||
"""FMP Earnings Calendar query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-Dividends
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPHistoricalDividendsQueryParams"
|
||||
|
||||
|
||||
class FMPHistoricalDividendsData(Data):
|
||||
__name__ = "FMPHistoricalDividendsData"
|
||||
|
||||
date: dateType
|
||||
label: str
|
||||
adjDividend: float
|
||||
dividend: float
|
||||
recordDate: Optional[dateType]
|
||||
paymentDate: Optional[dateType]
|
||||
declarationDate: Optional[dateType]
|
||||
|
||||
@validator("declarationDate", pre=True)
|
||||
def declaration_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
if v:
|
||||
return datetime.strptime(v, "%Y-%m-%d").date()
|
||||
return None
|
||||
|
||||
@validator("recordDate", pre=True)
|
||||
def record_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
if v:
|
||||
return datetime.strptime(v, "%Y-%m-%d").date()
|
||||
return None
|
||||
|
||||
@validator("paymentDate", pre=True)
|
||||
def payment_date_validate(cls, v: str): # pylint: disable=E0213
|
||||
if v:
|
||||
return datetime.strptime(v, "%Y-%m-%d").date()
|
||||
return 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)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPHistoricalDividendsQueryParams, api_key: str
|
||||
) -> List[FMPHistoricalDividendsData]:
|
||||
url = create_url(
|
||||
3, f"historical-price-full/stock_dividend/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPHistoricalDividendsData, "historical")
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPHistoricalDividendsData],
|
||||
) -> List[HistoricalDividendsData]:
|
||||
return data_transformer(data, HistoricalDividendsData)
|
||||
@@ -0,0 +1,63 @@
|
||||
"""FMP Historical Stock Splits fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.historical_stock_splits import (
|
||||
HistoricalStockSplitsData,
|
||||
HistoricalStockSplitsQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPHistoricalStockSplitsQueryParams(HistoricalStockSplitsQueryParams):
|
||||
"""FMP Historical Stock Splits query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/earnings-calendar-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPHistoricalStockSplitsQueryParams"
|
||||
|
||||
|
||||
class FMPHistoricalStockSplitsData(HistoricalStockSplitsData):
|
||||
__name__ = "FMPHistoricalStockSplitsData"
|
||||
|
||||
|
||||
class FMPHistoricalStockSplitsFetcher(
|
||||
Fetcher[
|
||||
HistoricalStockSplitsQueryParams,
|
||||
HistoricalStockSplitsData,
|
||||
FMPHistoricalStockSplitsQueryParams,
|
||||
FMPHistoricalStockSplitsData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: HistoricalStockSplitsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPHistoricalStockSplitsQueryParams:
|
||||
return FMPHistoricalStockSplitsQueryParams(symbol=query.symbol)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPHistoricalStockSplitsQueryParams, api_key: str
|
||||
) -> List[FMPHistoricalStockSplitsData]:
|
||||
url = create_url(
|
||||
3, f"historical-price-full/stock_split/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPHistoricalStockSplitsData, "historical")
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPHistoricalStockSplitsData],
|
||||
) -> List[HistoricalStockSplitsData]:
|
||||
return data_transformer(data, HistoricalStockSplitsData)
|
||||
131
openbb_providers/builtin_providers/fmp/income_statement.py
Normal file
131
openbb_providers/builtin_providers/fmp/income_statement.py
Normal file
@@ -0,0 +1,131 @@
|
||||
"""FMP Income Statement Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt, root_validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.income_statement import (
|
||||
IncomeStatementData,
|
||||
IncomeStatementQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
PeriodType = Literal["annual", "quarter"]
|
||||
|
||||
|
||||
class FMPIncomeStatementQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPIncomeStatementQueryParams"
|
||||
symbol: Optional[str]
|
||||
cik: Optional[str]
|
||||
period: PeriodType = Field(default="annual")
|
||||
limit: Optional[NonNegativeInt]
|
||||
|
||||
@root_validator()
|
||||
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 FMPIncomeStatementData(Data):
|
||||
__name__ = "FMPIncomeStatementData"
|
||||
date: dateType
|
||||
symbol: str
|
||||
reportedCurrency: str = Field(alias="currency")
|
||||
cik: Optional[int]
|
||||
fillingDate: Optional[dateType] = Field(alias="filing_date")
|
||||
acceptedDate: Optional[datetime]
|
||||
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]
|
||||
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 {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPIncomeStatementQueryParams, api_key: str
|
||||
) -> List[FMPIncomeStatementData]:
|
||||
url = create_url(
|
||||
3, f"income-statement/{query.symbol}", api_key, query, ["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPIncomeStatementData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPIncomeStatementData],
|
||||
) -> List[IncomeStatementData]:
|
||||
return data_transformer(data, IncomeStatementData)
|
||||
@@ -0,0 +1,118 @@
|
||||
"""FMP Institutional Ownership Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.base import BaseSymbol
|
||||
from openbb_provider.model.data.institutional_ownership import (
|
||||
InstitutionalOwnershipData,
|
||||
InstitutionalOwnershipQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPInstitutionalOwnershipQueryParams(QueryParams, BaseSymbol):
|
||||
"""FMP Institutional Ownership QueryParams.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPInstitutionalOwnershipQueryParams"
|
||||
includeCurrentQuarter: bool = Field(default=False, alias="include_current_quarter")
|
||||
date: Optional[dateType]
|
||||
|
||||
|
||||
class FMPInstitutionalOwnershipData(Data):
|
||||
__name__ = "FMPInstitutionalOwnershipData"
|
||||
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
|
||||
|
||||
@validator("date", pre=True)
|
||||
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 {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPInstitutionalOwnershipQueryParams, api_key: str
|
||||
) -> List[FMPInstitutionalOwnershipData]:
|
||||
url = create_url(4, "institutional-ownership/symbol-ownership", api_key, query)
|
||||
return get_data_many(url, FMPInstitutionalOwnershipData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPInstitutionalOwnershipData],
|
||||
) -> List[InstitutionalOwnershipData]:
|
||||
return data_transformer(data, InstitutionalOwnershipData)
|
||||
139
openbb_providers/builtin_providers/fmp/key_metrics.py
Normal file
139
openbb_providers/builtin_providers/fmp/key_metrics.py
Normal file
@@ -0,0 +1,139 @@
|
||||
"""Key Metrics fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.key_metrics import KeyMetricsData, KeyMetricsQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPKeyMetricsQueryParams(QueryParams):
|
||||
"""FMP Key Metrics QueryParams.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPKeyMetricsQueryParams"
|
||||
|
||||
symbol: str
|
||||
period: Literal["quarter", "annual"] = "annual"
|
||||
limit: Optional[int] = None
|
||||
|
||||
|
||||
class FMPKeyMetricsData(Data):
|
||||
__name__ = "FMPKeyMetricsData"
|
||||
|
||||
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 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",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPKeyMetricsQueryParams, api_key: str
|
||||
) -> List[FMPKeyMetricsData]:
|
||||
url = create_url(
|
||||
3, f"key-metrics/{query.symbol}", api_key, query, exclude=["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPKeyMetricsData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPKeyMetricsData]) -> List[KeyMetricsData]:
|
||||
return data_transformer(data, KeyMetricsData)
|
||||
102
openbb_providers/builtin_providers/fmp/major_indices_eod.py
Normal file
102
openbb_providers/builtin_providers/fmp/major_indices_eod.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""FMP Major Indices end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt, validator
|
||||
|
||||
from builtin_providers.fmp.helpers import get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.major_indices_eod import (
|
||||
MajorIndicesEODData,
|
||||
MajorIndicesEODQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class FMPMajorIndicesEODQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPMajorIndicesEODQueryParams"
|
||||
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
|
||||
|
||||
|
||||
class FMPMajorIndicesEODData(Data):
|
||||
__name__ = "FMPMajorIndicesEODData"
|
||||
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
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_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 {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPMajorIndicesEODQueryParams, api_key: str
|
||||
) -> List[FMPMajorIndicesEODData]:
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
query_str = get_querystring(query.dict(), ["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")
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPMajorIndicesEODData]) -> List[MajorIndicesEODData]:
|
||||
return data_transformer(data, MajorIndicesEODData)
|
||||
@@ -0,0 +1,82 @@
|
||||
"""FMP Major Indices Price fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import QueryParams
|
||||
from openbb_provider.model.data.major_indices_price import (
|
||||
MajorIndicesPriceData,
|
||||
MajorIndicesPriceQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class Interval(str, Enum):
|
||||
oneminute = "1min"
|
||||
fiveminute = "5min"
|
||||
fifteenminute = "15min"
|
||||
thirtyminute = "30min"
|
||||
onehour = "1hour"
|
||||
fourhour = "4hour"
|
||||
|
||||
|
||||
class FMPMajorIndicesPriceQueryParams(QueryParams):
|
||||
"""FMP MajorIndices Price query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Historical-stock-index-prices
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
interval : Enum of ["1min", "5min", "15min", "30min", "1hour", "4hour"] (default: "1hour")
|
||||
The interval of the data.
|
||||
"""
|
||||
|
||||
__name__ = "FMPMajorIndicesPriceQueryParams"
|
||||
symbol: str = Field(min_length=1)
|
||||
interval: Interval = Field(default=Interval.onehour)
|
||||
|
||||
|
||||
class FMPMajorIndicesPriceData(BaseStockPriceData):
|
||||
__name__ = "FMPMajorIndicesPriceData"
|
||||
|
||||
|
||||
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 if extra_params else {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPMajorIndicesPriceQueryParams, api_key: str
|
||||
) -> List[FMPMajorIndicesPriceData]:
|
||||
url = create_url(
|
||||
3, f"historical-chart/{query.interval}/{query.symbol}", api_key
|
||||
)
|
||||
return get_data_many(url, FMPMajorIndicesPriceData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPMajorIndicesPriceData],
|
||||
) -> List[MajorIndicesPriceData]:
|
||||
return data_transformer(data, MajorIndicesPriceData)
|
||||
75
openbb_providers/builtin_providers/fmp/price_target.py
Normal file
75
openbb_providers/builtin_providers/fmp/price_target.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""FMP Stock Ownership fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.price_target import (
|
||||
PriceTargetData,
|
||||
PriceTargetQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPPriceTargetQueryParams(PriceTargetQueryParams):
|
||||
"""FMP Price Target query.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/#Price-Target
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPPriceTargetQueryParams"
|
||||
|
||||
|
||||
class FMPPriceTargetData(Data):
|
||||
__name__ = "FMPPriceTargetData"
|
||||
|
||||
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 FMPPriceTargetFetcher(
|
||||
Fetcher[
|
||||
PriceTargetQueryParams,
|
||||
PriceTargetData,
|
||||
FMPPriceTargetQueryParams,
|
||||
FMPPriceTargetData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: PriceTargetQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPPriceTargetQueryParams:
|
||||
return FMPPriceTargetQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPPriceTargetQueryParams, api_key: str
|
||||
) -> List[FMPPriceTargetData]:
|
||||
url = create_url(4, "price-target", api_key, query)
|
||||
return get_data_many(url, FMPPriceTargetData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPPriceTargetData]) -> List[PriceTargetData]:
|
||||
return data_transformer(data, PriceTargetData)
|
||||
@@ -0,0 +1,79 @@
|
||||
"""FMP Price Target Consensus fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.price_target_consensus import (
|
||||
PriceTargetConsensusData,
|
||||
PriceTargetConsensusQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/price-target-consensus-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPPriceTargetConsensusQueryParams"
|
||||
|
||||
|
||||
class FMPPriceTargetConsensusData(Data):
|
||||
__name__ = "FMPPriceTargetConsensusData"
|
||||
|
||||
symbol: str
|
||||
targetHigh: float
|
||||
targetLow: float
|
||||
targetConsensus: float
|
||||
targetMedian: float
|
||||
|
||||
|
||||
class FMPPriceTargetConsensusFetcher(
|
||||
Fetcher[
|
||||
PriceTargetConsensusQueryParams,
|
||||
PriceTargetConsensusData,
|
||||
FMPPriceTargetConsensusQueryParams,
|
||||
FMPPriceTargetConsensusData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: PriceTargetConsensusQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPPriceTargetConsensusQueryParams:
|
||||
return FMPPriceTargetConsensusQueryParams(symbol=query.symbol)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPPriceTargetConsensusQueryParams, api_key: str
|
||||
) -> List[FMPPriceTargetConsensusData]:
|
||||
url = create_url(4, "price-target-consensus", api_key, query)
|
||||
return get_data_many(url, FMPPriceTargetConsensusData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPPriceTargetConsensusData],
|
||||
) -> List[PriceTargetConsensusData]:
|
||||
return data_transformer(data, PriceTargetConsensusData)
|
||||
95
openbb_providers/builtin_providers/fmp/provider.py
Normal file
95
openbb_providers/builtin_providers/fmp/provider.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""FMP Provider module."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
|
||||
from builtin_providers.fmp.analyst_estimates import FMPAnalystEstimatesFetcher
|
||||
from builtin_providers.fmp.balance_sheet import FMPBalanceSheetFetcher
|
||||
from builtin_providers.fmp.cash_flow import FMPCashFlowStatementFetcher
|
||||
from builtin_providers.fmp.company_profile import FMPCompanyProfileFetcher
|
||||
from builtin_providers.fmp.crypto_eod import FMPCryptoEODFetcher
|
||||
from builtin_providers.fmp.crypto_price import FMPCryptoPriceFetcher
|
||||
from builtin_providers.fmp.earnings_calendar import FMPEarningsCalendarFetcher
|
||||
from builtin_providers.fmp.earnings_call_transcript import (
|
||||
FMPEarningsCallTranscriptFetcher,
|
||||
)
|
||||
from builtin_providers.fmp.esg_risk_rating import FMPESGRiskRatingFetcher
|
||||
from builtin_providers.fmp.esg_score import FMPESGScoreFetcher
|
||||
from builtin_providers.fmp.esg_sector import FMPESGSectorFetcher
|
||||
from builtin_providers.fmp.executive_compensation import FMPExecutiveCompensationFetcher
|
||||
from builtin_providers.fmp.executives import FMPKeyExecutivesFetcher
|
||||
from builtin_providers.fmp.forex_eod import FMPForexEODFetcher
|
||||
from builtin_providers.fmp.forex_price import FMPForexPriceFetcher
|
||||
from builtin_providers.fmp.global_news import FMPGlobalNewsFetcher
|
||||
from builtin_providers.fmp.historical_dividends import FMPHistoricalDividendsFetcher
|
||||
from builtin_providers.fmp.historical_stock_splits import (
|
||||
FMPHistoricalStockSplitsFetcher,
|
||||
)
|
||||
from builtin_providers.fmp.income_statement import FMPIncomeStatementFetcher
|
||||
from builtin_providers.fmp.institutional_ownership import (
|
||||
FMPInstitutionalOwnershipFetcher,
|
||||
)
|
||||
from builtin_providers.fmp.key_metrics import FMPKeyMetricsFetcher
|
||||
from builtin_providers.fmp.major_indices_eod import FMPMajorIndicesEODFetcher
|
||||
from builtin_providers.fmp.major_indices_price import FMPMajorIndicesPriceFetcher
|
||||
from builtin_providers.fmp.price_target import FMPPriceTargetFetcher
|
||||
from builtin_providers.fmp.price_target_consensus import FMPPriceTargetConsensusFetcher
|
||||
from builtin_providers.fmp.revenue_business_line import FMPRevenueBusinessLineFetcher
|
||||
from builtin_providers.fmp.revenue_geographic import FMPRevenueGeographicFetcher
|
||||
from builtin_providers.fmp.sec_filings import FMPSECFilingsFetcher
|
||||
from builtin_providers.fmp.share_stats import FMPShareStatisticsFetcher
|
||||
from builtin_providers.fmp.stock_eod import FMPStockEODFetcher
|
||||
from builtin_providers.fmp.stock_insider_trading import FMPStockInsiderTradingFetcher
|
||||
from builtin_providers.fmp.stock_news import FMPStockNewsFetcher
|
||||
from builtin_providers.fmp.stock_ownership import FMPStockOwnershipFetcher
|
||||
from builtin_providers.fmp.stock_price import FMPStockPriceFetcher
|
||||
from builtin_providers.fmp.treasury_rates import FMPTreasuryRatesFetcher
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.provider.abstract.provider import Provider
|
||||
|
||||
# mypy: disable-error-code="list-item"
|
||||
|
||||
# ignoring because I dont know how to type the string properly
|
||||
fmp_provider = Provider(
|
||||
name="fmp", # type: ignore
|
||||
description="Provider for FMP.",
|
||||
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,
|
||||
FMPHistoricalDividendsFetcher,
|
||||
FMPKeyMetricsFetcher,
|
||||
FMPSECFilingsFetcher,
|
||||
FMPTreasuryRatesFetcher,
|
||||
FMPExecutiveCompensationFetcher,
|
||||
FMPCryptoPriceFetcher,
|
||||
FMPCryptoEODFetcher,
|
||||
FMPMajorIndicesPriceFetcher,
|
||||
FMPForexEODFetcher,
|
||||
FMPForexPriceFetcher,
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
"""FMP Revenue Business Line Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.revenue_business_line import (
|
||||
RevenueBusinessLineData,
|
||||
RevenueBusinessLineQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
# This part is only provided by FMP and not by the other providers for now.
|
||||
|
||||
|
||||
class FMPRevenueBusinessLineQueryParams(RevenueBusinessLineQueryParams):
|
||||
"""FMP Revenue Business Line QueryParams.
|
||||
|
||||
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".
|
||||
"""
|
||||
|
||||
__name__ = "FMPRevenueBusinessLineQueryParams"
|
||||
|
||||
|
||||
class FMPRevenueBusinessLineData(RevenueBusinessLineData):
|
||||
__name__ = "FMPRevenueBusinessLineData"
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_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)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPRevenueBusinessLineQueryParams, api_key: str
|
||||
) -> List[FMPRevenueBusinessLineData]:
|
||||
# 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)
|
||||
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],
|
||||
}
|
||||
for d in data
|
||||
]
|
||||
|
||||
return [FMPRevenueBusinessLineData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPRevenueBusinessLineData],
|
||||
) -> List[RevenueBusinessLineData]:
|
||||
return data_transformer(data, RevenueBusinessLineData)
|
||||
102
openbb_providers/builtin_providers/fmp/revenue_geographic.py
Normal file
102
openbb_providers/builtin_providers/fmp/revenue_geographic.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""FMP Revenue Geographic Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.revenue_geographic import (
|
||||
RevenueGeographicData,
|
||||
RevenueGeographicQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
# 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".
|
||||
"""
|
||||
|
||||
__name__ = "FMPRevenueGeographicQueryParams"
|
||||
|
||||
|
||||
class FMPRevenueGeographicData(RevenueGeographicData):
|
||||
__name__ = "FMPRevenueGeographicData"
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_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.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPRevenueGeographicQueryParams, api_key: str
|
||||
) -> List[FMPRevenueGeographicData]:
|
||||
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)
|
||||
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"),
|
||||
}
|
||||
for d in data
|
||||
]
|
||||
|
||||
return [FMPRevenueGeographicData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPRevenueGeographicData],
|
||||
) -> List[RevenueGeographicData]:
|
||||
# Parse data to RevenueGeographicData
|
||||
return data_transformer(data, RevenueGeographicData)
|
||||
83
openbb_providers/builtin_providers/fmp/sec_filings.py
Normal file
83
openbb_providers/builtin_providers/fmp/sec_filings.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""SEC Filings fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from pydantic import validator
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
from openbb_provider.model.data.sec_filings import SECFilingsData, SECFilingsQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPSECFilingsQueryParams(SECFilingsQueryParams):
|
||||
"""FMP SEC Filings QueryParams.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPSECFilingsQueryParams"
|
||||
|
||||
|
||||
class FMPSECFilingsData(Data):
|
||||
__name__ = "FMPSECFilingsData"
|
||||
|
||||
symbol: str
|
||||
fillingDate: dateType
|
||||
acceptedDate: dateType
|
||||
cik: str
|
||||
type: str
|
||||
link: str
|
||||
finalLink: str
|
||||
|
||||
@validator("fillingDate", "acceptedDate", pre=True)
|
||||
def convert_date(cls, v): # pylint: disable=no-self-argument
|
||||
return datetime.strptime(v, "%Y-%m-%d %H:%M:%S").date()
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPSECFilingsQueryParams, api_key: str
|
||||
) -> List[FMPSECFilingsData]:
|
||||
url = create_url(
|
||||
3, f"sec_filings/{query.symbol}", api_key, query, exclude=["symbol"]
|
||||
)
|
||||
return get_data_many(url, FMPSECFilingsData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPSECFilingsData]) -> List[SECFilingsData]:
|
||||
return data_transformer(data, SECFilingsData)
|
||||
77
openbb_providers/builtin_providers/fmp/share_stats.py
Normal file
77
openbb_providers/builtin_providers/fmp/share_stats.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""FMP Share Statistics Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import validator
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.base import BaseSymbol
|
||||
from openbb_provider.model.data.share_statistics import (
|
||||
ShareStatisticsData,
|
||||
ShareStatisticsQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPShareStatisticsQueryParams(QueryParams, BaseSymbol):
|
||||
"""FMP Income Statement QueryParams.
|
||||
|
||||
Source: https://site.financialmodelingprep.com/developer/docs/shares-float-api/
|
||||
|
||||
Parameter
|
||||
---------
|
||||
symbol : str
|
||||
The symbol of the company.
|
||||
"""
|
||||
|
||||
__name__ = "FMPShareStatisticsQueryParams"
|
||||
|
||||
|
||||
class FMPShareStatisticsData(Data):
|
||||
__name__ = "FMPShareStatisticsData"
|
||||
symbol: str
|
||||
date: dateType
|
||||
freeFloat: float
|
||||
floatShares: float
|
||||
outstandingShares: float
|
||||
source: str
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_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)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPShareStatisticsQueryParams, api_key: str
|
||||
) -> List[FMPShareStatisticsData]:
|
||||
url = create_url(4, "shares_float", api_key, query)
|
||||
return get_data_many(url, FMPShareStatisticsData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPShareStatisticsData],
|
||||
) -> List[ShareStatisticsData]:
|
||||
return data_transformer(data, ShareStatisticsData)
|
||||
99
openbb_providers/builtin_providers/fmp/stock_eod.py
Normal file
99
openbb_providers/builtin_providers/fmp/stock_eod.py
Normal file
@@ -0,0 +1,99 @@
|
||||
"""FMP Stocks end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date, datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt, validator
|
||||
|
||||
from builtin_providers.fmp.helpers import get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.stock_eod import StockEODData, StockEODQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class FMPStockEODQueryParams(QueryParams):
|
||||
"""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.
|
||||
serietype : Optional[Literal["line"]]
|
||||
The type of the series. Only "line" is supported.
|
||||
"""
|
||||
|
||||
__name__ = "FMPStockEODQueryParams"
|
||||
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
|
||||
|
||||
|
||||
class FMPStockEODData(Data):
|
||||
__name__ = "FMPStockEODData"
|
||||
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
|
||||
|
||||
@validator("date", pre=True)
|
||||
def time_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:
|
||||
raw_end = query.end_date if query.end_date else datetime.now()
|
||||
return FMPStockEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=raw_end,
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockEODQueryParams, api_key: str
|
||||
) -> List[FMPStockEODData]:
|
||||
base_url = "https://financialmodelingprep.com/api/v3/"
|
||||
query_str = get_querystring(query.dict(), ["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")
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockEODData]) -> List[StockEODData]:
|
||||
return data_transformer(data, StockEODData)
|
||||
@@ -0,0 +1,74 @@
|
||||
"""FMP Stock Insider Trading fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.stock_insider_trading import (
|
||||
StockInsiderTradingData,
|
||||
StockInsiderTradingQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPStockInsiderTradingQueryParams(StockInsiderTradingQueryParams):
|
||||
"""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 : Optional[str]
|
||||
The symbol of the company.
|
||||
reportingCik : Optional[str]
|
||||
The CIK of the reporting owner.
|
||||
companyCik: Optional[str]
|
||||
The CIK of the company owner.
|
||||
page: int
|
||||
The page number to get
|
||||
"""
|
||||
|
||||
__name__ = "FMPStockInsiderTradingQueryParams"
|
||||
|
||||
|
||||
class FMPStockInsiderTradingData(StockInsiderTradingData):
|
||||
__name__ = "FMPStockInsiderTradingData"
|
||||
|
||||
|
||||
class FMPStockInsiderTradingFetcher(
|
||||
Fetcher[
|
||||
StockInsiderTradingQueryParams,
|
||||
StockInsiderTradingData,
|
||||
FMPStockInsiderTradingQueryParams,
|
||||
FMPStockInsiderTradingData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockInsiderTradingQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockInsiderTradingQueryParams:
|
||||
return FMPStockInsiderTradingQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockInsiderTradingQueryParams, api_key: str
|
||||
) -> List[FMPStockInsiderTradingData]:
|
||||
# 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)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[FMPStockInsiderTradingData],
|
||||
) -> List[StockInsiderTradingData]:
|
||||
return data_transformer(data, StockInsiderTradingData)
|
||||
78
openbb_providers/builtin_providers/fmp/stock_news.py
Normal file
78
openbb_providers/builtin_providers/fmp/stock_news.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""FMP Stock News fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeInt
|
||||
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.stock_news import StockNewsData, StockNewsQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class FMPStockNewsQueryParams(QueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPStockNewsQueryParams"
|
||||
tickers: str = Field(min_length=1, alias="symbols")
|
||||
page: int = Field(default=0)
|
||||
limit: Optional[NonNegativeInt]
|
||||
|
||||
|
||||
class FMPStockNewsData(Data):
|
||||
__name__ = "FMPStockNewsData"
|
||||
symbol: str
|
||||
publishedDate: datetime = Field(alias="date")
|
||||
title: str
|
||||
image: Optional[str]
|
||||
text: str
|
||||
url: str
|
||||
site: str
|
||||
|
||||
|
||||
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 {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockNewsQueryParams, api_key: str
|
||||
) -> List[FMPStockNewsData]:
|
||||
url = create_url(3, "stock_news", api_key, query)
|
||||
return get_data_many(url, FMPStockNewsData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockNewsData]) -> List[StockNewsData]:
|
||||
return data_transformer(data, StockNewsData)
|
||||
68
openbb_providers/builtin_providers/fmp/stock_ownership.py
Normal file
68
openbb_providers/builtin_providers/fmp/stock_ownership.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""FMP Stock Ownership fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.fmp.helpers import create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.stock_ownership import (
|
||||
StockOwnershipData,
|
||||
StockOwnershipQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPStockOwnershipQueryParams"
|
||||
|
||||
|
||||
class FMPStockOwnershipData(StockOwnershipData):
|
||||
__name__ = "FMPStockOwnershipData"
|
||||
|
||||
|
||||
class FMPStockOwnershipFetcher(
|
||||
Fetcher[
|
||||
StockOwnershipQueryParams,
|
||||
StockOwnershipData,
|
||||
FMPStockOwnershipQueryParams,
|
||||
FMPStockOwnershipData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockOwnershipQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> FMPStockOwnershipQueryParams:
|
||||
return FMPStockOwnershipQueryParams.parse_obj(query)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPStockOwnershipQueryParams, api_key: str
|
||||
) -> List[FMPStockOwnershipData]:
|
||||
url = create_url(
|
||||
4,
|
||||
"institutional-ownership/institutional-holders/symbol-ownership-percent",
|
||||
api_key,
|
||||
query,
|
||||
)
|
||||
return get_data_many(url, FMPStockOwnershipData)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPStockOwnershipData]) -> List[StockOwnershipData]:
|
||||
return data_transformer(data, StockOwnershipData)
|
||||
77
openbb_providers/builtin_providers/fmp/stock_price.py
Normal file
77
openbb_providers/builtin_providers/fmp/stock_price.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""FMP Stock Price fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import BaseStockPriceData, create_url, get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import QueryParams
|
||||
from openbb_provider.model.data.stock_price import StockPriceData, StockPriceQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPStockPriceQueryParams"
|
||||
symbol: str = Field(min_length=1)
|
||||
interval: Literal["1min", "5min", "15min", "30min", "1hour", "4hour"] = "1hour"
|
||||
|
||||
|
||||
class FMPStockPriceData(BaseStockPriceData):
|
||||
__name__ = "FMPStockPriceData"
|
||||
|
||||
|
||||
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, api_key: str
|
||||
) -> List[FMPStockPriceData]:
|
||||
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)
|
||||
83
openbb_providers/builtin_providers/fmp/treasury_rates.py
Normal file
83
openbb_providers/builtin_providers/fmp/treasury_rates.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""FMP Treasury Rates fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.fmp.helpers import get_data_many
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
from openbb_provider.model.data.treasury_rates import (
|
||||
TreasuryRatesData,
|
||||
TreasuryRatesQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class FMPTreasuryRatesQueryParams(TreasuryRatesQueryParams):
|
||||
"""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.
|
||||
"""
|
||||
|
||||
__name__ = "FMPTreasuryRatesQueryParams"
|
||||
|
||||
|
||||
class FMPTreasuryRatesData(Data):
|
||||
__name__ = "FMPTreasuryRatesData"
|
||||
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 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
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: FMPTreasuryRatesQueryParams, api_key: str
|
||||
) -> List[FMPTreasuryRatesData]:
|
||||
base_url = "https://financialmodelingprep.com/api/v4/"
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[FMPTreasuryRatesData]) -> List[TreasuryRatesData]:
|
||||
return data_transformer(data, TreasuryRatesData)
|
||||
100
openbb_providers/builtin_providers/polygon/balance_sheet.py
Normal file
100
openbb_providers/builtin_providers/polygon/balance_sheet.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import PolygonFundamentalQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
from openbb_provider.model.data.balance_sheet import (
|
||||
BalanceSheetData,
|
||||
BalanceSheetQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class PolygonBalanceSheetQueryParams(PolygonFundamentalQueryParams):
|
||||
"""Source: https://polygon.io/docs/stocks#!/get_vx_reference_financials"""
|
||||
|
||||
__name__ = "PolygonBalanceSheetQueryParams"
|
||||
|
||||
|
||||
class PolygonBalanceSheetData(Data):
|
||||
__name__ = "PolygonBalanceSheetData"
|
||||
cik: Optional[str]
|
||||
start_date: dateType = Field(alias="date")
|
||||
assets: Optional[int]
|
||||
current_assets: Optional[int]
|
||||
current_liabilities: Optional[int]
|
||||
equity: Optional[int]
|
||||
equity_attributable_to_noncontrolling_interest: Optional[int]
|
||||
equity_attributable_to_parent: Optional[int]
|
||||
liabilities: Optional[int]
|
||||
liabilities_and_equity: Optional[int]
|
||||
noncurrent_assets: Optional[int]
|
||||
noncurrent_liabilities: Optional[int]
|
||||
|
||||
|
||||
class PolygonBalanceSheetFetcher(
|
||||
Fetcher[
|
||||
BalanceSheetQueryParams,
|
||||
BalanceSheetData,
|
||||
PolygonBalanceSheetQueryParams,
|
||||
PolygonBalanceSheetData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: BalanceSheetQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonBalanceSheetQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarterly"
|
||||
return PolygonBalanceSheetQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonBalanceSheetQueryParams, api_key: str
|
||||
) -> List[PolygonBalanceSheetData]:
|
||||
base_url = "https://api.polygon.io/vX/reference/financials"
|
||||
query_string = get_querystring(query.dict(), [])
|
||||
request_url = f"{base_url}?{query_string}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No balance sheet found")
|
||||
|
||||
to_return = []
|
||||
for item in data:
|
||||
new = {"start_date": item["start_date"]}
|
||||
new["cik"] = item["cik"]
|
||||
bs = item["financials"]["balance_sheet"]
|
||||
new["assets"] = bs["assets"].get("value")
|
||||
new["current_assets"] = bs["current_assets"].get("value")
|
||||
new["current_liabilities"] = bs["current_liabilities"].get("value")
|
||||
new["equity"] = bs["equity"].get("value")
|
||||
new["equity_attributable_to_noncontrolling_interest"] = bs[
|
||||
"equity_attributable_to_noncontrolling_interest"
|
||||
].get("value")
|
||||
new["equity_attributable_to_parent"] = bs[
|
||||
"equity_attributable_to_parent"
|
||||
].get("value")
|
||||
new["equity"] = bs["equity"].get("value")
|
||||
new["liabilities"] = bs["liabilities"].get("value")
|
||||
new["liabilities_and_equity"] = bs["liabilities_and_equity"].get("value")
|
||||
new["noncurrent_assets"] = bs["noncurrent_assets"].get("value")
|
||||
new["noncurrent_liabilities"] = bs["noncurrent_liabilities"].get("value")
|
||||
|
||||
to_return.append(PolygonBalanceSheetData(**new))
|
||||
return to_return
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonBalanceSheetData],
|
||||
) -> List[BalanceSheetData]:
|
||||
return data_transformer(data, BalanceSheetData)
|
||||
118
openbb_providers/builtin_providers/polygon/cash_flow.py
Normal file
118
openbb_providers/builtin_providers/polygon/cash_flow.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import PolygonFundamentalQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
from openbb_provider.model.data.cash_flows import (
|
||||
CashFlowStatementData,
|
||||
CashFlowStatementQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
# noqa: E501
|
||||
|
||||
|
||||
class PolygonCashFlowStatementQueryParams(PolygonFundamentalQueryParams):
|
||||
"""Source: https://polygon.io/docs/stocks#!/get_vx_reference_financials"""
|
||||
|
||||
__name__ = "PolygonCashFlowStatementQueryParams"
|
||||
|
||||
|
||||
class PolygonCashFlowStatementData(Data):
|
||||
__name__ = "PolygonCashFlowStatementData"
|
||||
start_date: dateType = Field(alias="date")
|
||||
tickers: Optional[List[str]] = Field(alias="symbol")
|
||||
cik: Optional[str]
|
||||
filing_date: dateType
|
||||
acceptance_datetime: Optional[datetime]
|
||||
fiscal_period: Optional[str] = Field(alias="period")
|
||||
# exchange_gain_losses: int
|
||||
net_cash_flow: int
|
||||
net_cash_flow_from_financing_activities: int
|
||||
net_cash_flow_from_investing_activities: int
|
||||
net_cash_flow_from_operating_activities: int
|
||||
net_cash_flow_continuing: int
|
||||
net_cash_flow_from_financing_activities_continuing: int
|
||||
net_cash_flow_from_investing_activities_continuing: int
|
||||
net_cash_flow_from_operating_activities_continuing: int
|
||||
|
||||
|
||||
class PolygonCashFlowStatementFetcher(
|
||||
Fetcher[
|
||||
CashFlowStatementQueryParams,
|
||||
CashFlowStatementData,
|
||||
PolygonCashFlowStatementQueryParams,
|
||||
PolygonCashFlowStatementData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CashFlowStatementQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonCashFlowStatementQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarterly"
|
||||
return PolygonCashFlowStatementQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonCashFlowStatementQueryParams, api_key: str
|
||||
) -> List[PolygonCashFlowStatementData]:
|
||||
base_url = "https://api.polygon.io/vX/reference/financials"
|
||||
query_string = get_querystring(query.dict(), [])
|
||||
request_url = f"{base_url}?{query_string}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No Cash Flow Statement found")
|
||||
|
||||
to_return = []
|
||||
for item in data:
|
||||
new = {"acceptance_datetime": item.get("acceptance_datetime")}
|
||||
new["start_date"] = item["start_date"]
|
||||
new["filing_date"] = item.get("filing_date")
|
||||
new["cik"] = item["cik"]
|
||||
new["fiscal_period"] = item["fiscal_period"]
|
||||
new["tickers"] = item["tickers"]
|
||||
cf = item["financials"]["cash_flow_statement"]
|
||||
new["net_cash_flow_from_financing_activities"] = cf[
|
||||
"net_cash_flow_from_financing_activities"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_investing_activities"] = cf[
|
||||
"net_cash_flow_from_investing_activities"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_operating_activities"] = cf[
|
||||
"net_cash_flow_from_operating_activities"
|
||||
].get("value")
|
||||
new["net_cash_flow_continuing"] = cf["net_cash_flow_continuing"].get(
|
||||
"value"
|
||||
)
|
||||
new["net_cash_flow_from_financing_activities_continuing"] = cf[
|
||||
"net_cash_flow_from_financing_activities_continuing"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_investing_activities_continuing"] = cf[
|
||||
"net_cash_flow_from_investing_activities_continuing"
|
||||
].get("value")
|
||||
new["net_cash_flow_from_operating_activities_continuing"] = cf[
|
||||
"net_cash_flow_from_operating_activities_continuing"
|
||||
].get("value")
|
||||
new["net_cash_flow"] = cf["net_cash_flow"].get("value")
|
||||
|
||||
to_return.append(PolygonCashFlowStatementData(**new))
|
||||
return to_return
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonCashFlowStatementData],
|
||||
) -> List[CashFlowStatementData]:
|
||||
processors = {"tickers": lambda x: "" if not x else ",".join(x)}
|
||||
return data_transformer(data, CashFlowStatementData, processors)
|
||||
97
openbb_providers/builtin_providers/polygon/crypto_eod.py
Normal file
97
openbb_providers/builtin_providers/polygon/crypto_eod.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""Polygon crypto end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.crypto_eod import CryptoEODData, CryptoEODQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonCryptoEODQueryParams(BaseStockQueryParams):
|
||||
"""Polygon crypto end of day query.
|
||||
|
||||
Source: https://polygon.io/docs/crypto/get_v2_aggs_ticker__cryptoticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonCryptoEODQueryParams"
|
||||
|
||||
|
||||
class PolygonCryptoEODData(BaseStockData):
|
||||
__name__ = "PolygonEODCryptoData"
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: PositiveFloat
|
||||
|
||||
|
||||
class PolygonCryptoEODFetcher(
|
||||
Fetcher[
|
||||
CryptoEODQueryParams,
|
||||
CryptoEODData,
|
||||
PolygonCryptoEODQueryParams,
|
||||
PolygonCryptoEODData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CryptoEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonCryptoEODQueryParams:
|
||||
return PolygonCryptoEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonCryptoEODQueryParams, api_key: str
|
||||
) -> List[PolygonCryptoEODData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"X:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonCryptoEODData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonCryptoEODData]) -> List[CryptoEODData]:
|
||||
return data_transformer(data, CryptoEODData)
|
||||
100
openbb_providers/builtin_providers/polygon/crypto_price.py
Normal file
100
openbb_providers/builtin_providers/polygon/crypto_price.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""Polygon Crypto Price fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.crypto_price import (
|
||||
CryptoPriceData,
|
||||
CryptoPriceQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonCryptoPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon crypto price query.
|
||||
|
||||
Source: https://polygon.io/docs/crypto/get_v2_aggs_ticker__cryptoticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stocksTicker : str
|
||||
The ticker symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonCryptoPriceQueryParams"
|
||||
|
||||
|
||||
class PolygonCryptoPriceData(BaseStockData):
|
||||
__name__ = "PolygonPriceCryptoData"
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: PositiveFloat
|
||||
|
||||
|
||||
class PolygonCryptoPriceFetcher(
|
||||
Fetcher[
|
||||
CryptoPriceQueryParams,
|
||||
CryptoPriceData,
|
||||
PolygonCryptoPriceQueryParams,
|
||||
PolygonCryptoPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: CryptoPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonCryptoPriceQueryParams:
|
||||
return PolygonCryptoPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonCryptoPriceQueryParams, api_key: str
|
||||
) -> List[PolygonCryptoPriceData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"X:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonCryptoPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonCryptoPriceData]) -> List[CryptoPriceData]:
|
||||
return data_transformer(data, CryptoPriceData)
|
||||
97
openbb_providers/builtin_providers/polygon/forex_eod.py
Normal file
97
openbb_providers/builtin_providers/polygon/forex_eod.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""Polygon forex end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.forex_eod import ForexEODData, ForexEODQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonForexEODQueryParams(BaseStockQueryParams):
|
||||
"""Polygon forex end of day query.
|
||||
|
||||
Source: https://polygon.io/docs/forex/get_v2_aggs_ticker__forexticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stocksTicker : str
|
||||
The ticker symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonForexEODQueryParams"
|
||||
|
||||
|
||||
class PolygonForexEODData(BaseStockData):
|
||||
__name__ = "PolygonEODForexData"
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: Optional[PositiveFloat]
|
||||
|
||||
|
||||
class PolygonForexEODFetcher(
|
||||
Fetcher[
|
||||
ForexEODQueryParams,
|
||||
ForexEODData,
|
||||
PolygonForexEODQueryParams,
|
||||
PolygonForexEODData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ForexEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonForexEODQueryParams:
|
||||
return PolygonForexEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonForexEODQueryParams, api_key: str
|
||||
) -> List[PolygonForexEODData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"C:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonForexEODData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonForexEODData]) -> List[ForexEODData]:
|
||||
return data_transformer(data, ForexEODData)
|
||||
97
openbb_providers/builtin_providers/polygon/forex_price.py
Normal file
97
openbb_providers/builtin_providers/polygon/forex_price.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""Polygon Forex Price fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.forex_price import ForexPriceData, ForexPriceQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonForexPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon forex price query.
|
||||
|
||||
Source: https://polygon.io/docs/forex/get_v2_aggs_ticker__forexticker__range__multiplier___timespan___from___to
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stocksTicker : str
|
||||
The ticker symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonForexPriceQueryParams"
|
||||
|
||||
|
||||
class PolygonForexPriceData(BaseStockData):
|
||||
__name__ = "PolygonPriceForexData"
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: Optional[PositiveFloat]
|
||||
|
||||
|
||||
class PolygonForexPriceFetcher(
|
||||
Fetcher[
|
||||
ForexPriceQueryParams,
|
||||
ForexPriceData,
|
||||
PolygonForexPriceQueryParams,
|
||||
PolygonForexPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: ForexPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonForexPriceQueryParams:
|
||||
return PolygonForexPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonForexPriceQueryParams, api_key: str
|
||||
) -> List[PolygonForexPriceData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"C:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonForexPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonForexPriceData]) -> List[ForexPriceData]:
|
||||
return data_transformer(data, ForexPriceData)
|
||||
19
openbb_providers/builtin_providers/polygon/helpers.py
Normal file
19
openbb_providers/builtin_providers/polygon/helpers.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# IMPORT STANDARD
|
||||
|
||||
|
||||
# IMPORT THIRD PARTY
|
||||
import requests
|
||||
|
||||
# IMPORT INTERNAL
|
||||
|
||||
|
||||
def get_data(url: str) -> dict:
|
||||
r = requests.get(url, timeout=10)
|
||||
if r.status_code != 200:
|
||||
data = r.json()
|
||||
message = data.get("message")
|
||||
error = data.get("error")
|
||||
value = message or error
|
||||
raise RuntimeError(f"Error in Polygon request: {value}")
|
||||
|
||||
return r.json()
|
||||
155
openbb_providers/builtin_providers/polygon/income_statement.py
Normal file
155
openbb_providers/builtin_providers/polygon/income_statement.py
Normal file
@@ -0,0 +1,155 @@
|
||||
# IMPORT STANDARD
|
||||
from datetime import date as dateType
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import PolygonFundamentalQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data
|
||||
from openbb_provider.model.data.income_statement import (
|
||||
IncomeStatementData,
|
||||
IncomeStatementQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class PolygonIncomeStatementQueryParams(PolygonFundamentalQueryParams):
|
||||
"""Source: https://polygon.io/docs/stocks#!/get_vx_reference_financials"""
|
||||
|
||||
__name__ = "PolygonIncomeStatementQueryParams"
|
||||
|
||||
|
||||
class PolygonIncomeStatementData(Data):
|
||||
__name__ = "PolygonIncomeStatementData"
|
||||
start_date: dateType = Field(alias="date")
|
||||
tickers: Optional[List[str]] = Field(alias="symbol")
|
||||
cik: Optional[str]
|
||||
filing_date: dateType
|
||||
acceptance_datetime: Optional[datetime] = Field(alias="accepted_date")
|
||||
fiscal_period: Optional[str] = Field(alias="period")
|
||||
revenues: Optional[float] = Field(alias="revenue")
|
||||
cost_of_revenue: Optional[float]
|
||||
gross_profit: Optional[float]
|
||||
operating_expenses: Optional[float]
|
||||
costs_and_expenses: Optional[float]
|
||||
income_loss_from_continuing_operations_before_tax: Optional[float] = Field(
|
||||
alias="income_before_tax"
|
||||
)
|
||||
income_loss_from_continuing_operations_after_tax: Optional[float]
|
||||
income_tax_expense_benefit: Optional[float] = Field(alias="income_tax_expense")
|
||||
net_income_loss: Optional[float] = Field(alias="net_income")
|
||||
basic_earnings_per_share: Optional[float] = Field(alias="eps")
|
||||
diluted_earnings_per_share: Optional[float] = Field(alias="eps_diluted")
|
||||
benefits_costs_expenses: Optional[float]
|
||||
interest_expense_operating: Optional[float] = Field(alias="interest_expense")
|
||||
net_income_loss_attributable_to_noncontrolling_interest: Optional[int]
|
||||
net_income_loss_attributable_to_parent: Optional[float]
|
||||
net_income_loss_available_to_common_stockholders_basic: Optional[float]
|
||||
operating_income_loss: Optional[float]
|
||||
participating_securities_distributed_and_undistributed_earnings_loss_basic: Optional[
|
||||
float
|
||||
]
|
||||
preferred_stock_dividends_and_other_adjustments: Optional[float]
|
||||
|
||||
|
||||
class PolygonIncomeStatementFetcher(
|
||||
Fetcher[
|
||||
IncomeStatementQueryParams,
|
||||
IncomeStatementData,
|
||||
PolygonIncomeStatementQueryParams,
|
||||
PolygonIncomeStatementData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: IncomeStatementQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonIncomeStatementQueryParams:
|
||||
period = "annual" if query.period == "annually" else "quarterly"
|
||||
return PolygonIncomeStatementQueryParams(
|
||||
symbol=query.symbol, period=period, **extra_params if extra_params else {} # type: ignore
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonIncomeStatementQueryParams, api_key: str
|
||||
) -> List[PolygonIncomeStatementData]:
|
||||
base_url = "https://api.polygon.io/vX/reference/financials"
|
||||
query_string = get_querystring(query.dict(), [])
|
||||
request_url = f"{base_url}?{query_string}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No Income Statement found")
|
||||
|
||||
to_return = []
|
||||
for item in data:
|
||||
new = {"acceptance_datetime": item.get("acceptance_datetime")}
|
||||
new["start_date"] = item["start_date"]
|
||||
new["filing_date"] = item.get("filing_date")
|
||||
new["cik"] = item["cik"]
|
||||
new["fiscal_period"] = item["fiscal_period"]
|
||||
new["tickers"] = item["tickers"]
|
||||
to_return.append(PolygonIncomeStatementData(**new))
|
||||
incs = item["financials"]["income_statement"]
|
||||
new["revenues"] = incs["revenues"].get("value")
|
||||
new["cost_of_revenue"] = incs["cost_of_revenue"].get("value")
|
||||
new["gross_profit"] = incs["gross_profit"].get("value")
|
||||
new["operating_expenses"] = incs["operating_expenses"].get("value")
|
||||
new["costs_and_expenses"] = incs["costs_and_expenses"].get("value")
|
||||
new["income_loss_from_continuing_operations_before_tax"] = incs[
|
||||
"income_loss_from_continuing_operations_before_tax"
|
||||
].get("value")
|
||||
new["income_tax_expense_benefit"] = incs["income_tax_expense_benefit"].get(
|
||||
"value"
|
||||
)
|
||||
new["net_income_loss"] = incs["net_income_loss"].get("value")
|
||||
new["basic_earnings_per_share"] = incs.get(
|
||||
"basic_earnings_per_share", {}
|
||||
).get("value")
|
||||
new["diluted_earnings_per_share"] = incs.get(
|
||||
"diluted_earnings_per_share", {}
|
||||
).get("value")
|
||||
new["net_income_loss_attributable_to_noncontrolling_interest"] = incs[
|
||||
"net_income_loss_attributable_to_noncontrolling_interest"
|
||||
].get("value")
|
||||
new["net_income_loss_attributable_to_parent"] = incs[
|
||||
"net_income_loss_attributable_to_parent"
|
||||
].get("value")
|
||||
new["net_income_loss_available_to_common_stockholders_basic"] = incs[
|
||||
"net_income_loss_available_to_common_stockholders_basic"
|
||||
].get("value")
|
||||
new["operating_income_loss"] = incs["operating_income_loss"].get("value")
|
||||
new[
|
||||
"participating_securities_distributed_and_undistributed_earnings_loss_basic"
|
||||
] = incs[
|
||||
"participating_securities_distributed_and_undistributed_earnings_loss_basic"
|
||||
].get(
|
||||
"value"
|
||||
)
|
||||
new["preferred_stock_dividends_and_other_adjustments"] = incs[
|
||||
"preferred_stock_dividends_and_other_adjustments"
|
||||
].get("value")
|
||||
new["income_loss_from_continuing_operations_after_tax"] = incs[
|
||||
"income_loss_from_continuing_operations_after_tax"
|
||||
].get("value")
|
||||
new["benefits_costs_expenses"] = incs["benefits_costs_expenses"].get(
|
||||
"value"
|
||||
)
|
||||
new["interest_expense_operating"] = incs["interest_expense_operating"].get(
|
||||
"value"
|
||||
)
|
||||
to_return.append(PolygonIncomeStatementData(**new))
|
||||
return to_return
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonIncomeStatementData],
|
||||
) -> List[IncomeStatementData]:
|
||||
processors = {"tickers": lambda x: "" if not x else ",".join(x)}
|
||||
return data_transformer(data, IncomeStatementData, processors)
|
||||
@@ -0,0 +1,97 @@
|
||||
"""Polygon major indices end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.major_indices_eod import (
|
||||
MajorIndicesEODData,
|
||||
MajorIndicesEODQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonMajorIndicesEODQueryParams(BaseStockQueryParams):
|
||||
"""Polygon major indices end of day query.
|
||||
|
||||
Source: https://polygon.io/docs/indices/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonMajorIndicesEODQueryParams"
|
||||
|
||||
|
||||
class PolygonMajorIndicesEODData(BaseStockData):
|
||||
__name__ = "PolygonEODMajorIndicesData"
|
||||
|
||||
|
||||
class PolygonMajorIndicesEODFetcher(
|
||||
Fetcher[
|
||||
MajorIndicesEODQueryParams,
|
||||
MajorIndicesEODData,
|
||||
PolygonMajorIndicesEODQueryParams,
|
||||
PolygonMajorIndicesEODData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: MajorIndicesEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonMajorIndicesEODQueryParams:
|
||||
return PolygonMajorIndicesEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonMajorIndicesEODQueryParams, api_key: str
|
||||
) -> List[PolygonMajorIndicesEODData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"I:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonMajorIndicesEODData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonMajorIndicesEODData],
|
||||
) -> List[MajorIndicesEODData]:
|
||||
return data_transformer(data, MajorIndicesEODData)
|
||||
@@ -0,0 +1,97 @@
|
||||
"""Polygon major indices end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.major_indices_price import (
|
||||
MajorIndicesPriceData,
|
||||
MajorIndicesPriceQueryParams,
|
||||
)
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonMajorIndicesPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon major indices price query.
|
||||
|
||||
Source: https://polygon.io/docs/indices/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonMajorIndicesPriceQueryParams"
|
||||
|
||||
|
||||
class PolygonMajorIndicesPriceData(BaseStockData):
|
||||
__name__ = "PolygonPriceMajorIndicesData"
|
||||
|
||||
|
||||
class PolygonMajorIndicesPriceFetcher(
|
||||
Fetcher[
|
||||
MajorIndicesPriceQueryParams,
|
||||
MajorIndicesPriceData,
|
||||
PolygonMajorIndicesPriceQueryParams,
|
||||
PolygonMajorIndicesPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: MajorIndicesPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonMajorIndicesPriceQueryParams:
|
||||
return PolygonMajorIndicesPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonMajorIndicesPriceQueryParams, api_key: str
|
||||
) -> List[PolygonMajorIndicesPriceData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"I:{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonMajorIndicesPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonMajorIndicesPriceData],
|
||||
) -> List[MajorIndicesPriceData]:
|
||||
return data_transformer(data, MajorIndicesPriceData)
|
||||
44
openbb_providers/builtin_providers/polygon/provider.py
Normal file
44
openbb_providers/builtin_providers/polygon/provider.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""Polygon provider module."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
|
||||
from builtin_providers.polygon.balance_sheet import PolygonBalanceSheetFetcher
|
||||
from builtin_providers.polygon.cash_flow import PolygonCashFlowStatementFetcher
|
||||
from builtin_providers.polygon.crypto_eod import PolygonCryptoEODFetcher
|
||||
from builtin_providers.polygon.crypto_price import PolygonCryptoPriceFetcher
|
||||
from builtin_providers.polygon.forex_eod import PolygonForexEODFetcher
|
||||
from builtin_providers.polygon.forex_price import PolygonForexPriceFetcher
|
||||
from builtin_providers.polygon.income_statement import PolygonIncomeStatementFetcher
|
||||
from builtin_providers.polygon.major_indices_eod import PolygonMajorIndicesEODFetcher
|
||||
from builtin_providers.polygon.major_indices_price import (
|
||||
PolygonMajorIndicesPriceFetcher,
|
||||
)
|
||||
from builtin_providers.polygon.stock_eod import PolygonStockEODFetcher
|
||||
from builtin_providers.polygon.stock_news import PolygonStockNewsFetcher
|
||||
from builtin_providers.polygon.stock_price import PolygonStockPriceFetcher
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.provider.abstract.provider import Provider
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
|
||||
# mypy: disable-error-code="list-item"
|
||||
# ignoring because I dont know how to type the string properly
|
||||
polygon_provider = Provider(
|
||||
name="polygon", # type: ignore
|
||||
description="Provider for Polygon.",
|
||||
fetcher_list=[
|
||||
PolygonStockEODFetcher,
|
||||
PolygonStockNewsFetcher,
|
||||
PolygonBalanceSheetFetcher,
|
||||
PolygonIncomeStatementFetcher,
|
||||
PolygonCashFlowStatementFetcher,
|
||||
PolygonStockPriceFetcher,
|
||||
PolygonCryptoPriceFetcher,
|
||||
PolygonCryptoEODFetcher,
|
||||
PolygonMajorIndicesEODFetcher,
|
||||
PolygonMajorIndicesPriceFetcher,
|
||||
PolygonForexEODFetcher,
|
||||
PolygonForexPriceFetcher,
|
||||
],
|
||||
)
|
||||
97
openbb_providers/builtin_providers/polygon/stock_eod.py
Normal file
97
openbb_providers/builtin_providers/polygon/stock_eod.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""Polygon stocks end of day fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.stock_eod import StockEODData, StockEODQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonStockEODQueryParams(BaseStockQueryParams):
|
||||
"""Polygon stocks end of day query.
|
||||
|
||||
Source: https://polygon.io/docs/stocks/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonStockEODQueryParams"
|
||||
|
||||
|
||||
class PolygonStockEODData(BaseStockData):
|
||||
__name__ = "PolygonEODStockData"
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: PositiveFloat
|
||||
|
||||
|
||||
class PolygonStockEODFetcher(
|
||||
Fetcher[
|
||||
StockEODQueryParams,
|
||||
StockEODData,
|
||||
PolygonStockEODQueryParams,
|
||||
PolygonStockEODData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockEODQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonStockEODQueryParams:
|
||||
return PolygonStockEODQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonStockEODQueryParams, api_key: str
|
||||
) -> List[PolygonStockEODData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonStockEODData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonStockEODData]) -> List[StockEODData]:
|
||||
return data_transformer(data, StockEODData)
|
||||
129
openbb_providers/builtin_providers/polygon/stock_news.py
Normal file
129
openbb_providers/builtin_providers/polygon/stock_news.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""Polygon Stock News Fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Literal, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.data.stock_news import StockNewsData, StockNewsQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer, get_querystring
|
||||
|
||||
|
||||
class PolygonStockNewsQueryParams(QueryParams):
|
||||
"""Polygon stock news query.
|
||||
|
||||
Source: https://polygon.io/docs/stocks/get_v2_reference_news
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
ticker_lt : str, optional
|
||||
Less than, by default None
|
||||
ticker_lte : str, optional
|
||||
Less than or equal, by default None
|
||||
ticker_gt : str, optional
|
||||
Greater than, by default None
|
||||
ticker_gte : str, optional
|
||||
Greater than or equal, by default None
|
||||
published_utc : str, optional
|
||||
The published date of the query, by default None
|
||||
published_utc_lt : str, optional
|
||||
Less than, by default None
|
||||
published_utc_lte : str, optional
|
||||
Less than or equal, by default None
|
||||
published_utc_gt : str, optional
|
||||
Greater than, by default None
|
||||
published_utc_gte : str, optional
|
||||
Greater than or equal, by default None
|
||||
order : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default None
|
||||
limit : int, optional
|
||||
The limit of the query, by default 100
|
||||
sort : str, optional
|
||||
The sort of the query, by default None
|
||||
"""
|
||||
|
||||
__name__ = "PolygonStockNewsQueryParams"
|
||||
ticker: str = Field(alias="symbols")
|
||||
ticker_lt: Optional[str] = Field(alias="ticker.lt", default=None)
|
||||
ticker_lte: Optional[str] = Field(alias="ticker.lte", default=None)
|
||||
ticker_gt: Optional[str] = Field(alias="ticker.gt", default=None)
|
||||
ticker_gte: Optional[str] = Field(alias="ticker.gte", default=None)
|
||||
published_utc: Optional[str] = None
|
||||
published_utc_lt: Optional[str] = Field(alias="published_utc.lt", default=None)
|
||||
published_utc_lte: Optional[str] = Field(alias="published_utc.lte", default=None)
|
||||
published_utc_gt: Optional[str] = Field(alias="published_utc.gt", default=None)
|
||||
published_utc_gte: Optional[str] = Field(alias="published_utc.gte", default=None)
|
||||
order: Optional[Literal["asc", "desc"]] = None
|
||||
limit: Optional[int] = Field(default=100)
|
||||
sort: Optional[str] = None
|
||||
|
||||
|
||||
class PolygonPublisher(BaseModel):
|
||||
favicon_url: str
|
||||
homepage_url: str
|
||||
logo_url: str
|
||||
name: str
|
||||
|
||||
|
||||
class PolygonStockNewsData(Data):
|
||||
"""Source: https://polygon.io/docs/stocks/get_v2_reference_news"""
|
||||
|
||||
__name__ = "PolygonStockNewsData"
|
||||
amp_url: Optional[str]
|
||||
article_url: str = Field(alias="url")
|
||||
author: Optional[str]
|
||||
description: Optional[str] = Field(alias="text")
|
||||
id: str
|
||||
image_url: Optional[str]
|
||||
keywords: Optional[List[str]]
|
||||
published_utc: datetime = Field(alias="date")
|
||||
publisher: PolygonPublisher = Field(alias="image")
|
||||
tickers: List[str]
|
||||
title: str
|
||||
|
||||
|
||||
class PolygonStockNewsFetcher(
|
||||
Fetcher[
|
||||
StockNewsQueryParams,
|
||||
StockNewsData,
|
||||
PolygonStockNewsQueryParams,
|
||||
PolygonStockNewsData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockNewsQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonStockNewsQueryParams:
|
||||
return PolygonStockNewsQueryParams(
|
||||
symbols=query.symbols, **extra_params if extra_params else {}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonStockNewsQueryParams, api_key: str
|
||||
) -> List[PolygonStockNewsData]:
|
||||
base_url = "https://api.polygon.io/v2/reference/news"
|
||||
querystring = get_querystring(query.dict(), [])
|
||||
request_url = f"{base_url}?{querystring}&apiKey={api_key}"
|
||||
data = get_data(request_url)["results"]
|
||||
|
||||
if len(data) == 0:
|
||||
raise RuntimeError("No news found")
|
||||
|
||||
return [PolygonStockNewsData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
data: List[PolygonStockNewsData],
|
||||
) -> List[StockNewsData]:
|
||||
processors = {"publisher": lambda x: x.favicon_url}
|
||||
return data_transformer(data, StockNewsData, processors)
|
||||
97
openbb_providers/builtin_providers/polygon/stock_price.py
Normal file
97
openbb_providers/builtin_providers/polygon/stock_price.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""Polygon stocks price fetcher."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, NonNegativeFloat, PositiveFloat, PositiveInt
|
||||
|
||||
from builtin_providers.polygon.helpers import get_data
|
||||
from builtin_providers.polygon.types import BaseStockData, BaseStockQueryParams
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.data.stock_price import StockPriceData, StockPriceQueryParams
|
||||
from openbb_provider.provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.provider.provider_helpers import data_transformer
|
||||
|
||||
|
||||
class PolygonStockPriceQueryParams(BaseStockQueryParams):
|
||||
"""Polygon stocks price query.
|
||||
|
||||
Source: https://polygon.io/docs/stocks/getting-started
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : str
|
||||
The symbol of the stocks to fetch.
|
||||
start_date : Union[date, datetime]
|
||||
The start date of the query.
|
||||
end_date : Union[date, datetime]
|
||||
The end date of the query.
|
||||
timespan : Timespan, optional
|
||||
The timespan of the query, by default Timespan.day
|
||||
sort : Literal["asc", "desc"], optional
|
||||
The sort order of the query, by default "desc"
|
||||
limit : PositiveInt, optional
|
||||
The limit of the query, by default 49999
|
||||
adjusted : bool, optional
|
||||
Whether the query is adjusted, by default True
|
||||
multiplier : PositiveInt, optional
|
||||
The multiplier of the query, by default 1
|
||||
"""
|
||||
|
||||
__name__ = "PolygonStockPriceQueryParams"
|
||||
|
||||
|
||||
class PolygonStockPriceData(BaseStockData):
|
||||
__name__ = "PolygonPriceStockData"
|
||||
v: NonNegativeFloat = Field(alias="volume")
|
||||
n: PositiveInt
|
||||
vw: PositiveFloat
|
||||
|
||||
|
||||
class PolygonStockPriceFetcher(
|
||||
Fetcher[
|
||||
StockPriceQueryParams,
|
||||
StockPriceData,
|
||||
PolygonStockPriceQueryParams,
|
||||
PolygonStockPriceData,
|
||||
]
|
||||
):
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
query: StockPriceQueryParams, extra_params: Optional[Dict] = None
|
||||
) -> PolygonStockPriceQueryParams:
|
||||
return PolygonStockPriceQueryParams(
|
||||
symbol=query.symbol,
|
||||
start_date=query.start_date,
|
||||
end_date=query.end_date if query.end_date else datetime.now(),
|
||||
**extra_params if extra_params else {},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: PolygonStockPriceQueryParams, api_key: str
|
||||
) -> List[PolygonStockPriceData]:
|
||||
request_url = (
|
||||
f"https://api.polygon.io/v2/aggs/ticker/"
|
||||
f"{query.stocksTicker.upper()}/range/1/{query.timespan}/"
|
||||
f"{query.start_date}/{query.end_date}?adjusted={query.adjusted}"
|
||||
f"&sort={query.sort}&limit={query.limit}&multiplier={query.multiplier}"
|
||||
f"&apiKey={api_key}"
|
||||
)
|
||||
|
||||
data = get_data(request_url)
|
||||
if isinstance(data, list):
|
||||
raise ValueError("Expected a dict, got a list")
|
||||
|
||||
if "results" not in data.keys() or len(data["results"]) == 0:
|
||||
raise RuntimeError("No results found. Please change your query parameters.")
|
||||
|
||||
data = data["results"]
|
||||
return [PolygonStockPriceData(**d) for d in data]
|
||||
|
||||
@staticmethod
|
||||
def transform_data(data: List[PolygonStockPriceData]) -> List[StockPriceData]:
|
||||
return data_transformer(data, StockPriceData)
|
||||
68
openbb_providers/builtin_providers/polygon/types.py
Normal file
68
openbb_providers/builtin_providers/polygon/types.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""Polygon types helpers."""
|
||||
|
||||
# IMPORT STANDARD
|
||||
from datetime import date, datetime
|
||||
from enum import Enum
|
||||
from typing import Literal, Optional, Union
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import Field, PositiveFloat, PositiveInt, validator
|
||||
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
|
||||
|
||||
class Timespan(str, Enum):
|
||||
minute = "minute"
|
||||
hour = "hour"
|
||||
day = "day"
|
||||
week = "week"
|
||||
month = "month"
|
||||
quarter = "quarter"
|
||||
year = "year"
|
||||
|
||||
|
||||
class PolygonFundamentalQueryParams(QueryParams):
|
||||
ticker: Optional[str] = Field(alias="symbol")
|
||||
cik: Optional[str]
|
||||
company_name: Optional[str]
|
||||
company_name_search: Optional[str] = Field(alias="company_name.search")
|
||||
sic: Optional[str]
|
||||
filing_date: Optional[date]
|
||||
filing_date_lt: Optional[date] = Field(alias="filing_date.lt")
|
||||
filing_date_lte: Optional[date] = Field(alias="filing_date.lte")
|
||||
filing_date_gt: Optional[date] = Field(alias="filing_date.gt")
|
||||
filing_date_gte: Optional[date] = Field(alias="filing_date.gte")
|
||||
period_of_report_date: Optional[date]
|
||||
period_of_report_date_lt: Optional[date] = Field(alias="period_of_report_date.lt")
|
||||
period_of_report_date_lte: Optional[date] = Field(alias="period_of_report_date.lte")
|
||||
period_of_report_date_gt: Optional[date] = Field(alias="period_of_report_date.gt")
|
||||
period_of_report_date_gte: Optional[date] = Field(alias="period_of_report_date.gte")
|
||||
timeframe: Optional[Literal["annual", "quarterly", "ttm"]] = Field(alias="period")
|
||||
include_sources: Optional[bool]
|
||||
order: Optional[Literal["asc", "desc"]]
|
||||
limit: Optional[PositiveInt] = 10
|
||||
sort: Optional[Literal["filing_date", "period_of_report_date"]]
|
||||
|
||||
|
||||
class BaseStockQueryParams(QueryParams):
|
||||
stocksTicker: str = Field(alias="symbol")
|
||||
start_date: Union[date, datetime]
|
||||
end_date: Union[date, datetime]
|
||||
timespan: Timespan = Field(default=Timespan.day)
|
||||
sort: Literal["asc", "desc"] = Field(default="desc")
|
||||
limit: PositiveInt = Field(default=49999)
|
||||
adjusted: bool = Field(default=True)
|
||||
multiplier: PositiveInt = Field(default=1)
|
||||
|
||||
|
||||
class BaseStockData(Data):
|
||||
c: PositiveFloat = Field(alias="close")
|
||||
o: PositiveFloat = Field(alias="open")
|
||||
h: PositiveFloat = Field(alias="high")
|
||||
l: PositiveFloat = Field(alias="low") # noqa: E741
|
||||
t: datetime = Field(alias="date")
|
||||
|
||||
@validator("t", pre=True)
|
||||
def time_validate(cls, v): # pylint: disable=E0213
|
||||
return datetime.fromtimestamp(v / 1000)
|
||||
@@ -14,6 +14,7 @@ class Data(BaseModel):
|
||||
|
||||
class Config:
|
||||
extra = Extra.allow
|
||||
allow_population_by_field_name = True
|
||||
|
||||
|
||||
class QueryParams(BaseModel):
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
# IMPORT STANDARD
|
||||
|
||||
# IMPORT THIRD-PARTY
|
||||
from pydantic import BaseModel, Extra
|
||||
|
||||
# IMPORT INTERNAL
|
||||
|
||||
|
||||
class ProviderData(BaseModel):
|
||||
"""The Provider-specific data model."""
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}({', '.join([f'{k}={v}' for k, v in self.dict().items()])})"
|
||||
|
||||
class Config:
|
||||
extra = Extra.allow
|
||||
allow_population_by_field_name = True
|
||||
|
||||
|
||||
class ProviderQueryParams(BaseModel):
|
||||
"""The Provider-specific query parameter model."""
|
||||
|
||||
def __post_init__(self):
|
||||
# check the fields that were received vs the fields that are allowed
|
||||
# if there are any fields that were received that are not allowed, raise an error
|
||||
allowed_fields = set(self.__fields__.keys())
|
||||
received_fields = set(self.__dict__.keys())
|
||||
if not received_fields.issubset(allowed_fields):
|
||||
raise ValueError(
|
||||
f"Received fields that are not allowed: {received_fields - allowed_fields}"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}({', '.join([f'{k}={v}' for k, v in self.dict().items()])})"
|
||||
@@ -30,7 +30,7 @@ class CryptoPriceQueryParams(QueryParams, BaseSymbol):
|
||||
__name__ = "CryptoPriceQueryParams"
|
||||
|
||||
# These fields only work with Polygon
|
||||
start_date: Optional[date] = Field(description=DESCRIPTIONS.get("start_date", ""))
|
||||
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
|
||||
end_date: Optional[date] = Field(
|
||||
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
|
||||
)
|
||||
|
||||
@@ -6,15 +6,11 @@ from typing import Dict, Generic, List, Optional, TypeVar, Union
|
||||
# IMPORT THIRD-PARTY
|
||||
# IMPORT INTERNAL
|
||||
from openbb_provider.model.abstract.data import Data, QueryParams
|
||||
from openbb_provider.model.abstract.provider_data import (
|
||||
ProviderData,
|
||||
ProviderQueryParams,
|
||||
)
|
||||
|
||||
QueryParamsType = TypeVar("QueryParamsType", bound=QueryParams)
|
||||
DataType = TypeVar("DataType", bound=Data)
|
||||
ProviderQueryParamsType = TypeVar("ProviderQueryParamsType", bound=ProviderQueryParams)
|
||||
ProviderDataType = TypeVar("ProviderDataType", bound=ProviderData)
|
||||
ProviderQueryParamsType = TypeVar("ProviderQueryParamsType", bound=QueryParams)
|
||||
ProviderDataType = TypeVar("ProviderDataType", bound=Data)
|
||||
ReturnType = Union[List[ProviderDataType], ProviderDataType]
|
||||
UDataType = Union[List[DataType], DataType]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user