Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Add form_13f Endpoint to equity.ownership #6122

Merged
merged 22 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""From 13F-HR Standard Model."""

from datetime import date as dateType
from typing import Optional

from pydantic import Field, field_validator

from openbb_core.provider.abstract.data import Data
from openbb_core.provider.abstract.query_params import QueryParams
from openbb_core.provider.utils.descriptions import (
QUERY_DESCRIPTIONS,
)


class Form13FHRQueryParams(QueryParams):
"""Form 13F-HR Query."""

__validator_dict__ = {"check_single": ("symbol")}

symbol: str = Field(
description=QUERY_DESCRIPTIONS.get("symbol", "")
+ " A CIK or Symbol can be used."
)
date: Optional[dateType] = Field(
default=None,
description=QUERY_DESCRIPTIONS.get("date", "")
+ " The date represents the end of the reporting period."
+ " All form 13F-HR filings are based on the calendar year"
+ " and are reported quarterly."
+ " If a date is not supplied, the most recent filing is returned."
+ " Submissions beginning 2013-06-30 are supported.",
)
limit: Optional[int] = Field(
default=1,
description=QUERY_DESCRIPTIONS.get("limit", "")
+ " The number of previous filings to return."
+ " This parameter is overriden by the date parameter.",
deeleeramone marked this conversation as resolved.
Show resolved Hide resolved
)

@field_validator("symbol", mode="before", check_fields=False)
@classmethod
def upper_symbol(cls, v: str):
"""Convert symbol to uppercase."""
return str(v).upper()


class Form13FHRData(Data):
"""Form 13F-HR Data."""

period_ending: dateType = Field(
description="The date of the reporting period ended."
deeleeramone marked this conversation as resolved.
Show resolved Hide resolved
)
issuer: str = Field(description="The name of the issuer.")
cusip: str = Field(description="The CUSIP of the security.")
asset_class: str = Field(
description="The title of the asset class for the security."
)
security_type: str = Field(
description="The type of security"
+ " 'SH' for shares. 'PRN' for principal amount. 'Call' or 'Put' for options.",
deeleeramone marked this conversation as resolved.
Show resolved Hide resolved
)
investment_discretion: str = Field(
description="The nature of the investment discretion held by the Manager."
+ " One of: 'SOLE', 'DFND' (defined), 'OTR' (other).",
deeleeramone marked this conversation as resolved.
Show resolved Hide resolved
)
voting_authority_sole: Optional[int] = Field(
default=None,
description="The number of shares for which the Manager"
+ " exercises sole voting authority (none).",
)
voting_authority_shared: Optional[int] = Field(
default=None,
description="The number of shares for which the Manager"
+ " exercises a defined shared voting authority (none).",
)
voting_authority_other: Optional[int] = Field(
default=None,
description="The number of shares for which the Manager"
+ " exercises other shared voting authority (none).",
)
principal_amount: int = Field(
description="The total number of shares of the class of security"
+ " or the principla amount of such class.",
)
value: int = Field(
description="The fair market value of the holding of the particular class of security."
+ " Values are rounded to the nearest US dollar",
)
24 changes: 24 additions & 0 deletions openbb_platform/extensions/equity/integration/test_equity_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1766,3 +1766,27 @@ def test_equity_fundamental_reported_financials(params, headers):
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@parametrize(
"params",
[
(
{
"symbol": "NVDA",
"date": None,
"limit": 1,
"provider": "sec",
}
),
],
)
@pytest.mark.integration
def test_equity_ownership_form_13f(params, headers):
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/ownership/form_13f?{query_str}"
result = requests.get(url, headers=headers, timeout=10)
assert isinstance(result, requests.Response)
assert result.status_code == 200
Original file line number Diff line number Diff line change
Expand Up @@ -1655,3 +1655,26 @@ def test_equity_fundamental_reported_financials(params, obb):
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0


@parametrize(
"params",
[
(
{
"symbol": "NVDA",
"date": None,
"limit": 1,
"provider": "sec",
}
),
],
)
@pytest.mark.integration
def test_equity_ownership_form_13f(params, obb):
params = {p: v for p, v in params.items() if v}

result = obb.equity.ownership.form_13f(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,34 @@ async def share_statistics(
) -> OBBject:
"""Get data about share float for a given company."""
return await OBBject.from_query(Query(**locals()))


@router.command(
model="Form13FHR",
exclude_auto_examples=True,
examples=[
"### Enter the symbol as either the stock ticker or the CIK number as a string. ###",
'obb.equity.ownership.form_13f(symbol="NVDA").to_df()',
"### Enter a date (calendar quarter ending) for a specific report. ###",
'obb.equity.ownership.form_13f(symbol="BRK-A", date="2016-09-30")',
"### Use the `limit` parameter to return N number of reports from the most recent. ###",
"### Example finding Michael Burry's filings. ###",
'cik = obb.regulators.sec.institutions_search("Scion Asset Management").results[0].cik'
"obb.equity.ownership.form_13f(cik, limit=2).to_df()",
],
)
async def form_13f(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject:
"""
The Securities and Exchange Commission's (SEC) Form 13F is a quarterly report
that is required to be filed by all institutional investment managers with at least
$100 million in assets under management.
Managers are required to file Form 13F within 45 days after the last day of the calendar quarter.
Most funds wait until the end of this period in order to conceal
their investment strategy from competitors and the public.
"""
return await OBBject.from_query(Query(**locals()))
1 change: 1 addition & 0 deletions openbb_platform/openbb/assets/module_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"equity_fundamental_transcript": "/equity/fundamental/transcript",
"equity_market_snapshots": "/equity/market_snapshots",
"equity_ownership": "/equity/ownership",
"equity_ownership_form_13f": "/equity/ownership/form_13f",
"equity_ownership_insider_trading": "/equity/ownership/insider_trading",
"equity_ownership_institutional": "/equity/ownership/institutional",
"equity_ownership_major_holders": "/equity/ownership/major_holders",
Expand Down
119 changes: 119 additions & 0 deletions openbb_platform/openbb/package/equity_ownership.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

class ROUTER_equity_ownership(Container):
"""/equity/ownership
form_13f
insider_trading
institutional
major_holders
Expand All @@ -22,6 +23,124 @@ class ROUTER_equity_ownership(Container):
def __repr__(self) -> str:
return self.__doc__ or ""

