[Feature] Add Endpoint For The Latest Financial Reports Filed With The SEC (#6936)

* add endpoint for the latest financial reports filed with the sec

* lint

* more lint
This commit is contained in:
Danglewood
2024-11-09 02:27:44 -08:00
committed by GitHub
parent 85ca5501a5
commit baff57dfc8
11 changed files with 796 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
"""Latest Financial Reports Standard Model."""
from datetime import date as dateType
from typing import Optional
from openbb_core.provider.abstract.data import Data
from openbb_core.provider.abstract.query_params import QueryParams
from openbb_core.provider.utils.descriptions import DATA_DESCRIPTIONS
from pydantic import Field
class LatestFinancialReportsQueryParams(QueryParams):
"""Latest Financial Reports Query."""
class LatestFinancialReportsData(Data):
"""Latest Financial Reports Data."""
filing_date: dateType = Field(description="The date of the filing.")
period_ending: Optional[dateType] = Field(
default=None, description="Report for the period ending."
)
symbol: Optional[str] = Field(
default=None, description=DATA_DESCRIPTIONS.get("symbol")
)
name: Optional[str] = Field(default=None, description="Name of the company.")
cik: Optional[str] = Field(default=None, description=DATA_DESCRIPTIONS.get("cik"))
sic: Optional[str] = Field(
default=None, description="Standard Industrial Classification code."
)
report_type: Optional[str] = Field(default=None, description="Type of filing.")
description: Optional[str] = Field(
default=None, description="Description of the report."
)
url: str = Field(description="URL to the filing page.")

View File

@@ -2104,3 +2104,27 @@ def test_equity_historical_market_cap(params, headers):
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200
@parametrize(
"params",
[
(
{
"date": None,
"report_type": None,
"provider": "sec",
}
),
],
)
@pytest.mark.integration
def test_equity_discovery_latest_financial_reports(params, headers):
"""Test the equity discovery latest financial reports endpoint."""
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/discovery/latest_financial_reports?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200

View File

@@ -1966,3 +1966,26 @@ def test_equity_historical_market_cap(params, obb):
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
@parametrize(
"params",
[
(
{
"date": None,
"report_type": None,
"provider": "sec",
}
),
],
)
@pytest.mark.integration
def test_equity_discovery_latest_financial_reports(params, obb):
"""Test the equity discovery latest financial reports endpoint."""
params = {p: v for p, v in params.items() if v}
result = obb.equity.discovery.latest_financial_reports(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0

View File

@@ -181,3 +181,20 @@ async def filings(
and audited financial statements.
"""
return await OBBject.from_query(Query(**locals()))
@router.command(
model="LatestFinancialReports",
examples=[
APIEx(parameters={"provider": "sec"}),
APIEx(parameters={"provider": "sec", "date": "2024-09-30"}),
],
)
async def latest_financial_reports(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject:
"""Get the newest quarterly, annual, and current reports for all companies."""
return await OBBject.from_query(Query(**locals()))

View File

@@ -15387,6 +15387,196 @@
},
"model": "DiscoveryFilings"
},
"/equity/discovery/latest_financial_reports": {
"deprecated": {
"flag": null,
"message": null
},
"description": "Get the newest quarterly, annual, and current reports for all companies.",
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.equity.discovery.latest_financial_reports(provider='sec')\nobb.equity.discovery.latest_financial_reports(provider='sec', date=2024-09-30)\n```\n\n",
"parameters": {
"standard": [],
"sec": [
{
"name": "date",
"type": "Union[date, str]",
"description": "A specific date to get data for. Defaults to today.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "report_type",
"type": "Union[str, List[str]]",
"description": "Return only a specific form type. Default is all quarterly, annual, and current reports. Choices: 1-K, 1-SA, 1-U, 10-D, 10-K, 10-KT, 10-Q, 10-QT, 20-F, 40-F, 6-K, 8-K. Multiple items allowed for provider(s): sec.",
"default": null,
"optional": true,
"choices": [
"1-K",
"1-SA",
"1-U",
"10-D",
"10-K",
"10-KT",
"10-Q",
"10-QT",
"20-F",
"40-F",
"6-K",
"8-K"
]
}
]
},
"returns": {
"OBBject": [
{
"name": "results",
"type": "List[LatestFinancialReports]",
"description": "Serializable results."
},
{
"name": "provider",
"type": "Optional[Literal['sec']]",
"description": "Provider name."
},
{
"name": "warnings",
"type": "Optional[List[Warning_]]",
"description": "List of warnings."
},
{
"name": "chart",
"type": "Optional[Chart]",
"description": "Chart object."
},
{
"name": "extra",
"type": "Dict[str, Any]",
"description": "Extra info."
}
]
},
"data": {
"standard": [
{
"name": "filing_date",
"type": "date",
"description": "The date of the filing.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "period_ending",
"type": "date",
"description": "Report for the period ending.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "symbol",
"type": "str",
"description": "Symbol representing the entity requested in the data.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "name",
"type": "str",
"description": "Name of the company.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "cik",
"type": "str",
"description": "Central Index Key (CIK) for the requested entity.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "sic",
"type": "str",
"description": "Standard Industrial Classification code.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "report_type",
"type": "str",
"description": "Type of filing.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "description",
"type": "str",
"description": "Description of the report.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "url",
"type": "str",
"description": "URL to the filing page.",
"default": "",
"optional": false,
"choices": null
}
],
"sec": [
{
"name": "items",
"type": "str",
"description": "Item codes associated with the filing.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "index_headers",
"type": "str",
"description": "URL to the index headers file.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "complete_submission",
"type": "str",
"description": "URL to the complete submission text file.",
"default": "",
"optional": false,
"choices": null
},
{
"name": "metadata",
"type": "str",
"description": "URL to the MetaLinks.json file, if available.",
"default": null,
"optional": true,
"choices": null
},
{
"name": "financial_report",
"type": "str",
"description": "URL to the Financial_Report.xlsx file, if available.",
"default": null,
"optional": true,
"choices": null
}
]
},
"model": "LatestFinancialReports"
},
"/equity/fundamental/multiples": {
"deprecated": {
"flag": null,

View File

@@ -18,6 +18,7 @@ class ROUTER_equity_discovery(Container):
filings
gainers
growth_tech
latest_financial_reports
losers
undervalued_growth
undervalued_large_caps
@@ -479,6 +480,117 @@ class ROUTER_equity_discovery(Container):
)
)
@exception_handler
@validate
def latest_financial_reports(
self,
provider: Annotated[
Optional[Literal["sec"]],
OpenBBField(
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: sec."
),
] = None,
**kwargs
) -> OBBject:
"""Get the newest quarterly, annual, and current reports for all companies.
Parameters
----------
provider : Optional[Literal['sec']]
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: sec.
date : Optional[datetime.date]
A specific date to get data for. Defaults to today. (provider: sec)
report_type : Optional[str]
Return only a specific form type. Default is all quarterly, annual, and current reports. Choices: 1-K, 1-SA, 1-U, 10-D, 10-K, 10-KT, 10-Q, 10-QT, 20-F, 40-F, 6-K, 8-K. Multiple comma separated items allowed. (provider: sec)
Returns
-------
OBBject
results : List[LatestFinancialReports]
Serializable results.
provider : Optional[Literal['sec']]
Provider name.
warnings : Optional[List[Warning_]]
List of warnings.
chart : Optional[Chart]
Chart object.
extra : Dict[str, Any]
Extra info.
LatestFinancialReports
----------------------
filing_date : date
The date of the filing.
period_ending : Optional[date]
Report for the period ending.
symbol : Optional[str]
Symbol representing the entity requested in the data.
name : Optional[str]
Name of the company.
cik : Optional[str]
Central Index Key (CIK) for the requested entity.
sic : Optional[str]
Standard Industrial Classification code.
report_type : Optional[str]
Type of filing.
description : Optional[str]
Description of the report.
url : str
URL to the filing page.
items : Optional[str]
Item codes associated with the filing. (provider: sec)
index_headers : Optional[str]
URL to the index headers file. (provider: sec)
complete_submission : Optional[str]
URL to the complete submission text file. (provider: sec)
metadata : Optional[str]
URL to the MetaLinks.json file, if available. (provider: sec)
financial_report : Optional[str]
URL to the Financial_Report.xlsx file, if available. (provider: sec)
Examples
--------
>>> from openbb import obb
>>> obb.equity.discovery.latest_financial_reports(provider='sec')
>>> obb.equity.discovery.latest_financial_reports(provider='sec', date='2024-09-30')
""" # noqa: E501
return self._run(
"/equity/discovery/latest_financial_reports",
**filter_inputs(
provider_choices={
"provider": self._get_provider(
provider,
"equity.discovery.latest_financial_reports",
("sec",),
)
},
standard_params={},
extra_params=kwargs,
info={
"report_type": {
"sec": {
"multiple_items_allowed": True,
"choices": [
"1-K",
"1-SA",
"1-U",
"10-D",
"10-K",
"10-KT",
"10-Q",
"10-QT",
"20-F",
"40-F",
"6-K",
"8-K",
],
}
}
},
)
)
@exception_handler
@validate
def losers(

View File

@@ -9,6 +9,7 @@ from openbb_sec.models.equity_search import SecEquitySearchFetcher
from openbb_sec.models.etf_holdings import SecEtfHoldingsFetcher
from openbb_sec.models.form_13FHR import SecForm13FHRFetcher
from openbb_sec.models.institutions_search import SecInstitutionsSearchFetcher
from openbb_sec.models.latest_financial_reports import SecLatestFinancialReportsFetcher
from openbb_sec.models.rss_litigation import SecRssLitigationFetcher
from openbb_sec.models.schema_files import SecSchemaFilesFetcher
from openbb_sec.models.sic_search import SecSicSearchFetcher
@@ -29,6 +30,7 @@ sec_provider = Provider(
"Filings": SecCompanyFilingsFetcher,
"Form13FHR": SecForm13FHRFetcher,
"InstitutionsSearch": SecInstitutionsSearchFetcher,
"LatestFinancialReports": SecLatestFinancialReportsFetcher,
"RssLitigation": SecRssLitigationFetcher,
"SchemaFiles": SecSchemaFilesFetcher,
"SicSearch": SecSicSearchFetcher,

View File

@@ -0,0 +1,261 @@
"""RSS Latest Financials Model."""
# pylint: disable=unused-argument
from datetime import date as dateType
from typing import Any, Optional
from openbb_core.app.model.abstract.error import OpenBBError
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.standard_models.latest_financial_reports import (
LatestFinancialReportsData,
LatestFinancialReportsQueryParams,
)
from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS
from openbb_core.provider.utils.errors import EmptyDataError
from pydantic import Field, field_validator
report_type_choices = [
"1-K",
"1-SA",
"1-U",
"10-D",
"10-K",
"10-KT",
"10-Q",
"10-QT",
"20-F",
"40-F",
"6-K",
"8-K",
]
class SecLatestFinancialReportsQueryParams(LatestFinancialReportsQueryParams):
"""SEC Latest Financial Reports Query.
source: https://www.sec.gov/edgar/search/
"""
__json_schema_extra__ = {
"report_type": {"multiple_items_allowed": True, "choices": report_type_choices}
}
date: Optional[dateType] = Field(
default=None,
description=QUERY_DESCRIPTIONS.get("date", "") + " Defaults to today.",
)
report_type: Optional[str] = Field(
default=None,
description="Return only a specific form type. Default is all quarterly, annual, and current reports."
+ f" Choices: {', '.join(report_type_choices)}.",
)
@field_validator("report_type", mode="before", check_fields=False)
@classmethod
def validate_report_type(cls, v):
"""Validate the report type."""
if v is None:
return v
rpts = v.split(",")
for rpt in rpts:
if rpt not in report_type_choices:
raise ValueError(
f"Invalid report type: {rpt}. Choices: {', '.join(report_type_choices)}"
)
return v
class SecLatestFinancialReportsData(LatestFinancialReportsData):
"""SEC Latest Financial Reports Data."""
items: Optional[str] = Field(
default=None, description="Item codes associated with the filing."
)
index_headers: str = Field(description="URL to the index headers file.")
complete_submission: str = Field(
description="URL to the complete submission text file."
)
metadata: Optional[str] = Field(
default=None, description="URL to the MetaLinks.json file, if available."
)
financial_report: Optional[str] = Field(
default=None, description="URL to the Financial_Report.xlsx file, if available."
)
class SecLatestFinancialReportsFetcher(
Fetcher[SecLatestFinancialReportsQueryParams, list[SecLatestFinancialReportsData]]
):
"""SEC Latest Financial Reports Fetcher."""
@staticmethod
def transform_query(params: dict[str, Any]) -> SecLatestFinancialReportsQueryParams:
"""Transform the query params."""
return SecLatestFinancialReportsQueryParams(**params)
@staticmethod
async def aextract_data(
query: SecLatestFinancialReportsQueryParams,
credentials: Optional[dict[str, str]],
**kwargs: Any,
) -> list[dict]:
"""Extract the raw data from the SEC."""
# pylint: disable=import-outside-toplevel
from datetime import timedelta # noqa
from openbb_core.provider.utils.helpers import amake_request
from warnings import warn
today = dateType.today()
query_date = query.date if query.date is not None else today
if query_date.weekday() > 4:
query_date -= timedelta(days=query_date.weekday() - 4)
date = query_date.strftime("%Y-%m-%d")
SEARCH_HEADERS = {
"User-Agent": "my real company name definitelynot@fakecompany.com",
"Accept-Encoding": "gzip, deflate",
}
forms = (
query.report_type
if query.report_type is not None
else (
"1-K%2C1-SA%2C1-U%2C1-Z%2C1-Z-W%2C10-D%2C10-K%2C10-KT%2C10-Q%2C10-QT%2C11-K%2C11-KT%2C15-12B%2C15-12G%2C"
"15-15D%2C15F-12B%2C15F-12G%2C15F-15D%2C18-K%2C20-F%2C24F-2NT%2C25%2C25-NSE%2C40-17F2%2C40-17G%2C40-F%2C"
"6-K%2C8-K%2C8-K12G3%2C8-K15D5%2CABS-15G%2CABS-EE%2CANNLRPT%2CDSTRBRPT%2CN-30B-2%2CN-30D%2CN-CEN%2CN-CSR%2C"
"N-CSRS%2CN-MFP%2CN-MFP1%2CN-MFP2%2CN-PX%2CN-Q%2CNSAR-A%2CNSAR-B%2CNSAR-U%2CNT%2010-D%2CNT%2010-K%2C"
"NT%2010-Q%2CNT%2011-K%2CNT%2020-F%2CQRTLYRPT%2CSD%2CSP%2015D2"
)
)
def get_url(date, offset):
return (
"https://efts.sec.gov/LATEST/search-index?dateRange=custom"
f"&category=form-cat1&startdt={date}&enddt={date}&forms={forms}&count=100&from={offset}"
)
n_hits = 0
results: list = []
url = get_url(date, n_hits)
try:
response = await amake_request(url, headers=SEARCH_HEADERS)
except OpenBBError as e:
raise OpenBBError(f"Failed to get SEC data: {e}") from e
if not isinstance(response, dict):
raise OpenBBError(
f"Unexpected data response. Expected dictionary, got {response.__class__.__name__}"
)
hits = response.get("hits", {})
total_hits = hits.get("total", {}).get("value")
if hits.get("hits"):
results.extend(hits["hits"])
n_hits += len(results)
while n_hits < total_hits:
offset = n_hits
url = get_url(date, offset)
try:
response = await amake_request(url, headers=SEARCH_HEADERS)
except Exception as e:
warn(f"Failed to get the next page of SEC data: {e}")
break
hits = response.get("hits", {})
new_results = hits.get("hits", [])
if not new_results:
break
results.extend(new_results)
n_hits += len(new_results)
if not results and query.report_type is None:
raise OpenBBError("No data was returned.")
if not results and query.report_type is not None:
raise EmptyDataError(
f"No data was returned for form type {query.report_type}."
)
return results
@staticmethod
def transform_data(
query: SecLatestFinancialReportsQueryParams,
data: list[dict],
**kwargs: Any,
) -> list[SecLatestFinancialReportsData]:
"""Transform the raw data."""
results: list[SecLatestFinancialReportsData] = []
def parse_entry(entry):
"""Parse each entry in the response."""
source = entry.get("_source", {})
ciks = ",".join(source["ciks"]) if source.get("ciks") else None
display_nammes = source.get("display_names", [])
names: list = []
tickers: list = []
sics = ",".join(source.get("sics", []))
for name in display_nammes:
ticker = name.split("(")[1].split(")")[0].strip()
tickers.append(ticker)
_name = name.split("(")[0].strip()
names.append(_name)
output: dict = {}
output["filing_date"] = source.get("file_date")
output["period_ending"] = source.get("period_ending")
output["symbol"] = ",".join(tickers).replace(" ", "")
output["name"] = ",".join(names)
output["cik"] = ciks
output["sic"] = sics
output["report_type"] = source.get("form")
output["description"] = source.get("file_description")
_id = entry.get("_id")
root_url = (
"https://www.sec.gov/Archives/edgar/data/"
+ source["ciks"][0]
+ "/"
+ source["adsh"].replace("-", "")
+ "/"
)
output["items"] = ",".join(source["items"]) if source.get("items") else None
output["url"] = root_url + _id.split(":")[1]
output["index_headers"] = (
root_url + _id.split(":")[0] + "-index-headers.html"
)
output["complete_submission"] = root_url + _id.split(":")[0] + ".txt"
output["metadata"] = (
root_url + "MetaLinks.json"
if output["report_type"].startswith("10-")
or output["report_type"].startswith("8-")
else None
)
output["financial_report"] = (
root_url + "Financial_Report.xlsx"
if output["report_type"].startswith("10-")
or output["report_type"].startswith("8-")
or output["report_type"] in ["N-CSR", "QRTLYRPT", "ANNLRPT"]
else None
)
return output
# Some duplicates may exist in the data.
seen = set()
for entry in data:
parsed_entry = parse_entry(entry)
if parsed_entry["url"] not in seen:
seen.add(parsed_entry["url"])
results.append(
SecLatestFinancialReportsData.model_validate(parsed_entry)
)
return results

View File

@@ -0,0 +1,58 @@
interactions:
- request:
body: null
headers:
Accept-Encoding:
- gzip, deflate
method: GET
uri: https://efts.sec.gov/LATEST/search-index?category=form-cat1&count=100&dateRange=custom&enddt=2024-11-05&forms=10-K&from=0&startdt=2024-11-05
response:
body:
string: !!binary |
H4sIAAAAAAAAALVV247aMBD9lchPrZRsnRtkeWspbVfdBan3qlpZIRnAIomp7XShaP+9YweWEFip
rbQ8kMSeOXNmcnyyJVqIJRnEsUs0LyFnotZkMEsLBS5hapHKXJHBFsN0WmAcdYmqswyUmtX75yVf
rSAnA7yfpbywt/cuWXDdTt2SX2lRAxkELpFQpJqLigwI/CQYW6ZrpjIhcbuqi2Kf/GNLGK9yWJvA
fJ5KNkN8gsw4FiGUUj/q9y/DwAsij9JeksSDYlpvmE+XFwtdmsgjWKZELTMwbDK+NBUsSC8K+4FP
bl2yAslFzqDKeTXHEgE1yD0vpIhlirOqLndpXhwncWyycq5WRbphVVqCBb0evXzz6vP30Qfn02j4
bjy5nry9Gn10navx8MJxnl3j3nO8Dq/eO4f6zw3UWhV7sgp+1lAZtj6OTAjNZkKWFt+n3nsTbRnl
qYY9Vd/3aIxUp/w3Uxo3bPhwYoIVz+xT0o8Cm4xomGexXJLmavHITJvWy33rQeRHQRL4lwbEFCpE
Zl+nRX8rAao7IXLnCy+KdA6u05S3XPVmBYeaDX1QmeSrnR7eTD7cOLttXmWtJsZfDArXYEdwi6pR
QqJYf/j9kPZ7UULND9f/QjSXoR83DUZhL4gHZhRYdJn+i2oShEnoI6oJPT/wQv9ENb4X0TDpnVXN
pIIbyMegnaGQK9THZHzz2nXM/9e2XJrCTyeXb/RYLqHfkcuLlx3BdOZ5TjDxZRieFczHWkrYuE5T
tasSW+pUJ03LxwJ5Pfo7gZiddD6XMN+T2BKoNNcboxQN0izkImOZqCvNQEohWY0eJ9kUVxqnU3XJ
hF7g2kOkXZ/W2RJ23rWEDXbxn17gkhawb1TdwP2rSDo4diw8e5JOrVIe421d5wyZg/SehBN6z2OM
vtFzfIzMn4TJztRaYQEWxIp4bOXG1Gr5DKyzos7ByNokaFhrctuOnQphP6plrYzEUfjmjlVi96QW
oi7y5n7fDVLBa2kFf84g7s1sTIQJONjJw5fbv7cRMq3mdrllJ1syP3WVoruE+bbjmRRlMz3+2+BS
enoiO+/hgfiMg+mr3cAeJ6QG/OQon6QeGe+FTO86CMfn4yTdGuNxxlkRnyS2XLadfjCqzkiFzA0S
Mc5H7Oj+AFpsuc6wCQAA
headers:
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Length:
- '870'
Content-Type:
- application/json
Date:
- Wed, 06 Nov 2024 23:46:07 GMT
Strict-Transport-Security:
- max-age=31536000 ; includeSubDomains ; preload
Vary:
- Accept-Encoding
X-Amz-Cf-Id:
- dd0jBe4juO5qrFa9TidjpxabDum7CjatTxUIHQBySjBss0mNEa-Cvg==
X-Amz-Cf-Pop:
- DFW57-P2
X-Amzn-Trace-Id:
- Root=1-672bffbf-2a8978e072decbd61c503a88;Parent=7a86ce10a1b8d665;Sampled=0;Lineage=1:fc027ad0:0
x-amz-apigw-id:
- A2TmCENeIAMELwg=
x-amzn-RequestId:
- 04ef45e1-e06c-497b-8a9d-8093f552d7d5
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,58 @@
interactions:
- request:
body: null
headers:
Accept-Encoding:
- gzip, deflate
method: GET
uri: https://efts.sec.gov/LATEST/search-index?category=form-cat1&count=100&dateRange=custom&enddt=2024-11-05&forms=10-K&from=0&startdt=2024-11-05
response:
body:
string: !!binary |
H4sIAAAAAAAAALVV247aMBD9lchPrZRsnRtkeWspbVfdBan3qlpZIRnAIomp7XShaP+9HgeWEFip
rbQ8kMSeOXNmcnyyJVqIJRnEPZdoXkLORK3JYJYWClzC1CKVuSKDrQnTaWHiqEtUnWWg1KzePy/5
agU5GZj7WcoLe3vvkgXX7dQt+ZUWNZBB4BIJRaq5qMiAwE9iYst0zVQmpNmu6qLYJ//YEsarHNYY
mM9TyWYGnxhm3BQhlFI/6vcvw8ALIo/SXpLEg2Jab5hPlxcLXWLkESxTopYZIJuML7GCBelFYT/w
ya1LViC5yBlUOa/mpkRAEbnnhdRgYXFW1eUuzYvjJI4xK+dqVaQbVqUlWNDr0cs3rz5/H31wPo2G
78aT68nbq9FH17kaDy8c59m12XtursOr986h/nOEWqtiT1bBzxoqZOubkQmh2UzI0uL71HuP0ZZR
nmrYU/V9j8aG6pT/ZkqbDRs+nGCw4pl9SvpRYJMNmsmzWC5Jc7V4ZKZN6+W+9SDyoyAJ/EsEwUKF
yOzrtOhvJUB1J0TufOFFkc7BdZrylqverOBQs6EPKpN8tdPDm8mHG2e3zaus1cT4C6JwDXYEt0Y1
Skgj1h9+P6T9XpRQ/Jn1vxDNZejHTYNR2AviAY7CFF2m/6KaxMAk9BHVhJ4feKF/ohrfi2iY9M6q
ZlLBDeRj0M5QyJXRx2R889p18P9rWy5N4aeTyzd6LJfQ78jlxcuOYDrzPCeY+DIMzwrmYy0lbFyn
qdpViS11qpOm5WOBvB79nUBwJ53PJcz3JLYEKs31BpWiQeJCLjKWibrSDKQUktXG4ySbmpXG6VRd
MqEXZu0h0q5P62wJO+9awsZ08Z9e4JIWsI+qbuD+VSQdHDsWnj1Jp1Ypj/G2rnOGzEF6T8LJeM9j
jL7Rc3xQ5k/CZGdqrbDAFDQVzbGVG6zV8hlYZ0WdA8oaEzSsNbltx06FsB/VslYocSN8vGOV2D2p
haiLvLnfd2OomGtpBX/OIO5xNhiBAQc7efhy+/c2QqbV3C637GRL5qeuUnSXTL7teCZF2UyP/0Zc
Sk9PZOc9PBCfccC+2g3scUKK4CdH+ST1yHgvZHrXQTg+Hyfp1hiPM86K+CSx5bLt9INRdUYqZI5I
BJ2P2NH9AWSYZluwCQAA
headers:
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Length:
- '870'
Content-Type:
- application/json
Date:
- Wed, 06 Nov 2024 23:47:05 GMT
Strict-Transport-Security:
- max-age=31536000 ; includeSubDomains ; preload
Vary:
- Accept-Encoding
X-Amz-Cf-Id:
- tiBqDHiaTK40xZ4q6fGRdhkr42yULJlGDxNihuuBCeqTOzjzp-61Rw==
X-Amz-Cf-Pop:
- ORD58-P1
X-Amzn-Trace-Id:
- Root=1-672bfff9-3c12ad3373afc4f500502c9b;Parent=381e677e9b9f417b;Sampled=0;Lineage=1:fc027ad0:0
x-amz-apigw-id:
- A2TvEEsLIAMEUMw=
x-amzn-RequestId:
- 806da0b3-66f4-43b3-a50e-dc0f6073d264
status:
code: 200
message: OK
version: 1

View File

@@ -1,5 +1,7 @@
"""Tests for the SEC fetchers."""
from datetime import date
import pytest
from openbb_core.app.service.user_service import UserService
from openbb_sec.models.cik_map import SecCikMapFetcher
@@ -10,6 +12,7 @@ from openbb_sec.models.equity_search import SecEquitySearchFetcher
from openbb_sec.models.etf_holdings import SecEtfHoldingsFetcher
from openbb_sec.models.form_13FHR import SecForm13FHRFetcher
from openbb_sec.models.institutions_search import SecInstitutionsSearchFetcher
from openbb_sec.models.latest_financial_reports import SecLatestFinancialReportsFetcher
from openbb_sec.models.rss_litigation import SecRssLitigationFetcher
from openbb_sec.models.schema_files import SecSchemaFilesFetcher
from openbb_sec.models.sic_search import SecSicSearchFetcher
@@ -154,3 +157,16 @@ def test_sec_compare_company_facts_fetcher(credentials=test_credentials):
fetcher = SecCompareCompanyFactsFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_sec_latest_financial_reports_fetcher(credentials=test_credentials):
"""Test the SEC Latest Financial Reports fetcher."""
params = {
"date": date(2024, 11, 5),
"report_type": "10-K",
}
fetcher = SecLatestFinancialReportsFetcher()
result = fetcher.test(params, credentials)
assert result is None