From 78695fa6de3ee46182f5531f620d6607fd0cc1d9 Mon Sep 17 00:00:00 2001 From: Danglewood <85772166+deeleeramone@users.noreply.github.com> Date: Thu, 21 Mar 2024 02:26:19 -0700 Subject: [BugFix] Return FMP Error Messages (#6237) * response callback and equity quote * merge branch develop * fix some more * static files * test param * executive comp * some more fetchers * test cassette * black * another one * some more * etf equity exposure * price_performance * black * ruff * test params * more test params --------- Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com> --- .../provider/standard_models/analyst_estimates.py | 112 +-- .../standard_models/executive_compensation.py | 62 +- .../provider/standard_models/historical_splits.py | 16 +- .../equity/integration/test_equity_api.py | 5 +- .../equity/integration/test_equity_python.py | 5 +- openbb_platform/openbb/assets/reference.json | 167 ++-- openbb_platform/openbb/package/equity_estimates.py | 88 +-- .../openbb/package/equity_fundamental.py | 24 +- openbb_platform/openbb/package/equity_price.py | 2 +- .../fmp/openbb_fmp/models/analyst_estimates.py | 45 +- .../fmp/openbb_fmp/models/company_filings.py | 26 +- .../fmp/openbb_fmp/models/equity_profile.py | 31 +- .../fmp/openbb_fmp/models/equity_quote.py | 46 +- .../models/equity_valuation_multiples.py | 42 +- .../fmp/openbb_fmp/models/etf_countries.py | 53 +- .../fmp/openbb_fmp/models/etf_equity_exposure.py | 16 +- .../fmp/openbb_fmp/models/etf_holdings.py | 6 +- .../providers/fmp/openbb_fmp/models/etf_info.py | 6 +- .../openbb_fmp/models/executive_compensation.py | 89 ++- .../fmp/openbb_fmp/models/financial_ratios.py | 13 +- .../providers/fmp/openbb_fmp/models/key_metrics.py | 73 +- .../fmp/openbb_fmp/models/price_performance.py | 10 + .../fmp/openbb_fmp/models/price_target.py | 36 +- .../openbb_fmp/models/price_target_consensus.py | 47 +- .../providers/fmp/openbb_fmp/utils/helpers.py | 57 +- ...est_fmp_equity_valuation_multiples_fetcher.yaml | 54 +- .../test_fmp_key_metrics_fetcher.yaml | 843 +++++++++++---------- .../providers/fmp/tests/test_fmp_fetchers.py | 2 +- 28 files changed, 1094 insertions(+), 882 deletions(-) diff --git a/openbb_platform/core/openbb_core/provider/standard_models/analyst_estimates.py b/openbb_platform/core/openbb_core/provider/standard_models/analyst_estimates.py index 4a4e76c796d..4e49cdbf98d 100644 --- a/openbb_platform/core/openbb_core/provider/standard_models/analyst_estimates.py +++ b/openbb_platform/core/openbb_core/provider/standard_models/analyst_estimates.py @@ -1,7 +1,7 @@ """Analyst Estimates Standard Model.""" from datetime import date as dateType -from typing import List, Literal, Optional, Set, Union +from typing import Optional from pydantic import Field, field_validator @@ -17,10 +17,6 @@ class AnalystEstimatesQueryParams(QueryParams): """Analyst Estimates Query.""" symbol: str = Field(description=QUERY_DESCRIPTIONS.get("symbol", "")) - period: Literal["quarter", "annual"] = Field( - default="annual", description=QUERY_DESCRIPTIONS.get("period", "") - ) - limit: int = Field(default=30, description=QUERY_DESCRIPTIONS.get("limit", "")) @field_validator("symbol", mode="before", check_fields=False) @classmethod @@ -28,57 +24,69 @@ class AnalystEstimatesQueryParams(QueryParams): """Convert field to uppercase.""" return v.upper() - @field_validator("period", mode="before", check_fields=False) - @classmethod - def to_lower(cls, v: Optional[str]) -> Optional[str]: - """Convert field to lowercase.""" - return v.lower() if v else v - class AnalystEstimatesData(Data): """Analyst Estimates data.""" symbol: str = Field(description=DATA_DESCRIPTIONS.get("symbol", "")) date: dateType = Field(description=DATA_DESCRIPTIONS.get("date", "")) - estimated_revenue_low: ForceInt = Field(description="Estimated revenue low.") - estimated_revenue_high: ForceInt = Field(description="Estimated revenue high.") - estimated_revenue_avg: ForceInt = Field(description="Estimated revenue average.") - estimated_ebitda_low: ForceInt = Field(description="Estimated EBITDA low.") - estimated_ebitda_high: ForceInt = Field(description="Estimated EBITDA high.") - estimated_ebitda_avg: ForceInt = Field(description="Estimated EBITDA average.") - estimated_ebit_low: ForceInt = Field(description="Estimated EBIT low.") - estimated_ebit_high: ForceInt = Field(description="Estimated EBIT high.") - estimated_ebit_avg: ForceInt = Field(description="Estimated EBIT average.") - estimated_net_income_low: ForceInt = Field(description="Estimated net income low.") - estimated_net_income_high: ForceInt = Field( - description="Estimated net income high." - ) - estimated_net_income_avg: ForceInt = Field( - description="Estimated net income average." - ) - estimated_sga_expense_low: ForceInt = Field( - description="Estimated SGA expense low." - ) - estimated_sga_expense_high: ForceInt = Field( - description="Estimated SGA expense high." - ) - estimated_sga_expense_avg: ForceInt = Field( - description="Estimated SGA expense average." - ) - estimated_eps_avg: float = Field(description="Estimated EPS average.") - estimated_eps_high: float = Field(description="Estimated EPS high.") - estimated_eps_low: float = Field(description="Estimated EPS low.") - number_analyst_estimated_revenue: ForceInt = Field( - description="Number of analysts who estimated revenue." - ) - number_analysts_estimated_eps: ForceInt = Field( - description="Number of analysts who estimated EPS." + estimated_revenue_low: Optional[ForceInt] = Field( + default=None, description="Estimated revenue low." + ) + estimated_revenue_high: Optional[ForceInt] = Field( + default=None, description="Estimated revenue high." + ) + estimated_revenue_avg: Optional[ForceInt] = Field( + default=None, description="Estimated revenue average." + ) + estimated_sga_expense_low: Optional[ForceInt] = Field( + default=None, description="Estimated SGA expense low." + ) + estimated_sga_expense_high: Optional[ForceInt] = Field( + default=None, description="Estimated SGA expense high." + ) + estimated_sga_expense_avg: Optional[ForceInt] = Field( + default=None, description="Estimated SGA expense average." + ) + estimated_ebitda_low: Optional[ForceInt] = Field( + default=None, description="Estimated EBITDA low." + ) + estimated_ebitda_high: Optional[ForceInt] = Field( + default=None, description="Estimated EBITDA high." + ) + estimated_ebitda_avg: Optional[ForceInt] = Field( + default=None, description="Estimated EBITDA average." + ) + estimated_ebit_low: Optional[ForceInt] = Field( + default=None, description="Estimated EBIT low." + ) + estimated_ebit_high: Optional[ForceInt] = Field( + default=None, description="Estimated EBIT high." + ) + estimated_ebit_avg: Optional[ForceInt] = Field( + default=None, description="Estimated EBIT average." + ) + estimated_net_income_low: Optional[ForceInt] = Field( + default=None, description="Estimated net income low." + ) + estimated_net_income_high: Optional[ForceInt] = Field( + default=None, description="Estimated net income high." + ) + estimated_net_income_avg: Optional[ForceInt] = Field( + default=None, description="Estimated net income average." + ) + estimated_eps_avg: Optional[float] = Field( + default=None, description="Estimated EPS average." + ) + estimated_eps_high: Optional[float] = Field( + default=None, description="Estimated EPS high." + ) + estimated_eps_low: Optional[float] = Field( + default=None, description="Estimated EPS low." + ) + number_analyst_estimated_revenue: Optional[ForceInt] = Field( + default=None, description="Number of analysts who estimated revenue." + ) + number_analysts_estimated_eps: Optional[ForceInt] = Field( + default=None, description="Number of analysts who estimated EPS." ) - - @field_validator("symbol", mode="before", check_fields=False) - @classmethod - def to_upper(cls, v: Union[str, List[str], Set[str]]): - """Convert field to uppercase.""" - if isinstance(v, str): - return v.upper() - return ",".join([symbol.upper() for symbol in list(v)]) if v else None diff --git a/openbb_platform/core/openbb_core/provider/standard_models/executive_compensation.py b/openbb_platform/core/openbb_core/provider/standard_models/executive_compensation.py index 7cf723f74ba..e2dea12ed25 100644 --- a/openbb_platform/core/openbb_core/provider/standard_models/executive_compensation.py +++ b/openbb_platform/core/openbb_core/provider/standard_models/executive_compensation.py @@ -1,10 +1,6 @@ """Executive Compensation Standard Model.""" -from datetime import ( - date as dateType, - datetime, -) -from typing import List, Optional, Set, Union +from typing import Optional from pydantic import Field, NonNegativeFloat, field_validator @@ -20,14 +16,6 @@ class ExecutiveCompensationQueryParams(QueryParams): """Executive Compensation Query.""" symbol: str = Field(description=QUERY_DESCRIPTIONS.get("symbol", "")) - start_date: Optional[dateType] = Field( - default=None, - description=QUERY_DESCRIPTIONS.get("start_date", ""), - ) - end_date: Optional[dateType] = Field( - default=None, - description=QUERY_DESCRIPTIONS.get("end_date", ""), - ) @field_validator("symbol", mode="before", check_fields=False) @classmethod @@ -41,29 +29,31 @@ class ExecutiveCompensationData(Data): symbol: str = Field(description=DATA_DESCRIPTIONS.get("symbol", "")) cik: Optional[str] = Field( - default=None, - description=DATA_DESCRIPTIONS.get("cik", ""), + default=None, description=DATA_DESCRIPTIONS.get("cik", "") ) - filing_date: dateType = Field(description="Date of the filing.") - accepted_date: datetime = Field(description="Date the filing was accepted.") - name_and_position: str = Field(description="Name and position of the executive.") - year: int = Field(description="Year of the compensation.") - salary: NonNegativeFloat = Field(description="Salary of the executive.") - bonus: NonNegativeFloat = Field(description="Bonus of the executive.") - stock_award: NonNegativeFloat = Field(description="Stock award of the executive.") - incentive_plan_compensation: NonNegativeFloat = Field( - description="Incentive plan compensation of the executive." + company_name: Optional[str] = Field( + default=None, description="The name of the company." ) - all_other_compensation: NonNegativeFloat = Field( - description="All other compensation of the executive." + industry: Optional[str] = Field( + default=None, description="The industry of the company." + ) + year: Optional[int] = Field(default=None, description="Year of the compensation.") + name_and_position: Optional[str] = Field( + default=None, description="Name and position." + ) + salary: Optional[NonNegativeFloat] = Field(default=None, description="Salary.") + bonus: Optional[NonNegativeFloat] = Field( + default=None, description="Bonus payments." + ) + stock_award: Optional[NonNegativeFloat] = Field( + default=None, description="Stock awards." + ) + incentive_plan_compensation: Optional[NonNegativeFloat] = Field( + default=None, description="Incentive plan compensation." + ) + all_other_compensation: Optional[NonNegativeFloat] = Field( + default=None, description="All other compensation." + ) + total: Optional[NonNegativeFloat] = Field( + default=None, description="Total compensation." ) - total: NonNegativeFloat = Field(description="Total compensation of the executive.") - url: str = Field(description="URL of the filing data.") - - @field_validator("symbol", mode="before", check_fields=False) - @classmethod - def to_upper(cls, v: Union[str, List[str], Set[str]]): - """Convert field to uppercase.""" - if isinstance(v, str): - return v.upper() - return ",".join([symbol.upper() for symbol in list(v)]) diff --git a/openbb_platform/core/openbb_core/provider/standard_models/historical_splits.py b/openbb_platform/core/openbb_core/provider/standard_models/historical_splits.py index 504e3a92d53..d088c65a1ee 100644 --- a/openbb_platform/core/openbb_core/provider/standard_models/historical_splits.py +++ b/openbb_platform/core/openbb_core/provider/standard_models/historical_splits.py @@ -1,6 +1,7 @@ """Historical Splits Standard Model.""" from datetime import date as dateType +from typing import Optional from pydantic import Field, field_validator @@ -28,8 +29,15 @@ class HistoricalSplitsData(Data): """Historical Splits Data.""" date: dateType = Field(description=DATA_DESCRIPTIONS.get("date", "")) - label: str = Field(description="Label of the historical stock splits.") - numerator: float = Field(description="Numerator of the historical stock splits.") - denominator: float = Field( - description="Denominator of the historical stock splits." + numerator: Optional[float] = Field( + default=None, + description="Numerator of the split.", + ) + denominator: Optional[float] = Field( + default=None, + description="Denominator of the split.", + ) + split_ratio: Optional[str] = Field( + default=None, + description="Split ratio.", ) diff --git a/openbb_platform/extensions/equity/integration/test_equity_api.py b/openbb_platform/extensions/equity/integration/test_equity_api.py index 97b56b20045..f30e471e073 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_api.py +++ b/openbb_platform/extensions/equity/integration/test_equity_api.py @@ -235,8 +235,7 @@ def test_equity_fundamental_cash_growth(params, headers): ( { "symbol": "AAPL", - "start_date": "2020-01-01", - "end_date": "2021-01-01", + "year": 2022, "provider": "fmp", } ), @@ -244,12 +243,14 @@ def test_equity_fundamental_cash_growth(params, headers): { "symbol": "AAPL", "provider": "fmp", + "year": None, } ), ( { "symbol": "AAPL,MSFT", "provider": "fmp", + "year": None, } ), ], diff --git a/openbb_platform/extensions/equity/integration/test_equity_python.py b/openbb_platform/extensions/equity/integration/test_equity_python.py index 8b802da8dcf..671df076840 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_python.py +++ b/openbb_platform/extensions/equity/integration/test_equity_python.py @@ -217,8 +217,7 @@ def test_equity_fundamental_cash_growth(params, obb): ( { "symbol": "AAPL", - "start_date": "2020-01-01", - "end_date": "2021-01-01", + "year": 2022, "provider": "fmp", } ), @@ -226,12 +225,14 @@ def test_equity_fundamental_cash_growth(params, obb): { "symbol": "AAPL", "provider": "fmp", + "year": None, } ), ( { "symbol": "AAPL,MSFT", "provider": "fmp", + "year": None, } ), ], diff --git a/openbb_platform/openbb/assets/reference.json b/openbb_platform/openbb/assets/reference.json index 96162f453bf..13c7fda420d 100644 --- a/openbb_platform/openbb/assets/reference.json +++ b/openbb_platform/openbb/assets/reference.json @@ -4310,7 +4310,7 @@ { "name": "symbol", "type": "Union[str, List[str]]", - "description": "Symbol to get data for. Multiple items allowed for provider(s): benzinga.", + "description": "Symbol to get data for. Multiple items allowed for provider(s): benzinga, fmp.", "default": null, "optional": true }, @@ -4657,11 +4657,20 @@ "standard": [ { "name": "symbol", - "type": "str", - "description": "Symbol to get data for.", + "type": "Union[str, List[str]]", + "description": "Symbol to get data for. Multiple items allowed for provider(s): fmp.", "default": "", "optional": false }, + { + "name": "provider", + "type": "Literal['fmp']", + "description": "The provider to use for the query, by default None. If None, the provider specified in defaults is selected or 'fmp' if there is no default.", + "default": "fmp", + "optional": true + } + ], + "fmp": [ { "name": "period", "type": "Literal['quarter', 'annual']", @@ -4673,18 +4682,10 @@ "name": "limit", "type": "int", "description": "The number of data entries to return.", - "default": 30, - "optional": true - }, - { - "name": "provider", - "type": "Literal['fmp']", - "description": "The provider to use for the query, by default None. If None, the provider specified in defaults is selected or 'fmp' if there is no default.", - "default": "fmp", + "default": null, "optional": true } - ], - "fmp": [] + ] }, "returns": { "OBBject": [ @@ -4735,141 +4736,141 @@ "name": "estimated_revenue_low", "type": "int", "description": "Estimated revenue low.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_revenue_high", "type": "int", "description": "Estimated revenue high.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_revenue_avg", "type": "int", "description": "Estimated revenue average.", - "default": "", - "optional": false + "default": null, + "optional": true + }, + { + "name": "estimated_sga_expense_low", + "type": "int", + "description": "Estimated SGA expense low.", + "default": null, + "optional": true + }, + { + "name": "estimated_sga_expense_high", + "type": "int", + "description": "Estimated SGA expense high.", + "default": null, + "optional": true + }, + { + "name": "estimated_sga_expense_avg", + "type": "int", + "description": "Estimated SGA expense average.", + "default": null, + "optional": true }, { "name": "estimated_ebitda_low", "type": "int", "description": "Estimated EBITDA low.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_ebitda_high", "type": "int", "description": "Estimated EBITDA high.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_ebitda_avg", "type": "int", "description": "Estimated EBITDA average.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_ebit_low", "type": "int", "description": "Estimated EBIT low.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_ebit_high", "type": "int", "description": "Estimated EBIT high.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_ebit_avg", "type": "int", "description": "Estimated EBIT average.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_net_income_low", "type": "int", "description": "Estimated net income low.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_net_income_high", "type": "int", "description": "Estimated net income high.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_net_income_avg", "type": "int", "description": "Estimated net income average.", - "default": "", - "optional": false - }, - { - "name": "estimated_sga_expense_low", - "type": "int", - "description": "Estimated SGA expense low.", - "default": "", - "optional": false - }, - { - "name": "estimated_sga_expense_high", - "type": "int", - "description": "Estimated SGA expense high.", - "default": "", - "optional": false - }, - { - "name": "estimated_sga_expense_avg", - "type": "int", - "description": "Estimated SGA expense average.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_eps_avg", "type": "float", "description": "Estimated EPS average.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_eps_high", "type": "float", "description": "Estimated EPS high.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "estimated_eps_low", "type": "float", "description": "Estimated EPS low.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "number_analyst_estimated_revenue", "type": "int", "description": "Number of analysts who estimated revenue.", - "default": "", - "optional": false + "default": null, + "optional": true }, { "name": "number_analysts_estimated_eps", "type": "int", "description": "Number of analysts who estimated EPS.", - "default": "", - "optional": false + "default": null, + "optional": true } ], "fmp": [] @@ -4888,7 +4889,7 @@ { "name": "symbol", "type": "Union[str, List[str]]", - "description": "Symbol to get data for. Multiple items allowed for provider(s): yfinance.", + "description": "Symbol to get data for. Multiple items allowed for provider(s): fmp, yfinance.", "default": "", "optional": false }, @@ -15039,26 +15040,26 @@ "default": "", "optional": false }, - { - "name": "label", - "type": "str", - "description": "Label of the historical stock splits.", - "default": "", - "optional": false - }, { "name": "numerator", "type": "float", - "description": "Numerator of the historical stock splits.", - "default": "", - "optional": false + "description": "Numerator of the split.", + "default": null, + "optional": true }, { "name": "denominator", "type": "float", - "description": "Denominator of the historical stock splits.", - "default": "", - "optional": false + "description": "Denominator of the split.", + "default": null, + "optional": true + }, + { + "name": "split_ratio", + "type": "str", + "description": "Split ratio.", + "default": null, + "optional": true } ], "fmp": [] @@ -16950,7 +16951,7 @@ }, { "name": "earnings_announcement", - "type": "Union[datetime, str]", + "type": "datetime", "description": "Upcoming earnings announcement date.", "default": null, "optional": true diff --git a/openbb_platform/openbb/package/equity_estimates.py b/openbb_platform/openbb/package/equity_estimates.py index 4016105cc9d..b2921e97b77 100644 --- a/openbb_platform/openbb/package/equity_estimates.py +++ b/openbb_platform/openbb/package/equity_estimates.py @@ -205,7 +205,7 @@ class ROUTER_equity_estimates(Container): symbol: Annotated[ Union[str, List[str]], OpenBBCustomParameter( - description="Symbol to get data for. Multiple items allowed for provider(s): yfinance." + description="Symbol to get data for. Multiple items allowed for provider(s): fmp, yfinance." ), ], provider: Annotated[ @@ -221,7 +221,7 @@ class ROUTER_equity_estimates(Container): Parameters ---------- symbol : Union[str, List[str]] - Symbol to get data for. Multiple items allowed for provider(s): yfinance. + Symbol to get data for. Multiple items allowed for provider(s): fmp, yfinance. provider : Optional[Literal['fmp', 'yfinance']] The provider to use for the query, by default None. If None, the provider specified in defaults is selected or 'fmp' if there is @@ -230,7 +230,7 @@ class ROUTER_equity_estimates(Container): Returns ------- OBBject - results : Union[List[PriceTargetConsensus], PriceTargetConsensus] + results : List[PriceTargetConsensus] Serializable results. provider : Optional[Literal['fmp', 'yfinance']] Provider name. @@ -285,7 +285,7 @@ class ROUTER_equity_estimates(Container): "symbol": symbol, }, extra_params=kwargs, - extra_info={"symbol": {"multiple_items_allowed": ["yfinance"]}}, + extra_info={"symbol": {"multiple_items_allowed": ["fmp", "yfinance"]}}, ) ) @@ -294,16 +294,11 @@ class ROUTER_equity_estimates(Container): def historical( self, symbol: Annotated[ - str, OpenBBCustomParameter(description="Symbol to get data for.") + Union[str, List[str]], + OpenBBCustomParameter( + description="Symbol to get data for. Multiple items allowed for provider(s): fmp." + ), ], - period: Annotated[ - Literal["quarter", "annual"], - OpenBBCustomParameter(description="Time period of the data to return."), - ] = "annual", - limit: Annotated[ - int, - OpenBBCustomParameter(description="The number of data entries to return."), - ] = 30, provider: Annotated[ Optional[Literal["fmp"]], OpenBBCustomParameter( @@ -316,16 +311,16 @@ class ROUTER_equity_estimates(Container): Parameters ---------- - symbol : str - Symbol to get data for. - period : Literal['quarter', 'annual'] - Time period of the data to return. - limit : int - The number of data entries to return. + symbol : Union[str, List[str]] + Symbol to get data for. Multiple items allowed for provider(s): fmp. provider : Optional[Literal['fmp']] The provider to use for the query, by default None. If None, the provider specified in defaults is selected or 'fmp' if there is no default. + period : Literal['quarter', 'annual'] + Time period of the data to return. (provider: fmp) + limit : Optional[int] + The number of data entries to return. (provider: fmp) Returns ------- @@ -347,45 +342,45 @@ class ROUTER_equity_estimates(Container): Symbol representing the entity requested in the data. date : date The date of the data. - estimated_revenue_low : int + estimated_revenue_low : Optional[int] Estimated revenue low. - estimated_revenue_high : int + estimated_revenue_high : Optional[int] Estimated revenue high. - estimated_revenue_avg : int + estimated_revenue_avg : Optional[int] Estimated revenue average. - estimated_ebitda_low : int + estimated_sga_expense_low : Optional[int] + Estimated SGA expense low. + estimated_sga_expense_high : Optional[int] + Estimated SGA expense high. + estimated_sga_expense_avg : Optional[int] + Estimated SGA expense average. + estimated_ebitda_low : Optional[int] Estimated EBITDA low. - estimated_ebitda_high : int + estimated_ebitda_high : Optional[int] Estimated EBITDA high. - estimated_ebitda_avg : int + estimated_ebitda_avg : Optional[int] Estimated EBITDA average. - estimated_ebit_low : int + estimated_ebit_low : Optional[int] Estimated EBIT low. - estimated_ebit_high : int + estimated_ebit_high : Optional[int] Estimated EBIT high. - estimated_ebit_avg : int + estimated_ebit_avg : Optional[int] Estimated EBIT average. - estimated_net_income_low : int + estimated_net_income_low : Optional[int] Estimated net income low. - estimated_net_income_high : int + estimated_net_income_high : Optional[int] Estimated net income high. - estimated_net_income_avg : int + estimated_net_income_avg : Optional[int] Estimated net income average. - estimated_sga_expense_low : int - Estimated SGA expense low. - estimated_sga_expense_high : int - Estimated SGA expense high. - estimated_sga_expense_avg : int - Estimated SGA expense average. - estimated_eps_avg : float + estimated_eps_avg : Optional[float] Estimated EPS average. - estimated_eps_high : float + estimated_eps_high : Optional[float] Estimated EPS high. - estimated_eps_low : float + estimated_eps_low : Optional[float] Estimated EPS low. - number_analyst_estimated_revenue : int + number_analyst_estimated_revenue : Optional[int] Number of analysts who estimated revenue. - number_analysts_estimated_eps : int + number_analysts_estimated_eps : Optional[int] Number of analysts who estimated EPS. Examples @@ -406,10 +401,9 @@ class ROUTER_equity_estimates(Container): }, standard_params={ "symbol": symbol, - "period": period, - "limit": limit, }, extra_params=kwargs, + extra_info={"symbol": {"multiple_items_allowed": ["fmp"]}}, ) ) @@ -420,7 +414,7 @@ class ROUTER_equity_estimates(Container): symbol: Annotated[ Union[str, None, List[Optional[str]]], OpenBBCustomParameter( - description="Symbol to get data for. Multiple items allowed for provider(s): benzinga." + description="Symbol to get data for. Multiple items allowed for provider(s): benzinga, fmp." ), ] = None, limit: Annotated[ @@ -440,7 +434,7 @@ class ROUTER_equity_estimates(Container): Parameters ---------- symbol : Union[str, None, List[Optional[str]]] - Symbol to get data for. Multiple items allowed for provider(s): benzinga. + Symbol to get data for. Multiple items allowed for provider(s): benzinga, fmp. limit : int The number of data entries to return. provider : Optional[Literal['benzinga', 'fmp']] @@ -566,6 +560,6 @@ class ROUTER_equity_estimates(Container): "limit": limit, }, extra_params=kwargs, - extra_info={"symbol": {"multiple_items_allowed": ["benzinga"]}}, + extra_info={"symbol": {"multiple_items_allowed": ["benzinga", "fmp"]}}, ) ) diff --git a/openbb_platform/openbb/package/equity_fundamental.py b/openbb_platform/openbb/package/equity_fundamental.py index 862cb291ef4..6e23c198aa6 100644 --- a/openbb_platform/openbb/package/equity_fundamental.py +++ b/openbb_platform/openbb/package/equity_fundamental.py @@ -1586,12 +1586,12 @@ class ROUTER_equity_fundamental(Container): ---------------- date : date The date of the data. - label : str - Label of the historical stock splits. - numerator : float - Numerator of the historical stock splits. - denominator : float - Denominator of the historical stock splits. + numerator : Optional[float] + Numerator of the split. + denominator : Optional[float] + Denominator of the split. + split_ratio : Optional[str] + Split ratio. Examples -------- @@ -1992,7 +1992,7 @@ class ROUTER_equity_fundamental(Container): OpenBBCustomParameter(description="The number of data entries to return."), ] = 10, period: Annotated[ - Literal["quarter", "annual"], + Literal["annual", "quarter"], OpenBBCustomParameter(description="Time period of the data to return."), ] = "annual", provider: Annotated[ @@ -2011,7 +2011,7 @@ class ROUTER_equity_fundamental(Container): Symbol to get data for. limit : int The number of data entries to return. - period : Literal['quarter', 'annual'] + period : Literal['annual', 'quarter'] Time period of the data to return. provider : Optional[Literal['fmp']] The provider to use for the query, by default None. @@ -3379,7 +3379,7 @@ class ROUTER_equity_fundamental(Container): str, OpenBBCustomParameter(description="Symbol to get data for.") ], period: Annotated[ - Literal["quarter", "annual"], + Literal["annual", "quarter"], OpenBBCustomParameter(description="Time period of the data to return."), ] = "annual", structure: Annotated[ @@ -3400,7 +3400,7 @@ class ROUTER_equity_fundamental(Container): ---------- symbol : str Symbol to get data for. - period : Literal['quarter', 'annual'] + period : Literal['annual', 'quarter'] Time period of the data to return. structure : Literal['hierarchical', 'flat'] Structure of the returned data. @@ -3470,7 +3470,7 @@ class ROUTER_equity_fundamental(Container): str, OpenBBCustomParameter(description="Symbol to get data for.") ], period: Annotated[ - Literal["quarter", "annual"], + Literal["annual", "quarter"], OpenBBCustomParameter(description="Time period of the data to return."), ] = "annual", structure: Annotated[ @@ -3491,7 +3491,7 @@ class ROUTER_equity_fundamental(Container): ---------- symbol : str Symbol to get data for. - period : Literal['quarter', 'annual'] + period : Literal['annual', 'quarter'] Time period of the data to return. structure : Literal['hierarchical', 'flat'] Structure of the returned data. diff --git a/openbb_platform/openbb/package/equity_price.py b/openbb_platform/openbb/package/equity_price.py index e0baa4ecd7a..608c1435db4 100644 --- a/openbb_platform/openbb/package/equity_price.py +++ b/openbb_platform/openbb/package/equity_price.py @@ -540,7 +540,7 @@ class ROUTER_equity_price(Container): Earnings per share. (provider: fmp) pe : Optional[float] Price earnings ratio. (provider: fmp) - earnings_announcement : Optional[Union[datetime, str]] + earnings_announcement : Optional[datetime] Upcoming earnings announcement date. (provider: fmp) is_darkpool : Optional[bool] Whether or not the current trade is from a darkpool. (provider: intrinio) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/analyst_estimates.py b/openbb_platform/providers/fmp/openbb_fmp/models/analyst_estimates.py index d525cf121d6..6d1e5c9e335 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/analyst_estimates.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/analyst_estimates.py @@ -1,13 +1,19 @@ """FMP Analyst Estimates Model.""" -from typing import Any, Dict, List, Optional +import asyncio +from typing import Any, Dict, List, Literal, Optional +from warnings import warn from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.analyst_estimates import ( AnalystEstimatesData, AnalystEstimatesQueryParams, ) -from openbb_fmp.utils.helpers import create_url, get_data_many +from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request +from openbb_fmp.utils.helpers import create_url, response_callback +from pydantic import Field class FMPAnalystEstimatesQueryParams(AnalystEstimatesQueryParams): @@ -16,6 +22,15 @@ class FMPAnalystEstimatesQueryParams(AnalystEstimatesQueryParams): Source: https://site.financialmodelingprep.com/developer/docs/analyst-estimates-api/ """ + __json_schema_extra__ = {"symbol": ["multiple_items_allowed"]} + + period: Literal["quarter", "annual"] = Field( + default="annual", description=QUERY_DESCRIPTIONS.get("period", "") + ) + limit: Optional[int] = Field( + default=None, description=QUERY_DESCRIPTIONS.get("limit", "") + ) + class FMPAnalystEstimatesData(AnalystEstimatesData): """FMP Analyst Estimates Data.""" @@ -43,11 +58,29 @@ class FMPAnalystEstimatesFetcher( """Return the raw data from the FMP endpoint.""" api_key = credentials.get("fmp_api_key") if credentials else "" - url = create_url( - 3, f"analyst-estimates/{query.symbol}", api_key, query, ["symbol"] - ) + symbols = query.symbol.split(",") # type: ignore + + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + url = create_url( + 3, f"analyst-estimates/{symbol}", api_key, query, ["symbol"] + ) + result = await amake_request( + url, response_callback=response_callback, **kwargs + ) + if not result or len(result) == 0: + warn(f"Symbol Error: No data found for {symbol}") + if result: + results.extend(result) + + await asyncio.gather(*[get_one(symbol) for symbol in symbols]) + + if not results: + raise EmptyDataError("No data returned for the given symbols.") - return await get_data_many(url, **kwargs) + return sorted(results, key=lambda x: (x["date"], x["symbol"]), reverse=False) @staticmethod def transform_data( diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/company_filings.py b/openbb_platform/providers/fmp/openbb_fmp/models/company_filings.py index e1820839555..226c12bd1eb 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/company_filings.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/company_filings.py @@ -1,5 +1,6 @@ """FMP Company Filings Model.""" +import asyncio import math from typing import Any, Dict, List, Optional @@ -8,7 +9,9 @@ from openbb_core.provider.standard_models.company_filings import ( CompanyFilingsData, CompanyFilingsQueryParams, ) -from openbb_core.provider.utils.helpers import amake_requests, get_querystring +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request, get_querystring +from openbb_fmp.utils.helpers import response_callback class FMPCompanyFilingsQueryParams(CompanyFilingsQueryParams): @@ -24,7 +27,7 @@ class FMPCompanyFilingsData(CompanyFilingsData): """FMP Company Filings Data.""" __alias_dict__ = { - "filing_date": "fillingDate", + "filing_date": "fillingDate", # FMP spells 'filing' wrong everywhere. "accepted_date": "acceptedDate", "report_type": "type", "filing_url": "link", @@ -65,9 +68,24 @@ class FMPCompanyFilingsFetcher( for page in range(pages) ] - data = await amake_requests(urls, **kwargs) + results = [] - return data[: query.limit] + async def get_one(url): + """Get the data from one URL.""" + result = await amake_request( + url, response_callback=response_callback, **kwargs + ) + if result: + results.extend(result) + + await asyncio.gather(*[get_one(url) for url in urls]) + + if not results: + raise EmptyDataError("No data was returned for the symbol provided.") + + return sorted(results, key=lambda x: x["fillingDate"], reverse=True)[ + : query.limit + ] @staticmethod def transform_data( diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/equity_profile.py b/openbb_platform/providers/fmp/openbb_fmp/models/equity_profile.py index bb430816b08..95a460fff79 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/equity_profile.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/equity_profile.py @@ -2,10 +2,12 @@ # pylint: disable=unused-argument +import asyncio from datetime import ( date as dateType, ) from typing import Any, Dict, List, Optional +from warnings import warn from openbb_core.provider.abstract.data import ForceInt from openbb_core.provider.abstract.fetcher import Fetcher @@ -13,7 +15,9 @@ from openbb_core.provider.standard_models.equity_info import ( EquityInfoData, EquityInfoQueryParams, ) -from openbb_core.provider.utils.helpers import amake_requests +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request +from openbb_fmp.utils.helpers import response_callback from pydantic import Field, field_validator, model_validator @@ -126,9 +130,30 @@ class FMPEquityProfileFetcher( api_key = credentials.get("fmp_api_key") if credentials else "" symbols = query.symbol.split(",") base_url = "https://financialmodelingprep.com/api/v3" - urls = [f"{base_url}/profile/{symbol}?apikey={api_key}" for symbol in symbols] - return await amake_requests(urls, **kwargs) + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + url = f"{base_url}/profile/{symbol}?apikey={api_key}" + result = await amake_request( + url, response_callback=response_callback, **kwargs + ) + if not result: + warn(f"Symbol Error: No data found for {symbol}") + + if result: + results.append(result[0]) + + await asyncio.gather(*[get_one(symbol) for symbol in symbols]) + + if not results: + raise EmptyDataError("No data found for the given symbols.") + + return sorted( + results, + key=(lambda item: (symbols.index(item.get("symbol", len(symbols))))), + ) @staticmethod def transform_data( diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/equity_quote.py b/openbb_platform/providers/fmp/openbb_fmp/models/equity_quote.py index 3cc5ecb626e..b5511730755 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/equity_quote.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/equity_quote.py @@ -1,7 +1,9 @@ """FMP Equity Quote Model.""" +import asyncio from datetime import datetime, timezone -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional +from warnings import warn from openbb_core.provider.abstract.data import ForceInt from openbb_core.provider.abstract.fetcher import Fetcher @@ -9,8 +11,9 @@ from openbb_core.provider.standard_models.equity_quote import ( EquityQuoteData, EquityQuoteQueryParams, ) -from openbb_core.provider.utils.helpers import amake_requests -from openbb_fmp.utils.helpers import get_querystring +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request +from openbb_fmp.utils.helpers import get_querystring, response_callback from pydantic import Field, field_validator @@ -54,7 +57,7 @@ class FMPEquityQuoteData(EquityQuoteData): ) eps: Optional[float] = Field(default=None, description="Earnings per share.") pe: Optional[float] = Field(default=None, description="Price earnings ratio.") - earnings_announcement: Optional[Union[datetime, str]] = Field( + earnings_announcement: Optional[datetime] = Field( default=None, description="Upcoming earnings announcement date." ) @@ -62,8 +65,10 @@ class FMPEquityQuoteData(EquityQuoteData): @classmethod def validate_last_timestamp(cls, v): # pylint: disable=E0213 """Return the date as a datetime object.""" - v = int(v) if isinstance(v, str) else v - return datetime.utcfromtimestamp(int(v)).replace(tzinfo=timezone.utc) + if v: + v = int(v) if isinstance(v, str) else v + return datetime.fromtimestamp(int(v), tz=timezone.utc) + return None @field_validator("earnings_announcement", mode="before", check_fields=False) @classmethod @@ -109,16 +114,29 @@ class FMPEquityQuoteFetcher( query_str = get_querystring(query.model_dump(), ["symbol"]) symbols = query.symbol.split(",") - symbols_split = [ - ",".join(symbols[i : i + 10]) for i in range(0, len(symbols), 10) - ] - urls = [ - f"{base_url}/quote/{symbol}?{query_str}&apikey={api_key}" - for symbol in symbols_split - ] + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + url = f"{base_url}/quote/{symbol}?{query_str}&apikey={api_key}" + result = await amake_request( + url, response_callback=response_callback, **kwargs + ) + if not result or len(result) == 0: + warn(f"Symbol Error: No data found for {symbol}") + if result and len(result) > 0: + results.extend(result) + + await asyncio.gather(*[get_one(s) for s in symbols]) + + if not results: + raise EmptyDataError("No data found for the given symbols.") - return await amake_requests(urls, **kwargs) + return sorted( + results, + key=(lambda item: (symbols.index(item.get("symbol", len(symbols))))), + ) @staticmethod def transform_data( diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/equity_valuation_multiples.py b/openbb_platform/providers/fmp/openbb_fmp/models/equity_valuation_multiples.py index a43fa0967fc..ea48b84b9db 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/equity_valuation_multiples.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/equity_valuation_multiples.py @@ -1,14 +1,19 @@ """FMP Equity Valuation Multiples Model.""" +# pylint: disable=unused-argument + +import asyncio from typing import Any, Dict, List, Optional +from warnings import warn from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.equity_valuation_multiples import ( EquityValuationMultiplesData, EquityValuationMultiplesQueryParams, ) -from openbb_core.provider.utils.helpers import ClientResponse, amake_requests -from openbb_fmp.utils.helpers import create_url +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request +from openbb_fmp.utils.helpers import create_url, response_callback class FMPEquityValuationMultiplesQueryParams(EquityValuationMultiplesQueryParams): @@ -111,24 +116,37 @@ class FMPEquityValuationMultiplesFetcher( ) -> List[Dict]: """Return the raw data from the FMP endpoint.""" api_key = credentials.get("fmp_api_key") if credentials else "" - urls = [ - create_url( + + symbols = query.symbol.split(",") + + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + url = create_url( 3, f"key-metrics-ttm/{symbol}", api_key, query, exclude=["symbol"] ) - for symbol in query.symbol.split(",") - ] + result = await amake_request( + url, response_callback=response_callback, **kwargs + ) + if not result: + warn(f"Symbol Error: No data found for {symbol}.") + if result: + data = [{**d, "symbol": symbol} for d in result] + results.extend(data) - async def callback(response: ClientResponse, _: Any) -> List[Dict]: - data = await response.json() - symbol = response.url.parts[-1] + await asyncio.gather(*[get_one(symbol) for symbol in symbols]) - return [{**d, "symbol": symbol} for d in data] + if not results: + raise EmptyDataError("No data found for given symbols.") - return await amake_requests(urls, callback, **kwargs) + return results @staticmethod def transform_data( - query: FMPEquityValuationMultiplesQueryParams, data: List[Dict], **kwargs: Any + query: FMPEquityValuationMultiplesQueryParams, + data: List[Dict], + **kwargs: Any, ) -> List[FMPEquityValuationMultiplesData]: """Return the transformed data.""" return [FMPEquityValuationMultiplesData.model_validate(d) for d in data] diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/etf_countries.py b/openbb_platform/providers/fmp/openbb_fmp/models/etf_countries.py index 4ffd1e762d6..13803e791d2 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/etf_countries.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/etf_countries.py @@ -1,14 +1,18 @@ """FMP ETF Countries Model.""" +import asyncio from typing import Any, Dict, List, Optional +from warnings import warn -import pandas as pd from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.etf_countries import ( EtfCountriesData, EtfCountriesQueryParams, ) -from openbb_fmp.utils.helpers import create_url, get_data_many +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request +from openbb_fmp.utils.helpers import create_url, response_callback +from pandas import DataFrame class FMPEtfCountriesQueryParams(EtfCountriesQueryParams): @@ -42,39 +46,50 @@ class FMPEtfCountriesFetcher( ) -> List[Dict]: """Return the raw data from the FMP endpoint.""" api_key = credentials.get("fmp_api_key") if credentials else "" - symbols = ( - query.symbol.split(",") if "," in query.symbol else [query.symbol.upper()] - ) + symbols = query.symbol.split(",") results = {} - for symbol in symbols: + async def get_one(symbol): + """Get data for one symbol.""" data = {} url = create_url( version=3, endpoint=f"etf-country-weightings/{symbol}", api_key=api_key, ) - result = await get_data_many(url, **kwargs) - df = pd.DataFrame(result).set_index("country") - if len(df) > 0: - for i in df.index: - data.update( - { - i: float(df.loc[i]["weightPercentage"].replace("%", "")) - * 0.01 - } - ) - results.update({symbol: data}) + result = await amake_request( + url, response_callback=response_callback, **kwargs + ) + + if not result: + warn(f"Symbol Error: No data found for {symbol}") + + if result: + df = DataFrame(result).set_index("country") + if len(df) > 0: + for i in df.index: + data.update( + { + i: float(df.loc[i]["weightPercentage"].replace("%", "")) + * 0.01 + } + ) + results.update({symbol: data}) + + await asyncio.gather(*[get_one(symbol) for symbol in symbols]) + + if not results: + raise EmptyDataError("No data found for the given symbols.") output = ( - pd.DataFrame(results) + DataFrame(results) .transpose() .reset_index() .fillna(value=0) .replace(0, None) .rename(columns={"index": "symbol"}) ).transpose() - output.columns = output.loc["symbol"].to_list() + output.columns = output.loc["symbol"].to_list() # type: ignore output = output.drop("symbol", axis=0).sort_values( by=output.columns[0], ascending=False ) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/etf_equity_exposure.py b/openbb_platform/providers/fmp/openbb_fmp/models/etf_equity_exposure.py index 06cd0f0ba21..f204d2fa5e1 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/etf_equity_exposure.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/etf_equity_exposure.py @@ -3,8 +3,8 @@ # pylint: disable=unused-argument import asyncio -import warnings from typing import Any, Dict, List, Optional +from warnings import warn from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.etf_equity_exposure import ( @@ -13,10 +13,9 @@ from openbb_core.provider.standard_models.etf_equity_exposure import ( ) from openbb_core.provider.utils.errors import EmptyDataError from openbb_core.provider.utils.helpers import amake_request +from openbb_fmp.utils.helpers import response_callback from pydantic import field_validator -_warn = warnings.warn - class FMPEtfEquityExposureQueryParams(EtfEquityExposureQueryParams): """ @@ -70,15 +69,18 @@ class FMPEtfEquityExposureFetcher( async def get_one(symbol): """Get one symbol.""" url = f"https://financialmodelingprep.com/api/v3/etf-stock-exposure/{symbol}?apikey={api_key}" - response = await amake_request(url) + response = await amake_request( + url, response_callback=response_callback, **kwargs + ) if not response: - _warn(f"No results found for {symbol}.") - results.extend(response) + warn(f"No results found for {symbol}.") + if response: + results.extend(response) await asyncio.gather(*[get_one(symbol) for symbol in symbols]) if not results: - raise EmptyDataError() + raise EmptyDataError("No data was found for the given symbols.") return results diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/etf_holdings.py b/openbb_platform/providers/fmp/openbb_fmp/models/etf_holdings.py index 94f91942959..f2dd9a40662 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/etf_holdings.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/etf_holdings.py @@ -2,12 +2,12 @@ # pylint: disable=unused-argument -import warnings from datetime import ( date as dateType, datetime, ) from typing import Any, Dict, List, Optional, Union +from warnings import warn from openbb_core.provider.abstract.data import ForceInt from openbb_core.provider.abstract.fetcher import Fetcher @@ -19,8 +19,6 @@ from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS from openbb_fmp.utils.helpers import create_url, get_data_many from pydantic import Field, field_validator -_warn = warnings.warn - class FMPEtfHoldingsQueryParams(EtfHoldingsQueryParams): """FMP ETF Holdings Query. @@ -174,7 +172,7 @@ class FMPEtfHoldingsFetcher( try: data = await get_data_many(url, **kwargs) except Exception: - _warn( + warn( "No data found for this symbol and date, attempting to retrieve the most recent data available." ) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/etf_info.py b/openbb_platform/providers/fmp/openbb_fmp/models/etf_info.py index d6cf1ff1b8d..21cfab00a8a 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/etf_info.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/etf_info.py @@ -3,8 +3,8 @@ # pylint: disable=unused-argument import asyncio -import warnings from typing import Any, Dict, List, Optional +from warnings import warn from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.etf_info import ( @@ -14,8 +14,6 @@ from openbb_core.provider.standard_models.etf_info import ( from openbb_core.provider.utils.helpers import amake_request from pydantic import Field -_warn = warnings.warn - class FMPEtfInfoQueryParams(EtfInfoQueryParams): """FMP ETF Info Query.""" @@ -85,7 +83,7 @@ class FMPEtfInfoFetcher( url = f"https://financialmodelingprep.com/api/v4/etf-info?symbol={symbol}&apikey={api_key}" response = await amake_request(url) if not response: - _warn(f"No results found for {symbol}.") + warn(f"No results found for {symbol}.") results.extend(response) await asyncio.gather(*[get_one(symbol) for symbol in symbols]) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/executive_compensation.py b/openbb_platform/providers/fmp/openbb_fmp/models/executive_compensation.py index c3ffcb44153..5914828ed02 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/executive_compensation.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/executive_compensation.py @@ -1,16 +1,22 @@ """FMP Executive Compensation Model.""" -from datetime import datetime, timedelta +import asyncio +from datetime import ( + date as dateType, + datetime, +) from typing import Any, Dict, List, Optional +from warnings import warn from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.executive_compensation import ( ExecutiveCompensationData, ExecutiveCompensationQueryParams, ) -from openbb_core.provider.utils.helpers import amake_requests +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request from openbb_fmp.utils.helpers import response_callback -from pydantic import field_validator +from pydantic import Field, field_validator class FMPExecutiveCompensationQueryParams(ExecutiveCompensationQueryParams): @@ -21,10 +27,25 @@ class FMPExecutiveCompensationQueryParams(ExecutiveCompensationQueryParams): __json_schema_extra__ = {"symbol": ["multiple_items_allowed"]} + year: Optional[int] = Field(default=None, description="Year of the compensation.") + class FMPExecutiveCompensationData(ExecutiveCompensationData): """FMP Executive Compensation Data.""" + __alias_dict__ = { + "company_name": "companyName", + "industry": "industryTitle", + } + + filing_date: Optional[dateType] = Field( + default=None, description="Date of the filing." + ) + accepted_date: Optional[datetime] = Field( + default=None, description="Date the filing was accepted." + ) + url: Optional[str] = Field(default=None, description="URL to the filing data.") + @field_validator("filingDate", mode="before", check