Source code for btgsolutions_dataservices.rest.alternative_data_ownership

from typing import Optional
import requests
from ..exceptions import BadResponse
from ..config import url_api_v1
from .authenticator import Authenticator


[docs] class AlternativeDataOwnership: """ This class provides ownership alternative data: top shareholders, ownership structure, change events, official notices, control group, free float, shareholder holdings, and institutional/fund holders of assets. * Main use case: >>> from btgsolutions_dataservices import AlternativeDataOwnership >>> ownership = AlternativeDataOwnership(api_key='YOUR_API_KEY') >>> ownership.get_top_shareholders(company_id='VALE3') >>> ownership.get_ownership_current(company_id='ITUB4') >>> ownership.get_shareholder_holdings(shareholder_id='00.000.000/0001-91') Parameters ---------------- api_key: str User identification key. Field is required. """ def __init__(self, api_key: str): self.api_key = api_key self.token = Authenticator(self.api_key).token self.headers = {"authorization": f"Bearer {self.token}"} def _get(self, path: str, params: dict) -> dict: url = f"{url_api_v1}/public-sources/{path}" params = {k: v for k, v in params.items() if v is not None and v != ""} response = requests.get(url, params=params, headers=self.headers, timeout=30) if response.status_code != 200: self._raise_error(response) return response.json() @staticmethod def _raise_error(response): try: body = response.json() detail = body.get("detail", body.get("error", body.get("ApiClientError", response.text))) except Exception: detail = response.text raise BadResponse(f"Error {response.status_code}: {detail}")
[docs] def get_top_shareholders( self, company_id: str, reference_date: Optional[str] = None, ownership_category: str = "all", limit: int = 20, ) -> dict: """ Top shareholders for a company. Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'VALE3'. reference_date: str Reference date in YYYY-MM-DD format. Defaults to the most recent snapshot. Field is not required. ownership_category: str Ownership category filter. Field is not required. Default: 'all'. limit: int Maximum number of shareholders to return. Field is not required. Default: 20. """ return self._get("companies/shareholders/top", { "company_id": company_id, "reference_date": reference_date, "ownership_category": ownership_category, "limit": limit, })
[docs] def get_ownership_current(self, company_id: str) -> dict: """ Current ownership structure snapshot for a company. Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'ITUB4'. """ return self._get("companies/ownership-current", {"company_id": company_id})
[docs] def get_ownership_history( self, company_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, ownership_category: str = "all", limit: int = 12, ) -> dict: """ Monthly ownership history snapshots for a company. Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'VALE3'. start_date: str Start date in YYYY-MM-DD format. Field is not required. end_date: str End date in YYYY-MM-DD format. Field is not required. ownership_category: str Ownership category filter. Field is not required. Default: 'all'. limit: int Maximum number of snapshots to return. Field is not required. Default: 12. """ return self._get("companies/ownership-history", { "company_id": company_id, "start_date": start_date, "end_date": end_date, "ownership_category": ownership_category, "limit": limit, })
[docs] def get_ownership_change_events( self, company_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, ownership_category: str = "all", limit: int = 100, ) -> dict: """ Ownership change events for a company (with inline official notices). Parameters ---------------- company_id: str Company identifier. Field is required. start_date: str Start date in YYYY-MM-DD format. Field is not required. end_date: str End date in YYYY-MM-DD format. Field is not required. ownership_category: str Ownership category filter. Field is not required. Default: 'all'. limit: int Maximum number of results to return. Field is not required. Default: 100. """ return self._get("companies/ownership-change-events", { "company_id": company_id, "start_date": start_date, "end_date": end_date, "ownership_category": ownership_category, "limit": limit, })
[docs] def get_ownership_official_notices( self, company_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, parser_status: str = "all", limit: int = 100, ) -> dict: """ Official ownership notices (CVM IPE, SEC 13D/13G/13F, IR page structures). Parameters ---------------- company_id: str Company identifier. Field is required. start_date: str Start date in YYYY-MM-DD format. Field is not required. end_date: str End date in YYYY-MM-DD format. Field is not required. parser_status: str Filter by parser status. Field is not required. Default: 'all'. limit: int Maximum number of results to return. Field is not required. Default: 100. """ return self._get("companies/ownership-official-notices", { "company_id": company_id, "start_date": start_date, "end_date": end_date, "parser_status": parser_status, "limit": limit, })
[docs] def get_ownership_control_group(self, company_id: str) -> dict: """ Control group composition for a Brazilian company (CVM FRE). Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'VALE3'. """ return self._get("companies/ownership-control-group", {"company_id": company_id})
[docs] def get_ownership_free_float(self, company_id: str, limit: int = 20) -> dict: """ Free float breakdown for a company. Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'PETR4'. limit: int Maximum number of results to return. Field is not required. Default: 20. """ return self._get("companies/ownership-free-float", { "company_id": company_id, "limit": limit, })
[docs] def get_shareholder_holdings( self, shareholder_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, ownership_category: str = "all", limit: int = 100, offset: int = 0, ) -> dict: """ Holdings owned by a shareholder across companies (reverse lookup). Parameters ---------------- shareholder_id: str Shareholder identifier (CNPJ, CPF, or name). Field is required. start_date: str Start date in YYYY-MM-DD format. Field is not required. end_date: str End date in YYYY-MM-DD format. Field is not required. ownership_category: str Ownership category filter. Field is not required. Default: 'all'. limit: int Maximum number of results to return. Field is not required. Default: 100. offset: int Number of results to skip for pagination. Field is not required. Default: 0. """ return self._get("shareholders/holdings", { "shareholder_id": shareholder_id, "start_date": start_date, "end_date": end_date, "ownership_category": ownership_category, "limit": limit, "offset": offset, })
[docs] def get_institutional_holders( self, identifier: str, identifier_type: str = "b3_ticker", reference_date: Optional[str] = None, limit: int = 50, ) -> dict: """ Institutional holders of a specific asset. Parameters ---------------- identifier: str Asset identifier. Field is required. Example: 'VALE3'. identifier_type: str Type of identifier: 'b3_ticker', 'isin', 'cusip', or 'issuer_cnpj'. Field is not required. Default: 'b3_ticker'. reference_date: str Reference date in YYYY-MM-DD format. Defaults to the most recent snapshot. Field is not required. limit: int Maximum number of holders to return. Field is not required. Default: 50. """ return self._get("assets/institutional-holders", { "identifier": identifier, "identifier_type": identifier_type, "reference_date": reference_date, "limit": limit, })
[docs] def get_fund_holders( self, identifier: str, identifier_type: str = "b3_ticker", reference_date: Optional[str] = None, limit: int = 50, ) -> dict: """ Funds that hold a specific asset. Parameters ---------------- identifier: str Asset identifier. Field is required. Example: 'PETR4'. identifier_type: str Type of identifier: 'b3_ticker', 'isin', 'cusip', or 'issuer_cnpj'. Field is not required. Default: 'b3_ticker'. reference_date: str Reference date in YYYY-MM-DD format. Defaults to the most recent snapshot. Field is not required. limit: int Maximum number of fund holders to return (max 500). Field is not required. Default: 50. """ return self._get("assets/fund-holders", { "identifier": identifier, "identifier_type": identifier_type, "reference_date": reference_date, "limit": limit, })