Move built-in providers code

This commit is contained in:
Theodore Aptekarev
2023-06-30 11:53:52 +02:00
parent 7fb76c74bf
commit d8787d4727
64 changed files with 5124 additions and 41 deletions

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

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

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

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

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

View 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

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

View 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

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

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

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

View File

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

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

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

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

View File

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

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

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

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

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

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

View File

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

View File

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

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

View File

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

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

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

View File

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

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

View File

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

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

View File

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

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

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

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

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

View File

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

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

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

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

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

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

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

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

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

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

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

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

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

View File

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

View File

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

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

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

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

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

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

View File

@@ -14,6 +14,7 @@ class Data(BaseModel):
class Config:
extra = Extra.allow
allow_population_by_field_name = True
class QueryParams(BaseModel):

View File

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

View File

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

View File

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