Source code for btgsolutions_dataservices.rest.alternative_data_companies

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


[docs] class AlternativeDataCompanies: """ This class provides company-level alternative data: corporate governance, board composition, financial statements, and issuer disclosures. * Main use case: >>> from btgsolutions_dataservices import AlternativeDataCompanies >>> companies = AlternativeDataCompanies(api_key='YOUR_API_KEY') >>> companies.get_board(company_id='PETR4') >>> companies.get_governance_summary(company_id='VALE3') >>> companies.get_financial_statements(company_id='ITUB4') >>> companies.get_disclosures(company_id='PETR4', document_type='insider') 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_board( self, company_id: str, reference_date: Optional[str] = None, body: Optional[str] = None, committee: Optional[str] = None, include_alternates: Optional[bool] = None, limit: int = 200, offset: int = 0, ) -> dict: """ Board and executive composition for a company (BR, US, or UK). Parameters ---------------- company_id: str Company identifier. Accepts CNPJ, CVM code, B3 ticker, ISIN, LEI, UK company number, SEC ticker/CIK, or company name. Field is required. Example: 'PETR4'. reference_date: str Reference date in YYYY-MM-DD format. Defaults to the most recent filing. Field is not required. Example: '2024-12-31'. body: str Governance body filter: 'board', 'executive', or 'committee'. Field is not required. Default: 'board'. committee: str Committee name filter (used when body='committee'). Field is not required. include_alternates: bool Whether to include alternate members. Field is not required. Default: True. limit: int Maximum number of results to return. Field is not required. Default: 200. offset: int Number of results to skip for pagination. Field is not required. Default: 0. """ return self._get("companies/board", { "company_id": company_id, "reference_date": reference_date, "body": body, "committee": committee, "include_alternates": include_alternates, "limit": limit, "offset": offset, })
[docs] def get_governance_summary(self, company_id: str) -> dict: """ Latest governance snapshot for a company (board size, independence, committees, CEO name, etc.). Parameters ---------------- company_id: str Company identifier (CNPJ, CVM code, B3 ticker, SEC ticker/CIK, etc.). Field is required. Example: 'VALE3'. """ return self._get("companies/governance-summary", {"company_id": company_id})
[docs] def get_governance_history( self, company_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, body: Optional[str] = None, limit: int = 12, ) -> dict: """ Monthly governance history snapshots (member counts per governance body). Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'ITUB4'. 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. body: str Governance body filter: 'board', 'executive', or 'committee'. Field is not required. limit: int Maximum number of snapshots to return. Field is not required. Default: 12. """ return self._get("companies/governance-history", { "company_id": company_id, "start_date": start_date, "end_date": end_date, "body": body, "limit": limit, })
[docs] def get_governance_documents( self, company_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, category: Optional[str] = None, governance_topic: Optional[str] = None, event_tag: Optional[str] = None, limit: int = 100, offset: int = 0, ) -> dict: """ CVM IPE governance documents for a Brazilian company. Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'PETR4'. 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. category: str Document category filter. Field is not required. governance_topic: str Governance topic filter. Field is not required. event_tag: str Event tag filter. Field is not required. 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("companies/governance-documents", { "company_id": company_id, "start_date": start_date, "end_date": end_date, "category": category, "governance_topic": governance_topic, "event_tag": event_tag, "limit": limit, "offset": offset, })
[docs] def get_governance_compensation( self, company_id: str, fiscal_year: Optional[str] = None, limit: int = 100, offset: int = 0, ) -> dict: """ Executive compensation data from CVM FRE (BR) or SEC proxy filings (US). Parameters ---------------- company_id: str Company identifier. Field is required. Example: 'VALE3'. fiscal_year: str Four-digit fiscal year filter. Field is not required. Example: '2024'. 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("companies/governance-compensation", { "company_id": company_id, "fiscal_year": fiscal_year, "limit": limit, "offset": offset, })
[docs] def get_governance_beneficial_ownership( self, company_id: str, holder_type: Optional[str] = None, limit: int = 100, offset: int = 0, ) -> dict: """ Beneficial ownership records (UK PSC or BR equivalents). Parameters ---------------- company_id: str Company identifier. Field is required. holder_type: str Holder type filter. Field is not required. 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("companies/governance-beneficial-ownership", { "company_id": company_id, "holder_type": holder_type, "limit": limit, "offset": offset, })
[docs] def get_corporate_registry( self, company_id: str, direction: str = "partners", reference_month: Optional[str] = None, partner_type: Optional[str] = None, qualification: Optional[str] = None, limit: int = 100, offset: int = 0, ) -> dict: """ Brazilian corporate registry (Receita Federal QSA + CVM FRE). Parameters ---------------- company_id: str Company identifier (CNPJ, CVM code, or B3 ticker). Field is required. Example: 'PETR4'. direction: str 'partners' (default) returns the company's shareholders/partners; 'investees' returns the companies this entity holds stakes in. Field is not required. Default: 'partners'. reference_month: str Reference month in YYYY-MM format. Field is not required. partner_type: str Partner type filter. Field is not required. qualification: str Partner qualification filter. Field is not required. 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("companies/corporate-registry", { "company_id": company_id, "direction": direction, "reference_month": reference_month, "partner_type": partner_type, "qualification": qualification, "limit": limit, "offset": offset, })
[docs] def get_insider_trades( self, company_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, transaction_code: Optional[str] = None, limit: int = 100, ) -> dict: """ Insider trade transactions from SEC Forms 3/4/5 (US only). Parameters ---------------- company_id: str Company identifier (SEC ticker or CIK). Field is required. Example: 'AAPL'. 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. transaction_code: str SEC transaction code filter (e.g. 'P' for purchase, 'S' for sale). Field is not required. limit: int Maximum number of results to return. Field is not required. Default: 100. """ return self._get("companies/insider-trades", { "company_id": company_id, "start_date": start_date, "end_date": end_date, "transaction_code": transaction_code, "limit": limit, })
[docs] def get_board_changes( self, company_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None, event: Optional[str] = None, limit: int = 100, ) -> dict: """ Board appointment and resignation events. 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. event: str Event type filter: 'appointed' or 'resigned'. Field is not required. limit: int Maximum number of results to return. Field is not required. Default: 100. """ return self._get("companies/board-changes", { "company_id": company_id, "start_date": start_date, "end_date": end_date, "event": event, "limit": limit, })
[docs] def get_financial_statements( self, company_id: str, statement: str = "income_statement", quarter: Optional[str] = None, reference_date: Optional[str] = None, statement_type: Optional[str] = None, account_code: Optional[str] = None, limit: int = 100, offset: int = 0, ) -> dict: """ Financial statements from CVM DFP/ITR filings (BR companies). Parameters ---------------- company_id: str Company identifier (CNPJ, CVM code, or B3 ticker). Field is required. Example: 'PETR4'. statement: str Statement type (e.g. 'income_statement', 'balance_sheet', 'cash_flow'). Field is not required. Default: 'income_statement'. quarter: str Quarter filter in QTyy format (e.g. 'Q12024'). Field is not required. reference_date: str Reference date in YYYY-MM-DD format. Field is not required. statement_type: str Statement type filter (e.g. 'DFP', 'ITR'). Field is not required. account_code: str Specific account code filter. Field is not required. 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("companies/financial-statements", { "company_id": company_id, "statement": statement, "quarter": quarter, "reference_date": reference_date, "statement_type": statement_type, "account_code": account_code, "limit": limit, "offset": offset, })
[docs] def get_financial_notes( self, company_id: str, quarter: Optional[str] = None, limit: int = 10, offset: int = 0, ) -> dict: """ LLM-parsed structured data from CVM DFP/ITR explanatory notes (notas explicativas): geographic_segments, fx_exposure, and supplier_concentration. Parameters ---------------- company_id: str Company identifier (CNPJ, CVM code, or B3 ticker). Field is required. Example: 'VALE3'. quarter: str Quarter filter in QTyy format (e.g. 'Q42024'). Field is not required. limit: int Maximum number of results to return. Field is not required. Default: 10. offset: int Number of results to skip for pagination. Field is not required. Default: 0. """ return self._get("companies/financial-notes", { "company_id": company_id, "quarter": quarter, "limit": limit, "offset": offset, })
[docs] def get_disclosures( self, company_id: Optional[str] = None, document_type: str = "repurchase", asset: Optional[str] = None, protocol_number: Optional[str] = None, reference_date: Optional[str] = None, start_date: Optional[str] = None, end_date: Optional[str] = None, transaction: Optional[str] = None, transaction_type: Optional[str] = None, participant_group: Optional[str] = None, limit: int = 100, offset: int = 0, ) -> dict: """ CVM IPE regulatory disclosure documents (buyback programs and insider activity notifications). Parameters ---------------- company_id: str Company identifier. Field is not required. Example: 'PETR4'. document_type: str Document type: 'repurchase' (buyback programs) or 'insider' (insider trading notifications). Field is not required. Default: 'repurchase'. asset: str Ticker asset filter. Field is not required. protocol_number: str CVM protocol number filter. Field is not required. reference_date: str Reference date in YYYY-MM-DD format. Field is not 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. transaction: str Transaction description filter. Field is not required. transaction_type: str Transaction type filter. Field is not required. participant_group: str Participant group filter. Field is not required. 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("companies/disclosures", { "company_id": company_id, "document_type": document_type, "asset": asset, "protocol_number": protocol_number, "reference_date": reference_date, "start_date": start_date, "end_date": end_date, "transaction": transaction, "transaction_type": transaction_type, "participant_group": participant_group, "limit": limit, "offset": offset, })