Start moving v4 code to the main repo

This commit is contained in:
Theodore Aptekarev
2023-06-29 15:19:16 +02:00
parent 1ba1f2cf80
commit 7fb76c74bf
53 changed files with 3839 additions and 0 deletions

144
openbb_providers/README.md vendored Normal file
View File

@@ -0,0 +1,144 @@
# Table of contents
- [Table of contents](#table-of-contents)
- [Temporary glossary](#temporary-glossary)
- [openbb-provider](#openbb-provider)
- [Functional Requirements](#functional-requirements)
- [How to use it?](#how-to-use-it)
- [Prerequisites](#prerequisites)
- [1. Defining : OpenBB QueryParams](#1-defining--openbb-queryparams)
- [2. Querying the Provider Table : OpenBB QueryParams -\> OpenBB Data](#2-querying-the-provider-table--openbb-queryparams---openbb-data)
- [Different ways of usage](#different-ways-of-usage)
- [1. OpenBB QueryParams -\> OpenBB Data](#1-openbb-queryparams---openbb-data)
- [2. OpenBB QueryParams -\> Provider Data](#2-openbb-queryparams---provider-data)
- [3. Provider QueryParams -\> OpenBB Data](#3-provider-queryparams---openbb-data)
- [4. Provider QueryParams -\> Provider Data](#4-provider-queryparams---provider-data)
- [Data Mapping](#data-mapping)
- [Package extension : Adding a new Provider extension](#package-extension--adding-a-new-provider-extension)
- [1. Build a Python package](#1-build-a-python-package)
- [2. Entrypoint](#2-entrypoint)
- [3. Install the extension](#3-install-the-extension)
# Temporary glossary
- **Provider** : A Provider is a Financial Data Provider such as FMP, Polygon, Benzinga, etc.
- **QueryParams** : A set of parameters that define a request to a Provider. It is defined by the user.
- **Provider QueryParams** : A set of parameters which are defined by the Provider.
- **Data** : A standardized set of data that is returned by a Provider and then standardized.
- **Provider Data** : Provider Data is a raw set of data that is returned by a Provider as is.
# openbb-provider
This library aim to give a coherent access to Financial Data Providers.
It provides coherence on:
- QueryParams : one can define QueryParams and use them on multiple Financial Data Providers.
- Data : one can process the data provided by multiple Financial Data Providers as if there were from the same one.
## Functional Requirements
Functional requirements are the following:
- Provide a standardized access to similar Data from multiple Data Providers.
- Use the same QueryParams to query similar Data from multiple Providers.
- Get similar Data from multiple Provider and process it as if there were from the same Provider.
# How to use it?
### Prerequisites
- Python 3.9 or higher
- .env file with the following variables:
- FMP_API_KEY
- POLYGON_API_KEY
- BENZINGA_API_KEY
- Install the dependencies:
- `pip install poetry==1.4.1`
- `poetry install`
### 1. Defining : OpenBB QueryParams
```python
from openbb_provider.model.data.stock_eod import StockEODQueryParams
query = StockEODQueryParams(
symbol="AAPL",
start_date="2022-01-01",
)
```
### 2. Querying the Provider Table : OpenBB QueryParams -> OpenBB Data
```python
from openbb_provider.provider.provider_registry import provider_registry
data = provider_registry.fetch(provider_name="fmp", query=query)
print(data)
```
# Different ways of usage
### 1. OpenBB QueryParams -> OpenBB Data
This is the most common way of usage that the SDK v4 users will use.
```python
provider_registry.fetch(provider_name="fmp", query=query)
```
### 2. OpenBB QueryParams -> Provider Data
This way uses the standardized query to obtain the raw data from the Provider. This is useful when the user wants specific data that is not available in the standardized data.
```python
provider_registry.fetch_provider_data(provider_name="fmp", query=query)
```
### 3. Provider QueryParams -> OpenBB Data
This way uses the Provider QueryParams to obtain the standardized data. This is useful when the user wants to use a specific query field that is not available in the standardized query.
```python
provider_registry.standardized(provider_name="fmp", query=provider_query)
```
### 4. Provider QueryParams -> Provider Data
This way uses the Provider QueryParams to obtain the raw data from the Provider. This is useful when the user wants specific data that is not available in the standardized data and wants to use a specific query field that is not available in the standardized query. It is the same a using the Provider directly.
This will primarily be used for integration tests so that we can notice Provider API changes in time and adjust the mapping accordingly.
```python
provider_registry.simple(provider_name="fmp", query=provider_query)
```
# Data Mapping
The data mapping is done in the following [file](https://docs.google.com/spreadsheets/d/1AhmQWGRDqORk8nlcNclcnCuPpWsdMuaHwxujMMdzcsk/edit#gid=152728452
).
# Package extension : Adding a new Provider extension
## 1. Build a Python package
```bash
poetry new opebb-provider-your_extension
```
## 2. Entrypoint
Add an entrypoint for the extension inside your `pyproject.toml` file
```toml
# File pyproject.toml
...
[tool.poetry.extensions."openbb_provider_extension"]
extension_name_space = "my_extension.provider:provider_module"
```
## 3. Install the extension
```bash
poetry install
```

View File

@@ -0,0 +1,2 @@
"""OpenBB Provider Package."""
from . import metadata, model, provider, settings # noqa: F401

View File

@@ -0,0 +1,11 @@
"""Metadata for the parameters of the Pydantic models."""
DESCRIPTIONS = {
"symbol": "Symbol to get data for.",
"start_date": "Start date of the data.",
"end_date": "End date of the data.",
"weekly": "Whether to return weekly data.",
"monthly": "Whether to return monthly data.",
"period": "Period of the data to return (quarterly or annually).",
"date": "A specific date to get data for.",
}

View File

@@ -0,0 +1,23 @@
# IMPORT STANDARD
# IMPORT THIRD-PARTY
from pydantic import BaseModel, Extra
# IMPORT INTERNAL
class Data(BaseModel):
"""The OpenBB Standardized 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
class QueryParams(BaseModel):
"""The OpenBB Standardized QueryParams Model that holds the query input parameters."""
def __repr__(self):
return f"{self.__class__.__name__}({', '.join([f'{k}={v}' for k, v in self.dict().items()])})"

View File

@@ -0,0 +1,34 @@
# 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

@@ -0,0 +1,103 @@
"""Analyst estimates data model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Literal
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class AnalystEstimatesQueryParams(QueryParams, BaseSymbol):
"""Analyst Estimates query.
Parameter
---------
symbol : str
The symbol of the company.
period : Literal["quarter", "annual"]
The period of the analyst estimates.
limit : int
The limit of the analyst estimates.
"""
__name__ = "AnalystEstimatesQueryParams"
period: Literal["quarter", "annual"] = "annual"
limit: int = 30
class AnalystEstimatesData(Data, BaseSymbol):
"""Analyst estimates data.
Returns
-------
symbol : str
The symbol of the asset.
date : date
The date of the analyst estimates.
estimated_revenue_low : int
The estimated revenue low of the analyst estimates.
estimated_revenue_high : int
The estimated revenue high of the analyst estimates.
estimated_revenue_avg : int
The estimated revenue average of the analyst estimates.
estimated_ebitda_low : int
The estimated EBITDA low of the analyst estimates.
estimated_ebitda_high : int
The estimated EBITDA high of the analyst estimates.
estimated_ebitda_avg : int
The estimated EBITDA average of the analyst estimates.
estimated_ebit_low : int
The estimated EBIT low of the analyst estimates.
estimated_ebit_high : int
The estimated EBIT high of the analyst estimates.
estimated_ebit_avg : int
The estimated EBIT average of the analyst estimates.
estimated_net_income_low : int
The estimated net income low of the analyst estimates.
estimated_net_income_high : int
The estimated net income high of the analyst estimates.
estimated_net_income_avg : int
The estimated net income average of the analyst estimates.
estimated_sga_expense_low : int
The estimated SGA expense low of the analyst estimates.
estimated_sga_expense_high : int
The estimated SGA expense high of the analyst estimates.
estimated_sga_expense_avg : int
The estimated SGA expense average of the analyst estimates.
estimated_eps_avg : float
The estimated EPS average of the analyst estimates.
estimated_eps_high : float
The estimated EPS high of the analyst estimates.
estimated_eps_low : float
The estimated EPS low of the analyst estimates.
number_analyst_estimated_revenue : int
The number of analysts who estimated revenue of the analyst estimates.
number_analysts_estimated_eps : int
The number of analysts who estimated EPS of the analyst estimates.
"""
symbol: str
date: dateType
estimated_revenue_low: int
estimated_revenue_high: int
estimated_revenue_avg: int
estimated_ebitda_low: int
estimated_ebitda_high: int
estimated_ebitda_avg: int
estimated_ebit_low: int
estimated_ebit_high: int
estimated_ebit_avg: int
estimated_net_income_low: int
estimated_net_income_high: int
estimated_net_income_avg: int
estimated_sga_expense_low: int
estimated_sga_expense_high: int
estimated_sga_expense_avg: int
estimated_eps_avg: float
estimated_eps_high: float
estimated_eps_low: float
number_analyst_estimated_revenue: int
number_analysts_estimated_eps: int

View File

@@ -0,0 +1,73 @@
"""Balance Sheet Data Model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data
from openbb_provider.model.data.base import FinancialStatementQueryParams
# IMPORT THIRD PARTY
class BalanceSheetQueryParams(FinancialStatementQueryParams):
"""Cash flow statement query.
Parameter
---------
symbol : str
The symbol of the company.
period : Literal["annually", "quarterly"]
The period of the balance sheet.
"""
__name__ = "BalanceSheetQueryParams"
class BalanceSheetData(Data):
"""Return Balance Sheet Data.
Returns
-------
date : date
The date of the balance sheet.
cik : Optional[int]
The CIK of the balance sheet.
assets : Optional[int]
The assets of the balance sheet.
current_assets : Optional[int]
The current assets of the balance sheet.
current_liabilities : Optional[int]
The current liabilities of the balance sheet.
equity : Optional[int]
The equity of the balance sheet.
equity_attributable_to_noncontrolling_interest : Optional[int]
The equity attributable to noncontrolling interest of the balance sheet.
equity_attributable_to_parent : Optional[int]
The equity attributable to parent of the balance sheet.
liabilities : Optional[int]
The liabilities of the balance sheet.
liabilities_and_equity : Optional[int]
The liabilities and equity of the balance sheet.
noncurrent_assets : Optional[int]
The noncurrent assets of the balance sheet.
noncurrent_liabilities : Optional[int]
The noncurrent liabilities of the balance sheet.
"""
date: dateType
# symbol: List[Optional[str]]
# currency: List[Optional[str]]
cik: Optional[int]
# period: List[Optional[str]]
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]

View File

@@ -0,0 +1,24 @@
# IMPORT STANDARD
from typing import Literal
# IMPORT THIRD-PARTY
from pydantic import BaseModel, Field, validator
# IMPORT INTERNAL
from openbb_provider.metadata import DESCRIPTIONS
from openbb_provider.model.abstract.data import QueryParams
class BaseSymbol(BaseModel):
symbol: str = Field(min_length=1, description=DESCRIPTIONS.get("symbol", ""))
@validator("symbol", pre=True)
def upper_symbol(cls, v: str): # pylint: disable=E0213
return v.upper()
class FinancialStatementQueryParams(QueryParams, BaseSymbol):
__name__ = "FinancialStatementQueryParams"
period: Literal["annually", "quarterly"] = Field(
default="annually", description=DESCRIPTIONS.get("period", "")
)

View File

@@ -0,0 +1,74 @@
"""Cash Flow Statement Data Model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data
from openbb_provider.model.data.base import FinancialStatementQueryParams
class CashFlowStatementQueryParams(FinancialStatementQueryParams):
"""Cash flow statement query.
Parameter
---------
symbol : str
The symbol of the company.
period : Literal["annually", "quarterly"]
The period of the income statement.
"""
__name__ = "CashFlowStatementQueryParams"
class CashFlowStatementData(Data):
"""Return Cash Flow Statement Data.
Returns
-------
date : date
The date of the cash flow statement.
symbol : str
The symbol of the company.
currency : Optional[str]
The currency of the cash flow statement.
cik : Optional[int]
The Central Index Key (CIK) of the company.
period : Optional[str]
The period of the cash flow statement.
exchange_gain_losses : Optional[int]
The exchange gain losses of the cash flow statement.
net_cash_flow : Optional[int]
The net cash flow of the cash flow statement.
net_cash_flow_continuing : Optional[int]
The net cash flow continuing of the cash flow statement.
net_cash_flow_from_financing_activities : Optional[int]
The net cash flow from financing activities of the cash flow statement.
net_cash_flow_from_financing_activities_continuing : Optional[int]
The net cash flow from financing activities continuing of the cash flow statement.
net_cash_flow_from_investing_activities : Optional[int]
The net cash flow from investing activities of the cash flow statement.
net_cash_flow_from_investing_activities_continuing : Optional[int]
The net cash flow from investing activities continuing of the cash flow statement.
net_cash_flow_from_operating_activities : Optional[int]
The net cash flow from operating activities of the cash flow statement.
net_cash_flow_from_operating_activities_continuing : Optional[int]
The net cash flow from operating activities continuing of the cash flow statement.
"""
date: dateType
symbol: str
currency: Optional[str] = None
cik: Optional[int]
period: Optional[str]
exchange_gain_losses: Optional[int] = None
net_cash_flow: Optional[int]
net_cash_flow_continuing: Optional[int]
net_cash_flow_from_financing_activities: Optional[int]
net_cash_flow_from_financing_activities_continuing: Optional[int]
net_cash_flow_from_investing_activities: Optional[int]
net_cash_flow_from_investing_activities_continuing: Optional[int]
net_cash_flow_from_operating_activities: Optional[int]
net_cash_flow_from_operating_activities_continuing: Optional[int]

View File

@@ -0,0 +1,139 @@
"""Company Overview Data Model."""
# IMPORT STANDARD
from datetime import date
from typing import Optional
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class CompanyOverviewQueryParams(QueryParams, BaseSymbol):
"""Company overview query.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "CompanyOverviewQueryParams"
class CompanyOverviewData(Data):
"""Company Overview data.
Returns
-------
symbol : str
The symbol of the company.
price : float
The price of the company.
beta : float
The beta of the company.
vol_avg : int
The volume average of the company.
mkt_cap : int
The market capitalization of the company.
last_div : float
The last dividend of the company.
range : str
The range of the company.
changes : float
The changes of the company.
company_name : str
The company name of the company.
currency : str
The currency of the company.
cik : Optional[str]
The CIK of the company.
isin : Optional[str]
The ISIN of the company.
cusip : Optional[str]
The CUSIP of the company.
exchange : str
The exchange of the company.
exchange_short_name : str
The exchange short name of the company.
industry : str
The industry of the company.
website : str
The website of the company.
description : str
The description of the company.
ceo : str
The CEO of the company.
sector : str
The sector of the company.
country : str
The country of the company.
full_time_employees : str
The full time employees of the company.
phone : str
The phone of the company.
address : str
The address of the company.
city : str
The city of the company.
state : str
The state of the company.
zip : str
The zip of the company.
dcf_diff : float
The discounted cash flow difference of the company.
dcf : float
The discounted cash flow of the company.
image : str
The image of the company.
ipo_date : date
The IPO date of the company.
default_image : bool
If the image is the default image.
is_etf : bool
If the company is an ETF.
is_actively_trading : bool
If the company is actively trading.
is_adr : bool
If the company is an ADR.
is_fund : bool
If the company is a fund.
"""
symbol: str
price: float
beta: float
vol_avg: int
mkt_cap: int
last_div: float
range: str
changes: float
company_name: str
currency: str
cik: Optional[str]
isin: Optional[str]
cusip: Optional[str]
exchange: str
exchange_short_name: str
industry: str
website: str
description: str
ceo: str
sector: str
country: str
full_time_employees: str
phone: str
address: str
city: str
state: str
zip: str
dcf_diff: float
dcf: float
image: str
ipo_date: date
default_image: bool
is_etf: bool
is_actively_trading: bool
is_adr: bool
is_fund: bool

View File

@@ -0,0 +1,64 @@
"""Crypto aggregate end of day price data model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class CryptoEODQueryParams(QueryParams, BaseSymbol):
"""Crypto end of day query.
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 : Optional[date]
The end date of the stock data up to which to retrieve the data.
"""
__name__ = "CryptoEODQueryParams"
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class CryptoEODData(Data):
"""Crypto end of day price data.
Returns
-------
date : datetime
The date of the stock.
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
adj_close : Optional[PositiveFloat]
The adjusted close price of the stock.
volume : PositiveFloat
The volume of the stock.
"""
date: datetime
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
adj_close: Optional[PositiveFloat]
volume: PositiveFloat

View File

@@ -0,0 +1,60 @@
"""Crypto Price Data Model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class CryptoPriceQueryParams(QueryParams, BaseSymbol):
"""Crypto price query.
Parameter
---------
symbol : str
The symbol of the company.
start_date : date
The start date of the query.
end_date : Optional[date]
The end date of the query.
"""
__name__ = "CryptoPriceQueryParams"
# These fields only work with Polygon
start_date: Optional[date] = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class CryptoPriceData(Data):
"""Crypto price data.
Returns
-------
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
date : datetime
The date of the stock.
"""
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
date: datetime

View File

@@ -0,0 +1,61 @@
"""Earnings calendar data model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class EarningsCalendarQueryParams(QueryParams, BaseSymbol):
"""Earnings calendar rating query model.
Parameter
---------
symbol : str
The symbol of the company.
limit : int
"""
__name__ = "EarningsCalendarQueryParams"
limit: Optional[int]
class EarningsCalendarData(Data, BaseSymbol):
"""Earnings calendar data.
Returns
-------
symbol : str
The symbol of the asset.
date : date
The date of the earnings calendar.
eps : float
The EPS of the earnings calendar.
eps_estimated : float
The estimated EPS of the earnings calendar.
time : str
The time of the earnings calendar.
revenue : int
The revenue of the earnings calendar.
revenue_estimated : int
The estimated revenue of the earnings calendar.
updated_from_date : date
The updated from date of the earnings calendar.
fiscal_date_ending : date
The fiscal date ending of the earnings calendar.
"""
date: dateType
symbol: str
eps: Optional[float]
eps_estimated: Optional[float]
time: str
revenue: Optional[int]
revenue_estimated: Optional[int]
updated_from_date: Optional[dateType]
fiscal_date_ending: dateType

View File

@@ -0,0 +1,60 @@
"""Earnings call transcript data model."""
# IMPORT STANDARD
from datetime import datetime
# IMPORT THIRD-PARTY
from pydantic import validator
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class EarningsCallTranscriptQueryParams(QueryParams, BaseSymbol):
"""Earnings call transcript rating query model.
Parameter
---------
symbol : str
The symbol of the company.
year : int
The year of the earnings call transcript.
"""
__name__ = "EarningsCallTranscriptQueryParams"
year: int
@validator("year", pre=True)
def time_validate(cls, v: int): # pylint: disable=E0213
current_year = datetime.now().year
if v > current_year:
return current_year
if v < 1950:
return current_year
return v
class EarningsCallTranscriptData(Data, BaseSymbol):
"""Earnings call transcript data.
Returns
-------
symbol : str
The symbol of the asset.
quarter : int
The quarter of the earnings call transcript.
year : int
The year of the earnings call transcript.
date : datetime
The date of the earnings call transcript.
content : str
The content of the earnings call transcript.
"""
symbol: str
quarter: int
year: int
date: datetime
content: str

View File

@@ -0,0 +1,53 @@
"""ESG Risk Rating data model."""
# IMPORT STANDARD
from typing import Literal
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
# IMPORT THIRD-PARTY
class ESGRiskRatingQueryParams(QueryParams, BaseSymbol):
"""ESG risk rating query model.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "ESGRiskRatingQueryParams"
class ESGRiskRatingData(Data, BaseSymbol):
"""ESG Risk Rating data.
Returns
-------
symbol : str
The symbol of the asset.
cik : int
The CIK of the ESG Risk Rating.
company_name : str
The company name of the ESG Risk Rating.
industry : str
The industry of the ESG Risk Rating.
year : int
The year of the ESG Risk Rating.
esg_risk_rating : str
The ESG Risk Rating of the ESG Risk Rating.
industry_rank : str
The industry rank of the ESG Risk Rating.
"""
cik: int
company_name: str
industry: str
year: int
esg_risk_rating: Literal[
"A+", "A", "A-", "B+", "B", "B-", "C+", "C", "C-", "D+", "D", "D-", "F"
]
industry_rank: str

View File

@@ -0,0 +1,64 @@
"""ESG Score data model."""
# IMPORT STANDARD
from datetime import date, datetime
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
# IMPORT THIRD-PARTY
class ESGScoreQueryParams(QueryParams, BaseSymbol):
"""ESG score query model.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "ESGScoreQueryParams"
class ESGScoreData(Data):
"""ESG Score data.
Returns
-------
symbol : str
The symbol of the asset.
cik : int
The CIK of the ESG Score.
company_name : str
The company name of the ESG Score.
form_type : str
The form type of the ESG Score.
accepted_date : datetime
The accepted date of the ESG Score.
date : date
The date of the ESG Score.
environmental_score : float
The environmental score of the ESG Score.
social_score : float
The social score of the ESG Score.
governance_score : float
The governance score of the ESG Score.
esg_score : float
The ESG score of the ESG Score.
url : str
The URL of the ESG Score.
"""
symbol: str
cik: int
company_name: str
form_type: str
accepted_date: datetime
date: date
environmental_score: float
social_score: float
governance_score: float
esg_score: float
url: str

View File

@@ -0,0 +1,48 @@
"""ESG Sector data model."""
# IMPORT STANDARD
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
# IMPORT THIRD-PARTY
class ESGSectorQueryParams(QueryParams):
"""ESG sector query model.
Parameter
---------
year : int
The year to get ESG information for
"""
__name__ = "ESGSectorQueryParams"
year: int
class ESGSectorData(Data):
"""ESG Sector data.
Returns
-------
year : int
The year of the ESG Sector.
sector : str
The sector of the ESG Sector.
environmental_score : float
The environmental score of the ESG Sector.
social_score : float
The social score of the ESG Sector.
governance_score : float
The governance score of the ESG Sector.
esg_score : float
The ESG score of the ESG Sector.
"""
year: int
sector: str
environmental_score: float
social_score: float
governance_score: float
esg_score: float

View File

@@ -0,0 +1,69 @@
"""Executive Compensation Data Model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class ExecutiveCompensationQueryParams(QueryParams, BaseSymbol):
"""Executive Compensation query model.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "ExecutiveCompensationQueryParams"
class ExecutiveCompensationData(Data):
"""Return Executive Compensation Data.
Returns
-------
cik : Optional[str]
The Central Index Key (CIK) of the company.
symbol : str
The symbol of the company.
filing_date : dateType
The date of the filing.
accepted_date : dateType
The date the filing was accepted.
name_and_position : str
The name and position of the executive.
year : int
The year of the compensation.
salary : float
The salary of the executive.
bonus : float
The bonus of the executive.
stock_award : float
The stock award of the executive.
incentive_plan_compensation : float
The incentive plan compensation of the executive.
all_other_compensation : float
The all other compensation of the executive.
total : float
The total compensation of the executive.
url : str
The URL of the filing.
"""
cik: Optional[str]
symbol: str
filing_date: dateType
accepted_date: dateType
name_and_position: str
year: int
salary: float
bonus: float
stock_award: float
incentive_plan_compensation: float
all_other_compensation: float
total: float
url: str

View File

@@ -0,0 +1,64 @@
"""Forex aggregate end of day price data model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class ForexEODQueryParams(QueryParams, BaseSymbol):
"""Forex end of day query.
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 : Optional[date]
The end date of the stock data up to which to retrieve the data.
"""
__name__ = "ForexEODQueryParams"
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class ForexEODData(Data):
"""Forex end of day price data.
Returns
-------
date : datetime
The date of the stock.
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
adj_close : Optional[PositiveFloat]
The adjusted close price of the stock.
volume : PositiveFloat
The volume of the stock.
"""
date: datetime
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
adj_close: Optional[PositiveFloat]
volume: PositiveFloat

View File

@@ -0,0 +1,60 @@
"""Forex Price Data Model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class ForexPriceQueryParams(QueryParams, BaseSymbol):
"""Forex price query.
Parameter
---------
symbol : str
The symbol of the company.
start_date : date
The start date of the query.
end_date : Optional[date]
The end date of the query.
"""
__name__ = "ForexPriceQueryParams"
# These fields only work with Polygon
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class ForexPriceData(Data):
"""Forex price data.
Returns
-------
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
date : datetime
The date of the stock.
"""
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
date: datetime

View File

@@ -0,0 +1,48 @@
"""Global News Data Model."""
# IMPORT STANDARD
from datetime import datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, NonNegativeInt
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
class GlobalNewsQueryParams(QueryParams):
"""Global news query.
Parameter
---------
page : NonNegativeInt
The page of the global news to be retrieved.
"""
__name__ = "GlobalNewsQueryParams"
page: NonNegativeInt = Field(default=0)
class GlobalNewsData(Data):
"""Return Global News Data.
Returns
-------
date : datetime
The published date of the news.
title : str
The title of the news.
image : Optional[str]
The image URL of the news.
text : str
The text/body of the news.
url : str
The URL of the news.
"""
date: datetime
title: str
image: Optional[str]
text: str
url: str

View File

@@ -0,0 +1,52 @@
"""Historical dividends data model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class HistoricalDividendsQueryParams(QueryParams, BaseSymbol):
"""Historical dividends query.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "HistoricalDividendsQueryParams"
class HistoricalDividendsData(Data):
"""Historical dividends data.
Returns
-------
date : date
The date of the historical dividends.
label : str
The label of the historical dividends.
adj_dividend : float
The adjusted dividend of the historical dividends.
dividend : float
The dividend of the historical dividends.
record_date : date
The record date of the historical dividends.
payment_date : date
The payment date of the historical dividends.
declaration_date : date
The declaration date of the historical dividends.
"""
date: dateType
label: str
adj_dividend: float
dividend: float
record_date: Optional[dateType]
payment_date: Optional[dateType]
declaration_date: Optional[dateType]

View File

@@ -0,0 +1,42 @@
"""Historical stock splits data model."""
# IMPORT STANDARD
from datetime import date as dateType
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class HistoricalStockSplitsQueryParams(QueryParams, BaseSymbol):
"""Historical Stock Splits query model.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "HistoricalStockSplitsQueryParams"
class HistoricalStockSplitsData(Data):
"""Historical stock splits data.
Returns
-------
date : date
The date of the historical stock splits.
label : str
The label of the historical stock splits.
numerator : float
The numerator of the historical stock splits.
denominator : float
The denominator of the historical stock splits.
"""
date: dateType
label: str
numerator: float
denominator: float

View File

@@ -0,0 +1,122 @@
"""Income Statement Data Model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data
from openbb_provider.model.data.base import FinancialStatementQueryParams
class IncomeStatementQueryParams(FinancialStatementQueryParams):
"""Income statement query.
Parameter
---------
symbol : str
The symbol of the company.
period : Literal["annually", "quarterly"]
The period of the income statement.
"""
__name__ = "IncomeStatementQueryParams"
class IncomeStatementData(Data):
"""Income Statement Data.
Returns
-------
date : date
The date of the income statement.
symbol : str
The symbol of the company.
currency : Optional[str]
The currency of the income statement.
cik : Optional[int]
The Central Index Key (CIK) of the company.
filing_date : date
The filing date of the income statement.
accepted_date : Optional[date]
The accepted date of the income statement.
period : Optional[str]
The period of the income statement.
revenue : Optional[int]
The revenue of the income statement.
cost_of_revenue : Optional[int]
The cost of revenue of the income statement.
gross_profit : Optional[int]
The gross profit of the income statement.
research_and_development_expenses : Optional[int]
The research and development expenses of the income statement.
general_and_administrative_expenses : Optional[int]
The general and administrative expenses of the income statement.
selling_and_marketing_expenses : Optional[float]
The selling and marketing expenses of the income statement.
selling_general_and_administrative_expenses : Optional[int]
The selling general and administrative expenses of the income statement.
other_expenses : Optional[int]
The other expenses of the income statement.
operating_expenses : Optional[int]
The operating expenses of the income statement.
cost_and_expenses : Optional[int]
The cost and expenses of the income statement.
depreciation_and_amortization : Optional[int]
The depreciation and amortization of the income statement.
ebitda : Optional[int]
The earnings before interest, taxes, depreciation, and amortization of the income statement.
operating_income : Optional[int]
The operating income of the income statement.
total_other_income_expenses_net : Optional[int]
The total other income expenses net of the income statement.
income_before_tax : Optional[int]
The income before tax of the income statement.
income_tax_expense : Optional[int]
The income tax expense of the income statement.
net_income : Optional[int]
The net income of the income statement.
eps : Optional[float]
The earnings per share of the income statement.
eps_diluted : Optional[float]
The earnings per share diluted of the income statement.
interest_expense : Optional[int]
The interest expense of the income statement.
interest_income : Optional[int]
The interest income of the income statement.
weighted_average_shares_outstanding : Optional[int]
The weighted average shares outstanding of the income statement.
weighted_average_shares_outstanding_dil : Optional[int]
The weighted average shares outstanding diluted of the income statement.
"""
date: dateType
symbol: str
currency: Optional[str] = None
cik: Optional[int]
filing_date: dateType
accepted_date: Optional[dateType] = None
period: Optional[str]
revenue: Optional[int]
cost_of_revenue: Optional[int]
gross_profit: Optional[int]
research_and_development_expenses: Optional[int] = None
general_and_administrative_expenses: Optional[int] = None
selling_and_marketing_expenses: Optional[float] = None
selling_general_and_administrative_expenses: Optional[int] = None
other_expenses: Optional[int] = None
operating_expenses: Optional[int]
cost_and_expenses: Optional[int]
depreciation_and_amortization: Optional[int] = None
ebitda: Optional[int] = None
operating_income: Optional[int] = None
total_other_income_expenses_net: Optional[int] = None
income_before_tax: Optional[int]
income_tax_expense: Optional[int]
net_income: Optional[int]
eps: Optional[float]
eps_diluted: Optional[float]
interest_expense: Optional[int] = None
interest_income: Optional[int] = None
weighted_average_shares_outstanding: Optional[int] = None
weighted_average_shares_outstanding_dil: Optional[int] = None

View File

@@ -0,0 +1,131 @@
"""Institutional Ownership Data Model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class InstitutionalOwnershipQueryParams(QueryParams, BaseSymbol):
"""Institutional Ownership QueryParams.
Parameter
---------
symbol : str
The symbol of the company.
include_current_quarter : bool
Whether to include the current quarter. Default is False.
date : Optional[dateType]
A specific date to get data for.
"""
__name__ = "InstitutionalOwnershipQueryParams"
include_current_quarter: bool = Field(
default=False, description="Include current quarter data."
)
date: Optional[dateType] = Field(description=DESCRIPTIONS.get("date", ""))
class InstitutionalOwnershipData(Data):
"""Institutional Ownership data.
Returns
-------
symbol : str
The symbol of the company.
cik : str
The CIK of the company.
date : dateType
The date of the institutional ownership.
investors_holding : int
The number of investors holding the stock.
last_investors_holding : int
The number of investors holding the stock in the last quarter.
investors_holding_change : int
The change in the number of investors holding the stock.
number_of_13f_shares : int
The number of 13F shares.
last_number_of_13f_shares : int
The number of 13F shares in the last quarter.
number_of_13f_shares_change : int
The change in the number of 13F shares.
total_invested : float
The total amount invested.
last_total_invested : float
The total amount invested in the last quarter.
total_invested_change : float
The change in the total amount invested.
ownership_percent : float
The ownership percent.
last_ownership_percent : float
The ownership percent in the last quarter.
ownership_percent_change : float
The change in the ownership percent.
new_positions : int
The number of new positions.
last_new_positions : int
The number of new positions in the last quarter.
new_positions_change : int
The change in the number of new positions.
increased_positions : int
The number of increased positions.
last_increased_positions : int
The number of increased positions in the last quarter.
increased_positions_change : int
The change in the number of increased positions.
closed_positions : int
The number of closed positions.
last_closed_positions : int
The number of closed positions in the last quarter.
closed_positions_change : int
The change in the number of closed positions.
reduced_positions : int
The number of reduced positions.
last_reduced_positions : int
The number of reduced positions in the last quarter.
"""
symbol: str = Field(min_lenght=1)
cik: Optional[str] = Field(min_lenght=1)
date: dateType
investors_holding: int
last_investors_holding: int
investors_holding_change: int
number_of_13f_shares: Optional[int]
last_number_of_13f_shares: Optional[int]
number_of_13f_shares_change: Optional[int]
total_invested: float
last_total_invested: float
total_invested_change: float
ownership_percent: float
last_ownership_percent: float
ownership_percent_change: float
new_positions: int
last_new_positions: int
new_positions_change: int
increased_positions: int
last_increased_positions: int
increased_positions_change: int
closed_positions: int
last_closed_positions: int
closed_positions_change: int
reduced_positions: int
last_reduced_positions: int
reduced_positions_change: int
total_calls: int
last_total_calls: int
total_calls_change: int
total_puts: int
last_total_puts: int
total_puts_change: int
put_call_ratio: float
last_put_call_ratio: float
put_call_ratio_change: float

View File

@@ -0,0 +1,60 @@
"""Key Executives Data Model."""
# IMPORT STANDARD
from datetime import datetime
from typing import Optional
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class KeyExecutivesQueryParams(QueryParams, BaseSymbol):
"""Key executives query.
Parameter
---------
symbol : str
The symbol of the company.
key_executive_name : Optional[str]
The name of the key executive to be retrieved.
key_executive_title : Optional[str]
The title of the key executive to be retrieved.
key_executive_title_since : Optional[datetime]
The period since the position of the key executive to be retrieved.
key_executive_year_born : Optional[datetime]
The year born of the key executive to be retrieved.
key_executive_gender: Optional[str]
The gender of the key executive to be retrieved.
"""
__name__ = "KeyExecutivesQueryParams"
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 KeyExecutivesData(Data):
"""Key Executives Data.
Returns
-------
name : Optional[str]
The name of the key executive.
title : Optional[str]
The title of the key executive.
title_since : Optional[datetime]
The title since of the key executive.
year_born : Optional[datetime]
The year born of the key executive.
gender : Optional[str]
The gender of the key executive.
"""
name: Optional[str]
title: Optional[str]
title_since: Optional[datetime]
year_born: Optional[datetime]
gender: Optional[str]

View File

@@ -0,0 +1,212 @@
"""Key Metrics Data Model."""
# IMPORT STANDARD
from datetime import date as DateType
from typing import Literal, Optional
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class KeyMetricsQueryParams(QueryParams, BaseSymbol):
"""Key Metrics query model.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "KeyMetricsQueryParams"
period: Literal["annually", "quarterly"] = "annually"
limit: Optional[int] = None
class KeyMetricsData(Data):
"""Return Key Metrics Data.
Returns
-------
symbol : str
The symbol of the stock.
date : DateType
The date of the key metrics.
period : str
The period of the key metrics.
revenue_per_share : float
The revenue per share of the stock.
net_income_per_share : float
The net income per share of the stock.
operating_cash_flow_per_share : float
The operating cash flow per share of the stock.
free_cash_flow_per_share : float
The free cash flow per share of the stock.
cash_per_share : float
The cash per share of the stock.
book_value_per_share : float
The book value per share of the stock.
tangible_book_value_per_share : float
The tangible book value per share of the stock.
shareholders_equity_per_share : float
The shareholders equity per share of the stock.
interest_debt_per_share : float
The interest debt per share of the stock.
market_cap : float
The market cap of the stock.
enterprise_value : float
The enterprise value of the stock.
pe_ratio : float
The PE ratio of the stock.
price_to_sales_ratio : float
The price to sales ratio of the stock.
pocf_ratio : float
The POCF ratio of the stock.
pfcf_ratio : float
The PFCF ratio of the stock.
pb_ratio : float
The PB ratio of the stock.
ptb_ratio : float
The PTB ratio of the stock.
ev_to_sales : float
The EV to sales of the stock.
enterprise_value_over_ebitda : float
The enterprise value over EBITDA of the stock.
ev_to_operating_cash_flow : float
The EV to operating cash flow of the stock.
ev_to_free_cash_flow : float
The EV to free cash flow of the stock.
earnings_yield : float
The earnings yield of the stock.
free_cash_flow_yield : float
The free cash flow yield of the stock.
debt_to_equity : float
The debt to equity of the stock.
debt_to_assets : float
The debt to assets of the stock.
net_debt_to_ebitda : float
The net debt to EBITDA of the stock.
current_ratio : float
The current ratio of the stock.
interest_coverage : float
The interest coverage of the stock.
income_quality : float
The income quality of the stock.
dividend_yield : float
The dividend yield of the stock.
payout_ratio : float
The payout ratio of the stock.
sales_general_and_administrative_to_revenue : float
The sales general and administrative to revenue of the stock.
research_and_developement_to_revenue : float
The research and development to revenue of the stock.
intangibles_to_total_assets : float
The intangibles to total assets of the stock.
capex_to_operating_cash_flow : float
The capex to operating cash flow of the stock.
capex_to_revenue : float
The capex to revenue of the stock.
capex_to_depreciation : float
The capex to depreciation of the stock.
stock_based_compensation_to_revenue : float
The stock based compensation to revenue of the stock.
graham_number : float
The graham number of the stock.
roic : float
The ROIC of the stock.
return_on_tangible_assets : float
The return on tangible assets of the stock.
graham_net_net : float
The graham net net of the stock.
working_capital : float
The working capital of the stock.
tangible_asset_value : float
The tangible asset value of the stock.
net_current_asset_value : float
The net current asset value of the stock.
invested_capital : float
The invested capital of the stock.
average_receivables : float
The average receivables of the stock.
average_payables : float
The average payables of the stock.
average_inventory : float
The average inventory of the stock.
days_sales_outstanding : float
The days sales outstanding of the stock.
days_payables_outstanding : float
The days payables outstanding of the stock.
days_of_inventory_on_hand : float
The days of inventory on hand of the stock.
receivables_turnover : float
The receivables turnover of the stock.
payables_turnover : float
The payables turnover of the stock.
inventory_turnover : float
The inventory turnover of the stock.
roe : float
The ROE of the stock.
capex_per_share : float
The capex per share of the stock.
"""
symbol: str
date: DateType
period: str
revenue_per_share: Optional[float]
net_income_per_share: Optional[float]
operating_cash_flow_per_share: Optional[float]
free_cash_flow_per_share: Optional[float]
cash_per_share: Optional[float]
book_value_per_share: Optional[float]
tangible_book_value_per_share: Optional[float]
shareholders_equity_per_share: Optional[float]
interest_debt_per_share: Optional[float]
market_cap: Optional[float]
enterprise_value: Optional[float]
pe_ratio: Optional[float]
price_to_sales_ratio: Optional[float]
pocf_ratio: Optional[float]
pfcf_ratio: Optional[float]
pb_ratio: Optional[float]
ptb_ratio: Optional[float]
ev_to_sales: Optional[float]
enterprise_value_over_ebitda: Optional[float]
ev_to_operating_cash_flow: Optional[float]
ev_to_free_cash_flow: Optional[float]
earnings_yield: Optional[float]
free_cash_flow_yield: Optional[float]
debt_to_equity: Optional[float]
debt_to_assets: Optional[float]
net_debt_to_ebitda: Optional[float]
current_ratio: Optional[float]
interest_coverage: Optional[float]
income_quality: Optional[float]
dividend_yield: Optional[float]
payout_ratio: Optional[float]
sales_general_and_administrative_to_revenue: Optional[float]
research_and_development_to_revenue: Optional[float]
intangibles_to_total_assets: Optional[float]
capex_to_operating_cash_flow: Optional[float]
capex_to_revenue: Optional[float]
capex_to_depreciation: Optional[float]
stock_based_compensation_to_revenue: Optional[float]
graham_number: Optional[float]
roic: Optional[float]
return_on_tangible_assets: Optional[float]
graham_net_net: Optional[float]
working_capital: Optional[float]
tangible_asset_value: Optional[float]
net_current_asset_value: Optional[float]
invested_capital: Optional[float]
average_receivables: Optional[float]
average_payables: Optional[float]
average_inventory: Optional[float]
days_sales_outstanding: Optional[float]
days_payables_outstanding: Optional[float]
days_of_inventory_on_hand: Optional[float]
receivables_turnover: Optional[float]
payables_turnover: Optional[float]
inventory_turnover: Optional[float]
roe: Optional[float]
capex_per_share: Optional[float]

View File

@@ -0,0 +1,64 @@
"""Major indices aggregate end of day price data model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class MajorIndicesEODQueryParams(QueryParams, BaseSymbol):
"""Major Indices end of day query.
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 : Optional[date]
The end date of the stock data up to which to retrieve the data.
"""
__name__ = "MajorIndicesEODQueryParams"
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class MajorIndicesEODData(Data):
"""Major Indices end of day price data.
Returns
-------
date : datetime
The date of the stock.
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
adj_close : Optional[PositiveFloat]
The adjusted close price of the stock.
volume : Optional[PositiveFloat]
The volume of the stock.
"""
date: datetime
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
adj_close: Optional[PositiveFloat]
volume: Optional[PositiveFloat]

View File

@@ -0,0 +1,60 @@
"""Major Indices Price Data Model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class MajorIndicesPriceQueryParams(QueryParams, BaseSymbol):
"""Major indices price query.
Parameter
---------
symbol : str
The symbol of the company.
start_date : date
The start date of the query.
end_date : Optional[date]
The end date of the query.
"""
__name__ = "MajorIndicesPriceQueryParams"
# These fields only work with Polygon
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class MajorIndicesPriceData(Data):
"""Major Indices price data.
Returns
-------
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
date : datetime
The date of the stock.
"""
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
date: datetime

View File

@@ -0,0 +1,64 @@
"""Price target data model."""
# IMPORT STANDARD
from datetime import datetime
from typing import Optional
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class PriceTargetQueryParams(QueryParams, BaseSymbol):
"""Price Target query.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "PriceTargetQueryParams"
class PriceTargetData(Data, BaseSymbol):
"""Price target data.
Returns
-------
symbol : str
The symbol of the asset.
published_date : datetime
The published date of the price target.
news_url : str
The news URL of the price target.
news_title : str
The news title of the price target.
analyst_name : str
The analyst name of the price target.
price_target : float
The price target of the price target.
adj_price_target : float
The adjusted price target of the price target.
price_when_posted : float
The price when posted of the price target.
news_publisher : str
The news publisher of the price target.
news_base_url : str
The news base URL of the price target.
analyst_company : str
The analyst company of the price target.
"""
symbol: str
published_date: datetime
news_url: str
news_title: Optional[str]
analyst_name: Optional[str]
price_target: float
adj_price_target: float
price_when_posted: float
news_publisher: str
news_base_url: str
analyst_company: str

View File

@@ -0,0 +1,43 @@
"""Price target consensus data model."""
# IMPORT STANDARD
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class PriceTargetConsensusQueryParams(QueryParams, BaseSymbol):
"""Price Target Consensus query.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "PriceTargetConsensusQueryParams"
class PriceTargetConsensusData(Data):
"""Price target consensus data.
Returns
-------
symbol : str
The symbol of the asset.
target_high : float
The high target of the price target consensus.
target_low : float
The low target of the price target consensus.
target_consensus : float
The consensus target of the price target consensus.
target_median : float
The median target of the price target consensus.
"""
symbol: str
target_high: float
target_low: float
target_consensus: float
target_median: float

View File

@@ -0,0 +1,52 @@
"""Revenue by business line data model."""
# IMPORT STANDARD
from datetime import date
from typing import Dict, Literal
# IMPORT THIRD-PARTY
from pydantic import Field
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class RevenueBusinessLineQueryParams(QueryParams, BaseSymbol):
"""Revenue business line query.
Parameter
---------
symbol : str
The symbol of the company.
period : Literal["quarterly", "annually"]
The period of the income statement.
structure : Literal["hierarchical", "flat"]
The structure of the revenue business line. Should always be flat.
"""
__name__ = "RevenueBusinessLineQueryParams"
period: Literal["quarterly", "annually"] = Field(
default="quarterly", description=DESCRIPTIONS.get("period", "")
)
structure: Literal["hierarchical", "flat"] = Field(
default="flat"
) # should always be flat
class RevenueBusinessLineData(Data):
"""Revenue by business line data.
Returns
-------
date : date
The date of the revenue.
data_and_service : Dict[str, int]
The data and service of the revenue.
"""
date: date
data_and_service: Dict[str, int]

View File

@@ -0,0 +1,63 @@
"""Revenue by geographic segments data model."""
# IMPORT STANDARD
from datetime import date
from typing import Literal, Optional
# IMPORT THIRD-PARTY
from pydantic import Field
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class RevenueGeographicQueryParams(QueryParams, BaseSymbol):
"""Revenue geographic query.
Parameter
---------
symbol : str
The symbol of the company.
period : Literal["quarterly", "annually"]
The period of the income statement.
structure : Literal["hierarchical", "flat"]
The structure of the revenue geographic. Should always be flat.
"""
__name__ = "RevenueGeographicQueryParams"
period: Literal["quarterly", "annually"] = Field(
default="quarterly", description=DESCRIPTIONS.get("period", "")
)
structure: Literal["hierarchical", "flat"] = Field(
default="flat"
) # should always be flat
class RevenueGeographicData(Data):
"""Revenue by geographic segments data.
Returns
-------
date : date
The date of the revenue.
americas : Optional[int]
The revenue of the America segment.
europe : Optional[int]
The revenue of the Europe segment.
greater_china : Optional[int]
The revenue of the Greater China segment.
japan : Optional[int]
The revenue of the Japan segment.
rest_of_asia_pacific : Optional[int]
The revenue of the Rest of Asia Pacific segment.
"""
date: date
americas: Optional[int]
europe: Optional[int]
greater_china: Optional[int]
japan: Optional[int]
rest_of_asia_pacific: Optional[int]

View File

@@ -0,0 +1,61 @@
"""SEC filings data model."""
# IMPORT STANDARD
from datetime import date as dateType
from typing import Optional
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class SECFilingsQueryParams(QueryParams, BaseSymbol):
"""SEC Filings query model.
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__ = "SECFilingsQueryParams"
symbol: str
type: Optional[str] = None
page: Optional[int] = 0
limit: Optional[int] = None
class SECFilingsData(Data):
"""SEC filings data.
Returns
-------
symbol : str
The symbol of the stock.
filling_date : date
The filling date of the SEC filing.
accepted_date : date
The accepted date of the SEC filing.
cik : str
The CIK of the SEC filing.
type : str
The type of the SEC filing.
link : str
The link of the SEC filing.
final_link : str
The final link of the SEC filing.
"""
symbol: str
filling_date: dateType
accepted_date: dateType
cik: Optional[str]
type: str
link: str
final_link: str

View File

@@ -0,0 +1,47 @@
"""Share Statistics Data Model."""
# IMPORT STANDARD
from datetime import date as dateType
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class ShareStatisticsQueryParams(QueryParams, BaseSymbol):
"""Share Statistics query.
Parameter
---------
symbol : str
The symbol of the company.
"""
__name__ = "ShareStatisticsQueryParams"
class ShareStatisticsData(Data):
"""Return Share Statistics Data.
Returns
-------
symbol : str
The symbol of the company.
date : dateType
The date of the share statistics.
free_float : float
The free float of the company.
float_shares : float
The float shares of the company.
outstanding_shares : float
The outstanding shares of the company.
source : str
The source of the data.
"""
symbol: str
date: dateType
free_float: float
float_shares: float
outstanding_shares: float
source: str

View File

@@ -0,0 +1,63 @@
"""Stock aggregate end of day price data model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class StockEODQueryParams(QueryParams, BaseSymbol):
"""Stock end of day query.
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 : Optional[date]
The end date of the stock data up to which to retrieve the data.
"""
__name__ = "StockEODQueryParams"
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class StockEODData(Data):
"""Stock end of day price data.
Returns
-------
date : datetime
The date of the stock.
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
adj_close : Optional[PositiveFloat]
The adjusted close price of the stock.
volume : PositiveFloat
The volume of the stock.
"""
date: datetime
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
adj_close: Optional[PositiveFloat]
volume: PositiveFloat

View File

@@ -0,0 +1,115 @@
"""Stock insider trading data model."""
# IMPORT STANDARD
from datetime import date, datetime
from enum import Enum
from typing import List, Optional
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
# IMPORT THIRD-PARTY
class TransactionTypes(str, Enum):
Award = "A-Award"
Conversion = "C-Conversion"
Return = "D-Return"
ExpireShort = "E-ExpireShort"
InKind = "F-InKind"
Gift = "G-Gift"
ExpireLong = "H-ExpireLong"
Discretionary = "I-Discretionary"
Other = "J-Other"
Small = "L-Small"
Exempt = "M-Exempt"
OutOfTheMoney = "O-OutOfTheMoney"
Purchase = "P-Purchase"
Sale = "S-Sale"
Tender = "U-Tender"
Will = "W-Will"
InTheMoney = "X-InTheMoney"
Trust = "Z-Trust"
class StockInsiderTradingQueryParams(QueryParams):
"""Stock Insider Trading query.
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[int]
The CIK of the reporting owner.
companyCik : Optional[int]
The CIK of the company owner.
page: int
The page number to get
"""
__name__ = "StockInsiderTradingQueryParams"
transactionType: List[TransactionTypes] = []
symbol: Optional[str]
reportingCik: Optional[int]
companyCik: Optional[int]
page: int = 0
class StockInsiderTradingData(Data):
"""Stock insider trading data.
Returns
-------
symbol : str
The symbol of the asset.
filingDate : datetime
The filing date of the stock insider trading.
transactionDate : date
The transaction date of the stock insider trading.
reportingCik : int
The reporting CIK of the stock insider trading.
transactionType : str
The transaction type of the stock insider trading.
securitiesOwned : int
The securities owned of the stock insider trading.
companyCik : int
The company CIK of the stock insider trading.
reportingName : str
The reporting name of the stock insider trading.
typeOfOwner : str
The type of owner of the stock insider trading.
acquistionOrDisposition : str
The acquistion or disposition of the stock insider trading.
formType : str
The form type of the stock insider trading.
securitiesTransacted : float
The securities transacted of the stock insider trading.
price : float
The price of the stock insider trading.
securityName : str
The security name of the stock insider trading.
link : str
The link of the stock insider trading.
"""
symbol: str
filingDate: datetime
transactionDate: date
reportingCik: int
transactionType: str
securitiesOwned: int
companyCik: int
reportingName: str
typeOfOwner: str
acquistionOrDisposition: str
formType: str
securitiesTransacted: float
price: float
securityName: str
link: str

View File

@@ -0,0 +1,58 @@
"""Stock News Data Model."""
# IMPORT STANDARD
from datetime import date
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, validator
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
class StockNewsQueryParams(QueryParams):
"""Stock news query.
Parameter
---------
symbols : str
The symbols of the company.
page : int
The page of the stock news to be retrieved.
"""
__name__ = "StockNewsQueryParams"
symbols: str = Field(min_length=1, description=DESCRIPTIONS.get("symbols", ""))
page: int = Field(default=0)
@validator("symbols", pre=True)
def time_validate(cls, v: str): # pylint: disable=E0213
return v.upper()
class StockNewsData(Data):
"""Stock News data.
Returns
-------
date : date
The published date of the news.
title : str
The title of the news.
image : Optional[str]
The image URL of the news.
text : str
The text/body of the news.
url : str
The URL of the news.
"""
date: date
title: str
image: Optional[str]
text: Optional[str]
url: str

View File

@@ -0,0 +1,190 @@
"""Stock owner data model."""
# IMPORT STANDARD
from datetime import date as dateType
from datetime import datetime
# IMPORT THIRD-PARTY
from pydantic import validator
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
def most_recent_quarter(base: dateType = dateType.today()) -> dateType:
"""Get the most recent quarter date.
Parameter
---------
base : date
The date to get the most recent quarter.
Returns
-------
date : date
The most recent quarter date.
"""
base = min(base, dateType.today()) # This prevents dates from being in the future
exacts = [(3, 31), (6, 30), (9, 30), (12, 31)]
for exact in exacts:
if base.month == exact[0] and base.day == exact[1]:
return base
if base.month < 4:
return dateType(base.year - 1, 12, 31)
if base.month < 7:
return dateType(base.year, 3, 31)
if base.month < 10:
return dateType(base.year, 6, 30)
return dateType(base.year, 9, 30)
class StockOwnershipQueryParams(QueryParams, BaseSymbol):
"""Stock ownership query.
Parameter
---------
symbol : string
The symbol of the company.
page : int
The page number to get
date : date
The CIK of the company owner.
"""
__name__ = "StockOwnershipQueryParams"
page: int = 0
date: dateType = most_recent_quarter()
@validator("date", pre=True)
def time_validate(cls, v: str): # pylint: disable=E0213
base = datetime.strptime(v, "%Y-%m-%d").date()
return most_recent_quarter(base)
class StockOwnershipData(Data):
"""Stock ownership data.
Returns
-------
date : date
The date of the stock ownership.
cik : int
The cik of the stock ownership.
filingDate : date
The filing date of the stock ownership.
investorName : str
The investor name of the stock ownership.
symbol : str
The symbol of the stock ownership.
securityName : str
The security name of the stock ownership.
typeOfSecurity : str
The type of security of the stock ownership.
securityCusip : str
The security cusip of the stock ownership.
sharesType : str
The shares type of the stock ownership.
putCallShare : str
The put call share of the stock ownership.
investmentDiscretion : str
The investment discretion of the stock ownership.
industryTitle : str
The industry title of the stock ownership.
weight : float
The weight of the stock ownership.
lastWeight : float
The last weight of the stock ownership.
changeInWeight : float
The change in weight of the stock ownership.
changeInWeightPercentage : float
The change in weight percentage of the stock ownership.
marketValue : int
The market value of the stock ownership.
lastMarketValue : int
The last market value of the stock ownership.
changeInMarketValue : int
The change in market value of the stock ownership.
changeInMarketValuePercentage : float
The change in market value percentage of the stock ownership.
sharesNumber : int
The shares number of the stock ownership.
lastSharesNumber : int
The last shares number of the stock ownership.
changeInSharesNumber : float
The change in shares number of the stock ownership.
changeInSharesNumberPercentage : float
The change in shares number percentage of the stock ownership.
quarterEndPrice : float
The quarter end price of the stock ownership.
avgPricePaid : float
The average price paid of the stock ownership.
isNew : bool
Is the stock ownership new.
isSoldOut : bool
Is the stock ownership sold out.
ownership : float
How much is the ownership.
lastOwnership : float
The last ownership amount.
changeInOwnership : float
The change in ownership amount.
changeInOwnershipPercentage : float
The change in ownership percentage.
holdingPeriod : int
The holding period of the stock ownership.
firstAdded : date
The first added date of the stock ownership.
performance : float
The performance of the stock ownership.
performancePercentage : float
The performance percentage of the stock ownership.
lastPerformance : float
The last performance of the stock ownership.
changeInPerformance : float
The change in performance of the stock ownership.
isCountedForPerformance : bool
Is the stock ownership counted for performance.
"""
date: dateType
cik: int
filingDate: dateType
investorName: str
symbol: str
securityName: str
typeOfSecurity: str
securityCusip: str
sharesType: str
putCallShare: str
investmentDiscretion: str
industryTitle: str
weight: float
lastWeight: float
changeInWeight: float
changeInWeightPercentage: float
marketValue: int
lastMarketValue: int
changeInMarketValue: int
changeInMarketValuePercentage: float
sharesNumber: int
lastSharesNumber: int
changeInSharesNumber: float
changeInSharesNumberPercentage: float
quarterEndPrice: float
avgPricePaid: float
isNew: bool
isSoldOut: bool
ownership: float
lastOwnership: float
changeInOwnership: float
changeInOwnershipPercentage: float
holdingPeriod: int
firstAdded: dateType
performance: float
performancePercentage: float
lastPerformance: float
changeInPerformance: float
isCountedForPerformance: bool

View File

@@ -0,0 +1,60 @@
"""Stock Price Data Model."""
# IMPORT STANDARD
from datetime import date, datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field, PositiveFloat
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
from openbb_provider.model.data.base import BaseSymbol
class StockPriceQueryParams(QueryParams, BaseSymbol):
"""Stock price query.
Parameter
---------
symbol : str
The symbol of the company.
start_date : date
The start date of the query.
end_date : Optional[date]
The end date of the query.
"""
__name__ = "StockPriceQueryParams"
# These fields only work with Polygon
start_date: date = Field(description=DESCRIPTIONS.get("start_date", ""))
end_date: Optional[date] = Field(
description=DESCRIPTIONS.get("end_date", ""), default=date.today()
)
class StockPriceData(Data):
"""Stock price data.
Returns
-------
open : PositiveFloat
The open price of the stock.
high : PositiveFloat
The high price of the stock.
low : PositiveFloat
The low price of the stock.
close : PositiveFloat
The close price of the stock.
date : datetime
The date of the stock.
"""
open: PositiveFloat
high: PositiveFloat
low: PositiveFloat
close: PositiveFloat
date: datetime

View File

@@ -0,0 +1,81 @@
"""Treasury Rates Data Model."""
# IMPORT STANDARD
from datetime import date as dateType
from datetime import datetime
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import Field
from openbb_provider.metadata import DESCRIPTIONS
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import Data, QueryParams
class TreasuryRatesQueryParams(QueryParams):
"""Treasury Rates query.
Parameter
---------
start_date : str
Start date of the data.
end_date : str
End date of the data. Default is today.
"""
__name__ = "TreasuryRatesQueryParams"
start_date: str = Field(default=None, description=DESCRIPTIONS["start_date"])
end_date: Optional[str] = Field(
default=datetime.today().strftime("%Y-%m-%d"),
description=DESCRIPTIONS["end_date"],
)
class TreasuryRatesData(Data):
"""Return Treasury Rates Data.
Returns
-------
date : dateType
The date of the treasury rates.
month_1 : float
The 1 month treasury rate.
month_2 : float
The 2 month treasury rate.
month_3 : float
The 3 month treasury rate.
month_6 : float
The 6 month treasury rate.
year_1 : float
The 1 year treasury rate.
year_2 : float
The 2 year treasury rate.
year_3 : float
The 3 year treasury rate.
year_5 : float
The 5 year treasury rate.
year_7 : float
The 7 year treasury rate.
year_10 : float
The 10 year treasury rate.
year_20 : float
The 20 year treasury rate.
year_30 : float
The 30 year treasury rate.
"""
date: dateType
month_1: float
month_2: float
month_3: float
month_6: float
year_1: float
year_2: float
year_3: float
year_5: float
year_7: float
year_10: float
year_20: float
year_30: float

View File

@@ -0,0 +1,87 @@
"""Abstract class for the fetcher."""
# IMPORT STANDARD
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)
ReturnType = Union[List[ProviderDataType], ProviderDataType]
UDataType = Union[List[DataType], DataType]
class Fetcher(
Generic[
QueryParamsType,
DataType,
ProviderQueryParamsType,
ProviderDataType,
]
):
@staticmethod
def transform_query(
query: QueryParamsType,
extra_params: Optional[Dict] = None,
) -> ProviderQueryParamsType:
raise NotImplementedError("Method `transform_query` not implemented.")
@staticmethod
def extract_data(query: ProviderQueryParamsType, api_key: str) -> ReturnType:
raise NotImplementedError("Method `extract_data` not implemented.")
@staticmethod
def transform_data(data: ReturnType) -> UDataType:
raise NotImplementedError("Method `transform_query` not implemented.")
@classmethod
def fetch_data(
cls, query: QueryParamsType, extra_params: Optional[Dict], api_key: str
) -> UDataType:
provider_query = cls.transform_query(query=query, extra_params=extra_params)
provider_data = cls.extract_data(query=provider_query, api_key=api_key)
data = cls.transform_data(data=provider_data)
return data
@classmethod
def fetch_provider_data(
cls, query: QueryParamsType, extra_params: Optional[Dict], api_key: str
) -> ReturnType:
provider_query = cls.transform_query(query=query, extra_params=extra_params)
provider_data = cls.extract_data(query=provider_query, api_key=api_key)
return provider_data
@classmethod
def standardized(cls, query: ProviderQueryParamsType, api_key: str) -> UDataType:
provider_data = cls.extract_data(query=query, api_key=api_key)
data = cls.transform_data(data=provider_data)
return data
@classmethod
def simple(cls, query: ProviderQueryParamsType, api_key: str) -> ReturnType:
provider_data = cls.extract_data(query=query, api_key=api_key)
return provider_data
@classmethod
def get_query_type(cls):
return cls.transform_query.__annotations__["query"]
@classmethod
def get_data_type(cls):
return cls.transform_data.__annotations__["return"]
@classmethod
def get_provider_query_type(cls):
return cls.extract_data.__annotations__["query"]
@classmethod
def get_provider_data_type(cls):
return cls.extract_data.__annotations__["return"]

View File

@@ -0,0 +1,67 @@
"""Abstract class for providers."""
# IMPORT STANDARD
from typing import Any, Dict, List, Literal
import pkg_resources
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
def build_provider_name():
"""Builds the provider name Literal from the entry points."""
extension_names = []
for entry_point in pkg_resources.iter_entry_points("openbb_provider_extension"):
extension_names.append(entry_point.name)
literal_values = ()
for extension_name in extension_names:
literal_values += (extension_name,)
provider_name = Literal[literal_values] # type: ignore
return provider_name
ProviderName = build_provider_name()
class ProviderNameType(type):
__args__ = ProviderName.__args__
__str__ = ProviderName.__str__
def __init__(cls, value):
if value not in ProviderName.__args__:
raise ValueError(f"{value} is not a valid provider name.")
cls.value = value
def __getstate__(cls):
return cls.value
def __setstate__(cls, state):
cls.value = state
def __repr__(cls):
return f"ProviderName({cls.value})"
class Provider:
QUERIES = ["get_query_type", "get_provider_query_type"]
def __init__(
self,
name: ProviderNameType,
description: str,
fetcher_list: List[Any],
) -> None:
self.name = name
self.description = description
the_dict: Dict[str, Any] = {}
for query in self.QUERIES:
the_dict[query] = {getattr(x, query)().__name__: x for x in fetcher_list}
self.fetcher_dict = the_dict
# This is used only for documentation generation
self.fetcher_list = fetcher_list

View File

@@ -0,0 +1,153 @@
"""Provider helpers."""
# IMPORT STANDARD
import json
import re
from io import StringIO
from typing import Callable, Dict, List, Optional, Type, Union
# IMPORT THIRD-PARTY
# IMPORT INTERNAL
from openbb_provider.provider.abstract.fetcher import DataType, ProviderDataType
def get_querystring(items: dict, exclude: List[str]) -> str:
"""Turns a dictionary into a querystring, excluding the keys in the exclude list.
Parameters:
-----------
items: dict
The dictionary to be turned into a querystring.
exclude: List[str]
The keys to be excluded from the querystring.
Returns:
--------
str
The querystring.
"""
for item in exclude:
items.pop(item)
params = {k: v for k, v in items.items() if v is not None}
return "&".join([f"{k}={v}" for k, v in params.items()])
def extract_data(schema, data: list):
new_data: Dict[str, list] = {x: [] for x in schema.__fields__}
for item in data:
for key, value in item.items():
if key in new_data:
new_data[key].append(value)
return schema(**new_data)
def process(
row: ProviderDataType, key: str, processors: Optional[Dict[str, Callable]] = None
):
if not processors:
return getattr(row, key)
if key not in processors:
return getattr(row, key)
return processors[key](getattr(row, key))
def camel_to_snake(name: str) -> str:
"Converts a camelCase string to snake_case."
pattern = re.compile(r"(?<!^)(?=[A-Z])")
return pattern.sub("_", name).lower()
def convert_schema(
row: ProviderDataType,
new_schema: Type[DataType],
mapping: Dict[str, str],
processors: Optional[Dict[str, Callable]] = None,
):
mapped_fields = {
value: process(row, key, processors) for key, value in mapping.items()
}
return new_schema.parse_obj(mapped_fields)
def check_alias(field) -> bool:
"Checks if a field has an alias."
alias = getattr(field, "alias")
name = getattr(field, "name")
return alias != name
def data_transformer(
data: Union[List[ProviderDataType], ProviderDataType],
new_schema: Type[DataType],
processors: Optional[Dict[str, Callable]] = None,
) -> List[DataType]:
"""Converts a specific data into the standardised version
Parameters:
-----------
data: Union[List[ProviderDataType], ProviderDataType]
A list of pydantic schemas
new_schema: DataType
The standardised pydantic schema
processors: Optional[Dict[str, str]]
A dictionary with fields and custom processing functions
Returns:
--------
List[DataType]
A list of the newly formatted schemas
"""
the_data = data[0] if isinstance(data, list) else data
fields = the_data.__dict__.keys()
final_mapping = {x: camel_to_snake(x) for x in fields}
mapping = {
attr: field.alias
for attr, field in the_data.__fields__.items()
if check_alias(field)
}
if mapping:
for key, value in mapping.items():
final_mapping[key] = value
if not isinstance(data, list):
return convert_schema(data, new_schema, final_mapping, processors)
new_data = []
for row in data:
schema = convert_schema(row, new_schema, final_mapping, processors)
new_data.append(schema)
return new_data
class BasicResponse:
def __init__(self, response: StringIO):
# Find a way to get the status code
self.status_code = 200
response.seek(0)
self.text = response.read()
def json(self) -> dict:
return json.loads(self.text)
def request(url: str) -> BasicResponse:
"""
Request function for PyScript. Pass in Method and make sure to await!
Parameters:
-----------
url: str
URL to make request to
Return:
-------
response: BasicRequest
BasicRequest object with status_code and text attributes
"""
# pylint: disable=import-outside-toplevel
from pyodide.http import open_url
response = open_url(url)
return BasicResponse(response)

View File

@@ -0,0 +1,319 @@
"""Create a detailed Map of the Provider Registry."""
from typing import Dict, Tuple
from openbb_provider.provider.provider_registry import provider_registry
def _get_data_type(fetcher) -> str:
"""Get the data type of the fetcher."""
data_type = (
str(fetcher.get_data_type()) # pylint: disable=use-maxsplit-arg
.split(".")[-1]
.replace("]", "")
.replace("'>", "")
)
return data_type
def _get_query_type(fetcher) -> str:
"""Get the query type of the fetcher."""
query_type = (
str(fetcher.get_query_type()) # pylint: disable=use-maxsplit-arg
.split(".")[-1]
.replace("'>", "")
)
return query_type
def _get_data_fields(fetcher) -> Tuple[Dict, Dict]:
"""Get the standard and provider-specific data fields of the fetcher.
Parameters
----------
fetcher : Fetcher
The fetcher to get the data fields from.
Returns
-------
Tuple[Dict, Dict]
A tuple of the provider-specific and standardized data fields.
"""
try:
provider_fields = (fetcher.get_provider_data_type()).__fields__
except AttributeError:
provider_fields = (fetcher.get_provider_data_type().__args__[0]).__fields__
try:
standard_fields = (fetcher.get_data_type()).__fields__
except AttributeError:
standard_fields = (fetcher.get_data_type().__args__[0]).__fields__
return provider_fields, standard_fields
def _extract_fields(
provider_fields: Dict,
standard_fields: Dict,
) -> Tuple[Dict, Dict]:
"""Extract the fields and their details from pydantic models.
Parameters
----------
provider_fields : Dict
The fields of the provider pydantic model.
standard_fields : Dict
The fields of the standardized pydantic model.
Returns
-------
Tuple[Dict, Dict]
A tuple of the provider fields and standardized fields.
"""
provider_dict: Dict = {}
standard_dict: Dict = {}
for field in provider_fields:
provider_dict[provider_fields[field].alias] = {
"type": provider_fields[field].annotation,
"default": provider_fields[field].default
if provider_fields[field].default
else None,
"required": provider_fields[field].required,
}
for field in standard_fields:
standard_dict[standard_fields[field].alias] = {
"type": standard_fields[field].annotation,
"default": standard_fields[field].default
if standard_fields[field].default
else None,
"required": standard_fields[field].required,
}
return provider_dict, standard_dict
def build_query_params_mapping() -> Dict:
"""Build a mapping of the provider registry QueryParams.
Returns
-------
Dict :
The mapping is a nested dictionary with the following structure:
{
"QueryParamsType": {
"provider_name": {
"param_name": {
"type": "param_type",
"default": "param_default",
"required": "param_required"
}
}
"openbb": {
"param_name": {
"type": "param_type",
"default": "param_default",
"required": "param_required"
}
}
}
}
"""
provider_registry_mapping = provider_registry.provider_mapping
mapping = {}
for provider in provider_registry_mapping.values():
for fetcher in provider.fetcher_list:
provider_name = provider.name
query_type = _get_query_type(fetcher)
provider_param_fields = (fetcher.get_provider_query_type()).__fields__
standard_param_fields = (fetcher.get_query_type()).__fields__
provider_specific_query_params, standardized_query_params = _extract_fields(
provider_param_fields,
standard_param_fields,
)
if query_type not in mapping:
mapping[query_type] = {provider_name: provider_specific_query_params}
mapping[query_type]["openbb"] = standardized_query_params # type: ignore
else:
mapping[query_type][provider_name] = provider_specific_query_params
return mapping
def build_data_mapping() -> Dict:
"""Build a mapping of the provider registry Data.
Returns
-------
Dict :
The mapping is a nested dictionary with the following structure:
{
"DataType": {
"provider_name": {
"data_field_name": {
"type": "param_type",
"default": "param_default",
"required": "param_required"
}
}
"openbb": {
"data_field_name": {
"type": "param_type",
"default": "param_default",
"required": "param_required"
}
}
}
}
"""
provider_registry_mapping = provider_registry.provider_mapping
mapping = {}
for provider in provider_registry_mapping.values():
for fetcher in provider.fetcher_list:
provider_name = provider.name
data_type = _get_data_type(fetcher)
provider_data_fields, standard_data_fields = _get_data_fields(fetcher)
provider_specific_data_fields, standardized_data_fields = _extract_fields(
provider_data_fields,
standard_data_fields,
)
if data_type not in mapping:
mapping[data_type] = {provider_name: provider_specific_data_fields}
mapping[data_type]["openbb"] = standardized_data_fields # type: ignore
else:
mapping[data_type][provider_name] = provider_specific_data_fields
return mapping
def _get_data_docstring(fetcher) -> Tuple[str, str]:
"""Get the data docstring of the fetcher for the provider and standardized data.
Parameters
----------
fetcher : Fetcher
The fetcher to get the data docstring from.
Returns
-------
Tuple[str, str]
A tuple of the provider and standardized data docstrings.
"""
provider_data_docstring = (fetcher.get_provider_data_type()).__doc__
if not provider_data_docstring:
try:
provider_data_docstring = (
fetcher.get_provider_data_type().__args__[0]
).__doc__
except AttributeError:
provider_data_docstring = ""
standard_data_docstring = (fetcher.get_data_type()).__doc__
if not standard_data_docstring:
try:
standard_data_docstring = (fetcher.get_data_type().__args__[0]).__doc__
except AttributeError:
standard_data_docstring = ""
return provider_data_docstring, standard_data_docstring
def build_docstring_mapping() -> Dict:
"""Build a mapping of the provider registry docstrings.
Returns
-------
Dict :
The mapping is a nested dictionary with the following structure:
{
"DataType": {
"provider_name": "docstring",
"openbb": "docstring"
},
"QueryParamsType": {
"provider_name": "docstring",
"openbb": "docstring"
}
}
"""
mapping = {}
provider_registry_mapping = provider_registry.provider_mapping
for provider in provider_registry_mapping.values():
for fetcher in provider.fetcher_list:
provider_name = provider.name
data_type = _get_data_type(fetcher)
query_type = _get_query_type(fetcher)
provider_query_docstring = (fetcher.get_provider_query_type()).__doc__
standard_query_docstring = (fetcher.get_query_type()).__doc__
provider_data_docstring, standard_data_docstring = _get_data_docstring(
fetcher
)
if data_type not in mapping:
mapping[data_type] = {
provider_name: provider_data_docstring,
"openbb": standard_data_docstring,
}
else:
mapping[data_type][provider_name] = provider_data_docstring
if query_type not in mapping:
mapping[query_type] = {
provider_name: provider_query_docstring,
"openbb": standard_query_docstring,
}
else:
mapping[query_type][provider_name] = provider_query_docstring
return mapping
def build_provider_mapping() -> Dict:
"""Build a mapping of the provider registry.
Returns
-------
Dict :
The mapping is a nested dictionary of data and query mappings.
"""
mapping: Dict = {}
data_mapping = build_data_mapping()
query_mapping = build_query_params_mapping()
docstring_mapping = build_docstring_mapping()
for query_type, providers in query_mapping.items():
query_type_name = query_type.replace("QueryParams", "")
mapping[query_type_name] = {}
for provider, fields in providers.items():
mapping[query_type_name][provider] = {
"QueryParams": {},
"Data": {},
}
mapping[query_type_name][provider]["QueryParams"] = {
"fields": fields,
"docstring": docstring_mapping[query_type][provider],
}
for data_type, providers in data_mapping.items():
data_type_name = data_type.replace("Data", "")
for provider, fields in providers.items():
mapping[data_type_name][provider]["Data"] = {
"fields": fields,
"docstring": docstring_mapping[data_type][provider],
}
return mapping
provider_mapping = build_provider_mapping()

View File

@@ -0,0 +1,256 @@
"""ProviderRegistry class and Builder class."""
# IMPORT STANDARD
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
import pkg_resources
# IMPORT INTERNAL
from openbb_provider.model.abstract.data import QueryParams
from openbb_provider.provider.abstract.fetcher import ProviderDataType
from openbb_provider.provider.abstract.provider import Provider, ProviderNameType
from openbb_provider.settings import settings
# IMPORT THIRD-PARTY
orients = Literal["LIST", "RECORDS"]
def process(
data: Union[List[ProviderDataType], ProviderDataType], orientation: orients
) -> Any:
"""
Converts the data into the desired orientation.
Naming is based on the pandas to_dict() method:
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.from_dict.html
Parameters
----------
data: Union[List[ProviderDataType], ProviderDataType]
The data to be processed.
orientation: orients
The orientation of the data to be returned.
Returns
-------
Any
The processed data.
"""
if not isinstance(data, list):
# TODO: how do we want to handle this?
return data
if orientation == "RECORDS":
return data
if orientation == "LIST":
layout = data[0].dict()
new_dict: Dict[str, list] = {x: [] for x in layout}
for item in data:
for key, value in item.dict().items():
new_dict[key].append(value)
return [new_dict]
raise ValueError(f"Orientation {orientation} is not supported.")
class ProviderRegistry:
"""A Provider Registry is the "brain" of the openbb_provider library
with which users and the SDK v4 interact for retrieving data.
"""
def __init__(self) -> None:
self.provider_mapping: Dict[ProviderNameType, Provider] = {}
self.api_keys: Dict[ProviderNameType, str] = {}
def add(self, provider: Provider) -> None:
if provider.name not in self.provider_mapping:
self.provider_mapping[provider.name] = provider
else:
raise ValueError(
f"Provider {provider.name} is already in the ProviderRegistry."
)
def __fetch_factory__( # noqa: PLR0913
self,
provider_name: ProviderNameType,
query: QueryParams,
extra_params: Optional[Dict],
query_name: str,
data_name: str, # type: ignore
data_orientation: orients,
):
if not self.provider_mapping:
raise ValueError(
"Provider Mapping is empty. Please confirm plugins are loaded."
)
try:
provider = self.provider_mapping[provider_name]
except KeyError as e:
raise ValueError(
f"{provider_name} is not part of the ProviderRegistry. "
f"Available providers are: {list(self.provider_mapping.keys())}"
) from e
api_key = self.api_keys[provider_name]
fetch_dict = provider.fetcher_dict[query_name]
fetcher = fetch_dict.get(query.__name__) # type: ignore
if fetcher is None:
raise ValueError(
f"This query is not supported by the {provider_name} provider. "
f"Please try another provider: {ProviderNameType.__args__}"
)
try:
if data_name == "standardized":
result = getattr(fetcher, data_name)(query, api_key)
else:
result = getattr(fetcher, data_name)(query, extra_params, api_key)
return process(result, data_orientation)
except Exception as e:
raise RuntimeError(
f"The {provider_name} provider failed to fetch the data: {e}"
) from e
def fetch(
self,
provider_name: ProviderNameType,
query: QueryParams,
extra_params: Optional[Dict] = None,
data_orientation: orients = "RECORDS",
):
return self.__fetch_factory__(
provider_name,
query,
extra_params,
"get_query_type",
"fetch_data",
data_orientation,
)
def fetch_provider_data(
self,
provider_name: ProviderNameType,
query: QueryParams,
extra_params: Optional[Dict] = None,
data_orientation: orients = "RECORDS",
):
return self.__fetch_factory__(
provider_name,
query,
extra_params,
"get_query_type",
"fetch_provider_data",
data_orientation,
)
def standardized(
self,
provider_name: ProviderNameType,
query: QueryParams,
extra_params: Optional[Dict] = None,
data_orientation: orients = "RECORDS",
):
return self.__fetch_factory__(
provider_name,
query,
extra_params,
"get_provider_query_type",
"standardized",
data_orientation,
)
def simple(
self,
provider_name: ProviderNameType,
query: QueryParams,
extra_params: Optional[Dict] = None,
data_orientation: orients = "RECORDS",
):
return self.__fetch_factory__(
provider_name,
query,
extra_params,
"get_provider_query_type",
"simple",
data_orientation,
)
class Builder:
"""A Builder class builds out the provider table by adding providers and their
API keys to it. It can build multiple different types of Provider Registries
with their own state.
"""
def __init__(self) -> None:
self.provider_registry = ProviderRegistry()
self.api_keys: Dict[ProviderNameType, str] = {}
def add_providers(self, providers: List[Provider]):
for provider in providers:
self.provider_registry.add(provider)
return f"{len(providers)} providers have been added."
def add_api_key(self, provider_name: ProviderNameType, api_key: str) -> str:
if provider_name not in self.api_keys:
self.api_keys[provider_name] = api_key
else:
raise ValueError(
f"API key for {provider_name} is already in the ProviderRegistry."
)
self.provider_registry.api_keys[provider_name] = api_key
return f"API key for {provider_name} has been added."
def add_keys(self, api_keys: Dict[ProviderNameType, str]) -> str:
for provider_name, api_key in api_keys.items():
self.add_api_key(provider_name, api_key)
return f"{len(api_keys)} API keys have been added."
def build(self) -> ProviderRegistry:
return self.provider_registry
def load_extensions(
entry_point_group: str = "openbb_provider_extension",
) -> Tuple[list, dict]:
"""Load extensions from entry points and their API keys from settings.
Parameters
----------
entry_point_group : str
The entry point group to load extensions from.
Returns
-------
Tuple[list, dict]
A tuple of the extensions and their API keys.
"""
extensions = []
extension_api_keys = {}
entry_points = pkg_resources.iter_entry_points(entry_point_group)
for entry_point in entry_points:
extensions.append(entry_point.load())
for extension in extensions:
extension_name = extension.name
try:
if extension_name in ProviderNameType.__args__:
extension_api_keys[extension_name] = getattr(
settings, f"{extension_name.upper()}_API_KEY"
)
except AttributeError as exc:
raise ValueError(f"API key for {extension_name} is not set.") from exc
return extensions, extension_api_keys
entry_point_extensions, entry_point_extension_api_keys = load_extensions(
"openbb_provider_extension"
)
builder = Builder()
builder.add_keys(entry_point_extension_api_keys)
builder.add_providers(entry_point_extensions)
provider_registry = builder.build()

View File

@@ -0,0 +1,7 @@
"""Provider types helper module."""
from typing import List, Optional
OptListInt = Optional[List[Optional[int]]]
OptListStr = Optional[List[Optional[str]]]
OptListFloat = Optional[List[Optional[float]]]

View File

@@ -0,0 +1,32 @@
"""Settings for the openbb_provider package."""
# IMPORT STANDARD
import os
from typing import Optional
# IMPORT THIRD-PARTY
from pydantic import BaseSettings
from pydantic.error_wrappers import ValidationError
# IMPORT INTERNAL
def create_path(*path: str) -> str:
base_path = os.path.dirname(os.path.abspath(__file__))
in_between = os.path.dirname(base_path)
default_path = os.path.join(in_between, *path)
return default_path
class Settings(BaseSettings):
FMP_API_KEY: Optional[str] = None
POLYGON_API_KEY: Optional[str] = None
BENZINGA_API_KEY: Optional[str] = None
DEBUG_MODE: bool = False
try:
settings = Settings() # type: ignore[call-arg]
except ValidationError:
env_path = create_path(".env")
settings = Settings(env_path) # type: ignore[call-arg,misc,arg-type]