@exception_handler
@validate
def form_13f(
self,
symbol: Annotated[
str,
OpenBBCustomParameter(
description="Symbol to get data for. A CIK or Symbol can be used."
),
],
date: Annotated[
Union[datetime.date, None, str],
OpenBBCustomParameter(
description="A specific date to get data for. The date represents the end of the reporting period. All form 13F-HR filings are based on the calendar year and are reported quarterly. If a date is not supplied, the most recent filing is returned. Submissions beginning 2013-06-30 are supported."
),
] = None,
limit: Annotated[
Optional[int],
OpenBBCustomParameter(
description="The number of data entries to return. The number of previous filings to return. This parameter is overriden by the date parameter."
),
] = 1,
provider: Optional[Literal["sec"]] = None,
**kwargs
) -> OBBject:
"""The Securities and Exchange Commission's (SEC) Form 13F is a quarterly report
that is required to be filed by all institutional investment managers with at least
$100 million in assets under management.
Managers are required to file Form 13F within 45 days after the last day of the calendar quarter.
Most funds wait until the end of this period in order to conceal
their investment strategy from competitors and the public.


Parameters
----------
symbol : str
Symbol to get data for. A CIK or Symbol can be used.
date : Union[datetime.date, None, str]
A specific date to get data for. The date represents the end of the reporting period. All form 13F-HR filings are based on the calendar year and are reported quarterly. If a date is not supplied, the most recent filing is returned. Submissions beginning 2013-06-30 are supported.
limit : Optional[int]
The number of data entries to return. The number of previous filings to return. This parameter is overriden by the date parameter.
provider : Optional[Literal['sec']]
The provider to use for the query, by default None.
If None, the provider specified in defaults is selected or 'sec' if there is
no default.

Returns
-------
OBBject
results : List[Form13FHR]
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.

Form13FHR
---------
period_ending : date
The date of the reporting period ended.
issuer : str
The name of the issuer.
cusip : str
The CUSIP of the security.
asset_class : str
The title of the asset class for the security.
security_type : str
The type of security 'SH' for shares. 'PRN' for principal amount. 'Call' or 'Put' for options.
investment_discretion : str
The nature of the investment discretion held by the Manager. One of: 'SOLE', 'DFND' (defined), 'OTR' (other).
voting_authority_sole : Optional[int]
The number of shares for which the Manager exercises sole voting authority (none).
voting_authority_shared : Optional[int]
The number of shares for which the Manager exercises a defined shared voting authority (none).
voting_authority_other : Optional[int]
The number of shares for which the Manager exercises other shared voting authority (none).
principal_amount : int
The total number of shares of the class of security or the principla amount of such class.
value : int
The fair market value of the holding of the particular class of security. Values are rounded to the nearest US dollar
weight : Optional[float]
The weight of the security relative to the market value of all securities in the filing , as a normalized percent.. (provider: sec)

Example
-------
>>> from openbb import obb
>>> ### Enter the symbol as either the stock ticker or the CIK number as a string. ###
>>> obb.equity.ownership.form_13f(symbol="NVDA").to_df()
>>> ### Enter a date (calendar quarter ending) for a specific report. ###
>>> obb.equity.ownership.form_13f(symbol="BRK-A", date="2016-09-30")
>>> ### Use the `limit` parameter to return N number of reports from the most recent. ###
>>> ### Example finding Michael Burry's filings. ###
>>> cik = obb.regulators.sec.institutions_search("Scion Asset Management").results[0].cikobb.equity.ownership.form_13f(cik, limit=2).to_df()
""" # noqa: E501

return self._run(
"/equity/ownership/form_13f",
**filter_inputs(
provider_choices={
"provider": self._get_provider(
provider,
"/equity/ownership/form_13f",
("sec",),
)
},
standard_params={
"symbol": symbol,
"date": date,
"limit": limit,
},
extra_params=kwargs,
)
)

@exception_handler
@validate
def insider_trading(
Expand Down
2 changes: 2 additions & 0 deletions openbb_platform/providers/sec/openbb_sec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from openbb_sec.models.equity_ftd import SecEquityFtdFetcher
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.rss_litigation import SecRssLitigationFetcher
from openbb_sec.models.schema_files import SecSchemaFilesFetcher
Expand All @@ -24,6 +25,7 @@
"EquitySearch": SecEquitySearchFetcher,
"EtfHoldings": SecEtfHoldingsFetcher,
"Filings": SecCompanyFilingsFetcher,
"Form13FHR": SecForm13FHRFetcher,
"InstitutionsSearch": SecInstitutionsSearchFetcher,
"RssLitigation": SecRssLitigationFetcher,
"SchemaFiles": SecSchemaFilesFetcher,
Expand Down
Loading
Loading