Seprate Intrinio financials data tags into a different command (#5723)

* add `ebit` field in income statement standard model

* only add required data tags

* remove calculations data

* use `name` key instead of `tag` key

* set `period` as required in data

* remove `period` and `cik` from provider models

* add `equity/fundamental/search_financial_attributes` with tests

* clean descriptions file

* add `equity/fundamental/financial_attributes` with tests

* set `value` as `Optional`
This commit is contained in:
Pratyush Shukla
2023-11-15 03:29:49 +05:30
committed by GitHub
parent 139efd31ab
commit 68965c4cec
18 changed files with 505 additions and 43 deletions

View File

@@ -964,7 +964,7 @@ def test_equity_news(params, headers):
@pytest.mark.parametrize(
"params",
[({"symbol": "AAPL", "limit": 100})],
[({"symbol": "AAPL", "limit": 100, "provider": "fmp"})],
)
@pytest.mark.integration
def test_equity_fundamental_multiples(params, headers):
@@ -977,6 +977,52 @@ def test_equity_fundamental_multiples(params, headers):
assert result.status_code == 200
@pytest.mark.parametrize(
"params",
[
({"query": "ebit", "limit": 100, "provider": "intrinio"}),
],
)
@pytest.mark.integration
def test_equity_fundamental_search_financial_attributes(params, obb):
params = {p: v for p, v in params.items() if v}
query_str = get_querystring(params, [])
url = f"http://0.0.0.0:8000/api/v1/equity/fundamental/search_financial_attributes?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200
@pytest.mark.parametrize(
"params",
[
(
{
"provider": "intrinio",
"symbol": "AAPL",
"tag": "ebit",
"period": "annual",
"limit": 1000,
"type": None,
"start_date": "2013-01-01",
"end_date": "2023-01-01",
"sort": "desc",
}
),
],
)
@pytest.mark.integration
def test_equity_fundamental_financial_attributes(params, obb):
params = {p: v for p, v in params.items() if v}
query_str = get_querystring(params, [])
url = f"http://0.0.0.0:8000/api/v1/equity/fundamental/financial_attributes?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200
@pytest.mark.parametrize(
"params",
[

View File

@@ -894,7 +894,7 @@ def test_equity_news(params, obb):
@pytest.mark.parametrize(
"params",
[
({"symbol": "AAPL", "limit": 100}),
({"symbol": "AAPL", "limit": 100, "provider": "fmp"}),
],
)
@pytest.mark.integration
@@ -905,6 +905,46 @@ def test_equity_fundamental_multiples(params, obb):
assert len(result.results) > 0
@pytest.mark.parametrize(
"params",
[
({"query": "ebit", "limit": 100, "provider": "intrinio"}),
],
)
@pytest.mark.integration
def test_equity_fundamental_search_financial_attributes(params, obb):
result = obb.equity.fundamental.search_financial_attributes(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
@pytest.mark.parametrize(
"params",
[
(
{
"provider": "intrinio",
"symbol": "AAPL",
"tag": "ebit",
"period": "annual",
"limit": 1000,
"type": None,
"start_date": "2013-01-01",
"end_date": "2023-01-01",
"sort": "desc",
}
),
],
)
@pytest.mark.integration
def test_equity_fundamental_financial_attributes(params, obb):
result = obb.equity.fundamental.financial_attributes(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
@pytest.mark.parametrize(
"params",
[

View File

@@ -103,6 +103,28 @@ def employee_count(
return OBBject(results=Query(**locals()).execute())
@router.command(model="SearchFinancialAttributes")
def search_financial_attributes(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject[BaseModel]:
"""Search financial attributes for financial statements."""
return OBBject(results=Query(**locals()).execute())
@router.command(model="FinancialAttributes")
def financial_attributes(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject[BaseModel]:
"""Fetch the value of financial attributes for a selected company and fiscal period."""
return OBBject(results=Query(**locals()).execute())
@router.command(model="IncomeStatement")
def income(
cc: CommandContext,

View File

@@ -62,9 +62,7 @@ class BalanceSheetData(Data):
accepted_date: Optional[datetime] = Field(
default=None, description="Accepted date."
)
period: Optional[str] = Field(
default=None, description="Reporting period of the statement."
)
period: str = Field(default=None, description="Reporting period of the statement.")
cash_and_cash_equivalents: Optional[StrictFloat] = Field(
default=None, description="Cash and cash equivalents"

View File

@@ -51,9 +51,7 @@ class CashFlowStatementData(Data):
default=None, description=DATA_DESCRIPTIONS.get("symbol", "")
)
date: dateType = Field(description=DATA_DESCRIPTIONS.get("date" ""))
period: Optional[str] = Field(
default=None, description="Reporting period of the statement."
)
period: str = Field(default=None, description="Reporting period of the statement.")
cik: Optional[str] = Field(
default=None, description="Central Index Key (CIK) of the company."
)

View File

@@ -0,0 +1,42 @@
"""Financial Attributes standard model."""
from datetime import date as dateType
from typing import Literal, Optional
from pydantic import Field
from openbb_provider.abstract.data import Data
from openbb_provider.abstract.query_params import QueryParams
from openbb_provider.utils.descriptions import DATA_DESCRIPTIONS, QUERY_DESCRIPTIONS
class FinancialAttributesQueryParams(QueryParams):
"""Financial Attributes Query."""
symbol: str = Field(description=QUERY_DESCRIPTIONS.get("symbol"))
tag: str = Field(description=QUERY_DESCRIPTIONS.get("tag"))
period: Optional[Literal["annual", "quarter"]] = Field(
default="annual", description=QUERY_DESCRIPTIONS.get("period")
)
limit: Optional[int] = Field(
default=1000, description=QUERY_DESCRIPTIONS.get("limit")
)
type: Optional[str] = Field(
default=None, description="Filter by type, when applicable."
)
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")
)
sort: Optional[Literal["asc", "desc"]] = Field(
default="desc", description="Sort order."
)
class FinancialAttributesData(Data):
"""Financial Attributes Data."""
date: dateType = Field(description=DATA_DESCRIPTIONS.get("date"))
value: Optional[float] = Field(default=None, description="The value of the data.")

View File

@@ -54,9 +54,7 @@ class IncomeStatementData(Data):
description=DATA_DESCRIPTIONS.get("date", "")
+ " In this case, the date of the income statement."
)
period: Optional[str] = Field(
default=None, description="Period of the income statement."
)
period: str = Field(default=None, description="Period of the income statement.")
cik: Optional[str] = Field(default=None, description="Central Index Key.")
revenue: Optional[StrictFloat] = Field(default=None, description="Revenue.")
@@ -95,6 +93,10 @@ class IncomeStatementData(Data):
depreciation_and_amortization: Optional[StrictFloat] = Field(
default=None, description="Depreciation and amortization."
)
ebit: Optional[StrictFloat] = Field(
default=None,
description="Earnings before interest, and taxes.",
)
ebitda: Optional[StrictFloat] = Field(
default=None,
description="Earnings before interest, taxes, depreciation and amortization.",

View File

@@ -0,0 +1,49 @@
"""Search Financial Attributes standard model."""
from typing import Optional
from pydantic import Field
from openbb_provider.abstract.data import Data
from openbb_provider.abstract.query_params import QueryParams
from openbb_provider.utils.descriptions import QUERY_DESCRIPTIONS
class SearchFinancialAttributesQueryParams(QueryParams):
"""Search Financial Attributes Query."""
query: str = Field(description="Query to search for.")
limit: Optional[int] = Field(
default=1000, description=QUERY_DESCRIPTIONS.get("limit")
)
class SearchFinancialAttributesData(Data):
"""Search Financial Attributes Data."""
id: str = Field(description="ID of the financial attribute.")
name: str = Field(description="Name of the financial attribute.")
tag: str = Field(description="Tag of the financial attribute.")
statement_code: str = Field(description="Code of the financial statement.")
statement_type: Optional[str] = Field(
default=None, description="Type of the financial statement."
)
parent_name: Optional[str] = Field(
default=None, description="Parent's name of the financial attribute."
)
sequence: Optional[int] = Field(
default=None, description="Sequence of the financial statement."
)
factor: Optional[str] = Field(
default=None, description="Unit of the financial attribute."
)
transaction: Optional[str] = Field(
default=None,
description="Transaction type (credit/debit) of the financial attribute.",
)
type: Optional[str] = Field(
default=None, description="Type of the financial attribute."
)
unit: Optional[str] = Field(
default=None, description="Unit of the financial attribute."
)

View File

@@ -5,8 +5,6 @@ QUERY_DESCRIPTIONS = {
"start_date": "Start date of the data, in YYYY-MM-DD format.",
"end_date": "End date of the data, in YYYY-MM-DD format.",
"interval": "Time interval of the data to return.",
# "weekly": "Whether to return weekly data.",
# "monthly": "Whether to return monthly data.",
"period": "Time period of the data to return.",
"date": "A specific date to get data for.",
"limit": "The number of data entries to return.",

View File

@@ -7,11 +7,17 @@ from openbb_intrinio.models.company_news import IntrinioCompanyNewsFetcher
from openbb_intrinio.models.currency_pairs import IntrinioCurrencyPairsFetcher
from openbb_intrinio.models.equity_historical import IntrinioEquityHistoricalFetcher
from openbb_intrinio.models.equity_quote import IntrinioEquityQuoteFetcher
from openbb_intrinio.models.financial_attributes import (
IntrinioFinancialAttributesFetcher,
)
from openbb_intrinio.models.fred_indices import IntrinioFredIndicesFetcher
from openbb_intrinio.models.global_news import IntrinioGlobalNewsFetcher
from openbb_intrinio.models.income_statement import IntrinioIncomeStatementFetcher
from openbb_intrinio.models.options_chains import IntrinioOptionsChainsFetcher
from openbb_intrinio.models.options_unusual import IntrinioOptionsUnusualFetcher
from openbb_intrinio.models.search_financial_attributes import (
IntrinioSearchFinancialAttributesFetcher,
)
from openbb_provider.abstract.provider import Provider
intrinio_provider = Provider(
@@ -28,10 +34,12 @@ intrinio_provider = Provider(
"CurrencyPairs": IntrinioCurrencyPairsFetcher,
"EquityHistorical": IntrinioEquityHistoricalFetcher,
"EquityQuote": IntrinioEquityQuoteFetcher,
"FinancialAttributes": IntrinioFinancialAttributesFetcher,
"FredIndices": IntrinioFredIndicesFetcher,
"GlobalNews": IntrinioGlobalNewsFetcher,
"IncomeStatement": IntrinioIncomeStatementFetcher,
"OptionsChains": IntrinioOptionsChainsFetcher,
"OptionsUnusual": IntrinioOptionsUnusualFetcher,
"SearchFinancialAttributes": IntrinioSearchFinancialAttributesFetcher,
},
)

View File

@@ -85,24 +85,16 @@ class IntrinioBalanceSheetFetcher(
def get_financial_statement_data(period: str, data: List[Dict]) -> None:
statement_data: Dict = {}
calculations_data: Dict = {}
intrinio_id = f"{query.symbol}-{statement_code}-{period}"
statement_url = f"{base_url}/fundamentals/{intrinio_id}/standardized_financials?api_key={api_key}"
statement_data = get_data_one(statement_url, **kwargs)
intrinio_id = f"{query.symbol}-calculations-{period}"
calculations_url = f"{base_url}/fundamentals/{intrinio_id}/standardized_financials?api_key={api_key}"
calculations_data = get_data_one(calculations_url, **kwargs)
data.append(
{
"date": statement_data["fundamental"]["end_date"],
"period": statement_data["fundamental"]["fiscal_period"],
"cik": statement_data["fundamental"]["company"]["cik"],
"symbol": statement_data["fundamental"]["company"]["ticker"],
"financials": statement_data["standardized_financials"]
+ calculations_data["standardized_financials"],
"financials": statement_data["standardized_financials"],
}
)
@@ -122,13 +114,11 @@ class IntrinioBalanceSheetFetcher(
sub_dict: Dict[str, Any] = {}
for sub_item in item["financials"]:
field_name = alias_generators.to_snake(sub_item["data_tag"]["tag"])
field_name = alias_generators.to_snake(sub_item["data_tag"]["name"])
sub_dict[field_name] = float(sub_item["value"])
sub_dict["date"] = item["date"]
sub_dict["period"] = item["period"]
sub_dict["cik"] = item["cik"]
sub_dict["symbol"] = item["symbol"]
# Intrinio does not return Q4 data but FY data instead
if query.period == "quarter" and item["period"] == "FY":

View File

@@ -101,24 +101,16 @@ class IntrinioCashFlowStatementFetcher(
def get_financial_statement_data(period: str, data: List[Dict]) -> None:
statement_data: Dict = {}
calculations_data: Dict = {}
intrinio_id = f"{query.symbol}-{statement_code}-{period}"
statement_url = f"{base_url}/fundamentals/{intrinio_id}/standardized_financials?api_key={api_key}"
statement_data = get_data_one(statement_url, **kwargs)
intrinio_id = f"{query.symbol}-calculations-{period}"
calculations_url = f"{base_url}/fundamentals/{intrinio_id}/standardized_financials?api_key={api_key}"
calculations_data = get_data_one(calculations_url, **kwargs)
data.append(
{
"date": statement_data["fundamental"]["end_date"],
"period": statement_data["fundamental"]["fiscal_period"],
"cik": statement_data["fundamental"]["company"]["cik"],
"symbol": statement_data["fundamental"]["company"]["ticker"],
"financials": statement_data["standardized_financials"]
+ calculations_data["standardized_financials"],
"financials": statement_data["standardized_financials"],
}
)
@@ -143,8 +135,6 @@ class IntrinioCashFlowStatementFetcher(
sub_dict["date"] = item["date"]
sub_dict["period"] = item["period"]
sub_dict["cik"] = item["cik"]
sub_dict["symbol"] = item["symbol"]
# Intrinio does not return Q4 data but FY data instead
if query.period == "quarter" and item["period"] == "FY":

View File

@@ -0,0 +1,78 @@
"""Intrinio Financial Attributes model."""
from datetime import datetime
from typing import Any, Dict, List, Optional
from dateutil.relativedelta import relativedelta
from openbb_intrinio.utils.helpers import get_data_many
from openbb_provider.abstract.fetcher import Fetcher
from openbb_provider.standard_models.financial_attributes import (
FinancialAttributesData,
FinancialAttributesQueryParams,
)
from openbb_provider.utils.helpers import get_querystring
class IntrinioFinancialAttributesQueryParams(FinancialAttributesQueryParams):
"""Intrinio Financial Attributes Query."""
__alias_dict__ = {"sort": "sort_order", "limit": "page_size"}
class IntrinioFinancialAttributesData(FinancialAttributesData):
"""Intrinio Financial Attributes Data."""
class IntrinioFinancialAttributesFetcher(
Fetcher[
IntrinioFinancialAttributesQueryParams,
List[IntrinioFinancialAttributesData],
]
):
"""Transform the query, extract and transform the data from the Intrinio endpoints."""
@staticmethod
def transform_query(
params: Dict[str, Any]
) -> IntrinioFinancialAttributesQueryParams:
"""Transform the query params."""
transformed_params = params
now = datetime.now().date()
if params.get("start_date") is None:
transformed_params["start_date"] = now - relativedelta(years=5)
if params.get("end_date") is None:
transformed_params["end_date"] = now
return IntrinioFinancialAttributesQueryParams(**transformed_params)
@staticmethod
def extract_data(
query: IntrinioFinancialAttributesQueryParams,
credentials: Optional[Dict[str, str]],
**kwargs: Any,
) -> List[Dict]:
"""Return the raw data from the Intrinio endpoint."""
api_key = credentials.get("intrinio_api_key") if credentials else ""
frequency = "yearly" if query.period == "annual" else "quarterly"
data: List[Dict] = []
base_url = "https://api-v2.intrinio.com"
query_str = get_querystring(query.model_dump(by_alias=True), ["frequency"])
query_str = f"{query_str}&frequency={frequency}"
url = f"{base_url}/historical_data/{query.symbol}/{query.tag}?{query_str}&api_key={api_key}"
# data = get_data_one(url).get("historical_data", [])
data = get_data_many(url, "historical_data")
return data
@staticmethod
def transform_data(
query: IntrinioFinancialAttributesQueryParams,
data: List[Dict],
**kwargs: Any,
) -> List[IntrinioFinancialAttributesData]:
"""Return the transformed data."""
return [IntrinioFinancialAttributesData.model_validate(item) for item in data]

View File

@@ -28,6 +28,9 @@ class IntrinioIncomeStatementData(IncomeStatementData):
__alias_dict__ = {
"research_and_development_expenses": "ResearchAndDevelopmentExpense",
"selling_general_and_administrative_expenses": "SellingGeneralAndAdministrativeExpense",
"ebit": "earnings before interest and taxes (ebit)",
"ebitda": "earnings before interest, taxes, depreciation and amortization (ebitda)",
"ebitda_margin": "ebitda margin",
"operating_income": "OperatingIncomeLoss",
"income_before_tax": "IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest", # noqa: E501
"eps_diluted": "EarningsPerShareDiluted",
@@ -59,6 +62,7 @@ class IntrinioIncomeStatementFetcher(
api_key = credentials.get("intrinio_api_key") if credentials else ""
statement_code = "income_statement"
period_type = "FY" if query.period == "annual" else "QTR"
data_tags = ["ebit", "ebitda", "ebitdamargin"]
fundamentals_data: Dict = {}
data: List[Dict] = []
@@ -81,7 +85,7 @@ class IntrinioIncomeStatementFetcher(
def get_financial_statement_data(period: str, data: List[Dict]) -> None:
statement_data: Dict = {}
calculations_data: Dict = {}
calculations_data: List = []
intrinio_id = f"{query.symbol}-{statement_code}-{period}"
statement_url = f"{base_url}/fundamentals/{intrinio_id}/standardized_financials?api_key={api_key}"
@@ -89,16 +93,21 @@ class IntrinioIncomeStatementFetcher(
intrinio_id = f"{query.symbol}-calculations-{period}"
calculations_url = f"{base_url}/fundamentals/{intrinio_id}/standardized_financials?api_key={api_key}"
calculations_data = get_data_one(calculations_url, **kwargs)
calculations_data = get_data_one(calculations_url, **kwargs).get(
"standardized_financials", []
)
calculations_data = [
item
for item in calculations_data
if item["data_tag"]["tag"] in data_tags
]
data.append(
{
"date": statement_data["fundamental"]["end_date"],
"period": statement_data["fundamental"]["fiscal_period"],
"cik": statement_data["fundamental"]["company"]["cik"],
"symbol": statement_data["fundamental"]["company"]["ticker"],
"financials": statement_data["standardized_financials"]
+ calculations_data["standardized_financials"],
+ calculations_data,
}
)
@@ -123,8 +132,6 @@ class IntrinioIncomeStatementFetcher(
sub_dict["date"] = item["date"]
sub_dict["period"] = item["period"]
sub_dict["cik"] = item["cik"]
sub_dict["symbol"] = item["symbol"]
# Intrinio does not return Q4 data but FY data instead
if query.period == "quarter" and item["period"] == "FY":

View File

@@ -0,0 +1,76 @@
"""Intrinio Search Financial Attributes model."""
from typing import Any, Dict, List, Optional
from openbb_intrinio.utils.helpers import get_data_one
from openbb_provider.abstract.fetcher import Fetcher
from openbb_provider.standard_models.search_financial_attributes import (
SearchFinancialAttributesData,
SearchFinancialAttributesQueryParams,
)
from openbb_provider.utils.helpers import get_querystring
class IntrinioSearchFinancialAttributesQueryParams(
SearchFinancialAttributesQueryParams
):
"""Intrinio Search Financial Attributes Query."""
__alias_dict__ = {"limit": "page_size"}
class IntrinioSearchFinancialAttributesData(SearchFinancialAttributesData):
"""Intrinio Search Financial Attributes Data."""
__alias_dict__ = {
"parent_name": "parent",
"transaction": "balance",
}
class IntrinioSearchFinancialAttributesFetcher(
Fetcher[
IntrinioSearchFinancialAttributesQueryParams,
List[IntrinioSearchFinancialAttributesData],
]
):
"""Transform the query, extract and transform the data from the Intrinio endpoints."""
@staticmethod
def transform_query(
params: Dict[str, Any]
) -> IntrinioSearchFinancialAttributesQueryParams:
"""Transform the query params."""
return IntrinioSearchFinancialAttributesQueryParams(**params)
@staticmethod
def extract_data(
query: IntrinioSearchFinancialAttributesQueryParams,
credentials: Optional[Dict[str, str]],
**kwargs: Any,
) -> List[Dict]:
"""Return the raw data from the Intrinio endpoint."""
api_key = credentials.get("intrinio_api_key") if credentials else ""
data: List[Dict] = []
base_url = "https://api-v2.intrinio.com"
query_str = get_querystring(query.model_dump(by_alias=True), [])
url = f"{base_url}/data_tags/search?{query_str}&api_key={api_key}"
data = get_data_one(url).get("tags", [])
# Intrinio doesn't return the correct number of results when using the limit parameter
# Temporary fix until they fix it
data = data[: query.limit]
return data
@staticmethod
def transform_data(
query: IntrinioSearchFinancialAttributesQueryParams,
data: List[Dict],
**kwargs: Any,
) -> List[IntrinioSearchFinancialAttributesData]:
"""Return the transformed data."""
return [
IntrinioSearchFinancialAttributesData.model_validate(item) for item in data
]

View File

@@ -0,0 +1,36 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate, br
Connection:
- keep-alive
method: GET
uri: https://api-v2.intrinio.com/historical_data/AAPL/ebit?api_key=MOCK_API_KEY&end_date=2023-01-01&frequency=yearly&page_size=1000&period=annual&provider=intrinio&sort_order=desc&start_date=2013-01-01&symbol=AAPL&tag=ebit
response:
body:
string: !!binary |
H4sIAOjTU2UAA3TQ2wrCMAwG4Hfp9ZQkPaTdq4iMokMHZYpuIoy9u7U3LaPrVWg+/qZZxH14T4/X
cPGhu/rJi/a0iFj0ohUERAdwB1KiER8f5niJ6BAkpHOEtSkxJqwLDI6A6xgSNhkbhhhds+iStYXV
LOu5aJN12TK5nYGR/1ZCkavAuro1200YlEx1q7d/Y9Ko61Yly9lqqezOvHK7Bx3fyrnnRoz9d+qe
/hZ74xzC+gMAAP//AwAceBCU4AEAAA==
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Tue, 14 Nov 2023 20:09:12 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,48 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate, br
Connection:
- keep-alive
method: GET
uri: https://api-v2.intrinio.com/data_tags/search?api_key=MOCK_API_KEY&page_size=1000&query=ebit
response:
body:
string: !!binary |
H4sIALG6U2UAA9SYa0/bMBSG/0qUT6AxAVVB0G9liSagKxcxSDtNlZOcGrPETm2nlyD++5xek7Qd
mdQm7Uf7xI4f+/Vr+7zrEmGh136968TVa3Gp08Qt3rT0I50iH1SdiTglFAvNhi7joF1TCRyE1BB1
tSc0BKEdmFfXT4eqiWqvWoBNpCoIiST4QGXHYW7ck4M8J/SQJIyKVFyOgjjeJRRRhyBPBQPEVUSv
0dDz1KfQC4E6MCt3kSMZn5Vs5KFEcNqbD5ITR3UVUjWcmh4KV/84SoBWoj59jMoAJdQNhRpdUaQv
o1NjkCRVFNrD8YP2nbOBfE3x9FgPz2rLBpsPZAoWAHdUlwhDmu82OjOGVgF8m1VoXrxn66VJ8QLP
AFtqkmkxplGf07mqWrKY0UU7sHiCeX3VZrTg63oMyTSagSt1b7R1tM2uWy4yho1eP6vJFXrcNzFW
ossf51kv2ShXSSbSxPeDRkKKDUbx1yfgvrZGlJ7cxx2ndHlHi8UsYfepxWw0cEalPxDHhKZU6s+q
yl67gLMukcgmHpGjz8VqRKy95C4b5dvsov0nnonrdxcZkzHqq2zGRftmoCau3rS3zlaaibYGlQRc
E+Q6X6Gwl/6ppNm6wUURlmCdJyP7/sJa0uea67SL9vHBwPEJui2KsRybca27qrtsMyvOCBft6Smh
3kWc4m0jlnvQX1qoBUmlxkmJgBMB2jPyQpjZjnZgPh9nshP9ifPsAHRfDXX8swWwH3qSBF72dYGv
2EXxuJuVcW5aO+oFS3kLRTjPPJnDAKiAlJYlI9MwDHdgaR3WBx7L9l9nSjXib0b20bht0M0uai5O
5Ui3NEfu9GiSTzxSN4eAgxpjDDHOM9Z9xiWJJhUHE0c7zHjZDqz6pynHXmTWz3MkV4ufiYKzzE3r
/M9bVvoNEEL7hgJz+Oku8NSnDgpguI/7/mV0+tjOPsPLgC/BC2yrHVQTiZZ1R5m6scwOs5TA+zv0
Msp9oj1GPkvlXYqELukUV6Z/c5Jg/klBmR242j0Hn4S+0OpCgJxDhtN4MA27624t03F1xCuA7MzD
edF1yaTqIf73eLrmc3B6tpgB/YuemAB9NpZpt+kRrPS634pb7c9OEO+H8Qx+/AUAAP//AwBIw/g6
VhwAAA==
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Tue, 14 Nov 2023 18:21:37 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
version: 1

View File

@@ -9,11 +9,17 @@ from openbb_intrinio.models.company_news import IntrinioCompanyNewsFetcher
from openbb_intrinio.models.currency_pairs import IntrinioCurrencyPairsFetcher
from openbb_intrinio.models.equity_historical import IntrinioEquityHistoricalFetcher
from openbb_intrinio.models.equity_quote import IntrinioEquityQuoteFetcher
from openbb_intrinio.models.financial_attributes import (
IntrinioFinancialAttributesFetcher,
)
from openbb_intrinio.models.fred_indices import IntrinioFredIndicesFetcher
from openbb_intrinio.models.global_news import IntrinioGlobalNewsFetcher
from openbb_intrinio.models.income_statement import IntrinioIncomeStatementFetcher
from openbb_intrinio.models.options_chains import IntrinioOptionsChainsFetcher
from openbb_intrinio.models.options_unusual import IntrinioOptionsUnusualFetcher
from openbb_intrinio.models.search_financial_attributes import (
IntrinioSearchFinancialAttributesFetcher,
)
test_credentials = UserService().default_user_settings.credentials.model_dump(
mode="json"
@@ -148,3 +154,31 @@ def test_intrinio_calendar_ipo_fetcher(credentials=test_credentials):
fetcher = IntrinioCalendarIpoFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_intrinio_search_financial_attributes(credentials=test_credentials):
params = {"query": "ebit"}
fetcher = IntrinioSearchFinancialAttributesFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_intrinio_financial_attributes(credentials=test_credentials):
params = {
"provider": "intrinio",
"symbol": "AAPL",
"tag": "ebit",
"period": "annual",
"limit": 1000,
"type": None,
"start_date": date(2013, 1, 1),
"end_date": date(2023, 1, 1),
"sort": "desc",
}
fetcher = IntrinioFinancialAttributesFetcher()
result = fetcher.test(params, credentials)
assert result is None