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: [PATCH] [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> --- .../standard_models/analyst_estimates.py | 112 +-- .../standard_models/executive_compensation.py | 62 +- .../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/package/equity_estimates.py | 88 +- .../openbb/package/equity_fundamental.py | 24 +- .../openbb/package/equity_price.py | 2 +- .../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 +- .../openbb_fmp/models/etf_equity_exposure.py | 16 +- .../fmp/openbb_fmp/models/etf_holdings.py | 6 +- .../fmp/openbb_fmp/models/etf_info.py | 6 +- .../models/executive_compensation.py | 89 +- .../fmp/openbb_fmp/models/financial_ratios.py | 13 +- .../fmp/openbb_fmp/models/key_metrics.py | 73 +- .../openbb_fmp/models/price_performance.py | 10 + .../fmp/openbb_fmp/models/price_target.py | 36 +- .../models/price_target_consensus.py | 47 +- .../providers/fmp/openbb_fmp/utils/helpers.py | 57 +- ...mp_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 4a4e76c796d0..4e49cdbf98df 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 @@ def to_upper(cls, v: str) -> str: """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 7cf723f74ba6..e2dea12ed254 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 504e3a92d536..d088c65a1eeb 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 97b56b200454..f30e471e0736 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 8b802da8dcf0..671df0768402 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 96162f453bfa..13c7fda420d7 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 4016105cc9d6..b2921e97b77e 100644 --- a/openbb_platform/openbb/package/equity_estimates.py +++ b/openbb_platform/openbb/package/equity_estimates.py @@ -205,7 +205,7 @@ def consensus( 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 @@ def consensus( 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 @@ def consensus( Returns ------- OBBject - results : Union[List[PriceTargetConsensus], PriceTargetConsensus] + results : List[PriceTargetConsensus] Serializable results. provider : Optional[Literal['fmp', 'yfinance']] Provider name. @@ -285,7 +285,7 @@ def consensus( "symbol": symbol, }, extra_params=kwargs, - extra_info={"symbol": {"multiple_items_allowed": ["yfinance"]}}, + extra_info={"symbol": {"multiple_items_allowed": ["fmp", "yfinance"]}}, ) ) @@ -294,16 +294,11 @@ def consensus( 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 @@ def historical( 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 @@ def historical( 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 @@ def historical( }, standard_params={ "symbol": symbol, - "period": period, - "limit": limit, }, extra_params=kwargs, + extra_info={"symbol": {"multiple_items_allowed": ["fmp"]}}, ) ) @@ -420,7 +414,7 @@ def price_target( 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 @@ def price_target( 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 @@ def price_target( "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 862cb291ef40..6e23c198aa69 100644 --- a/openbb_platform/openbb/package/equity_fundamental.py +++ b/openbb_platform/openbb/package/equity_fundamental.py @@ -1586,12 +1586,12 @@ def historical_splits( ---------------- 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 @@ def income_growth( 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 @@ def income_growth( 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 @@ def revenue_per_geography( 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 @@ def revenue_per_geography( ---------- 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 @@ def revenue_per_segment( 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 @@ def revenue_per_segment( ---------- 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 e0baa4ecd7a3..608c1435db43 100644 --- a/openbb_platform/openbb/package/equity_price.py +++ b/openbb_platform/openbb/package/equity_price.py @@ -540,7 +540,7 @@ def quote( 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 d525cf121d62..6d1e5c9e335e 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 @@ async def aextract_data( """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 e18208395550..226c12bd1eb2 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 @@ 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 @@ async def aextract_data( 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 bb430816b08b..95a460fff792 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 @@ 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 @@ async def aextract_data( 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 3cc5ecb626e0..b55117307557 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 @@ 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 @@ async def aextract_data( 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 a43fa0967fc3..ea48b84b9db6 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 @@ async def aextract_data( ) -> 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 4ffd1e762d6d..13803e791d22 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 @@ async def aextract_data( ) -> 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 06cd0f0ba211..f204d2fa5e11 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.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 @@ async def aextract_data( 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 94f919429599..f2dd9a406626 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_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 @@ async def aextract_data( 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 d6cf1ff1b8d6..21cfab00a8aa 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.utils.helpers import amake_request from pydantic import Field -_warn = warnings.warn - class FMPEtfInfoQueryParams(EtfInfoQueryParams): """FMP ETF Info Query.""" @@ -85,7 +83,7 @@ async def get_one(symbol): 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 c3ffcb44153a..5914828ed024 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_fields=False) @classmethod def filing_date_validate(cls, v): # pylint: disable=E0213 @@ -39,7 +60,7 @@ def accepted_date_validate(cls, v): # pylint: disable=E0213 class FMPExecutiveCompensationFetcher( - Fetcher[ # type: ignore + Fetcher[ FMPExecutiveCompensationQueryParams, List[FMPExecutiveCompensationData], ] @@ -49,15 +70,7 @@ class FMPExecutiveCompensationFetcher( @staticmethod def transform_query(params: Dict[str, Any]) -> FMPExecutiveCompensationQueryParams: """Transform the query params.""" - transformed_params = params - now = datetime.now().date() - if params.get("start_date") is None: - transformed_params["start_date"] = now - timedelta(days=10 * 365) - - if params.get("end_date") is None: - transformed_params["end_date"] = now - - return FMPExecutiveCompensationQueryParams(**transformed_params) + return FMPExecutiveCompensationQueryParams(**params) @staticmethod async def aextract_data( @@ -66,27 +79,47 @@ async def aextract_data( **kwargs: Any, ) -> List[Dict]: """Return the raw data from the FMP endpoint.""" + api_key = credentials.get("fmp_api_key") if credentials else "" + base_url = "https://financialmodelingprep.com/api/v4/" - urls = [ - f"{base_url}/governance/executive_compensation?symbol={s.strip()}&apikey={api_key}" - for s in query.symbol.split(",") - ] - return await amake_requests(urls, response_callback, **kwargs) + + symbols = query.symbol.split(",") + + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + + url = f"{base_url}/governance/executive_compensation?symbol={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.extend(result) + + await asyncio.gather(*[get_one(symbol) for symbol in symbols]) + + if not results: + raise EmptyDataError("No data found for given symbols.") + + return sorted(results, key=lambda x: (x["year"]), reverse=True) @staticmethod def transform_data( - query: FMPExecutiveCompensationQueryParams, data: List[Dict], **kwargs: Any + query: FMPExecutiveCompensationQueryParams, + data: List[Dict], + **kwargs: Any, ) -> List[FMPExecutiveCompensationData]: """Return the transformed data.""" - result = [] + results: List[FMPExecutiveCompensationData] = [] for d in data: - if "year" in d: - if ( - d["year"] >= query.start_date.year - and d["year"] <= query.end_date.year - ): - result.append(FMPExecutiveCompensationData(**d)) + if "year" in d and query.year is not None: + if d["year"] >= query.year and d["year"] <= query.year: + results.append(FMPExecutiveCompensationData.model_validate(d)) else: - result.append(FMPExecutiveCompensationData(**d)) - return result + results.append(FMPExecutiveCompensationData.model_validate(d)) + return results diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/financial_ratios.py b/openbb_platform/providers/fmp/openbb_fmp/models/financial_ratios.py index 98ed8ba41b2b..2cc5b5f7d9b9 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/financial_ratios.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/financial_ratios.py @@ -9,10 +9,12 @@ FinancialRatiosQueryParams, ) 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_requests, + amake_request, to_snake_case, ) +from openbb_fmp.utils.helpers import response_callback from pydantic import Field, model_validator @@ -232,9 +234,14 @@ async def aextract_data( if query.period != "ttm" else ttm_url ) - results = await amake_requests(url, **kwargs) + results = await amake_request( + url, response_callback=response_callback, **kwargs + ) + + if not results: + raise EmptyDataError(f"No data found for the symbol {query.symbol}.") - return results + return results # type: ignore @staticmethod def transform_data( diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/key_metrics.py b/openbb_platform/providers/fmp/openbb_fmp/models/key_metrics.py index f55c51553dca..3f7f7b0ce3f9 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/key_metrics.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/key_metrics.py @@ -1,10 +1,12 @@ """FMP Key Metrics Model.""" +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.data import ForceInt from openbb_core.provider.abstract.fetcher import Fetcher @@ -13,11 +15,9 @@ KeyMetricsQueryParams, ) from openbb_core.provider.utils.descriptions import DATA_DESCRIPTIONS -from openbb_core.provider.utils.helpers import ( - ClientResponse, - ClientSession, - 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 @@ -227,35 +227,48 @@ async def aextract_data( api_key = credentials.get("fmp_api_key") if credentials else "" base_url = "https://financialmodelingprep.com/api/v3" - async def response_callback( - response: ClientResponse, session: ClientSession - ) -> List[Dict]: - results = await response.json() - symbol = response.url.parts[-1] + symbols = query.symbol.split(",") + + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + + url = f"{base_url}/key-metrics/{symbol}?period={query.period}&limit={query.limit}&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: - # TTM data - ttm_url = f"{base_url}/key-metrics-ttm/{symbol}?&apikey={api_key}" - if query.with_ttm and (metrics_ttm := await session.get_one(ttm_url)): - results.insert( - 0, - { - "symbol": symbol, - "period": "TTM", - "date": datetime.now().strftime("%Y-%m-%d"), - "calendar_year": datetime.now().year, - **{k.replace("TTM", ""): v for k, v in metrics_ttm.items()}, - }, - ) + ttm_url = f"{base_url}/key-metrics-ttm/{symbol}?&apikey={api_key}" + if query.with_ttm and ( + metrics_ttm := await amake_request( + ttm_url, response_callback=response_callback, **kwargs + ) + ): + result.insert( # type: ignore + 0, + { + "symbol": symbol, + "period": "TTM", + "date": datetime.now().strftime("%Y-%m-%d"), + "calendar_year": datetime.now().year, + **{k.replace("TTM", ""): v for k, v in metrics_ttm.items()}, # type: ignore + }, + ) + results.extend(result) - return results + await asyncio.gather(*[get_one(symbol) for symbol in symbols]) - urls = [ - f"{base_url}/key-metrics/{symbol}?" - f"period={query.period}&limit={query.limit}&apikey={api_key}" - for symbol in query.symbol.split(",") - ] + if not results: + raise EmptyDataError("No data found for given symbols.") - return await amake_requests(urls, response_callback=response_callback, **kwargs) + return results @staticmethod def transform_data( diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/price_performance.py b/openbb_platform/providers/fmp/openbb_fmp/models/price_performance.py index 59030913ae77..9a90bd7c7eab 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/price_performance.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/price_performance.py @@ -2,6 +2,7 @@ # pylint: disable=unused-argument 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.recent_performance import ( @@ -86,4 +87,13 @@ def transform_data( **kwargs: Any, ) -> List[FMPPricePerformanceData]: """Return the transformed data.""" + + symbols = query.symbol.split(",") + if len(data) != len(symbols): + data_symbols = [d["symbol"] for d in data] + missing_symbols = [ + symbol for symbol in symbols if symbol not in data_symbols + ] + warn(f"Missing data for symbols: {missing_symbols}") + return [FMPPricePerformanceData.model_validate(i) for i in data] diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/price_target.py b/openbb_platform/providers/fmp/openbb_fmp/models/price_target.py index ad53c335c0a4..92589fc6c002 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/price_target.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/price_target.py @@ -2,15 +2,19 @@ # pylint: disable=unused-argument +import asyncio from datetime import 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.price_target import ( PriceTargetData, PriceTargetQueryParams, ) -from openbb_fmp.utils.helpers import create_url, get_data_urls +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, field_validator @@ -20,6 +24,8 @@ class FMPPriceTargetQueryParams(PriceTargetQueryParams): Source: https://site.financialmodelingprep.com/developer/docs/#Price-Target """ + __json_schema_extra__ = {"symbol": ["multiple_items_allowed"]} + with_grade: bool = Field( False, description="Include upgrades and downgrades in the response.", @@ -81,12 +87,30 @@ async def aextract_data( api_key = credentials.get("fmp_api_key") if credentials else "" endpoint = "upgrades-downgrades" if query.with_grade else "price-target" - urls = [] - for symbol in query.symbol.split(","): - query.symbol = symbol - urls.append(create_url(4, endpoint, api_key, query, exclude=["limit"])) + symbols = query.symbol.split(",") # type: ignore + + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + url = create_url(4, endpoint, api_key, query, exclude=["limit", "symbol"]) + url += f"&symbol={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_urls(urls) + return sorted( + results, key=lambda x: (x["publishedDate"], x["symbol"]), reverse=True + ) @staticmethod def transform_data( diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/price_target_consensus.py b/openbb_platform/providers/fmp/openbb_fmp/models/price_target_consensus.py index 79095eb74aa0..a2b58c79fcc8 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/price_target_consensus.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/price_target_consensus.py @@ -1,13 +1,17 @@ """FMP Price Target Consensus Model.""" -from typing import Any, Dict, Optional +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.price_target_consensus import ( PriceTargetConsensusData, PriceTargetConsensusQueryParams, ) -from openbb_fmp.utils.helpers import create_url, get_data_one +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 FMPPriceTargetConsensusQueryParams(PriceTargetConsensusQueryParams): @@ -16,6 +20,8 @@ class FMPPriceTargetConsensusQueryParams(PriceTargetConsensusQueryParams): Source: https://site.financialmodelingprep.com/developer/docs/price-target-consensus-api/ """ + __json_schema_extra__ = {"symbol": ["multiple_items_allowed"]} + class FMPPriceTargetConsensusData(PriceTargetConsensusData): """FMP Price Target Consensus Data.""" @@ -24,7 +30,7 @@ class FMPPriceTargetConsensusData(PriceTargetConsensusData): class FMPPriceTargetConsensusFetcher( Fetcher[ FMPPriceTargetConsensusQueryParams, - FMPPriceTargetConsensusData, + List[FMPPriceTargetConsensusData], ] ): """Transform the query, extract and transform the data from the FMP endpoints.""" @@ -39,19 +45,42 @@ async def aextract_data( query: FMPPriceTargetConsensusQueryParams, credentials: Optional[Dict[str, str]], **kwargs: Any, - ) -> Dict: + ) -> List[Dict]: """Return the raw data from the FMP endpoint.""" api_key = credentials.get("fmp_api_key") if credentials else "" - url = create_url(4, "price-target-consensus", api_key, query) + symbols = query.symbol.split(",") + results = [] + + async def get_one(symbol): + """Get data for one symbol.""" + url = create_url( + 4, "price-target-consensus", api_key, query, exclude=["symbol"] + ) + url = f"{url}&symbol={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_one(url, **kwargs) + return sorted( + results, + key=(lambda item: (symbols.index(item.get("symbol", len(symbols))))), + ) @staticmethod def transform_data( query: FMPPriceTargetConsensusQueryParams, - data: Dict, + data: List[Dict], **kwargs: Any, - ) -> FMPPriceTargetConsensusData: + ) -> List[FMPPriceTargetConsensusData]: """Return the transformed data.""" - return FMPPriceTargetConsensusData.model_validate(data) + return [FMPPriceTargetConsensusData.model_validate(d) for d in data] diff --git a/openbb_platform/providers/fmp/openbb_fmp/utils/helpers.py b/openbb_platform/providers/fmp/openbb_fmp/utils/helpers.py index ac99bbcac9d5..26d59ac562c0 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/utils/helpers.py +++ b/openbb_platform/providers/fmp/openbb_fmp/utils/helpers.py @@ -1,9 +1,7 @@ """FMP Helpers Module.""" -import json from datetime import date as dateType -from io import StringIO -from typing import Any, Dict, List, Optional, TypeVar, Union +from typing import Any, Dict, List, Optional, Union from openbb_core.provider.utils.client import ClientSession from openbb_core.provider.utils.errors import EmptyDataError @@ -15,61 +13,20 @@ ) from pydantic import BaseModel -T = TypeVar("T", bound=BaseModel) - - -class BasicResponse: - """Basic Response class.""" - - def __init__(self, response: StringIO): - """Initialize the BasicResponse class.""" - # Find a way to get the status code - self.status_code = 200 - response.seek(0) - self.text = response.read() - - def json(self) -> dict: - """Return the response as a dictionary.""" - 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 # type: ignore - - response = open_url(url) - return BasicResponse(response) - async def response_callback( response: ClientResponse, _: ClientSession -) -> Union[dict, List[dict]]: +) -> Union[Dict, List[Dict]]: """Callback for make_request.""" data = await response.json() - if response.status != 200: - message = data.get("message", None) or data.get("error", "unknown error") - raise RuntimeError(f"Error in FMP request -> {message}") - - if "Error Message" in data: + if isinstance(data, dict) and "Error Message" in data: raise RuntimeError(f"FMP Error Message -> {data['Error Message']}") - if len(data) == 0: - raise EmptyDataError() + if isinstance(data, dict) and "error" in data: + raise RuntimeError( + f"FMP Error Message -> {data['error']}. Status code: {response.status}" + ) return data diff --git a/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_equity_valuation_multiples_fetcher.yaml b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_equity_valuation_multiples_fetcher.yaml index 39f7091fab96..3a8a03cb0cde 100644 --- a/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_equity_valuation_multiples_fetcher.yaml +++ b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_equity_valuation_multiples_fetcher.yaml @@ -3,9 +3,9 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET @@ -13,33 +13,33 @@ interactions: response: body: string: !!binary | - H4sIAAAAAAAAA5VWTW/bRhC951cYOTfEfs9sb/5IWh9SpY5QoCh6oKi1TVgi1SWl1Cj63/vW4lKk - 4gCpIJ30ZnbmzXuz+8ebi4t/8Lu4eBvDITT78CnEz49lDMvlx7c/XihTWBLGKDIspRX+hyO4Cf1t - U7XbM7grlCS2moV0kmkAt7sQy75uHq7L7vHDpv0yD6JCsNPGsRXE3rIbwu5jCK9HuEKzZiW1k6Q0 - OTtEVEDPkbrwxnoghDTWSplLWrXt02/l5rxdwJHYKeOlUVI6PcD7snmoV5tw9f/CugR5bDfrELv3 - f+3r/vn74uqmDzF0/U1Y9edcadJGsDUsFAvO89iW8Sn01+VuGJu3WjAmIbVXAySkpLtYd+Glg6EC - oXGymAF34Q7TajOgsJqEw5laCYzVZFSsq7BsP5eb0E3wVEAujpg9eUUyd7Rrq/t4QilXkDeGlXcs - nVN6PPu+up9kU75w1igjpEVLTnnOuNUEZahwTgqtLAsLTWQB7frvQYXD0EVuwGMQYE9ITIaNeZ2+ - xSHE91e3y5vL0SgkjffEUgmHxibZF+f6H0KoSBQYYSUOIuJJyIeJ9sdBwCJs2TtSSo+aD2VskLr7 - vQ6b9REqCnRJhoTHKBSdpjB11Blek5LeQw2C8M3VryHAZXuU7hErC2KyiUT4ib2RPINedl3ou5xW - Y2M4L8h6rdnrzDiWx80x8YRAgenA/8pj2OQhyEx8tY8R5E8mKWAbjEc6kkitPGUusm+uW0ynfMg7 - zBfCKaG9RMVOOEcjPG2wX/flZtIejOCItEgWIqBze/WhXodmPadNWAGqk2A8RqK1fw0NB1doYKwH - jppFjY4qn9v9vE9pDWbIHs4zZFTus0ty/Sk0aHJz2awv19u6qbs+iewAT94dN/mQZIgBL5BK9Qj8 - Df7fYClvUdU5usAM0omUFoIwp40Pbocl2C3bZdvj5Omsxw28C39/U/HvkN57qSl1ZJTA4pnHzWpJ - aMUYsBaCHGtLZOfwm7CLoaoTY80Y47HL2Dh4BR62p13ct9XTVdmF9XW73YWmO0Z91b5i5TTCHHSi - tPRZAA+xfCy3v+y3qxAHXenCCfgXdxFZiX2cmW7rapy0UygEqsbCsWK8EWPo97FZNMuB0rltFIF2 - 1gZVEDkzdj2UEHp8h3alTOvZ4MaFGVPteVxf2vj0wv+uxqgyGhoSL58B1U/Pn1wLTknjZkh49vpo - xHPsO0CZ5AxdNwfYEFRPj//m6iiPbr0LVagP5WpcxbAJWzvNOyA/lc9TmHED6gx2iyqavo2Dtx2b - eZXr8rl72fyLfd+BijUIG1IyfGCdYcgI7Eo/iciHfxUkBW61RBzD3dLQKL0Utbgfq1k0PyMsx+Ai - lMrjCZCCIJJRIScyIJW00IYuClxKXjipDATC0+3xCloXyWZ4k+EKx2NJnDZlpmYO1wUrqN/BaxIC - kKOkQ55hWtIGW93jRk6vgqkj528VeJGEsgpvFdRr8V7LDsnrcY5P1s2Al+vh4/xRk64pQhOW8AZy - GDproP998+d/uXYPVsUKAAA= + H4sIAAAAAAAAA5VWTW/bRhC951cYOTeL2d3Zr978kbQ+pEodoUAQ9EBRa5uwRKpLSqlR9L/3UeIy + pOIAqRzDDvxmdubNvJn5/Ori4h98X1y8TvEQ6338ENPHxyLF5fL9658vFAtnpVdSsWIrnfzpBK5j + d1uXzfYMbgU7z1459lZpJh7gzS6moqvqh+uifXy3ab7MzRzM2LNlR6yCtdnsPsX4soUV3pI3JK21 + ZJQOg0UJ9BzJwgYVFLP31iqlZHa+apqnP4rNecZI2DipNJImh1+1GfBdUT9Uq028+p92bY95bDbr + mNq3f+2r7vkHDau6iym23U1cded8oR5SBSKvSZrgB4ttkZ5id13shuI56Qwr56QhGiCxd7pLVRuP + OWRgX7Q5cBfvULEmA4S0bHRg6YPhkDmEozIum4/FJrYTuBPExmplJZEj73WGN+V9mnjVwrC2ymln + gw+ac+a7+/J++roRrLxTXlttA/pRZdxqgtJWhKBDsJ6dJgqjs+5HUPEwpJEzUIrIglrrvPNjR57R + tzjE9PbqdnlzOUQqBROycTpI6d3Ylr33xbkGRhKCdF5q1pphafXE5t1EAAPcCjJeeUZpSXqSI7xI + NZy3n6q4WZ+wJEhbLxXINdJZRcq9IKwzg6CVMQEfNtIGOxis0YPL5tS+JywyNZ6gVh+gxL4wM+hl + 28auzW41GQwPjR5CHW3gTCfGyM3J84REEohWEgTrg3OOdE6x3KeEAkyqKQU5ZZjZuiBhlfPL0rlu + UKDiISuNBPftQ0Gh0eVXcD/Ift8Xm0ly0mgXjGe0fD/Scsetq0O1jvV6ThoZNnCIyhNIxn9fQkPC + JaIfo0Gac6vM9a54bvbTLElISM4Yhj4RDfjO4bR9x/4SayS5uazXl+ttVVdt1/fZAbq8O430wctg + A17QK+Uj8Df4+wazeYu4ztGiH0bKoK5kNXttwlduh0nYLptl0+Hlaa3HQbyLf3+36d/APZYKY3yj + d6B8Ke3ccBZMD1fHxH2/ipQ1eo6+ibsUy6qnrB5NELOS5CFhKdmN47hryqeroo3r62a7i3V7Mvom + e0wbbDwPBkj1rZvtH1LxWGx/229XMY2S1Fr1z0BsXo/zOzVVOZYalXZBGw9KjR9bL8Vun+pFvRwY + natGeXSI9a7fchrbax5B7PBvSFaSwL7FhMT7zgRl8kb40qSnI/u7CoU6oYOT2Bz9ZwB109cna8Gx + JJohodfrkwjPsW+kNq6fmRN0VR+gQRA9ff27c6M4SfUulrE6FKtxFIM61mbqd0B+KJ4nMAsd+Zdg + t4ii7po0SBsjSM6iXBfP7XHyL/ZdCyrW4GuYF7hLsJgRADrBsdITi/z4N0ZwLihofHDOOHTQ1Gpx + P0azqH+F2WAjhaJ+UKPSQUMLuXxpQgYapZ9mQ2lw1WAH4PLpbxs/jshd5mSG1sIydpll2OABN95l + 1cjNHK+EsfjyUmL8qvHqS03MRTSWmCU2KXapsWqmx/mxAiVa2W9cTdrjDlOjePN4nONJnG2d9/Or + 5rikHKI7/sC1GAzQ/7768z++Y4gyzAoAAA== headers: Access-Control-Allow-Credentials: - 'true' Access-Control-Allow-Headers: - X-Requested-With, content-type, auth-token, Authorization, stripe-signature, - APPS + APPS, publicauthkey, privateauthkey Access-Control-Allow-Methods: - GET, POST, OPTIONS Access-Control-Allow-Origin: @@ -53,9 +53,9 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Mon, 27 Nov 2023 20:32:11 GMT - ETag: - - W/"ac5-TK5uSKDDH1MDw8JW4fhrs39OVhQ" + - Tue, 19 Mar 2024 17:49:49 GMT + Etag: + - W/"acc-gbEnl5NIKZ7JjzxEGOIeGQylbts" Server: - nginx/1.18.0 (Ubuntu) Transfer-Encoding: diff --git a/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_key_metrics_fetcher.yaml b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_key_metrics_fetcher.yaml index bcfe11e16ae5..86a96bf67ad3 100644 --- a/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_key_metrics_fetcher.yaml +++ b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_key_metrics_fetcher.yaml @@ -3,9 +3,9 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET @@ -13,422 +13,433 @@ interactions: response: body: string: !!binary | - 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 - nlCs/mTChQh3h9Msl4VQPvyf/y8mGDilGnMBAA== + H4sIAAAAAAAAA+29Wa8lyXmud9+/guC1eyHmwXcUdWQLMExZhzAgGL4odpfEhppd7aoijwXj/He/ + T+ydETlEZq7NYhltQNXdm2DtyDVkxvB80/v9H9/86lf/j/771a9+/ek//vSHDz/++n/81a9/85t/ + +l9+/T+8/O337z6/5++ccf5bU7/1ZvnNd+9+fP/T9+8+/sv7dx+XEcvvfn7/8YcP3/O3//Avy999 + fP+X9z/9+f0/vf/4X//47iMv6sLD+epqjMGmWpIrr0N/ev/5H3/67sOf1oPTw/pgoqvWF+Ntza9j + P+i93n3+4ad/++27T3/8hx8//LfNNbWaEkwppuZSin+95l8/vn8/He5qzsWn6ILP0fnYv+qnP67G + +UepLteQow/e2boM+8OHD//+v7/7cfMd/aN6Y7OxPgVrXQ2vYz+/++nffvjDj+//7g3XfOL3f/zw + 4/fvP376L//Xn3/4/B9PXPTDT5/ff3z/6fPfv//D59Xw/HA5GO+zjdZF3aTX4X969/Hf33/+7buf + eT7ZZJeSzbZk8/r797zczx9/+PS+feo2Sje21M2on9//s57Jh/bbR7XW16oXSsm75RHoJb57//sP + /1WT6NMyNj9M8t7peYWiz5XtMvbDd//6cXm98AjVJJtMSlnPICw3/+d//e5fV29qS8xRv80uOOvS + MugPy5DgHzG5WmvMNfoSTR/y+X7M+7+8fvLlRtYcq+aXblfpH2h3p373l/cf/8vf/ePv//43fED3 + sLqv+q7W+FCsjatX/t1+RnNBfDgXNONcKbW4mMrqgn9YTWfGlocxxuvVdRONpmkf++7jT3rZT//y + w/sfWZzmYXwsLqcYo5ZVzf1V1wtkPTppddRsSipZM3/ZIjSzfv/hZUJqnH3kopXhom5FLDXYshn3 + m0+f3n/+1F7P6+OlanTvvCaQX+6uVv/fv7zkcrvMI/Hdgya2ZkjQprEszD9//Kj7vDww89BTMNam + bPWiWszLbV0WwW8/6Cm8+7c2batmmzO+Wn3KNpv6WHae/+3P735cvo9ujeaaN9qpfE59Fnz/w19+ + +F5b4OoGGW1lteRqnbGpxP6aP7/7jw9/Xn1Mq2EmaBcxJuTglo/5iTn1P73/SZ/xx9/89P1vvv/T + Dz/98Okzs+EvWiz//LKD8gp9T/2kh/rdHzX477/Xb3/Ubvgn3ZDN2IfJhTfL+h7OBE2JcVded6FP + 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 + LBxQOH0BAA== headers: Access-Control-Allow-Credentials: - 'true' Access-Control-Allow-Headers: - X-Requested-With, content-type, auth-token, Authorization, stripe-signature, - APPS + APPS, publicauthkey, privateauthkey Access-Control-Allow-Methods: - GET, POST, OPTIONS Access-Control-Allow-Origin: @@ -442,9 +453,9 @@ interactions: Content-Type: - application/json; charset=utf-8 Date: - - Mon, 16 Oct 2023 12:22:27 GMT - ETag: - - W/"1731a-I+hE3E7KdXImrdUd7/lxEVWlPTY" + - Tue, 19 Mar 2024 17:45:50 GMT + Etag: + - W/"17d38-DmViIZi9XAA+LF93Gan6DIxOhKU" Server: - nginx/1.18.0 (Ubuntu) Transfer-Encoding: diff --git a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py index 733fff7a423f..e1b25d3bebb3 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -343,7 +343,7 @@ def test_fmp_price_target_fetcher(credentials=test_credentials): @pytest.mark.record_http def test_fmp_analyst_estimates_fetcher(credentials=test_credentials): - params = {"symbol": "AAPL"} + params = {"symbol": "AAPL", "limit": 30} fetcher = FMPAnalystEstimatesFetcher() result = fetcher.test(params, credentials)